What does TranslateAccelerator do?


For some reason, there appears to be some confusion over what TranslateAccelerator does. It’s very simple, and it’s all spelled out in the documentation. You give it a message, and if the message is a keypress that matches an entry in the accelerator table, the corresponding WM_COMMAND or WM_SYSCOMMAND message is sent to the window you said you are translating messages for.

One point of confusion is which window receives the translated message. Is it the window in the MSG structure or the window passed as the first parameter to TranslateAccelerator? This confusion shouldn’t last long, though, because of the two options, one of them raises more questions than it resolves.

  • If it went to the window in the MSG structure, then there would be no need for a hWnd parameter to TranslateAccelerator, since it wouldn’t be used for anything.

  • If it went to the window in the MSG structure, there wouldn’t be much need to have a TranslateAccelerator function anyway, because even without it, the message would have gone to the window in the MSG structure anyway.

If the message matches an accelerator, the WM_COMMAND or WM_SYSCOMMAND message goes to the window you passed as the first parameter to TranslateAccelerator.

Once you understand this, you can answer the next question:

My program has two dialogs containing tabs, both running on the same UI thread. I want to make sure that the Ctrl+Tab hotkey switches between the tabs on the correct dialog. I’ve already created an accelerator table, but how do I decide which window to pass as the first parameter to TranslateAccelerator? Right now, I’m using GetForegroundWindow().

Well, first off, GetForegroundWindow() is completely wrong, since the foreground window need not be one of your two dialogs. The user may be working with Notepad, and now you sent a WM_COMMAND to Notepad with one of your private command codes, a command code that has a completely different meaning to Notepad.

Okay, back to the question. How do you know which window to pass as the first parameter to TranslateAccelerator? Well, it’s the window that you want the WM_COMMAND message to go to: You want it to go to the dialog that contains the window that the user typed Ctrl+Tab into. You can determine this window by looking at the MSG structure, since keyboard messages are delivered to the window with keyboard focus.

if (IsChild(hwnd1, msg.hwnd))
    TranslateAccelerator(hwnd1, hAccel, &msg);
else if (IsChild(hwnd2, msg.hwnd))
    TranslateAccelerator(hwnd2, hAccel, &msg);

The window handle in the MSG structure tells you which window the user typed the key into; if that window is part of the first dialog, then translate the message and send any translated message to the first dialog. Otherwise, check the same thing with the second dialog.

Easy as pie.

Comments (13)
  1. Medinoc says:

    Is this the reason why it’s a bad idea to associate one of the Ctrl-X, Ctrl-C or Ctrl-V to an accelerator in a window that contains some edit controls ? The keystroke would be intercepted by the window instead of going to the editbox ?

  2. meh says:

    These sort of postings are my favorite. Keep up the good work, Raymond!

  3. chrismcb says:

    Man if ONLY pies were this easy!

  4. yme says:

    Near the end, in “… tells you which window the user typed the key into; if that message is part of the first dialog …”, I guess “message” should be “window”?

    [Fixed, thanks. -Raymond]
  5. poenits says:

    If WM_KEYUP/KEYDOWN messages are sent to a top-level window, TranslateAccelerator is never called.

    I’d add else TranslateAccelerator(msg.hwnd, hAccel, &msg);

  6. Frymaster says:

    "Is this the reason why it’s a bad idea to associate one of the Ctrl-X, Ctrl-C or Ctrl-V to an accelerator in a window that contains some edit controls ? The keystroke would be intercepted by the window instead of going to the editbox ?"

    I’d say it was a bad idea just because of the confusion.  Whether it was the edit box or the window, you can bet at least one person would want their ctrl-x to be intercepted by the other one

    (and why do ctrl-insert, shift-insert and shift-delete never get the wub?)

  7. Ulric says:

    Wait a minute, semantically GetForegroundWindow is wrong.  But in practice, how could it be wrong?  

    If you are getting the keyboard messages, then the user is not working in another application.  You have the keyboard the focus;  the foreground window is one of your windows.

  8. bigfoot says:

    "Easy as pie"

    How easy is this?

    Is it so easy even a caveman could do it? (ok, ok, caveperson)

    Does the type of pie affect this, and is it relative? I prefer cherry over apple – is cherry easier for me and harder for someone else?

    Who knew that Windows had such subtleties!

  9. Jonas says:

    "If you are getting the keyboard messages, then the user is not working in another application.  You have the keyboard the focus;  the foreground window is one of your windows."

    It might have been the foreground window when the key was pressed, but there is no guarantee that it still is.

  10. blip says:

    @Ulric: Getting focus doesn’t mean raising to the top. Assuming that ruins everything for those who configure Windows to set focus on mouse hover. Those who hate it also turned on auto-raise, which sucks. But focus-on-hover is great, you should try it! (with 0ms delay, of course)

  11. Ulric says:

    @blip, The ForeGround window is not the window on top.  It is defined as the one the user is working in, not the Z order.

  12. Andy says:

    @Ulric: The reason you shouldn’t use GetForegroundWindow() is because the code is executed asyncronously from the keypress (during the message queue loop), and the user may have switched the foreground window before the code is executed.

  13. SuperKoko says:

    @Andy:

    Many programmers ignore that Windows is a preemptive multitasking OS. Sad but true.

Comments are closed.