Hello

Attached is a patch for the syndaemon of the synaptics driver. It prevents
the
polling of the keyboard state. Instead it uses the XRecord extension of the
Xserver for an event triggered notification of key events. Of course, there
is a fallback to the polling when no XRecord extension is found. This should

finally stop complains of syndaemon preventing good power saving.

Comments are welcome.

Best regards

Andre Herms
From 31f2d5252fc4aa88bb9ced49b59bd541c5e6faad Mon Sep 17 00:00:00 2001
From: Andre Herms <aherms(ae)ivs(d)cs(d)uni-magdeburg(d)de>
Date: Thu, 9 Oct 2008 21:59:48 +0200
Subject: [PATCH] use Xrecord extension in syndaemon to avoid polling.

---
 configure.ac      |   27 ++++---
 tools/Makefile.am |    2 +-
 tools/syndaemon.c |  220 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 226 insertions(+), 23 deletions(-)

diff --git a/configure.ac b/configure.ac
index 69f1041..23c9f26 100644
--- a/configure.ac
+++ b/configure.ac
@@ -22,9 +22,9 @@
 
 AC_PREREQ(2.57)
 AC_INIT([xf86-input-synaptics],
-        0.15.2,
-        [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
-        xf86-input-synaptics)
+	0.15.2,
+	[https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
+	xf86-input-synaptics)
 
 AC_CONFIG_SRCDIR([Makefile.am])
 AC_CONFIG_AUX_DIR(.)
@@ -90,10 +90,10 @@ fi
 #fi
 
 AC_ARG_WITH(xorg-module-dir,
-            AC_HELP_STRING([--with-xorg-module-dir=DIR],
-                           [Default xorg module directory [[default=$libdir/xorg/modules]]]),
-            [moduledir="$withval"],
-            [moduledir="$libdir/xorg/modules"])
+	    AC_HELP_STRING([--with-xorg-module-dir=DIR],
+			   [Default xorg module directory [[default=$libdir/xorg/modules]]]),
+	    [moduledir="$withval"],
+	    [moduledir="$libdir/xorg/modules"])
 inputdir=${moduledir}/input
 AC_SUBST(inputdir)
 
@@ -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
@@ -119,9 +120,9 @@ XORG_MANPAGE_SECTIONS
 XORG_RELEASE_VERSION
 
 AC_OUTPUT([Makefile
-           src/Makefile
-           man/Makefile
-           tools/Makefile
-           fdi/Makefile
-           include/Makefile
-           xorg-synaptics.pc])
+	   src/Makefile
+	   man/Makefile
+	   tools/Makefile
+	   fdi/Makefile
+	   include/Makefile
+	   xorg-synaptics.pc])
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..d4cfd4c 100644
--- a/tools/syndaemon.c
+++ b/tools/syndaemon.c
@@ -29,6 +29,9 @@
 #endif
 
 #include <X11/Xlib.h>
+#include <X11/Xproto.h>
+#include <X11/extensions/record.h>
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
@@ -45,6 +48,7 @@ static SynapticsSHM *synshm;
 static int pad_disabled;
 static int disable_taps_only;
 static int ignore_modifier_combos;
+static int ignore_modifier_keys = 0;
 static int background;
 static const char *pid_file;
 
@@ -64,6 +68,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);
 }
 
@@ -166,7 +171,7 @@ touchpad_buttons_active(void)
 	if (synshm->multi[i])
 	    return 1;
     if (synshm->guest_left || synshm->guest_mid || synshm->guest_right)
-        return 1;
+	return 1;
     return 0;
 }
 
@@ -243,6 +248,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;
+    /*printf("something happend, category=%d\n", recorded_data->category); */
+
+    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. */
+
+	    /* 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, &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) * 100000.;
+
+	    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 +444,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 +472,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 +530,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;
 }
-- 
1.5.6.5

_______________________________________________
xorg mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/xorg

Reply via email to