← ST-Computer 06 / 1988

EXTKEY: Tastaturbelegung einmal anders (Assembler)

Programmierpraxis

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