use Xrecord extension for event triggered key event notification

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Christoph Brill <egore911@egore911.de>
Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
This commit is contained in:
Andre Herms
2008-11-11 21:15:30 +01:00
committed by Peter Hutterer
parent 97530109c3
commit eda5153312
4 changed files with 218 additions and 8 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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);
}
}
#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);
setup_keyboard_mask(display, ignore_modifier_keys);
/* Run the main loop */
main_loop(display, idle_time, poll_delay);
/* Run the main loop */
main_loop(display, idle_time, poll_delay);
}
return 0;
}