31

我正在尝试将虚拟键码映射到字符。

我的代码使用 ProcessCmdKey 来收听 WM_KEYDOWN ,这使我可以访问按下的键。例如,当我按下单引号时,我得到一个 222 的键,我希望将它映射到 keychar 39,它表示......你猜对了......单引号。

我的开发环境是: - .net Framework 2.0 - UserControl 放置在很多地方

你知道问题的答案吗?

4

7 回答 7

45

这不是System.Windows.Form.KeysConverter类的用途吗?

KeysConverter kc = new KeysConverter();
string keyChar = kc.ConvertToString(keyData);
于 2008-11-26T14:40:30.010 回答
28

是的,我确实使用了这种MapVirtualKey方法。但我期待更多关于如何使用它的细节:使用什么DllImport指令,enum映射到字符的具体内容等。

我不喜欢你用谷歌搜索 5 秒钟然后提出解决方案的这些答案:真正的挑战是将所有部分放在一起,而不必在大量无样本的 MSDN 页面或其他编码论坛上浪费时间为了得到你的答案。没有冒犯,但你的回答(甚至很好)毫无价值,因为我在论坛上发布我的问题之前就有了这个答案!

所以你去吧,我将发布我正在寻找的东西 - 一个开箱即用的 C# 解决方案:

1-将此指令放在您的班级中:

[DllImport("user32.dll")]
static extern int MapVirtualKey(uint uCode, uint uMapType);

2- 像这样检索你的字符:

  protected override bool ProcessCmdKey(ref Message msg, Keys keyData)      
  {
     const int WM_KEYDOWN = 0x100;

     if (msg.Msg == WM_KEYDOWN)
     {            
        // 2 is used to translate into an unshifted character value 
        int nonVirtualKey = MapVirtualKey((uint)keyData, 2);

        char mappedChar = Convert.ToChar(nonVirtualKey);
     }

     return base.ProcessCmdKey(ref msg, keyData);
  }

感谢您的关心...并享受!

于 2008-11-26T14:29:30.750 回答
22

我正在寻找类似的东西,但我需要映射到当前键盘布局的字符。由于以上答案都没有满足我的要求,这就是我想出的。


        public string KeyCodeToUnicode(Keys key)
        {
            byte[] keyboardState = new byte[255];
            bool keyboardStateStatus = GetKeyboardState(keyboardState);

            if (!keyboardStateStatus)
            {
                return "";
            }

            uint virtualKeyCode = (uint)key;
            uint scanCode = MapVirtualKey(virtualKeyCode, 0);
            IntPtr inputLocaleIdentifier = GetKeyboardLayout(0);

            StringBuilder result = new StringBuilder();
            ToUnicodeEx(virtualKeyCode, scanCode, keyboardState, result, (int)5, (uint)0, inputLocaleIdentifier);

            return result.ToString();
        }

        [DllImport("user32.dll")]
        static extern bool GetKeyboardState(byte[] lpKeyState);

        [DllImport("user32.dll")]
        static extern uint MapVirtualKey(uint uCode, uint uMapType);

        [DllImport("user32.dll")]
        static extern IntPtr GetKeyboardLayout(uint idThread);

        [DllImport("user32.dll")]
        static extern int ToUnicodeEx(uint wVirtKey, uint wScanCode, byte[] lpKeyState, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszBuff, int cchBuff, uint wFlags, IntPtr dwhkl);

于 2016-08-05T10:44:27.270 回答
7

在阅读并测试了提供的一些答案之后,我想我会建议一个替代方案。

正如MM所提到的,System.Windows.KeysConverter 不提供键的字符表示,而是提供枚举的名称,例如“Enter”而不是“\n”。

Horas在回答他自己的问题时建议的 MapVirtualKey 方法是一个很好的起点,但仍然不支持大写锁定或使用 shift 键输入的字符,例如“!”、“$”和“>”。

我正在使用的 MapVirtualKey 方法的替代方法是 Keys 类的扩展方法:

public static char ToChar(this Keys key)
{
    char c = '\0';
    if((key >= Keys.A) && (key <= Keys.Z))
    {
        c = (char)((int)'a' + (int)(key - Keys.A));
    }

    else if((key >= Keys.D0) && (key <= Keys.D9))
    {
        c = (char)((int)'0' + (int)(key - Keys.D0));
    }

    return c;
}

上面显示的方法将提供对字母数字字符的支持。可以使用 switch 语句或查找表来实现对附加字符的支持。

于 2015-02-27T08:56:27.177 回答
5

我刚刚编写了Ivan Petrov 答案的改进,以在 WPF 中显示按键组合的字符串表示,请参见下面的代码:

public static string GetKeyString(Key key, ModifierKeys modifiers)
{
    string result = "";
    if (key != Key.None)
    {
        // Setup modifiers
        if (modifiers.HasFlag(ModifierKeys.Control))
            result += "Ctrl + ";
        if (modifiers.HasFlag(ModifierKeys.Alt))
            result += "Alt + ";
        if (modifiers.HasFlag(ModifierKeys.Shift))
            result += "Shift + ";
        // Get string representation
        string keyStr = key.ToString();
        int keyInt = (int)key;
        // Numeric keys are returned without the 'D'
        if (key >= Key.D0 && key <= Key.D9)
            keyStr = char.ToString((char)(key - Key.D0 + '0'));
        // Char keys are returned directly
        else if (key >= Key.A && key <= Key.Z)
            keyStr = char.ToString((char)(key - Key.A + 'A'));
        // If the key is a keypad operation (Add, Multiply, ...) or an 'Oem' key, P/Invoke
        else if ((keyInt >= 84 && keyInt <= 89) || keyInt >= 140)
            keyStr = KeyCodeToUnicode(key);
        result += keyStr;
    }
    return result;
}

private static string KeyCodeToUnicode(Key key)
{
    byte[] keyboardState = new byte[255];
    bool keyboardStateStatus = GetKeyboardState(keyboardState);

    if (!keyboardStateStatus)
    {
        return "";
    }

    uint virtualKeyCode = (uint)KeyInterop.VirtualKeyFromKey(key);
    uint scanCode = MapVirtualKey(virtualKeyCode, 0);
    IntPtr inputLocaleIdentifier = GetKeyboardLayout(0);

    StringBuilder result = new StringBuilder();
    ToUnicodeEx(virtualKeyCode, scanCode, new byte[255], result, (int)5, (uint)0, inputLocaleIdentifier);

    return result.ToString();
}

[DllImport("user32.dll")]
static extern bool GetKeyboardState(byte[] lpKeyState);

[DllImport("user32.dll")]
static extern uint MapVirtualKey(uint uCode, uint uMapType);

[DllImport("user32.dll")]
static extern IntPtr GetKeyboardLayout(uint idThread);

[DllImport("user32.dll")]
static extern int ToUnicodeEx(uint wVirtKey, uint wScanCode, byte[] lpKeyState, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszBuff, int cchBuff, uint wFlags, IntPtr dwhkl);
于 2017-07-12T10:51:31.667 回答
1

KeysConverter 获取键名而不是键“文本”例如:“Num2”而不是“2” MapVirtualKey 将适用于英语,但对于使用 MapVirtualKeyEx 的非英语字符文档状态,但这需要一个语言环境标识符,该标识符由 LoadKeyBoardLayout 加载,需要一个文化 id 常量,但是在找到正确的 id 值之后,它在我尝试时不起作用,所以最后我把整个东西都扔掉了

于 2009-10-24T12:25:31.930 回答
-1

如果你使用的是 WPF(我没有用 WinForms 尝试过),有一个非常简单的解决方案,直接返回按下的字符,即 Window 的TextInput 事件

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        TextInput += MainWindow_TextInput;
    }

    private void MainWindow_TextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
    {
        txtInput.Text += e.Text;
    }
}
于 2020-05-13T10:27:15.773 回答