10

我如何构建自己的对象,这些对象与最终用户键入内容时KeyEvent收到的对象完全(或非常接近)匹配?KeyListener


例如,我有一个英国 ISO 键盘布局并输入"我按的字符Shift+2。如果我用 a 将其记录在 aJFrameKeyListener,我会收到以下事件:

java.awt.event.KeyEvent[KEY_PRESSED,keyCode=16,keyText=Shift,keyChar=Undefined keyChar,modifiers=Shift,extModifiers=Shift,keyLocation=KEY_LOCATION_LEFT,rawCode=16,primaryLevelUnicode=0,scancode=42,extendedKeyCode=0x10] on frame0
java.awt.event.KeyEvent[KEY_PRESSED,keyCode=50,keyText=2,keyChar='"',modifiers=Shift,extModifiers=Shift,keyLocation=KEY_LOCATION_STANDARD,rawCode=50,primaryLevelUnicode=50,scancode=3,extendedKeyCode=0x32] on frame0
java.awt.event.KeyEvent[KEY_TYPED,keyCode=0,keyText=Unknown keyCode: 0x0,keyChar='"',modifiers=Shift,extModifiers=Shift,keyLocation=KEY_LOCATION_UNKNOWN,rawCode=0,primaryLevelUnicode=0,scancode=0,extendedKeyCode=0x0] on frame0
java.awt.event.KeyEvent[KEY_RELEASED,keyCode=16,keyText=Shift,keyChar=Undefined keyChar,keyLocation=KEY_LOCATION_LEFT,rawCode=16,primaryLevelUnicode=0,scancode=42,extendedKeyCode=0x10] on frame0
java.awt.event.KeyEvent[KEY_RELEASED,keyCode=50,keyText=2,keyChar='"',keyLocation=KEY_LOCATION_STANDARD,rawCode=50,primaryLevelUnicode=50,scancode=3,extendedKeyCode=0x32] on frame0

我想创建一个方法,将其"作为 char 参数提供,它会返回上面列出的 KeyEvents 数组。

我的问题是:

  • KEY_PRESSEDandKEY_RELEASED事件中,keyChar='"'表示被按下的字符 ( "),但是keyCode=50指的是“未移位”的 ASCII 值 (aka 2)。"我需要知道如何仅从角色中获取此非移位值。

  • 对于不同的键盘布局,此非移位值也将有所不同。例如,美国 ANSI 布局要求Shift+'键入"密钥,这意味着keyCode39 而不是 50。

  • 在某些键盘布局中,需要使用 shift 键来键入一个键,但在其他键盘布局中则不需要。例如,该#字符Shift+3在美国 ANSI 键盘上需要,但在英国 ISO 键盘上不需要移位键。我需要知道是否应该模拟换档按下/释放事件并提供换档修饰符。

任何有关如何解决这些问题的见解将不胜感激。我还应该注意,Robot在我的情况下不能使用该类。

4

1 回答 1

6

没有“简单”的方法可以将虚拟键转换为实际键序列或再次返回,至少不是我能够找到的。

调度关键事件的两种主要方式是通过java.awt.Robot或直接通过系统事件队列。您要使用哪个取决于您要实现的目标。

组件通常无法区分从您自己生成的键盘发送的击键。

下面的示例令人费解,对不起,我没有找到更好的方法来满足我需要的要求。

public class TestKeyEvents {
    public static void main(String[] args) {
        new TestKeyEvents();
    }
    public TestKeyEvents() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }
                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
                new Thread(new KeyDispatcher()).start();
            }
        });
    }
    public class TestPane extends JPanel {
        public TestPane() {
            setLayout(new BorderLayout());
            JTextArea area = new JTextArea(10, 30);
            area.setWrapStyleWord(true);
            area.setLineWrap(true);
            add(area);
        }
    }
    public class KeyDispatcher implements Runnable {
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
            }
            dispatchKeyEventsViaEventQueue();
            dispatchKeyEventsViaRobot();
        }

        protected void dispatchKeyEventsViaEventQueue() {
            if (EventQueue.isDispatchThread()) {
                String text = "This is a key sequence dispatched via the event queue\n";
                KeySequence keySequence = getKeySequence(text);
                List<KeyEvent> events = new ArrayList<>();
                List<Integer> modifers = new ArrayList<>();
                for (Key key : keySequence) {
                    events.clear();
                    System.out.println(key);
                    switch (key.getStrokeType()) {
                        case Press:
                            switch (key.getKeyCode()) {
                                case KeyEvent.VK_SHIFT:
                                case KeyEvent.VK_ALT:
                                case KeyEvent.VK_CONTROL:
                                case KeyEvent.VK_META:
                                    if (!modifers.contains(key.getKeyCode())) {
                                        modifers.add(key.getKeyCode());
                                    }
                                    break;
                                default:
                                    events.add(new KeyEvent(new JPanel(), KeyEvent.KEY_PRESSED, System.currentTimeMillis(), getModifiers(modifers), key.getKeyCode(), key.getKeyChar()));
                                    break;
                            }
                            break;
                        case Release:
                            switch (key.getKeyCode()) {
                                case KeyEvent.VK_SHIFT:
                                case KeyEvent.VK_ALT:
                                case KeyEvent.VK_CONTROL:
                                case KeyEvent.VK_META:
                                    if (!modifers.contains(key.getKeyCode())) {
                                        modifers.remove(key.getKeyCode());
                                    }
                                    break;
                                default:
                                    events.add(new KeyEvent(new JPanel(), KeyEvent.KEY_RELEASED, System.currentTimeMillis(), getModifiers(modifers), key.getKeyCode(), key.getKeyChar()));
                                    break;
                            }
                            break;
                        case Type:
                            events.add(new KeyEvent(new JPanel(), KeyEvent.KEY_PRESSED, System.currentTimeMillis(), getModifiers(modifers), key.getKeyCode(), key.getKeyChar()));
                            events.add(new KeyEvent(new JPanel(), KeyEvent.KEY_RELEASED, System.currentTimeMillis(), getModifiers(modifers), key.getKeyCode(), key.getKeyChar()));
                            events.add(new KeyEvent(new JPanel(), KeyEvent.KEY_TYPED, System.currentTimeMillis(), getModifiers(modifers), KeyEvent.VK_UNDEFINED, key.getKeyChar()));
                            break;
                    }

                    for (KeyEvent evt : events) {
                        Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(evt);
                    }
                }
            } else {
                try {
                    SwingUtilities.invokeAndWait(new Runnable() {
                        @Override
                        public void run() {
                            dispatchKeyEventsViaEventQueue();
                        }
                    });
                } catch (Exception exp) {
                    exp.printStackTrace();
                }
            }
        }

        protected void dispatchKeyEventsViaRobot() {
            try {
                Robot robot = new Robot();
                String text = "This is a key sequence dispatched via java.awt.Robot\n";
                KeySequence keySequence = getKeySequence(text);
                List<KeyEvent> events = new ArrayList<>();
                for (Key key : keySequence) {
                    events.clear();
                    System.out.println(key);
                    switch (key.getStrokeType()) {
                        case Press:
                            robot.keyPress(key.getKeyCode());
                            break;
                        case Release:
                            robot.keyRelease(key.getKeyCode());
                            break;
                        case Type:
                            robot.keyPress(key.getKeyCode());
                            robot.keyRelease(key.getKeyCode());
                            break;
                    }
                }
            } catch (AWTException exp) {
                exp.printStackTrace();
            }
        }
    }

    protected int getModifiers(List<Integer> mods) {
        int result = 0;
        for (int mod : mods) {
            result &= mod;
        }
        return result;
    }

    public static class Key {
        public enum StrokeType {
            Type,
            Press,
            Release
        }
        private StrokeType strokeType;
        private int keyCode;
        private char keyChar;
        public Key(StrokeType type, int keyCode, char keyChar) {
            this.strokeType = type;
            this.keyCode = keyCode;
            this.keyChar = keyChar;
        }

        public StrokeType getStrokeType() {
            return strokeType;
        }

        public int getKeyCode() {
            return keyCode;
        }

        public char getKeyChar() {
            return keyChar;
        }

        @Override
        public String toString() {
            return getStrokeType().name() + " " + getKeyChar() + " (" + getKeyCode() + ")";
        }
    }

    public static KeySequence getKeySequence(String text) {
        KeySequence ks = new KeySequence();
        for (char c : text.toCharArray()) {
            addKeySequence(ks, c);
        }
        return ks;
    }

    public static void addKeySequence(KeySequence ks, char character) {
        switch (character) {
            case 'a':
                ks.type(KeyEvent.VK_A, character);
                break;
            case 'b':
                ks.type(KeyEvent.VK_B, character);
                break;
            case 'c':
                ks.type(KeyEvent.VK_C, character);
                break;
            case 'd':
                ks.type(KeyEvent.VK_D, character);
                break;
            case 'e':
                ks.type(KeyEvent.VK_E, character);
                break;
            case 'f':
                ks.type(KeyEvent.VK_F, character);
                break;
            case 'g':
                ks.type(KeyEvent.VK_G, character);
                break;
            case 'h':
                ks.type(KeyEvent.VK_H, character);
                break;
            case 'i':
                ks.type(KeyEvent.VK_I, character);
                break;
            case 'j':
                ks.type(KeyEvent.VK_J, character);
                break;
            case 'k':
                ks.type(KeyEvent.VK_K, character);
                break;
            case 'l':
                ks.type(KeyEvent.VK_L, character);
                break;
            case 'm':
                ks.type(KeyEvent.VK_M, character);
                break;
            case 'n':
                ks.type(KeyEvent.VK_N, character);
                break;
            case 'o':
                ks.type(KeyEvent.VK_O, character);
                break;
            case 'p':
                ks.type(KeyEvent.VK_P, character);
                break;
            case 'q':
                ks.type(KeyEvent.VK_Q, character);
                break;
            case 'r':
                ks.type(KeyEvent.VK_R, character);
                break;
            case 's':
                ks.type(KeyEvent.VK_S, character);
                break;
            case 't':
                ks.type(KeyEvent.VK_T, character);
                break;
            case 'u':
                ks.type(KeyEvent.VK_U, character);
                break;
            case 'v':
                ks.type(KeyEvent.VK_V, character);
                break;
            case 'w':
                ks.type(KeyEvent.VK_W, character);
                break;
            case 'x':
                ks.type(KeyEvent.VK_X, character);
                break;
            case 'y':
                ks.type(KeyEvent.VK_Y, character);
                break;
            case 'z':
                ks.type(KeyEvent.VK_Z, character);
                break;
            case 'A':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_A, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'B':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_B, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'C':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_C, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'D':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_D, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'E':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_E, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'F':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_F, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'G':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_G, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'H':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_H, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'I':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_I, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'J':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_J, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'K':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_K, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'L':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_L, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'M':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_M, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'N':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_N, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'O':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_O, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'P':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_P, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'Q':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_Q, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'R':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_R, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'S':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_S, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'T':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_T, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'U':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_U, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'V':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_V, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'W':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_W, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'X':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_X, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'Y':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_Y, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case 'Z':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_Z, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case '`':
                ks.type(KeyEvent.VK_BACK_QUOTE, character);
                break;
            case '0':
                ks.type(KeyEvent.VK_0, character);
                break;
            case '1':
                ks.type(KeyEvent.VK_1, character);
                break;
            case '2':
                ks.type(KeyEvent.VK_2, character);
                break;
            case '3':
                ks.type(KeyEvent.VK_3, character);
                break;
            case '4':
                ks.type(KeyEvent.VK_4, character);
                break;
            case '5':
                ks.type(KeyEvent.VK_5, character);
                break;
            case '6':
                ks.type(KeyEvent.VK_6, character);
                break;
            case '7':
                ks.type(KeyEvent.VK_7, character);
                break;
            case '8':
                ks.type(KeyEvent.VK_8, character);
                break;
            case '9':
                ks.type(KeyEvent.VK_9, character);
                break;
            case '-':
                ks.type(KeyEvent.VK_MINUS, character);
                break;
            case '=':
                ks.type(KeyEvent.VK_EQUALS, character);
                break;
            case '~':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_BACK_QUOTE, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case '!':
                ks.type(KeyEvent.VK_EXCLAMATION_MARK, character);
                break;
            case '@':
                ks.type(KeyEvent.VK_AT, character);
                break;
            case '#':
                ks.type(KeyEvent.VK_NUMBER_SIGN, character);
                break;
            case '$':
                ks.type(KeyEvent.VK_DOLLAR, character);
                break;
            case '%':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_5, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case '^':
                ks.type(KeyEvent.VK_CIRCUMFLEX, character);
                break;
            case '&':
                ks.type(KeyEvent.VK_AMPERSAND, character);
                break;
            case '*':
                ks.type(KeyEvent.VK_ASTERISK, character);
                break;
            case '(':
                ks.type(KeyEvent.VK_LEFT_PARENTHESIS, character);
                break;
            case ')':
                ks.type(KeyEvent.VK_RIGHT_PARENTHESIS, character);
                break;
            case '_':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_MINUS, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case '+':
                ks.type(KeyEvent.VK_PLUS, character);
                break;
            case '\t':
                ks.type(KeyEvent.VK_TAB, character);
                break;
            case '\n':
                ks.type(KeyEvent.VK_ENTER, character);
                break;
            case '[':
                ks.type(KeyEvent.VK_OPEN_BRACKET, character);
                break;
            case ']':
                ks.type(KeyEvent.VK_CLOSE_BRACKET, character);
                break;
            case '\\':
                ks.type(KeyEvent.VK_BACK_SLASH, character);
                break;
            case '{':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_OPEN_BRACKET, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case '}':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_CLOSE_BRACKET, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case '|':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_BACK_SLASH, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case ';':
                ks.type(KeyEvent.VK_SEMICOLON, character);
                break;
            case ':':
                ks.type(KeyEvent.VK_COLON, character);
                break;
            case '\'':
                ks.type(KeyEvent.VK_QUOTE, character);
                break;
            case '"':
                ks.type(KeyEvent.VK_QUOTEDBL, character);
                break;
            case ',':
                ks.type(KeyEvent.VK_COMMA, character);
                break;
            case '<':
                ks.type(KeyEvent.VK_LESS, character);
                break;
            case '.':
                ks.type(KeyEvent.VK_PERIOD, character);
                break;
            case '>':
                ks.type(KeyEvent.VK_GREATER, character);
                break;
            case '/':
                ks.type(KeyEvent.VK_SLASH, character);
                break;
            case '?':
                ks.press(KeyEvent.VK_SHIFT, '\0');
                ks.type(KeyEvent.VK_SLASH, character);
                ks.release(KeyEvent.VK_SHIFT, '\0');
                break;
            case ' ':
                ks.type(KeyEvent.VK_SPACE, character);
                break;
            default:
                throw new IllegalArgumentException("Cannot type character " + character);
        }
    }

    public static class KeySequence implements Iterable<Key> {
        private List<Key> keys;
        public KeySequence() {
            keys = new ArrayList<>(25);
        }

        public void type(int keyCode, char keyChar) {
            keys.add(new Key(Key.StrokeType.Type, keyCode, keyChar));
        }

        public void press(int keyCode, char keyChar) {
            keys.add(new Key(Key.StrokeType.Press, keyCode, keyChar));
        }

        public void release(int keyCode, char keyChar) {
            keys.add(new Key(Key.StrokeType.Release, keyCode, keyChar));
        }

        public Iterator<Key> iterator() {
            return keys.iterator();
        }
    }
}
于 2013-01-30T23:27:35.883 回答