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), GermanyGo Back Up