markwk@metheny.unx.sas.com (Mark Kernodle) (08/13/90)
/* * Sample application for Xt intrinsics "feature" * Author: E. Blair, SAS Institute, Inc. (919) 677-8000 x6956 * * Problem statement: This program demonstrates what I believe to be a problem * in the _XtTranslateEvent Xt event handler interpretation of * eventObjTbl entries in the XtTranslations state table. This problem was * experienced in the DECwindows Xt intrinsics as well as in the Motif * intrinsics. The behavior is that non-initial key events associated * with a multi-key event sequence are thrown away even though a translation * action exists in the table that should receive the event. The * _XtTranslateEvent handler returns for such events because the EventRec * state is NULL. For this sample, I would expect the translation to match the * explicit sequences given, dispatching all other keys to the "normal-key" * action. Instead, KeyPress events for keys a and b are never delivered to * the "normal-key" action. */ #include <ctype.h> #include <Xm/Xm.h> #include <X11/Shell.h> #include <X11/Xlib.h> /* Some statics for widgets */ static Widget toplevel, window_widget; /* * Widget action table and translations */ static void MyFocusIn(); static void MyFocusOut(); static void MyPFKey(); static void MyNormalKey(); static XtActionsRec TestActions[] = { {"focus-in", MyFocusIn}, {"focus-out", MyFocusOut}, {"pf-key", MyPFKey}, {"normal-key", MyNormalKey}, {NULL, NULL} }; static XtTranslations TestTLP = NULL; static char TestTranslations[] = "<FocusIn>: focus-in() \n\ <FocusOut>: focus-out() \n\ <Key>KP_F1,<Key>a: pf-key(1) \n\ <Key>KP_F1,<Key>b: pf-key(2) \n\ <Key>: normal-key()"; static void ShowKey(event) XEvent *event; { int keylen,keysym; char *modify,*keystr; char keyascii[4]; keylen = XLookupString (event, keyascii, sizeof(keyascii), &keysym, NULL); keyascii[keylen] = '\0'; if (event->xkey.state & ShiftMask) modify = "Shift"; if (event->xkey.state & LockMask) modify = "Lock"; else if (event->xkey.state & ControlMask) modify = "Control"; else if (event->xkey.state & Mod1Mask) modify = "Meta"; else modify = ""; if (isprint(keyascii[0])) keystr = keyascii; else { keystr = XKeysymToString (keysym); if (!keystr) keystr = "**NoKeySymString**"; } printf ("KeyString: %s<Key>%s\n",modify,keystr); return; } static void MyFocusIn (w, event, argv, nargs) Widget w; XEvent *event; String argv[]; int *nargs; { printf ("Focus in window\n"); return; } static void MyFocusOut (w, event, argv, nargs) Widget w; XEvent *event; String argv[]; int *nargs; { printf ("Focus left window\n"); return; } static void MyPFKey(w, event, argv, nargs) Widget w; XEvent *event; int *nargs; String argv[]; { int i; for (i=0; i < *nargs; i++) printf ("PF key: Arg[%d]: %s\n", i, argv[i]); ShowKey(event); return; } static void MyNormalKey(w, event, argv, nargs) Widget w; XEvent *event; int *nargs; String argv[]; { printf("Normal key event\n"); ShowKey (event); return; } static Widget build_main (p) Widget p; { Arg al[10]; int ac = 0; XtSetArg (al[ac], XmNx, 100); ac++; XtSetArg (al[ac], XmNy, 100); ac++; XtSetArg (al[ac], XmNheight, 100); ac++; XtSetArg (al[ac], XmNwidth, 300); ac++; XtSetArg (al[ac], XmNtranslations, TestTLP); ac++; window_widget = XmCreateDrawingArea(p, "Window", al, ac); XtManageChild (window_widget); return (window_widget); } main (argc, argv) int argc; char *argv[]; { Arg args[1]; /* * do toolkit initialization */ toplevel = XtInitialize("Simple", "TEST", NULL, 0, &argc, argv); if (!toplevel) { printf ("Initialize failed\n"); exit(1); } XtSetArg (args[0], XtNallowShellResize, TRUE); XtSetValues (toplevel, args, 1); XtAddActions (TestActions,XtNumber(TestActions)); TestTLP = XtParseTranslationTable (TestTranslations); if (!TestTLP) { printf ("Translation parse failed\n"); exit(1); } /* * now set up the test window */ build_main (toplevel); /* * and realize the test window */ XtRealizeWidget (toplevel); /* * main event loop for test window */ XtMainLoop(); }
gabe@hpcvlx.cv.hp.com (Gabe Begeddov) (08/15/90)
/ hpcvlx:comp.windows.x / markwk@metheny.unx.sas.com (Mark Kernodle) / 8:25 am Aug 13, 1990 / * intrinsics. The behavior is that non-initial key events associated * with a multi-key event sequence are thrown away even though a translation * action exists in the table that should receive the event. The You are quite right. There are many problems with the translation manager handling of multiple event left hand sides. This is mostly due to the fact that a single table is used to do both caching of event matching information and lookup ordering of both initial and ensueing incoming events. We (HP) are in the process of rewriting the translation manager for much improved data space usage with a byproduct being (hopefully :-) correct handling of event sequences and table merges (another problem area in the current implementation). We will be donating this code to MIT in the next few months. Depending on timing and release decisions it should be available by R5 (if not sooner). Please also send bug reports related to the tm to xbugs@expo.lcs.mit.edu so that they can be logged and checked against any proposed implementation changes. Thanx, Gabe Beged-Dov Interface Technology Operation Hewlett Packard
swick@ATHENA.MIT.EDU (Ralph Swick) (08/16/90)
The behavior is that non-initial key events associated with a multi-key event sequence are thrown away even though a translation action exists in the table that should receive the event. This is an interesting case of ambiguity in the Xt specification. To summarize, given the translation specification <Key>a,<Key>b : something() <Key> : else() then <KeyPress>b events not preceeded by <KeyPress>a wind up being discarded as a side-effect of the rule that "more specific events must preceed more general events". I won't argue with anyone claiming that this is non-intuitive. You'd probably argue (and in theory, I'd probably agree) that 'a' is meant to be a prefix character ala emacs and that un-prefixed 'b' should invoke the else() action. You'd still have to invoke the "more specific preceed more general" rule to explain why 'a' not followed by 'b' should go into the bit-bucket, if that's what you want to have happen. Such a rule is easy to implement (it's 1 line; I just did it) but it opens a big compatibility can o'worms. If it were to become part of the implementation, we'd have to provide a compatibility mode for the current behavior. Fortunately, there's a simple alternative: you can specify <Key>a,<Key>b : something() <Key>b : else() <Key> : else() to get the behavior in the preceeding paragraph. Yes, it's ugly, but it may be the best option available. -Ralph