代表当前文化中的特殊键盘键?

Represent an special keyboard key in the current culture?

场景

我使用现代 RawInput 技术编写了一个简单的键盘记录器,为 event/data 拦截注册所需的设备。

然后,我基本上使用了所有这些 Windows API 成员定义:


Problem/Question

我使用的是非英语键盘和非英语 O.S,然后,当我尝试解析这个的特殊键时,我的问题就开始了键盘像 ñ/Ñ 字符,被识别为 System.Windows.Forms.Keys.OemTilde 键, 或被识别为 System.Windows.Forms.Keys.OemQuestion 键的 ç/Ç 字符。

我想让我的键盘记录器识别特定语言(或者至少,对我当前的文化有适当的字符识别,es-ES),但我被卡住了因为缺乏开始正确检索这些字符的知识。

请注意,我的目的是学习如何以 efficient/automated 的方式做到这一点,就像 O.S 对我的键盘所做的那样,当我按一个 Ñ 字符,它会输入 Ñ,我的意思是我完全知道一个解决方案,它暗示要执行手动解析特殊字符,例如:

Select Case MyKey

    Case Keys.OemTilde
        char = "ñ"c

End Select

这不是我要寻找的行为,但我可以理解,也许我需要额外的 "things" 来为每种 keayborad 重现良好的 recognition/translation 这些字符,但是"things" 我需要什么?


研究

我不确定如何进行,因为正如我所说,我没有知识来知道这个问题的答案(这就是我问的原因),但我想当前的键盘布局将被涉及,那么,我知道我可以使用 CultureInfo.CurrentCulture.KeyboardLayoutId 属性.

检索当前的键盘布局

我知道文化 en-US 的键盘布局是 1033,文化 es-ES 3082.

另外,注意RAWKEYBOARD结构的MakeCode成员的文档,也许这似乎是对我假装做的事情的暗示,我不知道:

MakeCode

Type: USHORT

The scan code from the key depression. The scan code for keyboard overrun is KEYBOARD_OVERRUN_MAKE_CODE.

但实际上这是一个猜测 这是我找到的代码。

正确的解决方案是 ToUnicode WinAPI 函数:

[DllImport("user32.dll")]
public static extern int ToUnicode(uint virtualKeyCode, uint scanCode,
    byte[] keyboardState,
    [Out, MarshalAs(UnmanagedType.LPWStr, SizeConst = 64)]
    StringBuilder receivingBuffer,
    int bufferSize, uint flags);



static string GetCharsFromKeys(Keys keys, bool shift, bool altGr)
{
    var buf = new StringBuilder(256);
    var keyboardState = new byte[256];
    if (shift)
        keyboardState[(int) Keys.ShiftKey] = 0xff;
    if (altGr)
    {
        keyboardState[(int) Keys.ControlKey] = 0xff;
        keyboardState[(int) Keys.Menu] = 0xff;
    }
    WinAPI.ToUnicode((uint) keys, 0, keyboardState, buf, 256, 0);
    return buf.ToString();
}


Console.WriteLine(GetCharsFromKeys(Keys.E, false, false));    // prints e
Console.WriteLine(GetCharsFromKeys(Keys.E, true, false));     // prints E

// Assuming British keyboard layout:
Console.WriteLine(GetCharsFromKeys(Keys.E, false, true));     // prints é
Console.WriteLine(GetCharsFromKeys(Keys.E, true, true));      // prints É