Skip to content

Commit 733335e

Browse files
committed
x11: Apply remapping to XInput2 mouse button events from slave devices
Slave pointer devices report raw button values, while the master pointer device reports button values with remapping applied. Manually apply the remapping table to slave device buttons to eliminate multiple button events from one press, and allow button remapping to function when relative mode is active.
1 parent 4363582 commit 733335e

File tree

4 files changed

+51
-5
lines changed

4 files changed

+51
-5
lines changed

src/video/x11/SDL_x11events.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,14 +1400,19 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
14001400

14011401
X11_ReconcileKeyboardState(_this);
14021402
} else if (xevent->type == MappingNotify) {
1403-
if (!videodata->keyboard.xkb_enabled) {
1404-
// Has the keyboard layout changed?
1405-
const int request = xevent->xmapping.request;
1403+
const int request = xevent->xmapping.request;
14061404

1405+
if (request == MappingPointer) {
1406+
#ifdef DEBUG_XEVENTS
1407+
SDL_Log("window 0x%lx: MappingNotify!", xevent->xany.window);
1408+
#endif
1409+
X11_Xinput2UpdatePointerMapping(_this);
1410+
} else if (!videodata->keyboard.xkb_enabled) {
1411+
// Has the keyboard layout changed?
14071412
#ifdef DEBUG_XEVENTS
14081413
SDL_Log("window 0x%lx: MappingNotify!", xevent->xany.window);
14091414
#endif
1410-
if ((request == MappingKeyboard) || (request == MappingModifier)) {
1415+
if (request == MappingKeyboard || request == MappingModifier) {
14111416
X11_XRefreshKeyboardMapping(&xevent->xmapping);
14121417
}
14131418

src/video/x11/SDL_x11sym.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ SDL_X11_SYM(char*,XResourceManagerString,(Display *display))
171171
SDL_X11_SYM(XrmDatabase,XrmGetStringDatabase,(char *data))
172172
SDL_X11_SYM(void,XrmDestroyDatabase,(XrmDatabase db))
173173
SDL_X11_SYM(Bool,XrmGetResource,(XrmDatabase db, char* str_name, char* str_class, char **str_type_return, XrmValue *))
174+
SDL_X11_SYM(int,XGetPointerMapping,(Display *a, unsigned char *b, unsigned int c))
174175

175176
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
176177
SDL_X11_MODULE(XFIXES)

src/video/x11/SDL_x11xinput2.c

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ static Atom xinput2_rel_y_atom;
5050
static Atom xinput2_abs_x_atom;
5151
static Atom xinput2_abs_y_atom;
5252

53+
// Pointer button remapping table
54+
static unsigned char *xinput2_pointer_button_map;
55+
static int xinput2_pointer_button_map_size;
56+
5357
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO
5458
typedef struct
5559
{
@@ -328,6 +332,7 @@ bool X11_InitXinput2(SDL_VideoDevice *_this)
328332
X11_XISelectEvents(data->display, DefaultRootWindow(data->display), &eventmask, 1);
329333

330334
X11_Xinput2UpdateDevices(_this);
335+
X11_Xinput2UpdatePointerMapping(_this);
331336

332337
return true;
333338
#else
@@ -337,6 +342,10 @@ bool X11_InitXinput2(SDL_VideoDevice *_this)
337342

338343
void X11_QuitXinput2(SDL_VideoDevice *_this)
339344
{
345+
SDL_free(xinput2_pointer_button_map);
346+
xinput2_pointer_button_map = NULL;
347+
xinput2_pointer_button_map_size = 0;
348+
340349
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO
341350
for (int i = 0; i < scrollable_device_count; ++i) {
342351
SDL_free(scrollable_devices[i].scroll_info);
@@ -347,6 +356,29 @@ void X11_QuitXinput2(SDL_VideoDevice *_this)
347356
#endif
348357
}
349358

359+
void X11_Xinput2UpdatePointerMapping(SDL_VideoDevice *_this)
360+
{
361+
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
362+
if (X11_Xinput2IsInitialized()) {
363+
SDL_VideoData *vid = _this->internal;
364+
365+
SDL_free(xinput2_pointer_button_map);
366+
xinput2_pointer_button_map = NULL;
367+
xinput2_pointer_button_map_size = 0;
368+
369+
xinput2_pointer_button_map_size = X11_XGetPointerMapping(vid->display, NULL, 0);
370+
if (xinput2_pointer_button_map_size) {
371+
xinput2_pointer_button_map = SDL_calloc(xinput2_pointer_button_map_size, sizeof(unsigned char));
372+
if (xinput2_pointer_button_map) {
373+
xinput2_pointer_button_map_size = X11_XGetPointerMapping(vid->display, xinput2_pointer_button_map, xinput2_pointer_button_map_size);
374+
} else {
375+
xinput2_pointer_button_map_size = 0;
376+
}
377+
}
378+
}
379+
#endif
380+
}
381+
350382
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
351383
// xi2 device went away? take it out of the list.
352384
static void xinput2_remove_device_info(SDL_VideoData *videodata, const int device_id)
@@ -562,7 +594,7 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
562594
{
563595
const XIDeviceEvent *xev = (const XIDeviceEvent *)cookie->data;
564596
X11_PenHandle *pen = X11_FindPenByDeviceID(xev->sourceid);
565-
const int button = xev->detail;
597+
int button = xev->detail;
566598
const bool down = (cookie->evtype == XI_ButtonPress);
567599
#if defined(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO) || defined(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH)
568600
bool pointer_emulated = (xev->flags & XIPointerEmulated) != 0;
@@ -587,6 +619,13 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
587619
SDL_WindowData *windowdata = xinput2_get_sdlwindowdata(videodata, xev->event);
588620
int x_ticks = 0, y_ticks = 0;
589621

622+
// Slave pointer devices don't have button remapping applied automatically, so do it manually.
623+
if (xev->deviceid != videodata->xinput_master_pointer_device) {
624+
if (button <= xinput2_pointer_button_map_size) {
625+
button = xinput2_pointer_button_map[button - 1];
626+
}
627+
}
628+
590629
/* Discard wheel events from "Master" devices to avoid duplicates,
591630
* as coarse wheel events are stateless and can't be deduplicated.
592631
*

src/video/x11/SDL_x11xinput2.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,6 @@ extern void X11_Xinput2GrabTouch(SDL_VideoDevice *_this, SDL_Window *window);
4040
extern void X11_Xinput2UngrabTouch(SDL_VideoDevice *_this, SDL_Window *window);
4141
extern bool X11_Xinput2SelectMouseAndKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
4242
extern void X11_Xinput2UpdateDevices(SDL_VideoDevice *_this);
43+
extern void X11_Xinput2UpdatePointerMapping(SDL_VideoDevice *_this);
4344

4445
#endif // SDL_x11xinput2_h_

0 commit comments

Comments
 (0)