How can I get the keyboard scan code in java?

后端 未结 2 1622
孤街浪徒
孤街浪徒 2020-12-03 23:39

I would like to write an application where the keybindings are specific to the location of the key on the keyboard, not the character they are mapped to. For example, the ke

2条回答
  •  旧巷少年郎
    2020-12-03 23:44

    Excerpt from Oracle's KeyEvent source code:

    //set from native code.
    private transient long rawCode = 0;
    private transient long primaryLevelUnicode = 0;
    private transient long scancode = 0; // for MS Windows only
    private transient long extendedKeyCode = 0;
    

    First, I thought about parsing the KeyEvent's toString() return value because it contains the scancode. But then I wrote a utility method (Tried successfully on Windows 8.) that uses reflection:

    final public static Integer getScancodeFromKeyEvent(final KeyEvent keyEvent) {
    
        Integer ret;
        Field field;
    
        try {
            field = KeyEvent.class.getDeclaredField("scancode");
        } catch (NoSuchFieldException nsfe) {
            System.err.println("ATTENTION! The KeyEvent object does not have a field named \"scancode\"! (Which is kinda weird.)");
            nsfe.printStackTrace();
            return null;
        }
    
        try {
            field.setAccessible(true);
        } catch (SecurityException se) {
            System.err.println("ATTENTION! Changing the accessibility of the KeyEvent class' field \"scancode\" caused a security exception!");
            se.printStackTrace();
            return null;
        }
    
        try {
            ret = (int) field.getLong(keyEvent);
        } catch (IllegalAccessException iae) {
            System.err.println("ATTENTION! It is not allowed to read the field \"scancode\" of the KeyEvent instance!");
            iae.printStackTrace();
            return null;
        }
    
        return ret;
    }
    

    Apparently, resetting the field's accessibility afterwards is not necessary, as I got an exception when using this method while the setAccessible() line was commented out. (I changed it on the fly back and forth and recompiled in IntelliJ while the runtime was still on. Should be the same in Eclipse.) Would be easily possible, though, using the isAccessible() method first.

    I needed the scancode for playing music on the keyboard because changing the keyboard language between QWERTZ and QWERTY swapped the notes accordeonly. It's really sad that we don't have legal access to a scancode-like value. The above solution successfully ignored the current keyboard layout configuration.

    By the way, toString return value for "z" and "y" with US keyboard layout:

    [KEY_PRESSED,keyCode=90,keyText=Z,keyChar='z',keyLocation=KEY_LOCATION_STANDARD,rawCode=90,primaryLevelUnicode=122,scancode=44,extendedKeyCode=0x5a] on frame0]
    [KEY_PRESSED,keyCode=89,keyText=Y,keyChar='y',keyLocation=KEY_LOCATION_STANDARD,rawCode=89,primaryLevelUnicode=121,scancode=21,extendedKeyCode=0x59] on frame0]
    

    With DE keyboard layout:

    [KEY_PRESSED,keyCode=89,keyText=Y,keyChar='y',keyLocation=KEY_LOCATION_STANDARD,rawCode=89,primaryLevelUnicode=121,scancode=44,extendedKeyCode=0x59] on frame0]
    [KEY_PRESSED,keyCode=90,keyText=Z,keyChar='z',keyLocation=KEY_LOCATION_STANDARD,rawCode=90,primaryLevelUnicode=122,scancode=21,extendedKeyCode=0x5a] on frame0]
    

    Mind the scancode.

    As a bonus, off-topic:

    [KEY_PRESSED,keyCode=10,keyText=Enter,keyChar=Enter,keyLocation=KEY_LOCATION_STANDARD,rawCode=13,primaryLevelUnicode=13,scancode=28,extendedKeyCode=0xa] on frame0]
    [KEY_PRESSED,keyCode=10,keyText=Enter,keyChar=Enter,keyLocation=KEY_LOCATION_NUMPAD,rawCode=13,primaryLevelUnicode=13,scancode=28,extendedKeyCode=0xa] on frame0]
    [KEY_PRESSED,keyCode=49,keyText=1,keyChar='1',keyLocation=KEY_LOCATION_STANDARD,rawCode=49,primaryLevelUnicode=49,scancode=2,extendedKeyCode=0x31] on frame0]
    [KEY_PRESSED,keyCode=97,keyText=NumPad-1,keyChar='1',keyLocation=KEY_LOCATION_NUMPAD,rawCode=97,primaryLevelUnicode=49,scancode=79,extendedKeyCode=0x61] on frame0]
    

提交回复
热议问题