Added support for using XTest to warp the mouse

This commit is contained in:
Sam Lantinga 2025-03-05 12:39:06 -08:00
parent fae324dacb
commit 794ff283e2
10 changed files with 159 additions and 6 deletions

View file

@ -357,6 +357,7 @@ dep_option(SDL_X11_XRANDR "Enable Xrandr support" "${SDL_X11_XRANDR_DEF
dep_option(SDL_X11_XSCRNSAVER "Enable Xscrnsaver support" ON SDL_X11 OFF) dep_option(SDL_X11_XSCRNSAVER "Enable Xscrnsaver support" ON SDL_X11 OFF)
dep_option(SDL_X11_XSHAPE "Enable XShape support" ON SDL_X11 OFF) dep_option(SDL_X11_XSHAPE "Enable XShape support" ON SDL_X11 OFF)
dep_option(SDL_X11_XSYNC "Enable Xsync support" ON SDL_X11 OFF) dep_option(SDL_X11_XSYNC "Enable Xsync support" ON SDL_X11 OFF)
dep_option(SDL_X11_XTEST "Enable XTest support" ON SDL_X11 OFF)
dep_option(SDL_WAYLAND "Use Wayland video driver" ${UNIX_SYS} "SDL_VIDEO" OFF) dep_option(SDL_WAYLAND "Use Wayland video driver" ${UNIX_SYS} "SDL_VIDEO" OFF)
dep_option(SDL_WAYLAND_SHARED "Dynamically load Wayland support" ON "SDL_WAYLAND;SDL_DEPS_SHARED" OFF) dep_option(SDL_WAYLAND_SHARED "Dynamically load Wayland support" ON "SDL_WAYLAND;SDL_DEPS_SHARED" OFF)
dep_option(SDL_WAYLAND_LIBDECOR "Use client-side window decorations on Wayland" ON "SDL_WAYLAND" OFF) dep_option(SDL_WAYLAND_LIBDECOR "Use client-side window decorations on Wayland" ON "SDL_WAYLAND" OFF)

View file

@ -274,10 +274,11 @@ macro(CheckX11)
set(Xrandr_PKG_CONFIG_SPEC xrandr) set(Xrandr_PKG_CONFIG_SPEC xrandr)
set(Xrender_PKG_CONFIG_SPEC xrender) set(Xrender_PKG_CONFIG_SPEC xrender)
set(Xss_PKG_CONFIG_SPEC xscrnsaver) set(Xss_PKG_CONFIG_SPEC xscrnsaver)
set(Xtst_PKG_CONFIG_SPEC xtst)
find_package(X11) find_package(X11)
foreach(_LIB X11 Xext Xcursor Xi Xfixes Xrandr Xrender Xss) foreach(_LIB X11 Xext Xcursor Xi Xfixes Xrandr Xrender Xss Xtst)
get_filename_component(_libdir "${X11_${_LIB}_LIB}" DIRECTORY) get_filename_component(_libdir "${X11_${_LIB}_LIB}" DIRECTORY)
FindLibraryAndSONAME("${_LIB}" LIBDIRS ${_libdir}) FindLibraryAndSONAME("${_LIB}" LIBDIRS ${_libdir})
endforeach() endforeach()
@ -310,6 +311,7 @@ macro(CheckX11)
find_file(HAVE_XSYNC_H NAMES "X11/extensions/sync.h" HINTS "${X11_INCLUDEDIR}") find_file(HAVE_XSYNC_H NAMES "X11/extensions/sync.h" HINTS "${X11_INCLUDEDIR}")
find_file(HAVE_XSS_H NAMES "X11/extensions/scrnsaver.h" HINTS "${X11_INCLUDEDIR}") find_file(HAVE_XSS_H NAMES "X11/extensions/scrnsaver.h" HINTS "${X11_INCLUDEDIR}")
find_file(HAVE_XSHAPE_H NAMES "X11/extensions/shape.h" HINTS "${X11_INCLUDEDIR}") find_file(HAVE_XSHAPE_H NAMES "X11/extensions/shape.h" HINTS "${X11_INCLUDEDIR}")
find_file(HAVE_XTEST_H NAMES "X11/extensions/XTest.h" HINTS "${X11_INCLUDEDIR}")
find_file(HAVE_XDBE_H NAMES "X11/extensions/Xdbe.h" HINTS "${X11_INCLUDEDIR}") find_file(HAVE_XDBE_H NAMES "X11/extensions/Xdbe.h" HINTS "${X11_INCLUDEDIR}")
find_file(HAVE_XEXT_H NAMES "X11/extensions/Xext.h" HINTS "${X11_INCLUDEDIR}") find_file(HAVE_XEXT_H NAMES "X11/extensions/Xext.h" HINTS "${X11_INCLUDEDIR}")
@ -472,6 +474,16 @@ macro(CheckX11)
set(SDL_VIDEO_DRIVER_X11_XSHAPE 1) set(SDL_VIDEO_DRIVER_X11_XSHAPE 1)
set(HAVE_X11_XSHAPE TRUE) set(HAVE_X11_XSHAPE TRUE)
endif() endif()
if(SDL_X11_XTEST AND HAVE_XTEST_H AND XTST_LIB)
if(HAVE_X11_SHARED)
set(SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST "\"${XTST_LIB_SONAME}\"")
else()
sdl_link_dependency(xtst LIBS X11::Xtst CMAKE_MODULE X11 PKG_CONFIG_SPECS ${Xtst_PKG_CONFIG_SPEC})
endif()
set(SDL_VIDEO_DRIVER_X11_XTEST 1)
set(HAVE_X11_XTEST TRUE)
endif()
endif() endif()
endif() endif()
if(NOT HAVE_X11) if(NOT HAVE_X11)

View file

@ -17,7 +17,7 @@ Ubuntu 18.04, all available features enabled:
sudo apt-get install build-essential git make \ sudo apt-get install build-essential git make \
pkg-config cmake ninja-build gnome-desktop-testing libasound2-dev libpulse-dev \ pkg-config cmake ninja-build gnome-desktop-testing libasound2-dev libpulse-dev \
libaudio-dev libjack-dev libsndio-dev libx11-dev libxext-dev \ libaudio-dev libjack-dev libsndio-dev libx11-dev libxext-dev \
libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev \ libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libxtst-dev \
libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \ libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \
libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev
@ -46,7 +46,7 @@ openSUSE Tumbleweed:
libgbm-devel pipewire-devel libpulse-devel sndio-devel Mesa-libEGL-devel libgbm-devel pipewire-devel libpulse-devel sndio-devel Mesa-libEGL-devel
Arch: Arch:
sudo pacman -S alsa-lib cmake hidapi ibus jack libdecor libgl libpulse libusb libx11 libxcursor libxext libxinerama libxkbcommon libxrandr libxrender libxss mesa ninja pipewire sndio vulkan-driver vulkan-headers wayland wayland-protocols sudo pacman -S alsa-lib cmake hidapi ibus jack libdecor libgl libpulse libusb libx11 libxcursor libxext libxinerama libxkbcommon libxrandr libxrender libxss libxtst mesa ninja pipewire sndio vulkan-driver vulkan-headers wayland wayland-protocols
Joystick does not work Joystick does not work

View file

@ -390,6 +390,7 @@
#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 @SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2@ #cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 @SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2@
#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR @SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR@ #cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR @SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR@
#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS @SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS@ #cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS @SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS@
#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST @SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST@
#cmakedefine SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM 1 #cmakedefine SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM 1
#cmakedefine SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 1 #cmakedefine SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 1
#cmakedefine SDL_VIDEO_DRIVER_X11_XCURSOR 1 #cmakedefine SDL_VIDEO_DRIVER_X11_XCURSOR 1
@ -401,6 +402,7 @@
#cmakedefine SDL_VIDEO_DRIVER_X11_XSCRNSAVER 1 #cmakedefine SDL_VIDEO_DRIVER_X11_XSCRNSAVER 1
#cmakedefine SDL_VIDEO_DRIVER_X11_XSHAPE 1 #cmakedefine SDL_VIDEO_DRIVER_X11_XSHAPE 1
#cmakedefine SDL_VIDEO_DRIVER_X11_XSYNC 1 #cmakedefine SDL_VIDEO_DRIVER_X11_XSYNC 1
#cmakedefine SDL_VIDEO_DRIVER_X11_XTEST 1
#cmakedefine SDL_VIDEO_DRIVER_QNX 1 #cmakedefine SDL_VIDEO_DRIVER_QNX 1
#cmakedefine SDL_VIDEO_RENDER_D3D 1 #cmakedefine SDL_VIDEO_RENDER_D3D 1

View file

@ -56,6 +56,9 @@ typedef struct
#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS #ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS
#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS NULL #define SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS NULL
#endif #endif
#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST
#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST NULL
#endif
static x11dynlib x11libs[] = { static x11dynlib x11libs[] = {
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC }, { NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC },
@ -64,7 +67,8 @@ static x11dynlib x11libs[] = {
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 }, { NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 },
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XFIXES }, { NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XFIXES },
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR }, { NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR },
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS } { NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS },
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST }
}; };
static void *X11_GetSym(const char *fnname, int *pHasModule) static void *X11_GetSym(const char *fnname, int *pHasModule)

View file

@ -26,6 +26,7 @@
#include "SDL_x11video.h" #include "SDL_x11video.h"
#include "SDL_x11mouse.h" #include "SDL_x11mouse.h"
#include "SDL_x11xinput2.h" #include "SDL_x11xinput2.h"
#include "SDL_x11xtest.h"
#include "../SDL_video_c.h" #include "../SDL_video_c.h"
#include "../../events/SDL_mouse_c.h" #include "../../events/SDL_mouse_c.h"
@ -367,6 +368,10 @@ static bool X11_WarpMouse(SDL_Window *window, float x, float y)
{ {
SDL_WindowData *data = window->internal; SDL_WindowData *data = window->internal;
if (X11_WarpMouseXTest(SDL_GetVideoDevice(), window, x, y)) {
return true;
}
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES #ifdef SDL_VIDEO_DRIVER_X11_XFIXES
// If we have no barrier, we need to warp // If we have no barrier, we need to warp
if (data->pointer_barrier_active == false) { if (data->pointer_barrier_active == false) {
@ -380,6 +385,10 @@ static bool X11_WarpMouse(SDL_Window *window, float x, float y)
static bool X11_WarpMouseGlobal(float x, float y) static bool X11_WarpMouseGlobal(float x, float y)
{ {
if (X11_WarpMouseXTest(SDL_GetVideoDevice(), NULL, x, y)) {
return true;
}
X11_WarpMouseInternal(DefaultRootWindow(GetDisplay()), x, y); X11_WarpMouseInternal(DefaultRootWindow(GetDisplay()), x, y);
return true; return true;
} }

View file

@ -182,6 +182,12 @@ SDL_X11_SYM(Status, XSyncDestroyCounter, (Display* a, XSyncCounter b), (a, b), r
SDL_X11_SYM(Status, XSyncSetCounter, (Display* a, XSyncCounter b, XSyncValue c), (a, b, c), return) SDL_X11_SYM(Status, XSyncSetCounter, (Display* a, XSyncCounter b, XSyncValue c), (a, b, c), return)
#endif #endif
#ifdef SDL_VIDEO_DRIVER_X11_XTEST
SDL_X11_MODULE(XTEST)
SDL_X11_SYM(Status, XTestQueryExtension, (Display* a, int* b, int* c), (a, b, c), return)
SDL_X11_SYM(int, XTestFakeMotionEvent, (Display* a, int b, int c, int d, unsigned long e), (a, b, c, d, e), return)
#endif
#ifdef SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS #ifdef SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
SDL_X11_SYM(Bool,XGetEventData,(Display* a,XGenericEventCookie* b),(a,b),return) SDL_X11_SYM(Bool,XGetEventData,(Display* a,XGenericEventCookie* b),(a,b),return)
SDL_X11_SYM(void,XFreeEventData,(Display* a,XGenericEventCookie* b),(a,b),) SDL_X11_SYM(void,XFreeEventData,(Display* a,XGenericEventCookie* b),(a,b),)

View file

@ -39,6 +39,7 @@
#include "SDL_x11messagebox.h" #include "SDL_x11messagebox.h"
#include "SDL_x11shape.h" #include "SDL_x11shape.h"
#include "SDL_x11xsync.h" #include "SDL_x11xsync.h"
#include "SDL_x11xtest.h"
#ifdef SDL_VIDEO_OPENGL_EGL #ifdef SDL_VIDEO_OPENGL_EGL
#include "SDL_x11opengles.h" #include "SDL_x11opengles.h"
@ -443,13 +444,17 @@ static bool X11_VideoInit(SDL_VideoDevice *_this)
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES #ifdef SDL_VIDEO_DRIVER_X11_XFIXES
X11_InitXfixes(_this); X11_InitXfixes(_this);
#endif // SDL_VIDEO_DRIVER_X11_XFIXES #endif
X11_InitXsettings(_this); X11_InitXsettings(_this);
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC #ifdef SDL_VIDEO_DRIVER_X11_XSYNC
X11_InitXsync(_this); X11_InitXsync(_this);
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */ #endif
#ifdef SDL_VIDEO_DRIVER_X11_XTEST
X11_InitXTest(_this);
#endif
#ifndef X_HAVE_UTF8_STRING #ifndef X_HAVE_UTF8_STRING
#warning X server does not support UTF8_STRING, a feature introduced in 2000! This is likely to become a hard error in a future libSDL3. #warning X server does not support UTF8_STRING, a feature introduced in 2000! This is likely to become a hard error in a future libSDL3.

View file

@ -0,0 +1,83 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_DRIVER_X11)
#include "SDL_x11video.h"
#include "SDL_x11xtest.h"
static bool xtest_initialized = false;
void X11_InitXTest(SDL_VideoDevice *_this)
{
#ifdef SDL_VIDEO_DRIVER_X11_XTEST
Display *display = _this->internal->display;
int event, error;
int opcode;
if (!SDL_X11_HAVE_XTEST ||
!X11_XQueryExtension(display, "XTEST", &opcode, &event, &error)) {
return;
}
xtest_initialized = true;
#endif
}
bool X11_XTestIsInitialized(void)
{
return xtest_initialized;
}
bool X11_WarpMouseXTest(SDL_VideoDevice *_this, SDL_Window *window, float x, float y)
{
#ifdef SDL_VIDEO_DRIVER_X11_XTEST
if (!X11_XTestIsInitialized()) {
return false;
}
Display *display = _this->internal->display;
SDL_DisplayData *displaydata = window ? SDL_GetDisplayDriverDataForWindow(window) : SDL_GetDisplayDriverData(SDL_GetPrimaryDisplay());
if (!displaydata) {
return false;
}
int motion_x = (int)SDL_roundf(x);
int motion_y = (int)SDL_roundf(y);
if (window) {
motion_x += window->x;
motion_y += window->y;
}
if (!X11_XTestFakeMotionEvent(display, displaydata->screen, motion_x, motion_y, CurrentTime)) {
return false;
}
X11_XSync(display, False);
return true;
#else
return false;
#endif
}
#endif // SDL_VIDEO_DRIVER_X11

View file

@ -0,0 +1,31 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_x11xtest_h_
#define SDL_x11xtest_h_
extern void X11_InitXTest(SDL_VideoDevice *_this);
extern bool X11_XTestIsInitialized(void);
extern bool X11_WarpMouseXTest(SDL_VideoDevice *_this, SDL_Window *window, float x, float y);
#endif // SDL_x11xtest_h_