From a66d7d74a4f2d85f2a774b0e8b673d928fc3290e Mon Sep 17 00:00:00 2001 From: maxjivi05 Date: Sat, 24 Oct 2026 08:51:08 -0400 Subject: [PATCH] fix: Steam Input mouse clicks, scrolling and pointer moves reach games again --- tools/linuxfs/preload/rptouch.c | 11 +++++++++-- tools/tests/test_venc_emulator.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/tools/linuxfs/preload/rptouch.c b/tools/linuxfs/preload/rptouch.c index 3d6f584ed..7d39f286e 100644 --- a/tools/linuxfs/preload/rptouch.c +++ b/tools/linuxfs/preload/rptouch.c @@ -51,9 +51,16 @@ static void rt_send(void *dpy, uint32_t action) { } } +static void *rt_xtst(const char *name) { + void *fn = dlsym(RTLD_NEXT, name); + if (fn) return fn; + void *lib = dlopen("libXtst.so.6", RTLD_LAZY | RTLD_NOLOAD); + return lib ? dlsym(lib, name) : NULL; +} + int XTestFakeMotionEvent(void *dpy, int screen, int x, int y, unsigned long delay) { static int (*real)(void *, int, int, int, unsigned long); - if (!real) real = (int (*)(void *, int, int, int, unsigned long))dlsym(RTLD_NEXT, "XTestFakeMotionEvent"); + if (!real) real = (int (*)(void *, int, int, int, unsigned long))rt_xtst("XTestFakeMotionEvent"); if (rt_enabled()) { pthread_mutex_lock(&rt_lock); rt_x = x; @@ -69,7 +76,7 @@ int XTestFakeMotionEvent(void *dpy, int screen, int x, int y, unsigned long dela int XTestFakeButtonEvent(void *dpy, unsigned int button, int press, unsigned long delay) { static int (*real)(void *, unsigned int, int, unsigned long); - if (!real) real = (int (*)(void *, unsigned int, int, unsigned long))dlsym(RTLD_NEXT, "XTestFakeButtonEvent"); + if (!real) real = (int (*)(void *, unsigned int, int, unsigned long))rt_xtst("XTestFakeButtonEvent"); if (button == 1) { pthread_mutex_lock(&rt_lock); int handled = 0; diff --git a/tools/tests/test_venc_emulator.py b/tools/tests/test_venc_emulator.py index 9fcf1f10d..416f6b61b 100644 --- a/tools/tests/test_venc_emulator.py +++ b/tools/tests/test_venc_emulator.py @@ -223,5 +223,35 @@ class VencEmulatorTest(unittest.TestCase): self.assertEqual(server.touches, [(0, 65535, 32767), (1, 32767, 0), (2, 32767, 0)]) + def test_xtest_calls_from_a_locally_loaded_library_still_reach_libxtst(self): + with tempfile.TemporaryDirectory() as tmp: + tmp = Path(tmp) + (tmp / 'xtst.c').write_text( + 'int XTestFakeButtonEvent(void *d, unsigned b, int p, unsigned long t) { return 7; }\n' + 'int XTestFakeMotionEvent(void *d, int s, int x, int y, unsigned long t) { return 7; }\n') + (tmp / 'ui.c').write_text( + 'int XTestFakeButtonEvent(void *, unsigned, int, unsigned long);\n' + 'int XTestFakeMotionEvent(void *, int, int, int, unsigned long);\n' + 'int ui_click(void) { return XTestFakeButtonEvent(0, 1, 1, 0) + XTestFakeButtonEvent(0, 3, 0, 0); }\n' + 'int ui_move(void) { return XTestFakeMotionEvent(0, 0, 10, 20, 0); }\n') + (tmp / 'main.c').write_text( + '#include \n#include \n' + 'int main(int argc, char **argv) {\n' + ' void *ui = dlopen(argv[1], RTLD_NOW | RTLD_LOCAL);\n' + ' if (!ui) return 2;\n' + ' int (*click)(void) = dlsym(ui, "ui_click"), (*move)(void) = dlsym(ui, "ui_move");\n' + ' printf("%d %d\\n", click(), move());\n' + ' return click() == 14 && move() == 7 ? 0 : 1;\n' + '}\n') + run = lambda *a: subprocess.run(['cc', *a], check=True, cwd=tmp) + run('-shared', '-fPIC', '-Wl,-soname,libXtst.so.6', '-o', 'libXtst.so.6', 'xtst.c') + run('-shared', '-fPIC', '-o', 'libui.so', 'ui.c', '-L.', '-l:libXtst.so.6', "-Wl,-rpath,$ORIGIN") + run('-shared', '-fPIC', '-pthread', '-o', 'libhook.so', str(VENC), str(TOUCH), '-ldl') + run('-o', 'main', 'main.c', '-ldl') + done = subprocess.run([str(tmp / 'main'), str(tmp / 'libui.so')], + env=dict(os.environ, LD_PRELOAD=str(tmp / 'libhook.so')), + capture_output=True, text=True, timeout=20) + self.assertEqual(done.returncode, 0, done.stdout + done.stderr) + if __name__ == '__main__': unittest.main()