#10 pyHook breakes deadkeys

closed-fixed
nobody
None
5
2008-07-23
2006-12-30
Anonymous
No

Using a keyboard layout with deadkeys (us-int) and starting the keyboard hook brakes the function for deadkeys. For example the character ö is build from " (the deadkey) and o. When the hook is activated the " is no longer dead, it even prints itself twice. That is you type " once and the display is "".

Discussion

  • Peter Parente

    Peter Parente - 2008-07-23

    Logged In: YES
    user_id=624776
    Originator: NO

    Fixed in patch by Christian Packmann.

     
  • Peter Parente

    Peter Parente - 2008-07-23
    • status: open --> open-fixed
     
  • Peter Parente

    Peter Parente - 2008-07-23
    • status: open-fixed --> closed-fixed
     
  • nanotube

    nanotube - 2008-07-31

    Logged In: YES
    user_id=1173666
    Originator: NO

    Hi,
    ok, so... while pyhook may no longer break deadkeys, it is now broken itself - the mapvirtualkey function does not produce the true ascii value of the key, but just the key name. so the "ascii" attribute of a keyboard event is, for example, always set to 'A' if key 'a' was pressed, regardless of whether shift or capslock was on at the time, '5' if 5 is pressed, even if it's supposed to be '%' because shift was pressed, etc.
    so it appears that mapvirtualkey is not a complete solution to this problem, since it breaks pyhook.

    i have looked around quite a bit and found a possible solution, which i may or may not have the expertise to implement properly, but i'll try.

    first, some references for solving this problem, so that i don't lose them:
    http://www.experts-exchange.com/Programming/System/Windows__Programming/Q_23453780.html
    http://blogs.msdn.com/michkap/archive/2005/01/19/355870.aspx

    and this solution from that experts-exchange thread:

    ========
    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.

    ======== some code:
    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];
    static KBDLLHOOKSTRUCT lastState = {0};

    GetKeyboardState(dbKbdState);
    dwhkl = GetKeyboardLayout(GetWindowThreadProcessId(GetForegroundWindow(), NULL));

    if(ToAsciiEx(pkbdllhook->vkCode, pkbdllhook->scanCode, dbKbdState, (LPWORD)szCharBuf, 0, dwhkl) == -1)
    {
    //Save the current keyboard state.
    lastState = *pkbdllhook;

    //You might also need to hang onto the dbKbdState array... I'm thinking not.

    //Clear out the buffer to return to the previous state - wait for ToAsciiEx to return a value other than -1 by passing the same key again. It should happen after 1 call.
    while(ToAsciiEx(pkbdllhook->vkCode, pkbdllhook->scanCode, dbKbdState, (LPWORD)szCharBuf, 0, dwhkl) <0);
    }
    else
    {
    //Do something with szCharBuf here since this will overwrite it...

    //If we have a saved vkCode from last call, it was a dead key we need to place back in the buffer.
    if(lastState.vkCode != 0)
    {
    //Safest to just clear this.
    memset(dbKbdState, 0, 256);

    //Put the old vkCode back into the locale's buffer.
    ToAsciiEx(lastState.vkCode, lastState.scanCode, dbKbdState, (LPWORD)szCharBuf, 0, dwhkl);

    //Set vkCode to 0, we can use this as a flag as a vkCode of 0 is invalid.
    lastState.vkCode = 0;
    }
    }
    }

    return (CallNextHookEx(hHook, ccode, wParam, lParam));
    }
    ============= end code

     
  • nanotube

    nanotube - 2008-08-20

    Logged In: YES
    user_id=1173666
    Originator: NO

    more info about fixing this:
    http://blogs.msdn.com/michkap/archive/2007/10/27/5717859.aspx

    in particular:
    private static void ClearKeyboardBuffer(uint vk, uint sc, IntPtr hkl) {
    StringBuilder sb = new StringBuilder(10);
    do {
    rc = ToUnicodeEx(vk, sc, lpKeyStateNull, sb, sb.Capacity, 0, hkl);
    } while(rc < 0);
    }

     

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks