From 482f5b0a26746b64c471d2e3291752dd35048e73 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 23 Feb 2020 19:43:43 +0100 Subject: [PATCH] WIP: xinput support related to #112 --- Makefile.am | 4 +- configure.ac | 2 +- i3lock.c | 4 ++ xcb.c | 7 ++- xinput.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++ xinput.h | 11 ++++ 6 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 xinput.c create mode 100644 xinput.h diff --git a/Makefile.am b/Makefile.am index 5847975..b722233 100644 --- a/Makefile.am +++ b/Makefile.am @@ -48,7 +48,9 @@ i3lock_SOURCES = \ unlock_indicator.c \ unlock_indicator.h \ xcb.c \ - xcb.h + xcb.h \ + xinput.h \ + xinput.c EXTRA_DIST = \ $(pamd_files) \ diff --git a/configure.ac b/configure.ac index 474f750..ef51a4a 100644 --- a/configure.ac +++ b/configure.ac @@ -90,7 +90,7 @@ AC_SEARCH_LIBS([iconv_open], [iconv], , [AC_MSG_FAILURE([cannot find the require dnl Each prefix corresponds to a source tarball which users might have dnl downloaded in a newer version and would like to overwrite. -PKG_CHECK_MODULES([XCB], [xcb xcb-xkb xcb-xinerama xcb-randr]) +PKG_CHECK_MODULES([XCB], [xcb xcb-xkb xcb-xinerama xcb-randr xcb-xinput]) PKG_CHECK_MODULES([XCB_IMAGE], [xcb-image]) PKG_CHECK_MODULES([XCB_UTIL], [xcb-event xcb-util xcb-atom]) PKG_CHECK_MODULES([XCB_UTIL_XRM], [xcb-xrm]) diff --git a/i3lock.c b/i3lock.c index 134fdda..7823a3f 100644 --- a/i3lock.c +++ b/i3lock.c @@ -47,6 +47,7 @@ #include "unlock_indicator.h" #include "randr.h" #include "dpi.h" +#include "xinput.h" #define TSTAMP_N_SECS(n) (n * 1.0) #define TSTAMP_N_MINS(n) (60 * TSTAMP_N_SECS(n)) @@ -1196,6 +1197,8 @@ int main(int argc, char *argv[]) { randr_init(&randr_base, screen->root); randr_query(screen->root); + xinput_init(); + last_resolution[0] = screen->width_in_pixels; last_resolution[1] = screen->height_in_pixels; @@ -1310,6 +1313,7 @@ int main(int argc, char *argv[]) { DEBUG("restoring focus to X11 window 0x%08x\n", stolen_focus); xcb_ungrab_pointer(conn, XCB_CURRENT_TIME); xcb_ungrab_keyboard(conn, XCB_CURRENT_TIME); + xinput_ungrab(); xcb_destroy_window(conn, win); set_focused_window(conn, screen->root, stolen_focus); xcb_aux_sync(conn); diff --git a/xcb.c b/xcb.c index 2867a47..f7e83c0 100644 --- a/xcb.c +++ b/xcb.c @@ -23,6 +23,7 @@ #include "cursors.h" #include "unlock_indicator.h" +#include "xinput.h" extern auth_state_t auth_state; @@ -303,7 +304,11 @@ bool grab_pointer_and_keyboard(xcb_connection_t *conn, xcb_screen_t *screen, xcb } } - return (tries > 0); + if (tries == 0) { + return false; + } + + return xinput_grab(screen->root); } xcb_cursor_t create_cursor(xcb_connection_t *conn, xcb_screen_t *screen, xcb_window_t win, int choice) { diff --git a/xinput.c b/xinput.c new file mode 100644 index 0000000..b559dde --- /dev/null +++ b/xinput.c @@ -0,0 +1,139 @@ +/* + * vim:ts=4:sw=4:expandtab + * + * © 2010 Michael Stapelberg + * + * See LICENSE for licensing information + * + */ +#include "xinput.h" + +#include +#include +#include +#include +#include +#include + +#include "i3lock.h" +#include "xcb.h" + +extern bool debug_mode; + +static bool xinput_available = false; + +void xinput_init(void) { + const xcb_query_extension_reply_t *extreply; + + extreply = xcb_get_extension_data(conn, &xcb_input_id); + if (!extreply->present) { + DEBUG("xinput is not present\n"); + return; + } + + DEBUG("xinput: querying version\n"); + xcb_generic_error_t *err = NULL; + xcb_input_xi_query_version_reply_t *xinput_version = + xcb_input_xi_query_version_reply( + conn, xcb_input_xi_query_version(conn, XCB_INPUT_MAJOR_VERSION, XCB_INPUT_MINOR_VERSION), &err); + if (err != NULL) { + DEBUG("Could not query xinput version: X11 error code %d\n", err->error_code); + return; + } + DEBUG("xinput %d.%d found\n", + xinput_version->major_version, + xinput_version->minor_version); + free(xinput_version); + + xinput_available = true; +} + +bool xinput_grab(xcb_window_t root_window) { + if (!xinput_available) { + return true; + } + + xcb_generic_error_t *err = NULL; + xcb_input_xi_query_device_reply_t *devices = + xcb_input_xi_query_device_reply( + conn, xcb_input_xi_query_device(conn, XCB_INPUT_DEVICE_ALL_MASTER), &err); + if (err != NULL) { + DEBUG("xinput: querying devices: X11 error code %d\n", err->error_code); + return false; + } + + xcb_input_xi_device_info_iterator_t device_iter; + for (device_iter = xcb_input_xi_query_device_infos_iterator(devices); + device_iter.rem; + xcb_input_xi_device_info_next(&device_iter)) { + xcb_input_xi_device_info_t *device_info = device_iter.data; + DEBUG("device %s\n", + xcb_input_xi_device_info_name(device_info)); + // TODO: skip virtual core pointer/keyboard + + const uint32_t mask = + XCB_INPUT_XI_EVENT_MASK_BUTTON_PRESS | + XCB_INPUT_XI_EVENT_MASK_BUTTON_RELEASE | + XCB_INPUT_XI_EVENT_MASK_MOTION | + XCB_INPUT_XI_EVENT_MASK_ENTER | + XCB_INPUT_XI_EVENT_MASK_LEAVE; + + xcb_input_xi_grab_device_reply_t *reply = + xcb_input_xi_grab_device_reply( + conn, + xcb_input_xi_grab_device(conn, + root_window, + XCB_TIME_CURRENT_TIME, + XCB_CURSOR_NONE, + device_info->deviceid, + XCB_INPUT_GRAB_MODE_22_ASYNC, + XCB_INPUT_GRAB_MODE_22_ASYNC, + true /* owner_events */, + 1, + &mask), + &err); + if (err != NULL) { + DEBUG("xinput: grabbing device %s: X11 error code %d\n", + xcb_input_xi_device_info_name(device_info), + err->error_code); + free(devices); + return false; + } + if (reply->status != 0 /* XiGrabSuccess */) { + free(reply); + free(devices); + return false; + } + free(reply); + } + + free(devices); + return true; +} + +void xinput_ungrab(void) { + if (!xinput_available) { + return; + } + + xcb_generic_error_t *err = NULL; + xcb_input_xi_query_device_reply_t *devices = + xcb_input_xi_query_device_reply( + conn, xcb_input_xi_query_device(conn, XCB_INPUT_DEVICE_ALL_MASTER), &err); + if (err != NULL) { + DEBUG("xinput: querying devices: X11 error code %d\n", err->error_code); + return; + } + + xcb_input_xi_device_info_iterator_t device_iter; + for (device_iter = xcb_input_xi_query_device_infos_iterator(devices); + device_iter.rem; + xcb_input_xi_device_info_next(&device_iter)) { + xcb_input_xi_device_info_t *device_info = device_iter.data; + // TODO: skip virtual core pointer/keyboard + + xcb_input_xi_ungrab_device(conn, XCB_TIME_CURRENT_TIME, device_info->deviceid); + } + + free(devices); +} diff --git a/xinput.h b/xinput.h new file mode 100644 index 0000000..df951c0 --- /dev/null +++ b/xinput.h @@ -0,0 +1,11 @@ +#ifndef _XINPUT_H +#define _XINPUT_H + +#include +#include + +void xinput_init(void); +bool xinput_grab(xcb_window_t root_window); +void xinput_ungrab(void); + +#endif