Skip to content

Instantly share code, notes, and snippets.

@fischman
Created October 29, 2023 17:54
Show Gist options
  • Save fischman/c701731134f1aec37077eab12ee3d48b to your computer and use it in GitHub Desktop.
Save fischman/c701731134f1aec37077eab12ee3d48b to your computer and use it in GitHub Desktop.
commit e7e6c21a75e799be2e47fc2cc3ef0405dd88a717
Author: Ami Fischman <ami@fischman.org>
Date: Sun Oct 29 10:54:17 2023 -0700
cmd_meta: use XTEST to send fake key event instead of XSendEvent, which is ignored by applications linked with XInput2
diff --git a/src/actions.c b/src/actions.c
index e65ca0c..1b7d0e2 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -17,34 +17,33 @@
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*/
-
-#include <unistd.h>
-#include <ctype.h>
-#include <sys/wait.h>
+
+#include <X11/Xproto.h>
#include <X11/keysym.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
#include <string.h>
#include <strings.h>
+#include <sys/wait.h>
#include <time.h>
-#include <errno.h>
-#include <signal.h>
-#include <limits.h>
-#include <X11/Xproto.h>
+#include <unistd.h>
#include "ratpoison.h"
#ifdef HAVE_LIBXTST
-# include <X11/extensions/XTest.h>
+#include <X11/XKBlib.h>
+#include <X11/extensions/XTest.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
+#include <sys/ioctl.h>
#endif
-
-
-
/* arg_REST and arg_SHELLCMD eat the rest of the input. */
-enum argtype {
+enum argtype
+{
arg_REST,
arg_NUMBER,
arg_STRING,
@@ -1358,22 +1357,70 @@ cmd_definekey (int interactive UNUSED, struct cmdarg **args)
return cmdret_new (RET_SUCCESS, NULL);
}
-cmdret *
-cmd_source (int interactive UNUSED, struct cmdarg **args)
-{
+cmdret *cmd_source(int interactive UNUSED, struct cmdarg **args) {
FILE *fileptr;
- if ((fileptr = fopen (ARG_STRING(0), "r")) == NULL)
- return cmdret_new (RET_FAILURE, "source: %s : %s", ARG_STRING(0), strerror(errno));
- else
+ if ((fileptr = fopen(ARG_STRING(0), "r")) == NULL)
+ return cmdret_new(RET_FAILURE, "source: %s : %s", ARG_STRING(0),
+ strerror(errno));
+ else {
+ set_close_on_exec(fileno(fileptr));
+ read_rc_file(fileptr);
+ fclose(fileptr);
+ }
+
+ return cmdret_new(RET_SUCCESS, NULL);
+}
+
+#ifdef HAVE_LIBXTST
+static void
+_send_xkeyevent_via_xtest (XEvent *event)
+{
+ for (int is_press = 1; is_press >= 0; --is_press)
{
- set_close_on_exec (fileno (fileptr));
- read_rc_file (fileptr);
- fclose (fileptr);
- }
+ XkbStateRec state;
+ XkbGetState (dpy, XkbUseCoreKbd, &state);
- return cmdret_new (RET_SUCCESS, NULL);
+ long event_mask = event->xkey.state;
+ PRINT_ERROR (
+ ("AMI: mask is %ld, is_press is %d\n", event_mask, is_press));
+ if (event_mask)
+ {
+ XModifierKeymap *modifiers = XGetModifierMapping (dpy);
+ int mod_index, mod_key, keycode;
+ for (mod_index = ShiftMapIndex; mod_index <= Mod5MapIndex;
+ ++mod_index)
+ {
+ if (event_mask & (1 << mod_index))
+ {
+ PRINT_ERROR (("AMI: mask matched index %d\n", mod_index));
+ for (mod_key = 0; mod_key < modifiers->max_keypermod;
+ ++mod_key)
+ {
+ keycode
+ = modifiers
+ ->modifiermap[mod_index
+ * modifiers->max_keypermod
+ + mod_key];
+ if (keycode)
+ {
+ PRINT_ERROR (
+ ("AMI: sending modifier code %d\n", keycode));
+ XTestFakeKeyEvent (dpy, keycode, is_press,
+ CurrentTime);
+ XSync (dpy, False);
+ break;
+ }
+ }
+ }
+ }
+ XFreeModifiermap (modifiers);
+ }
+ PRINT_ERROR (("AMI: sending keycode %d\n", event->xkey.keycode));
+ XTestFakeKeyEvent (dpy, event->xkey.keycode, is_press, CurrentTime);
+ }
}
+#endif
cmdret *
cmd_meta (int interactive UNUSED, struct cmdarg **args)
@@ -1385,19 +1432,19 @@ cmd_meta (int interactive UNUSED, struct cmdarg **args)
garbage time value trips up some clients */
ev.xkey.time = CurrentTime;
- if (current_window() == NULL)
+ if (current_window () == NULL)
return cmdret_new (RET_FAILURE, NULL);
ev.xkey.type = KeyPress;
ev.xkey.display = dpy;
- ev.xkey.window = current_window()->w;
+ ev.xkey.window = current_window ()->w;
if (args[0])
{
struct rp_key key;
cmdret *ret;
- ret = parse_keydesc (ARG_STRING(0), &key);
+ ret = parse_keydesc (ARG_STRING (0), &key);
if (ret != NULL)
return ret;
@@ -1413,7 +1460,13 @@ cmd_meta (int interactive UNUSED, struct cmdarg **args)
ev.xkey.keycode = XKeysymToKeycode (dpy, prefix_key.sym);
}
- XSendEvent (dpy, current_window()->w, False, KeyPressMask, &ev);
+#ifdef HAVE_LIBXTST
+ ungrab_keys_all_wins ();
+ _send_xkeyevent_via_xtest (&ev);
+ grab_keys_all_wins ();
+#else
+ XSendEvent (dpy, current_window ()->w, False, KeyPressMask, &ev);
+#endif
XSync (dpy, False);
return cmdret_new (RET_SUCCESS, NULL);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment