dddogget
asked on
LowLevel Keystroke Hook removes Accents on French Keyboard
When I filter all keystrokes on a French keyboard, the Accent keys no longer work.
Im using the SetWindowsHookEx(WH_KEYBOA RD_LL, MyKeyboardProc, hInst, 0); to install the low-level keyboard hook.
Apparently the call to ToAsciiEx() inside the low-level keystroke hook stops the proper functioning on Accent keys. If I set the keyboard to Canadian French the call to ToAscii() or ToAsciiEx() stops the creation of Accent keys (on an English keyboard, press the [ key followed by the a and you should get a â key.)
There is an ToAsciiEx() which allows me to specify the Input Local. Ive tried that with a similar result. In that call, I get the keyboard local for the foreground window process.
When this hook is active and the keyboard is set to Canadian French, I can no longer get an "accent" key when typing in Notepad, Word, etc... If I deactivate the hook, then I can create an accented letter.
Im using the SetWindowsHookEx(WH_KEYBOA
Apparently the call to ToAsciiEx() inside the low-level keystroke hook stops the proper functioning on Accent keys. If I set the keyboard to Canadian French the call to ToAscii() or ToAsciiEx() stops the creation of Accent keys (on an English keyboard, press the [ key followed by the a and you should get a â key.)
There is an ToAsciiEx() which allows me to specify the Input Local. Ive tried that with a similar result. In that call, I get the keyboard local for the foreground window process.
When this hook is active and the keyboard is set to Canadian French, I can no longer get an "accent" key when typing in Notepad, Word, etc... If I deactivate the hook, then I can create an accented letter.
LRESULT CALLBACK MyKeyboardProc(int ccode, WPARAM wParam, LPARAM lParam)
{
if (ccode == HC_ACTION)
{
KBDLLHOOKSTRUCT
*pkbdllhook = (KBDLLHOOKSTRUCT *)lParam;
HKL
dwhkl = 0;
BYTE
dbKbdState[256];
TCHAR
szCharBuf[32];
GetKeyboardState(dbKbdState);
dwhkl = GetKeyboardLayout(GetWindowThreadProcessId(GetForegroundWindow(), NULL));
ToAsciiEx(pkbdllhook->vkCode, pkbdllhook->scanCode, dbKbdState, (LPWORD)szCharBuf, 0, dwhkl);
}
return (CallNextHookEx(hHook, ccode, wParam, lParam));
}
And if you're really asking question #1, I found some information that will help you right out!
http://blogs.msdn.com/michkap/archive/2005/01/19/355870.aspx
http://blogs.msdn.com/michkap/archive/2005/01/19/355870.aspx
ASKER
My problem deals witn question #1. Once my hook is active, foreground apps break. The blog post seems to describe what's happening, but I don't understand the solution they are proposing. Is there a way to detect that the keystroke is a "dead-key"? If so, I suppose I could not process any dead-keys.
Here's my interpretation:
When you call ToAsciiEx (or ToUnicodeEx) with a dead key, you will be placing a dead key into the keyboard layout's static buffer (which is apparently global). You will know this is the case, because the function will return -1. This then puts the function into the wrong state for the NEXT app that calls it.
So your goal here is to put that buffer back into it's prior state.
So what you could do is, whenever you have added a dead key to the buffer, store it in your own buffer, then call the ToAsciiEx function again with the same parameters until it does not return -1. That means that the buffer is cleared.
Next time your hook is called, the dead key will ALREADY be in the ToAsciiEx buffer. Check to see if the key you pressed is again a dead key by checking for -1. After you get your character translated, put the buffer you built back into the ToAsciiEx buffer for the next function.
There's some implementation details hidden in there, but that's the idea. I hope that makes sense.
When you call ToAsciiEx (or ToUnicodeEx) with a dead key, you will be placing a dead key into the keyboard layout's static buffer (which is apparently global). You will know this is the case, because the function will return -1. This then puts the function into the wrong state for the NEXT app that calls it.
So your goal here is to put that buffer back into it's prior state.
So what you could do is, whenever you have added a dead key to the buffer, store it in your own buffer, then call the ToAsciiEx function again with the same parameters until it does not return -1. That means that the buffer is cleared.
Next time your hook is called, the dead key will ALREADY be in the ToAsciiEx buffer. Check to see if the key you pressed is again a dead key by checking for -1. After you get your character translated, put the buffer you built back into the ToAsciiEx buffer for the next function.
There's some implementation details hidden in there, but that's the idea. I hope that makes sense.
ASKER
That's similar to what I found in http://blogs.msdn.com/michkap/archive/2005/01/19/355870.aspx. However, I'm still foggy on the implementation. I can certainly call ToAscii() until it returns a non-negative. I don't understand how to "put the buffer you built back into the ToAsciiEx buffer..." A code snippet would be GREAT!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Perfect! Thanks so much. I would have spent a week trying to do this one by myself. Your code snippet did the trick!!!
Is the problem that after installing your hook that other applications break? Or is it the character that you are getting inside of your hook is not what you expect?
I'm going to tackle the second one:
Your hook function gets the keystrokes at a lower level before any dead key processing is done. In order to get an accented key in this case you will need to handle the dead key "[" yourself.
You should buffer the dead key press until the NEXT keystroke and then process this combination.