The dialog manager, part 9: Custom accelerators in dialog boxes

Date:April 8, 2005 / year-entry #89
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20050408-41/?p=35943
Comments:    2
Summary:Along lines similar to last time, you can also add custom accelerators to your dialog box. (In a sense, this is a generalization of custom navigation, since you can make your navigation keys be accelerators.) So let's use accelerators to navigate instead of picking off the keys manually. Our accelerator table might look like this:...

Along lines similar to last time, you can also add custom accelerators to your dialog box. (In a sense, this is a generalization of custom navigation, since you can make your navigation keys be accelerators.)

So let's use accelerators to navigate instead of picking off the keys manually. Our accelerator table might look like this:

IDA_PROPSHEET ACCELERATORS
BEGIN
    VK_TAB      ,IDC_NEXTPAGE       ,VIRTKEY,CONTROL
    VK_TAB      ,IDC_PREVPAGE       ,VIRTKEY,CONTROL,SHIFT
END

Here you can see my comma placement convention for tables. I like to put commas at the far end of the field rather than jamming it up against the last word in the column. Doing this makes cut/paste a lot easier, since you can cut a column and paste it somewhere else without having to go back and twiddle all the commas.

Assuming you've loaded this accelerator table into the variable "hacc", you can use that table in your custom dialog loop:

while (<dialog still active> &&
       GetMessage(&msg, NULL, 0, 0, 0)) {
 if (!TranslateAccelerator(hdlg, hacc, &msg) &&
     !IsDialogMessage(hdlg, &msg)) {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }
}

The TranslateAccelerator function checks if the message matches any entries in the accelerator table. If so, then it posts a WM_COMMAND message to the window passed as its first parameter. In our case, we pass the dialog box handle. Not shown above is the WM_COMMAND handler in the dialog box that responds to IDC_NEXTPAGE and IDC_PREVPAGE by performing a navigation.

The same as last time, if you think there might be modeless dialogs owned by this message loop, you will have to do filtering so that you don't pick off somebody else's navigation keys.

while (<dialog still active> &&
       GetMessage(&msg, NULL, 0, 0, 0)) {
 if (!((hdlg == msg.hwnd || IsChild(hdlg, msg.hwnd)) &&
       !TranslateAccelerator(hdlg, hacc, &msg)) &&
     !IsDialogMessage(hdlg, &msg)) {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }
}

Okay, I think that's enough of dialog boxes for now.


Comments (2)
  1. François says:

    My head certainly hurts. However I have one question (I hope this is not off topic) : what should we do about APCs in modal loops ? I have sometimes wanted to do something like what follows, but I do not have enough experience to decide if this is suicide or not.

    //CTor

    m_hDummy = ::CreateEvent(NULL, FALSE, FALSE, NULL);

    //Message loop :

    while (<dialog still active>)

    {

    //alertable wait on dummy handle until there are messages to process

    while(WAIT_IO_COMPLETION == ::MsgWaitForMultipleObjectsEx(1, &m_hDummy, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE))

    {

    //Process APCs and go back to sleep.

    }

    //Message handling.

    if(GetMessage(&msg, NULL, 0, 0, 0)))

    {

    //Do your stuff

    }

    }

  2. Ben says:

    Fracois, you definitely can do that. Just be sure to structure your loop to pump messages while waiting on that handle.

    while (-1 != (iRet = PeekMessage(..)))

    {

    if (iRet)

    {

    // translate, dispatch, etc

    }

    else

    {

    MsgWaitForMultipleObjectsEx(…)

    // process here if the handle woke us up.

    // otherwise fall through to the PeekMessage

    }

    }

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index