67) Why can't I use accelerators on buttons not in a menu?

Answer: It is apparently a difficult feature to implement, but OSF are
considering this for the future. It is problematic trying to use the Xt
accelerators since the Motif method interferes with this.  one workaround
suggested is to duplicate your non-menu button by a button in a menu
somewhere, which does have a menu-accelerator installed.  When the user
invokes what they think is the accelerator for the button they can see Motif
actually invokes the button on the menu that they can't see at the time.
Another method is described below and was contributed by Harald Albrecht of
Institute of Geometry and Practical Mathematics Rhine Westphalia Technical
University Aachen (RWTH Aachen), Germany


From albrecht@igpm.rwth-aachen.de Thu Jul  8 11:44:21 1993

My work-around of this problem looks like this: (I've written that code for a
Motif Object Library in C++ so please forgive me for being object orientated!)
The hack consists of a rewritten message loop which checks for keypresses
<MAlt>+<key>. If MessageLoop() finds such a keypress HandleAcc() ist called
and the widget tree is searched for a suitable widget with the right mnemonic.


// --------------------------------------------------------------------------
// traverse the widget tree starting with the given widget.
//
BOOL TraverseWidgetTree(Widget w, char *pMnemonic, XKeyEvent *KeyEvent)
{
    Widget               wChild;
    WidgetList           ChildList;
    int                  NumChilds, Child;
    KeySym               LabelMnemonic;
    char                 *pMnemonicString;

// Check if the widget is a subclass of label -- then it may have an
// accelerator attached...
    if ( XtIsSubclass(w, xmLabelWidgetClass) ) {
// ok. Now: get the widget's mnemonic, convert it to ASCII and compare
// it with the Key we're looking for.
        XtVaGetValues(w, XmNmnemonic, &LabelMnemonic, NULL);
        pMnemonicString = XKeysymToString(LabelMnemonic);
        if ( pMnemonicString &&
             (strcasecmp(pMnemonicString, pMnemonic) == 0) ) {
            // stimulate the keypress
            XmProcessTraversal((Widget)w, XmTRAVERSE_CURRENT);
            KeyEvent->type      = KeyPress;
            KeyEvent->window    = XtWindow(w);
            KeyEvent->subwindow = XtWindow(w);
            KeyEvent->state     = 0;
            KeyEvent->keycode   =
                XKeysymToKeycode(XtDisplay(w), XK_space);
            XSendEvent(XtDisplay(w), XtWindow(w),
                       True,
                       ButtonPressMask, (XEvent*) KeyEvent);
            KeyEvent->type      = KeyRelease;
            XSendEvent(XtDisplay(w), XtWindow(w),
                       True,
                       ButtonReleaseMask, (XEvent*) KeyEvent);
            return True;
        }
    }
// if this widget is a subclass of Composite check all the widget's
// childs.
    if ( XtIsSubclass(w, compositeWidgetClass) ) {
// if we're in a menu (or something like that) forget this leaf of the
// widget tree!
        if ( XtIsSubclass(w, xmRowColumnWidgetClass) ) {
            unsigned char RowColumnType;
            XtVaGetValues(w, XmNrowColumnType, &RowColumnType, NULL);
            if ( RowColumnType != XmWORK_AREA ) return False;
        }
        XtVaGetValues(w, XmNchildren, &ChildList,
                         XmNnumChildren, &NumChilds, NULL);
        for ( Child = 0; Child < NumChilds; ++Child ) {
            wChild = ChildList[Child];
            if ( TraverseWidgetTree(wChild, pMnemonic, KeyEvent) )
                return True;
        }
    }
    return False;
} // TraverseWidgetTree
// --------------------------------------------------------------------------
// handle accelerators (keypress MAlt + key)
//
#define MAX_MAPPING 10
BOOL HandleAcc(Widget w, XEvent *event)
{
           Widget         widget, OldWidget;
    static char           keybuffer[MAX_MAPPING];
           int            CharCount;
    static XComposeStatus composeStatus;

// convert KeyPress to ASCII
    CharCount = XLookupString((XKeyEvent*) event,
                              keybuffer, sizeof(keybuffer),
                              NULL, &composeStatus);
    keybuffer[CharCount] = 0;
// Only one char is alright -- then search the widget tree for a widget
// with the right mnemonic
    if ( CharCount == 1 ) {
        keybuffer[0] = tolower(keybuffer[0]);
        widget = w;
        while ( (widget != NULL) &&
                !XtIsSubclass(widget, shellWidgetClass) ) {
            OldWidget = widget; widget = XtParent(widget);
        }
        if ( !widget ) widget = OldWidget;
        return TraverseWidgetTree(widget,
                                  keybuffer, (XKeyEvent*) event);
    }
    return False; // no-one found.
} // HandleAcc
// --------------------------------------------------------------------------
// modified message loop
// loops until the Boolean pFlag points to is set to False
void MessageLoop(Boolean *pFlag)
{
    XEvent nextEvent;

    while ( *pFlag ) {
        if ( XtAppPending(AppContext) ) {
            XtAppNextEvent(AppContext, &nextEvent);
            if ( nextEvent.type == KeyPress ) {
// Falls es ein Tastendruck ist, bei dem auch noch die ALT-Taste
// (=Modifier 1) gedrueckt ist, koennte es ein Accelerator sein!
                if ( nextEvent.xkey.state & Mod1Mask )
                    if ( HandleAcc(XtWindowToWidget(nextEvent.xkey.display,
                                                    nextEvent.xkey.window),
                                   &nextEvent) )
                        continue; // Mitteilung konnte ausgeliefert werden
                                  // und darf daher nicht den ueblichen
                                  // Weg gehen!
            }
            XtDispatchEvent(&nextEvent);
        }
    }
} // TApplication::MessageLoop


Harald Albrecht albrecht@igpm.rwth-aachen.de Institute of Geometry and
Practical Mathematics Rhine Westphalia Technical University Aachen (RWTH
Aachen), Germany
Go Back Up

Go To Previous

Go To Next