诀窍是使用一组 user32.dll 函数:GetWindowThreadProcessId、GetKeyboardLayout、GetKeyboardState 和 ToUnicodeEx。
- 使用GetWindowThreadProcessId 函数和您的控制句柄来获得相关的本机线程ID。
- 将该线程 ID 传递给 GetKeyboardLayout 以获取当前键盘布局。
- 调用GetKeyboardState获取当前键盘状态。这有助于下一个方法根据修饰符状态决定生成哪个字符。
- 最后,调用ToUnicodeEx函数,使用想要的虚拟键码和扫描码(这两个可以相同),当前键盘状态,作为字符串持有者的字符串生成器(保存结果),没有标志(0) 和当前键盘布局指针。
如果结果不为零,则返回第一个返回的字符。
public class KeyboardHelper
{
[DllImport("user32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
private static extern int ToUnicodeEx(
uint wVirtKey,
uint wScanCode,
Keys[] lpKeyState,
StringBuilder pwszBuff,
int cchBuff,
uint wFlags,
IntPtr dwhkl);
[DllImport("user32.dll", ExactSpelling = true)]
internal static extern IntPtr GetKeyboardLayout(uint threadId);
[DllImport("user32.dll", ExactSpelling = true)]
internal static extern bool GetKeyboardState(Keys[] keyStates);
[DllImport("user32.dll", ExactSpelling = true)]
internal static extern uint GetWindowThreadProcessId(IntPtr hwindow, out uint processId);
public static string CodeToString(int scanCode)
{
uint procId;
uint thread = GetWindowThreadProcessId(Process.GetCurrentProcess().MainWindowHandle, out procId);
IntPtr hkl = GetKeyboardLayout(thread);
if (hkl == IntPtr.Zero)
{
Console.WriteLine("Sorry, that keyboard does not seem to be valid.");
return string.Empty;
}
Keys[] keyStates = new Keys[256];
if (!GetKeyboardState(keyStates))
return string.Empty;
StringBuilder sb = new StringBuilder(10);
int rc = ToUnicodeEx((uint)scanCode, (uint)scanCode, keyStates, sb, sb.Capacity, 0, hkl);
return sb.ToString();
}
}