Reputation: 101
I need to be able to read a char and get it's Key relevant to it's language and keyboard layout.
I know how to see the cultural settings and languages. But how can i take a letter like 'S' in english and know what key it is on the keyboard? Or for a harder problem, how can i take the letter 'ש' and know what key it is on the keyboard?
Upvotes: 2
Views: 2589
Reputation: 113232
This one might be more easily explained with an example program than anything else:
namespace KeyFinder
{
class Program
{
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern short VkKeyScanEx(char ch, IntPtr dwhkl);
[DllImport("user32.dll")]
static extern bool UnloadKeyboardLayout(IntPtr hkl);
[DllImport("user32.dll")]
static extern IntPtr LoadKeyboardLayout(string pwszKLID, uint Flags);
public class KeyboardPointer : IDisposable
{
private readonly IntPtr pointer;
public KeyboardPointer(int klid)
{
pointer = LoadKeyboardLayout(klid.ToString("X8"), 1);
}
public KeyboardPointer(CultureInfo culture)
:this(culture.KeyboardLayoutId){}
public void Dispose()
{
UnloadKeyboardLayout(pointer);
GC.SuppressFinalize(this);
}
~KeyboardPointer()
{
UnloadKeyboardLayout(pointer);
}
// Converting to System.Windows.Forms.Key here, but
// some other enumerations for similar tasks have the same
// one-to-one mapping to the underlying Windows API values
public bool GetKey(char character, out Keys key)
{
short keyNumber = VkKeyScanEx(character, pointer);
if(keyNumber == -1)
{
key = System.Windows.Forms.Keys.None;
return false;
}
key = (System.Windows.Forms.Keys)(((keyNumber & 0xFF00) << 8) | (keyNumber & 0xFF));
return true;
}
}
private static string DescribeKey(Keys key)
{
StringBuilder desc = new StringBuilder();
if((key & Keys.Shift) != Keys.None)
desc.Append("Shift: ");
if((key & Keys.Control) != Keys.None)
desc.Append("Control: ");
if((key & Keys.Alt) != Keys.None)
desc.Append("Alt: ");
return desc.Append(key & Keys.KeyCode).ToString();
}
public static void Main(string[] args)
{
string testChars = "Aéש";
Keys key;
foreach(var culture in (new string[]{"he-IL", "en-US", "en-IE"}).Select(code => CultureInfo.GetCultureInfo(code)))
{
Console.WriteLine(culture.Name);
using(var keyboard = new KeyboardPointer(culture))
foreach(char test in testChars)
{
Console.Write(test);
Console.Write('\t');
if(keyboard.GetKey(test, out key))
Console.WriteLine(DescribeKey(key));
else
Console.WriteLine("No Key");
}
}
Console.Read();//Stop window closing
}
}
}
Output:
he-IL
A Shift: A
é No Key
ש A
en-US
A Shift: A
é No Key
ש No Key
en-IE
A Shift: A
é Control: Alt: E
ש No Key
(Though your own console might mess up ש and/or é depending on settings and fonts).
Note that the Windows kludge of using Ctrl+Alt as a substitute in case a keyboard has no AltGr key is precisely how it is reported, it's only at a lower level again that the two are treated as separate, which is one of the things that makes Windows keyboards less flexible (Alt + AltGr is meaningless in Windows).
Edit: The constructor for KeyboardPointer
that takes a CultureInfo
has obvious ease of use, but that which takes a number is useful for secondary keyboards for a given culture. E.g. en-US most often uses 0x0149, but there are variants with a different higher word (0x00010149, 0x00020149, 0x00030149, etc.) for variant layouts like Dvorak, extended support for characters (the so-called "International US" needed to write English words like "naïve", "façade" or "résumé"), and so on.
Upvotes: 13
Reputation: 37566
You can parse the KeyCode to determine if it containts the Letter you are searching for. For non english input i guess you will have to map these to english letters to know which key is it on the keyboard.
Upvotes: 0