File libX11-unmark-fabricate-key-events-with-XKeyEvent-serial.patch of Package libX11.41856

From 024d229fdf88a7755577b01b46af6ef908d599e0 Mon Sep 17 00:00:00 2001
From: Takao Fujiwara <tfujiwar@redhat.com>
Date: Wed, 31 Jan 2024 20:26:40 +0900
Subject: [PATCH] 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.

--- a/modules/im/ximcp/imDefFlt.c
+++ b/modules/im/ximcp/imDefFlt.c
@@ -142,9 +142,9 @@
 {
     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 @@
 {
     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;
     }
 
--- a/modules/im/ximcp/imDefIm.c
+++ b/modules/im/ximcp/imDefIm.c
@@ -430,6 +430,7 @@
 	return False;
 
     im->private.proto.im_window = im_window;
+    im->private.proto.fabricated_serial = 0;
     return True;
 }
 
--- a/modules/im/ximcp/imDefLkup.c
+++ b/modules/im/ximcp/imDefLkup.c
@@ -341,6 +341,54 @@
     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 @@
     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 @@
 
     (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 @@
 
     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.
     */
--- a/src/xlibi18n/XimintP.h
+++ b/src/xlibi18n/XimintP.h
@@ -149,6 +149,8 @@
     XimTransRegDispatcher	 register_dispatcher;
     XimTransCallDispatcher	 call_dispatcher;
     XPointer			 spec;
+
+    unsigned long                fabricated_serial;
 } XimProtoPrivateRec;
 
 /*
@@ -307,4 +309,19 @@
 #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 */
openSUSE Build Service is sponsored by