Last active
July 2, 2016 12:10
-
-
Save LemonBoy/dfe1d7ea428794c65b3d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// gcc grab.c -lxcb -lxcb-xfixes -lxcb-xinput -Wall -o grab | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <signal.h> | |
#include <errno.h> | |
#include <sys/select.h> | |
#include <sys/time.h> | |
#include <xcb/xcb.h> | |
#include <xcb/xinput.h> | |
#include <xcb/xfixes.h> | |
#include <xcb/xcb_event.h> | |
static int timeout = 4; | |
static int running = 1; | |
void signal_handler (int signal) { | |
(void)signal; | |
running = 0; | |
} | |
int main (int argc, char **argv) { | |
xcb_connection_t *c; | |
xcb_screen_t *scr; | |
xcb_generic_event_t *ev; | |
const xcb_query_extension_reply_t *qe_reply; | |
xcb_xfixes_query_version_cookie_t qv_cookie; | |
xcb_xfixes_query_version_reply_t *qv_reply; | |
fd_set fds; | |
int xfd, rc, hidden = 0; | |
struct timeval tv; | |
c = xcb_connect(NULL, NULL); | |
xfd = xcb_get_file_descriptor(c); | |
scr = xcb_setup_roots_iterator(xcb_get_setup(c)).data; | |
qe_reply = xcb_get_extension_data(c, &xcb_xfixes_id); | |
if (qe_reply && qe_reply->present) { | |
// We *must* negotiate the XFIXES version with the server | |
qv_cookie = xcb_xfixes_query_version(c, | |
XCB_XFIXES_MAJOR_VERSION, | |
XCB_XFIXES_MINOR_VERSION); | |
qv_reply = xcb_xfixes_query_version_reply(c, qv_cookie, NULL); | |
if (qv_reply->major_version < 4) { | |
fputs("Unsupported XFIXES version\n", stderr); | |
free(qv_reply); | |
return 1; | |
} | |
free(qv_reply); | |
} | |
else { | |
fputs("The XFIXES extension is required\n", stderr); | |
return 1; | |
} | |
struct { | |
xcb_input_event_mask_t head; | |
xcb_input_xi_event_mask_t mask; | |
} mask; | |
mask.head.deviceid = XCB_INPUT_DEVICE_ALL; | |
mask.head.mask_len = sizeof(mask.mask) / sizeof(uint32_t); | |
mask.mask = XCB_INPUT_XI_EVENT_MASK_MOTION; | |
// Grab the input events non-invasively using XInput | |
xcb_input_xi_select_events(c, scr->root, 1, &mask.head); | |
xcb_flush(c); | |
signal(SIGTERM, signal_handler); | |
signal(SIGQUIT, signal_handler); | |
signal(SIGINT, signal_handler); | |
signal(SIGHUP, signal_handler); | |
while (running) { | |
FD_ZERO(&fds); | |
FD_SET(xfd, &fds); | |
tv.tv_usec = 0; | |
tv.tv_sec = timeout; | |
rc = select(xfd + 1, &fds, NULL, NULL, &tv); | |
if (rc < 0) { | |
if (errno == EINTR) | |
break; | |
perror("select()"); | |
break; | |
} | |
// Timeout | |
if (!FD_ISSET(xfd, &fds)) { | |
if (!hidden) { | |
// xcb_warp_pointer(c, XCB_NONE, scr->root, 0, 0, 0, 0, 0, 0); | |
xcb_xfixes_hide_cursor(c, scr->root); | |
hidden = 1; | |
} | |
} | |
else { | |
if (xcb_connection_has_error(c)) | |
break; | |
while ((ev = xcb_poll_for_event(c))) { | |
// The generic events are the one coming from XInput | |
if (hidden && (ev->response_type & ~80) == XCB_GE_GENERIC) { | |
switch (((xcb_ge_event_t *)ev)->event_type) { | |
case XCB_INPUT_MOTION: | |
{ | |
xcb_input_motion_event_t *mot = (xcb_input_motion_event_t *)ev; | |
unsigned char *mask = (unsigned char *)ev + | |
sizeof(xcb_input_motion_event_t) + | |
mot->buttons_len * 4; | |
// Avoid scroll events | |
if ((mask[0] & 8) != 8) { | |
xcb_xfixes_show_cursor(c, scr->root); | |
hidden = 0; | |
} | |
break; | |
} | |
} | |
} | |
free(ev); | |
} | |
} | |
xcb_flush(c); | |
} | |
xcb_disconnect(c); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment