Если вы добавите привязку клавиш в java с маской — скажем, ActionEvent.ALT_MASK с KeyEvent.VK_A — и затем вы нажмете эту клавишу (ALT + A), НО, вы отпустите клавишу alt просто перед клавишей «A» вы обычно сталкиваетесь с проблемой, когда actionPerformed() в классе (реализующем ActionListener) будет продолжать активироваться. Это, вероятно (уверен на 98%), означает, что привязка ключей никогда не регистрировала освобождение ключа. Если вы отпустите клавишу «A» перед клавишей alt, все в порядке, но, как я уже сказал, если вы отпустите клавишу alt, возможно, за 1/10 секунды до другой клавиши, она будет повторяться.
Примечание: видимо, это происходит только в моей программе (здесь)
Попробуйте сами, если не верите мне. Вот фрагмент моего кода:
public ConwayPanel() {
super();
setBackground(new Color(245, 255, 245, 255)); // BG slightly green - all ready
paused = true; // nothing to play... in FUTURE put cool organism in
startX = 0; // starting position of the left of the grid
startY = 0; // starting position of the top of the grid
zoom = 15; // the width of each cell (EXCLUDING the lines that make up the boundaries)
cellNum = 1000; // The number of cells
cells = new boolean[cellNum][cellNum]; // populate cells with false/dead
currentX = 0; // current x cursor position
currentY = 0; // current y cursor position
flipBoundaries = new int[4];
hideCurrentPos = false; // don't want to hide cursor position unless explicitly told to do so
defineMaps(); // creates Key enums
setKeyBindings(); // defines Key and KeyNoMask key bindings
Timer timer = new Timer(100, new KeyListener());
timer.start();
setupMouseListeners(); // creates MouseListener, MouseMotionListener and MouseWheelListener
setFocusable(true); // make isFocusable() true
requestFocusInWindow(); // get focus for listeners
}
private void defineMaps() {
for (KeyAltMask key : KeyAltMask.values()) {
keyMap.put(key, false); // value true when key is pressed - all initiated to false
}
for (KeyNoMask key : KeyNoMask.values()) {
keyNoMaskMap.put(key, false); // value true when key is pressed - all initiated to false
}
}
private void setKeyBindings() {
InputMap inMap = getInputMap(JComponent.WHEN_FOCUSED/* or... WHEN_IN_FOCUSED_WINDOW*/);
ActionMap actMap = getActionMap();
for (final KeyAltMask key : KeyAltMask.values()) {
KeyStroke pressed = KeyStroke.getKeyStroke(key.getKeyCode(), ActionEvent.ALT_MASK, false); // just right! (not blocking shortcut key and preventing accidental keyboard mishaps)
KeyStroke released = KeyStroke.getKeyStroke(key.getKeyCode(), ActionEvent.ALT_MASK, true); // just right! (not blocking shortcut key and preventing accidental keyboard mishaps)
inMap.put(pressed, key.toString() + "pressed");
inMap.put(released, key.toString() + "released");
actMap.put(key.toString() + "pressed", new AbstractAction() { // adds each value of Key into a HashMap (when the key is pressed) and puts that HashMap action into ActionMap
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyMap.put(key, true);
}
});
actMap.put(key.toString() + "released", new AbstractAction() { // adds each value of Key into a HashMap (when the key is released) and puts that HashMap action into ActionMap
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyMap.put(key, false);
}
});
}
for (final KeyNoMask key : KeyNoMask.values()) {
KeyStroke pressed = KeyStroke.getKeyStroke(key.getKeyCode(), 0, false);
KeyStroke released = KeyStroke.getKeyStroke(key.getKeyCode(), 0, true);
inMap.put(pressed, key.toString() + "pressed");
inMap.put(released, key.toString() + "released");
actMap.put(key.toString() + "pressed", new AbstractAction() { // adds each value of KeyNoMask into a HashMap (when the key is pressed) and puts that HashMap action into ActionMap
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyNoMaskMap.put(key, true);
}
});
actMap.put(key.toString() + "released", new AbstractAction() { // adds each value of KeyNoMask into a HashMap (when the key is released) and puts that HashMap action into ActionMap
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyNoMaskMap.put(key, false);
}
});
}
}
private class KeyListener implements ActionListener { // probably not great to have same name, but "real" KeyListener not imported
@Override
public void actionPerformed(ActionEvent e) {
for (KeyAltMask key : KeyAltMask.values()) { // run through the ALL of the keys
if (keyMap.get(key)) { // if key in HashMap is true (i.e. the actionPerformed() above set it true)
switch(key.toString()) {
case "c": // clear all cells and pause if not paused
for (int y = 0; y < cellNum; y++) {
for (int x = 0; x < cellNum; x++) {
cells[x][y] = false;
}
}
if (!paused) {
paused = true;
}
break;
case "f": // fill all cells and pause if not paused
for (int y = 0; y < cellNum; y++) {
for (int x = 0; x < cellNum; x++) {
cells[x][y] = true;
}
if (!paused) {
paused = true;
}
}
break;
case "i": // invert all cells and pause if not paused
for (int y = 0; y < cellNum; y++) {
for (int x = 0; x < cellNum; x++) {
cells[x][y] = !cells[x][y];
}
if (!paused) {
paused = true;
}
}
break;
case "l": // lock all cells that have a live/true cell
for (int y = 0; y < cellNum; y++) {
for (int x = 0; x < cellNum; x++) {
if (cells[x][y]) {
//set Lock
}
}
}
break;
case "p": // pause/play
paused = !paused;
break;
case "s": // step once
step = true;
break;
case "h": // hide current cursor position
hideCurrentPos = !hideCurrentPos;
break;
// default:
}
}
}
for (KeyNoMask key : KeyNoMask.values()) { // run through ALL of the keys (this is the beauty of key bindings - you can move the cursor diagonally). I kinda like a pause after the first key press, though
if (keyNoMaskMap.get(key)) { // if key in HashMap is true (i.e. the actionPerformed() above returned true)
switch(key.toString()) { // move cursor position appropriately and pause if not paused
case "down":
currentY += currentY == cellNum - 1 ? 0 : 1;
if (!paused) {
paused = true;
}
break;
case "up":
currentY -= currentY == 0 ? 0 : 1;
if (!paused) {
paused = true;
}
break;
case "left":
currentX -= currentX == 0 ? 0 : 1;
if (!paused) {
paused = true;
}
break;
case "right":
currentX += currentX == cellNum - 1 ? 0 : 1;
if (!paused) {
paused = true;
}
break;
case "space": // flip pixel at current cursor position
flipCell(currentX, currentY);
if (!paused) {
paused = true;
}
// default:
}
}
}
}
}
Кода много, но он довольно стандартный, по крайней мере, для KeyBindings. Итак, мне было интересно, есть ли способ обойти это. Является ли это ошибкой ОС или ошибкой Java и как я могу это исправить. Я хотел бы избежать else
в actionPerformed()
, потому что мне нужно, чтобы это было быстро. Кроме того, можно ли как-то оптимизировать метод actionPerformed()
, потому что кажется, что он может быть немного странным.
Я только что собрал это вместе, но это не здесь! Небольшой исполняемый файл:
package bindingstest;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
/**
*
* @author Dylan AND Hovercraft Full Of Eels
*/
public class BindingsTest {
static Map<Key, Boolean> keyMap = new HashMap<>();
enum Key { // possibly used in conjunction with mask in order to prevent keyboard mishaps - it will probably be ALT in FUTURE
a(KeyEvent.VK_A),
b(KeyEvent.VK_B),
c(KeyEvent.VK_C),
d(KeyEvent.VK_D),
e(KeyEvent.VK_E),
f(KeyEvent.VK_F);
private final int keyCode;
private Key(int keyCode) {
this.keyCode = keyCode; // KeyEvent.VK_...
}
public int getKeyCode() {
return keyCode;
}
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setBounds(50, 50, 1000, 1000);
JPanel panel = new JPanel();
panel.setFocusable(true);
panel.requestFocusInWindow();
for (Key key : Key.values()) {
keyMap.put(key, false);
}
InputMap inMap = panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap actMap = panel.getActionMap();
for (final Key key : Key.values()) {
KeyStroke pressed = KeyStroke.getKeyStroke(key.getKeyCode(), ActionEvent.ALT_MASK, false);
KeyStroke released = KeyStroke.getKeyStroke(key.getKeyCode(), ActionEvent.ALT_MASK, true);
inMap.put(pressed, key.toString() + "pressed");
inMap.put(released, key.toString() + "released");
actMap.put(key.toString() + "pressed", new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyMap.put(key, true);
}
});
actMap.put(key.toString() + "released", new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyMap.put(key, false);
}
});
}
for (final Key key : Key.values()) {
KeyStroke pressed = KeyStroke.getKeyStroke(key.getKeyCode(), 0, false);
KeyStroke released = KeyStroke.getKeyStroke(key.getKeyCode(), 0, true);
inMap.put(pressed, key.toString() + "pressed");
inMap.put(released, key.toString() + "released");
actMap.put(key.toString() + "pressed", new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyMap.put(key, true);
}
});
actMap.put(key.toString() + "released", new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
keyMap.put(key, false);
}
});
}
Timer timer = new Timer(100, new KeyListener());
timer.start();
frame.add(panel);
}
private static class KeyListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
for (Key key : Key.values()) { // run through the ALL of the keys
if (keyMap.get(key)) { // if key in HashMap is true (i.e. the actionPerformed() above set it true)
switch(key.toString()) {
case "a":
System.out.println("a");
break;
case "b":
System.out.println("b");
break;
case "c":
System.out.println("c");
break;
case "d":
System.out.println("d");
break;
case "e":
System.out.println("e");
break;
case "f":
System.out.println("f");
}
}
}
}
}
}