La langue internationale Espéranto comporte six lettres accentuées qui ne figurent pas sur les configurations classiques de clavier : Ĉ, Ĝ, Ĥ , Ĵ, Ŝ et Ŭ (U bref). La solution qui permettra leur entrée ne devra ni dépendre de la nationalité de la disposition du clavier ni interférer avec.
Dans un premier temps, je vais vous présenter un TSR remplissant son rôle au strict minimum.
Je me suis inspiré pour cela du programme EKLAVO de Byrial Jensen. Il exploite le service 4Fh de l'interruption 15h et le service 5 de l'interruption 16h. Il s'agit d'obtenir les lettres accentuées avec l'appui simultanée de la touche AltGr (Alt gauche) ou la combinaison Ctrl+Alt (gauche) et de la touche correspondante. Ainsi, ĝ est introduit soit par AltGr (Alt droite)+g soit par Ctrl+Alt (gauche)+g. Le programme requiert la page de codes 853.
Je suis parti de deux constats.
La touche Maj sert de préfixe. Elle indique toujours le contraire de l'état du verrouillage majuscule — sur le clavier français, elle le désactive aussi.
Ensuite, la touche AltGr de la plupart des claviers correspond à l'Alt droite du clavier américain. Normalement, elle peut indiquer qu'une touche Alt est enfoncée via l'octet 17h du segment de données du BIOS (40h). Cependant, le gestionnaire KEYB de DR DOS n'agit pas ainsi (ce que le programme EKLAVO ne prévoit pas). Or, c'est sous DR DOS que la page de codes 853 est disponible (bien que non supportée officiellement).
La version suivante met en lumière ce problème accompagné d'un autre : le service 12h de l'interruption 16h du clavier ne permet plus d'indiquer l'actionnement de la touche Alt droite du clavier étendu.
Code : Tout sélectionner ; Assemblage :
; MASM ESPKLAVO;
; LINK ESPKLAVO;
; EXE2BIN ESPKLAVO ESPKLAVO.COM
VerrMaj equ 100b * 16
Alt equ 1000b
Ctrl equ 100b
MajG equ 10b
MajD equ 1
AltD equ 1000b
NUL SEGMENT AT 0
Adresse_nulle label far
NUL ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:CODE
ORG 100h
Depart:
jmp Installe
; Données --------------------------------------------------------------------
Drapeau db (0) ; 1 : code étendu attendu ; 2 : AltGr
Touches db 2Eh,22h,23h,24h,1Fh,16h ; c, g, h, j, s, u
Esperanto db 134,143 ; c circonflexe min & maj
db 155,157 ; g circonflexe "
db 169,168 ; h circonflexe "
db 159,172 ; j circonflexe "
db 199,198 ; s circonflexe "
db 237,236 ; u brève "
; Saut vers le vecteur précédent ---------------------------------------------
Int_orig:
jmp Adresse_nulle
Vect_orig equ $-4
RESIDANT PROC FAR
jnc Int_Orig ; Bit de retenue positionné ?
cmp ah,4Fh ; Fct interception clavier ?
jne Int_Orig
push ax
push bx
push cx
push di
push ds
push es
push cs
pop es ; ES = CS
mov cx,6 ; 6 touches concernées
mov di,offset Touches
cld ; Incrémentation
repne scasb ; Répète tant que CX<>0, [ES:DI]<>AL
jne Retour ; Si aucune touche correspondante, ret.
sub di,offset Touches + 1 ; Obtient un index
shl di,1 ; DI x 2
; Sauve code touche dans CH en vue la fct 5 de l'int 16h
mov ch,al
mov ah,12h ; Obtient état du clavier std ou étendu
int 16h
xor bx,bx ; Drapeau BX à 0
test al,VerrMaj ; Verrouillage majuscule actif ?
jz Maj? ; Non, Maj ?
inc bx ; Drapeau BX à 1
Maj?:
test al,MajG + MajD ; Touche Maj (gauche ou dr.) enfoncée ?
jz AltGr? ; Non, AltGr ?
xor bl,1 ; Bascule le drapeau BX
AltGr?:
test ah,AltD ; Touche AltGr enfoncée ?
jnz Tampon_clavier ; Oui, écrit caractère dans tampon
not al ; Inverse les bits de l'octet d'état
test al,Ctrl + Alt ; Ctrl+Alt ?
jnz Retour ; Non, retour
Tampon_clavier:
mov ah,5 ; Place 1 code & 1 car. dans le tampon
mov cl,byte ptr es:[Esperanto + di + bx] ; Caractère dans CL
int 16h
or al,al ; Tampon plein ?
jnz Retour ; Oui, retour
clc ; Bit de retenue effacé :
; code de touche consommé
jmp short Code_efface
Retour:
stc ; Bit de retenue positionné :
; code de touche disponible
Code_efface:
pop es
pop ds
pop di
pop cx
pop bx
pop ax
ret 2 ; Retour d'int.
RESIDANT ENDP
Installe:
mov ax,3515h ; Sauve ancien vecteur
int 21h
mov word ptr Vect_orig+0,bx
mov word ptr Vect_orig+2,es
mov ax,2515h ; Instaure nouveau vecteur
mov dx,offset Residant
int 21h
mov dx,offset Installe ; Laisse la partie résidente
int 27h
CODE ENDS
END Depart
|
- pour savoir si la touche Maj gauche ou droite était enfoncée, j'ai appliqué un masque sur l'octet d'état du clavier avec seulement les deux bits correspondant positionnés puis vérifier si le résultat était non nul ;
- pour savoir si la combinaison Ctrl et Alt était pressée, j'ai d'abord inversé les bits de l'octet recueilli avant d'appliquer le masque afin de vérifier si le résultat était nul.
Description des services clavier utilisés :
Code : Tout sélectionner INT 15h - INTERCEPTION CLAVIER (service appelé par le BIOS lors d'une INT 9)
(BIOS du PC/XT postérieur au 8/11/82 — modèle FBh —, du PC/AT après le 10/01/84
— sous-modèle 00 & 01 — et du PS/2 ; cf. service C0h).
Appel :
AH = 4Fh
AL = code de touche
Bit de retenue (carry flag) positionné.
Retour :
Si bit de retenue positionné,
AL = code de touche (modifié ou pas) à faire traiter par la routine de l'interruption 9.
Si bit de retenue effacé, le code n'est plus à traiter.
INT 16h - ÉCRITURE CLAVIER
(BIOS supportant le claviers étendu : celui du PC/AT depuis le 15/11/85 — sous-modèle 01 — et du PS/2).
Appel :
AH = 5
CH = code de la touche
CL = caractère
Retour :
AL = 0 si succès
1 si tampon plein
AH détruit
INT 16h - OBTENTION DE L'OCTET D'ÉTAT DU CLAVIER STANDARD (à l'instar du service 2) ET ÉTENDU
Appel :
AH = 12h
Retour :
AL = octet d'état standard (lu en 40:17h) :
76543210 bit
x....... Etat Inser : 1|0
.x...... Etat Verr maj : 1, actif ; 0, inactif
..x..... Etat Verr num : 1, actif ; 0, inactif
...x.... Etat Arrêt défil : 1, actif ; 0, inactif
....x... 1 : Alt enfoncée
.....x.. 1 : Ctrl enfoncée
......x. 1 : Maj gauche enfoncée
.......x 1 : Maj droite enfoncée
AH = octet d'état étendu :
76543210 bit
x....... Sys Req enfoncée (1)
.x...... Verr maj "
..x..... Verr num "
...x.... Arrêt défil "
....x... Alt droite " (2)
.....x.. Ctrl droite " (2)
......x. Alt gauche "
.......x Ctrl gauche "
(1) ne peut être positionné que par un BIOS supportant le clavier AT.
(2) ne peut être positionné que par un BIOS supportant le clavier étendu :
celui du PC/AT depuis le 15/11/85 — sous-modèle 01 — et du PS/2.
|
_____________________
Version fonctionnelle
En testant le programme précédent sans charger KEYB de DR DOS, on remarque qu'il est plutôt aisé d'entrer les caractères accentués des touches C, G et S avec AltGr ou la combinaison Maj+AltGr. En revanche, si on souhaite garder la main droite pour les touches G, H et U, l'autre main appuyera sur Ctrl+Alt voire Maj+Ctrl+Alt ; ce qui représente trois doigts en action.
En s'inspirant d'autres claviers proposant quatre caractères par touche, il devient envisageable d'adopter la combinaison Maj+Alt.
On suppose que le verrouillage majuscule est inactif (ce qui est normalement le cas sur le clavier français lorsque la touche Maj est pressée), on obtient :
Code : Tout sélectionner Ctrl + Alt minuscule Maj + Alt MAJUSCULE AltGr minuscule Maj + AltGr MAJUSCULE |
Code : Tout sélectionner Maj ?
|
+------+------+
| |
BX=1 BX=0
| |
| Ctrl ?
| |
Alt ?-----------+----+
| |
+--+---------------Alt Gr ?
| |
| +-------+
| | |
| | CF=1, sortie
+----------Verr.maj ?-+
|
+-------+---+
| |
BX <-BX xor 1 |
| |
+---Majuscule si BX=1
Minuscule si BX=0
Se lit de haut en bas.
Issue d'une condition :
- positive : gauche ;
- négative : droite.
|
Code : Tout sélectionner MAKE (appui) BREAK (relâchement) Touche Alt classique (gauche) : 38h B8h Touche Alt droite du clavier étendu (AltGr) : E0h 38h E0h B8h |
Code : Tout sélectionner INT 15h - DEMANDE LA CONFIGURATION DU SYSTÈME
Appel.
AH = C0h
Retour.
ES :BX = adresse de la table de configuration fixée en ROM
Format de la table :
Octets Contenu
00-01 longueur de la table en octets
02 modèle du système (octet situé en F000:FFFEh)
03 modèle du sous-système
04 niveau de révision du BIOS
05 drapeaux de configuration :
Bit Signification (si positionné)
0 jadis réservé (système à bus MCA et ISA)
1 architecture MCA implémentée
2 zone de données complémentaires du BIOS (EBDA) allouée
3 attente d'un événement externe (Int 15h, fct 41h) disponible
4 interception du clavier (Int 15h, fct 4Fh) disponible
5 horloge sauvegardée (RTC) sur la carte mère
6 8259 présent (mode cascadé)
7 canal DMA 3 destiné au BIOS du disque dur
Signification des octets de modèles, de sous-modèles et de révision du BIOS :
Machine Date Modèle Sous-mod. Révision du BIOS
PC 24/04/81 FFh - 00
19/10/81 01 (quelques bugs arrangés)
27/10/82 02 (mise à jour au niveau du XT)
PC/XT 08/11/82 FEh - 00
XT/2* 10/01/86 FBh 00 01 (drapeaux de config. faux)
09/05/86 02
PCjr 01/06/83 FDh - 00
PC/AT 10/01/84 FCh - 00 (80286-6)
10/06/85 00 01 (lecteur de disquette 720 Ko)
15/11/85 01 00 (80286-8)
XT-286 21/04/86 FCh 02 00
Convertible 13/09/85 F9h 00 00
PS/2 8525 26/06/87 FAh 01 00
8530 02/09/86 00 00
12/12/86 01
8550 13/02/87 FCh 04 00
8560 idem 05 00
8580 ? ? ? F8h 00 00 (80386-16)
* XT/2 : PC/XT 256/640 Ko |
http://www.minuszerodegrees.net/bios/BI ... 0JAN86.zip
En bref, les machines IBM qui supportent cette interception du clavier sont les suivantes :
- les AT mais pas l'original ;
- le XT/2 ;
- le XT-286 ;
- le PC Convertible ;
- les PS/2.
Tout est bon pour créer un TSR qui se donne la peine de reconnaître le matériel.
Toutefois, il faut empêcher son chargement multiple. Ainsi, lors d'un appel au service 4Fh de l'interruption 15h avec le code de touche inexistant FFh, le TSR renvoie AL nul (AX=5000h) pour indiquer sa présence.
Voici le programme obtenu :
Code : Tout sélectionner ; MASM ESPKLAVO;
; LINK ESPKLAVO;
; EXE2BIN ESPKLAVO ESPKLAVO.COM
MAKE_Alt equ 38h ; Code de pression des touches Alt
BREAK_Alt equ 0B8h ; Code de relâchement des touches Alt
Code_etendu equ 0E0h ; Précède le code d'une touche étendue
VerrMaj equ 100b * 16
Alt equ 1000b
Ctrl equ 100b
MajG equ 10b
MajD equ 1
BDA SEGMENT AT 40h ; BDA : zone de données du BIOS
Adresse_bidon label far
org 17h
Etat_clav equ this byte
ORG 1AH ; Tampon circulaire du clavier
TETE DW (?) ; Prochaine lecture (2nd octet nul)
TAILLE DW (?) ; Prochaine entrée (idem)
LIM_INF LABEL FAR ; Car., scancode, car., scancode...
ORG 3EH
LIM_DEPASSEE LABEL FAR
BDA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:BDA
; PARTIE RESIDANTE **********************************************************
ORG 100h
Depart:
jmp Installe
; Données --------------------------------------------------------------------
Drapeau db (0) ; 0 : aucun code étendu ; 1 : code étendu reçu
; 2 : AltGr enfoncée ; 3 : id. + code étendu
Touches db 2Eh,22h,23h,24h,1Fh,16h ; c, g, h, j, s, u
Esperanto db 134,143 ; c circonflexe min & maj
db 155,157 ; g circonflexe "
db 169,168 ; h circonflexe "
db 159,172 ; j circonflexe "
db 199,198 ; s circonflexe "
db 237,236 ; u brève "
; Saut vers le vecteur précédent ---------------------------------------------
Int_orig:
jmp Adresse_bidon
Vect_orig equ $-4
RESIDANT PROC FAR
cmp ah,4Fh ; Fct interception clavier ?
jne Int_orig
cmp al,0FFh ; Test de présence du TSR ?
jne Bonne_fct
inc ax ; Signature : AL nul
iret ; Retour d'interruption
Bonne_fct:
cmp ah,4Fh ; Fct interception clavier ?
jne Int_orig
push ax ; Sauve les registres
push bx
push cx
push di
push ds
push es
cmp cs:Drapeau,2
ja Code_BREAK? ; 3 ; AltGr pressée et code étendu
je Code_etendu? ; 2 ; AltGr pressée
jnp Code_etendu? ; 0 ; aucun code étendu
cmp al,MAKE_Alt ; 1 ; code étendu : AltGr pressée ?
jne Drapeau_nul
Inc_drapeau:
inc cs:Drapeau ; Drapeau dans {1;3}
jmp short Retour
Code_BREAK?:
cmp al,BREAK_Alt ; Touche AltGr relâchée ?
je Drapeau_nul
dec cs:Drapeau ; Drapeau = 2
jmp short Retour
Drapeau_nul:
mov cs:Drapeau,0 ; Drapeau = 0
jmp short Retour
Code_etendu?:
cmp al,Code_etendu
je Inc_drapeau
push cs
pop es ; ES = CS
mov cx,6 ; 6 touches concernées
mov di,offset Touches
cld ; Incrémentation
repne scasb ; Répète tant que CX<>0, [ES:DI]<>AL
jne Retour ; Si aucune touche correspondante, ret.
sub di,offset Touches + 1 ; Obtient un index
shl di,1 ; DI x 2
; Sauve code touche dans CH en vue de l'écriture dans le tampon du clavier
mov ch,al
mov ax,BDA ; Segment de données du BIOS
mov ds,ax
mov al,Etat_clav ; Recueille le 1er octet d'état clavier
xor bx,bx ; Drapeau BX à 0
test al,MajG + MajD ; Touche Maj enfoncée (gauche ou dr.) ?
jz Ctrl? ; Non, Ctrl ?
inc bx ; Drapeau BX à 1
Alt?:
test al,Alt ; Touche Alt ?
jz AltGr? ; Non, AltGr ?
jmp short VerrMaj? ; Oui, va vérifier Verr. maj.
Ctrl?:
test al,Ctrl ; Touche Ctrl ?
jnz Alt? ; Oui, Alt aussi ?
AltGr?:
cmp cs:Drapeau,2 ; Touche AltGr (Alt de droite) ?
jne Retour ; Non, retour
VerrMaj?:
test al,VerrMaj ; Verr. maj. actif ?
jz Tampon_clavier ; Non
xor bx,1 ; Oui, bascule le drapeau BX
Tampon_clavier:
mov cl,byte ptr es:Esperanto[di + bx] ; Caractère dans CL
CLI ; Inhibe les interruptions
MOV AX,TAILLE ; AL pointe la taille du tampon & AH=0
MOV BX,AX ; BX pointe aussi la taille actuelle
INC AX
INC AX ; Nouvelle taille dans AL + 2
CMP AL,OFFSET LIM_DEPASSEE ; Au-delà du tampon circulaire ?
JB TAMPON_PLEIN?
MOV AL,OFFSET LIM_INF ; Limite inférieure du tampon
TAMPON_PLEIN?:
CMP BYTE PTR TETE,AL ; Tampon clavier plein ?
JE Retour ; Oui, retour
AJOUT_CAR:
MOV [BX],CX ; Car. & code dans tampon
MOV BYTE PTR TAILLE,AL ; Indique 1 car. à traiter
clc ; Bit de retenue effacé :
; code de touche consommé
jmp short Code_efface
Retour:
stc ; Bit de retenue positionné :
; code de touche disponible
Code_efface:
STI ; Autorise les interruptions
pop es ; Restitue les registres
pop ds
pop di
pop cx
pop bx
pop ax
ret 2 ; Retour d'int.
RESIDANT ENDP
; PARTIE EXTERNE *************************************************************
ASSUME DS:CODE
Non_compatible$ db 'Interception clavier (Int 15h, fct 4Fh) '
db 'non supportée par le BIOS',13,10,'$'
Deja_la$ db 'Déjà chargé$'
Charge$ db 13,10,'ESPKLAVO chargé',13,10,'$'
;-----------------------------------------------------------------------------
Sortie:
mov ah,9 ; Afficher un message
int 21h
ret ; Fin
Installe:
mov ah,0C0h ; Demande configuration système
int 15h
jc Non_compatible
mov al,es:[bx+5] ; Pointe drapeaux de config. (octet 5)
test al,10000b ; INT 15h Fct 4Fh supportée ?
jne Deja_la? ; Oui, CF = 0
Non_compatible:
mov dx,offset Non_compatible$
jmp Sortie
Deja_la?:
mov ax,4FFFh ; Teste présence TSR
int 15h
or al,al ; Signature AL nulle ?
jnz Sauve_vecteur
mov dx,offset Deja_la$
jmp Sortie
Sauve_vecteur:
XOR AX,AX
MOV ES,AX ; ES = 0
MOV BX,ES:[4*15h] ; Offset
MOV ES,ES:[4*15h+2] ; Segment
mov word ptr Vect_orig+0,bx
mov word ptr Vect_orig+2,es
mov ax,2515h ; Instaure nouveau vecteur
mov dx,offset Residant
int 21h
mov ah,49h ; Libère environnement
mov es,ds:2Ch
int 21h
mov dx,offset Charge$ ; Sort la confirmation de chargement
call Sortie
mov dx,offset Installe ; Laisse la partie résidante
int 27h
CODE ENDS
END Depart
|
Code : Tout sélectionner Offset Description 001Ah Offset de la tête du tampon (lieu de la prochaine lecture) 001Ch Offset de la taille du tampon (lieu de la prochaine écriture) 002Eh Tampon circulaire de 16 mots (un mot : caractère suivi de code de touche) 003Eh ... |
La tête du tampon peut rattraper la taille mais pas l'inverse (tampon plein).
Dans le même segment, se trouvent les octets d'état du clavier (cf. : viewtopic.php?f=24&t=5047&start=67) :
Code : Tout sélectionner Octet 0040:0017h 76543210 bit x....... Etat Inser : 1|0 .x...... Etat Verr maj : 1, actif ; 0, inactif ..x..... Etat Verr num : 1, actif ; 0, inactif ...x.... Etat Arrêt défil : 1, actif ; 0, inactif ....x... 1 : Alt enfoncée .....x.. 1 : Ctrl enfoncée ......x. 1 : Maj gauche enfoncée .......x 1 : Maj droite enfoncée Octet 0040:0018h 76543210 bit x....... 1 : Ins enfoncée .x...... 1 : Verr maj enfoncée ..x..... 1 : Verr num enfoncée ...x.... 1 : Arrêt défil enfoncée ....x... 1 : Etat Pause actif (Ctrl-Verr num ou Pause) .....x.. 1 : Sys Req enfoncée ......x. 1 : Alt gauche enfoncée .......x 1 : Ctrl gauche enfoncée |
