diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c
index 72ad194c6..6d568a90d 100644
--- a/src/video/x11/SDL_x11events.c
+++ b/src/video/x11/SDL_x11events.c
@@ -832,6 +832,99 @@ SDL_WindowData *X11_FindWindow(SDL_VideoDevice *_this, Window window)
return NULL;
}
+void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_KeyboardID keyboardID, XEvent *xevent)
+{
+ SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
+ Display *display = videodata->display;
+ KeyCode keycode = xevent->xkey.keycode;
+ KeySym keysym = NoSymbol;
+ char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
+ Status status = 0;
+ SDL_bool handled_by_ime = SDL_FALSE;
+
+ /* Save the original keycode for dead keys, which are filtered out by
+ the XFilterEvent() call below.
+ */
+ int orig_event_type = xevent->type;
+ KeyCode orig_keycode = xevent->xkey.keycode;
+
+ /* filter events catches XIM events and sends them to the correct handler */
+ if (X11_XFilterEvent(xevent, None)) {
+#if 0
+ printf("Filtered event type = %d display = %d window = %d\n",
+ xevent->type, xevent->xany.display, xevent->xany.window);
+#endif
+ /* Make sure dead key press/release events are sent */
+ /* But only if we're using one of the DBus IMEs, otherwise
+ some XIM IMEs will generate duplicate events */
+#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX)
+ SDL_Scancode scancode = videodata->key_layout[orig_keycode];
+ videodata->filter_code = orig_keycode;
+ videodata->filter_time = xevent->xkey.time;
+
+ if (orig_event_type == KeyPress) {
+ SDL_SendKeyboardKey(0, keyboardID, SDL_PRESSED, scancode);
+ } else {
+ SDL_SendKeyboardKey(0, keyboardID, SDL_RELEASED, scancode);
+ }
+#endif
+ return;
+ }
+
+#ifdef DEBUG_XEVENTS
+ printf("window %p: %s (X11 keycode = 0x%X)\n", data, (xevent->type == KeyPress ? "KeyPress" : "KeyRelease"), xevent->xkey.keycode);
+#endif
+#ifdef DEBUG_SCANCODES
+ if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) {
+ int min_keycode, max_keycode;
+ X11_XDisplayKeycodes(display, &min_keycode, &max_keycode);
+ keysym = X11_KeyCodeToSym(_this, keycode, xevent->xkey.state >> 13);
+ SDL_Log("The key you just pressed is not recognized by SDL. To help get this fixed, please report this to the SDL forums/mailing list X11 KeyCode %d (%d), X11 KeySym 0x%lX (%s).\n",
+ keycode, keycode - min_keycode, keysym,
+ X11_XKeysymToString(keysym));
+ }
+#endif /* DEBUG SCANCODES */
+
+ SDL_zeroa(text);
+#ifdef X_HAVE_UTF8_STRING
+ if (windowdata->ic && xevent->type == KeyPress) {
+ X11_Xutf8LookupString(windowdata->ic, &xevent->xkey, text, sizeof(text),
+ &keysym, &status);
+ } else {
+ XLookupStringAsUTF8(&xevent->xkey, text, sizeof(text), &keysym, NULL);
+ }
+#else
+ XLookupStringAsUTF8(&xevent->xkey, text, sizeof(text), &keysym, NULL);
+#endif
+
+#ifdef SDL_USE_IME
+ if (SDL_TextInputActive()) {
+ handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode, (xevent->type == KeyPress ? SDL_PRESSED : SDL_RELEASED));
+ }
+#endif
+ if (!handled_by_ime) {
+ if (xevent->type == KeyPress) {
+ /* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */
+ if (xevent->xkey.keycode != videodata->filter_code || xevent->xkey.time != videodata->filter_time) {
+ SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, SDL_PRESSED, videodata->key_layout[keycode]);
+ }
+ if (*text) {
+ SDL_SendKeyboardText(text);
+ }
+ } else {
+ if (X11_KeyRepeat(display, xevent)) {
+ /* We're about to get a repeated key down, ignore the key up */
+ return;
+ }
+ SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, SDL_RELEASED, videodata->key_layout[keycode]);
+ }
+ }
+
+ if (xevent->type == KeyPress) {
+ X11_UpdateUserTime(windowdata, xevent->xkey.time);
+ }
+}
+
void X11_HandleButtonPress(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_MouseID mouseID, int button, const float x, const float y, const unsigned long time)
{
SDL_Window *window = windowdata->window;
@@ -923,47 +1016,22 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
SDL_VideoData *videodata = _this->driverdata;
Display *display;
SDL_WindowData *data;
- int orig_event_type;
- KeyCode orig_keycode;
XClientMessageEvent m;
int i;
SDL_assert(videodata != NULL);
display = videodata->display;
- /* Save the original keycode for dead keys, which are filtered out by
- the XFilterEvent() call below.
- */
- orig_event_type = xevent->type;
- if (orig_event_type == KeyPress || orig_event_type == KeyRelease) {
- orig_keycode = xevent->xkey.keycode;
- } else {
- orig_keycode = 0;
- }
-
/* filter events catches XIM events and sends them to the correct handler */
- if (X11_XFilterEvent(xevent, None) == True) {
+ /* Key press/release events are filtered in X11_HandleKeyEvent() */
+ if (xevent->type != KeyPress && xevent->type != KeyRelease) {
+ if (X11_XFilterEvent(xevent, None)) {
#if 0
- printf("Filtered event type = %d display = %d window = %d\n",
- xevent->type, xevent->xany.display, xevent->xany.window);
-#endif
- /* Make sure dead key press/release events are sent */
- /* But only if we're using one of the DBus IMEs, otherwise
- some XIM IMEs will generate duplicate events */
- if (orig_keycode) {
-#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX)
- SDL_Scancode scancode = videodata->key_layout[orig_keycode];
- videodata->filter_code = orig_keycode;
- videodata->filter_time = xevent->xkey.time;
-
- if (orig_event_type == KeyPress) {
- SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, SDL_PRESSED, scancode);
- } else {
- SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, SDL_RELEASED, scancode);
- }
+ printf("Filtered event type = %d display = %d window = %d\n",
+ xevent->type, xevent->xany.display, xevent->xany.window);
#endif
+ return;
}
- return;
}
#ifdef SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
@@ -1217,69 +1285,6 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
#endif /* SDL_VIDEO_DRIVER_X11_XFIXES */
} break;
- /* Key press/release? */
- case KeyPress:
- case KeyRelease:
- {
- KeyCode keycode = xevent->xkey.keycode;
- KeySym keysym = NoSymbol;
- char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
- Status status = 0;
- SDL_bool handled_by_ime = SDL_FALSE;
-
-#ifdef DEBUG_XEVENTS
- printf("window %p: %s (X11 keycode = 0x%X)\n", data, (xevent->type == KeyPress ? "KeyPress" : "KeyRelease"), xevent->xkey.keycode);
-#endif
-#ifdef DEBUG_SCANCODES
- if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) {
- int min_keycode, max_keycode;
- X11_XDisplayKeycodes(display, &min_keycode, &max_keycode);
- keysym = X11_KeyCodeToSym(_this, keycode, xevent->xkey.state >> 13);
- SDL_Log("The key you just pressed is not recognized by SDL. To help get this fixed, please report this to the SDL forums/mailing list X11 KeyCode %d (%d), X11 KeySym 0x%lX (%s).\n",
- keycode, keycode - min_keycode, keysym,
- X11_XKeysymToString(keysym));
- }
-#endif /* DEBUG SCANCODES */
-
- SDL_zeroa(text);
-#ifdef X_HAVE_UTF8_STRING
- if (data->ic && xevent->type == KeyPress) {
- X11_Xutf8LookupString(data->ic, &xevent->xkey, text, sizeof(text),
- &keysym, &status);
- } else {
- XLookupStringAsUTF8(&xevent->xkey, text, sizeof(text), &keysym, NULL);
- }
-#else
- XLookupStringAsUTF8(&xevent->xkey, text, sizeof(text), &keysym, NULL);
-#endif
-
-#ifdef SDL_USE_IME
- if (SDL_TextInputActive()) {
- handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode, (xevent->type == KeyPress ? SDL_PRESSED : SDL_RELEASED));
- }
-#endif
- if (!handled_by_ime) {
- if (xevent->type == KeyPress) {
- /* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */
- if (xevent->xkey.keycode != videodata->filter_code || xevent->xkey.time != videodata->filter_time) {
- SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, SDL_PRESSED, videodata->key_layout[keycode]);
- }
- if (*text) {
- SDL_SendKeyboardText(text);
- }
- } else {
- if (X11_KeyRepeat(display, xevent)) {
- /* We're about to get a repeated key down, ignore the key up */
- break;
- }
- SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, SDL_RELEASED, videodata->key_layout[keycode]);
- }
- }
-
- if (xevent->type == KeyPress) {
- X11_UpdateUserTime(data, xevent->xkey.time);
- }
- } break;
/* Have we been iconified? */
case UnmapNotify:
@@ -1511,11 +1516,19 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
} break;
/* Use XInput2 instead of the xevents API if possible, for:
+ - KeyPress
+ - KeyRelease
- MotionNotify
- ButtonPress
- ButtonRelease
XInput2 has more precise information, e.g., to distinguish different input devices. */
#ifndef SDL_VIDEO_DRIVER_X11_XINPUT2
+ case KeyPress:
+ case KeyRelease:
+ {
+ X11_HandleKeyEvent(_this, data, SDL_GLOBAL_KEYBOARD_ID, xevent);
+ } break;
+
case MotionNotify:
{
SDL_Mouse *mouse = SDL_GetMouse();
diff --git a/src/video/x11/SDL_x11events.h b/src/video/x11/SDL_x11events.h
index 911d9102e..4a95a558a 100644
--- a/src/video/x11/SDL_x11events.h
+++ b/src/video/x11/SDL_x11events.h
@@ -29,8 +29,9 @@ extern void X11_SendWakeupEvent(SDL_VideoDevice *_this, SDL_Window *window);
extern int X11_SuspendScreenSaver(SDL_VideoDevice *_this);
extern void X11_ReconcileKeyboardState(SDL_VideoDevice *_this);
extern void X11_GetBorderValues(SDL_WindowData *data);
-extern void X11_HandleButtonPress(SDL_VideoDevice *_this, SDL_WindowData *wdata, SDL_MouseID mouseID, int button, const float x, const float y, const unsigned long time);
-extern void X11_HandleButtonRelease(SDL_VideoDevice *_this, SDL_WindowData *wdata, SDL_MouseID mouseID, int button);
+extern void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_KeyboardID keyboardID, XEvent *xevent);
+extern void X11_HandleButtonPress(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_MouseID mouseID, int button, const float x, const float y, const unsigned long time);
+extern void X11_HandleButtonRelease(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_MouseID mouseID, int button);
extern SDL_WindowData *X11_FindWindow(SDL_VideoDevice *_this, Window window);
extern SDL_bool X11_ProcessHitTest(SDL_VideoDevice *_this, SDL_WindowData *data, const float x, const float y, SDL_bool force_new_result);
extern SDL_bool X11_TriggerHitTestAction(SDL_VideoDevice *_this, SDL_WindowData *data, const float x, const float y);
diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c
index dfd9975ec..f056abb2d 100644
--- a/src/video/x11/SDL_x11window.c
+++ b/src/video/x11/SDL_x11window.c
@@ -794,16 +794,17 @@ int X11_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesI
X11_Xinput2SelectTouch(_this, window);
{
+ unsigned int x11_keyboard_events = KeyPressMask | KeyReleaseMask;
unsigned int x11_pointer_events = ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
- if (X11_Xinput2SelectMouse(_this, window)) {
- /* If XInput2 can handle pointer events, we don't track them here */
+ if (X11_Xinput2SelectMouseAndKeyboard(_this, window)) {
+ /* If XInput2 can handle pointer and keyboard events, we don't track them here */
+ x11_keyboard_events = 0;
x11_pointer_events = 0;
}
X11_XSelectInput(display, w,
(FocusChangeMask | EnterWindowMask | LeaveWindowMask | ExposureMask |
- x11_pointer_events |
- KeyPressMask | KeyReleaseMask |
+ x11_keyboard_events | x11_pointer_events |
PropertyChangeMask | StructureNotifyMask |
KeymapStateMask | fevent));
}
diff --git a/src/video/x11/SDL_x11xinput2.c b/src/video/x11/SDL_x11xinput2.c
index 03bb87cd2..e599e0e5c 100644
--- a/src/video/x11/SDL_x11xinput2.c
+++ b/src/video/x11/SDL_x11xinput2.c
@@ -423,6 +423,41 @@ int X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
X11_InitPen(_this);
} break;
+ case XI_KeyPress:
+ case XI_KeyRelease:
+ {
+ const XIDeviceEvent *xev = (const XIDeviceEvent *)cookie->data;
+ SDL_WindowData *windowdata = X11_FindWindow(_this, xev->event);
+ XEvent xevent;
+
+ if (xev->deviceid != xev->sourceid) {
+ /* Discard events from "Master" devices to avoid duplicates. */
+ return 1;
+ }
+
+ if (cookie->evtype == XI_KeyPress) {
+ xevent.type = KeyPress;
+ } else {
+ xevent.type = KeyRelease;
+ }
+ xevent.xkey.serial = xev->serial;
+ xevent.xkey.send_event = xev->send_event;
+ xevent.xkey.display = xev->display;
+ xevent.xkey.window = xev->event;
+ xevent.xkey.root = xev->root;
+ xevent.xkey.subwindow = xev->child;
+ xevent.xkey.time = xev->time;
+ xevent.xkey.x = xev->event_x;
+ xevent.xkey.y = xev->event_y;
+ xevent.xkey.x_root = xev->root_x;
+ xevent.xkey.y_root = xev->root_y;
+ xevent.xkey.state = xev->mods.effective;
+ xevent.xkey.keycode = xev->detail;
+ xevent.xkey.same_screen = 1;
+
+ X11_HandleKeyEvent(_this, windowdata, (SDL_KeyboardID)xev->sourceid, &xevent);
+ } break;
+
case XI_RawButtonPress:
case XI_RawButtonRelease:
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
@@ -608,7 +643,7 @@ int X11_Xinput2IsInitialized(void)
#endif
}
-SDL_bool X11_Xinput2SelectMouse(SDL_VideoDevice *_this, SDL_Window *window)
+SDL_bool X11_Xinput2SelectMouseAndKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
{
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
const SDL_VideoData *data = (SDL_VideoData *)_this->driverdata;
@@ -620,6 +655,8 @@ SDL_bool X11_Xinput2SelectMouse(SDL_VideoDevice *_this, SDL_Window *window)
eventmask.mask = mask;
eventmask.deviceid = XIAllDevices;
+ XISetMask(mask, XI_KeyPress);
+ XISetMask(mask, XI_KeyRelease);
XISetMask(mask, XI_ButtonPress);
XISetMask(mask, XI_ButtonRelease);
XISetMask(mask, XI_Motion);
diff --git a/src/video/x11/SDL_x11xinput2.h b/src/video/x11/SDL_x11xinput2.h
index e67e1cb4c..b0f749fa5 100644
--- a/src/video/x11/SDL_x11xinput2.h
+++ b/src/video/x11/SDL_x11xinput2.h
@@ -38,6 +38,6 @@ extern int X11_Xinput2IsMultitouchSupported(void);
extern void X11_Xinput2SelectTouch(SDL_VideoDevice *_this, SDL_Window *window);
extern void X11_Xinput2GrabTouch(SDL_VideoDevice *_this, SDL_Window *window);
extern void X11_Xinput2UngrabTouch(SDL_VideoDevice *_this, SDL_Window *window);
-extern SDL_bool X11_Xinput2SelectMouse(SDL_VideoDevice *_this, SDL_Window *window);
+extern SDL_bool X11_Xinput2SelectMouseAndKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
#endif /* SDL_x11xinput2_h_ */