C# 如何将虚拟键码转换为字符?

发布于 2024-07-09 21:38:56 字数 222 浏览 6 评论 0原文

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

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

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

你知道问题的答案吗?

I am trying to map a virtual keycode to a char.

My code uses ProcessCmdKey to listen to WM_KEYDOWN which gives me access to the key pressed. For example, when I press single quote I get a key of 222 which I want to have it mapped to keychar 39 which represents... you guessed it... single quote.

My dev context is:
- .net Framework 2.0
- UserControl placed in a lot of places

Do you know the answer to the question?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

土豪我们做朋友吧 2024-07-16 21:38:56

这不是 System.Windows.Form.KeysConverter 吗 类是用来做什么的?

KeysConverter kc = new KeysConverter();
string keyChar = kc.ConvertToString(keyData);

Isn't that what the System.Windows.Form.KeysConverter class is for?

KeysConverter kc = new KeysConverter();
string keyChar = kc.ConvertToString(keyData);
烟花肆意 2024-07-16 21:38:56

是的,我确实使用了 MapVirtualKey 方法。 但我期待有关如何使用它的更多详细信息:使用什么 DllImport 指令、什么 enum 专门用于映射到字符等。

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

好了,我将发布我正在寻找的内容 - 一个开箱即用的 C# 解决方案:

1- 将此指令放入您的类中:

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

2- 像这样检索您的 char:

  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);
  }

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

Yes, I did use the MapVirtualKey method. But I was expecting more details on how to use it: what DllImport directive to use, what enum is specific for mapping to characters, etc.

I don't like these answers where you google for like 5 seconds and then just suggest a solution: the real challenge is to put all the pieces together and not have to waste your time with tons of sample-less MSDN pages or other coding forums in order to get your answer. No offense plinth, but your answer (even good) was worhtless since I had this answer even before posting my question on the forum!

So there you go, I am going to post what I was looking for - an out-of-the-box C# solution:

1- Place this directive inside your class:

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

2- Retrieve your char like this:

  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);
  }

Thanks for caring... and enjoy!

︶ ̄淡然 2024-07-16 21:38:56

我一直在寻找类似的东西,但我需要映射到当前键盘布局的字符。 由于以上答案均不能满足我的要求,这就是我的想法。


        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);

I was looking for something similar but I needed the character mapped to the current keyboard layout. Since none of the above answers fulfilled my requirements, here is what I came up with.


        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);

謌踐踏愛綪 2024-07-16 21:38:56

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

正如 MM 提到的,System.Windows.KeysConverter 不提供键的字符表示,而是提供枚举的名称,例如“输入”而不是“\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 语句或查找表来实现。

After reading and testing some of the answers provided, I thought I'd suggest an alternative.

As mentioned by MM, System.Windows.KeysConverter does not provide a character representation of the key but rather the enum's name, e.g. "Enter" instead of '\n'.

The MapVirtualKey method suggested by Horas, in answer to his own question, is a good starting point, but still does not support either capslock, or characters entered with the shift key, e.g. '!', '$' and '>'.

An alternative to the MapVirtualKey method, that I am using, is an extension method for the Keys class:

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;
}

The method shown above will provide support for alphanumeric characters. Support for additional characters could be implemented with either a switch statement or lookup table.

瑾兮 2024-07-16 21:38:56

我刚刚编写了 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);

I've just written an improvement of Ivan Petrov answer to display a string representation of pressed key combinations in WPF, see my code below:

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);
山色无中 2024-07-16 21:38:56

KeysConverter 获取键名称而不是键“文本”
例如:“Num2”而不是“2”
MapVirtualKey 适用于英语,但对于非英语字符文档说明使用 MapVirtualKeyEx,但这需要区域设置标识符
该标识符由 LoadKeyBoardLayout 加载,需要区域性 id 常量
但在找到正确的 id 值后,它在我尝试时不起作用,所以最后我抛弃了整个东西

KeysConverter gets the key name not the keys "text"
ex: "Num2" instead of "2"
MapVirtualKey will work for english but for non-english chars documentation states using MapVirtualKeyEx but that requires a locale Identifier
that identifier is loaded by LoadKeyBoardLayout which requires a culture id constant
but then after finding the correct id values it didn't work as i tried it so finally i dumped the whole thing

无法回应 2024-07-16 21:38:56

如果您使用的是 WPF(我没有尝试使用 WinForms),有一个非常简单的解决方案,可以直接返回按下的字符,即 窗口的 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;
    }
}

If you are using WPF (I didn't try it with WinForms), there is a very simple solution that returns directly the pressed char, the TextInput Event of Window.

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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文