代表当前文化中的特殊键盘键?
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 É
场景
我使用现代 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 É