当前位置: 首页 > 面试题库 >

使用JNA(JAVA)的GetAsyncKeyState和VirtualKeys /特殊字符

姚智
2023-03-14
问题内容

我正在双向聊天,将在全屏游戏中使用。

这是使用户 即使在没有焦点的情况下也可以 在屏幕顶部键入半透明文本框的必需项。

使用以下代码, 我可以检测到所有物理密钥 ,但是使用虚拟密钥时比较困难。

SHIFT 被检测到。

2 被检测到。

但是Shift + 2,这两个键都被检测为单独的键(即使键盘上[SHIFT+2]给出@了)。IE:程序输出SHIFT和2,但不输出它们产生的:@

问题是,如何根据键盘转换为字符?例如:

  • 在英国键盘上,SHIFT + 2会给我"(引号)。
  • 在美式键盘上,SHIFT +2会给我@

如何根据键盘转换为特定字符?

这是到目前为止的代码:

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




}

它可以正常工作并输出已按下的键,但不适用于Shift +组合键。我意识到我可以执行“切换”并将Shift + 3更改为“£”,但这不适用于其他键盘。


问题答案:

我知道了。经过许多小时的搜索,我设法创建了一种方法,可以将组合转换为当前键盘布局上的组合。它不处理死键(例如重音符号),但是捕获了[SHIFT+Combinations]我需要捕获的所有内容。

要使用它,请按以下方式调用它:

getCharacter(int vkCode, boolean shiftKeyPressed);

因此,请观看此魔术。如果我想得到SHIFT+3键盘上的东西(£),请使用:

getCharacter(KeyEvent.VK_3, true);

这是代码:

public static char getCharacter(int vkCode, boolean shiftKeyPressed)
{

    byte[] keyStates = new byte[256]; //Create a keyboard map of 256 keys

    if (shiftKeyPressed)
    {
        keyStates[16]=-127; //Emulate the shift key being held down
        keyStates[160]=-128; //This needs to be set as well
    }

    IntByReference keyblayoutID = User32.INSTANCE.GetKeyboardLayout(0); //Load local keyboard layout

    int ScanCode  = User32.INSTANCE.MapVirtualKeyExW(vkCode, MAPVK_VK_TO_VSC, keyblayoutID); //Get the scancode

    char[] buff = new char[1];

    int ret = User32.INSTANCE.ToUnicodeEx(vkCode, ScanCode, keyStates, buff, 1, 0, _currentInputLocaleIdentifier);

    switch (ret)
    {
    case -1: //Error
        return (char) -1;

    case 0:  //No Translation
        return (char) 0;

    default: //Returning key...
        return buff[0];
    }
}

以下是声明:

final static int MAPVK_VK_TO_VSC = 0;
static IntByReference _currentInputLocaleIdentifier;

static interface User32 extends Library {

    public static User32 INSTANCE = (User32) Native.loadLibrary("User32", User32.class);


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

}

非常感谢BrendanMcK,他帮助我获得了此解决方案。



 类似资料:
  • 问题内容: 我想在Winforms中编写一个小型应用程序,在其中我可以写一些单词,然后使用ADO.net将它们写到SQL数据库中。 当我想用一个占位符写一个字符串时遇到麻烦: 我的数据库中记录的是: 我该如何克服通过传输到我的数据库的C#更改字符串? 这是我的代码的一部分: 问题答案: 您使用参数化的sql。

  • 问题内容: 我正在阅读文件,但我不知道如何阅读口音和特殊字符,这是我阅读的代码,我必须添加其他编纂,但我不知道该怎么做 谢谢 问题答案: 请尝试以下操作:

  • 问题内容: 如何在Java / Eclipse中使用/显示♥,♦,♣或like等字符? 当我尝试直接使用它们时,例如在源代码中,Eclipse无法保存文件。 我能做什么? 编辑:如何找到Unicode转义序列? 问题答案: 问题在于,您使用的字符无法在文件设置为(Cp1252)的编码中表示。从我的角度来看,您基本上有两个选择: 选项1. 更改编码。 根据IBM的介绍,您应该将编码设置为UTF-8。

  • 我有一个网络服务,我想用“应用/x-www-表单-urlencoded”内容类型调用它。请求有时包含特殊字符,如*-和......问题是目标Web服务不能完美地接收请求。它接收类似这样的: "////////////////w=="几乎所有字符都转到/。到底是什么问题? 这是我的密码: web服务接收:

  • 问题内容: 我无法从网络服务向数据库发送或显示带有特殊字符的文本。在月食中,我已将字符编码设置为UTF-8,但仍然无法显示字符。例如像下面的代码的简单打印 要么 在控制台上的结果,如果我将其发送到数据库,则结果为??????。我如何使它正确显示在控制台上以及希望在数据库中正确显示 问题答案: 是的,它是XXI 世纪,我们仍在努力处理字符编码等问题。 我的第一个猜测是: 您的源文件编码可能是错误的(

  • 我无法将带有特殊字符的文本从webservice发送或显示到数据库。在我的eclipse上,我已经将字符编码设置为UTF-8,但它仍然不允许我显示字符。例如,一个简单的打印,如下面的代码 或 控制台上的结果是??????,如果我把它发送到我的数据库。我如何使它正确地显示在控制台上,希望在数据库中