summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile.am32
-rw-r--r--tools/synclient.c364
-rw-r--r--tools/syndaemon.c336
3 files changed, 732 insertions, 0 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 0000000..6fc9a4a
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,32 @@
+# Copyright 2008 Red Hat, Inc.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# on the rights to use, copy, modify, merge, publish, distribute, sub
+# license, and/or sell copies of the Software, and to permit persons to whom
+# the Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+# ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+bin_PROGRAMS = \
+ synclient \
+ syndaemon
+
+synclient_INCLUDES = $(top_srcdir)/src/
+syndaemon_INCLUDES = $(top_srcdir)/src/
+
+synclient_SOURCES = synclient.c
+synclient_LDFLAGS = -lm
+
+syndaemon_SOURCES = syndaemon.c
+syndaemon_LDFLAGS = -lXi
diff --git a/tools/synclient.c b/tools/synclient.c
new file mode 100644
index 0000000..f633988
--- /dev/null
+++ b/tools/synclient.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright © 2002-2005,2007 Peter Osterlund
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of Red Hat
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission. Red
+ * Hat makes no representations about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors:
+ * Peter Osterlund (petero2@telia.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <string.h>
+#include <stddef.h>
+#include <math.h>
+
+#include <X11/Xdefs.h>
+#include "synaptics.h"
+
+enum ParaType {
+ PT_INT,
+ PT_BOOL,
+ PT_DOUBLE
+};
+
+struct Parameter {
+ char *name; /* Name of parameter */
+ int offset; /* Offset in shared memory area */
+ enum ParaType type; /* Type of parameter */
+ double min_val; /* Minimum allowed value */
+ double max_val; /* Maximum allowed value */
+};
+
+#define DEFINE_PAR(name, memb, type, min_val, max_val) \
+{ name, offsetof(SynapticsSHM, memb), (type), (min_val), (max_val) }
+
+static struct Parameter params[] = {
+ DEFINE_PAR("LeftEdge", left_edge, PT_INT, 0, 10000),
+ DEFINE_PAR("RightEdge", right_edge, PT_INT, 0, 10000),
+ DEFINE_PAR("TopEdge", top_edge, PT_INT, 0, 10000),
+ DEFINE_PAR("BottomEdge", bottom_edge, PT_INT, 0, 10000),
+ DEFINE_PAR("FingerLow", finger_low, PT_INT, 0, 255),
+ DEFINE_PAR("FingerHigh", finger_high, PT_INT, 0, 255),
+ DEFINE_PAR("FingerPress", finger_press, PT_INT, 0, 256),
+ DEFINE_PAR("MaxTapTime", tap_time, PT_INT, 0, 1000),
+ DEFINE_PAR("MaxTapMove", tap_move, PT_INT, 0, 2000),
+ DEFINE_PAR("MaxDoubleTapTime", tap_time_2, PT_INT, 0, 1000),
+ DEFINE_PAR("SingleTapTimeout", single_tap_timeout, PT_INT, 0, 1000),
+ DEFINE_PAR("ClickTime", click_time, PT_INT, 0, 1000),
+ DEFINE_PAR("FastTaps", fast_taps, PT_BOOL, 0, 1),
+ DEFINE_PAR("EmulateMidButtonTime", emulate_mid_button_time, PT_INT, 0, 1000),
+ DEFINE_PAR("EmulateTwoFingerMinZ", emulate_twofinger_z, PT_INT, 0, 1000),
+ DEFINE_PAR("VertScrollDelta", scroll_dist_vert, PT_INT, 0, 1000),
+ DEFINE_PAR("HorizScrollDelta", scroll_dist_horiz, PT_INT, 0, 1000),
+ DEFINE_PAR("VertEdgeScroll", scroll_edge_vert, PT_BOOL, 0, 1),
+ DEFINE_PAR("HorizEdgeScroll", scroll_edge_horiz, PT_BOOL, 0, 1),
+ DEFINE_PAR("CornerCoasting", scroll_edge_corner, PT_BOOL, 0, 1),
+ DEFINE_PAR("VertTwoFingerScroll", scroll_twofinger_vert, PT_BOOL, 0, 1),
+ DEFINE_PAR("HorizTwoFingerScroll", scroll_twofinger_horiz, PT_BOOL, 0, 1),
+ DEFINE_PAR("MinSpeed", min_speed, PT_DOUBLE, 0, 1.0),
+ DEFINE_PAR("MaxSpeed", max_speed, PT_DOUBLE, 0, 1.0),
+ DEFINE_PAR("AccelFactor", accl, PT_DOUBLE, 0, 0.2),
+ DEFINE_PAR("TrackstickSpeed", trackstick_speed, PT_DOUBLE, 0, 200.0),
+ DEFINE_PAR("EdgeMotionMinZ", edge_motion_min_z, PT_INT, 1, 255),
+ DEFINE_PAR("EdgeMotionMaxZ", edge_motion_max_z, PT_INT, 1, 255),
+ DEFINE_PAR("EdgeMotionMinSpeed", edge_motion_min_speed, PT_INT, 0, 1000),
+ DEFINE_PAR("EdgeMotionMaxSpeed", edge_motion_max_speed, PT_INT, 0, 1000),
+ DEFINE_PAR("EdgeMotionUseAlways", edge_motion_use_always, PT_BOOL, 0, 1),
+ DEFINE_PAR("UpDownScrolling", updown_button_scrolling, PT_BOOL, 0, 1),
+ DEFINE_PAR("LeftRightScrolling", leftright_button_scrolling, PT_BOOL, 0, 1),
+ DEFINE_PAR("UpDownScrollRepeat", updown_button_repeat, PT_BOOL, 0, 1),
+ DEFINE_PAR("LeftRightScrollRepeat",leftright_button_repeat, PT_BOOL, 0, 1),
+ DEFINE_PAR("ScrollButtonRepeat", scroll_button_repeat, PT_INT, SBR_MIN , SBR_MAX),
+ DEFINE_PAR("TouchpadOff", touchpad_off, PT_INT, 0, 2),
+ DEFINE_PAR("GuestMouseOff", guestmouse_off, PT_BOOL, 0, 1),
+ DEFINE_PAR("LockedDrags", locked_drags, PT_BOOL, 0, 1),
+ DEFINE_PAR("LockedDragTimeout", locked_drag_time, PT_INT, 0, 30000),
+ DEFINE_PAR("RTCornerButton", tap_action[RT_TAP], PT_INT, 0, SYN_MAX_BUTTONS),
+ DEFINE_PAR("RBCornerButton", tap_action[RB_TAP], PT_INT, 0, SYN_MAX_BUTTONS),
+ DEFINE_PAR("LTCornerButton", tap_action[LT_TAP], PT_INT, 0, SYN_MAX_BUTTONS),
+ DEFINE_PAR("LBCornerButton", tap_action[LB_TAP], PT_INT, 0, SYN_MAX_BUTTONS),
+ DEFINE_PAR("TapButton1", tap_action[F1_TAP], PT_INT, 0, SYN_MAX_BUTTONS),
+ DEFINE_PAR("TapButton2", tap_action[F2_TAP], PT_INT, 0, SYN_MAX_BUTTONS),
+ DEFINE_PAR("TapButton3", tap_action[F3_TAP], PT_INT, 0, SYN_MAX_BUTTONS),
+ DEFINE_PAR("CircularScrolling", circular_scrolling, PT_BOOL, 0, 1),
+ DEFINE_PAR("CircScrollDelta", scroll_dist_circ, PT_DOUBLE, .01, 3),
+ DEFINE_PAR("CircScrollTrigger", circular_trigger, PT_INT, 0, 8),
+ DEFINE_PAR("CircularPad", circular_pad, PT_BOOL, 0, 1),
+ DEFINE_PAR("PalmDetect", palm_detect, PT_BOOL, 0, 1),
+ DEFINE_PAR("PalmMinWidth", palm_min_width, PT_INT, 0, 15),
+ DEFINE_PAR("PalmMinZ", palm_min_z, PT_INT, 0, 255),
+ DEFINE_PAR("CoastingSpeed", coasting_speed, PT_DOUBLE, 0, 20),
+ DEFINE_PAR("PressureMotionMinZ", press_motion_min_z, PT_INT, 1, 255),
+ DEFINE_PAR("PressureMotionMaxZ", press_motion_max_z, PT_INT, 1, 255),
+ DEFINE_PAR("PressureMotionMinFactor", press_motion_min_factor, PT_DOUBLE, 0, 10.0),
+ DEFINE_PAR("PressureMotionMaxFactor", press_motion_max_factor, PT_DOUBLE, 0, 10.0),
+ DEFINE_PAR("GrabEventDevice", grab_event_device, PT_BOOL, 0, 1),
+ { 0, 0, 0, 0, 0 }
+};
+
+static void
+show_hw_info(SynapticsSHM *synshm)
+{
+ printf("Hardware properties:\n");
+ if (synshm->synhw.model_id) {
+ printf(" Model Id = %08x\n", synshm->synhw.model_id);
+ printf(" Capabilities = %08x\n", synshm->synhw.capabilities);
+ printf(" Identity = %08x\n", synshm->synhw.identity);
+ } else {
+ printf(" Can't detect hardware properties.\n");
+ printf(" This is normal if you are running linux kernel 2.6.\n");
+ printf(" Check the kernel log for touchpad hardware information.\n");
+ }
+ printf("Driver version: %d\n", (PACKAGE_VERSION_MAJOR*10000+PACKAGE_VERSION_MINOR*100+PACKAGE_VERSION_PATCHLEVEL));
+}
+
+static void
+show_settings(SynapticsSHM *synshm)
+{
+ int i;
+
+ printf("Parameter settings:\n");
+ for (i = 0; params[i].name; i++) {
+ struct Parameter* par = &params[i];
+ switch (par->type) {
+ case PT_INT:
+ printf(" %-23s = %d\n", par->name, *(int*)((char*)synshm + par->offset));
+ break;
+ case PT_BOOL:
+ printf(" %-23s = %d\n", par->name, *(Bool*)((char*)synshm + par->offset));
+ break;
+ case PT_DOUBLE:
+ printf(" %-23s = %g\n", par->name, *(double*)((char*)synshm + par->offset));
+ break;
+ }
+ }
+}
+
+static void
+set_variables(SynapticsSHM *synshm, int argc, char *argv[], int first_cmd)
+{
+ int i;
+ for (i = first_cmd; i < argc; i++) {
+ char *cmd = argv[i];
+ char *eqp = index(cmd, '=');
+ if (eqp) {
+ int j;
+ int found = 0;
+ *eqp = 0;
+ for (j = 0; params[j].name; j++) {
+ if (strcasecmp(cmd, params[j].name) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (found) {
+ double val = atof(&eqp[1]);
+ struct Parameter* par = &params[j];
+
+ if (val < par->min_val)
+ val = par->min_val;
+ if (val > par->max_val)
+ val = par->max_val;
+
+ switch (par->type) {
+ case PT_INT:
+ *(int*)((char*)synshm + par->offset) = (int)rint(val);
+ break;
+ case PT_BOOL:
+ *(Bool*)((char*)synshm + par->offset) = (Bool)rint(val);
+ break;
+ case PT_DOUBLE:
+ *(double*)((char*)synshm + par->offset) = val;
+ break;
+ }
+ } else {
+ printf("Unknown parameter %s\n", cmd);
+ }
+ } else {
+ printf("Invalid command: %s\n", cmd);
+ }
+ }
+}
+
+static int
+is_equal(SynapticsSHM *s1, SynapticsSHM *s2)
+{
+ int i;
+
+ if ((s1->x != s2->x) ||
+ (s1->y != s2->y) ||
+ (s1->z != s2->z) ||
+ (s1->numFingers != s2->numFingers) ||
+ (s1->fingerWidth != s2->fingerWidth) ||
+ (s1->left != s2->left) ||
+ (s1->right != s2->right) ||
+ (s1->up != s2->up) ||
+ (s1->down != s2->down) ||
+ (s1->middle != s2->middle) ||
+ (s1->guest_left != s2->guest_left) ||
+ (s1->guest_mid != s2->guest_mid) ||
+ (s1->guest_right != s2->guest_right) ||
+ (s1->guest_dx != s2->guest_dx) ||
+ (s1->guest_dy != s2->guest_dy))
+ return 0;
+
+ for (i = 0; i < 8; i++)
+ if (s1->multi[i] != s2->multi[i])
+ return 0;
+
+ return 1;
+}
+
+static double
+get_time()
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec + tv.tv_usec / 1000000.0;
+}
+
+static void
+monitor(SynapticsSHM *synshm, int delay)
+{
+ int header = 0;
+ SynapticsSHM old;
+ double t0 = get_time();
+
+ memset(&old, 0, sizeof(SynapticsSHM));
+ old.x = -1; /* Force first equality test to fail */
+
+ while (1) {
+ SynapticsSHM cur = *synshm;
+ if (!is_equal(&old, &cur)) {
+ if (!header) {
+ printf("%8s %4s %4s %3s %s %2s %2s %s %s %s %s %8s "
+ "%2s %2s %2s %3s %3s\n",
+ "time", "x", "y", "z", "f", "w", "l", "r", "u", "d", "m",
+ "multi", "gl", "gm", "gr", "gdx", "gdy");
+ header = 20;
+ }
+ header--;
+ printf("%8.3f %4d %4d %3d %d %2d %2d %d %d %d %d %d%d%d%d%d%d%d%d "
+ "%2d %2d %2d %3d %3d\n",
+ get_time() - t0,
+ cur.x, cur.y, cur.z, cur.numFingers, cur.fingerWidth,
+ cur.left, cur.right, cur.up, cur.down, cur.middle,
+ cur.multi[0], cur.multi[1], cur.multi[2], cur.multi[3],
+ cur.multi[4], cur.multi[5], cur.multi[6], cur.multi[7],
+ cur.guest_left, cur.guest_mid, cur.guest_right,
+ cur.guest_dx, cur.guest_dy);
+ fflush(stdout);
+ old = cur;
+ }
+ usleep(delay * 1000);
+ }
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "Usage: synclient [-m interval] [-h] [-l] [-V] [-?] [var1=value1 [var2=value2] ...]\n");
+ fprintf(stderr, " -m monitor changes to the touchpad state.\n"
+ " interval specifies how often (in ms) to poll the touchpad state\n");
+ fprintf(stderr, " -h Show detected hardware properties\n");
+ fprintf(stderr, " -l List current user settings\n");
+ fprintf(stderr, " -V Print synclient version string and exit\n");
+ fprintf(stderr, " -? Show this help message\n");
+ fprintf(stderr, " var=value Set user parameter 'var' to 'value'.\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ SynapticsSHM *synshm;
+ int shmid;
+
+ int c;
+ int delay = -1;
+ int do_monitor = 0;
+ int dump_hw = 0;
+ int dump_settings = 0;
+ int first_cmd;
+
+ /* Parse command line parameters */
+ while ((c = getopt(argc, argv, "m:hlV")) != -1) {
+ switch (c) {
+ case 'm':
+ do_monitor = 1;
+ if ((delay = atoi(optarg)) < 0)
+ usage();
+ break;
+ case 'h':
+ dump_hw = 1;
+ break;
+ case 'l':
+ dump_settings = 1;
+ break;
+ case 'V':
+ printf("%s\n", VERSION);
+ exit(0);
+ default:
+ usage();
+ }
+ }
+ first_cmd = optind;
+ if (!do_monitor && !dump_hw && !dump_settings && first_cmd == argc)
+ usage();
+
+ /* Connect to the shared memory area */
+ if ((shmid = shmget(SHM_SYNAPTICS, sizeof(SynapticsSHM), 0)) == -1) {
+ if ((shmid = shmget(SHM_SYNAPTICS, 0, 0)) == -1) {
+ fprintf(stderr, "Can't access shared memory area. SHMConfig disabled?\n");
+ exit(1);
+ } else {
+ fprintf(stderr, "Incorrect size of shared memory area. Incompatible driver version?\n");
+ exit(1);
+ }
+ }
+ if ((synshm = (SynapticsSHM*) shmat(shmid, NULL, 0)) == NULL) {
+ perror("shmat");
+ exit(1);
+ }
+
+ /* Perform requested actions */
+ if (dump_hw) {
+ show_hw_info(synshm);
+ }
+ set_variables(synshm, argc, argv, first_cmd);
+ if (dump_settings) {
+ show_settings(synshm);
+ }
+ if (do_monitor) {
+ monitor(synshm, delay);
+ }
+
+ exit(0);
+}
diff --git a/tools/syndaemon.c b/tools/syndaemon.c
new file mode 100644
index 0000000..ebbeb52
--- /dev/null
+++ b/tools/syndaemon.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright © 2003-2004 Peter Osterlund
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of Red Hat
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission. Red
+ * Hat makes no representations about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors:
+ * Peter Osterlund (petero2@telia.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <X11/Xlib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include "synaptics.h"
+
+static SynapticsSHM *synshm;
+static int pad_disabled;
+static int disable_taps_only;
+static int ignore_modifier_combos;
+static int background;
+static const char *pid_file;
+
+#define KEYMAP_SIZE 32
+static unsigned char keyboard_mask[KEYMAP_SIZE];
+
+static void
+usage()
+{
+ fprintf(stderr, "Usage: syndaemon [-i idle-time] [-m poll-delay] [-d] [-t] [-k]\n");
+ fprintf(stderr, " -i How many seconds to wait after the last key press before\n");
+ fprintf(stderr, " enabling the touchpad. (default is 2.0s)\n");
+ fprintf(stderr, " -m How many milli-seconds to wait until next poll.\n");
+ fprintf(stderr, " (default is 200ms)\n");
+ fprintf(stderr, " -d Start as a daemon, ie in the background.\n");
+ fprintf(stderr, " -p Create a pid file with the specified name.\n");
+ 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");
+ exit(1);
+}
+
+static int
+enable_touchpad()
+{
+ int ret = 0;
+ if (pad_disabled) {
+ synshm->touchpad_off = 0;
+ pad_disabled = 0;
+ ret = 1;
+ }
+ return ret;
+}
+
+static void
+signal_handler(int signum)
+{
+ enable_touchpad();
+ if (pid_file)
+ unlink(pid_file);
+ kill(getpid(), signum);
+}
+
+static void
+install_signal_handler()
+{
+ static int signals[] = {
+ SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT,
+ SIGBUS, SIGFPE, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE,
+ SIGALRM, SIGTERM, SIGPWR
+ };
+ int i;
+ struct sigaction act;
+ sigset_t set;
+
+ sigemptyset(&set);
+ act.sa_handler = signal_handler;
+ act.sa_mask = set;
+ act.sa_flags = SA_ONESHOT;
+
+ for (i = 0; i < sizeof(signals) / sizeof(int); i++) {
+ if (sigaction(signals[i], &act, 0) == -1) {
+ perror("sigaction");
+ exit(2);
+ }
+ }
+}
+
+/**
+ * Return non-zero if the keyboard state has changed since the last call.
+ */
+static int
+keyboard_activity(Display *display)
+{
+ static unsigned char old_key_state[KEYMAP_SIZE];
+ unsigned char key_state[KEYMAP_SIZE];
+ int i;
+ int ret = 0;
+
+ XQueryKeymap(display, (char*)key_state);
+
+ for (i = 0; i < KEYMAP_SIZE; i++) {
+ if ((key_state[i] & ~old_key_state[i]) & keyboard_mask[i]) {
+ ret = 1;
+ break;
+ }
+ }
+ if (ignore_modifier_combos) {
+ for (i = 0; i < KEYMAP_SIZE; i++) {
+ if (key_state[i] & ~keyboard_mask[i]) {
+ ret = 0;
+ break;
+ }
+ }
+ }
+ for (i = 0; i < KEYMAP_SIZE; i++)
+ old_key_state[i] = key_state[i];
+ return ret;
+}
+
+/**
+ * Return non-zero if any physical touchpad button is currently pressed.
+ */
+static int
+touchpad_buttons_active()
+{
+ int i;
+
+ if (synshm->left || synshm->right || synshm->up || synshm->down)
+ return 1;
+ for (i = 0; i < 8; i++)
+ if (synshm->multi[i])
+ return 1;
+ if (synshm->guest_left || synshm->guest_mid || synshm->guest_right)
+ return 1;
+ return 0;
+}
+
+static double
+get_time()
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec + tv.tv_usec / 1000000.0;
+}
+
+static void
+main_loop(Display *display, double idle_time, int poll_delay)
+{
+ double last_activity = 0.0;
+ double current_time;
+
+ pad_disabled = 0;
+ keyboard_activity(display);
+
+ for (;;) {
+ current_time = get_time();
+ if (keyboard_activity(display))
+ last_activity = current_time;
+ if (touchpad_buttons_active())
+ last_activity = 0.0;
+
+ if (current_time > last_activity + idle_time) { /* Enable touchpad */
+ if (enable_touchpad()) {
+ if (!background)
+ printf("Enable\n");
+ }
+ } else { /* Disable touchpad */
+ if (!pad_disabled && !synshm->touchpad_off) {
+ if (!background)
+ printf("Disable\n");
+ pad_disabled = 1;
+ if (disable_taps_only)
+ synshm->touchpad_off = 2;
+ else
+ synshm->touchpad_off = 1;
+ }
+ }
+
+ usleep(poll_delay);
+ }
+}
+
+static void
+clear_bit(unsigned char *ptr, int bit)
+{
+ int byte_num = bit / 8;
+ int bit_num = bit % 8;
+ ptr[byte_num] &= ~(1 << bit_num);
+}
+
+static void
+setup_keyboard_mask(Display *display, int ignore_modifier_keys)
+{
+ XModifierKeymap *modifiers;
+ int i;
+
+ for (i = 0; i < KEYMAP_SIZE; i++)
+ keyboard_mask[i] = 0xff;
+
+ if (ignore_modifier_keys) {
+ modifiers = XGetModifierMapping(display);
+ for (i = 0; i < 8 * modifiers->max_keypermod; i++) {
+ KeyCode kc = modifiers->modifiermap[i];
+ if (kc != 0)
+ clear_bit(keyboard_mask, kc);
+ }
+ XFreeModifiermap(modifiers);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ double idle_time = 2.0;
+ int poll_delay = 200000; /* 200 ms */
+ Display *display;
+ int c;
+ int shmid;
+ int ignore_modifier_keys = 0;
+
+ /* Parse command line parameters */
+ while ((c = getopt(argc, argv, "i:m:dtp:kK?")) != EOF) {
+ switch(c) {
+ case 'i':
+ idle_time = atof(optarg);
+ break;
+ case 'm':
+ poll_delay = atoi(optarg) * 1000;
+ break;
+ case 'd':
+ background = 1;
+ break;
+ case 't':
+ disable_taps_only = 1;
+ break;
+ case 'p':
+ pid_file = optarg;
+ break;
+ case 'k':
+ ignore_modifier_keys = 1;
+ break;
+ case 'K':
+ ignore_modifier_combos = 1;
+ ignore_modifier_keys = 1;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+ if (idle_time <= 0.0)
+ usage();
+
+ /* Open a connection to the X server */
+ display = XOpenDisplay(NULL);
+ if (!display) {
+ fprintf(stderr, "Can't open display.\n");
+ exit(2);
+ }
+
+ /* Connect to the shared memory area */
+ if ((shmid = shmget(SHM_SYNAPTICS, sizeof(SynapticsSHM), 0)) == -1) {
+ if ((shmid = shmget(SHM_SYNAPTICS, 0, 0)) == -1) {
+ fprintf(stderr, "Can't access shared memory area. SHMConfig disabled?\n");
+ exit(2);
+ } else {
+ fprintf(stderr, "Incorrect size of shared memory area. Incompatible driver version?\n");
+ exit(2);
+ }
+ }
+ if ((synshm = (SynapticsSHM*) shmat(shmid, NULL, 0)) == NULL) {
+ perror("shmat");
+ exit(2);
+ }
+
+ /* Install a signal handler to restore synaptics parameters on exit */
+ install_signal_handler();
+
+ if (background) {
+ pid_t pid;
+ if ((pid = fork()) < 0) {
+ perror("fork");
+ exit(3);
+ } else if (pid != 0)
+ exit(0);
+
+ /* Child (daemon) is running here */
+ setsid(); /* Become session leader */
+ chdir("/"); /* In case the file system gets unmounted */
+ umask(0); /* We don't want any surprises */
+ if (pid_file) {
+ FILE *fd = fopen(pid_file, "w");
+ if (!fd) {
+ perror("Can't create pid file");
+ exit(2);
+ }
+ fprintf(fd, "%d\n", getpid());
+ fclose(fd);
+ }
+ }
+
+ setup_keyboard_mask(display, ignore_modifier_keys);
+
+ /* Run the main loop */
+ main_loop(display, idle_time, poll_delay);
+
+ return 0;
+}