Search the FAQ Archives

3 - A - B - C - D - E - F - G - H - I - J - K - L - M
N - O - P - Q - R - S - T - U - V - W - X - Y - Z
faqs.org - Internet FAQ Archives

Motif FAQ (Part 5 of 9)
Section - 132) Why can't I use accelerators on buttons not in a menu?

( Part1 - Part2 - Part3 - Part4 - Part5 - Part6 - Part7 - Part8 - Part9 - Single Page )
[ Usenet FAQs | Web FAQs | Documents | RFC Index | Houses ]


Top Document: Motif FAQ (Part 5 of 9)
Previous Document: 131) Why doesn't the enter or return key activate the button with
Next Document: 133) TOPIC: TOGGLEBUTTON WIDGET
See reader questions & answers on this topic! - Help others by sharing your knowledge
[Last modified: Sept 94]

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


albrecht@igpm.rwth-aachen.de wrote (Jul 8, 1993):

NOTE: Pointers to a more recent solution by the same author follow this code
sample.

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

NOTE: Harald Albrecht has re-designed his solution so that you can assign
hotkeys to *every* widget by placing a label near that widget. Get the code
from:

ftp.informatik.rwth-aachen.de (137.226.112.172) in:
/pub/packages/Mnemonic/Mnemonic.tar.gz

or from the WWW:

file://134.130.161.30/arc/pub/unix/html/motifcorner.html

User Contributions:

Comment about this article, ask questions, or add new information about this topic:

CAPTCHA




Top Document: Motif FAQ (Part 5 of 9)
Previous Document: 131) Why doesn't the enter or return key activate the button with
Next Document: 133) TOPIC: TOGGLEBUTTON WIDGET

Part1 - Part2 - Part3 - Part4 - Part5 - Part6 - Part7 - Part8 - Part9 - Single Page

[ Usenet FAQs | Web FAQs | Documents | RFC Index ]

Send corrections/additions to the FAQ Maintainer:
kenton@rahul.net (Ken Lee)





Last Update March 27 2014 @ 02:11 PM