Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hide cursor on touch events. #52

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions xbanish.1
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
245 changes: 149 additions & 96 deletions xbanish.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#include <linux/joystick.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/extensions/sync.h>
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -94,14 +96,17 @@ 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;
break;
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++)
Expand Down Expand Up @@ -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();
}
}
}
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down