Hello there. I'm trying to detect which character is produced whenever the user presses a key. For this, I'm using the ToUnicodeEx function, which translates the specified virtual-key code and keyboard state to the corresponding Unicode character, inside a keyboard system wide hook. However, every time the user presses dead keys, such as the ones producing '¨', '~' or '´', strange things happen. Here is sample code of the first version:
With this code I faced the following problem: Whenever I tried to type "á" in notepad, which requires '´' to be pressed before 'a', the result would be "´´a". Although the captured character by ToUnicodeEx was 'á', I can't admit that my application prevents the user from using characters such as 'á'.Code:private static int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam) { //indicates if any of underlaing events set e.Handled flag bool handled = false; if (nCode >= 0) { //read structure KeyboardHookStruct at lParam KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)); // raise KeyPress if (s_KeyPress != null && wParam == WM_KEYDOWN) { bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80 ? true : false); bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false); byte[] keyState = new byte[256]; GetKeyboardState(keyState); System.Text.StringBuilder sbString = new System.Text.StringBuilder(); IntPtr HKL = GetKeyboardLayout(0); switch (ToUnicodeEx((uint)MyKeyboardHookStruct.VirtualKeyCode, (uint)MyKeyboardHookStruct.ScanCode, keyState, sbString, 5, (uint)MyKeyboardHookStruct.Flags, HKL)) { case 1: char key = sbString.ToString()[0]; if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key); KeyPressEventArgs e = new KeyPressEventArgs(key); s_KeyPress.Invoke(null, e); handled = handled || e.Handled; break; } } } //if event handled in application do not handoff to other listeners if (handled) return -1; //forward to other application return CallNextHookEx(s_KeyboardHookHandle, nCode, wParam, lParam); }
So, I worked around this problem by avoiding ToUnicodeEx to be called whenever a dead key is pressed. This way, I can avoid the ToUnicodeEx function from messing with the keyboard state. Here is the current version code:
I though this solution would solve my problem, but I was wrong. The result has improved, but it's not quite what I wanted. Now, typing 'á' in notepad results in 'a'. Notice that the accent '´' is missing.Code:private static int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam) { //indicates if any of underlaing events set e.Handled flag bool handled = false; if (nCode >= 0) { //read structure KeyboardHookStruct at lParam KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)); // raise KeyPress if (s_KeyPress != null && wParam == WM_KEYDOWN) { bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80 ? true : false); bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false); byte[] keyState = new byte[256]; GetKeyboardState(keyState); System.Text.StringBuilder sbString = new System.Text.StringBuilder(); IntPtr HKL = GetKeyboardLayout(0); if (!IsDeadKey((uint)MyKeyboardHookStruct.VirtualKeyCode)) { switch (ToUnicodeEx((uint)MyKeyboardHookStruct.VirtualKeyCode, (uint)MyKeyboardHookStruct.ScanCode, keyState, sbString, 5, (uint)MyKeyboardHookStruct.Flags, HKL)) { case 1: char key = sbString.ToString()[0]; if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key); KeyPressEventArgs e = new KeyPressEventArgs(key); s_KeyPress.Invoke(null, e); handled = handled || e.Handled; break; } } } } //if event handled in application do not handoff to other listeners if (handled) return -1; //forward to other application return CallNextHookEx(s_KeyboardHookHandle, nCode, wParam, lParam); } static bool IsDeadKey(uint key) { if ((MapVirtualKey(key, 2) & 2147483648) == 2147483648) { return true; } else { return false; } }
Does anyone know how to work around this issue? My current method already captures the correct character, but prevents the user from producing characters with accents or diacritics. I think the KeyboardHookProc method just need a few changes, but I can't figure them out.
Thanks in advance.
PS: I tried the solution described in the following link: Keyboard hooks, ToUnicodeEx, MapVirtrualKeyEx. However, the result is quite the same as in my current version. That code only erases the keyboard buffer, which deletes the accents, therefore not allowing the user to use them.



LinkBack URL
About LinkBacks


