Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GetAsyncKeyState and VirtualKeys/special characters using JNA (JAVA)

I am working on a two-way private chat that will work in a full screen game.

This is required to let the user to type into a semi-transparent textbox at the top of the screen even when it doesn't have focus.

Using the following code, I can detect ALL physical keys, but have a tough time with virtual keys.

SHIFT is detected.

2 is detected.

However Shift + 2 are detected both as separate keys (Even though [SHIFT+2] gives @ on my keyboard). IE: The program outputs both SHIFT, and 2, but not what they produce: @.

The problem is, how will I convert to a character depending on the keyboard? For example:

  • On a UK Keyboard, SHIFT+2 will give me " (quotes).
  • On a US keyboard, SHIFT +2 will give me @.

How can I convert to a specific character depending on the keyboard?

Here is the code so far:

static interface User32 extends Library {
    public static User32 INSTANCE = (User32) Native.loadLibrary("User32", User32.class);

    short GetAsyncKeyState(int key);
    short GetKeyState(int key);

    IntByReference GetKeyboardLayout(int dwLayout);
    int MapVirtualKeyExW (int uCode, int nMapType, IntByReference dwhkl);

    boolean GetKeyboardState(byte[] lpKeyState);

    int ToUnicodeEx(int wVirtKey, int wScanCode, byte[] lpKeyState, char[] pwszBuff, int cchBuff, int wFlags, IntByReference dwhkl);

}



public static void main(String[] args)  {   
    long currTime = System.currentTimeMillis();

    while (System.currentTimeMillis() < currTime + 20000)
    {
        for (int key = 1; key < 256; key++)
            {
                if (isKeyPressed(key)) 
                    getKeyType(key);
            }
    }
}



private static boolean isKeyPressed(int key)
{
    return User32.INSTANCE.GetAsyncKeyState(key) == -32767;
}



private static void getKeyType(int key)
{

    boolean isDownShift = (User32.INSTANCE.GetKeyState(VK_SHIFT) & 0x80) == 0x80;
    boolean isDownCapsLock = (User32.INSTANCE.GetKeyState(VK_CAPS)) != 0;


    byte[] keystate = new byte[256];
    User32.INSTANCE.GetKeyboardState(keystate); 


    IntByReference keyblayoutID = User32.INSTANCE.GetKeyboardLayout(0);
    int ScanCode  = User32.INSTANCE.MapVirtualKeyExW(key, MAPVK_VK_TO_VSC, keyblayoutID);






    char[] buff = new char[10];

    int bufflen = buff.length;
    int ret = User32.INSTANCE.ToUnicodeEx(key, ScanCode, keystate, buff, bufflen, 0, keyblayoutID);


    switch (ret)
    {
        case -1: 
            System.out.println("Error");
        break;

        case 0:  // no translation

        break;

        default: 
        System.out.println("output=" + String.valueOf(buff).substring(0, ret));
    }




}

It works fine and outputs the keys pressed, but doesn't work with Shift + combinations. I realize that I could do a "Switch" and change Shift+3 to "£", but this will not work with different keyboards.

like image 713
David Avatar asked Jun 04 '11 14:06

David


1 Answers

Try to use JIntelliType library instead. Its much simplier to use than JNA and it should be able to do SHIFT + key (MOD_SHIFT). The only problem you can have is detecting 3, but thats easy to solve (for example by KeyListener printing code of the key).

like image 52
Erveron Avatar answered Oct 28 '22 02:10

Erveron