C# Windows.Forms プロジェクトには、KeyPressed イベントを提供しないコントロールがあります (これは COM コントロール – ESRI マップです)。
KeyEventArgs構造体を含む KeyUp および KeyDown イベントのみを提供します。
現在アクティブなキーボード レイアウトなどを考慮して、KeyEventArgs の情報を表示可能な Unicode 文字に変換するにはどうすればよいですか?
トリックは、一連の user32.dll 関数を使用することです: GetWindowThreadProcessId、GetKeyboardLayout、GetKeyboardState、およびToUnicodeEx。
結果がゼロでない場合は、最初に返された文字を返します。
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();
}
}
Itai Bar-Haim のソリューションは優れていますが、デッド キーに問題があります。
デッド キーのスキャン コードで CodeToString(int scanCode) を初めて呼び出すと、ToUnicodeEx() の戻りコードは -1 になり、メソッドは正しい値を返します。
ただし、次の呼び出しでは、ToUnicodeEx() は 2 を返します。結果の文字列には、予想される結果の前にデッド キーが含まれ、その後にメモリ ジャンク データが続きます。
たとえば、^ (デッド キー) を使用してメソッドを呼び出し、次に $ を使用してメソッドを呼び出します。最初の呼び出しは ^ (良い) を返しますが、2 番目の呼び出しは ^$azertyui を返します。
それを修正するには、次の 2 つのことを行う必要があります。
1) ToUnicodeEx() 戻りコードの絶対値を使用して、StringBuilder の長さを設定する必要があります。したがって、文字の後にジャンク データを取得することを回避できます。
2) ToUnicodeEx() の戻りコードが -1 の場合、メソッドの結果として StringBuilder の最初の文字を取得する必要があります。次に、デッド キーをキーボードの状態から削除する必要があります。スペース キーのスキャンコードを使用して ToUnicodeEx() を呼び出します。
別の問題が発生する可能性があります。ToUnicodeEx() を呼び出す前にデッド キーを押したユーザーによってキーボードの状態が変更された場合、返される文字列には、期待値の前にデッド キー文字が含まれます。私が見つけた回避策は、実際の呼び出しの前に、スペース キーのスキャンコードで ToUnicodeEx() を呼び出すことです。
この助けを願っています!
KeysConverterとその ConvertToString メソッドを見てください。すべての KeyDown が KeyPress にマップされるわけではないことに注意してください。