如何在最终用户键入某些东西时,构建自己的KeyEvent对象,它完美地(或非常接近)匹配从KeyListener接收到的对象?
例如,我有一个英国的ISO键盘布局,并键入“我按下Shift 2的字符.如果我用一个KeyListener在JFrame上记录它,我收到以下事件:
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='"',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,keyLocation=KEY_LOCATION_UNKNOWN,rawCode=0,scancode=0,extendedKeyCode=0x0] on frame0 java.awt.event.KeyEvent[KEY_RELEASED,extendedKeyCode=0x10] on frame0 java.awt.event.KeyEvent[KEY_RELEASED,extendedKeyCode=0x32] on frame0
我想创建一个方法,我将给出“作为一个char参数,它将返回一个如上所列的KeyEvents的数组.
我的问题是:
>在KEY_PRESSED和KEY_RELEASED事件中,keyChar =’“’表示被按下的字符(”),但是keyCode = 50表示“非移位”ASCII值(又称为2).我需要知道如何从“字符”中获取这个非移位值.
>对于不同的键盘布局,此非移位值也将不同.例如,美国ANSI布局要求Shift’键入“键,这意味着keyCode将是39而不是50.
>在某些键盘布局上,需要使用Shift键来键入键,但不需要键.例如,#字符需要在美国ANSI键盘上使用Shift 3,但不需要按英国ISO键盘上的移动键.我需要知道是否应该模拟换档按钮/释放事件并提供换档修改器.
任何关于如何解决这些问题的见解将不胜感激.我也应该注意到,在我的情况下使用Robot类不能使用.
解决方法
将虚拟键转换为实际的键序列或再次返回是没有“简单”的方法,至少我没有找到.
调度关键事件的两种主要方式是通过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,key.getKeyChar())); break; } break; case Type: events.add(new KeyEvent(new JPanel(),key.getKeyChar())); events.add(new KeyEvent(new JPanel(),KeyEvent.KEY_TYPED,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,'\0'); break; case 'C': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_C,'\0'); break; case 'D': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_D,'\0'); break; case 'E': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_E,'\0'); break; case 'F': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_F,'\0'); break; case 'G': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_G,'\0'); break; case 'H': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_H,'\0'); break; case 'I': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_I,'\0'); break; case 'J': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_J,'\0'); break; case 'K': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_K,'\0'); break; case 'L': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_L,'\0'); break; case 'M': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_M,'\0'); break; case 'N': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_N,'\0'); break; case 'O': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_O,'\0'); break; case 'P': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_P,'\0'); break; case 'Q': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_Q,'\0'); break; case 'R': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_R,'\0'); break; case 'S': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_S,'\0'); break; case 'T': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_T,'\0'); break; case 'U': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_U,'\0'); break; case 'V': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_V,'\0'); break; case 'W': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_W,'\0'); break; case 'X': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_X,'\0'); break; case 'Y': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_Y,'\0'); break; case 'Z': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_Z,'\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,'\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,'\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,'\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,'\0'); break; case '}': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_CLOSE_BRACKET,'\0'); break; case '|': ks.press(KeyEvent.VK_SHIFT,'\0'); ks.type(KeyEvent.VK_BACK_SLASH,'\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,'\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,keyChar)); } public void release(int keyCode,char keyChar) { keys.add(new Key(Key.StrokeType.Release,keyChar)); } public Iterator<Key> iterator() { return keys.iterator(); } } }