Lars, the attached patch to xforms' forms.c cures these two bugs in xforms
handling of key events.
o xforms should swallow null keyevents. They occur during composition of
multi-byte chars. The problem was reported and a solution proposed here:
o xforms should pass FL_KEYRELEASE events to the widgets. Currently they are
swallowed.
I find that holding down the 'a' key continuously results in this
lyx -dbg 524292 (workarea + key) output.
Ie each and every KEYPRESS event is followed by a KEYRELEASE event.
Work area event KEYPRESS
Key is `a' [97]
Keysym is `a' [97]
State is
Workarea Diff: 141800041
KeySym is a
action first set to [88]
action now set to [88]
Key [action=88][a]
Cannot decode: a
SelfInsert arg[`a']
Workarea event: KEYRELEASE
Work area event KEYPRESS
Key is `a' [97]
Keysym is `a' [97]
State is
Workarea Diff: 250
KeySym is a
action first set to [88]
action now set to [88]
Key [action=88][a]
Cannot decode: a
SelfInsert arg[`a']
Workarea event: KEYRELEASE
You said yesterday that you would use this information to take the hack at
the bottom of this letter out of the FL_KEYPRESS part of XWorkArea's
handler. My question to you is how do you propose using this new information?
I envisage replacing it with something like
handler() {
// This variable is used to block spurious keyboard input from multiple
// FL_KEYPRESS events that are not separated by an FL_KEYRELEASE
// event.
static bool input_acceptable = true;
switch (event) {
case FL_KEYPRESS:
if (!input_acceptable) break;
...
workAreaKeyPress(LyXKeySymPtr(xlk), x_key_state(ret_state));
input_acceptable = false;
break;
case FL_KEYRELEASE:
input_acceptable = true;
break;
}
}
Is that what you had in mind too? If so, wouldn't the most suitable place for
this be in xforms itself, in the switch handling the raw XEvents
(do_interaction_step)
case KeyPress:
...
case KeyRelease:
...
Let me know your thoughts on this. (Incidentally, is this a real problem or
an imaginary one? Ie, is this code really needed?)
Angus
Code to go:
static Time last_time_pressed;
static unsigned int last_key_pressed;
static unsigned int last_state_pressed;
lyxerr[Debug::KEY] << "Workarea Diff: "
<< xke->time - last_time_pressed
<< endl;
if (xke->time - last_time_pressed < 25 // Should be tunable?
&& ret_state == last_state_pressed
&& xke->keycode == last_key_pressed) {
lyxerr[Debug::KEY]
<< "Workarea: Purging X events." << endl;
if (XEventsQueued(fl_get_display(), QueuedAlready) > 0)
waitForX(true);
// This purge make f.ex. scrolling stop immediately when
// releasing the PageDown button. The question is if
// this purging of XEvents can cause any harm...
// after some testing I can see no problems, but
// I'd like other reports too. (Lgb)
break;
}
last_time_pressed = xke->time;
last_key_pressed = xke->keycode;
last_state_pressed = ret_state;
--- xforms-1.0-release/lib/forms.c Tue Nov 19 21:06:43 2002
+++ xforms-1.0-release-modified/lib/./forms.c Tue Dec 10 09:58:44 2002
@@ -1218,7 +1218,8 @@
}
static void
-fl_keyboard(FL_FORM * form, int key, FL_Coord x, FL_Coord y, void *xev)
+fl_keyboard(int event,
+ FL_FORM * form, int key, FL_Coord x, FL_Coord y, void *xev)
{
FL_OBJECT *obj, *obj1, *special;
@@ -1239,7 +1240,7 @@
if (obj1 && obj1 != special)
special = fl_mouseobj;
- if (form->focusobj)
+ if (event == FL_KEYPRESS && form->focusobj)
{
FL_OBJECT *focusobj = form->focusobj;
@@ -1294,11 +1295,11 @@
/* space is an exception for browser */
if ((key > 255 || key == ' ') && (special->wantkey & FL_KEY_SPECIAL))
- fl_handle_object(special, FL_KEYBOARD, x, y, key, xev);
+ fl_handle_object(special, event, x, y, key, xev);
else if (key < 255 && (special->wantkey & FL_KEY_NORMAL))
- fl_handle_object(special, FL_KEYBOARD, x, y, key, xev);
+ fl_handle_object(special, event, x, y, key, xev);
else if (special->wantkey == FL_KEY_ALL)
- fl_handle_object(special, FL_KEYBOARD, x, y, key, xev);
+ fl_handle_object(special, event, x, y, key, xev);
#if FL_DEBUG >= ML_INFO
M_info("KeyBoard", "(%d %d)pushing %d to %s\n", x, y, key, special->label);
@@ -1424,8 +1425,9 @@
fl_pushobj = NULL;
fl_handle_object(obj, FL_RELEASE, xx, yy, key, xev);
break;
- case FL_KEYBOARD: /* A key was pressed */
- fl_keyboard(form, key, xx, yy, xev);
+ case FL_KEYPRESS: /* A key was pressed */
+ case FL_KEYRELEASE: /* A key was released */
+ fl_keyboard(event, form, key, xx, yy, xev);
break;
case FL_STEP: /* A simple step */
obj1 = fl_find_first(form, FL_FIND_AUTOMATIC, 0, 0);
@@ -1555,7 +1557,20 @@
}
} else {
+
+ /* Always pass on FL_KEYRELEASE, even though keysym is almost
+ always null */
+ if (formevent == FL_KEYRELEASE) {
+ fl_handle_form(keyform, formevent, keysym, xev);
+ return;
+ }
+ /* keysym == 0 during multi-byte char composition.
+ Eg, I've typed Multi_key-a but not yet ' to give � */
+
+ if (!keysym)
+ return;
+
/* ignore modifier keys as they don't cause action and are
taken care of by the lookupstring routine */