java swing key bindings – action manquante pour la clé relâchée

Après avoir enregistré les raccourcis clavier pour “SPACE” et “SPACE publié” qui fonctionne comme indiqué lorsque l’espace est la seule touche enfoncée / relâchée, je remarque que vous appuyez sur espace, puis sur ctrl (ou sur toute autre touche de modification), puis que vous relâchez ctrl entraînera l’exécution de l’action associée à “SPACE”, mais pas de l’action associée à “libéré SPACE”.

Quel est le moyen préféré pour que l’action soit exécutée une fois que vous n’avez plus appuyé sur l’espace (ou sur une touche de modification simultanément)? Je n’ai essayé cela que sur Windows 7, 64 bits.

import javax.swing.SwingUtilities; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.AbstractAction; import javax.swing.KeyStroke; import java.awt.event.ActionEvent; import java.awt.Cursor; class Bind extends JPanel { { getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "pressed"); getInputMap().put(KeyStroke.getKeyStroke("released SPACE"), "released"); getActionMap().put("pressed", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { System.out.println("pressed"); setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); } }); getActionMap().put("released", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { System.out.println("released"); setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } }); } public static void main(Ssortingng[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JFrame f = new JFrame("Key Bindings"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.add(new Bind()); f.setSize(640, 480); f.setVisible(true); } }); } } 

UPDATE : C’est le moyen d’éviter un espace collant lorsque vous appuyez accidentellement sur ctrl, alt ou shift avant de libérer de l’espace:

 import javax.swing.SwingUtilities; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.AbstractAction; import javax.swing.KeyStroke; import java.awt.event.ActionEvent; import java.awt.Cursor; class Bind extends JPanel { { getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "pressed"); getInputMap().put(KeyStroke.getKeyStroke("released SPACE"), "released"); getInputMap().put(KeyStroke.getKeyStroke("ctrl released SPACE"), "released"); getInputMap().put(KeyStroke.getKeyStroke("shift released SPACE"), "released"); getInputMap().put(KeyStroke.getKeyStroke("shift ctrl released SPACE"), "released"); getInputMap().put(KeyStroke.getKeyStroke("alt released SPACE"), "released"); getInputMap().put(KeyStroke.getKeyStroke("alt ctrl released SPACE"), "released"); getInputMap().put(KeyStroke.getKeyStroke("alt shift released SPACE"), "released"); getInputMap().put(KeyStroke.getKeyStroke("alt shift ctrl released SPACE"), "released"); getActionMap().put("pressed", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { System.out.println("pressed"); setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); } }); getActionMap().put("released", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { System.out.println("released"); setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } }); } public static void main(Ssortingng[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JFrame f = new JFrame("Key Bindings"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.add(new Bind()); f.setSize(640, 480); f.setVisible(true); } }); } } 

Cela signifie que l’événement released SPACE n’est pas déclenché lorsque la touche Contrôle est toujours enfoncée. Je m’attendrais à ce qu’un événement control released SPACE soit déclenché.

Ajoutez ce qui suit à votre code:

 getInputMap().put(KeyStroke.getKeyStroke("control released SPACE"), "released"); 

Pour la même raison, l’événement SPACE ne se déclenchera pas si vous maintenez la touche Contrôle enfoncée. Vous devrez donc également append des liaisons pour le control SPACE .

Vous devez le faire pour toutes les touches de modification, ce qui peut être une solution plus simple que de suivre les événements de touches.

Il est possible que votre système d’exploitation ne déclenche pas les événements keyReleased , mais uniquement les événements keyPressed et keyTyped , ou une autre combinaison. Vérifiez-le d’abord. Vous devrez peut-être simplement vérifier les événements keyTyped au lieu de keyReleased et vous en aurez fini.

Réponse courte:

Utilisez un masque de bits ou un tableau pour savoir quelles clés sont actuellement à l’état “enfoncé”, puis utilisez celles qui ont la valeur pour déclencher des événements. Autrement dit, n’utilisez pas les événements Swing directement pour déclencher des réponses dans votre application. Vous avez besoin d’un calque supplémentaire qui stocke essentiellement l’état du clavier. À partir de cet état, il effectue les actions appropriées.

Il existe également des méthodes disponibles ( voir la fin de ce didacticiel – “isAltDown”, “isCtrlDown” etc. ) pour vérifier si les touches de modification sont activées lorsque vous recevez un événement tel que la touche “Espace”.

Longue réponse:

Vous avez raison de dire que les événements sont déclenchés lorsque les touches sont enfoncées et relâchées. Cela doit en quelque sorte fonctionner de telle sorte que vous puissiez prendre en charge des applications qui doivent traiter ces événements séparément, et non ensemble. Un exemple (bien que ce ne soit pas le seul) concerne les jeux vidéo sur PC où vous pouvez appuyer simultanément sur plusieurs touches alphabétiques / de modification (par exemple, A pour aller à gauche et W pour avancer) et le jeu doit traiter ces deux événements sont des entrées distinctes, par opposition aux entrées composites, ce qui entraîne votre mouvement en avant gauche.

Donc, ce que vous voulez faire, si vous avez besoin de traiter des entrées composites, c’est simplement un tableau des actions auxquelles votre application doit répondre, ainsi que leurs liaisons de touches associées (que ce soit une ou plusieurs clés n’a pas d’importance ). Lorsqu’une touche est enfoncée, vous activez un indicateur indiquant qu’elle est actuellement “enfoncée” et effacez l’indicateur lorsqu’il est relâché.

Ensuite, pour déclencher vos événements, il vous suffit de vérifier toutes les touches sur lesquelles vous appuyez (en vérifiant quelles touches sont activées), et si la combinaison de touches d’un événement particulier est activée, l’événement est déclenché.

Si vous avez moins de 32 clés qui déclenchent des événements, vous pouvez le faire avec un masque binary et une valeur int 32 bits, plutôt que sous la forme d’un tableau. En fait, c’est beaucoup plus simple de le faire de cette façon si vous le pouvez. Si vous avez besoin de 64 clés au maximum, faites la même chose avec un long . Si vous avez très peu de clés qui déclenchent des événements (8 ou moins, par exemple), vous pouvez utiliser le type short 8 bits.