x11: Add keymap support

XkbKeycodeToKeySym is replaced with XkbLookupKeySym, which can take the modifier states. The associated cmake check has been renamed for consistency.

Only the XKB path is currently handled. The deprecated XKeycodeToKeysym path is TODO.
This commit is contained in:
Frank Praznik 2024-06-22 19:09:50 -04:00
parent c874a78ffb
commit 974bbea20b
9 changed files with 87 additions and 72 deletions

View File

@ -371,7 +371,7 @@ macro(CheckX11)
set(SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 1) set(SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 1)
endif() endif()
check_symbol_exists(XkbKeycodeToKeysym "X11/Xlib.h;X11/XKBlib.h" SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM) check_symbol_exists(XkbLookupKeySym "X11/Xlib.h;X11/XKBlib.h" SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM)
if(SDL_X11_XCURSOR AND HAVE_XCURSOR_H AND XCURSOR_LIB) if(SDL_X11_XCURSOR AND HAVE_XCURSOR_H AND XCURSOR_LIB)
set(HAVE_X11_XCURSOR TRUE) set(HAVE_X11_XCURSOR TRUE)

View File

@ -400,7 +400,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_HAS_XKBKEYCODETOKEYSYM @SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM@ #cmakedefine SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM @SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM@
#cmakedefine SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS @SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS@ #cmakedefine SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS @SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS@
#cmakedefine SDL_VIDEO_DRIVER_X11_XCURSOR @SDL_VIDEO_DRIVER_X11_XCURSOR@ #cmakedefine SDL_VIDEO_DRIVER_X11_XCURSOR @SDL_VIDEO_DRIVER_X11_XCURSOR@
#cmakedefine SDL_VIDEO_DRIVER_X11_XDBE @SDL_VIDEO_DRIVER_X11_XDBE@ #cmakedefine SDL_VIDEO_DRIVER_X11_XDBE @SDL_VIDEO_DRIVER_X11_XDBE@

View File

@ -194,7 +194,7 @@
#define SDL_VIDEO_DRIVER_X11_XRANDR 1 #define SDL_VIDEO_DRIVER_X11_XRANDR 1
#define SDL_VIDEO_DRIVER_X11_XSCRNSAVER 1 #define SDL_VIDEO_DRIVER_X11_XSCRNSAVER 1
#define SDL_VIDEO_DRIVER_X11_XSHAPE 1 #define SDL_VIDEO_DRIVER_X11_XSHAPE 1
#define SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM 1 #define SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM 1
#ifdef MAC_OS_X_VERSION_10_8 #ifdef MAC_OS_X_VERSION_10_8
/* /*

View File

@ -28,7 +28,7 @@
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <X11/Xresource.h> #include <X11/Xresource.h>
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM #ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
#include <X11/XKBlib.h> #include <X11/XKBlib.h>
#endif #endif

View File

@ -1131,6 +1131,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
printf("window %p: KeymapNotify!\n", data); printf("window %p: KeymapNotify!\n", data);
#endif #endif
if (SDL_GetKeyboardFocus() != NULL) { if (SDL_GetKeyboardFocus() != NULL) {
X11_UpdateKeymap(_this, SDL_TRUE);
X11_ReconcileKeyboardState(_this); X11_ReconcileKeyboardState(_this);
} }
} else if (xevent->type == MappingNotify) { } else if (xevent->type == MappingNotify) {

View File

@ -72,7 +72,7 @@ static SDL_bool X11_ScancodeIsRemappable(SDL_Scancode scancode)
/* This function only correctly maps letters and numbers for keyboards in US QWERTY layout */ /* This function only correctly maps letters and numbers for keyboards in US QWERTY layout */
static SDL_Scancode X11_KeyCodeToSDLScancode(SDL_VideoDevice *_this, KeyCode keycode) static SDL_Scancode X11_KeyCodeToSDLScancode(SDL_VideoDevice *_this, KeyCode keycode)
{ {
const KeySym keysym = X11_KeyCodeToSym(_this, keycode, 0); const KeySym keysym = X11_KeyCodeToSym(_this, keycode, 0, 0);
if (keysym == NoSymbol) { if (keysym == NoSymbol) {
return SDL_SCANCODE_UNKNOWN; return SDL_SCANCODE_UNKNOWN;
@ -81,24 +81,15 @@ static SDL_Scancode X11_KeyCodeToSDLScancode(SDL_VideoDevice *_this, KeyCode key
return SDL_GetScancodeFromKeySym(keysym, keycode); return SDL_GetScancodeFromKeySym(keysym, keycode);
} }
static Uint32 X11_KeyCodeToUcs4(SDL_VideoDevice *_this, KeyCode keycode, unsigned char group) KeySym X11_KeyCodeToSym(SDL_VideoDevice *_this, KeyCode keycode, unsigned char group, unsigned int mod_mask)
{
KeySym keysym = X11_KeyCodeToSym(_this, keycode, group);
if (keysym == NoSymbol) {
return 0;
}
return SDL_KeySymToUcs4(keysym);
}
KeySym
X11_KeyCodeToSym(SDL_VideoDevice *_this, KeyCode keycode, unsigned char group)
{ {
SDL_VideoData *data = _this->driverdata; SDL_VideoData *data = _this->driverdata;
KeySym keysym; KeySym keysym;
unsigned int mods_ret[16];
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM SDL_zero(mods_ret);
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
if (data->xkb) { if (data->xkb) {
int num_groups = XkbKeyNumGroups(data->xkb, keycode); int num_groups = XkbKeyNumGroups(data->xkb, keycode);
unsigned char info = XkbKeyGroupInfo(data->xkb, keycode); unsigned char info = XkbKeyGroupInfo(data->xkb, keycode);
@ -118,13 +109,16 @@ X11_KeyCodeToSym(SDL_VideoDevice *_this, KeyCode keycode, unsigned char group)
group %= num_groups; group %= num_groups;
} }
} }
keysym = X11_XkbKeycodeToKeysym(data->display, keycode, group, 0);
} else { if (X11_XkbLookupKeySym(data->display, keycode, XkbBuildCoreState(mod_mask, group), mods_ret, &keysym) == NoSymbol) {
keysym = NoSymbol;
}
} else
#endif
{
/* TODO: Handle groups and modifiers on the legacy path. */
keysym = X11_XKeycodeToKeysym(data->display, keycode, 0); keysym = X11_XKeycodeToKeysym(data->display, keycode, 0);
} }
#else
keysym = X11_XKeycodeToKeysym(data->display, keycode, 0);
#endif
return keysym; return keysym;
} }
@ -153,7 +147,7 @@ int X11_InitKeyboard(SDL_VideoDevice *_this)
int distance; int distance;
Bool xkb_repeat = 0; Bool xkb_repeat = 0;
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM #ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
{ {
int xkb_major = XkbMajorVersion; int xkb_major = XkbMajorVersion;
int xkb_minor = XkbMinorVersion; int xkb_minor = XkbMinorVersion;
@ -334,6 +328,21 @@ int X11_InitKeyboard(SDL_VideoDevice *_this)
void X11_UpdateKeymap(SDL_VideoDevice *_this, SDL_bool send_event) void X11_UpdateKeymap(SDL_VideoDevice *_this, SDL_bool send_event)
{ {
struct Keymod_masks
{
SDL_Keymod sdl_mask;
unsigned int xkb_mask;
} const keymod_masks[] = {
{ SDL_KMOD_NONE, 0 },
{ SDL_KMOD_SHIFT, ShiftMask },
{ SDL_KMOD_CAPS, LockMask },
{ SDL_KMOD_SHIFT | SDL_KMOD_CAPS, ShiftMask | LockMask },
{ SDL_KMOD_MODE, Mod5Mask },
{ SDL_KMOD_MODE | SDL_KMOD_SHIFT, Mod5Mask | ShiftMask },
{ SDL_KMOD_MODE | SDL_KMOD_CAPS, Mod5Mask | LockMask },
{ SDL_KMOD_MODE | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, Mod5Mask | ShiftMask | LockMask }
};
SDL_VideoData *data = _this->driverdata; SDL_VideoData *data = _this->driverdata;
int i; int i;
SDL_Scancode scancode; SDL_Scancode scancode;
@ -342,7 +351,7 @@ void X11_UpdateKeymap(SDL_VideoDevice *_this, SDL_bool send_event)
keymap = SDL_CreateKeymap(); keymap = SDL_CreateKeymap();
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM #ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
if (data->xkb) { if (data->xkb) {
XkbStateRec state; XkbStateRec state;
X11_XkbGetUpdatedMap(data->display, XkbAllClientInfoMask, data->xkb); X11_XkbGetUpdatedMap(data->display, XkbAllClientInfoMask, data->xkb);
@ -353,49 +362,54 @@ void X11_UpdateKeymap(SDL_VideoDevice *_this, SDL_bool send_event)
} }
#endif #endif
// FIXME: Need to get the mapping for all modifiers, not just the first one for (int m = 0; m < SDL_arraysize(keymod_masks); ++m) {
for (i = 0; i < SDL_arraysize(data->key_layout); i++) { for (i = 0; i < SDL_arraysize(data->key_layout); i++) {
Uint32 key; SDL_Keycode keycode;
SDL_Keycode keycode;
/* Make sure this is a valid scancode */ /* Make sure this is a valid scancode */
scancode = data->key_layout[i]; scancode = data->key_layout[i];
if (scancode == SDL_SCANCODE_UNKNOWN) { if (scancode == SDL_SCANCODE_UNKNOWN) {
continue; continue;
}
/* See if there is a UCS keycode for this scancode */
key = X11_KeyCodeToUcs4(_this, (KeyCode)i, group);
if (key) {
keycode = (SDL_Keycode)key;
} else {
SDL_Scancode keyScancode = X11_KeyCodeToSDLScancode(_this, (KeyCode)i);
switch (keyScancode) {
case SDL_SCANCODE_UNKNOWN:
keycode = SDLK_UNKNOWN;
break;
case SDL_SCANCODE_RETURN:
keycode = SDLK_RETURN;
break;
case SDL_SCANCODE_ESCAPE:
keycode = SDLK_ESCAPE;
break;
case SDL_SCANCODE_BACKSPACE:
keycode = SDLK_BACKSPACE;
break;
case SDL_SCANCODE_TAB:
keycode = SDLK_TAB;
break;
case SDL_SCANCODE_DELETE:
keycode = SDLK_DELETE;
break;
default:
keycode = SDL_SCANCODE_TO_KEYCODE(keyScancode);
break;
} }
KeySym keysym = X11_KeyCodeToSym(_this, i, group, keymod_masks[m].xkb_mask);
/* Note: The default SDL scancode table sets this to right alt instead of AltGr/Mode, so handle it separately. */
if (keysym != XK_ISO_Level3_Shift) {
keycode = SDL_KeySymToUcs4(keysym);
} else {
keycode = SDLK_MODE;
}
if (!keycode) {
SDL_Scancode keyScancode = SDL_GetScancodeFromKeySym(keysym, (KeyCode)i);
switch (keyScancode) {
case SDL_SCANCODE_UNKNOWN:
keycode = SDLK_UNKNOWN;
break;
case SDL_SCANCODE_RETURN:
keycode = SDLK_RETURN;
break;
case SDL_SCANCODE_ESCAPE:
keycode = SDLK_ESCAPE;
break;
case SDL_SCANCODE_BACKSPACE:
keycode = SDLK_BACKSPACE;
break;
case SDL_SCANCODE_TAB:
keycode = SDLK_TAB;
break;
case SDL_SCANCODE_DELETE:
keycode = SDLK_DELETE;
break;
default:
keycode = SDL_SCANCODE_TO_KEYCODE(keyScancode);
break;
}
}
SDL_SetKeymapEntry(keymap, scancode, keymod_masks[m].sdl_mask, keycode);
} }
SDL_SetKeymapEntry(keymap, scancode, SDL_KMOD_NONE, keycode);
} }
SDL_SetKeymap(keymap, send_event); SDL_SetKeymap(keymap, send_event);
} }
@ -404,7 +418,7 @@ void X11_QuitKeyboard(SDL_VideoDevice *_this)
{ {
SDL_VideoData *data = _this->driverdata; SDL_VideoData *data = _this->driverdata;
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM #ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
if (data->xkb) { if (data->xkb) {
X11_XkbFreeKeyboard(data->xkb, 0, True); X11_XkbFreeKeyboard(data->xkb, 0, True);
data->xkb = NULL; data->xkb = NULL;

View File

@ -33,6 +33,6 @@ extern SDL_bool X11_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
extern void X11_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window); extern void X11_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
extern void X11_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window); extern void X11_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
extern SDL_bool X11_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window); extern SDL_bool X11_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);
extern KeySym X11_KeyCodeToSym(SDL_VideoDevice *_this, KeyCode, unsigned char group); extern KeySym X11_KeyCodeToSym(SDL_VideoDevice *_this, KeyCode, unsigned char group, unsigned int mod_mask);
#endif /* SDL_x11keyboard_h_ */ #endif /* SDL_x11keyboard_h_ */

View File

@ -178,12 +178,12 @@ 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),)
#endif #endif
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM #ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
SDL_X11_SYM(Bool,XkbQueryExtension,(Display* a,int * b,int * c,int * d,int * e, int *f),(a,b,c,d,e,f),return) SDL_X11_SYM(Bool,XkbQueryExtension,(Display* a,int * b,int * c,int * d,int * e, int *f),(a,b,c,d,e,f),return)
#if NeedWidePrototypes #if NeedWidePrototypes
SDL_X11_SYM(KeySym,XkbKeycodeToKeysym,(Display* a,unsigned int b,int c,int d),(a,b,c,d),return) SDL_X11_SYM(Bool,XkbLookupKeySym,(Display* a, unsigned int b, unsigned int c, unsigned int* d, KeySym* e),(a,b,c,d,e),return)
#else #else
SDL_X11_SYM(KeySym,XkbKeycodeToKeysym,(Display* a,KeyCode b,int c,int d),(a,b,c,d),return) SDL_X11_SYM(Bool,XkbLookupKeySym,(Display* a, KeyCode b, unsigned int c, unsigned int* d, KeySym* e),(a,b,c,d,e),return)
#endif #endif
SDL_X11_SYM(Status,XkbGetState,(Display* a,unsigned int b,XkbStatePtr c),(a,b,c),return) SDL_X11_SYM(Status,XkbGetState,(Display* a,unsigned int b,XkbStatePtr c),(a,b,c),return)
SDL_X11_SYM(Status,XkbGetUpdatedMap,(Display* a,unsigned int b,XkbDescPtr c),(a,b,c),return) SDL_X11_SYM(Status,XkbGetUpdatedMap,(Display* a,unsigned int b,XkbDescPtr c),(a,b,c),return)

View File

@ -121,7 +121,7 @@ struct SDL_VideoData
int xrandr_event_base; int xrandr_event_base;
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM #ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
XkbDescPtr xkb; XkbDescPtr xkb;
#endif #endif
int xkb_event; int xkb_event;