diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index e0254fbfbe..1299be7368 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -1400,14 +1400,19 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) X11_ReconcileKeyboardState(_this); } else if (xevent->type == MappingNotify) { - if (!videodata->keyboard.xkb_enabled) { - // Has the keyboard layout changed? - const int request = xevent->xmapping.request; + const int request = xevent->xmapping.request; + if (request == MappingPointer) { #ifdef DEBUG_XEVENTS SDL_Log("window 0x%lx: MappingNotify!", xevent->xany.window); #endif - if ((request == MappingKeyboard) || (request == MappingModifier)) { + X11_Xinput2UpdatePointerMapping(_this); + } else if (!videodata->keyboard.xkb_enabled) { + // Has the keyboard layout changed? +#ifdef DEBUG_XEVENTS + SDL_Log("window 0x%lx: MappingNotify!", xevent->xany.window); +#endif + if (request == MappingKeyboard || request == MappingModifier) { X11_XRefreshKeyboardMapping(&xevent->xmapping); } diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h index 9ee239c3f1..ea0b42aae6 100644 --- a/src/video/x11/SDL_x11sym.h +++ b/src/video/x11/SDL_x11sym.h @@ -171,6 +171,7 @@ SDL_X11_SYM(char*,XResourceManagerString,(Display *display)) SDL_X11_SYM(XrmDatabase,XrmGetStringDatabase,(char *data)) SDL_X11_SYM(void,XrmDestroyDatabase,(XrmDatabase db)) SDL_X11_SYM(Bool,XrmGetResource,(XrmDatabase db, char* str_name, char* str_class, char **str_type_return, XrmValue *)) +SDL_X11_SYM(int,XGetPointerMapping,(Display *a, unsigned char *b, unsigned int c)) #ifdef SDL_VIDEO_DRIVER_X11_XFIXES SDL_X11_MODULE(XFIXES) diff --git a/src/video/x11/SDL_x11xinput2.c b/src/video/x11/SDL_x11xinput2.c index b251d0e9cc..4a5e3aca4e 100644 --- a/src/video/x11/SDL_x11xinput2.c +++ b/src/video/x11/SDL_x11xinput2.c @@ -50,6 +50,10 @@ static Atom xinput2_rel_y_atom; static Atom xinput2_abs_x_atom; static Atom xinput2_abs_y_atom; +// Pointer button remapping table +static unsigned char *xinput2_pointer_button_map; +static int xinput2_pointer_button_map_size; + #ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO typedef struct { @@ -328,6 +332,7 @@ bool X11_InitXinput2(SDL_VideoDevice *_this) X11_XISelectEvents(data->display, DefaultRootWindow(data->display), &eventmask, 1); X11_Xinput2UpdateDevices(_this); + X11_Xinput2UpdatePointerMapping(_this); return true; #else @@ -337,6 +342,10 @@ bool X11_InitXinput2(SDL_VideoDevice *_this) void X11_QuitXinput2(SDL_VideoDevice *_this) { + SDL_free(xinput2_pointer_button_map); + xinput2_pointer_button_map = NULL; + xinput2_pointer_button_map_size = 0; + #ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO for (int i = 0; i < scrollable_device_count; ++i) { SDL_free(scrollable_devices[i].scroll_info); @@ -347,6 +356,29 @@ void X11_QuitXinput2(SDL_VideoDevice *_this) #endif } +void X11_Xinput2UpdatePointerMapping(SDL_VideoDevice *_this) +{ +#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2 + if (X11_Xinput2IsInitialized()) { + SDL_VideoData *vid = _this->internal; + + SDL_free(xinput2_pointer_button_map); + xinput2_pointer_button_map = NULL; + xinput2_pointer_button_map_size = 0; + + xinput2_pointer_button_map_size = X11_XGetPointerMapping(vid->display, NULL, 0); + if (xinput2_pointer_button_map_size) { + xinput2_pointer_button_map = SDL_calloc(xinput2_pointer_button_map_size, sizeof(unsigned char)); + if (xinput2_pointer_button_map) { + xinput2_pointer_button_map_size = X11_XGetPointerMapping(vid->display, xinput2_pointer_button_map, xinput2_pointer_button_map_size); + } else { + xinput2_pointer_button_map_size = 0; + } + } + } +#endif +} + #ifdef SDL_VIDEO_DRIVER_X11_XINPUT2 // xi2 device went away? take it out of the list. 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) { const XIDeviceEvent *xev = (const XIDeviceEvent *)cookie->data; X11_PenHandle *pen = X11_FindPenByDeviceID(xev->sourceid); - const int button = xev->detail; + int button = xev->detail; const bool down = (cookie->evtype == XI_ButtonPress); #if defined(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO) || defined(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH) bool pointer_emulated = (xev->flags & XIPointerEmulated) != 0; @@ -587,6 +619,13 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie) SDL_WindowData *windowdata = xinput2_get_sdlwindowdata(videodata, xev->event); int x_ticks = 0, y_ticks = 0; + // Slave pointer devices don't have button remapping applied automatically, so do it manually. + if (xev->deviceid != videodata->xinput_master_pointer_device) { + if (button <= xinput2_pointer_button_map_size) { + button = xinput2_pointer_button_map[button - 1]; + } + } + /* Discard wheel events from "Master" devices to avoid duplicates, * as coarse wheel events are stateless and can't be deduplicated. * diff --git a/src/video/x11/SDL_x11xinput2.h b/src/video/x11/SDL_x11xinput2.h index 91c33aa654..f05e96cd1e 100644 --- a/src/video/x11/SDL_x11xinput2.h +++ b/src/video/x11/SDL_x11xinput2.h @@ -40,5 +40,6 @@ extern void X11_Xinput2GrabTouch(SDL_VideoDevice *_this, SDL_Window *window); extern void X11_Xinput2UngrabTouch(SDL_VideoDevice *_this, SDL_Window *window); extern bool X11_Xinput2SelectMouseAndKeyboard(SDL_VideoDevice *_this, SDL_Window *window); extern void X11_Xinput2UpdateDevices(SDL_VideoDevice *_this); +extern void X11_Xinput2UpdatePointerMapping(SDL_VideoDevice *_this); #endif // SDL_x11xinput2_h_