mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-09-06 03:18:13 +00: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)
|
set(SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 1)
|
||||||
endif()
|
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)
|
if(SDL_X11_XCURSOR AND HAVE_XCURSOR_H AND XCURSOR_LIB)
|
||||||
set(HAVE_X11_XCURSOR TRUE)
|
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_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_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_SUPPORTS_GENERIC_EVENTS 1
|
||||||
#cmakedefine SDL_VIDEO_DRIVER_X11_XCURSOR 1
|
#cmakedefine SDL_VIDEO_DRIVER_X11_XCURSOR 1
|
||||||
#cmakedefine SDL_VIDEO_DRIVER_X11_XDBE 1
|
#cmakedefine SDL_VIDEO_DRIVER_X11_XDBE 1
|
||||||
|
@@ -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_XKBLOOKUPKEYSYM
|
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB
|
||||||
#include <X11/XKBlib.h>
|
#include <X11/XKBlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -248,94 +248,202 @@ static void X11_HandleGenericEvent(SDL_VideoDevice *_this, XEvent *xev)
|
|||||||
|
|
||||||
static void X11_UpdateSystemKeyModifiers(SDL_VideoData *viddata)
|
static void X11_UpdateSystemKeyModifiers(SDL_VideoData *viddata)
|
||||||
{
|
{
|
||||||
Window junk_window;
|
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB
|
||||||
int x, y;
|
if (viddata->keyboard.xkb_enabled) {
|
||||||
|
XkbStateRec xkb_state;
|
||||||
|
if (X11_XkbGetState(viddata->display, XkbUseCoreKbd, &xkb_state) == Success) {
|
||||||
|
viddata->keyboard.pressed_modifiers = xkb_state.base_mods;
|
||||||
|
viddata->keyboard.locked_modifiers = xkb_state.latched_mods | xkb_state.locked_mods;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
Window junk_window;
|
||||||
|
int x, y;
|
||||||
|
unsigned int mod_mask;
|
||||||
|
|
||||||
X11_XQueryPointer(viddata->display, DefaultRootWindow(viddata->display), &junk_window, &junk_window, &x, &y, &x, &y, &viddata->xkb.xkb_modifiers);
|
X11_XQueryPointer(viddata->display, DefaultRootWindow(viddata->display), &junk_window, &junk_window, &x, &y, &x, &y, &mod_mask);
|
||||||
|
viddata->keyboard.pressed_modifiers = mod_mask & (ShiftMask | ControlMask | Mod1Mask | Mod3Mask | Mod4Mask | Mod5Mask);
|
||||||
|
viddata->keyboard.locked_modifiers = mod_mask & (LockMask | viddata->keyboard.numlock_mask | viddata->keyboard.scrolllock_mask);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void X11_ReconcileModifiers(SDL_VideoData *viddata)
|
static void X11_ReconcileModifiers(SDL_VideoData *viddata, bool key_pressed)
|
||||||
{
|
{
|
||||||
const Uint32 xk_modifiers = viddata->xkb.xkb_modifiers;
|
/* Handle explicit pressed modifier state. This will correct the modifier state
|
||||||
|
* if common modifier keys were remapped and the modifiers presumed to be set
|
||||||
/* If a modifier was activated by a keypress, it will be tied to the
|
* during a key press event were incorrect, if the modifier was set to the
|
||||||
* specific left/right key that initiated it. Otherwise, the ambiguous
|
* pressed state via means other than pressing the physical key, or if the
|
||||||
* left/right combo is used.
|
* modifier state was set by a keypress before the corresponding key event
|
||||||
|
* was received.
|
||||||
*/
|
*/
|
||||||
if (xk_modifiers & ShiftMask) {
|
if (key_pressed) {
|
||||||
if (!(viddata->xkb.sdl_modifiers & SDL_KMOD_SHIFT)) {
|
if (viddata->keyboard.pressed_modifiers & ShiftMask) {
|
||||||
viddata->xkb.sdl_modifiers |= SDL_KMOD_SHIFT;
|
if (viddata->keyboard.sdl_physically_pressed_modifiers & SDL_KMOD_SHIFT) {
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_SHIFT;
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers |= (viddata->keyboard.sdl_physically_pressed_modifiers & SDL_KMOD_SHIFT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viddata->keyboard.pressed_modifiers & ControlMask) {
|
||||||
|
if (viddata->keyboard.sdl_physically_pressed_modifiers & SDL_KMOD_CTRL) {
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_CTRL;
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers |= (viddata->keyboard.sdl_physically_pressed_modifiers & SDL_KMOD_CTRL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viddata->keyboard.pressed_modifiers & viddata->keyboard.alt_mask) {
|
||||||
|
if (viddata->keyboard.sdl_physically_pressed_modifiers & SDL_KMOD_ALT) {
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_ALT;
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers |= (viddata->keyboard.sdl_physically_pressed_modifiers & SDL_KMOD_ALT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viddata->keyboard.pressed_modifiers & viddata->keyboard.gui_mask) {
|
||||||
|
if (viddata->keyboard.sdl_physically_pressed_modifiers & SDL_KMOD_GUI) {
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_GUI;
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers |= (viddata->keyboard.sdl_physically_pressed_modifiers & SDL_KMOD_GUI);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
viddata->xkb.sdl_modifiers &= ~SDL_KMOD_SHIFT;
|
if (viddata->keyboard.pressed_modifiers & ShiftMask) {
|
||||||
|
if (!(viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_SHIFT)) {
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers |= SDL_KMOD_SHIFT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viddata->keyboard.pressed_modifiers & ControlMask) {
|
||||||
|
if (!(viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_CTRL)) {
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers |= SDL_KMOD_CTRL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_CTRL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viddata->keyboard.pressed_modifiers & viddata->keyboard.alt_mask) {
|
||||||
|
if (!(viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_ALT)) {
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers |= SDL_KMOD_ALT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_ALT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viddata->keyboard.pressed_modifiers & viddata->keyboard.gui_mask) {
|
||||||
|
if (!(viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_GUI)) {
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers |= SDL_KMOD_GUI;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_GUI;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viddata->keyboard.pressed_modifiers & viddata->keyboard.level3_mask) {
|
||||||
|
if (!(viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_MODE)) {
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers |= SDL_KMOD_MODE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_MODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viddata->keyboard.pressed_modifiers & viddata->keyboard.level5_mask) {
|
||||||
|
if (!(viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_LEVEL5)) {
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers |= SDL_KMOD_LEVEL5;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_LEVEL5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xk_modifiers & ControlMask) {
|
/* If a latch or lock was activated by a keypress, the latch/lock will
|
||||||
if (!(viddata->xkb.sdl_modifiers & SDL_KMOD_CTRL)) {
|
* be tied to the specific left/right key that initiated it. Otherwise,
|
||||||
viddata->xkb.sdl_modifiers |= SDL_KMOD_CTRL;
|
* the ambiguous left/right combo is used.
|
||||||
|
*
|
||||||
|
* The modifier will remain active until the latch/lock is released by
|
||||||
|
* the system.
|
||||||
|
*/
|
||||||
|
if (viddata->keyboard.locked_modifiers & ShiftMask) {
|
||||||
|
if (viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_SHIFT) {
|
||||||
|
viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_SHIFT;
|
||||||
|
viddata->keyboard.sdl_locked_modifiers |= (viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_SHIFT);
|
||||||
|
} else if (!(viddata->keyboard.sdl_locked_modifiers & SDL_KMOD_SHIFT)) {
|
||||||
|
viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_SHIFT;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
viddata->xkb.sdl_modifiers &= ~SDL_KMOD_CTRL;
|
viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mod1 is used for the Alt keys
|
if (viddata->keyboard.locked_modifiers & ControlMask) {
|
||||||
if (xk_modifiers & Mod1Mask) {
|
if (viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_CTRL) {
|
||||||
if (!(viddata->xkb.sdl_modifiers & SDL_KMOD_ALT)) {
|
viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_CTRL;
|
||||||
viddata->xkb.sdl_modifiers |= SDL_KMOD_ALT;
|
viddata->keyboard.sdl_locked_modifiers |= (viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_CTRL);
|
||||||
|
} else if (!(viddata->keyboard.sdl_locked_modifiers & SDL_KMOD_CTRL)) {
|
||||||
|
viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_CTRL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
viddata->xkb.sdl_modifiers &= ~SDL_KMOD_ALT;
|
viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_CTRL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mod4 is used for the Super (aka GUI/Logo) keys.
|
if (viddata->keyboard.locked_modifiers & viddata->keyboard.alt_mask) {
|
||||||
if (xk_modifiers & Mod4Mask) {
|
if (viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_ALT) {
|
||||||
if (!(viddata->xkb.sdl_modifiers & SDL_KMOD_GUI)) {
|
viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_ALT;
|
||||||
viddata->xkb.sdl_modifiers |= SDL_KMOD_GUI;
|
viddata->keyboard.sdl_locked_modifiers |= (viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_ALT);
|
||||||
|
} else if (!(viddata->keyboard.sdl_locked_modifiers & SDL_KMOD_ALT)) {
|
||||||
|
viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_ALT;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
viddata->xkb.sdl_modifiers &= ~SDL_KMOD_GUI;
|
viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_ALT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mod3 is typically Level 5 shift.
|
if (viddata->keyboard.locked_modifiers & viddata->keyboard.gui_mask) {
|
||||||
if (xk_modifiers & Mod3Mask) {
|
if (viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_GUI) {
|
||||||
viddata->xkb.sdl_modifiers |= SDL_KMOD_LEVEL5;
|
viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_GUI;
|
||||||
|
viddata->keyboard.sdl_locked_modifiers |= (viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_GUI);
|
||||||
|
} else if (!(viddata->keyboard.sdl_locked_modifiers & SDL_KMOD_GUI)) {
|
||||||
|
viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_GUI;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
viddata->xkb.sdl_modifiers &= ~SDL_KMOD_LEVEL5;
|
viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_GUI;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mod5 is typically Level 3 shift (aka AltGr).
|
if (viddata->keyboard.locked_modifiers & viddata->keyboard.level3_mask) {
|
||||||
if (xk_modifiers & Mod5Mask) {
|
viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_MODE;
|
||||||
viddata->xkb.sdl_modifiers |= SDL_KMOD_MODE;
|
|
||||||
} else {
|
} else {
|
||||||
viddata->xkb.sdl_modifiers &= ~SDL_KMOD_MODE;
|
viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xk_modifiers & LockMask) {
|
if (viddata->keyboard.locked_modifiers & viddata->keyboard.level5_mask) {
|
||||||
viddata->xkb.sdl_modifiers |= SDL_KMOD_CAPS;
|
viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_LEVEL5;
|
||||||
} else {
|
} else {
|
||||||
viddata->xkb.sdl_modifiers &= ~SDL_KMOD_CAPS;
|
viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_LEVEL5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xk_modifiers & viddata->xkb.numlock_mask) {
|
// Capslock, Numlock, and Scrolllock can only be locked, not pressed.
|
||||||
viddata->xkb.sdl_modifiers |= SDL_KMOD_NUM;
|
if (viddata->keyboard.locked_modifiers & LockMask) {
|
||||||
|
viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_CAPS;
|
||||||
} else {
|
} else {
|
||||||
viddata->xkb.sdl_modifiers &= ~SDL_KMOD_NUM;
|
viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_CAPS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xk_modifiers & viddata->xkb.scrolllock_mask) {
|
if (viddata->keyboard.locked_modifiers & viddata->keyboard.numlock_mask) {
|
||||||
viddata->xkb.sdl_modifiers |= SDL_KMOD_SCROLL;
|
viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_NUM;
|
||||||
} else {
|
} else {
|
||||||
viddata->xkb.sdl_modifiers &= ~SDL_KMOD_SCROLL;
|
viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_NUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_SetModState(viddata->xkb.sdl_modifiers);
|
if (viddata->keyboard.locked_modifiers & viddata->keyboard.scrolllock_mask) {
|
||||||
|
viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_SCROLL;
|
||||||
|
} else {
|
||||||
|
viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_SCROLL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_SetModState(viddata->keyboard.sdl_pressed_modifiers | viddata->keyboard.sdl_locked_modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void X11_HandleModifierKeys(SDL_VideoData *viddata, SDL_Scancode scancode, bool pressed, bool allow_reconciliation)
|
static void X11_HandleModifierKeys(SDL_VideoData *viddata, SDL_Scancode scancode, bool pressed)
|
||||||
{
|
{
|
||||||
const SDL_Keycode keycode = SDL_GetKeyFromScancode(scancode, SDL_KMOD_NONE, false);
|
const SDL_Keycode keycode = SDL_GetKeyFromScancode(scancode, SDL_KMOD_NONE, false);
|
||||||
SDL_Keymod mod = SDL_KMOD_NONE;
|
SDL_Keymod mod = SDL_KMOD_NONE;
|
||||||
bool reconcile = false;
|
|
||||||
|
|
||||||
/* SDL clients expect modifier state to be activated at the same time as the
|
/* SDL clients expect modifier state to be activated at the same time as the
|
||||||
* source keypress, so we set pressed modifier state with the usual modifier
|
* source keypress, so we set pressed modifier state with the usual modifier
|
||||||
@@ -378,48 +486,46 @@ static void X11_HandleModifierKeys(SDL_VideoData *viddata, SDL_Scancode scancode
|
|||||||
case SDLK_NUMLOCKCLEAR:
|
case SDLK_NUMLOCKCLEAR:
|
||||||
case SDLK_SCROLLLOCK:
|
case SDLK_SCROLLLOCK:
|
||||||
{
|
{
|
||||||
/* For locking modifier keys, query the lock state directly, or we may have to wait until the next
|
// XKB provides the latched/locked state explicitly.
|
||||||
* key press event to know if a lock was actually activated from the key event.
|
if (viddata->keyboard.xkb_enabled) {
|
||||||
*/
|
/* For locking modifier keys, query the lock state directly, or we may have to wait until the next
|
||||||
unsigned int cur_mask = viddata->xkb.xkb_modifiers;
|
* key press event to know if a lock was actually activated from the key event.
|
||||||
X11_UpdateSystemKeyModifiers(viddata);
|
*/
|
||||||
|
unsigned int cur_mask = viddata->keyboard.locked_modifiers;
|
||||||
|
X11_UpdateSystemKeyModifiers(viddata);
|
||||||
|
|
||||||
if (viddata->xkb.xkb_modifiers & LockMask) {
|
if (viddata->keyboard.locked_modifiers & LockMask) {
|
||||||
cur_mask |= LockMask;
|
cur_mask |= LockMask;
|
||||||
} else {
|
} else {
|
||||||
cur_mask &= ~LockMask;
|
cur_mask &= ~LockMask;
|
||||||
}
|
}
|
||||||
if (viddata->xkb.xkb_modifiers & viddata->xkb.numlock_mask) {
|
if (viddata->keyboard.locked_modifiers & viddata->keyboard.numlock_mask) {
|
||||||
cur_mask |= viddata->xkb.numlock_mask;
|
cur_mask |= viddata->keyboard.numlock_mask;
|
||||||
} else {
|
} else {
|
||||||
cur_mask &= ~viddata->xkb.numlock_mask;
|
cur_mask &= ~viddata->keyboard.numlock_mask;
|
||||||
}
|
}
|
||||||
if (viddata->xkb.xkb_modifiers & viddata->xkb.scrolllock_mask) {
|
if (viddata->keyboard.locked_modifiers & viddata->keyboard.scrolllock_mask) {
|
||||||
cur_mask |= viddata->xkb.scrolllock_mask;
|
cur_mask |= viddata->keyboard.scrolllock_mask;
|
||||||
} else {
|
} else {
|
||||||
cur_mask &= ~viddata->xkb.scrolllock_mask;
|
cur_mask &= ~viddata->keyboard.scrolllock_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
viddata->xkb.xkb_modifiers = cur_mask;
|
viddata->keyboard.locked_modifiers = cur_mask;
|
||||||
} SDL_FALLTHROUGH;
|
}
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
reconcile = true;
|
return;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
viddata->xkb.sdl_modifiers |= mod;
|
viddata->keyboard.sdl_pressed_modifiers |= mod;
|
||||||
|
viddata->keyboard.sdl_physically_pressed_modifiers |= mod;
|
||||||
} else {
|
} else {
|
||||||
viddata->xkb.sdl_modifiers &= ~mod;
|
viddata->keyboard.sdl_pressed_modifiers &= ~mod;
|
||||||
|
viddata->keyboard.sdl_physically_pressed_modifiers &= ~mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allow_reconciliation) {
|
X11_ReconcileModifiers(viddata, true);
|
||||||
if (reconcile) {
|
|
||||||
X11_ReconcileModifiers(viddata);
|
|
||||||
} else {
|
|
||||||
SDL_SetModState(viddata->xkb.sdl_modifiers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void X11_ReconcileKeyboardState(SDL_VideoDevice *_this)
|
void X11_ReconcileKeyboardState(SDL_VideoDevice *_this)
|
||||||
@@ -427,18 +533,25 @@ void X11_ReconcileKeyboardState(SDL_VideoDevice *_this)
|
|||||||
SDL_VideoData *videodata = _this->internal;
|
SDL_VideoData *videodata = _this->internal;
|
||||||
Display *display = videodata->display;
|
Display *display = videodata->display;
|
||||||
char keys[32];
|
char keys[32];
|
||||||
int keycode;
|
|
||||||
const bool *keyboardState;
|
// Rebuild the modifier state in case it changed while focus was lost.
|
||||||
|
X11_UpdateSystemKeyModifiers(videodata);
|
||||||
|
X11_ReconcileModifiers(videodata, false);
|
||||||
|
|
||||||
|
// Keep caps, num, and scroll, but clear the others until we have updated key state.
|
||||||
|
videodata->keyboard.sdl_pressed_modifiers = 0;
|
||||||
|
videodata->keyboard.sdl_physically_pressed_modifiers = 0;
|
||||||
|
videodata->keyboard.sdl_locked_modifiers &= SDL_KMOD_CAPS | SDL_KMOD_NUM | SDL_KMOD_SCROLL;
|
||||||
|
videodata->keyboard.pressed_modifiers = 0;
|
||||||
|
videodata->keyboard.locked_modifiers &= LockMask | videodata->keyboard.numlock_mask| videodata->keyboard.scrolllock_mask;
|
||||||
|
|
||||||
X11_XQueryKeymap(display, keys);
|
X11_XQueryKeymap(display, keys);
|
||||||
|
|
||||||
keyboardState = SDL_GetKeyboardState(0);
|
for (Uint32 keycode = 0; keycode < SDL_arraysize(videodata->keyboard.key_layout); ++keycode) {
|
||||||
for (keycode = 0; keycode < SDL_arraysize(videodata->key_layout); ++keycode) {
|
const SDL_Scancode scancode = videodata->keyboard.key_layout[keycode];
|
||||||
SDL_Scancode scancode = videodata->key_layout[keycode];
|
const bool x11KeyPressed = (keys[keycode / 8] & (1 << (keycode % 8))) != 0;
|
||||||
bool x11KeyPressed = (keys[keycode / 8] & (1 << (keycode % 8))) != 0;
|
|
||||||
bool sdlKeyPressed = keyboardState[scancode];
|
|
||||||
|
|
||||||
if (x11KeyPressed && !sdlKeyPressed) {
|
if (x11KeyPressed) {
|
||||||
// Only update modifier state for keys that are pressed in another application
|
// Only update modifier state for keys that are pressed in another application
|
||||||
switch (SDL_GetKeyFromScancode(scancode, SDL_KMOD_NONE, false)) {
|
switch (SDL_GetKeyFromScancode(scancode, SDL_KMOD_NONE, false)) {
|
||||||
case SDLK_LCTRL:
|
case SDLK_LCTRL:
|
||||||
@@ -451,20 +564,18 @@ void X11_ReconcileKeyboardState(SDL_VideoDevice *_this)
|
|||||||
case SDLK_RGUI:
|
case SDLK_RGUI:
|
||||||
case SDLK_MODE:
|
case SDLK_MODE:
|
||||||
case SDLK_LEVEL5_SHIFT:
|
case SDLK_LEVEL5_SHIFT:
|
||||||
X11_HandleModifierKeys(videodata, scancode, true, false);
|
X11_HandleModifierKeys(videodata, scancode, true);
|
||||||
SDL_SendKeyboardKeyIgnoreModifiers(0, SDL_GLOBAL_KEYBOARD_ID, keycode, scancode, true);
|
SDL_SendKeyboardKeyIgnoreModifiers(0, SDL_GLOBAL_KEYBOARD_ID, keycode, scancode, true);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (!x11KeyPressed && sdlKeyPressed) {
|
|
||||||
X11_HandleModifierKeys(videodata, scancode, false, false);
|
|
||||||
SDL_SendKeyboardKeyIgnoreModifiers(0, SDL_GLOBAL_KEYBOARD_ID, keycode, scancode, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the latched/locked state for modifiers other than Caps, Num, and Scroll lock.
|
||||||
X11_UpdateSystemKeyModifiers(videodata);
|
X11_UpdateSystemKeyModifiers(videodata);
|
||||||
X11_ReconcileModifiers(videodata);
|
X11_ReconcileModifiers(videodata, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void X11_DispatchFocusIn(SDL_VideoDevice *_this, SDL_WindowData *data)
|
static void X11_DispatchFocusIn(SDL_VideoDevice *_this, SDL_WindowData *data)
|
||||||
@@ -933,7 +1044,7 @@ void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_
|
|||||||
Status status = 0;
|
Status status = 0;
|
||||||
bool handled_by_ime = false;
|
bool handled_by_ime = false;
|
||||||
bool pressed = (xevent->type == KeyPress);
|
bool pressed = (xevent->type == KeyPress);
|
||||||
SDL_Scancode scancode = videodata->key_layout[keycode];
|
SDL_Scancode scancode = videodata->keyboard.key_layout[keycode];
|
||||||
Uint64 timestamp = X11_GetEventTimestamp(xevent->xkey.time);
|
Uint64 timestamp = X11_GetEventTimestamp(xevent->xkey.time);
|
||||||
|
|
||||||
#ifdef DEBUG_XEVENTS
|
#ifdef DEBUG_XEVENTS
|
||||||
@@ -951,7 +1062,12 @@ void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_
|
|||||||
#endif // DEBUG SCANCODES
|
#endif // DEBUG SCANCODES
|
||||||
|
|
||||||
text[0] = '\0';
|
text[0] = '\0';
|
||||||
videodata->xkb.xkb_modifiers = xevent->xkey.state;
|
|
||||||
|
// XKB updates the modifiers explicitly via a state event.
|
||||||
|
if (!videodata->keyboard.xkb_enabled) {
|
||||||
|
videodata->keyboard.pressed_modifiers = xevent->xkey.state & (ShiftMask | ControlMask | Mod1Mask | Mod3Mask | Mod4Mask | Mod5Mask);
|
||||||
|
videodata->keyboard.locked_modifiers = xevent->xkey.state & (LockMask | videodata->keyboard.numlock_mask | videodata->keyboard.scrolllock_mask);
|
||||||
|
}
|
||||||
|
|
||||||
if (SDL_TextInputActive(windowdata->window)) {
|
if (SDL_TextInputActive(windowdata->window)) {
|
||||||
// filter events catches XIM events and sends them to the correct handler
|
// filter events catches XIM events and sends them to the correct handler
|
||||||
@@ -979,7 +1095,7 @@ void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_
|
|||||||
|
|
||||||
if (!handled_by_ime) {
|
if (!handled_by_ime) {
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
X11_HandleModifierKeys(videodata, scancode, true, true);
|
X11_HandleModifierKeys(videodata, scancode, true);
|
||||||
SDL_SendKeyboardKeyIgnoreModifiers(timestamp, keyboardID, keycode, scancode, true);
|
SDL_SendKeyboardKeyIgnoreModifiers(timestamp, keyboardID, keycode, scancode, true);
|
||||||
|
|
||||||
if (*text && !(SDL_GetModState() & (SDL_KMOD_CTRL | SDL_KMOD_ALT))) {
|
if (*text && !(SDL_GetModState() & (SDL_KMOD_CTRL | SDL_KMOD_ALT))) {
|
||||||
@@ -993,7 +1109,7 @@ void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
X11_HandleModifierKeys(videodata, scancode, false, true);
|
X11_HandleModifierKeys(videodata, scancode, false);
|
||||||
SDL_SendKeyboardKeyIgnoreModifiers(timestamp, keyboardID, keycode, scancode, false);
|
SDL_SendKeyboardKeyIgnoreModifiers(timestamp, keyboardID, keycode, scancode, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1225,37 +1341,78 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
|
|||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
// The window for KeymapNotify, etc events is 0
|
// The window for KeymapNotify, etc events is 0
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB
|
||||||
|
if (videodata->keyboard.xkb_enabled && xevent->type == videodata->keyboard.xkb.event) {
|
||||||
|
XkbEvent *xkbevent = (XkbEvent *)xevent;
|
||||||
|
switch (xkbevent->any.xkb_type) {
|
||||||
|
case XkbStateNotify:
|
||||||
|
{
|
||||||
|
#ifdef DEBUG_XEVENTS
|
||||||
|
SDL_Log("window 0x%lx: XkbStateNotify!", xevent->xany.window);
|
||||||
|
#endif
|
||||||
|
if ((xkbevent->state.changed & XkbGroupStateMask) && xkbevent->state.group != videodata->keyboard.xkb.current_group) {
|
||||||
|
videodata->keyboard.xkb.current_group = xkbevent->state.group;
|
||||||
|
SDL_SetKeymap(videodata->keyboard.xkb.keymaps[videodata->keyboard.xkb.current_group], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xkbevent->state.changed & XkbModifierStateMask) {
|
||||||
|
videodata->keyboard.pressed_modifiers = xkbevent->state.base_mods;
|
||||||
|
videodata->keyboard.locked_modifiers = xkbevent->state.latched_mods | xkbevent->state.locked_mods;
|
||||||
|
X11_ReconcileModifiers(videodata, false);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case XkbMapNotify:
|
||||||
|
#ifdef DEBUG_XEVENTS
|
||||||
|
SDL_Log("window 0x%lx: XkbMapNotify!", xevent->xany.window);
|
||||||
|
SDL_FALLTHROUGH;
|
||||||
|
#endif
|
||||||
|
case XkbNewKeyboardNotify:
|
||||||
|
{
|
||||||
|
#ifdef DEBUG_XEVENTS
|
||||||
|
if (xkbevent->any.xkb_type == XkbNewKeyboardNotify) {
|
||||||
|
SDL_Log("window 0x%lx: XkbNewKeyboardNotify!", xevent->xany.window);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
X11_XkbRefreshKeyboardMapping(&xkbevent->map);
|
||||||
|
|
||||||
|
// Don't redundantly rebuild the keymap if this is a duplicate event.
|
||||||
|
if (xkbevent->any.serial != videodata->keyboard.xkb.last_map_serial) {
|
||||||
|
videodata->keyboard.xkb.last_map_serial = xkbevent->any.serial;
|
||||||
|
X11_UpdateKeymap(_this, true);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
if (xevent->type == KeymapNotify) {
|
if (xevent->type == KeymapNotify) {
|
||||||
#ifdef DEBUG_XEVENTS
|
#ifdef DEBUG_XEVENTS
|
||||||
SDL_Log("window 0x%lx: KeymapNotify!", xevent->xany.window);
|
SDL_Log("window 0x%lx: KeymapNotify!", xevent->xany.window);
|
||||||
#endif
|
#endif
|
||||||
if (SDL_GetKeyboardFocus() != NULL) {
|
if (!videodata->keyboard.xkb_enabled) {
|
||||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
|
if (SDL_GetKeyboardFocus() != NULL) {
|
||||||
if (videodata->xkb.desc_ptr) {
|
X11_UpdateKeymap(_this, true);
|
||||||
XkbStateRec state;
|
|
||||||
if (X11_XkbGetState(videodata->display, XkbUseCoreKbd, &state) == Success) {
|
|
||||||
if (state.group != videodata->xkb.current_group) {
|
|
||||||
// Only rebuild the keymap if the layout has changed.
|
|
||||||
videodata->xkb.current_group = state.group;
|
|
||||||
X11_UpdateKeymap(_this, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
X11_ReconcileKeyboardState(_this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
X11_ReconcileKeyboardState(_this);
|
||||||
} else if (xevent->type == MappingNotify) {
|
} else if (xevent->type == MappingNotify) {
|
||||||
// Has the keyboard layout changed?
|
if (!videodata->keyboard.xkb_enabled) {
|
||||||
const int request = xevent->xmapping.request;
|
// Has the keyboard layout changed?
|
||||||
|
const int request = xevent->xmapping.request;
|
||||||
|
|
||||||
#ifdef DEBUG_XEVENTS
|
#ifdef DEBUG_XEVENTS
|
||||||
SDL_Log("window 0x%lx: MappingNotify!", xevent->xany.window);
|
SDL_Log("window 0x%lx: MappingNotify!", xevent->xany.window);
|
||||||
#endif
|
#endif
|
||||||
if ((request == MappingKeyboard) || (request == MappingModifier)) {
|
if ((request == MappingKeyboard) || (request == MappingModifier)) {
|
||||||
X11_XRefreshKeyboardMapping(&xevent->xmapping);
|
X11_XRefreshKeyboardMapping(&xevent->xmapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
X11_UpdateKeymap(_this, true);
|
X11_UpdateKeymap(_this, true);
|
||||||
|
}
|
||||||
} else if (xevent->type == PropertyNotify && videodata && videodata->windowlist) {
|
} else if (xevent->type == PropertyNotify && videodata && videodata->windowlist) {
|
||||||
char *name_of_atom = X11_XGetAtomName(display, xevent->xproperty.atom);
|
char *name_of_atom = X11_XGetAtomName(display, xevent->xproperty.atom);
|
||||||
|
|
||||||
|
@@ -28,7 +28,10 @@
|
|||||||
#include "../../events/SDL_scancode_tables_c.h"
|
#include "../../events/SDL_scancode_tables_c.h"
|
||||||
|
|
||||||
#include <X11/keysym.h>
|
#include <X11/keysym.h>
|
||||||
|
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB
|
||||||
#include <X11/XKBlib.h>
|
#include <X11/XKBlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "../../events/imKStoUCS.h"
|
#include "../../events/imKStoUCS.h"
|
||||||
#include "../../events/SDL_keysym_to_scancode_c.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
|
// 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)
|
||||||
{
|
{
|
||||||
@@ -82,48 +107,6 @@ static SDL_Scancode X11_KeyCodeToSDLScancode(SDL_VideoDevice *_this, KeyCode key
|
|||||||
return SDL_GetScancodeFromKeySym(keysym, keycode);
|
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)
|
bool X11_InitKeyboard(SDL_VideoDevice *_this)
|
||||||
{
|
{
|
||||||
SDL_VideoData *data = _this->internal;
|
SDL_VideoData *data = _this->internal;
|
||||||
@@ -146,21 +129,33 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this)
|
|||||||
int best_distance;
|
int best_distance;
|
||||||
int best_index;
|
int best_index;
|
||||||
int distance;
|
int distance;
|
||||||
Bool xkb_repeat = 0;
|
|
||||||
|
|
||||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
|
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB
|
||||||
{
|
int xkb_major = XkbMajorVersion;
|
||||||
int xkb_major = XkbMajorVersion;
|
int xkb_minor = XkbMinorVersion;
|
||||||
int xkb_minor = XkbMinorVersion;
|
|
||||||
|
|
||||||
if (X11_XkbQueryExtension(data->display, NULL, &data->xkb.event, NULL, &xkb_major, &xkb_minor)) {
|
if (X11_XkbQueryExtension(data->display, NULL, &data->keyboard.xkb.event, NULL, &xkb_major, &xkb_minor)) {
|
||||||
data->xkb.desc_ptr = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd);
|
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);
|
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
|
#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
|
// Open a connection to the X input manager
|
||||||
#ifdef X_HAVE_UTF8_STRING
|
#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);
|
SDL_Log("Using scancode set %d, min_keycode = %d, max_keycode = %d, table_size = %d", best_index, min_keycode, max_keycode, table_size);
|
||||||
#endif
|
#endif
|
||||||
// This should never happen, but just in case...
|
// This should never happen, but just in case...
|
||||||
if (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->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.
|
/* 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
|
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));
|
(unsigned int)sym, sym == NoSymbol ? "NoSymbol" : X11_XKeysymToString(sym));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (scancode == data->key_layout[i]) {
|
if (scancode == data->keyboard.key_layout[i]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((SDL_GetKeymapKeycode(NULL, scancode, SDL_KMOD_NONE) & (SDLK_SCANCODE_MASK | SDLK_EXTENDED_MASK)) && X11_ScancodeIsRemappable(scancode)) {
|
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
|
#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));
|
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
|
#endif
|
||||||
data->key_layout[i] = scancode;
|
data->keyboard.key_layout[i] = scancode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -293,7 +288,7 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this)
|
|||||||
SDL_Log("scancode = %d (%s)", scancode, SDL_GetScancodeName(scancode));
|
SDL_Log("scancode = %d (%s)", scancode, SDL_GetScancodeName(scancode));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
data->key_layout[i] = scancode;
|
data->keyboard.key_layout[i] = scancode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,149 +301,235 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this)
|
|||||||
return true;
|
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;
|
SDL_VideoData *videodata = _this->internal;
|
||||||
Display *display = videodata->display;
|
Display *display = videodata->display;
|
||||||
unsigned num_mask = 0;
|
unsigned int mod_mask = 0;
|
||||||
int i, j;
|
|
||||||
XModifierKeymap *xmods;
|
|
||||||
unsigned n;
|
|
||||||
|
|
||||||
xmods = X11_XGetModifierMapping(display);
|
XModifierKeymap *xmods = X11_XGetModifierMapping(display);
|
||||||
n = xmods->max_keypermod;
|
unsigned int n = xmods->max_keypermod;
|
||||||
for (i = 3; i < 8; i++) {
|
for (int i = 3; i < 8; i++) {
|
||||||
for (j = 0; j < n; j++) {
|
for (int j = 0; j < n; j++) {
|
||||||
KeyCode kc = xmods->modifiermap[i * n + j];
|
const KeyCode kc = xmods->modifiermap[i * n + j];
|
||||||
if (videodata->key_layout[kc] == SDL_SCANCODE_NUMLOCKCLEAR) {
|
if (videodata->keyboard.key_layout[kc] == scancode) {
|
||||||
num_mask = 1 << i;
|
mod_mask = 1 << i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
X11_XFreeModifiermap(xmods);
|
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;
|
SDL_Keycode keycode = SDL_GetKeyCodeFromKeySym(xkeysym, xkeycode, sdl_mod_mask);
|
||||||
Display *display = videodata->display;
|
|
||||||
unsigned num_mask = 0;
|
|
||||||
int i, j;
|
|
||||||
XModifierKeymap *xmods;
|
|
||||||
unsigned n;
|
|
||||||
|
|
||||||
xmods = X11_XGetModifierMapping(display);
|
if (!keycode) {
|
||||||
n = xmods->max_keypermod;
|
switch (sdl_scancode) {
|
||||||
for (i = 3; i < 8; i++) {
|
case SDL_SCANCODE_RETURN:
|
||||||
for (j = 0; j < n; j++) {
|
keycode = SDLK_RETURN;
|
||||||
KeyCode kc = xmods->modifiermap[i * n + j];
|
break;
|
||||||
if (videodata->key_layout[kc] == SDL_SCANCODE_SCROLLLOCK) {
|
case SDL_SCANCODE_ESCAPE:
|
||||||
num_mask = 1 << i;
|
keycode = SDLK_ESCAPE;
|
||||||
break;
|
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)
|
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_VideoData *data = _this->internal;
|
||||||
SDL_Scancode scancode;
|
|
||||||
SDL_Keymap *keymap = SDL_CreateKeymap(true);
|
|
||||||
|
|
||||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
|
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB
|
||||||
if (data->xkb.desc_ptr) {
|
if (data->keyboard.xkb_enabled) {
|
||||||
XkbStateRec state;
|
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) {
|
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) {
|
data->keyboard.alt_mask = X11_GetXkbVirtualModifierMask(_this, "Alt");
|
||||||
for (int i = 0; i < SDL_arraysize(data->key_layout); ++i) {
|
if (!data->keyboard.alt_mask) {
|
||||||
// Make sure this is a valid scancode
|
data->keyboard.alt_mask = X11_GetXkbVirtualModifierMask(_this, "Meta");
|
||||||
scancode = data->key_layout[i];
|
}
|
||||||
|
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) {
|
if (scancode == SDL_SCANCODE_UNKNOWN) {
|
||||||
continue;
|
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) {
|
Uint32 effective_group = group;
|
||||||
SDL_Keycode keycode = SDL_GetKeyCodeFromKeySym(keysym, i, keymod_masks[m].sdl_mask);
|
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) {
|
if (max_key_group && effective_group >= max_key_group) {
|
||||||
switch (scancode) {
|
const unsigned char action = XkbOutOfRangeGroupAction(key_group_info);
|
||||||
case SDL_SCANCODE_RETURN:
|
|
||||||
keycode = SDLK_RETURN;
|
switch (action) {
|
||||||
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:
|
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;
|
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);
|
SDL_SetKeymap(data->keyboard.xkb.keymaps[data->keyboard.xkb.current_group], send_event);
|
||||||
data->xkb.scrolllock_mask = X11_GetScrollLockModifierMask(_this);
|
} else
|
||||||
SDL_SetKeymap(keymap, send_event);
|
#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)
|
void X11_QuitKeyboard(SDL_VideoDevice *_this)
|
||||||
{
|
{
|
||||||
SDL_VideoData *data = _this->internal;
|
SDL_VideoData *data = _this->internal;
|
||||||
|
|
||||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
|
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB
|
||||||
if (data->xkb.desc_ptr) {
|
if (data->keyboard.xkb_enabled) {
|
||||||
X11_XkbFreeKeyboard(data->xkb.desc_ptr, 0, True);
|
for (int i = 0; i < XkbNumKbdGroups; ++i) {
|
||||||
data->xkb.desc_ptr = NULL;
|
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
|
#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)
|
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_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
|
||||||
extern void X11_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
|
extern void X11_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
|
||||||
extern bool X11_IsScreenKeyboardShown(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_
|
#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(void,XFreeStringList,(char** a))
|
||||||
SDL_X11_SYM(char*,XGetAtomName,(Display *a,Atom b))
|
SDL_X11_SYM(char*,XGetAtomName,(Display *a,Atom b))
|
||||||
SDL_X11_SYM(int,XGetInputFocus,(Display *a,Window *b,int *c))
|
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(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(XModifierKeymap*,XGetModifierMapping,(Display* a))
|
||||||
SDL_X11_SYM(int,XGetPointerControl,(Display* a,int* b,int* c,int* d))
|
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))
|
SDL_X11_SYM(void,XFreeEventData,(Display* a,XGenericEventCookie* b))
|
||||||
#endif
|
#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))
|
SDL_X11_SYM(Bool,XkbQueryExtension,(Display* a,int * b,int * c,int * d,int * e, int *f))
|
||||||
#if NeedWidePrototypes
|
SDL_X11_SYM(KeySym,XkbKeycodeToKeysym,(Display* a, KeyCode b, unsigned int c, unsigned int d))
|
||||||
SDL_X11_SYM(Bool,XkbLookupKeySym,(Display* a, unsigned int b, unsigned int c, unsigned int* d, KeySym* e))
|
SDL_X11_SYM(Bool,XkbSelectEvents,(Display* a, unsigned int b, unsigned int c, unsigned long d))
|
||||||
#else
|
SDL_X11_SYM(Bool,XkbSelectEventDetails,(Display* a, unsigned int b, unsigned int c, unsigned long d, unsigned long e))
|
||||||
SDL_X11_SYM(Bool,XkbLookupKeySym,(Display* a, KeyCode b, unsigned int c, unsigned int* d, KeySym* e))
|
SDL_X11_SYM(Status,XkbGetNames,(Display *a, unsigned int b, XkbDescPtr c))
|
||||||
#endif
|
|
||||||
SDL_X11_SYM(Status,XkbGetState,(Display* a,unsigned int b,XkbStatePtr 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(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(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,XkbFreeClientMap,(XkbDescPtr a,unsigned int b, Bool c))
|
||||||
SDL_X11_SYM(void,XkbFreeKeyboard,(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))
|
SDL_X11_SYM(Bool,XkbSetDetectableAutoRepeat,(Display* a, Bool b, Bool* c))
|
||||||
#endif
|
#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
|
#ifdef X_HAVE_UTF8_STRING
|
||||||
SDL_X11_MODULE(UTF8)
|
SDL_X11_MODULE(UTF8)
|
||||||
SDL_X11_SYM(int,Xutf8TextListToTextProperty,(Display* a,char** b,int c,XICCEncodingStyle d,XTextProperty* e))
|
SDL_X11_SYM(int,Xutf8TextListToTextProperty,(Display* a,char** b,int c,XICCEncodingStyle d,XTextProperty* e))
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
#define SDL_x11video_h_
|
#define SDL_x11video_h_
|
||||||
|
|
||||||
#include "../SDL_sysvideo.h"
|
#include "../SDL_sysvideo.h"
|
||||||
|
#include "../../events/SDL_keymap_c.h"
|
||||||
|
|
||||||
#include "../../core/linux/SDL_dbus.h"
|
#include "../../core/linux/SDL_dbus.h"
|
||||||
#include "../../core/linux/SDL_ime.h"
|
#include "../../core/linux/SDL_ime.h"
|
||||||
@@ -125,7 +126,6 @@ struct SDL_VideoData
|
|||||||
Atom pen_atom_wacom_tool_type;
|
Atom pen_atom_wacom_tool_type;
|
||||||
} atoms;
|
} atoms;
|
||||||
|
|
||||||
SDL_Scancode key_layout[256];
|
|
||||||
bool selection_waiting;
|
bool selection_waiting;
|
||||||
bool selection_incr_waiting;
|
bool selection_incr_waiting;
|
||||||
|
|
||||||
@@ -144,21 +144,43 @@ struct SDL_VideoData
|
|||||||
int xrandr_event_base;
|
int xrandr_event_base;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
|
bool xkb_enabled;
|
||||||
XkbDescPtr desc_ptr;
|
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
|
#endif
|
||||||
int event;
|
struct
|
||||||
unsigned int current_group;
|
{
|
||||||
unsigned int xkb_modifiers;
|
KeySym *keysym_map;
|
||||||
|
int keysyms_per_key;
|
||||||
SDL_Keymod sdl_modifiers;
|
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 numlock_mask;
|
||||||
Uint32 scrolllock_mask;
|
Uint32 scrolllock_mask;
|
||||||
} xkb;
|
} keyboard;
|
||||||
|
|
||||||
KeyCode filter_code;
|
|
||||||
Time filter_time;
|
|
||||||
|
|
||||||
#ifdef SDL_VIDEO_VULKAN
|
#ifdef SDL_VIDEO_VULKAN
|
||||||
// Vulkan variables only valid if _this->vulkan_config.loader_handle is not NULL
|
// Vulkan variables only valid if _this->vulkan_config.loader_handle is not NULL
|
||||||
|
Reference in New Issue
Block a user