Skip to content

Instantly share code, notes, and snippets.

@LemonBoy
Last active July 2, 2016 12:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LemonBoy/dfe1d7ea428794c65b3d to your computer and use it in GitHub Desktop.
Save LemonBoy/dfe1d7ea428794c65b3d to your computer and use it in GitHub Desktop.
// 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