【问题标题】:How to convert a virtual-key code to a character according to the current keyboard layout?如何根据当前的键盘布局将虚拟键码转换为字符?
【发布时间】:2011-08-03 15:44:55
【问题描述】:

我之前浏览过几个关于这个的问题,到目前为止我找到的最好的答案是这样的:

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

但是,这在两种情况下都不起作用:

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

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

什么是正确的解决方案?

【问题讨论】:

  • 你可以明确检查是否按下了shift键,然后调整你的字符大小写。
  • @Ben:哦,真的吗?那么俄罗斯版面的西里尔字母 ф 的虚拟键码是什么?

标签: c# winapi


【解决方案1】:

正确的解决方案是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 É

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

【讨论】:

  • WinAPI.ToUnicode((uint) Keys.E, 0, keyboardState, buf, 256, 0);为什么是 Keys.E??
  • 如何获得 altGr 状态? KeyEventArgs 没有这样的东西。
  • 啊,看来 AltGr 就是 ctrl + alt。好的。当覆盖内部内容并且只能访问 KeyEventArgs 时,此功能可以挽救生命。
  • 这正是我想要的。谢谢。它与原始输入中的 MessageFilter 很好地结合。
【解决方案2】:

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

[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

【讨论】:

    【解决方案3】:
        [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();
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-24
      • 2012-01-06
      • 2011-02-25
      • 1970-01-01
      相关资源
      最近更新 更多