Eine heiße Sache: Hotkey!

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
Links

Copyright-Bestimmungen: siehe Über diese Seite