mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-03-23 10:12:47 +08:00
x11: Modernize and optimize key handling
- Use modern Xkb functions where appropriate and cleanly separate the modern and legacy paths. - Remove the deprecated XKeycodeToKeysym function in favor of directly querying the keymap on the legacy path. - Look up virtual modifiers by name on the Xkb path to better handle remapping (equivalent to the modifier handling under Wayland). - Optimize keymap creation on the Xkb path to cut keymap build times and enable fast group switching (equivalent to keymap handling on Wayland). - Enable and handle Xkb events to handle changes to the group, mapping, and modifier states. This is more reliable than using the legacy events (group changes may not arrive if the window lacks pointer focus), and better handles cases where modifiers are latched, locked, or activated externally rather than physically pressed.
This commit is contained in:
committed by
Sam Lantinga
parent
67e5130441
commit
f439e44771
@@ -390,7 +390,7 @@ macro(CheckX11)
|
||||
set(SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 1)
|
||||
endif()
|
||||
|
||||
check_symbol_exists(XkbLookupKeySym "X11/Xlib.h;X11/XKBlib.h" SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM)
|
||||
check_include_file("X11/XKBlib.h" SDL_VIDEO_DRIVER_X11_HAS_XKBLIB)
|
||||
|
||||
if(SDL_X11_XCURSOR AND HAVE_XCURSOR_H AND XCURSOR_LIB)
|
||||
set(HAVE_X11_XCURSOR TRUE)
|
||||
|
||||
@@ -422,7 +422,7 @@
|
||||
#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_XTEST @SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST@
|
||||
#cmakedefine SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM 1
|
||||
#cmakedefine SDL_VIDEO_DRIVER_X11_HAS_XKBLIB 1
|
||||
#cmakedefine SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 1
|
||||
#cmakedefine SDL_VIDEO_DRIVER_X11_XCURSOR 1
|
||||
#cmakedefine SDL_VIDEO_DRIVER_X11_XDBE 1
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xresource.h>
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB
|
||||
#include <X11/XKBlib.h>
|
||||
#endif
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,7 +28,10 @@
|
||||
#include "../../events/SDL_scancode_tables_c.h"
|
||||
|
||||
#include <X11/keysym.h>
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB
|
||||
#include <X11/XKBlib.h>
|
||||
#endif
|
||||
|
||||
#include "../../events/imKStoUCS.h"
|
||||
#include "../../events/SDL_keysym_to_scancode_c.h"
|
||||
@@ -70,6 +73,28 @@ static bool X11_ScancodeIsRemappable(SDL_Scancode scancode)
|
||||
}
|
||||
}
|
||||
|
||||
static KeySym X11_KeyCodeToSym(SDL_VideoDevice *_this, KeyCode keycode, unsigned int group, unsigned int level)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
KeySym keysym;
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB
|
||||
if (data->keyboard.xkb_enabled) {
|
||||
keysym = X11_XkbKeycodeToKeysym(data->display, keycode, group, level);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
// TODO: Handle groups on the legacy path.
|
||||
if (keycode >= data->keyboard.core.min_keycode && keycode <= data->keyboard.core.max_keycode) {
|
||||
keysym = data->keyboard.core.keysym_map[(keycode - data->keyboard.core.min_keycode) * data->keyboard.core.keysyms_per_key];
|
||||
} else {
|
||||
keysym = NoSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
return keysym;
|
||||
}
|
||||
|
||||
// This function only correctly maps letters and numbers for keyboards in US QWERTY layout
|
||||
static SDL_Scancode X11_KeyCodeToSDLScancode(SDL_VideoDevice *_this, KeyCode keycode)
|
||||
{
|
||||
@@ -82,48 +107,6 @@ static SDL_Scancode X11_KeyCodeToSDLScancode(SDL_VideoDevice *_this, KeyCode key
|
||||
return SDL_GetScancodeFromKeySym(keysym, keycode);
|
||||
}
|
||||
|
||||
KeySym X11_KeyCodeToSym(SDL_VideoDevice *_this, KeyCode keycode, unsigned char group, unsigned int mod_mask)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
KeySym keysym;
|
||||
unsigned int mods_ret[16];
|
||||
|
||||
SDL_zero(mods_ret);
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
|
||||
if (data->xkb.desc_ptr) {
|
||||
int num_groups = XkbKeyNumGroups(data->xkb.desc_ptr, keycode);
|
||||
unsigned char info = XkbKeyGroupInfo(data->xkb.desc_ptr, keycode);
|
||||
|
||||
if (num_groups && group >= num_groups) {
|
||||
|
||||
int action = XkbOutOfRangeGroupAction(info);
|
||||
|
||||
if (action == XkbRedirectIntoRange) {
|
||||
group = XkbOutOfRangeGroupNumber(info);
|
||||
if (group >= num_groups) {
|
||||
group = 0;
|
||||
}
|
||||
} else if (action == XkbClampIntoRange) {
|
||||
group = num_groups - 1;
|
||||
} else {
|
||||
group %= num_groups;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return keysym;
|
||||
}
|
||||
|
||||
bool X11_InitKeyboard(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
@@ -146,21 +129,33 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this)
|
||||
int best_distance;
|
||||
int best_index;
|
||||
int distance;
|
||||
Bool xkb_repeat = 0;
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
|
||||
{
|
||||
int xkb_major = XkbMajorVersion;
|
||||
int xkb_minor = XkbMinorVersion;
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB
|
||||
int xkb_major = XkbMajorVersion;
|
||||
int xkb_minor = XkbMinorVersion;
|
||||
|
||||
if (X11_XkbQueryExtension(data->display, NULL, &data->xkb.event, NULL, &xkb_major, &xkb_minor)) {
|
||||
data->xkb.desc_ptr = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd);
|
||||
}
|
||||
if (X11_XkbQueryExtension(data->display, NULL, &data->keyboard.xkb.event, NULL, &xkb_major, &xkb_minor)) {
|
||||
Bool xkb_repeat = 0;
|
||||
data->keyboard.xkb_enabled = true;
|
||||
data->keyboard.xkb.desc_ptr = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd);
|
||||
|
||||
// This will remove KeyRelease events for held keys
|
||||
// This will remove KeyRelease events for held keys.
|
||||
X11_XkbSetDetectableAutoRepeat(data->display, True, &xkb_repeat);
|
||||
}
|
||||
|
||||
// Enable the key mapping and state events.
|
||||
X11_XkbSelectEvents(data->display, XkbUseCoreKbd,
|
||||
XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask,
|
||||
XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask);
|
||||
X11_XkbSelectEventDetails(data->display, XkbUseCoreKbd, XkbStateNotify, XkbGroupStateMask | XkbModifierStateMask, XkbGroupStateMask | XkbModifierStateMask);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
// If XKB isn't available, initialize the legacy path.
|
||||
X11_XDisplayKeycodes(data->display, &data->keyboard.core.min_keycode, &data->keyboard.core.max_keycode);
|
||||
data->keyboard.core.keysym_map = X11_XGetKeyboardMapping(data->display, data->keyboard.core.min_keycode,
|
||||
data->keyboard.core.max_keycode - data->keyboard.core.min_keycode,
|
||||
&data->keyboard.core.keysyms_per_key);
|
||||
}
|
||||
|
||||
// Open a connection to the X input manager
|
||||
#ifdef X_HAVE_UTF8_STRING
|
||||
@@ -242,10 +237,10 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this)
|
||||
SDL_Log("Using scancode set %d, min_keycode = %d, max_keycode = %d, table_size = %d", best_index, min_keycode, max_keycode, table_size);
|
||||
#endif
|
||||
// This should never happen, but just in case...
|
||||
if (table_size > (SDL_arraysize(data->key_layout) - min_keycode)) {
|
||||
table_size = (SDL_arraysize(data->key_layout) - min_keycode);
|
||||
if (table_size > (SDL_arraysize(data->keyboard.key_layout) - min_keycode)) {
|
||||
table_size = (SDL_arraysize(data->keyboard.key_layout) - min_keycode);
|
||||
}
|
||||
SDL_memcpy(&data->key_layout[min_keycode], table, sizeof(SDL_Scancode) * table_size);
|
||||
SDL_memcpy(&data->keyboard.key_layout[min_keycode], table, sizeof(SDL_Scancode) * table_size);
|
||||
|
||||
/* Scancodes represent physical locations on the keyboard, unaffected by keyboard mapping.
|
||||
However, there are a number of extended scancodes that have no standard location, so use
|
||||
@@ -261,7 +256,7 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this)
|
||||
(unsigned int)sym, sym == NoSymbol ? "NoSymbol" : X11_XKeysymToString(sym));
|
||||
}
|
||||
#endif
|
||||
if (scancode == data->key_layout[i]) {
|
||||
if (scancode == data->keyboard.key_layout[i]) {
|
||||
continue;
|
||||
}
|
||||
if ((SDL_GetKeymapKeycode(NULL, scancode, SDL_KMOD_NONE) & (SDLK_SCANCODE_MASK | SDLK_EXTENDED_MASK)) && X11_ScancodeIsRemappable(scancode)) {
|
||||
@@ -269,7 +264,7 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this)
|
||||
#ifdef DEBUG_KEYBOARD
|
||||
SDL_Log("Changing scancode, was %d (%s), now %d (%s)", data->key_layout[i], SDL_GetScancodeName(data->key_layout[i]), scancode, SDL_GetScancodeName(scancode));
|
||||
#endif
|
||||
data->key_layout[i] = scancode;
|
||||
data->keyboard.key_layout[i] = scancode;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -293,7 +288,7 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this)
|
||||
SDL_Log("scancode = %d (%s)", scancode, SDL_GetScancodeName(scancode));
|
||||
}
|
||||
#endif
|
||||
data->key_layout[i] = scancode;
|
||||
data->keyboard.key_layout[i] = scancode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,149 +301,235 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this)
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned X11_GetNumLockModifierMask(SDL_VideoDevice *_this)
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB
|
||||
static unsigned int X11_GetXkbVirtualModifierMask(SDL_VideoDevice *_this, const char *vmod_name)
|
||||
{
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
unsigned int mod_mask = 0;
|
||||
|
||||
if (videodata->keyboard.xkb_enabled) {
|
||||
Atom vmod = X11_XInternAtom(videodata->display, vmod_name, True);
|
||||
if (vmod != None) {
|
||||
for (int i = 0; i < XkbNumVirtualMods; ++i) {
|
||||
if (vmod == videodata->keyboard.xkb.desc_ptr->names->vmods[i]) {
|
||||
mod_mask = videodata->keyboard.xkb.desc_ptr->server->vmods[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mod_mask;
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned X11_GetXModifierMask(SDL_VideoDevice *_this, SDL_Scancode scancode)
|
||||
{
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
Display *display = videodata->display;
|
||||
unsigned num_mask = 0;
|
||||
int i, j;
|
||||
XModifierKeymap *xmods;
|
||||
unsigned n;
|
||||
unsigned int mod_mask = 0;
|
||||
|
||||
xmods = X11_XGetModifierMapping(display);
|
||||
n = xmods->max_keypermod;
|
||||
for (i = 3; i < 8; i++) {
|
||||
for (j = 0; j < n; j++) {
|
||||
KeyCode kc = xmods->modifiermap[i * n + j];
|
||||
if (videodata->key_layout[kc] == SDL_SCANCODE_NUMLOCKCLEAR) {
|
||||
num_mask = 1 << i;
|
||||
XModifierKeymap *xmods = X11_XGetModifierMapping(display);
|
||||
unsigned int n = xmods->max_keypermod;
|
||||
for (int i = 3; i < 8; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
const KeyCode kc = xmods->modifiermap[i * n + j];
|
||||
if (videodata->keyboard.key_layout[kc] == scancode) {
|
||||
mod_mask = 1 << i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
X11_XFreeModifiermap(xmods);
|
||||
|
||||
return num_mask;
|
||||
return mod_mask;
|
||||
}
|
||||
|
||||
static unsigned X11_GetScrollLockModifierMask(SDL_VideoDevice *_this)
|
||||
static void X11_AddKeymapEntry(SDL_Keymap *keymap, Uint32 xkeycode, KeySym xkeysym, SDL_Scancode sdl_scancode, SDL_Keymod sdl_mod_mask)
|
||||
{
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
Display *display = videodata->display;
|
||||
unsigned num_mask = 0;
|
||||
int i, j;
|
||||
XModifierKeymap *xmods;
|
||||
unsigned n;
|
||||
SDL_Keycode keycode = SDL_GetKeyCodeFromKeySym(xkeysym, xkeycode, sdl_mod_mask);
|
||||
|
||||
xmods = X11_XGetModifierMapping(display);
|
||||
n = xmods->max_keypermod;
|
||||
for (i = 3; i < 8; i++) {
|
||||
for (j = 0; j < n; j++) {
|
||||
KeyCode kc = xmods->modifiermap[i * n + j];
|
||||
if (videodata->key_layout[kc] == SDL_SCANCODE_SCROLLLOCK) {
|
||||
num_mask = 1 << i;
|
||||
break;
|
||||
}
|
||||
if (!keycode) {
|
||||
switch (sdl_scancode) {
|
||||
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_DELETE:
|
||||
keycode = SDLK_DELETE;
|
||||
break;
|
||||
default:
|
||||
keycode = SDL_SCANCODE_TO_KEYCODE(sdl_scancode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
X11_XFreeModifiermap(xmods);
|
||||
|
||||
return num_mask;
|
||||
SDL_SetKeymapEntry(keymap, sdl_scancode, sdl_mod_mask, keycode);
|
||||
}
|
||||
|
||||
void X11_UpdateKeymap(SDL_VideoDevice *_this, 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_KMOD_LEVEL5, Mod3Mask },
|
||||
{ SDL_KMOD_LEVEL5 | SDL_KMOD_SHIFT, Mod3Mask | ShiftMask },
|
||||
{ SDL_KMOD_LEVEL5 | SDL_KMOD_CAPS, Mod3Mask | LockMask },
|
||||
{ SDL_KMOD_LEVEL5 | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, Mod3Mask | ShiftMask | LockMask },
|
||||
{ SDL_KMOD_LEVEL5 | SDL_KMOD_MODE, Mod5Mask | Mod3Mask },
|
||||
{ SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_SHIFT, Mod3Mask | Mod5Mask | ShiftMask },
|
||||
{ SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_CAPS, Mod3Mask | Mod5Mask | LockMask },
|
||||
{ SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, Mod3Mask | Mod5Mask | ShiftMask | LockMask }
|
||||
};
|
||||
|
||||
SDL_VideoData *data = _this->internal;
|
||||
SDL_Scancode scancode;
|
||||
SDL_Keymap *keymap = SDL_CreateKeymap(true);
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
|
||||
if (data->xkb.desc_ptr) {
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB
|
||||
if (data->keyboard.xkb_enabled) {
|
||||
XkbStateRec state;
|
||||
X11_XkbGetUpdatedMap(data->display, XkbAllClientInfoMask, data->xkb.desc_ptr);
|
||||
|
||||
SDL_SetKeymap(NULL, false);
|
||||
for (unsigned int i = 0; i < XkbNumKbdGroups; ++i) {
|
||||
SDL_DestroyKeymap(data->keyboard.xkb.keymaps[i]);
|
||||
data->keyboard.xkb.keymaps[i] = SDL_CreateKeymap(false);
|
||||
}
|
||||
|
||||
X11_XkbGetNames(data->display, XkbVirtualModNamesMask, data->keyboard.xkb.desc_ptr);
|
||||
X11_XkbGetUpdatedMap(data->display, XkbAllClientInfoMask | XkbVirtualModsMask, data->keyboard.xkb.desc_ptr);
|
||||
|
||||
if (X11_XkbGetState(data->display, XkbUseCoreKbd, &state) == Success) {
|
||||
data->xkb.current_group = state.group;
|
||||
data->keyboard.xkb.current_group = state.group;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int m = 0; m < SDL_arraysize(keymod_masks); ++m) {
|
||||
for (int i = 0; i < SDL_arraysize(data->key_layout); ++i) {
|
||||
// Make sure this is a valid scancode
|
||||
scancode = data->key_layout[i];
|
||||
data->keyboard.alt_mask = X11_GetXkbVirtualModifierMask(_this, "Alt");
|
||||
if (!data->keyboard.alt_mask) {
|
||||
data->keyboard.alt_mask = X11_GetXkbVirtualModifierMask(_this, "Meta");
|
||||
}
|
||||
data->keyboard.gui_mask = X11_GetXkbVirtualModifierMask(_this, "Super");
|
||||
data->keyboard.level3_mask = X11_GetXkbVirtualModifierMask(_this, "LevelThree");
|
||||
data->keyboard.level5_mask = X11_GetXkbVirtualModifierMask(_this, "LevelFive");
|
||||
data->keyboard.numlock_mask = X11_GetXkbVirtualModifierMask(_this, "NumLock");
|
||||
data->keyboard.scrolllock_mask = X11_GetXkbVirtualModifierMask(_this, "ScrollLock");
|
||||
|
||||
const Uint32 valid_mod_mask = ShiftMask | LockMask | data->keyboard.alt_mask | data->keyboard.level3_mask | data->keyboard.level5_mask;
|
||||
|
||||
for (Uint32 xkeycode = data->keyboard.xkb.desc_ptr->min_key_code; xkeycode < data->keyboard.xkb.desc_ptr->max_key_code; ++xkeycode) {
|
||||
const SDL_Scancode scancode = data->keyboard.key_layout[xkeycode];
|
||||
if (scancode == SDL_SCANCODE_UNKNOWN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const KeySym keysym = X11_KeyCodeToSym(_this, i, data->xkb.current_group, keymod_masks[m].xkb_mask);
|
||||
for (Uint32 group = 0; group < XkbNumKbdGroups; ++group) {
|
||||
SDL_Keymap *keymap = data->keyboard.xkb.keymaps[group];
|
||||
|
||||
if (keysym != NoSymbol) {
|
||||
SDL_Keycode keycode = SDL_GetKeyCodeFromKeySym(keysym, i, keymod_masks[m].sdl_mask);
|
||||
Uint32 effective_group = group;
|
||||
const unsigned char max_key_group = XkbKeyNumGroups(data->keyboard.xkb.desc_ptr, xkeycode);
|
||||
const unsigned char key_group_info = XkbKeyGroupInfo(data->keyboard.xkb.desc_ptr, xkeycode);
|
||||
|
||||
if (!keycode) {
|
||||
switch (scancode) {
|
||||
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_DELETE:
|
||||
keycode = SDLK_DELETE;
|
||||
break;
|
||||
if (max_key_group && effective_group >= max_key_group) {
|
||||
const unsigned char action = XkbOutOfRangeGroupAction(key_group_info);
|
||||
|
||||
switch (action) {
|
||||
default:
|
||||
keycode = SDL_SCANCODE_TO_KEYCODE(scancode);
|
||||
effective_group %= max_key_group;
|
||||
break;
|
||||
case XkbClampIntoRange:
|
||||
effective_group = max_key_group - 1;
|
||||
break;
|
||||
case XkbRedirectIntoRange:
|
||||
effective_group = XkbOutOfRangeGroupNumber(key_group_info);
|
||||
if (effective_group >= max_key_group) {
|
||||
effective_group = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SetKeymapEntry(keymap, scancode, keymod_masks[m].sdl_mask, keycode);
|
||||
XkbKeyTypePtr key_type = XkbKeyKeyType(data->keyboard.xkb.desc_ptr, xkeycode, effective_group);
|
||||
|
||||
for (Uint32 level = 0; level < key_type->num_levels; ++level) {
|
||||
const KeySym keysym = X11_KeyCodeToSym(_this, xkeycode, effective_group, level);
|
||||
|
||||
if (keysym != NoSymbol) {
|
||||
bool key_added = false;
|
||||
|
||||
for (int map_idx = 0; map_idx < key_type->map_count; ++map_idx) {
|
||||
if (key_type->map[map_idx].active && key_type->map[map_idx].level == level) {
|
||||
const unsigned int xkb_mod_mask = key_type->map[map_idx].mods.mask;
|
||||
if ((xkb_mod_mask | valid_mod_mask) == valid_mod_mask) {
|
||||
const SDL_Keymod sdl_mod_mask = (xkb_mod_mask & ShiftMask ? SDL_KMOD_SHIFT : 0) |
|
||||
(xkb_mod_mask & LockMask ? SDL_KMOD_CAPS : 0) |
|
||||
(xkb_mod_mask & data->keyboard.alt_mask ? SDL_KMOD_ALT : 0) |
|
||||
(xkb_mod_mask & data->keyboard.level3_mask ? SDL_KMOD_MODE : 0) |
|
||||
(xkb_mod_mask & data->keyboard.level5_mask ? SDL_KMOD_LEVEL5 : 0);
|
||||
|
||||
X11_AddKeymapEntry(keymap, xkeycode, keysym, scancode, sdl_mod_mask);
|
||||
key_added = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the unmodified key for level 0.
|
||||
if (!level && !key_added) {
|
||||
X11_AddKeymapEntry(keymap, xkeycode, keysym, scancode, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data->xkb.numlock_mask = X11_GetNumLockModifierMask(_this);
|
||||
data->xkb.scrolllock_mask = X11_GetScrollLockModifierMask(_this);
|
||||
SDL_SetKeymap(keymap, send_event);
|
||||
SDL_SetKeymap(data->keyboard.xkb.keymaps[data->keyboard.xkb.current_group], send_event);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
SDL_Keymap *keymap = SDL_CreateKeymap(true);
|
||||
|
||||
if (send_event) {
|
||||
if (data->keyboard.core.keysym_map) {
|
||||
X11_XFree(data->keyboard.core.keysym_map);
|
||||
}
|
||||
X11_XDisplayKeycodes(data->display, &data->keyboard.core.min_keycode, &data->keyboard.core.max_keycode);
|
||||
data->keyboard.core.keysym_map = X11_XGetKeyboardMapping(data->display, data->keyboard.core.min_keycode,
|
||||
data->keyboard.core.max_keycode - data->keyboard.core.min_keycode,
|
||||
&data->keyboard.core.keysyms_per_key);
|
||||
}
|
||||
|
||||
for (Uint32 xkeycode = data->keyboard.core.min_keycode; xkeycode <= data->keyboard.core.max_keycode; ++xkeycode) {
|
||||
const SDL_Scancode scancode = data->keyboard.key_layout[xkeycode];
|
||||
if (scancode == SDL_SCANCODE_UNKNOWN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const KeySym keysym = X11_KeyCodeToSym(_this, xkeycode, 0, 0);
|
||||
if (keysym != NoSymbol) {
|
||||
X11_AddKeymapEntry(keymap, xkeycode, keysym, scancode, 0);
|
||||
}
|
||||
}
|
||||
|
||||
data->keyboard.alt_mask = Mod1Mask; // Alt or Meta
|
||||
data->keyboard.gui_mask = Mod4Mask; // Super
|
||||
data->keyboard.level3_mask = Mod5Mask; // Note: Not a typo, Mod5 = level 3 shift, and Mod3 = level 5 shift.
|
||||
data->keyboard.level5_mask = Mod3Mask;
|
||||
data->keyboard.numlock_mask = X11_GetXModifierMask(_this, SDL_SCANCODE_NUMLOCKCLEAR);
|
||||
data->keyboard.scrolllock_mask = X11_GetXModifierMask(_this, SDL_SCANCODE_SCROLLLOCK);
|
||||
|
||||
SDL_SetKeymap(keymap, send_event);
|
||||
}
|
||||
}
|
||||
|
||||
void X11_QuitKeyboard(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
|
||||
if (data->xkb.desc_ptr) {
|
||||
X11_XkbFreeKeyboard(data->xkb.desc_ptr, 0, True);
|
||||
data->xkb.desc_ptr = NULL;
|
||||
}
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB
|
||||
if (data->keyboard.xkb_enabled) {
|
||||
for (int i = 0; i < XkbNumKbdGroups; ++i) {
|
||||
SDL_DestroyKeymap(data->keyboard.xkb.keymaps[i]);
|
||||
data->keyboard.xkb.keymaps[i] = NULL;
|
||||
}
|
||||
|
||||
if (data->keyboard.xkb_enabled) {
|
||||
X11_XkbFreeKeyboard(data->keyboard.xkb.desc_ptr, 0, True);
|
||||
data->keyboard.xkb.desc_ptr = NULL;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (data->keyboard.core.keysym_map) {
|
||||
X11_XFree(data->keyboard.core.keysym_map);
|
||||
data->keyboard.core.keysym_map = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void X11_ClearComposition(SDL_WindowData *data)
|
||||
|
||||
@@ -35,6 +35,5 @@ extern bool X11_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
|
||||
extern void X11_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
|
||||
extern void X11_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool X11_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern KeySym X11_KeyCodeToSym(SDL_VideoDevice *_this, KeyCode, unsigned char group, unsigned int mod_mask);
|
||||
|
||||
#endif // SDL_x11keyboard_h_
|
||||
|
||||
@@ -71,6 +71,7 @@ SDL_X11_SYM(int,XFreePixmap,(Display* a,Pixmap b))
|
||||
SDL_X11_SYM(void,XFreeStringList,(char** a))
|
||||
SDL_X11_SYM(char*,XGetAtomName,(Display *a,Atom b))
|
||||
SDL_X11_SYM(int,XGetInputFocus,(Display *a,Window *b,int *c))
|
||||
SDL_X11_SYM(KeySym*,XGetKeyboardMapping,(Display *a, KeyCode b, int c, int *d))
|
||||
SDL_X11_SYM(int,XGetErrorDatabaseText,(Display* a,_Xconst char* b,_Xconst char* c,_Xconst char* d,char* e,int f))
|
||||
SDL_X11_SYM(XModifierKeymap*,XGetModifierMapping,(Display* a))
|
||||
SDL_X11_SYM(int,XGetPointerControl,(Display* a,int* b,int* c,int* d))
|
||||
@@ -196,35 +197,21 @@ SDL_X11_SYM(Bool,XGetEventData,(Display* a,XGenericEventCookie* b))
|
||||
SDL_X11_SYM(void,XFreeEventData,(Display* a,XGenericEventCookie* b))
|
||||
#endif
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB
|
||||
SDL_X11_SYM(Bool,XkbQueryExtension,(Display* a,int * b,int * c,int * d,int * e, int *f))
|
||||
#if NeedWidePrototypes
|
||||
SDL_X11_SYM(Bool,XkbLookupKeySym,(Display* a, unsigned int b, unsigned int c, unsigned int* d, KeySym* e))
|
||||
#else
|
||||
SDL_X11_SYM(Bool,XkbLookupKeySym,(Display* a, KeyCode b, unsigned int c, unsigned int* d, KeySym* e))
|
||||
#endif
|
||||
SDL_X11_SYM(KeySym,XkbKeycodeToKeysym,(Display* a, KeyCode b, unsigned int c, unsigned int d))
|
||||
SDL_X11_SYM(Bool,XkbSelectEvents,(Display* a, unsigned int b, unsigned int c, unsigned long d))
|
||||
SDL_X11_SYM(Bool,XkbSelectEventDetails,(Display* a, unsigned int b, unsigned int c, unsigned long d, unsigned long e))
|
||||
SDL_X11_SYM(Status,XkbGetNames,(Display *a, unsigned int b, XkbDescPtr c))
|
||||
SDL_X11_SYM(Status,XkbGetState,(Display* a,unsigned int b,XkbStatePtr c))
|
||||
SDL_X11_SYM(Status,XkbGetUpdatedMap,(Display* a,unsigned int b,XkbDescPtr c))
|
||||
SDL_X11_SYM(XkbDescPtr,XkbGetMap,(Display* a,unsigned int b,unsigned int c))
|
||||
SDL_X11_SYM(void,XkbFreeClientMap,(XkbDescPtr a,unsigned int b, Bool c))
|
||||
SDL_X11_SYM(void,XkbFreeKeyboard,(XkbDescPtr a,unsigned int b, Bool c))
|
||||
SDL_X11_SYM(Status,XkbRefreshKeyboardMapping,(XkbMapNotifyEvent *a))
|
||||
SDL_X11_SYM(Bool,XkbSetDetectableAutoRepeat,(Display* a, Bool b, Bool* c))
|
||||
#endif
|
||||
|
||||
// XKeycodeToKeysym is a deprecated function
|
||||
#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
#if NeedWidePrototypes
|
||||
SDL_X11_SYM(KeySym,XKeycodeToKeysym,(Display* a,unsigned int b,int c))
|
||||
#else
|
||||
SDL_X11_SYM(KeySym,XKeycodeToKeysym,(Display* a,KeyCode b,int c))
|
||||
#endif
|
||||
#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef X_HAVE_UTF8_STRING
|
||||
SDL_X11_MODULE(UTF8)
|
||||
SDL_X11_SYM(int,Xutf8TextListToTextProperty,(Display* a,char** b,int c,XICCEncodingStyle d,XTextProperty* e))
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#define SDL_x11video_h_
|
||||
|
||||
#include "../SDL_sysvideo.h"
|
||||
#include "../../events/SDL_keymap_c.h"
|
||||
|
||||
#include "../../core/linux/SDL_dbus.h"
|
||||
#include "../../core/linux/SDL_ime.h"
|
||||
@@ -125,7 +126,6 @@ struct SDL_VideoData
|
||||
Atom pen_atom_wacom_tool_type;
|
||||
} atoms;
|
||||
|
||||
SDL_Scancode key_layout[256];
|
||||
bool selection_waiting;
|
||||
bool selection_incr_waiting;
|
||||
|
||||
@@ -144,21 +144,43 @@ struct SDL_VideoData
|
||||
int xrandr_event_base;
|
||||
struct
|
||||
{
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
|
||||
XkbDescPtr desc_ptr;
|
||||
bool xkb_enabled;
|
||||
SDL_Scancode key_layout[256];
|
||||
|
||||
union
|
||||
{
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB
|
||||
struct
|
||||
{
|
||||
XkbDescPtr desc_ptr;
|
||||
SDL_Keymap *keymaps[XkbNumKbdGroups];
|
||||
unsigned long last_map_serial;
|
||||
int event;
|
||||
Uint32 current_group;
|
||||
} xkb; // Modern XKB keyboard handling
|
||||
#endif
|
||||
int event;
|
||||
unsigned int current_group;
|
||||
unsigned int xkb_modifiers;
|
||||
|
||||
SDL_Keymod sdl_modifiers;
|
||||
struct
|
||||
{
|
||||
KeySym *keysym_map;
|
||||
int keysyms_per_key;
|
||||
int min_keycode;
|
||||
int max_keycode;
|
||||
} core; // Legacy core keyboard handling
|
||||
};
|
||||
Uint32 pressed_modifiers;
|
||||
Uint32 locked_modifiers;
|
||||
SDL_Keymod sdl_pressed_modifiers;
|
||||
SDL_Keymod sdl_physically_pressed_modifiers;
|
||||
SDL_Keymod sdl_locked_modifiers;
|
||||
|
||||
// Virtual modifiers looked up by name.
|
||||
Uint32 alt_mask;
|
||||
Uint32 gui_mask;
|
||||
Uint32 level3_mask;
|
||||
Uint32 level5_mask;
|
||||
Uint32 numlock_mask;
|
||||
Uint32 scrolllock_mask;
|
||||
} xkb;
|
||||
|
||||
KeyCode filter_code;
|
||||
Time filter_time;
|
||||
} keyboard;
|
||||
|
||||
#ifdef SDL_VIDEO_VULKAN
|
||||
// Vulkan variables only valid if _this->vulkan_config.loader_handle is not NULL
|
||||
|
||||
Reference in New Issue
Block a user