Professional UI Solutions
Site Map   /  Register
 
 

Forum

Please Log In to post a new message or reply to an existing one. If you are not registered, please register.

NOTE: Some forums may be read-only if you are not currently subscribed to our technical support services.

Forums » Prof-UIS Tech Support » Problem with keyboard accelerator customization Collapse All
Subject Author Date
Chris Thomas Apr 20, 2007 - 8:50 AM

Hello, I am having a problem with keyboard customization. I have been comparing my app with the BitmapEditor example, and I can’t figure out what is missing from my app. My app has customization enabled and I am able to do things like create and save user defined control bars, so I think the basic customization is correct.

The specific feature that isn’t working is the keyboard customization page on the customization dialog. My app shows all 3 tabs ("toolbars", "commands", "keyboard"):

    if( !CExtCustomizeSite::EnableCustomization(
        this,
        __ECSF_BARS
        |__ECSF_COMMANDS
        | __ECSF_USER_BARS
        | __ECSF_ACCELERATORS
        | __ECSF_PARMS_DISABLE_PERSONALIZED
        ))

But when I go to the keyboard page, I am unable to view any key bindings (I know they exist - you can see them on the menu. ie, File|New has an accelerator but the keyboard page doesn’t show it). You can’t type in a new binding, and the "Reset All" button is always disabled.

I did debug it some and the CExtCustomize.cpp code is having trouble getting the customization information tree from the command ID. I don’t know why.

More background: Our app is using the default MFC menu, not the prof-uis menu. I don’t know if that matters.

Am I missing something really fundamental here?


Chris Thomas Apr 26, 2007 - 2:22 PM

Thanks, that worked great!

Chris Thomas Apr 25, 2007 - 1:18 PM

I found it!!! The entire keyboard part is disabled if you are not using the Prof-uis CExtMenuControlBar menu. Our app isn’t using CExtMenuControlBar, instead uses regular MFC menu. I can’t get our app to work with CExtMenuControlBar, but that is our problem (there is an #ifdef to use CExtMenuControlBar or not, so I’ll have to look into that).

Anyway if you take one of the samples that has customization, say BitmapEditor, and comment out all CExtMenuControlBar references, recompile, run, then try the customize dialog, you’ll see the disabled controls on the keyboard page.

It is because this code in CExtCustomizeSite::OnRegisterToolBar():
    if( pToolBar->IsKindOf(RUNTIME_CLASS(CExtMenuControlBar)) )
    {
        ASSERT( m_pWndMenuBar == NULL ); // should be one!
        m_pWndMenuBar = (CExtMenuControlBar *)pToolBar;
....

doesn’t execute because it isn’t using the prof-uis menu. That leaves m_pWndMenuBar to be NULL, so MenuInfoActiveSet() doesn’t get called, which leaves m_pMenuInfoActiveCustomize = NULL. So later MenuInfoActiveGet() returns NULL, so this code in CExtCustomizePageKeyboard::_OnSyncContent() ends up setting m_wndComboAccelGroup.SetCurSel(-1):

INT nMenuCount = pSite->MenuInfoGetCount();
    if( nMenuCount >= 1 )
    {
        for( INT i = 0; i < nMenuCount; i++ )
        {
            CExtCustomizeSite::CCmdMenuInfo * pCmdMenuInfo =
                pSite->MenuInfoGetAt( i );
            ASSERT( pCmdMenuInfo != NULL );
            ASSERT( pCmdMenuInfo->IsInitialized() );
            ASSERT( pCmdMenuInfo->GetName() != NULL );
            m_wndComboAccelGroup.AddString( pCmdMenuInfo->GetName() );
        } // for( INT i = 0; i < nMenuCount; i++ )
        int nCurSel = -1;
        CExtCustomizeSite::CCmdMenuInfo * pCmdMenuInfo =
            pSite->MenuInfoActiveGet();
        if( pCmdMenuInfo != NULL )
        {
            nCurSel = pSite->MenuInfoFindIndex( pCmdMenuInfo );
            ASSERT( 0 <= nCurSel && nCurSel < nMenuCount );
        } // if( pCmdMenuInfo != NULL )
        m_wndComboAccelGroup.SetCurSel( nCurSel );
        OnSelendOkAccelGroupCombo();
    } // if( nMenuCount >= 1 )

And since wndComboAccelGroup current selection is -1, then this code in CExtCustomizePageKeyboard::_UpdateCmdButtons() disables buttons:
    if( m_pMenuInfo != NULL )
    {
        if( !m_wndBtnResetAll.IsWindowEnabled() )
            m_wndBtnResetAll.EnableWindow( TRUE );
    }
    else
    {
        if( m_wndBtnResetAll.IsWindowEnabled() )
            m_wndBtnResetAll.EnableWindow( FALSE );
    }


That explains why the "Reset All" button is always disabled. I’m assuming, but I haven’t debugged it, that there are no keys displaying because there is m_pMenuInfo object to get the keys from.

In any event, it looks like keyboard customization requires use of the prof-uis menu.

We aren’t using the prof-uis menu because our app has a feature that displays tooltips for disabled menu items. The tooltip is provided on-the-fly based on why the item is disabled, rather than static text from the RC file. This is done by catching these messages, but I’m not 100% sure on the details.
    ON_WM_MENUSELECT()
    ON_WM_ENTERIDLE()
    ON_WM_ENTERMENULOOP()
    ON_WM_EXITMENULOOP()
    ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
    ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)

I haven’t tried this with the prof-uis menu.

The other strange thing we do is add/remove menu items in CCmdUI update handlers. I noticed that with the prof-uis menu, the CCmdUI menu pointer is always NULL.

Thanks for the suggestions!



Technical Support Apr 26, 2007 - 1:21 PM

To fix this problem in SDI applications based on the standard window menu line, please update the source code for the following method:

CExtCustomizeSite::CCmdMenuInfo * CExtCustomizeSite::MenuInfoActiveGet()
{
      ASSERT( this != NULL );
      if( m_pMenuInfoActiveCustomize == NULL )
            return MenuInfoGetDefault();
      return m_pMenuInfoActiveCustomize;
}
The MDI applications will use only one default accelerator table after that.

Chris Thomas Apr 20, 2007 - 10:56 AM

Yes, I’m already calling MenuInfoAdd(). Not only am I unable to determine why my app’s keyboard customization doesn’t work, but I am unable to change the BitmapEditor example to show the same behavior.

I do agree that it appears like a missing menu tree and accelerator table, but I can’t see why.

Anyway thanks for the reply and I’ll keep on looking.

This is my code:
    VERIFY(
        g_CmdManager->UpdateFromMenu(
            ::AfxGetApp()->m_pszProfileName,
            IDR_MAINFRAME
            )
        );


    //setup profUIS customization
    VERIFY(
        CExtCustomizeSite::MenuInfoAdd(
        this,
        _T("Default"),
        IDR_MAINFRAME,
        true
        )
    );

    VERIFY(
        CExtCustomizeSite::MenuInfoLoadAccelTable(
        _T("Default"),
        IDR_MAINFRAME
        )
    );

    //enable customization, but don’t include __ECSF_PARMS (locks out the menu/toolbar customization page)
    if( !CExtCustomizeSite::EnableCustomization(
        this,
        __ECSF_BARS
        |__ECSF_COMMANDS
        | __ECSF_USER_BARS
        | __ECSF_ACCELERATORS
        | __ECSF_PARMS_DISABLE_PERSONALIZED
        ))
    {
        ASSERT( FALSE );
        return -1;
    }

    CExtCustomizeSite::CategoryUpdate( IDR_MAINFRAME );
    CExtCustomizeSite::CategoryMakeAllCmdsUnique();
    CExtCustomizeSite::CategoryAppendAllCommands();

Technical Support Apr 22, 2007 - 8:57 AM

If your application is MDI, please try to reproduce the problem using the DRAWCLI sample, which is also MDI. In any case, you can send us the source code of the main frame window or the entire project so we can find out what’s wrong.

Technical Support Apr 20, 2007 - 10:11 AM

The customize site allows you to register one or more named menu lines. You can do this with the CExtCustomizeSite::MenuInfoAdd() method. Each menu line includes a menu tree and an accelerator table. Even if you are not using the menu control bar, you should register at least one menu line. Otherwise the accelerator customization page will not work at all because it cannot find any registered menu line with an accelerator table to customize.