ximcp: Unmark to fabricate key events with XKeyEvent serial

_XimProtoKeypressFilter() and _XimProtoKeyreleaseFilter() can
receive XKeyEvent from both the typing on the keyboard and the
callback of XIM_FORWARD_EVENT.

If the filter functions unmark to fabricate XKeyEvent from the typing
on the keyboard during receiving XKeyEvent from the callback of
XIM_FORWARD_EVENT with typing keys very quickly likes an bar code
scanner (or evemu-play), XIM server cannot receive some key events and
it causes the key typing order to get scrambled.

Now XIM client saves the serial in XKeyEvent and the filter functions
unmark to fabricate XKeyEvent from the callback of XIM_FORWARD_EVENT
only.

Fixes: #198
This commit is contained in:
Takao Fujiwara 2024-01-31 20:26:40 +09:00
parent ae3eca18ce
commit 024d229fdf
No known key found for this signature in database
GPG key ID: B2F99ED770DC79EC
4 changed files with 75 additions and 9 deletions

View file

@ -142,9 +142,9 @@ _XimProtoKeypressFilter(
{
Xim im = (Xim)ic->core.im;
if (IS_FABRICATED(im)) {
if (_XimIsFabricatedSerial(im, ev->serial)) {
_XimPendingFilter(ic);
UNMARK_FABRICATED(im);
_XimUnfabricateSerial(im, ev->serial);
return NOTFILTERD;
}
@ -203,9 +203,9 @@ _XimProtoKeyreleaseFilter(
{
Xim im = (Xim)ic->core.im;
if (IS_FABRICATED(im)) {
if (_XimIsFabricatedSerial(im, ev->serial)) {
_XimPendingFilter(ic);
UNMARK_FABRICATED(im);
_XimUnfabricateSerial(im, ev->serial);
return NOTFILTERD;
}

View file

@ -430,6 +430,7 @@ _XimPreConnect(
return False;
im->private.proto.im_window = im_window;
im->private.proto.fabricated_serial = 0;
return True;
}

View file

@ -341,6 +341,54 @@ _XimForwardEvent(
return _XimForwardEventCore(ic, ev, sync);
}
Bool
_XimFabricateSerial(
Xim im,
unsigned long serial)
{
if (!serial)
return False;
if (serial == im->private.proto.fabricated_serial) {
fprintf(stderr, "%s,%d: The key event is already fabricated.\n", __FILE__, __LINE__);
return False;
}
if (im->private.proto.fabricated_serial)
fprintf(stderr, "%s,%d: Tried to fabricate a wrong key event.\n", __FILE__, __LINE__);
MARK_FABRICATED(im);
im->private.proto.fabricated_serial = serial;
return True;
}
Bool
_XimUnfabricateSerial(
Xim im,
unsigned long serial)
{
if (!serial)
return False;
if (!im->private.proto.fabricated_serial) {
fprintf(stderr, "%s,%d: The key event is already unfabricated.\n", __FILE__, __LINE__);
return False;
}
if (serial != im->private.proto.fabricated_serial)
fprintf(stderr, "%s,%d: Tried to unfabricate a wrong key event.\n", __FILE__, __LINE__);
im->private.proto.fabricated_serial = 0;
UNMARK_FABRICATED(im);
return True;
}
Bool
_XimIsFabricatedSerial(
Xim im,
unsigned long serial)
{
if (!serial)
return False;
return (serial == im->private.proto.fabricated_serial);
}
static void
_XimProcEvent(
Display *d,
@ -355,7 +403,7 @@ _XimProcEvent(
ev->xany.serial |= serial << 16;
ev->xany.send_event = False;
ev->xany.display = d;
MARK_FABRICATED(ic->core.im);
_XimFabricateSerial((Xim)ic->core.im, ev->xany.serial);
return;
}
@ -704,10 +752,6 @@ _XimCommitRecv(
(void)_XimRespSyncReply(ic, flag);
if (ic->private.proto.registed_filter_event
& (KEYPRESS_MASK | KEYRELEASE_MASK))
MARK_FABRICATED(im);
bzero(&ev, sizeof(ev)); /* uninitialized : found when running kterm under valgrind */
ev.type = KeyPress;
@ -719,6 +763,10 @@ _XimCommitRecv(
ev.time = 0L;
ev.serial = LastKnownRequestProcessed(im->core.display);
if (ic->private.proto.registed_filter_event
& (KEYPRESS_MASK | KEYRELEASE_MASK))
_XimFabricateSerial(im, ev.serial);
/* FIXME :
I wish there were COMMENTs (!) about the data passed around.
*/

View file

@ -149,6 +149,8 @@ typedef struct _XimProtoPrivateRec {
XimTransRegDispatcher register_dispatcher;
XimTransCallDispatcher call_dispatcher;
XPointer spec;
unsigned long fabricated_serial;
} XimProtoPrivateRec;
/*
@ -307,4 +309,19 @@ typedef struct _XicProtoPrivateRec {
#define XIM_MAXIMNAMELEN 64
#define XIM_MAXLCNAMELEN 64
Bool
_XimFabricateSerial(
Xim im,
unsigned long serial);
Bool
_XimUnfabricateSerial(
Xim im,
unsigned long serial);
Bool
_XimIsFabricatedSerial(
Xim im,
unsigned long serial);
#endif /* _XIMINTP_H */