如何根据当前键盘布局将虚拟键代码转换为字符?

我之前已经浏览了几个关于此的问题,到目前为止我找到的最佳答案是这样的:

(char) WinAPI.MapVirtualKey((uint) Keys.A, 2) 

但是,这在两个方面不起作用:

  • 它总是返回大写字母。 对于Keys.A我希望得到角色a ,而对于Keys.A | Keys.ShiftKey Keys.A | Keys.ShiftKey我希望得到A ; 但是,我似乎都得到了A

  • 它似乎没有考虑键盘布局。 例如,对于Keys.OemMinus我似乎总是得到这个角色-即使当前的键盘布局是德语,我希望这个键能够返回ß

对此有什么正确的解决方案?

正确的解决方案是ToUnicode WinAPIfunction:

 [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 É 

也可以使用ToUnicodeEx来检索不是当前活动的键盘布局的字符。 签名是相同的,除了一个额外的参数,输入区域设置ID,可以使用LoadKeyboardLayout函数检索。

  [DllImport("user32.dll")] static extern int MapVirtualKey(int uCode, uint uMapType); private void textBox1_OnKeyDown(object sender, KeyEventArgs e) { char c = (char)MapVirtualKey((int)e.KeyData, (uint)2); if (char.IsNumber(c)) DoSomething(); else if (!char.IsNumber(c)) DoNothing(); } 

我认为这可以使用这种方法实现:

 [DllImportAttribute("User32.dll")] public static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState, byte[] lpChar, int uFlags); 

可以在此处找到示例用法: http : //www.pcreview.co.uk/forums/toascii-function-t1706394.html