diff options
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | man/syndaemon.man | 5 | ||||
-rw-r--r-- | tools/Makefile.am | 2 | ||||
-rw-r--r-- | tools/syndaemon.c | 220 |
4 files changed, 219 insertions, 9 deletions
diff --git a/configure.ac b/configure.ac index 14d035b..d2aea91 100644 --- a/configure.ac +++ b/configure.ac @@ -111,6 +111,7 @@ AC_SUBST([CFLAGS]) # Checks for libraries. PKG_CHECK_MODULES(XLIB, x11) # needed for syndaemon +PKG_CHECK_MODULES(XRECORD, xtst, AC_DEFINE([HAVE_XRECORD],[],[Use XRecord]), true) # Checks for header files. AC_HEADER_STDC diff --git a/man/syndaemon.man b/man/syndaemon.man index b9adc3d..eaaa0f0 100644 --- a/man/syndaemon.man +++ b/man/syndaemon.man @@ -48,6 +48,11 @@ Ignore modifier keys when monitoring keyboard activity. .TP \fB\-K\fP Like \-k but also ignore Modifier+Key combos. +.LP +.TP +\fB\-R\fP +Disable the use of the XRecord extension for detecting keyboard activity. +This will force the use of polling the keyboard state. .SH "ENVIRONMENT VARIABLES" .LP .TP diff --git a/tools/Makefile.am b/tools/Makefile.am index a83da60..2f2199b 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -28,4 +28,4 @@ synclient_SOURCES = synclient.c synclient_LDFLAGS = -lm syndaemon_SOURCES = syndaemon.c -syndaemon_LDFLAGS = $(XLIB_LIBS) +syndaemon_LDFLAGS = $(XLIB_LIBS) $(XRECORD_LIBS) diff --git a/tools/syndaemon.c b/tools/syndaemon.c index 7aa8238..9acbbf8 100644 --- a/tools/syndaemon.c +++ b/tools/syndaemon.c @@ -29,6 +29,11 @@ #endif #include <X11/Xlib.h> +#ifdef HAVE_XRECORD +#include <X11/Xproto.h> +#include <X11/extensions/record.h> +#endif /* HAVE_XRECORD */ + #include <stdio.h> #include <stdlib.h> #include <sys/types.h> @@ -45,6 +50,7 @@ static SynapticsSHM *synshm; static int pad_disabled; static int disable_taps_only; static int ignore_modifier_combos; +static int ignore_modifier_keys; static int background; static const char *pid_file; @@ -64,6 +70,7 @@ usage(void) fprintf(stderr, " -t Only disable tapping and scrolling, not mouse movements.\n"); fprintf(stderr, " -k Ignore modifier keys when monitoring keyboard activity.\n"); fprintf(stderr, " -K Like -k but also ignore Modifier+Key combos.\n"); + fprintf(stderr, " -R Don't use the XRecord extension.\n"); exit(1); } @@ -243,6 +250,194 @@ setup_keyboard_mask(Display *display, int ignore_modifier_keys) } } +/* ---- the following code is for using the xrecord extension ----- */ +#ifdef HAVE_XRECORD + +#define MAX_MODIFIERS 16 + +/* used for exchanging information with the callback function */ +struct xrecord_callback_results { + XModifierKeymap *modifiers; + Bool key_event; + Bool non_modifier_event; + KeyCode pressed_modifiers[MAX_MODIFIERS]; +}; + +/* test if the xrecord extension is found */ +Bool check_xrecord(Display *display) { + + Bool found; + Status status; + int major_opcode, minor_opcode, first_error; + int version[2]; + + found = XQueryExtension(display, + "RECORD", + &major_opcode, + &minor_opcode, + &first_error); + + status = XRecordQueryVersion(display, version, version+1); + if (!background && status) { + printf("X RECORD extension version %d.%d\n", version[0], version[1]); + } + return found; +} + +/* called by XRecordProcessReplies() */ +void xrecord_callback( XPointer closure, XRecordInterceptData* recorded_data) { + + struct xrecord_callback_results *cbres; + xEvent *xev; + int nxev; + + cbres = (struct xrecord_callback_results *)closure; + + if (recorded_data->category != XRecordFromServer) { + XRecordFreeData(recorded_data); + return; + } + + nxev = recorded_data->data_len / 8; + xev = (xEvent *)recorded_data->data; + while(nxev--) { + + if ( (xev->u.u.type == KeyPress) || (xev->u.u.type == KeyRelease)) { + int i; + int is_modifier = 0; + + cbres->key_event = 1; /* remember, a key was pressed or released. */ + + /* test if it was a modifier */ + for (i = 0; i < 8 * cbres->modifiers->max_keypermod; i++) { + KeyCode kc = cbres->modifiers->modifiermap[i]; + + if (kc == xev->u.u.detail) { + is_modifier = 1; /* yes, it is a modifier. */ + break; + } + } + + if (is_modifier) { + if (xev->u.u.type == KeyPress) { + for (i=0; i < MAX_MODIFIERS; ++i) + if (!cbres->pressed_modifiers[i]) { + cbres->pressed_modifiers[i] = xev->u.u.detail; + break; + } + } else { /* KeyRelease */ + for (i=0; i < MAX_MODIFIERS; ++i) + if (cbres->pressed_modifiers[i] == xev->u.u.detail) + cbres->pressed_modifiers[i] = 0; + } + + } else { + /* remember, a non-modifier was pressed. */ + cbres->non_modifier_event = 1; + } + } + + xev++; + } + + XRecordFreeData(recorded_data); /* cleanup */ +} + +static int is_modifier_pressed(const struct xrecord_callback_results *cbres) { + int i; + + for (i = 0; i < MAX_MODIFIERS; ++i) + if (cbres->pressed_modifiers[i]) + return 1; + + return 0; +} + +void record_main_loop(Display* display, double idle_time) { + + struct xrecord_callback_results cbres; + XRecordContext context; + XRecordClientSpec cspec = XRecordAllClients; + Display *dpy_data; + XRecordRange *range; + int i; + + pad_disabled = 0; + + dpy_data = XOpenDisplay(NULL); /* we need an additional data connection. */ + range = XRecordAllocRange(); + + range->device_events.first = KeyPress; + range->device_events.last = KeyRelease; + + context = XRecordCreateContext(dpy_data, 0, + &cspec,1, + &range, 1); + + XRecordEnableContextAsync(dpy_data, context, xrecord_callback, (XPointer)&cbres); + + cbres.modifiers = XGetModifierMapping(display); + /* clear list of modifiers */ + for (i = 0; i < MAX_MODIFIERS; ++i) + cbres.pressed_modifiers[i] = 0; + + while (1) { + + int fd = ConnectionNumber(dpy_data); + fd_set read_fds; + int ret; + int disable_event = 0; + struct timeval timeout; + + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + + ret = select(fd+1 /* =(max descriptor in read_fds) + 1 */, + &read_fds, NULL, NULL, + pad_disabled ? &timeout : NULL /* timeout only required for enabling */ ); + + if (FD_ISSET(fd, &read_fds)) { + + cbres.key_event = 0; + cbres.non_modifier_event = 0; + + XRecordProcessReplies(dpy_data); + + if (!ignore_modifier_keys && cbres.key_event) { + disable_event = 1; + } + + if (cbres.non_modifier_event && + !(ignore_modifier_combos && is_modifier_pressed(&cbres)) ) { + disable_event = 1; + } + } + + if (disable_event) { + /* adjust the enable_time */ + timeout.tv_sec = (int)idle_time; + timeout.tv_usec = (idle_time-(double)timeout.tv_sec) * 1.e6; + + if (!pad_disabled) { + pad_disabled=1; + if (!background) printf("disable touchpad\n"); + + if (!synshm->touchpad_off) + synshm->touchpad_off = disable_taps_only ? 2 : 1; + } + } + + if (ret == 0 && pad_disabled) { /* timeout => enable event */ + enable_touchpad(); + if (!background) printf("enable touchpad\n"); + } + + } /* end while(1) */ + + XFreeModifiermap(cbres.modifiers); +} +#endif /* HAVE_XRECORD */ + int main(int argc, char *argv[]) { @@ -251,10 +446,11 @@ main(int argc, char *argv[]) Display *display; int c; int shmid; - int ignore_modifier_keys = 0; + int use_xrecord = 1; + /* Parse command line parameters */ - while ((c = getopt(argc, argv, "i:m:dtp:kK?")) != EOF) { + while ((c = getopt(argc, argv, "i:m:dtp:kKR?")) != EOF) { switch(c) { case 'i': idle_time = atof(optarg); @@ -278,6 +474,9 @@ main(int argc, char *argv[]) ignore_modifier_combos = 1; ignore_modifier_keys = 1; break; + case 'R': + use_xrecord = 0; + break; default: usage(); break; @@ -333,11 +532,16 @@ main(int argc, char *argv[]) fclose(fd); } } - - setup_keyboard_mask(display, ignore_modifier_keys); - - /* Run the main loop */ - main_loop(display, idle_time, poll_delay); - +#ifdef HAVE_XRECORD + if (use_xrecord && check_xrecord(display)) { + record_main_loop(display, idle_time); + } else +#endif /* HAVE_XRECORD */ + { + setup_keyboard_mask(display, ignore_modifier_keys); + + /* Run the main loop */ + main_loop(display, idle_time, poll_delay); + } return 0; } |