EXTKEY: Tastaturbelegung einmal anders (Assembler)

Schon wieder ein Programm, mit dem die Tastaturbelegung geändert werden kann, werden Sie vielleicht fragen. Dieses arbeitet allerdings etwas anders als üblich und ist auch anders programmiert. Der Interrupt-Programmierer wird hoffentlich einige Anregungen finden.

Die meisten Programme dieser Art legen die sonst nicht erreichbaren Sonderzeichen des ATARI-Zeichensatzes auf bestimmte Tastenkombinationen mit ALT, CTRL, usw. oder schalten die Tastatur komplett um. Das hat den Nachteil, daß man Tastaturbelegungstabellen im Kopf oder vor sich liegen haben muß.

Viele Zeichen kann man sich aber aus zwei anderen zusammengesetzt denken, so z.B. die Buchstaben mit Akzenten (á, à, usw.). Quasi durch Zusammensetzen kann man solche Zeichen mit dem Programm EXTKEY auf den Bildschirm bringen. Dazu gibt man zunächst das “Hauptzeichen” (z.B. ‘a’) ein, danach drückt man CTRL zusammen mit dem “Nebenzeichen” (z.B. CTRL-'~’), und schon sieht man ein ‘ã’ vor sich. Bei geshifteten Nebenzeichen muß SHIFT-CTRL betätigt werden (z.B. ergeben 'i' und SHIFT-CTRL-’^’ ein î).

Dieses Verfahren bietet sich auch bei einigen mathematischen Symbolen an. Mit EXTKEY sind alle Zeichen, die in Tabelle 1 stehen, auf diese Weise erreichbar (zu jedem Nebenzeichen sind die erzeugbaren Sonderzeichen angegeben)

´           : á, é, í, ó, ú, É
`           : à, è, ì, ò, ù, À
^ (Dach)    : â, ê, î, ô, û
: (Doppelp.): ä, ë, ï, ö, ü, ÿ, Ä, Ö, Ü
~ (Tilde)   : ã, ñ, õ, Ã, Ñ, Õ
BACKSPACE   : æ, ÿ,  , Æ, Y (Hauptzeichen sind a,i,o,..)
, (Komma)   : ç, Ç   
. (Punkt)   : å, Å   
/           : |, \   
- (Minus)   : £, Ø   
_ (Unterst.): ±, =, ä , a , a

Tab. 1: Diese Zeichen sind durch EXTKEY auf einfache Art und Weise zu erreichen

Damit dürfte das Schreiben in Fremdsprachen zum Kinderspiel werden. Die anderen Zeichen, bei denen mir keine Idee kam, wie man sie zusammensetzen könnte, sind über ALT oder SHIFT-ALT in Kombination mit “normalen” Tasten erreichbar. Dabei wurde auf eine sinnvolle Belegung geachtet, aber hier hat ja jeder seine eigenen Ansichten, was vernünftig ist.

EXTKEY läuft problemlos mit WORDPLUS, TEMPUS, MEGAMAX-Editor, GFA-BASIC (Input-Befehl) und sogar mit TEMPELMON. Auch in GEM-Dialogboxen gibt es keine Schwierigkeiten.

Bei Programmen, die bestimmte Tastenkombinationen für eigene Zwecke benutzen (wie etwa TEMPUS), “gewinnt” EXTKEY. Um trotzdem vernünftig arbeiten zu können, kann EXTKEY mit ALT-SHIFT-SHIFT ab- und wieder angeschaltet werden. Auch läuft EXTKEY mit allen TOS-Versionen, da keine unsauberen Zugriffe auf nicht-dokumentierte Systemvariablen gemacht werden.

Nun noch ein paar Worte zum Programm selbst:

Das Programm ist voll relokatibel geschrieben, kann also leicht in andere Programme eingebaut werden.

In der Initialisierungsroutine ‘alt_init’ wird EXTKEY im System installiert. Dazu wird der Vektor ‘ikbdsys’ verbogen, und das Programm wird resident im Speicher installiert.

In der ‘ikbdsys'-Routine wird ein vom Tastaturprozessor ausgelöster Interrupt analysiert, wobei dann in die Routinen für Maus-, Tastatur- und Joystick-Behandlung verzweigt wird.

Die ‘ikbdsys’-Routine von EXTKEY (‘kbdrv’) besorgt sich zuerst die Adresse des BIOS-Tastaturpuffers mit der XBIOS-Funktion ‘Iorec’ und merkt sich die Position des ersten Zeichens. Dann wird die Original-ikbdsys-Routine aufgerufen, die nun erst einmal die Hauptarbeit macht. Danach wird überprüft, ob ‘ikbdsys’ etwas in den Tastaturpuffer geschrieben hat. Wenn dies der Fall ist, kann EXTKEY aktiv werden.

ASCII- und Scan-Kode werden untersucht. Ein mit ALT oder ALT-SHIFT erreichtes Zeichen wird einfach über das eingegebene Zeichen in den Tastaturpuffer geschrieben.

Bei der Zusammensetzung mit CTRL wird das eingetippte Nebenzeichen durch ein Backspace ersetzt und das auszugebende Zeichen im Tastaturpuffer angefügt. Da wohl jedes Programm BACKSPACE richtig vergeht, wird es das Hauptzeichen löschen und durch das Sonderzeichen ersetzen.

Damit es keine Konfusionen gibt, müssen Haupt- und Nebenzeichen unmittelbar nacheinander eingegeben werden, sonst wird die Eingabe von EXTKEY ignoriert.

Ein Problem ergab die automatische Tastenwiederholung. Sie wird von einer anderen Interrupt-Routine erledigt (Systemtimer). Da die BIOS-Tastatur-Routine hier bestimmte Variablen setzt, die legal nicht zugänglich sind, würde die Wiederholfunktion falsche Zeichen wiederholen. Daher wird die Tastenwiederholung bei den durch EXTKEY erreichbaren Sonderzeichen abgeschaltet. Bei den normalen Zeichen wird sie wieder aktiviert, dies allerdings immer. Diese Einschränkung dürfte aber nicht allzu gravierend sein.

Wer schon einmal in einer Interrupt-Routine BIOS-Aufrufe gemacht hat, wird sein blaues Wunder erlebt haben. Schuld daran ist ein Fehler im BIOS, der aber umgangen werden kann.

Die Systemvariable ‘savptr’ ($4a2) zeigt auf einen Stack (wächst nach unten), auf dem das BIOS bei jedem Aufruf Prozessor-Register ablegt. Dadurch ist das BIOS “reentrant”, d.h. es kann aus sich selbst heraus auf gerufen werden. Während des Rettens der Register werden die Interrupts allerdings nicht gesperrt, daher kann es passieren, daß bei BIOS-Aufrufen im Interrupt schon gerettete Register in dieser “save area” überschrieben werden.

Eine Möglichkeit, dies zu umgehen, besteht darin, den ‘savptr’ zu Beginn der eigenen Interrupt-Routine herunterzusetzen und am Ende wieder zurück. Dies kann aber zu Konflikten mit anderen Programmen führen, die ebenfalls den ‘savptr’ manipulieren. Eine bessere Möglichkeit (Dank an Thomas!) ist, für die Dauer des Interrupts eine eigene save area einzurichten. Er braucht theoretisch nur für einen BIOS-Aufruf auszureichen, wenn es keine weiteren Verschachtelungen gibt. Sicherheitshalber wurde hier Platz für zwei Aufrufe gelassen. Wenn alle Programme nach diesem Schema verfahren, sollte es keine Komplikationen wie “Programm “A läuft nicht mit Programm B" geben. Zum Aufbau der Tabelle, die das Zusammensetzen steuert (vergleiche Listing).

Dem Scancode des Nebenzeichens folgen ASCII-Codes für Hauptzeichen und Sonderzeichen (immer abwechselnd). Diese Folge wird durch ein Nullbyte beendet. Dann folgt der nächste Nebenzeichen-Scancode usw. Ganz am Ende sind zwei Nullbytes.

;Extended Keyboard macht gesamten 
;Atari-Zeichensatz über ALT und CTRL zugänglich 
;Tastenbelegung nach Tabellen im Programm
;
;Version 1.2 
;15.2.1988 
;(C) A.Esser
;

;Systemvariablen 
conterm = $484 
savptr * $4a2

;BIOS-FunKtionen 
kbshift = 11

;XBIOS-Funktionen 
iorec    = 14 
kbdvbase = 34
supexec  = 38

;GEMDOS-Funktionen 
cconws   = $09 
ptermres = $31

;Struktur des I/O-Puffer 
IBUF    = 0 
IBUFSIZE= 4 
IBUFHD  = 6 
IBUFTL  = 8

;Struktur KBDVECS 
IKBDSYS = 32

;Konstanten
SAVSIZE * $2e ;Größe des BIOS-Save-Bereichs

    bra     alt_init    ;installieren
kbdrv:
    lea     tsavp,A0    ;BIOS-savptr merken
    move.l  savptr,(A0)
    lea     endarea,A0  ;und auf eigenen Bereich umsetzen
    move.l  A0,savptr   ;ermöglicht BIOS-Aufrufe im Interrupt 

    move.w  #1,-(A7)    ;IOREC für Tastatur holen
    move.w  #iorec,-(A7)
    trap    #14
    addq.w  #4,A7

    move.l  D0,A0
    move.w  IBUFTL(A0),-(A7) ;alten Tai1-Index merken
    move.l  A8,-(A7)         ;IOREC-Zeiger merken
    move.l  oldvec,A0        ;zuerst Standard-IKBD-Routine ausführen 
    jsr     (A0)             ;setzt uoraus, daß keine Parameter auf Stack

    move.w  #-1,-(A7)
    move.w  #kbshift,-(A7)  ;Tastenstatus holen nach D0
    trap    #13
    addq.w  #4,A7

    move.l  (A7)+,A1         ;IOREC-Zeiger zurück
    move.w  IBUFTL(A1),D2    ;neuer Tail Index
    cmp.w   (A7)+,D2         ;mit altem vergleichen
    beq     nokey            ;-> keine neue Taste registriert
    move.b  activ,D1
    bne     finis            ;-> EXTKEY abgeschaltet

    move.l  IBUF(A1),A2      ;Zeiger auf IO buffer
    move.l  0(A2,D2.w),D1    ;letzte Taste (ASCII in 0-7, Scan in 16-23)
    move.l  D1,D3
    move.w  D0,D3
    swap    D3               ;Scan-Code nach 0-7, Status nach 16-23 
    cmp.b   #$78,D3          ;spez. ALT-Scan Code (für 1..0.ß,') ? 
    bcs.s   kbdrv1           ;-> nein
    sub.b   #$76,D3          ;umrechnen auf norm. Scan-Codes

kbdrv1:
    ext.w   D3               ;Bit 8-15 (evtl. Tasten-Status) löschen 
    and.b   #$03,D0          ;L-Shift oder R-Shift ?
    beq.s   kbdrv2           ;-> nicht gedrückt
    bset    #7,D3            ;"geshifteter Scan-Code"
kbdrv2:
    btst    #19,D3
    beq.s   no_alt           ;-> ALT nicht gedrückt
    lea     altt,A0
    move.b  0(A0,D3.w),D1    ;Ersatzzeichen aus Tab. für ALT holen 
    bra.s   store            ;und fertig
no_alt:
    btst    #18,D3
    beq.s   regis            ;-> auch kein CTRL: EXTKEY tut nichts
    lea     ctrlt,A0
look1:                       ;CTRL-Zeichen in TAB suchen
    move.b  (A0)+,D0
    beq.s   regis            ;-> kein gültiges CTRL-2eichen
    cmp.b   D0,D3
    beq.s   look4            ;-> gefunden
look2:
    tst.b   (A0)+,D0         ;Infos zu diesem CTRL überlesen
    bne.s   1ook2
    bra.s   look1
look3:                       ;letztes Zeichen umwandelbar?
    addq.l  #1,A0            ;Ersatzzeichen überlesen
1ook4:
    move.b  (A0)+,D0
    beq.s   regis            ;-> CTRL bei diesem Zeichen nicht möglich
    cmp.b   lastc,D0
    bne.s   look3
    move.b  (A0),D1          ;Ersatzzeichen (erst bei 'store' geschrieben) 
    bclr    #26,D1           ;CTRL-Bit löschen
    move.l  #$0E0008,0(A2,D2.W) ;altes Zeichen durch Backspace ersetzen 
    addq.w  #4,D2            ;Tail-Index erhöhen
    emp.w   IBUFSIZE(A1),D2  ;Wrap around
    bcs.s   look5
    moveq   #0,D2
1ook5:
    cmp.w   IBUFHD(A1),D2    ;Puffer voll ?
    beq.s   regis            ;-> Abbruch (passiert normalerweise nicht) 
    move.w  D2,IBUFTL(A1)    ;neuen Tail-Index speichern
store:                       ;neues Zeichen in Puffer schreiben 
    move.l  D1,0(A2,D2.w)
    bclr    #1,conterm       ;Repeat aus: sonst falsche Zeichen
regis:                       ;ASCII-Kode merken (0 falls nicht vorhanden)
    lea     lastc,A0
    move.b  D1,(A0)
finis:
    move.l  tsavp,savptr     ;alten BIOS-Savebereich wieder aktivieren 
    rts                      ;IKBD-Interrupt fertig
nokey:                       ;keine Taste gedrückt
    bset    #1,conterm       ;Repeat ein
    cmp.b   #$0B,D0          ;ALT-SHIFT-SHIFT ?
    bne.s   finis
    lea     activ,A0
    not.b   (A0)             ;Umschalten zwischen aktiv/inaktiv 
    bra.s   finis            ;fertig
;
oldvec: dc.l 0              ;alter ikbdsys-Uektor
laste:  dc.b 0              ;letztes Zeichen (ASCII)
activ:  dc.b 0              ;Flag ob EXTKEY inaktiv
tsavp:  dc.l 0              ;gemerkter BlOS-savptr
    ALIGN
savarea: ds.b 2*SAVSIZE     ;sicherheitshalber für 2 BIOS-Aufrufe
endarea:

;
ctrlt:  dc.b $0d                ;': E,a,e,i,o,u
        dc.b $45.$90
        dc.b $61,$a0,$65,$82,$69,$a1,$6f,$a2,$75,$a3,0 
        dc.b $0e                ;BS: AE,IJ,OE,ae,ij,oe
        dc.b $41,$92,$49.$c1,$4f,$b5
        dc.b $61,$91,$69,$c0,$6f,$b4,0
        dc.b $2b                ;~: A,N,O,a,n,o
        dc.b $41,$b7,$4e,$a5,$4f,$B8
        dc.b $61,$b0,$6e,$a4,$6f,$b1,0
        dc.b $33                ;.: C.c
        dc.b $43,$80,$63,$87,0
        dc.b $34                ;.: A.a
        dc.b $41,$8f,$61,$86,0
        dc.b $35                ;-: :,L,Y
        dc.b $3a,$f6,$4c,$9c,$59,$9d,0
        dc.b $88                ;/: O,o
        dc.b $4f,$b2,$6f,$b3,0
        dc.b $8d                ;': A.a.e.i.o.u
        dc.b $41,$B6
        dc.b $61,$85,$65,$8a,$69,$8d,$6f,$95,$75,$97,0 
        dc.b $a9                ;^: a,e,i,o,u
        dc.b $61,$83,$65,$88,$69,$8c,$6f,$93,$75,$96,8
        dc.b $b4                ;:: A,O,U,a,e,i,o,u,y
        dc.b $41,$8e,$4f,$99,$55,$9a
        dc.b $61,$84,$65,$89,$69,$8b,$6f,$94,$75,$81,$79,$98,0
        dc.b $b5                ;_: +,<,=,7,a,o
        dc.b $2b,$f1,$3c,$f3,$3d,$f0,$3e,$f2
        dc.b $61,$a6,$6f,$a7,0
        dc.b 0,0

;ASCII-Kodes für Scan Kodes mit ALT
altt:   dc.b $00,$1b,$ad,$fd,$fe,$9b,$bd,$be ;____123456
        dc.b $bf,$a9,$aa,$df,$a8,$ba,$08,$09 ;7890ß'___
        dc.b $bc,$ea,$ee,$1a,$e7,$ec,$f4,$1c ;qwertzui
        dc.b $1d,$e3,$40,$f1,$0d,$00,$e0,$e5 ;opü*_as
        dc.b $eb,$ed,$e8,$9f,$f5,$1e,$1f,$5b ;dfghjk1ö
        dc.b $5d,$ef,$00,$f7,$e4,$7f,$e2,$e9 ;ä#_'yxcu
        dc.b $e1,$fc,$e6,$f9,$f8,$f6,$00,$00 ;bnm,.-_
        dc.b $00,$20,$00,$00,$00,$00,$00,$00 ;_________
        dc.b $00,$00,$00,$00,$80,$00,$00,$00 ;_________
        dc.b $00,$00,$ec,$00,$00,$00,$f1,$00 ;_-_____+_
        dc.b $00,$00,$00,$7f,$80,$08,$08,$00 ;_________
        dc.b $00,$00,$00,$00,$00,$00,$00,$00 ;_________
        dc.b $ae,$00,$00,$7b,$7d,$f6,$fb,$17 ;<_()/*7
        dc.b $18,$19,$14,$15,$16,$11,$12,$13 ;89456123
        dc.b $18,$2c,$0d,$00,$00,$00,$08,$00 ;0________
        dc.b $00,$00,$00,$00,$00,$00,$00,$00 ;_________
;ASCII-Kodes für ALT+Shift
        dc.b $00,$1b,$08,$ab,$00,$ac,$00,$00 ;_!"§$%&
        dc.b $00,$00,$00,$f0,$d0,$60,$08,$09 ;/()=?'__
        dc.b $d4,$c7,$d3,$d5,$d7,$c8,$d8,$db ;QUERTZUI
        dc.b $dc,$d2,$5c,$fb,$0d,$00,$c2,$d6 ;OPÜ*__AS
        dc.b $c5,$d9,$ca,$c6,$cb,$cc,$cd,$7b ;DFGHJKLÖ
        dc.b $7d,$de,$00,$bb,$d1,$c9,$c4,$da ;fiA_IYXCU
        dc.b $c3,$cf,$ce,$fa,$b9,$00,$00,$00 ;BNMi:____
        dc.b $00,$20,$00,$00,$00,$00,$00,$00 ;_________
        dc.b $00,$00,$00,$00,$00,$00,$00,$00 ;_________
        dc.b $00,$00,$ec,$00,$00,$00,$f1,$00 ;_-_____+_
        dc.b $00,$00,$00,$7f,$00,$00,$00,$00 ;_________
        dc.b $00,$00,$80,$00,$00,$00,$00,$00 ;_________
        dc.b $ae,$00,$00,$7b,$7d,$f6,$fb,$17 ;<___()/*7
        dc.b $18,$19,$14,$15,$16,$11,$12,$13 ;894S6123
        dc.b $10,$2c,$0d,$00,$00,$00,$00,$00 ;0________
    ALIGN

alt_init:
    move.w  #kbdvbase,-(A7)
    trap    #14
    addq.l  #2,A7

    move.l  D0,-(A7)        ;Zeiger auf Vektortabelle
    lea     alt_in1,A0      ;Init. im Supervisor-Mode durchführen
    move.l  A0,-(A7)
    move.w  #supexec,-(A7)
    trap    #14
    adda.w  #10,A7

    pea     mess            ;Meldung ausgeben
    move.w  #cconws,-(A7)
    trap    #1
    addq.l  #6,A7

    lea     alt_init,A0     ;Länge des residenten Teils berechnen
    suba.l  4(A7),A0        ;Base page
    clr.w   -(A7)
    move.l  A0,-(A7)
    move.w  #ptermres,-(A7) ;Programm resident installieren und beenden
    trap    #1
    illegal                 ;falls doch noch Rückkehr aus Ptermres

alt_in1:
    move.l  8(A7),A2        ;Zeiger auf Vektortabelle
    move    SR,-(A7)        ;SR retten
    ori     #$700,SR        ;IPL 7
    lea     oldvec,A0       ;alten ikbdsys-Vektor merken
    move.l  IKBDSYS(A2),(A0)
    lea     kbdrv,A1        ;und umsetzen
    move.l  A1,IKBDSYS(A2)
    moue    (A7)+,SR        ;SR zurück
    rts
;
mess:
    dc.b 13,'Extended keyboard V1.2 installed.',13,10 
    dc.b '(C) 1988 A.Esser',13,10

Alex Esser
Aus: ST-Computer 06 / 1988, Seite 126

Links

Copyright-Bestimmungen: siehe Über diese Seite