← ST-Magazin 01 / 1992

Eine heiße Sache: Hotkey!

Expertenforum

Wer schon einmal mit PCs gearbeitet hat, kennt sie: Hotkeys — Tastenkombinationen, mit denen sich langwierige Mausaktionen auf einen Wimpernschlag reduzieren lassen.

Short-Cuts haben leider den Nachteil, daß sie nur während der Laufzeit eines Programms abrufbar sind. Es gibt nur wenige pro-grammübergreifende Utilities. Dabei handelt es sich zum größten Teil um Accessories, die über einen »evnt_button« Sondertasten abfragen. Da die Anzahl dieser Tasten begrenzt ist (zwei Shift-, eine Alternate und eine Control-Taste), kommt es leicht zu Kollisionen. Will man z.B. eine Kompilierung mit Shift-Shift unterbrechen, kann es passieren, daß gleichzeitig auch die Festplatte parkt.

Scan-Code und Sondertasten

Wir stellen hier ein Programm vor, das eigene Funktionen auf beliebige Tastenkombinationen legt — soweit es der ST/TT eben gestattet. Jede Routine ist unabhängig von den anderen Programmteilen lauffähig und kann in eigene Programme eingebunden werden. Dazu hängt man zuerst den Assemblersource an HOTKEY. Dann trägt man in der Tabelle »HOTKEYS« den Tastencode ein. Für Experten: Es handelt sich um das obere Wort, das Bconin(2) bei gesetztem 3. Bit in conterm zurückgibt, also Sondertasten und Scancode. Man beachte dabei die Endmarke Null. Außerdem wird in der Tabelle »ROUTINEN« — dort, wo der Tastencode steht — die Adresse der neuen Routine eingefügt.

Ein Tastendruck löst nun einen (ACIA-) Interrupt aus. Dabei werden die Informationen zu dieser Taste (Sondertasten, Scan- und ASCII-Code) ermittelt. Dies geschieht in einem Ringspeicher mit der Funktion Iorec (XBIOS(14,1)). Bleibt die Taste über längere Zeit gedrückt, setzt die Tastenwiederholung ein. In diesem Fall werden die Tasten-Informationen nicht im ACIA-Interrupt gespeichert, sondern im Timer C, einem 200-Hz-Zähler.

Nun speichert das Programm die Adresse der Iorec-Struktur. Bei der Installation von Hotkey werden die Vektoren des ACIA-Interrupts und Timer C auf die eigenen Routinen gebogen. Schließlich wird das Programm resident verlassen, d.h. es bleibt im Speicher. Jeder Tastendruck führt dann in eine eigene Routine, die zuerst mal alle Register rettet. Dann holt sie sich die Position des Schreibzeigers aus der Iorec-Struktur. Nachdem eine der Originalroutinen aufgerufen wurde, vergleicht das Programm die nun alte Position des Schreibzeigers mit der aktuellen. Differieren sie, hat der Zeiger sich also bewegt, wurde eine Taste gedrückt und deren Tastencode im Ringspeicher abgelegt. Der für uns relevante Teil — das obere Wort — wird aus dem Buffer gelesen und mit den in Tabelle Hotkey aufgeführten Werten verglichen. Wird beim Vergleich die Endmarke Null erreicht, handelt es sich nicht um einen Hotkey — der Tastendruck wird ignoriert. Andernfalls wird die Taste aus dem Buffer gelöscht. Ist die entsprechende Routine ausgeführt, werden alle Register restauriert und die Exception mit einem RTE verlassen.

Leider kann man nicht alle Utilities in Hotkey installieren. Das fangt bei TOS-Programmen an, die ja GEM nicht nutzen. Auch bei TOS-Routinen ist Vorsicht geboten! TOS ist nicht reentrant. Auch GDOS scheint sich mit Hotkey nicht ganz zu vertragen: Startet man beide im AUTO-Ordner, führt dies zum Absturz. (mn)

; ********************************* ; * HOTKEY * ; * * ; * by Michael Krusemark * ; * Ravensburger Str.44 * ; * 7900 Ulm - 11 * ; ********************************* RSHT EQU $0100 ; Codes der Sondertasten LSHT EQU $0200 ; müssen auf Scancode CNTR EQU $0400 ; addiert werden ALT EQU $0800 BUF EQU 0 ; Offsets der SIZ EQU 4 ; lorec-Structur TL EQU 8 START: pea LOGO(PC) ; Logo move.w #9,-(SP) ; mit Cconws trap #1 ; ausgeben addq.l #6,SP move.w #1,-(SP) ; Iorec für Tastatur move.w #$0E,-(SP) ; holen trap #14 addq.l #4,SP move.l D0,IOREC ; Adresse der Struktur sichern pea INSTALL(PC) ; Hotkey move.w #$26,-(SP) ; im Supervisor-Modus trap #14 ; installieren addq.l #6,SP clr.w -(SP) ; HOTKEY resident move.l #ENDE-START+256,-(SP) move.w #$31,-(SP) ; verlassen trap #1 INSTALL: lea HZ200(PC),A0 ; Vektor für lea $0114,A1 ; Timer C move.l (A1),(A0)+ ; (200 Hz Zähler) move.l A0,(A1) ; verbiegen lea ACIA(PC),A0 ; das gleiche lea $0118,A1 ; auch mit move.l (A1),(A0)+ ; dem move.l A0,(A1) ; ACIA-Interrupt rts ; HOTKEY ist nun installiert DC.L 'XBRA' ; XBRA-Protokoll DC.L 'HTKY' ; ID ACIA: DS.L 1 ; alter ACIA-Vektor movem.l D0-A6,-(SP) ; Register retten movea.l IOREC(PC),A0 ; Adresse von Iorec der Tastatur move.w TL(A0),D3 ; altes Tail movea.l ACIA(PC),A1 ; Adresse der orginal ACIA-Routine bra.s EXCEPT ; Exception simulieren DC.L 'XBRA’ ; XBRA-Protokoll DC.L 'HTKY' ; ID von HoTKeY HZ200: DS.L 1 ; alter Timer C-Vekior movem.l D0-A6,-(SP) ; regiser retten movea.l IOREC(PC),A0 ; Adresse von Iorcc move.w TL(A0,D3 ; altes Tail movea.l HZ200(PC),A1 ; Adresse der orginal Timer-Routine bset #3,$0484.w ; Sondertasten beachten EXCEPT: pea WEITER(PC) ; Rücksprungadrcsse move SR,-(SP) ; Statusregister pea (A1) ; Exception rts ; simulieren WEITER: move.w TL(A0),D0 ; neues Tail cmp.w D0,D3 ; gleich altes Tail beq.s EXIT ; dann wurde nichts eingegeben movea.l BUF(A0),A1 ; Adresse des Ringbuffers move.w 0(A1,D0.w),D1 ; Zeichen holen lea HOTKEYS(PC),A2; Tabelle der Hotkeys lea ROUTINEN(PC),A1; Tabelle der Routinen SEARCH: movea.l (A1)+,A3 ; Sprungadresse move.w (A2)+,D2 ; Hotkey aus Tabelle beq.s EXIT ; Endmarke?, dann raus sub.w D1,D2 ; wenn nicht gleich, bne.s SEARCH ; dann weiter suchen move.w D3,TL(A0) ; Zeichen aus Buffer löschen jsr (A3) ; Zeichen war Hotkey, also springen EXIT: movem.l (SP)+,D0-A6 ; Register restaurieren rte ; ReTurn from Exception BLACK: bchg #0,$FFFF820A.w ; Monitor an/aus rts HDPARK: st $043E.w ; Flock setzen bne.s HAVE_PARKED ; Flock!=0, dann HD nicht parken moveq #20,D7 ; Zeit für Timeout lea $FFFF8604.w,A0 ; disketr move.w #$88,2(A0) ; DMA-Betrieb move.l #$1B0088,(A0) ; (START/)STOP-UNIT bsr.s WARTE ; Claus Brod's Zeiteisen move.w #2,D3 ; 3X 0L auf DMA WR_CMD: move.l #$8A,(A0) ; ausgeben bsr.s WARTE ; und wieder warten dbra D3,WR_CMD move.l #$8A,(A0) ; STOP-UNIT bsr.s WARTE ; schon wieder warten move.l #$0A,(A0) ; jetzt geht's bei der HD erst los move.l #800,D7 ; deshalb lassen wir ihr bsr.s WARTE ; jetzt etwas mehr Zeit HAVE_PARKED: clr.w $043E.w ; Flock löschen rts ; HD müßte geparkt sein WARTE: add.l D7,D0 ; Zeit bis Timeout WAIT: btst #5,$FFFFFA01.w ; HDC-lnterrupt? beq.s READY ; ja, dann fertig cmp.l $04BA.w,D0 ; Zeit abgelaufen? bne.s WAIT ; nein, dann noch warten addq.l #4,SP ; TIMEOUT, es stimmt was nicht bra.s HAVE_PARKED ; dann lassen wir 's besser READY: rts ; kein Timeout WARM: movea.l $04F2.w,A0 ; OS-Start jmp (A0) ; in Reset springen ; Warmstart KALT: clr.w $0420.w ; ein Magic löschen movea.l $04F2.w,A0 ; OS-Start jmp (A0) ; Reset (Kaltstart) CHANGEHZ: bchg #1,$FFFF820A.w rts INVERS: bchg #0,$FFFF8240.w rts DATA ; Tabelle der Hotkeys HOTKEYS: DC.W CNTR+ALT+25 ; ^ALT P DC.W CNTR+ALT+48 ; ^ALT B DC.W CNTR+ALT+83 ; ^ALT Delete DC.W CNTR+ALT+RSHT+83 ; ^ALT RShift Delete DC.W CNTR+ALT+46 ; ^ALT C DC.W CNTR+ALT+23 ; ^ALT+I ; Sondertaste+Scancode DC.W 0 ; Endmarke ; Tabelle der Routinen ROUTINEN: DC.L HDPARK,BLACK,WARM,KALT,CHANGEHZ,INVERS LOGO: DC.B 13,10 DC.B '************************************ ' ,13,10 DC.B '* HOTKEYS installiert * ' ,13,10 DC.B '* by Michael Krusemark * ' ,13,10 DC.B '* Ravensburger Str.44 * ' ,13,10 DC.B '* 7900 Ulm-11 * ' ,13,10 DC.B '************************************ ' ,13,10, 0 BSS IOREC: DS.L 1 ENDE: END
Michael Krusemark