3

In the post below

Menu Accelerator Keys (underline) for Owner-Draw menu items

I asked a question about "how to" draw the underline when users use Alt key to navigate the system menu, if the menubar is owner-draw. It is done (Thank Hans Passant).

But now comes another question: "When to" draw (and hide) the underline.

After the Alt is down, the WM_DRAWITEM messages are generated (for all items), then WM_SYSCOMMAND with wParam == SC_KEYMENU, and finally WM_DRAWITEM for the selected item.

See the message list at the end.

Since after WM_SYSCOMMAND, there is no WM_DRAWITEM for other items, I have to use WM_SYSKEYDOWN with VK_MENU to indicate that a user is using the key to navigate the system menu. So I got the following code: (Here byKey is a static bool variable)

    case WM_SYSKEYDOWN:
    {
        if (wParam == VK_MENU)
            byKey = true;
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }

    case WM_EXITMENULOOP:
    {
        if (wParam == 0)
            byKey = false;
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }

My question is that: Is there a better way to know "When to" draw (and hide) the underline??

<00686> 000B0444 P WM_SYSKEYDOWN nVirtKey:VK_MENU cRepeat:1 ScanCode:38 fExtended:0 fAltDown:1 fRepeat:0 fUp:0 [wParam:00000012 lParam:20380001]
<00687> 000B0444 S WM_DRAWITEM idCtl:0 lpdis:003EF080 [wParam:00000000 lParam:003EF080]
<00688> 000B0444 R WM_DRAWITEM fProcessed:True [lResult:00000001]
<00689> 000B0444 S WM_DRAWITEM idCtl:0 lpdis:003EF080 [wParam:00000000 lParam:003EF080]
<00690> 000B0444 R WM_DRAWITEM fProcessed:True [lResult:00000001]
<00691> 000B0444 S WM_DRAWITEM idCtl:0 lpdis:003EF080 [wParam:00000000 lParam:003EF080]
<00692> 000B0444 R WM_DRAWITEM fProcessed:True [lResult:00000001]
<00693> 000B0444 S WM_DRAWITEM idCtl:0 lpdis:003EF080 [wParam:00000000 lParam:003EF080]
<00694> 000B0444 R WM_DRAWITEM fProcessed:True [lResult:00000001]
<00695> 000B0444 S WM_DRAWITEM idCtl:0 lpdis:003EF080 [wParam:00000000 lParam:003EF080]
<00696> 000B0444 R WM_DRAWITEM fProcessed:True [lResult:00000001]
<00697> 000B0444 S WM_DRAWITEM idCtl:0 lpdis:003EF080 [wParam:00000000 lParam:003EF080]
<00698> 000B0444 R WM_DRAWITEM fProcessed:True [lResult:00000001]
<00699> 000B0444 S WM_DRAWITEM idCtl:0 lpdis:003EF080 [wParam:00000000 lParam:003EF080]
<00700> 000B0444 R WM_DRAWITEM fProcessed:True [lResult:00000001]
<00701> 000B0444 S WM_DRAWITEM idCtl:0 lpdis:003EF080 [wParam:00000000 lParam:003EF080]
<00702> 000B0444 R WM_DRAWITEM fProcessed:True [lResult:00000001]
....
<00708> 000B0444 P WM_SYSKEYUP nVirtKey:VK_MENU cRepeat:1 ScanCode:38 fExtended:0 fAltDown:0 fRepeat:1 fUp:1 [wParam:00000012 lParam:C0380001]
<00709> 000B0444 S WM_SYSCOMMAND uCmdType:SC_KEYMENU xPos:0 yPos:0 (used mnemonic) [wParam:0000F100 lParam:00000000]
<00710> 000B0444 S WM_ENTERMENULOOP fIsTrackPopupMenu:False [wParam:00000000 lParam:00000000]
<00711> 000B0444 R WM_ENTERMENULOOP lResult:00000000
....

<00714> 000B0444 S WM_INITMENU hmenuInit:01B10471 [wParam:01B10471 lParam:00000000]
<00715> 000B0444 R WM_INITMENU lResult:00000000
    <00716> 000B0444 S WM_DRAWITEM idCtl:0 lpdis:003EECE8 [wParam:00000000 lParam:003EECE8]
<00717> 000B0444 R WM_DRAWITEM fProcessed:True [lResult:00000001]
<00718> 000B0444 S WM_MENUSELECT uItem:0 fuFlags:MF_POPUP | MF_HILITE | MF_OWNERDRAW hmenu:01B10471 [wParam:01900000 lParam:01B10471]
<00719> 000B0444 R WM_MENUSELECT lResult:00000000
Community
  • 1
  • 1
user565739
  • 1,302
  • 4
  • 23
  • 46

2 Answers2

4

Your WM_DRAWITEM message contains a pointer to a DRAWITEMSTRUCT. In that structure, the ODS_NOACCEL flag will be set in the itemState if the underline should be hidden.

Raymond Chen
  • 44,448
  • 11
  • 96
  • 135
0

Take a look at the message WM_UPDATEUISTATE (http://msdn.microsoft.com/en-us/library/windows/desktop/ms646361%28v=vs.85%29.aspx).

Its implementation may look like this:

DWORD dwUiState = 0;  // current control state, usually a member in per-control struct.

switch(uMsg) {
   case WM_UPDATEUISTATE:
      switch(LOWORD(wParam)) {
         case UIS_INITIALIZE:  dwUiState = HIWORD(wParam); break;
         case UIS_CLEAR:       dwUiState &= ~HIWORD(wParam); break;
         case UIS_SET:         dwUiState |= HIWORD(wParam); break;
      }
      InvalidateRect(hWnd, NULL, TRUE);
      break;

   // ... handling of other messages
}

And in WM_PAINT, you should paint the underline when !(dwUiState & UISF_HIDEACCEL).

mity
  • 2,299
  • 17
  • 20
  • @mityMy app never generate or receive WM_UPDATEUISTATE. Should I use SendMessage to generate this message? But if so, when I need to send this message? – user565739 Feb 17 '13 at 13:21
  • System (since XP, AFAIK), sends it to the active (focused) top-level window, e.g. when `ALT` is pressed. The top-level window should pass it to `DefWindowProc()` which distributes to to its child windows. – mity Feb 17 '13 at 13:26
  • Weired. No WM_UPDATEUISTATE, (I used break point in WM_UPDATEUISTATE). – user565739 Feb 17 '13 at 13:42
  • Here http://stackoverflow.com/questions/14054036/show-hotkeys-at-all-times, David Heffernan said an application should use SendMessage to send WM_UPDATEUISTATE. But this doesn't help to my question. – user565739 Feb 17 '13 at 13:54