No announcement yet.

Keyboard Hook - Non US Keyboards

  • Filter
  • Time
  • Show
Clear All
new posts

  • Keyboard Hook - Non US Keyboards

    I'm using a Keyboard hook to intercept and handle some of the oddball keys differently. Keyboard traffic is passed to the App (after some minor fiddling) via %WM_USER calls. This is working just fine.

    However a new user now wishes to use a diferent keyboard layout (German/Swiss) and it just doesn't work. So I'm confused here.

    Does using a keyboard hook effectively bypass/kill all normal keyboard mapping since we're at the KeyCode level?

    Is it possible to intercept only a few keys I'm interested in and forward them via %WM_USER and somehow still let windows handle everything else and return them via %WM_CHAR? If so, would this restore support for other KB mappings?


  • #2
    Hi George,
    Do you need to hook the keyboard? (Antivirus and MalWare scanners may see this as a "KeyLogger") or Do you just need the KeyPress/KeyCode when your Window/Dialog has focus?

    I do have an example of Virtual Keyboard Routines in the source code forums, that could be built on for other keyboards I would think fairly painless.

    Also in the Documentation (I can't think of where at the moment) is a comment of an often overlooked place to catch keypresses (without subclassing) is to check in your program's message pump. But I have not looked into it yet
    Engineer's Motto: If it aint broke take it apart and fix it

    "If at 1st you don't succeed... call it version 1.0"

    "Half of Programming is coding"....."The other 90% is DEBUGGING"

    "Document my code????" .... "WHYYY??? do you think they call it CODE? "


    • #3
      Hi Cliff,
      The hook is not global, so looking like a keylogger isn't a problem. The problem is that I need to be able to 'see' keys like Control, NumLock, Alt etc. that aren't normally visible.
      e.g. a User can re-map the R-Ctl key, all by itself, into say an Enter key. (Don't ask)


      • #4
        I'm resurrecting this post rather than repeat some of the description above.

        I had managed to get working (I thought) the non-US keyboards but it turns out the truth is 'not quite'.

        What I now see is improper dead key handling. For example, using the US-International KB layout, all the characters using the Right-Alt and Right-Alt/Shift combinations work fine. The dead key combinations ' followed by e for example do not work.

        The keyboard hook sees the dead key message (and ignores it) but the next key comes through as a normal 'e' rather than é.

        There's an awful lot of traffic in other forums in this area, does anyone have a clue as to the correct handling of these messages in a keyboard trap?

        The scary part is that MSDN in the ToAsciiEx description has the following quote:
        The parameters supplied to the ToAsciiEx function might not be sufficient to translate the virtual-key code, because a previous dead key is stored in the keyboard layout.
        And then they provide NOTHING else as to how one might work around the problem. What a crock! A description that says what a function does and then says, "Well, it MIGHT not work!"

        Maybe the keyboard hook is not supposed to just ignore the dead key but do something else ?????



        • #5

          The problem probably lies with ToAsciiEx.
          It takes keystrokes and converts it to (ascii) character codes.

          When using ToAsciiEx in a global hook proc, this messes up the handling of dead key characters in the application that is being hooked ..
          The reason is that ToAsciiEx stores (remembers) the dead key when pressed and does not return a character.
          When a 2nd key is pressed, ToAsciiEx takes the stored dead key, combines that with the new key and returns the combined character.
          If a hook proc calls ToAsciiEx, the hooked application will also call ToAsciiEx (Actually TranslateMessage does this in the applications main message loop).
          The fact that ToAsciiEx is called twice to process the same keystrokes messes up the dead key character combination, because the first ToAsciiEx that is called will eat the dead key that was stored and the 2nd ToAsciiEx will no longer find a dead key character stored and will therefore produce an incorrect ascii character ...
          We basically confuse ToAsciiEx by calling it twice to process the same keystrokes: once in the global hook and once in the hooked application .
          Ofcourse, in English, these special characters like "à" do not exist and this problem does not occur there. But in most European languages it does.
          I have found a number of attempts on the internet to work around this problem, but none of them works as it should.

          A method that works is to simply trap the WM_CHAR message in a global hook.
          A WM_CHAR message carries complete characters like é, ñ, etc.
          A WM_CHAR message is generated by the API function TranslateMessage that takes the keystrokes (WM_KEYDOWN etc.)
          and translates the virtual key codes into an ascii character (most likely by calling ToAsciiEx internally).
          TranslateMessage is called in an applications main message loop like this:
              DO WHILE GetMessage(Msg, %NULL, 0, 0)
                  TranslateMessage Msg
                  DispatchMessage Msg
          Strangely enough, I have read that there are applications that do NOT call TranslateMessage, and use a message loop like:
              DO WHILE GetMessage(Msg, %NULL, 0, 0)
                  DispatchMessage Msg
          Like this, no WM_CHAR messages are generated and a global hook can not trap the characters ...
          However, keystroke messages like WM_KEYDOWN are still generated ..
          I read that Borland Delphi shows (or showed) this behaviour, though I myself have never encountered a program behaving like this.
          Apart from one I wrote myself to test.

          Hope this helps (a bit)...

          Kind regards


          • #6
            Eddy, thanks for your thoughts. After posting I kept browsing (getting nowhere) so I went back to my usual technique, poke, prod, etc. and combined with a lucky semi-educated guess I think I've stumbled on the answer.

            First, my keyboard trap is not a global trap. The answer is to look at the RC from ToAsciiEx and when it comes back as -1 (Dead key) to just exit the trap function. The part I missed was to set the return value of the trap function to 1, which I had NOT done - a big Oops!.

            Having done that, it now seems to work properly.