Gestion du clavier confortable avec RASM
Dans cet article, je vous présente ma façon d’utiliser les macros RASM pour intégrer de façon rapide et confortable la gestion des touches du clavier du CPC. En effet, lorsque l’on écrit du code, on aimerait pouvoir ajouter rapidement la possibilité d’utiliser une ou plusieurs touches de clavier pour contrôler un paramètre de notre code. Comme cela nécessite toujours un peu de travail, on y réfléchit a deux fois, la paresse prenant parfois le dessus.
Un Exemple concret
Imaginons que nous ayons une fonction qui nous permette de dessiner un sprite à un endroit (x,y) de l’écran. Une fois que l’on a cette routine, on veut ajouter rapidement la gestion des flèches pour déplacer le sprite. Ce que je propose ici c’est un ensemble de macros qui permette d’ajouter simplement ces quelques lignes pour gérer le changement de coordonnées:
ACTION_KEYLEFT:
LD a,(POSITION_X)
INC A
LD (POSITION_X),A
RET
Et c’est tout! Tout l’astuce va résider dans le fait que le symbole ‘ACTION_KEYLEFT‘ a été déclaré dans le code, et par l’utilisation de la directive ‘IFDEF’, la gestion de la touche se fera de façon transparente.
Etat du clavier
La première chose à faire est de récupérer l’état des touches du clavier. Je ne décrirai pas la méthode en détail, cela a déjà été fait de nombreuse fois ailleurs, par exemple ici. On pourra aussi consulter l’article écrit par roudoudou. Le code que l’on retrouve dans différentes productions est bien souvent similaire, probablement parce que c’est suffisamment pénible pour ne pas avoir à le réinventer. Celui que je donne ici ne fait pas exception:
MACRO GETKBSTATE0 DEST,FIRST,NUM
; Selection registre 14 du PSG
LD BC,PPI_PORTA |#0E
OUT (C),C
LD BC,PPI_PORTC |#C0
OUT (C),C
XOR A
OUT (C),A
LD BC,PPI_CTRL |#92
LD HL,{DEST}+{FIRST}
OUT (C),C
LD C,#40+{FIRST}
LD D,{NUM}
@KBGETLINE
; Selectionne ligne de clavier
LD B,hi(PPI_PORTC)
OUT (C),C
LD B,hi(PPI_PORTA)
IN A,(C)
LD (HL),A
INC HL
INC C ; Ligne suivante
DEC D
JR NZ, @KBGETLINE
;On desactive
LD BC,PPI_CTRL |#82
OUT (C),C
LD BC,PPI_PORTC
OUT (C),C
MEND
La routine principale de gestion des touches
MACRO CHECK_ACTION action,actionkey
IFDEF{action}
BIT {actionkey},A
JP Z,{action}
ENDIF
MEND
Ensuite, on va définir notre macro principale, qui sera à utiliser dans notre code. Cette macro va vérifier pour chaque touche du clavier si un symbole ACTION_ a été défini, et si oui, va générer le code nécessaire à tester l’état de la touche et appeler l’action associée:
MACRO CHECK_ACTION_KEYS kbstate
; Pour gérer le retour de l'action
ld HL,@end_actions
push hl
; Test Ligne 0
LD a,({kbstate}+0)
CP #ff
JR Z,@kbline1
CHECK_ACTION ACTION_KEYUP,KEY_UP_L0BIT
CHECK_ACTION ACTION_KEYDOWN,KEY_DOWN_L0BIT
CHECK_ACTION ACTION_KEYRIGHT,KEY_RIGHT_L0BIT
CHECK_ACTION ACTION_KP3,KEY_KP3_L0BIT
CHECK_ACTION ACTION_KP6,KEY_KP6_L0BIT
CHECK_ACTION ACTION_KPRET,KEY_KPRET_L0BIT
CHECK_ACTION ACTION_KP9,KEY_KP9_L0BIT
@kbline1:
; Ligne 1
LD a,({kbstate}+1)
CP #ff
JR Z,@nxtline2
CHECK_ACTION ACTION_KEYLEFT,KEY_LEFT_L1BIT
CHECK_ACTION ACTION_KP0,KEY_KP0_L1BIT
CHECK_ACTION ACTION_KP1,KEY_KP1_L1BIT
; ... le code pour gerer les autres touches...
@end:
POP HL
@end_actions:
MEND
Bien entendu, il faut définir quelques constantes, pour indiquer le bit associé à chaque touche de chaque ligne d’état du clavier, les ports du PPI, etc:
KEY_UP_L0BIT EQU 0
KEY_DOWN_L0BIT EQU 2
KEY_LEFT_L1BIT EQU 0
KEY_RIGHT_L0BIT EQU 1
...
PPI_PortA EQU #F400 ; RW
PPI_PortB EQU #F500 ; Read Only
PPI_PortC EQU #F600 ; Write Only
PPI_CTRL EQU #F700 ; Registre de controle. Write Only
Utilisation
Il reste maintenant à utiliser ces macros dans un exemple concret. Si on reprend l’exemple du début, on aurait cela:
ACTION_KEYLEFT:
LD a,(POSITION_X)
INC A
LD (POSITION_X),A
RET
LOOP:
GET_KB_STATE kbstate,0,10
CHECK_ACTION_KEYS kbstate
JP LOOP
kbstate: ds 10,#ff
Conclusion
Le code présenté est très pratique pour développer rapidement, sans surcoût inutile (si on ne souhaite pas gérer une touche, le code associé n’est pas généré). Il existe quelques restrictions, facilement contournables:
- L’appui simultané de plusieurs touches n’est pas géré. Pour cela, il faut remplacer le JP {action} par un CALL et retirer les quelques lignes relative à ‘end_actions’.
- Il faut définir les actions avant l’appel à la macro CHECK_ACTION_KEYS . En effet la directive IFDEF ne concerne que les symboles qui ont été définis avant. On peut contourner le problème avec la directive ORG si on veut que le code des actions soit placé après, dans la mémoire
Liens
- Documentations:
- Sur le site du quasar : Routine Clavier Rapide
- Sur CPC Wiki: How To Access the PSG via PPI
- Discussions sur divers forums: