Reputation: 1811
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?
Upvotes: 34
Views: 108284
Reputation: 5302
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;
}
}
Upvotes: -1
Reputation: 81
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);
Upvotes: 6
Reputation: 668
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);
Upvotes: 28
Reputation: 1811
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!
Upvotes: 31
Reputation: 501
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.
Upvotes: 7
Reputation: 21
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
Upvotes: 1
Reputation: 88786
Isn't that what the System.Windows.Form.KeysConverter class is for?
KeysConverter kc = new KeysConverter();
string keyChar = kc.ConvertToString(keyData);
Upvotes: 48