How to convert a VirtualKey to a char for non-US k

2019-06-26 07:54发布

In standard .NET there existed the ToAscii/ToUnicode and MapVirtualKey functions to take care of this functionality, though it seems an equivalent function or library has not been brought into Metro/WinRT. If there is actually no equivalent function or library exposed in Metro/WinRT then that would make a custom text input box VERY difficult to bring to market in non-US countries. Specific example: in my custom control, if a french keyboard user presses the è,ù,é, or à keys, they are unable to be translated to the correct character. For example, è uses the scan code for VirtualKey.Number7, and as far as I can tell there is no way to know the keyboard layout or no easy way to translate that scancode based on the current keyboard layout. Does anyone have some information about this?

3条回答
相关推荐>>
2楼-- · 2019-06-26 08:16

I suppose it depends on what you are looking for. If you are looking for a simple English letter or number, you can simply do this:

private static char? ToChar(VirtualKey key, bool shift)
{
    // convert virtual key to char
    if (32 == (int)key)
        return ' ';

    VirtualKey search;

    // look for simple letter
    foreach (var letter in "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
    {
        if (Enum.TryParse<VirtualKey>(letter.ToString(), out search) && search.Equals(key))
            return (shift) ? letter : letter.ToString().ToLower()[0];
    }

    // look for simple number
    foreach (var number in "1234567890")
    {
        if (Enum.TryParse<VirtualKey>("Number" + number.ToString(), out search) && search.Equals(key))
            return number;
    }

    // not found
    return null;
}

Best of luck!

查看更多
迷人小祖宗
3楼-- · 2019-06-26 08:19

You can use the Win32 API function MapVirtualKey that maps a virtual key to a bunch of values one of which is a character value. MapVirtualKey seems to use the currently set keyboard layout (this is not documented). To use a specified layout you could use MapVirtualKeyEx.

MapVirtualKey does not take into account whether Shift is pressed or not. To easily get an information if Shift is pressed you could use GetKeyState (unfortunately the WinRT team didn't make it easy to get the state of the modifier keys).

Here is an example of how to translate a virtual key into a character:

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

[DllImport("user32.dll")]
private static extern short GetKeyState(uint nVirtKey);

private const uint MAPVK_VK_TO_CHAR = 0x02;

private const uint VK_SHIFT = 0x10;

private char TranslateVirtualKeyIntoChar(VirtualKey key)
{
   char c = (char)MapVirtualKey((uint)key, MAPVK_VK_TO_CHAR);
   short shiftState = GetKeyState(VK_SHIFT);
   if (shiftState < 0)
   {
      // Shift is pressed
      c = char.ToUpper(c);
   }
   return c;
}

Update

Unfortunately this solution is not applicable for Windows Store Apps that must be certified. The certification fails since with MapVirtualKey and GetKeyState unsupported APIs are used. This means also that this solution will much likely not run under WinRT.

查看更多
混吃等死
4楼-- · 2019-06-26 08:33

For WinRT (example with a TextBox and only select Letters):

 CoreWindow.GetForCurrentThread().CharacterReceived += TextBox_CharacterReceived;
 void TextBox_CharacterReceived(CoreWindow sender, CharacterReceivedEventArgs args)
    {
        char c = Convert.ToChar(args.KeyCode);
        if (char.IsLetter(c))
        {
           ...
        }
    }

For cancel de char entry:

TextBox textBoxData;

void TextBox_KeyDown(object sender, KeyRoutedEventArgs e)
    {
        textBoxData = sender as TextBox;
        if (e.Key!=VirtualKey.Space)
        e.Handled = true;
    }

optional:

void TextBox_Paste(object sender, TextControlPasteEventArgs e)
   {
       e.Handled = true;
   }

and modify CharacterReceived:

if (char.IsLetter(c))
   {
     textBoxData.Text += c;
     textBoxData.SelectionStart = textBoxData.Text.Length;
    }

Warning! if your TextBox has a MaxLength you must modify your code:

if (char.IsLetter(c) && textBoxData.Text.Length < textBoxData.MaxLength)
查看更多
登录 后发表回答