Gestion clavier : Saisir du texte, gérer les touches spécialesComme vu dans les articles [ accéder au clavier ] et [ gestion de menu ],on sait lire l'état du clavier. Cela nous donne l'état d'une touche à un instant donné. Mais quand il s'agit de gérer des évènements, on peut seretrouver rapidement submergé si on ne gère pas différents états, à minima, qu'on n'attende pas que la touche soit remontée avant de continuer. Dans la [ gestion de menu ], on a utilisé une solution simple mais bloquante!Comment faire si on veut continuer à faire d'autres choses qu'attendre que les touche soient remontées? Et bien on pourrait commencer par réagir à des états! L'idée serait d'agir immédiatement à l'appui de la touche mais de ne pas recommencer l'action tant que la touche n'est pas remontée. Pour ça on va avoir besoin d'un tableau conservantle résultat du scan précédent et aussi d'un tampon pour y envoyer les nouvelles touches (ou un autre tableau qu'il faudra acquitter d'une façon ou d'une autre). matriceClavier defs 10 ; état des touches inversés pour avoir 1 quand enfoncée matriceRemanence defs 10 ; état précédent des touches inversées repetitionTouche defb 0 ; en cas de touche unique, compter le temps d'enfoncement nouvelleTouche defb 0 ; une nouvelle touche maxi par itérationOn démarre le code de comparaison? 4 chemins logiques possibles : - touche relâchée et était déjà relâchée, on ne fait rien. - touche relâchée et était enfoncée. On arrête la répétition au besoin. - touche enfoncée et était déjà enfoncée, on gère les répétitions si unique (besoin d'un compteur). - touche enfoncée et était relâchée, on ajoute de l'activité sur cette touche. - plusieurs touches enfoncées, on réinitialise les répétitions et on ne renvoie éventuellement qu'une nouvelle touche.Mais d'abord, définissons quelques tables en accord avec le clavier français de France. Pour faciliter le traitement, les touches de curseur, tab, esc, ... , seront relogées dans les32 premiers caractères afin de les regrouper dans un seul intervale, ce qui nous permettra deles traiter plus facilement et les dissocier des caractères à afficher. Pour compiler les tables suivantes qui contiennent certains caractères accentués (codés en UTF8), vous aurez besoin d'indiquer à RASM de convertirvos caractères UTF8 dans l'encodage du CPC (ça fonctionne aussi avec les caractères espagnols). rasm.exe saisieTexte.asm -utf8Le clavier FR est un peu particulier, en effet, il possède deux touches qui renvoient le même caractère, rapport à la fonte graphique située en ROM maiscomme nous allons utiliser notre propre fonte, on va pouvoir remettre un vrai pipe, l'arobe et l'anti-slash qui étaient respectivement remplacés parle ù, le à et le ç...
Je place ici les trois extras en fin de fonte, sur les codes 126,127 et 128. CODE_MORT equ 0 CODE_RETURN equ 1 CODE_BAS equ 2 CODE_DROITE equ 3 CODE_HAUT equ 4 CODE_GAUCHE equ 5 CODE_CLR equ 6 CODE_TAB equ 7 CODE_ESC equ 8 CODE_DEL equ 9 CODE_CTRL_BAS equ 10 CODE_CTRL_DROITE equ 11 CODE_CTRL_HAUT equ 12 CODE_CTRL_GAUCHE equ 13conversionASCII .ligne40 defb '.',CODE_RETURN,'369',CODE_BAS,CODE_DROITE,CODE_HAUT .ligne41 defb '021587',CODE_RETURN,CODE_GAUCHE .ligne42 defb CODE_MORT,'$',CODE_MORT,'4#',CODE_RETURN,'*',CODE_CLR .ligne43 defb ':=mùp^)-' .ligne44 defb ';,klioçà' .ligne45 defb ' njhyuè!' .ligne46 defb 'vbfgtr(]' .ligne47 defb 'xcdsze"\'' .ligne48 defb 'w',CODE_MORT,'q',CODE_TAB,'a',CODE_ESC,'é&' .ligne49 defb CODE_DEL,CODE_RETURN,CODE_RETURN,CODE_RETURN,CODE_DROITE,CODE_GAUCHE,CODE_BAS,CODE_HAUT .shift40 defb '.',CODE_RETURN,'369',CODE_BAS,CODE_DROITE,CODE_HAUT .shift41 defb '021587',CODE_RETURN,CODE_GAUCHE .shift42 defb CODE_MORT,128,CODE_MORT,'4>',CODE_RETURN,'<',CODE_CLR ; patch anti-slash .shift43 defb '/+M%P',126,'[_' ; patch pipe .shift44 defb '.?KLIO90' .shift45 defb ' NJHYU78' .shift46 defb 'VBFGTR56' .shift47 defb 'XCDSZE34' .shift48 defb 'W',CODE_MORT,'Q',CODE_TAB,'A',CODE_ESC,'21' .shift49 defb CODE_DEL,CODE_RETURN,CODE_RETURN,CODE_RETURN,CODE_DROITE,CODE_GAUCHE,CODE_BAS,CODE_HAUT .ctrl40 defb CODE_MORT,CODE_RETURN,CODE_MORT,CODE_MORT,CODE_MORT,CODE_CTRL_BAS,CODE_CTRL_DROITE,CODE_CTRL_HAUT .ctrl41 defb CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_RETURN,CODE_CTRL_GAUCHE .ctrl42 defb CODE_MORT,127,CODE_MORT,CODE_MORT,CODE_MORT,CODE_RETURN,CODE_MORT,CODE_CLR ; patch Arobe .ctrl43 defb CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT .ctrl44 defb CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT .ctrl45 defb CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT .ctrl46 defb CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT .ctrl47 defb CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT,CODE_MORT .ctrl48 defb CODE_MORT,CODE_MORT,CODE_MORT,CODE_TAB,CODE_MORT,CODE_ESC,CODE_MORT,CODE_MORT .ctrl49 defb CODE_DEL,CODE_RETURN,CODE_RETURN,CODE_RETURN,CODE_DROITE,CODE_GAUCHE,CODE_BAS,CODE_HAUTOn aura défini 3 tables, selon qu'on appuie sur SHIFT et/ou CTRL en même temps qu'une autre touche. Ces tables servirontdans l'analyse des changements de touche à la fin de la gestion clavier. Mais d'abord, il faut déterminer quelles touches ont été actionnées... On va doubler le tableau résultat de scan des touchespour conserver l'état précédent et pouvoir le comparer avec l'état courant. Une simple copie de l'un vers l'autre avant de scanner. lectureMatriceClavier ld hl,matriceClavier+9 : ld de,matriceRemanence+9 : ld bc,9 : lddr : ld a,(hl) : ld (de),a ; copier la rémanence ld bc,#f782 out (c),c ld bc,#f40e ld e,b out (c),c ld bc,#f6c0 ld d,b out (c),c out (c),0 ld bc,#f792 out (c),c ld a,#40 ld c,d .loop ld b,d out (c),a ; sélectionner la ligne ld b,e ini ; lire et stocker dans notre tableau inc a inc c jr nz,.loop ld bc,#f782 out (c),c ret confine 21 ; s'assurer que les 20 octets suivants ne chevauchent pas une incrémentation de poids fort matriceClavier defs 10,#FF matriceRemanence defs 10,#FF ; état précédent des touches inversées compteurRepetition defb 0 sousRepetition defb 0 shiftCTRL defb 0À partir de nos deux tableaux, on va analyer : - les changements - les états enfoncés GererClavier call lectureMatriceClavier ; on récupère SHIFT+CTRL qu'on reset pour ne pas interférer avec le scan ld hl,matriceClavier+2 : ld a,(hl) : ld (shiftCTRL),a : or %10100000 : ld (hl),a ld de,matriceClavier : ld hl,matriceRemanence exx : ld hl,#FF : ld c,8 : exx ld iy,10 ; YH=0 compteur de touches, YL=10 compteur de lignes ld a,(compteurRepetition) : exa ;----------------------------- gestionTouches ;----------------------------- ld a,(de) : cp #FF : jr nz,.scanEtat : cp (hl) : jr z,.pasDeChangement.scanEtat ld c,(hl) ; état précédent des touches dans C ld b,8 ;----------------------------- .scanBits add a : jr c,.couranteRelachee ;---------------- .couranteEnfoncee inc yh ; incrémenter le compteur de touches courantes sla c : jr c,.ajouteTouche ; saute si relâchée ; était déjà enfoncée, on récupère le code courant dans B' exx : ld b,h : exx jr .suiteBits .ajouteTouche exx : ld l,h : exx : exa : xor a : exa ; reset des répétitions + nouvelle touche dans L' jr .suiteBits ;---------------- .couranteRelachee sla c : jr c,.suiteBits ; relâchée/relâchée RAS ; était enfoncée, reset du compteur de répétition exa : xor a : exa .suiteBits exx : inc h : exx djnz .scanBits jr .reloop ;----------------------------- .pasDeChangement exx : ld a,h : add c : ld h,a : exx ; liste de conversion suivante .reloop inc e : inc l dec yl : jr nz,gestionTouchesUne fois qu'on a comparé nos tableaux, on a un nombre d'appuis, éventuellement une nouvelle touche ou une touche de répétition, on renvoie danstous les cas un pseudo-code ASCII (avec nos touches spéciales sous 32 et un code de non action de valeur zéro). ; analyse des résultats ld a,yh : or a : jr z,.pasDeTouchedec a : jp nz,.plusieursTouches ; une seule touche! ; si nouvelle touche alors L' ne vaut plus #FF et on récupère le code ASCII exx : ld a,l : exx : cp #FF : jr nz,.getASCII ; une seule touche déjà enfoncée, augmenter la répétition! ; B'=code de la touche touche à répeter exa : inc a : bit 5,a : jr z,.pasDeRepetition : dec a : ld (compteurRepetition),a ld a,(sousRepetition) : inc a : and 3 : ld (sousRepetition),a : jr nz,.sortie exx : ld l,b : exx jr .getASCII .pasDeRepetition ld (compteurRepetition),a : ld a,#FF : ld (sousRepetition),a : .sortie xor a : ret ;exx : ld a,l : inc a : ret z ; pas de nouvelle touche .plusieursTouches exx : ld a,l : exx : cp #FF : jr nz,.getASCII ; si il en existe au moins une nouvelle on l'envoie .pasDeTouche xor a : ld (compteurRepetition),a : ret ; sinon reset comme aucune touche .getASCII exx : ld h,hi(conversionASCII) : ld c,0 : ld a,(shiftCTRL) add a : jr c,.skipCtrl : ld c,160 : .skipCtrl add a : add a : jr c,.skipShift : ld c,80 : .skipShift ; deuxième chance ld a,l : add c : ld l,a : ld a,(hl) ; code ASCII retOn va mettre en place un code très simple pour voir qu'il se passe quelque chose, que la répétition est prise en compte et queles timings choisis pour la vitesse sont OK. Visuellement c'est pas foufou mais on aura du vrai texte à l'explorateur mémoire :) laBoucle halt 6 call GererClavier ; code mort 0 ; codes spéciaux < 32 ; code ASCII sinon :)or a : jr z,laBoucle ; code mort, on reboucle cp 32 : jr c,dispFunc ; afficher l'octet correspondant à la touche plug ld hl,#C000 : ld (hl),a : inc l : ld (plug+1),hl jp laBoucle ; remplir sur une ligne différente les codes spéciaux (s'affichent et s'effacent) dispFunc ld h,#D0 : ld l,a : ld a,(hl) : xor #AA : ld (hl),a jp laBoucle Et maintenant qu'on a une routine plutôt puissante comme celle là, on va pouvoir se fabriquer des petits modules qui s'en servent, à commencer par une [ checkbox ]. Roudoudou CPCrulez[Content Management System] v8.732-desktop/c Page créée en 780 millisecondes et consultée 23 foisL'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko. |
|