Re: Scrutation clavier Amstrad

Top Page

Reply to this message
Author: Edgar Bonet
Date:  
To: guilde
Subject: Re: Scrutation clavier Amstrad
Bonsoir !

Frédéric a écrit :
> dans [le cas où deux touches sont appuyées sur la même ligne], ma
> routine ne marche pas du tout, car je compare la donnée brute pour
> retrouver la touche, mais s'il y a 2 bits modifiés, ça ne matche
> aucune touche.


Si tu veux gérer ce cas, à mon avis tu ne peux pas faire mieux que de
tester chaque bit de la ligne un par un. Et pour le coup, je ne pense
pas que le XOR avec la lecture précédente te soit très utile, car tu
dois distinguer trois cas :

- touche pas enfoncée → rien à faire
- touche enfoncée qui ne l'était pas avant → nouvelle frappe
- touche enfoncée qui l'était avant → gérer la répétition

Il n'y a pas besoin de détecter le cas où la touche est relâchée, sauf
si tu veux générer des événements « key release ».

> il faut aussi gérer l'arrêt de la répétition, qui intervient soit
> quand on presse une nouvelle touche, soit quand on relâche celle qui a
> déclenché la répétition :o/


Si tu veux arrêter la répétition quand une autre touche est appuyée, ça
veut dire qu'au plus une touche peut répéter. Pour ça tu peux garder en
mémoire la position de la dernière touche enfoncée et, quand tu détectes
une touche qui est maintenue enfoncée, tu la fais répéter uniquement si
c'est la dernière touche enfoncée.

Je te propose l'algo ci dessous. Je l'ai écrit en C, mais j'imagine que
ça doit pouvoir facilement s'adapter en assembleur.

À+,

Edgar.

------------------------------------------------------------------------
#define LINES 10
#define COLUMNS 8
#define AUTO_REPEAT_DELAY ...
#define AUTO_REPEAT_PERIOD ...

extern emit_key_press_event(uint8_t line, uint8_t column);

uint8_t keyboard_states[2][LINES]; // double buffer
uint8_t current_buffer = 0;
uint8_t timer;
uint8_t last_key_line;
uint8_t last_key_column;

void scan_keyboard(void)
{
    // Switch buffers.
    uint8_t previous_buffer = current_buffer;
    current_buffer ^= 1;


    for (int line = 0; line < LINES; line++) {


        // Update port state.
        PORTC = (PORTC & 0xf0) | line;  // select kbd line
        keyboard_states[current_buffer][line] = PORTA;


        // Optimize the case when no key is pressed in the line.
        if (keyboard_states[current_buffer][line] == 0xff)
            continue;


        // Check each key within the line.
        for (int column = 0; column < COLUMNS; column++) {
            uint8_t mask = 1<<column;


            // Key not pressed -> nothing to do.
            if (keyboard_states[current_buffer][line] & mask)
                continue;


            // Key has just been pressed.
            if (keyboard_states[previous_buffer][line] & mask) {
                emit_key_press_event(line, column);
                last_key_line = line;
                last_key_column = column;
                timer = AUTO_REPEAT_DELAY;
                continue;
            }


            // Key is being held down. Only the key that was last
            // pressed can auto-repeat.
            if (line == last_key_line && column == last_key_column) {
                if (--timer == 0) {
                    emit_key_press_event(line, column);
                    timer = AUTO_REPEAT_PERIOD;
                }
            }
        }
    }
}
------------------------------------------------------------------------