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?
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.
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.