如何完美模拟KeyEvents? [英] How can I perfectly simulate KeyEvents?

查看:73
本文介绍了如何完美模拟KeyEvents?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

How can I construct my own KeyEvent objects which perfectly (or very closely) match the ones I would receive from a KeyListener when the end-user types something?

例如,我有一个英国的ISO键盘布局,并且输入字符我按 Shift + 2 。如果我在 JFrame上记录使用 KeyListener ,我收到以下事件:

For example, I have a United Kingdom ISO keyboard layout and to type the " character I press Shift+2. If I record this on a JFrame with a KeyListener, I receive the following events:

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数组。

I want to create a method which I would give the " as a char parameter, and it would return an array of the KeyEvents as listed above.

我的问题是:


  • KEY_PRESSED KEY_RELEASED 事件中, keyChar ='' 表示按下的字符(),但是 keyCode = 50 指的是非移位ASCII值(又名 2 )。我需要知道如何从字符中获取此非移位值。

  • In the KEY_PRESSED and KEY_RELEASED events, keyChar='"' represents the character that was pressed ("), however the keyCode=50 refers to the "non-shifted" ASCII value (aka 2). I need to know how to get this non-shifted value from just the " character.

这对于不同的键盘布局,非移位值也会有所不同。例如,美国ANSI布局需要 Shift +'来键入 key,表示 keyCode 将是39而不是50。

This non-shifted value will also be different for different keyboard layouts. For example, the US ANSI layout requires Shift+' to type the " key, which means the keyCode would be 39 rather than 50.

在某些键盘上布局时,Shift键需要键入一个键,而不是其他键。例如,字符需要美国ANSI键盘上的 Shift + 3 ,但不需要在英国ISO键盘上按压。我需要知道是否应该模拟班次按下/释放事件并提供班次修改。

On some keyboard layouts, the shift key is required to type a key, but not on others. The # character for example requires Shift+3 on US ANSI keyboards, but requires no shift press on UK ISO keyboards. I need to know whether I should simulate the shift press/release events and provide a shift modifier.

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

Any insight on how to solve these problems would be appreciated. I should also note that using the Robot class cannot be used in my situation.

推荐答案

没有简单的方法可以将虚拟密钥翻译成实际的密钥序列,或者再次返回,至少不是我能找到的。

There is no "easy" way to translate a virtual key to a actual key sequence or back again, at least not that I've been able to find.

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

The two main ways of dispatching key events is either via java.awt.Robot or directly through the system event queue. Which you want to use will depend on what it is you want to achieve.

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

Components generally won't be able to distinguish between key strokes sent from the keyboard of those your generate your self.

下面的例子很复杂,对不起,我找不到更好的方法来达到我所需的要求。

The sample below is convoluted, I'm sorry, I found no better way to achieve the requirements I needed.

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();
        }
    }
}

这篇关于如何完美模拟KeyEvents?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆