quarta-feira, 3 de setembro de 2008

KeyDown e KeyUp para applets java

Um grande problema da interface KeyListener do Java é não possuir uma maneira de saber se uma ou mais teclas estão pressionadas ao mesmo tempo, e quando elas realmente são soltas. Quando você mantém uma tecla pressionada os eventos keyPressed e keyReleased são ativados consecutivamente, e se você pressiona e segura outra tecla, o keyReleased da tecla anterior para de ser notificado, seguido por uma notificação consecutiva do keyPressed e keyReleased da nova tecla. Isso é facilmente demonstrado no applet abaixo:
public class ComProblema extends Applet implements KeyListener {
    @Override
    public void init() {
        addKeyListener(this);
    }
    public void keyPressed(KeyEvent e) {
        System.out.println("Pressionou: " + e.getKeyCode());
    }
    public void keyReleased(KeyEvent e) {
        System.out.println("Soltou: " + e.getKeyCode());
    }
    public void keyTyped(KeyEvent e) {}
}
Ao executarmos esse applet clicando e segurando a tecla "a" por alguns segundos, depois apertar e segurar a "w" por outros tantos e ao final soltar as duas, teremos o seguinte resultado:
Pressionou: 65
Soltou: 65
Pressionou: 65
Soltou: 65
Pressionou: 65
Soltou: 65
Pressionou: 65
Soltou: 65
Pressionou: 65
Soltou: 65
Pressionou: 65
Soltou: 65
Pressionou: 65
Pressionou: 87
Soltou: 87
Pressionou: 87
Soltou: 87
Pressionou: 87
Soltou: 87
Pressionou: 87
Soltou: 87
Pressionou: 87
Soltou: 87
Pressionou: 87
Soltou: 87
Pressionou: 87
Soltou: 87
Pressionou: 87
Soltou: 65
Soltou: 87
Encontrei em diversos fóruns pessoas com o mesmo problema e nenhuma solução. Então, para resolvê-lo implementei uma espécie de KeyAdapter para facilitar a notificação de quando uma tecla é apertada e quando ela é solta. O uso de exemplo dela ficaria como o mostrado abaixo:
public class SemProblema extends Applet {
    @Override
    public void init() {
        super.init();
        addKeyListener(new CumulativeKeyAdapterImpl());
    }
}
class CumulativeKeyAdapterImpl extends AcumuladorKeyAdapter {
    @Override
    public void keyDown(KeyEvent e) {
        System.out.println("Down: " + e.getKeyCode());
    }
    @Override
    public void keyUp(KeyEvent e) {
        System.out.println("Up: " + e.getKeyCode());
    }
}
O resultado fazendo a mesma combinação de teclas apertadas no teste anterior neste outro applet, seria como o mostrado a seguir:
Down: 65
Down: 87
Up: 65
Up: 87
Você também pode ver outros exemplos de applets utilizando o AcumuladorKeyAdapter aqui. Para utilizar esse recurso basta baixar os fontes e binários da timotta-api e colocar o timotta-api-applet.jar no atributo archive da sua tag applet, como demonstrado no exemplo abaixo:
<applet code="br.com.timotta.applet.MostraTeclas" 
    archive="timotta-api-applet-exemplos.jar,timotta-api-applet.jar"
    width=256 height=256 >
</applet>

2 comentários: