Les routines système du CPC concernant le clavier utilisent abondamment les cycles d'interruption . Pour cette raison : Tout appel à #BB06 , #BB1E , Etc ... A l'intérieur d'une interruption programmée ne peut qu'entraîner un plantage spectaculaire ! Une solution consiste à réécrire une routine de lecture directe du clavier et à convertir les codes lus en numéro de touche ( KEY(N) ) en Basic. Commençons par le commencement : La lecture directe du clavier . Seules des instructions IN/OUT peuvent réaliser cette lecture . Comme on ne peut adresser que 8 bits à la fois , le clavier de 80 touches est divisé en 10 lignes de 8 touches chacune (Joystick compris) . Le clavier est lu par un circuit d'interface nommé PPI . Ce circuit d'interface parallèle est composé de 3 ports de 8 bits : A , B & C . Le PPI s'occupe de l'interface K7 , du générateur sonore , du signal busy de l'imprimante , des cycles d'interruption et pour la partie qui nous intéresse , du clavier . Nous n'entrerons pas ici dans le détail de l'électronique Amstrad . Onnotera toutefois que pour économiser de la mémoire , l'adressage de lecture clavier se fait par l'intermédiaire du P.S.G. En fonction de cela, certaines erreurs de programmation ont des effets curieux sur l'instruction SOUND . L'efficacité primant avant tout , le plus simple est de reproduire en RAM la section 'SCAN KEYBOARD' de la ROM (En #846 pour CPC 464) et de l'adapter à nos besoins . STRUCTURE DU CLAVIER ET POSITION DES TOUCHES Voici ci-dessous la répartition des touches sur les 10 lignes du clavier. F.=Flèche - J.=Joystick - Pn.=Pavé numérique | Colonne=> | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | Lignes | | | | | | | | | 0 | F.Hau | F.Dro | F.Bas | Pn. 9 | Pn. 6 | Pn. 3 | Pn.En | Pn. . | 1 | F.Gau | Copy | Pn. 7 | Pn. 8 | Pn. 5 | Pn. 1 | Pn. 2 | Pn. 0 | 2 | CLR | "[" | Enter | "]" | Pn. 4 | SHIFT | "ç" | CTRL | 3 | "" | "=" | "à" | "P" | "+" | "*" | "?" | ">" | 4 | "0" | "9" | "O" | "I" | "L" | "K" | "M" | "<" | 5 | "8" | "7" | "U" | "Y" | "H" | "J" | "N" | SPACE | 6 | "6" | "5" | "R" | "T" | "G" | "F" | "B" | "V" | 7 | "4" | "3" | "E" | "W" | "S" | "D" | "C" | "X" | 8 | "1" | "2" | ESC | "Q" | TAB | "A" | CAPSL | "Z" | 9 | J.hau | J.bas | J.gau | J.dro | J.fir | ------ | ------ | DEL |
Si ceci vous fait penser à une matrice du genre DIM touches (8,10) vous avez raison ! La touche située sur la ligne 0 colonne 0 est KEY(0) , celle située sur la ligne 2 colonne 8 est KEY (66) , Etc ... Pour trouver le numéro de touche exact : TOUCHE=LIGNE*8 + COLONNE . La routine assembleur lira successivement chaque ligne du clavier et récupèrera au passage un octet indiquant l'état de cette ligne . Si cet octet contient #FF (11111111) , aucune touche des 8 de la ligne n'est enfoncée . Si une touche est pressée , un des bits de l'octet transmis sera à zéro . La position de ce bit nous donnera la colonne ou se trouve la touche . Exemples : 11110111 = 3 ème colonne . 10111111 = 7ème colonne . C'est une série de rotations à droite de l'octet qui donnera le numéro de colonne .(Noter que du point de vue binaire , le tableau ci-dessus est a l'envers de gauche à droite) . Chaque octet lu sera stocké dans un buffer de 10 octets pour interprétation ultérieure . Le principe de base sera : Lire les 10 lignes du clavier et stocker chaque octet . Ensuite : ; LD HL,BUFFER DE 10 OCTETS LD B,10 ;Pour 10 lignes . LD C,0 ;Contiendra le numéro de touche KEY(n) en sortie . ; BCL LD A,#FF CP (HL) ;Si contenu de HL <> #FF on a trouvé une touche pressée . JR NZ,TOUCHE ; INC HL ;Aucune touche sur la ligne N . LD A,8 ;On ajoute 8 touches au compteur C . ADD A,C ;et on continue . LD C,A DJNZ BCL RET ;Si on sort ici , aucune des 80 touches n'était pressée . ; TOUCHE LD A,(HL) ;Une touche a été pressée , chercher son numéro . LOOK RRC A ;Chercher le bit a zéro . JR NC,TOUCHETROUVEE INC C ;C contient déja le numéro de ligne , on avance de 1 JR LOOK ;dans la colonne . ; TOUCHETROUVEE : C'est fini . ;Comme on le voit , le principe est des plus simples si l'on veut lire une seule touche . Mais il ne faut pas oublier les combinaisons suivantes !Touche + CTRL , Touche + SHIFT , Touche + SHIFT + CTRL . Aie aie ... Lire 2 touches sur 2 lignes différentes ne constitue pas unvraiment un problème , on testera en priorité la ligne 2 et mettrons un flag si on y trouve SHIFT ou CTRL , mais SHIFT + CTRL + ENTER = 3 touches sur la même ligne ! Ca ce n'est pas un cadeau ... Dans ce cas le clavier renvoie un code btard qui équivaut à : La touche pressée , AND le code des autres touches pressées . Donc : ENTER + SHIFT = &FB AND &20 = &DB ENTER + CTRL = &FB AND & 80 = &7B ENTER + CTRL + SHIFT = &FB AND &80 AND &20 = &5BOu encore &FB AND &A0 =&5BDans le cas ou toutes les touches d'une même ligne serait pressées simultanément (Pas facile ça...) , le clavier renvérait donc un 0 . Si la les 80 touches étaient enfoncées (il faut être trois pour y-arriver) , les 10 octets transmis seraient tous à 0 . On peut donc tester simultanément des dizaines de touches à condition de savoir décoder le résultat . (10110101 signifie que les touches des colonnes 6,3 & 1 sont enfoncées sur une même ligne) . Inutile d'aller aussi loin dans nos spéculations . La reconnaissance de CTRL - SHIFT suffira . J'ai effectué ce décodage de manière un peu particulière . L'octet de ligne 3 est lu en premier . Si il est à #FF nous n'avons ni CTRL ni SHIFT et tout va bien . Sinon un OR &A0 restaure un octet sans SHIFT ni CTRL qui est remis dans le buffer . Ceci est nécéssaire pour que la boucle de décodage ne soit pas perturbée par un octet parasite . Ceci fait , l'état éventuel de SHIFT - CTRL est stocké et on relit la totalité du buffer pour trouver le numéro de touche . Un dernier détail : Lorsque SHIFT & CTRL sont enfoncés , la dernière colonne passe de #7F à #5F . Ceci quelque soit la ligne clavier concernée . La démonstration fournie (Décodage clavier) , vous montrera les résultats obtenus . Notez que si l'état de CTRL - SHIFT est lu et affiché en bas d'écran , on ne le voit pas dans l'affichage du buffer puisque le programme à effacé ces codes du buffer après interprétation . Le Basic est un peu lent . Attendez le BIP avant de relacher les touches . Appuyer sur CTRL+SHIFT+ESC pour quitter ce programme (Le RESET est déconnecté) . Ci-dessous le listing assembleur de "-KEY-ES" (Voir aussi NOTE après le listing ) . ; ;- LECTURE DU CLAVIER PAR PORTS E/S DU PPI - ; ORG 40000 ; scankeyboard: DI ;Toujours interdire les interruptions avant PUSH HL ;d'utiliser les ports ES PUSH BC PUSH AF ****************************** VOIR NOTE ********************************** ; ;- Routine recopiée de puis les ROMS - ; LD BC,#F40E ; Le registre R14 du PSG est connecte au port OUT (C),C ;A du PPI . LD B,#F6 ;Envoyer #C0 (11000000) sur le port C du PPI pour IN A,(C) ;l'activer en mode adressage AND #30 LD C,A OR #C0 OUT (C),A ;STROBE on puis OFF . On ne voit pas bien a quoi OUT (C),C ;ca sert ???? INC B ;Passer sur le port #F7 et envoyer un octet LD A,#92 ;10010010 qui active le PPI comme suit : OUT (C),A ;Port A = IN , port B = IN , port C = OUT LD C,#40 ;01000000 envoyer le bit 6 sur le port C pour activer PUSH BC ;le mode lecture PPI clavier . Les 4 bits de poids faible ;donnent le numéro de ligne a lire . ; ;- Modifiée a partir d'ici - ; LD HL,buf1 ;Départ du buffer pour les 10 lignes bcl : LD B,#F6 ;Envoyer l'ordre de lecture . OUT (C),C LD B,#F4 ;Lire le registre R14 sur le port A qui nous donne IN A,(C) ;l'octet transmis par le clavier . (#FF si aucune LD (HL),A ;touche enfoncée) . INC HL ;Adresse stockage ligne suivante . INC C ;Incrémenter pour lire la ligne clavier suivante . LD A,C AND #F ;Tester si on atteint la 10eme ligne CP 10 JR NZ,bcl ;Sinon recommencer ; POP BC ;Restaurer l'état des ports E/S LD A,#82 ;Sinon Gare !! OUT (C),A ;(Copie depuis ROMS) DEC B OUT (C),C POP AF ;Si cette routine est utilisée sous interruption POP BC ;Placer un RET après EI et n'appeler la routine de POP HL ;décodage que quand c'est nécéssaire . EI *************************************************************************** ; ; - Routine de décodage . ; keydecod: XOR A ;RAZ de la case CTRL-SHIFT LD (statkey),A DEC A ;Et mise a #FF du numéro de touche LD (numkey),A ; LD A,(buf1+2) ;Tester d'abord la ligne maudite (3) CP #FF ;Si #FF aucune touche de cette ligne JR Z,nostats ; LD HL,bitmap ;Charger adresse table pour comparaison . LD B,5 ;Voir les 5 1ers octets et éliminer les cases bclmap: CP (HL) ; <> SHIFT ou CTRL JR Z,nostats INC HL DJNZ bclmap INC HL ;Sauter aussi la case 7 CP (HL) JR Z,nostats ; ; - La présence de SHIFT ou CTRL ou les 2 a été détectée - ; LD HL,buf1+2 ;Reprendre la case 3eme ligne PUSH AF OR #A0 ;Or #A0 (10100000) A pour effet de mettre l'octet LD (HL),A ;a &FF si la case contenait CTRL ou SHIFT seuls. POP AF ;Dans le cas ou SHIFT - CTRL sont combines avec ; ;une autre touche sur la me^me ligne , le code de AND #A0 ;celle ci-se trouve restaurée . JR Z,shiftctrl AND #20 ;Ensuite ces 3 comparaisons permettent de JR NZ,ctrl ;déterminer SHIF & CTRL ou les 2 shift: LD A,#20 JR setstat ctrl : LD A,#80 JR setstat shiftctrl: LD A,#A0 setstat: LD (statkey),A ; ;- Traitement des touches sans CTRL ni SHIFT . 1 Chercher la ligne - ; nostats: LD HL,buf1 ;On balaie les 10 octets du buffer . LD C,0 ;Tant que #FF , aucune touche sur cette ligne LD B,10 ;et on ajoute 8 au compteur pour prendre en findline: ;compte la ligne suivante . LD A,(HL) CP #FF JR NZ,trouve &nb sp; LD A,8 ADD A,C LD C,A INC HL DJNZ findline RET ; ;- 2 Chercher la touche - ; trouve: LD B,0 ;Or #20 pour passer #5F en #7F dans le cas ou CP #5F ;dernière touche +CTRL + SHIFT mais tester JR NZ,findkey ;avant car #DF OR #20 = #FF et dans ce OR #20 ;cas on reste coince dans la boucle ! findkey: ;RRC A ;Rotation a droite JR NC,keyfind ;Si bit a 0 : Touche trouvée INC B JR findkey ; keyfind: LD A,C ;Ajouter le numéro de ligne au numéro de colonne ADD A,B nokey: LD (numkey),A ;Et nous avons enfin notre numéro INKEY RET ; ;- Les valeurs des 8 touches dans 1 ligne pour comparaison - ; bitmap: DB #FE,#FD,#FB,#F7,#EF,#DF,#BF,#7F *LIST ON numkey: DB 0 statkey: DB 0 ; ;- Buffer de stockage des 10 lignes clavier - ; buf1 : DB #FF,#FF,#FF,#FF,#FF,#FF,#FF,#FF,#FF,#FF ;NOTEOn peut remplacer la section de programme (tirée des ROMS) située à entre les 2 ligne d'astériques par : LD BC,#F792 ;Initialiser directement le PPI en lecture OUT (C),C ;clavier LD B,#F6 LD C,#40 ; LD HL,buf1 ;Départ du buffer pour les 10 lignes bcl : LD B,#F6 ;Envoyer l'ordre de lecture . OUT (C),C LD B,#F4 ;Lire le registre R14 sur le port A qui nous donne IN A,(C) ;l'octet transmis par le clavier . (#FF si aucune LD (HL),A ;touche enfoncée) . INC HL ;Adresse stockage ligne suivante . INC C ;Incrémenter pour lire la ligne clavier suivante . LD A,C AND #F ;Tester si on atteint la 10eme ligne CP 10 JR NZ,bcl ;Sinon recommencer ; POP AF ;Si cette routine est utilisée sous interruption POP BC ;Placer un RET après EI et n'appeler la routine de POP HL ;décodage que quand c'est nécéssaire . EIDans ce cas , en sortie de routine , les ports E/S systéme se trouvent plutot perturbés . Ce n'est pas bien grave car tous les 1/50S. , AMSDOS effectue une lecture clavier et restaure l'ordre normal des choses . En employant cette seconde version (Ne figure pas en code binaire sur la disquette) :10 CALL 40000:GOTO 10 . Ceci plante complètement car le système n'a pas le temps de repasser par sa routine lire clavier .10 CALL 40000:FOR tp=1 TO 20:NEXT:GOTO 10Tout va bien car on laisse au cycle d'interruption le temps de se produire .D'autres détails dans l'article : Buffer clavier AMSDOS . |