diff --git a/xbanish.1 b/xbanish.1 index 3d0f29b..c63f94a 100644 --- a/xbanish.1 +++ b/xbanish.1 @@ -8,6 +8,7 @@ .Nm .Op Fl a .Op Fl d +.Op Fl k .Op Fl i Ar modifier .Op Fl m Oo Ar w Oc Ns Ar nw|ne|sw|se|\(+-x\(+-y .Op Fl t Ar seconds @@ -29,6 +30,8 @@ Always keep mouse cursor hidden while is running. .It Fl d Print debugging messages to stdout. +.It Fl k +Keep the cursor visible after touch screen events. .It Fl i Ar modifier Ignore pressed key if .Ar modifier diff --git a/xbanish.c b/xbanish.c index e15f620..94d8012 100644 --- a/xbanish.c +++ b/xbanish.c @@ -21,7 +21,9 @@ #include #include #include +#include +#include #include #include #include @@ -50,7 +52,7 @@ static int device_change_type = -1; static long last_device_change = -1; static Display *dpy; -static int hiding = 0, legacy = 0, always_hide = 0, ignore_scroll = 0; +static int hiding = 0, legacy = 0, always_hide = 0, keep_touch_cursor = 0, ignore_scroll = 0; static unsigned timeout = 0; static unsigned char ignored; static XSyncCounter idler_counter = 0; @@ -94,7 +96,7 @@ main(int argc, char *argv[]) {"all", -1}, }; - while ((ch = getopt(argc, argv, "adi:m:t:s")) != -1) + while ((ch = getopt(argc, argv, "adki:m:t:s")) != -1) switch (ch) { case 'a': always_hide = 1; @@ -102,6 +104,9 @@ main(int argc, char *argv[]) case 'd': debug = 1; break; + case 'k': + keep_touch_cursor = 1; + break; case 'i': for (i = 0; i < sizeof(mods) / sizeof(struct mod_lookup); i++) @@ -181,117 +186,164 @@ main(int argc, char *argv[]) errx(1, "no idle counter"); } - for (;;) { - cookie = &e.xcookie; - XNextEvent(dpy, &e); - - int etype = e.type; - if (e.type == motion_type) - etype = MotionNotify; - else if (e.type == key_press_type || - e.type == key_release_type) - etype = KeyRelease; - else if (e.type == button_press_type || - e.type == button_release_type) - etype = ButtonRelease; - else if (e.type == device_change_type) { - XDevicePresenceNotifyEvent *xdpe = - (XDevicePresenceNotifyEvent *)&e; - if (last_device_change == xdpe->serial) - continue; - snoop_root(); - last_device_change = xdpe->serial; - continue; - } + fd_set in_fds; + struct timeval tv; + int x11_fd = ConnectionNumber(dpy); + int js_fd = open("/dev/input/js0", O_RDONLY); + struct js_event je; - switch (etype) { - case KeyRelease: - if (ignored) { - unsigned int state = 0; + if (js_fd != -1) + DPRINTF(("attaching to controller\n")); - /* masks are only set on key release, if - * ignore is set we must throw out non-release - * events here */ - if (e.type == key_press_type) { - break; - } - - /* extract modifier state */ - if (e.type == key_release_type) { - /* xinput device event */ - XDeviceKeyEvent *key = - (XDeviceKeyEvent *) &e; - state = key->state; - } else if (e.type == KeyRelease) { - /* legacy event */ - state = e.xkey.state; - } - - if (state & ignored) { - DPRINTF(("ignoring key %d\n", state)); - break; - } + for (;;) { + FD_ZERO(&in_fds); + FD_SET(x11_fd, &in_fds); + FD_SET(js_fd, &in_fds); + tv.tv_usec = 0; + tv.tv_sec = 1; + + // Wait for X Event, Joystick or a Timer + int max_fd = (x11_fd > js_fd) ? x11_fd : js_fd; + int num_ready_fds = select(max_fd + 1, &in_fds, NULL, NULL, &tv); + if (num_ready_fds < 0) + errx(1, "failed reading socket"); + else if (num_ready_fds == 0) { + if (js_fd == -1 && access("/dev/input/js0", R_OK) != -1) { + js_fd = open("/dev/input/js0", O_RDONLY); + DPRINTF(("attaching to controller\n")); } + }; - hide_cursor(); - break; - - case ButtonRelease: - case MotionNotify: - if (!always_hide) - show_cursor(); - break; - - case CreateNotify: - if (legacy) { - DPRINTF(("new window, snooping on it\n")); + if (FD_ISSET(js_fd, &in_fds)) { + if (read (js_fd, &je, sizeof(je)) == -1) { + close(js_fd); + js_fd = -1; + DPRINTF(("disconnected controller\n")); + } + if (!(je.type & JS_EVENT_INIT) && je.value != 0) { + hide_cursor(); + } + } - /* not sure why snooping directly on the window - * doesn't work, so snoop on all windows from - * its parent (probably root) */ - snoop_legacy(e.xcreatewindow.parent); + cookie = &e.xcookie; + while(XPending(dpy)) { + XNextEvent(dpy, &e); + + int etype = e.type; + if (e.type == motion_type) + etype = MotionNotify; + else if (e.type == key_press_type || + e.type == key_release_type) + etype = KeyRelease; + else if (e.type == button_press_type || + e.type == button_release_type) + etype = ButtonRelease; + else if (e.type == device_change_type) { + XDevicePresenceNotifyEvent *xdpe = + (XDevicePresenceNotifyEvent *)&e; + if (last_device_change == xdpe->serial) + continue; + snoop_root(); + last_device_change = xdpe->serial; + continue; } - break; - case GenericEvent: - /* xi2 raw event */ - XGetEventData(dpy, cookie); - XIDeviceEvent *xie = (XIDeviceEvent *)cookie->data; + switch (etype) { + case KeyRelease: + if (ignored) { + unsigned int state = 0; + + /* masks are only set on key release, if + * ignore is set we must throw out non-release + * events here */ + if (e.type == key_press_type) { + break; + } + + /* extract modifier state */ + if (e.type == key_release_type) { + /* xinput device event */ + XDeviceKeyEvent *key = + (XDeviceKeyEvent *) &e; + state = key->state; + } else if (e.type == KeyRelease) { + /* legacy event */ + state = e.xkey.state; + } + + if (state & ignored) { + DPRINTF(("ignoring key %d\n", state)); + break; + } + } - switch (xie->evtype) { - case XI_RawMotion: - case XI_RawButtonPress: - if (ignore_scroll && ((xie->detail >= 4 && xie->detail <= 7) || - xie->event_x == xie->event_y)) - break; + hide_cursor(); + break; + + case ButtonRelease: + case MotionNotify: if (!always_hide) show_cursor(); break; - case XI_RawButtonRelease: + case CreateNotify: + if (legacy) { + DPRINTF(("new window, snooping on it\n")); + + /* not sure why snooping directly on the window + * doesn't work, so snoop on all windows from + * its parent (probably root) */ + snoop_legacy(e.xcreatewindow.parent); + } break; - default: - DPRINTF(("unknown XI event type %d\n", - xie->evtype)); - } + case GenericEvent: + /* xi2 raw event */ + XGetEventData(dpy, cookie); + XIDeviceEvent *xie = (XIDeviceEvent *)cookie->data; + + switch (xie->evtype) { + case XI_RawMotion: + case XI_RawButtonPress: + if (ignore_scroll && ((xie->detail >= 4 && xie->detail <= 7) || + xie->event_x == xie->event_y)) + break; + if (!always_hide) + show_cursor(); + break; - XFreeEventData(dpy, cookie); - break; + case XI_RawButtonRelease: + break; - default: - if (!timeout || - e.type != (sync_event + XSyncAlarmNotify)) { - DPRINTF(("unknown event type %d\n", e.type)); + case XI_RawTouchBegin: + case XI_RawTouchEnd: + case XI_RawTouchUpdate: + if (!keep_touch_cursor) + hide_cursor(); + break; + + default: + DPRINTF(("unknown XI event type %d\n", + xie->evtype)); + } + + XFreeEventData(dpy, cookie); break; - } - alarm_e = (XSyncAlarmNotifyEvent *)&e; - if (alarm_e->alarm == idle_alarm) { - DPRINTF(("idle counter reached %dms, hiding " - "cursor\n", - XSyncValueLow32(alarm_e->counter_value))); - hide_cursor(); + default: + if (!timeout || + e.type != (sync_event + XSyncAlarmNotify)) { + DPRINTF(("unknown event type %d\n", e.type)); + break; + } + + alarm_e = (XSyncAlarmNotifyEvent *)&e; + if (alarm_e->alarm == idle_alarm) { + DPRINTF(("idle counter reached %dms, hiding " + "cursor\n", + XSyncValueLow32(alarm_e->counter_value))); + hide_cursor(); + } } } } @@ -437,6 +489,7 @@ snoop_xinput(Window win) XISetMask(mask, XI_RawMotion); XISetMask(mask, XI_RawButtonPress); + XISetMask(mask, XI_RawTouchBegin); evmasks[0].deviceid = XIAllMasterDevices; evmasks[0].mask_len = sizeof(mask); evmasks[0].mask = mask; @@ -587,7 +640,7 @@ set_alarm(XSyncAlarm *alarm, XSyncTestType test) void usage(char *progname) { - fprintf(stderr, "usage: %s [-a] [-d] [-i mod] [-m [w]nw|ne|sw|se|+/-xy] " + fprintf(stderr, "usage: %s [-a] [-d] [-k] [-i mod] [-m [w]nw|ne|sw|se|+/-xy] " "[-t seconds] [-s]\n", progname); exit(1); }