How can I get the keyboard scan code in java?

后端 未结 2 1620
孤街浪徒
孤街浪徒 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]
    
    0 讨论(0)
  • 2020-12-04 00:01

    As MadProgrammer said: You have to use JNA or JNI. You can also have a look at those projects:

    • jintellitype (Windows only)

    JIntellitype is a Java API for interacting with Microsoft Intellitype commands as well as registering for Global Hotkeys in your Java application. The API is a Java JNI library that uses a C++ DLL to do all the communication with Windows.

    There are similar projects Linux and Mac OS X.


    • JNativeHook (Windows, Linux and Mac OS?)

    JNativeHook is a library to provide global keyboard and mouse listeners for Java. This will allow you to listen for global shortcuts or mouse motion that would otherwise be impossible using pure Java. To accomplish this task, JNativeHook leverages platform dependent native code through Java's native interface to create low level system wide hooks and deliver those events to your application.


    • Java – Global (low level) Keyboard / Mouse Hook (Windows only)

    Windows only, capable of Win 7 / 8 (32 and 64 bit)


    • JNA Keyboard Hook in Windows
    0 讨论(0)
提交回复
热议问题