Article 1463 of alt.sources.amiga:
Path: news.csos.orst.edu!gaia.ucs.orst.edu!umn.edu!spool.mu.edu!uwm.edu!math.ohio-state.edu!usc!hela.iti.org!widener!dsinc!netnews.upenn.edu!jake.esu.edu!babbage.esu.edu!marvin
From: marvin@esu.edu (Michael Pedersen)
Newsgroups: alt.sources.amiga
Subject: Hotkeys in the CLI
Message-ID: <28r0qd$6rs@jake.esu.edu>
Date: 5 Oct 93 05:30:53 GMT
Organization: East Stroudsburg University, Pennsylvania
Lines: 475
NNTP-Posting-Host: babbage.esu.edu
X-Newsreader: TIN [version 1.2 PL0]


Well, for all of you who remember, I recently asked for some help on how to
activate Hotkeys in the cli.  I have found a program that does this (pretty
much, anyway).  However, in its current form, it is useless to me...  It's
written in assembler (a language that I just _BARELY_ understand), and
worse, the docs are written in German (a language that I don't understand
PERIOD).

If somebody could translate the source into C (or just simply explain how it
works), I would be most appreciative.  Here's the source:

(and thanks in advance for any help that you can provide)...

;  -----------------------------------------------------------------------
;  -----------------------------------------------------------------------
;  --                                                                   --
;  --                        WaitAnyKey V1.00                           --
;  --                                                                   --
;  -----------------------------------------------------------------------
;  -----------------------------------------------------------------------
;  --                                                                   --
;  --      Copyright 1990      Roger Fischlin                           --
;  --                          Steigerwaldweg 6                         --
;  --                          D-6450 Hanau 7                           --
;  --                          Germany                                  --
;  --                                                                   --
;  -----------------------------------------------------------------------
;  -----------------------------------------------------------------------
;  --                                                                   --
;  --  This program is FREEWARE. It's still copyrighted by the author.  --
;  --                                                                   --
;  --                                                                   --
;  --  This program can be freely distributed if :                      --
;  --  1. the name of  the author  and  the  copyright  remark  remain  --
;  --     unchanged.                                                    --
;  --  2. you don't gain any profit by distributing it !                --
;  --                                                                   --
;  --                                                                   --
;  -----------------------------------------------------------------------
;  -- This  program  ist  PC  relative and  100 %  PURE (set P flag) !  --
;  -----------------------------------------------------------------------





	incdir	"ram:include/"

	include	"exec/exec_lib.i"
	include	"exec/memory.i"
	include	"libraries/dos.i"
	include	"libraries/dos_lib.i"
	include	"libraries/dosextens.i"


	IFND	DOSTRUE
DOSTRUE	equ	-1
	ENDC
	IFND	DOSFALSE
DOSFALSE	equ	0
	ENDC




; ---------------------------------------------------------------------
; --                               Macro                             --
; ---------------------------------------------------------------------


DOS	macro			; der  alte  Macro  mu_  ersetzt
	move.l	a5,a6		; werden, da ja die DOS-Library-Base
	jsr	_LVO\1(a6)		; an anderer Stelle (a5) vermerkt ist.
	endm


; ---------------------------------------------------------------------
; --                     DOS-Library vffnen                          --
; ---------------------------------------------------------------------

_main	lea.l	DosName(pc),a1		; DOS-Library
	moveq.l	#33,d0		; ab Kickstart 1.2
	CALLEXEC	OpenLibrary		; vffnen
	move.l	d0,a5
	tst.l	d0
	beq.s	.Error		; Fehler !
	bsr	MAIN		; Hauptprogramm ausf|hren
	move.l	d0,-(sp)
	move.l	a5,a1		; DOS-Library wieder schlie_en
	CALLEXEC	CloseLibrary
	move.l	(sp)+,d0
	rts

Error	moveq.l	#20,d0
	rts

DosName	DOSNAME


; ---------------------------------------------------------------------
; --                          Hauptprogramm                          --
; ---------------------------------------------------------------------

MAIN	move.l	#DOSTRUE,d0
	bsr	GoRAW		; CON in RAW-Modus umwandeln
Loop	DOS	Input
	subq.l	#2,sp		; Puffer (2 Byte) anlegen
	move.l	d0,d1
	move.l	sp,d2
	moveq.l	#1,d3
	DOS	Read		; 1 Zeichen lesen (=auf ein Tastendruck warten)
	addq.l	#2,sp		; Stack wieder korrigieren
	DOS	Input
	move.l	d0,d1
	moveq.l	#1,d2		; noch weitere Zeichen im Puffer ?
	DOS	WaitForChar
	tst.l	d0	
	bne.s	.Loop		; gegebenenfalls weitere Zeichen auslesen
				; sonst stvren sie bei der spdteren Eingabe
	move.l	#DOSFALSE,d0
	bsr	GoRAW		; zur|ck in CON-Modus
	moveq.l	#0,d0
	rts


; ---------------------------------------------------------------------
; --                            GoRAW                                --
; ---------------------------------------------------------------------
; -- Enthdlt D0 DOSTRUE (-1) ,versetzt GoRAW die Console in den RAW- --
; -- Modus bei DOSFALSE (0) hingen versetzt GoRAW die Console zur|ck --
; -- in den CON-Modus. Bei einem Fehler ist d0 0.                    --
; ---------------------------------------------------------------------

	IFND	ACTION_SCREEN_MODE
ACTION_SCREEN_MODE	equ	994
	ENDC

GoRAW	movem.l	d7/a2-a5,-(sp)		; Register retten
	move.l	d0,d7		; Modus retten
	sub.l	a1,a1
	CALLEXEC	FindTask		; Zeiger auf eigenen Task
	move.l	d0,a0
	move.l	pr_ConsoleTask(a0),a2	; ID der zugehvrigen Console

	sub.l	a0,a0		; Reply-Port erzeugen
	moveq.l	#0,d0
	bsr	CreatePort
	tst.l	d0		; Fehler ?
	beq	.Label1
	move.l	d0,a3		; Zeiger auf Reply-Port retten

	bsr	CreatePacket		; StandardPacket erzeugen
	tst.l	d0		; Fehler ?
	beq.s	.Label2
	move.l	d0,a4
	move.l	a3,sp_Pkt+dp_Port(a4)	; Reply-Port eintragen

	move.l	d7,sp_Pkt+dp_Arg1(a4)	; Modus eintragen
	move.l	#ACTION_SCREEN_MODE,sp_Pkt+dp_Type(a4)	

	move.l	a4,a1		; Zeiger auf Packet
	move.l	a2,a0		; Zeiger auf Port
	CALLEXEC	PutMsg

Label5	move.l	a3,a0		; auf Reply warten
	CALLEXEC	WaitPort	

	move.l	a3,a0		; Reply-Message holen
	CALLEXEC	GetMsg
	tst.l	d0		; doch keine Message ?
	beq.s	.Label5
	moveq.l	#1,d0		; kein Fehler

Label3	move.l	d0,-(sp)
	move.l	a4,a0
	bsr	DeletePacket		; Standard-Packet lvschen
	move.l	(sp)+,d0

Label2	move.l	d0,-(sp)
	move.l	a3,a0
	bsr	DeletePort		; Reply-Port lvschen
	move.l	(sp)+,d0

Label1	movem.l	(sp)+,d7/a2-a5
	rts




; ---------------------------------------------------------------------
; --                           CreatePacket                          --
; ---------------------------------------------------------------------
; -- CreatePacket erzeugt ein StandardPacket,Message- und DosPacket- --
; -- Teil werden verbunden. In d0/a0 wird er Zeiger zur|ckgeben,bzw. --
; -- 0 bei einen Fehler.                                             --
; ---------------------------------------------------------------------


CreatePacket	moveq.l	#sp_SIZEOF,d0		; Speicher f|r StandardPacket reservieren
	move.l	#MEMF_PUBLIC!MEMF_CLEAR,d1
	CALLEXEC	AllocMem
	tst.l	d0
	beq.s	.Label1
	move.l	d0,a0	
	lea.l	sp_Pkt(a0),a1		; Zeiger auf Packet-Teil
	move.l	a1,sp_Msg+LN_NAME(a0)	; Node-Namen mu_ auf Packet-Teil zeigen
	move.l	a0,sp_Pkt+dp_Link(a0)	; DosPacket-Link mu_ auf Message-Teil zeigen
Label1	rts	

; ---------------------------------------------------------------------
; --                           DeletePacket                          --
; ---------------------------------------------------------------------
; -- DeletePacket  lvscht ein   zuvor   mit  CreatePacket  erzeugtes --
; -- StandardPacket. Als Parameter  wird  in A0 der  Zeiger auf  das --
; -- StandardPacket erwartet.                                        --
; ---------------------------------------------------------------------

DeletePacket	moveq.l	#0,d0
	cmp.l	d0,a0		; 0-Zeiger abfangen !
	beq.s	.NIL
	move.l	a0,a1
	moveq.l	#sp_SIZEOF,d0		; Speicher freigeben
	CALLEXEC	FreeMem
NIL	rts


; ---------------------------------------------------------------------
; --                          CreatePort                             --
; ---------------------------------------------------------------------
; -- CreatePort erzeugt einen  funktionsfdhigen   Msg-Port  des Typs --
; -- PA_SIGNAL mit der Prioritdt von D0.A0 zeigt auf den Port-Namen, --
; -- der nicht kopiert  wird. Falls A0 0  ist, wird er nicht in  die --
; -- Liste vffentlicher  Ports   aufgenommen.  Als SigTask wird  der --
; -- eigene eingetragen. Der Funktionswert in D0 ist  der Zeiger auf --
; -- auf den Port oder bei einem Fehler 0 .                          --
; ---------------------------------------------------------------------


CreatePort	move.l	a2,-(sp)
	movem.l	d0/a0,-(sp)		; retten
	moveq.l	#MP_SIZE,d0		; Speicher f|r Port reservieren
	move.l	#MEMF_PUBLIC!MEMF_CLEAR,d1
	CALLEXEC	AllocMem
	tst.l	d0
	beq.s	.NoMem
	move.l	d0,a2
	moveq.l	#-1,d0		; Signal belegen
	CALLEXEC	AllocSignal
	move.b	d0,MP_SIGBIT(a2)
	bmi.s	.FreeMem		; kein Signal 
	movem.l	(sp)+,d0/a0
	move.b	d0,MP+LN_PRI(a2)	; Prioritdt eintragen
	move.b	#NT_MSGPORT,LN_TYPE(a2)
	move.l	a0,MP+LN_NAME(a2)	; Name
	sub.l	a1,a1
	CALLEXEC	FindTask
	move.l	d0,MP_SIGTASK(a2)	; eigener Task als Signal-Empfdnger
	lea.l	MP_MSGLIST(a2),a0
	move.b	#NT_MESSAGE,LH_TYPE(a0)	; Messages werden verwaltet
	bsr	NewList
	tst.l	MP+LN_NAME(a2)		; vffentlicher Port ?
	beq.s	.Private
	move.l	a2,a1
	CALLEXEC	AddPort		; Port in allgemeine Liste eintragen
Private	move.l	a2,d0
	move.l	(sp)+,a2
	rts

FreeMem	move.l	a2,a1
	moveq.l	#MP_SIZE,d0		; Speicher freigeben
	CALLEXEC	FreeMem
NoMem	addq.l	#8,sp
	move.l	(sp)+,a2
	moveq.l	#0,d0		; Fehler !
	rts

; ---------------------------------------------------------------------
; --                            NewList                              --
; ---------------------------------------------------------------------
; -- NewList initialisiert eine LIST-Struktur, A0 mu_ auf die LIST-  --
; -- Struktur zeigen.                                                --
; ---------------------------------------------------------------------

NewList	move.l	a0,LH_HEAD(a0)		; LH_HEAD mu_ auf LH_TAIL zeigen
	addq.l	#LH_TAIL,(a0)
	clr.l	LH_TAIL(a0)		; LH_TAIL mu_ auf  0 zeigen
	move.l	a0,LH_TAILPRED(a0)
	rts

; ---------------------------------------------------------------------
; --                         DeletePort                              --
; ---------------------------------------------------------------------
; -- DeletePort lvscht einen zuvor mit CreatePort erzeugten MsgPort. --
; -- Als Parameter wird in A0 der Zeiger auf den Port erwartet.Noch  --
; -- ausstehende Messages werden zuvor reply-t.                      --
; ---------------------------------------------------------------------

DeletePort	move.l	a2,-(sp)
	move.l	a0,a2		; Zeiger retten
	CALLEXEC	Forbid		; Multitasking unterbinden
Loop	move.l	a2,a0
	CALLEXEC	GetMsg		; Msg holen
	tst.l	d0		; keine (weitere) Message mehr
	beq.s	.AllReplied
	move.l	d0,a1
	CALLEXEC	ReplyMsg		; Message reply-en
	bra.s	.Loop
AllReplied	move.l	MP+LN_NAME(a2),d0	; vffentlicher Port ?
	beq.s	.Private
	move.l	a2,a1
	CALLEXEC	RemPort		; entfernen
Private	move.b	MP_SIGBIT(a2),d0
	CALLEXEC	FreeSignal		; Signal freigeben
	move.l	a2,a1		; Speicher freigeben
	moveq.l	#MP_SIZE,d0
	CALLEXEC	FreeMem
	CALLEXEC	Permit		; Multitasking wieder erlauben
	move.l	(sp)+,a2
	rts

; ---------------------------------------------------------------------
; --                           CLIText                               --
; ---------------------------------------------------------------------
; -- CLIText gibt den mit einem $00-Byte  abgeschlossen Text (Zeiger --
; -- in A0) im CLI-Window aus.                                       --
; ---------------------------------------------------------------------

CLIText	movem.l	d2/d3,-(sp)		; Register retten
	move.l	a0,d2		; Zeiger nach D2
	moveq.l	#-1,d3		; Ldnge ermitteln
Label	addq.l	#1,d3
	tst.b	(a0)+
	bne.s	.Label
	DOS	Output		; Handle f|rs CLI-Fenster
	move.l	d0,d1
	DOS	Write		; Text ausgeben
	movem.l	(sp)+,d2/d3
	rts

; ---------------------------------------------------------------------
; --                          GetLong                                --
; ---------------------------------------------------------------------
; -- GetLong |bersetzt den ASCII-String (Zeiger in A0)  in ein Long- --
; -- Word, welches in D0 zur|ckgeben wird. Anschlie_end zeigt A0 auf --                                                      --
; -- das erste Zeichen nach der Zalh im String.  Enthdlt D1  0, trat --
; -- kein Fehler auf. 1 signalisiert einen \berlauf, -1 zeigt  einen --
; -- Fehler im Aufbau  an. Unterst|tzt werden  das  dezimale und das --
; -- hexadezimale ("$")  Zahlensystem.                               --
; ---------------------------------------------------------------------

GetLong	movem.l	d3-d3/a1-a3,-(sp)	; Register retten
	bsr.s	.Main
	movem.l	(sp)+,d3-d3/a1-a3
	rts

Main	moveq.l	#0,d0		; Register lvschen
	moveq.l	#0,d1
	moveq.l	#0,d2
Label1	move.b	(a0)+,d3		; Spaces und Tabs |berlesen
	cmp.b	#" ",d3
	beq.s	.Label1
	cmp.b	#9,d3
	beq.s	.Label1

	cmp.b	#"$",d3		; hexadezimal ?
	beq	.Hex
	cmp.b	#"-",d3		; negativ ?
	beq.s	.Negativ
	cmp.b	#"9",d3		; Ziffer ?
	bhi	.Fehler
	cmp.b	#"0"-1,d3
	bhi	.Dezimal

Fehler	subq.l	#1,a0		; ^Fehler
	moveq.l	#-1,d1		; Fehlercode
	rts

Negativ	tst.b	d2		; teste,ob bereits ein "-"
	bne.s	.Fehler
	moveq.l	#1,d2		; Flag f|r negativ seten
	bra	.Label1




Dezimal	subq.l	#1,a0		; A0 auf erste Ziffer setzen
	move.l	a0,a1		; A1 ^erstes Ziffer
Label_D2	move.b	(a0)+,d3		; ndchste Zeiffer holen 
	cmp.b	#"9",d3		; wiederhole, bis Zahlenende
	bhi.s	.Label_D3		; erreicht wird.
	cmp.b	#"0"-1,d3
	bhi.s	.Label_D2

Label_D3	lea.l	.Data10(pc),a2		; Zeiger auf 10'er-Potenzen
	subq.l	#1,a0		; A0 ^letzte Ziffer+1
	move.l	a0,a3		; A3 ^letzte Ziffer+1 

Label_D5	move.l	(a2)+,d4		; Stellenzahl holen
	beq.s	.Overflow		; Longwordgrenze |berschritten ?
	moveq.l	#0,d3		; D3 lvschen
	move.b	-(a3),d3		; vorherige Ziffer holen
	sub.b	#"0"+1,d3		; und in Zahl umwandeln (1 abziehen wegen DBRA-Schleife)
	bmi.s	.D_Zero		; Ziffer "0" abfangen
Label_D4	add.l	d4,d0		; Stellenzahl so oft wie Ziffer addieren
	dbra	d3,.Label_D4
D_Zero	cmp.l	a3,a1		; Zahlenanfang erreicht ?
	bne.s	.Label_D5

Vorzeichen	tst.b	d2		; negatives Vorzeichen ?
	beq.s	.NotNegative
	tst.l	d0		; Ist die Zahl grv_er als ein Longint ?
	bmi	.Overflow
	neg.l	d0		; negativieren
NotNegative	moveq.l	#0,d1		; keine Fehler
	rts

Data10	dc.l	1
	dc.l	10
	dc.l	100
	dc.l	1000
	dc.l	10000
	dc.l	100000
	dc.l	1000000
	dc.l	10000000
	dc.l	100000000
	dc.l	1000000000
	dc.l	0

Overflow	moveq.l	#1,d1		; \berflu_ (Zahl zu gro_ !)
	rts
		




Hex	move.b	(a0)+,d3		; erste Stelle OK ?
	bsr.s	.Nibble
	bmi	.Fehler		; Fehler !


	lea.l	-1(a0),a1		; A1 ^ erste Ziffer
Label_H2	move.b	(a0)+,d3
	bsr.s	.Nibble		; in Hexa-Ziffer |bersetzen 
	bpl.s	.Label_H2
	subq.l	#1,a0		; A0 ^letzte Ziffer+1
	move.l	a0,a2		; A2 ^letzte Ziffer+1
	moveq.l	#0,d1
Label_H3	move.b	-(a2),d3		; vorherige Ziffer
	bsr	.Nibble
	lsl.l	d1,d4		; Nibble an richtige Position schieben
	add.l	d4,d0		; zum Ergebnis addieren
	addq.l	#4,d1
	cmp.b	#32,d1		; 32. Bit erreicht ?
	bhi	.Overflow		; wenn ja, Overflow !
	cmp.l	a2,a1		; Zahlenanfang erreicht ?
	bne.s	.Label_H3
	bra	.Vorzeichen

Nibble	moveq.l	#0,d4
	cmp.b	#"a"-1,d3		; Ziffer d3 -> Zahl d4
	bls.s	.N1		; Upcase
	cmp.b	#"f",d3
	bhi.s	.N_Error
	sub.b	#"a"-"A",d3
N1	sub.b	#"0",d3
	cmp.b	#9,d3		; Ziffer ?
	bls.s	.Ziffer
	sub.b	#"@"-"9",d3		; Buchstabe
	cmp.b	#$f,d3
	bhi.s	.N_Error
Ziffer	move.b	d3,d4
	rts
N_Error	moveq.l	#-1,d4		; Fehler !
	rts
	


