Link to home
Start Free TrialLog in
Avatar of dddogget
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_KEYBOARD_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.
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));
}

Open in new window

Avatar of chikoto
chikoto

I'm not 100% sure what your goal here is.

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.
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
Avatar of dddogget

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.
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
Avatar of chikoto
chikoto

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Perfect! Thanks so much. I would have spent a week trying to do this one by myself. Your code snippet did the trick!!!