1429 lines
37 KiB
Diff
1429 lines
37 KiB
Diff
From b9e6a0fa5804bae802cf08a121557844f0ee2fbb Mon Sep 17 00:00:00 2001
|
|
From: Peter Hutterer <peter.hutterer@who-t.net>
|
|
Date: Fri, 7 Aug 2015 15:19:12 +1000
|
|
Subject: [PATCH xf86-input-libinput] Add drag lock support
|
|
|
|
Mostly the same functionality that evdev provides with two options on how it
|
|
works:
|
|
* a single button number configures the given button to lock the next button
|
|
pressed in a logically down state until a press+ release of that same button
|
|
again
|
|
* a set of button number pairs configures each button with the to-be-locked
|
|
logical button, i.e. a pair of "1 3" will hold 3 logically down after a
|
|
button 1 press
|
|
|
|
The property and the xorg.conf options take the same configuration as the
|
|
evdev driver (though the property has a different prefix, libinput instead of
|
|
Evdev).
|
|
|
|
The behavior difference to evdev is in how releases are handled, evdev sends
|
|
the release on the second button press event, this implementation sends the
|
|
release on the second release event.
|
|
|
|
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
|
|
---
|
|
Makefile.am | 2 +-
|
|
configure.ac | 1 +
|
|
include/libinput-properties.h | 6 +
|
|
man/libinput.man | 46 +++-
|
|
src/Makefile.am | 4 +-
|
|
src/draglock.c | 282 ++++++++++++++++++++++
|
|
src/draglock.h | 159 +++++++++++++
|
|
src/libinput.c | 146 +++++++++++-
|
|
test/.gitignore | 1 +
|
|
test/Makefile.am | 13 +
|
|
test/test-draglock.c | 540 ++++++++++++++++++++++++++++++++++++++++++
|
|
11 files changed, 1195 insertions(+), 5 deletions(-)
|
|
create mode 100644 src/draglock.c
|
|
create mode 100644 src/draglock.h
|
|
create mode 100644 test/.gitignore
|
|
create mode 100644 test/Makefile.am
|
|
create mode 100644 test/test-draglock.c
|
|
|
|
diff --git a/Makefile.am b/Makefile.am
|
|
index 99e6808..ef17c35 100644
|
|
--- a/Makefile.am
|
|
+++ b/Makefile.am
|
|
@@ -21,7 +21,7 @@
|
|
|
|
DISTCHECK_CONFIGURE_FLAGS = --with-sdkdir='$${includedir}/xorg'
|
|
|
|
-SUBDIRS = src include man
|
|
+SUBDIRS = src include man test
|
|
MAINTAINERCLEANFILES = ChangeLog INSTALL
|
|
|
|
pkgconfigdir = $(libdir)/pkgconfig
|
|
diff --git a/configure.ac b/configure.ac
|
|
index c149a1b..26e0e70 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -71,5 +71,6 @@ AC_CONFIG_FILES([Makefile
|
|
include/Makefile
|
|
src/Makefile
|
|
man/Makefile
|
|
+ test/Makefile
|
|
xorg-libinput.pc])
|
|
AC_OUTPUT
|
|
diff --git a/include/libinput-properties.h b/include/libinput-properties.h
|
|
index f54cee7..ed009d5 100644
|
|
--- a/include/libinput-properties.h
|
|
+++ b/include/libinput-properties.h
|
|
@@ -114,4 +114,10 @@
|
|
/* Disable while typing: BOOL, 1 value, read-only */
|
|
#define LIBINPUT_PROP_DISABLE_WHILE_TYPING_DEFAULT "libinput Disable While Typing Enabled Default"
|
|
|
|
+/* Drag lock buttons, either:
|
|
+ CARD8, one value, the meta lock button, or
|
|
+ CARD8, n * 2 values, the drag lock pairs with n being the button and n+1
|
|
+ the target button number */
|
|
+#define LIBINPUT_PROP_DRAG_LOCK_BUTTONS "libinput Drag Lock Buttons"
|
|
+
|
|
#endif /* _LIBINPUT_PROPERTIES_H_ */
|
|
diff --git a/man/libinput.man b/man/libinput.man
|
|
index ac546e6..ff7a411 100644
|
|
--- a/man/libinput.man
|
|
+++ b/man/libinput.man
|
|
@@ -123,6 +123,27 @@ continues.
|
|
.BI "Option \*qDisableWhileTyping\*q \*q" bool \*q
|
|
Indicates if the touchpad should be disabled while typing on the keyboard
|
|
(this does not apply to modifier keys such as Ctrl or Alt).
|
|
+.TP 7
|
|
+.BI "Option \*qDragLockButtons\*q \*q" "L1 B1 L2 B2 ..." \*q
|
|
+Sets "drag lock buttons" that simulate a button logically down even when it has
|
|
+been physically released. To logically release a locked button, a second click
|
|
+of the same button is required.
|
|
+.IP
|
|
+If the option is a single button number, that button acts as the
|
|
+"meta" locking button for the next button number. See section
|
|
+.B BUTTON DRAG LOCK
|
|
+for details.
|
|
+.IP
|
|
+If the option is a list of button number pairs, the first number of each
|
|
+number pair is the lock button, the second number the logical button number
|
|
+to be locked. See section
|
|
+.B BUTTON DRAG LOCK
|
|
+for details.
|
|
+.IP
|
|
+For both meta and button pair configuration, the button numbers are
|
|
+device button numbers, i.e. the
|
|
+.B ButtonMapping
|
|
+applies after drag lock.
|
|
.PP
|
|
For all options, the options are only parsed if the device supports that
|
|
configuration option. For all options, the default value is the one used by
|
|
@@ -195,11 +216,16 @@ disabled.
|
|
.BI "libinput Disable While Typing Enabled"
|
|
1 boolean value (8 bit, 0 or 1). Indicates if disable while typing is
|
|
enabled or disabled.
|
|
-.TP7
|
|
.PP
|
|
The above properties have a
|
|
.BI "libinput <property name> Default"
|
|
equivalent that indicates the default value for this setting on this device.
|
|
+.TP 7
|
|
+.BI "libinput Drag Lock Buttons"
|
|
+Either one 8-bit value specifying the meta drag lock button, or a list of
|
|
+button pairs. See section
|
|
+.B BUTTON DRAG LOCK
|
|
+for details.
|
|
|
|
.SH BUTTON MAPPING
|
|
X clients receive events with logical button numbers, where 1, 2, 3
|
|
@@ -226,6 +252,24 @@ __xservername__ input driver does not use the button mapping after setup.
|
|
Use XSetPointerMapping(__libmansuffix__) to modify the button mapping at
|
|
runtime.
|
|
|
|
+.SH BUTTON DRAG LOCK
|
|
+Button drag lock holds a button logically down even when the button itself
|
|
+has been physically released since. Button drag lock comes in two modes.
|
|
+.PP
|
|
+If in "meta" mode, a meta button click activates drag lock for the next
|
|
+button press of any other button. A button click in the future will keep
|
|
+that button held logically down until a subsequent click of that same
|
|
+button. The meta button events themselves are discarded. A separate meta
|
|
+button click is required each time a drag lock should be activated for a
|
|
+button in the future.
|
|
+.PP
|
|
+If in "pairs" mode, each button can be assigned a target locking button.
|
|
+On button click, the target lock button is held logically down until the
|
|
+next click of the same button. The button events themselves are discarded
|
|
+and only the target button events are sent.
|
|
+.TP
|
|
+This feature is provided by this driver, not by libinput.
|
|
+
|
|
.SH AUTHORS
|
|
Peter Hutterer
|
|
.SH "SEE ALSO"
|
|
diff --git a/src/Makefile.am b/src/Makefile.am
|
|
index 1f49893..df02aca 100644
|
|
--- a/src/Makefile.am
|
|
+++ b/src/Makefile.am
|
|
@@ -30,8 +30,10 @@ AM_CPPFLAGS =-I$(top_srcdir)/include $(LIBINPUT_CFLAGS)
|
|
|
|
@DRIVER_NAME@_drv_la_LTLIBRARIES = @DRIVER_NAME@_drv.la
|
|
@DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version
|
|
-@DRIVER_NAME@_drv_la_LIBADD = $(LIBINPUT_LIBS)
|
|
+@DRIVER_NAME@_drv_la_LIBADD = $(LIBINPUT_LIBS) libdraglock.la
|
|
@DRIVER_NAME@_drv_ladir = @inputdir@
|
|
|
|
@DRIVER_NAME@_drv_la_SOURCES = @DRIVER_NAME@.c
|
|
|
|
+noinst_LTLIBRARIES = libdraglock.la
|
|
+libdraglock_la_SOURCES = draglock.c draglock.h
|
|
diff --git a/src/draglock.c b/src/draglock.c
|
|
new file mode 100644
|
|
index 0000000..b0bcac3
|
|
--- /dev/null
|
|
+++ b/src/draglock.c
|
|
@@ -0,0 +1,282 @@
|
|
+/*
|
|
+ * Copyright © 2015 Red Hat, Inc.
|
|
+ *
|
|
+ * 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.
|
|
+ */
|
|
+
|
|
+#ifdef HAVE_CONFIG_H
|
|
+#include "config.h"
|
|
+#endif
|
|
+
|
|
+#include "draglock.h"
|
|
+
|
|
+#include <string.h>
|
|
+#include <stdlib.h>
|
|
+
|
|
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
|
|
+
|
|
+static int
|
|
+draglock_parse_config(struct draglock *dl, const char *config)
|
|
+{
|
|
+ int button = 0, target = 0;
|
|
+ const char *str = NULL;
|
|
+ char *end_str = NULL;
|
|
+ int pairs[DRAGLOCK_MAX_BUTTONS] = {0};
|
|
+
|
|
+ if (!config)
|
|
+ return 0;
|
|
+
|
|
+ /* empty string disables drag lock */
|
|
+ if (*config == '\0') {
|
|
+ dl->mode = DRAGLOCK_DISABLED;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* check for a single-number string first, config is "<int>" */
|
|
+ button = strtol(config, &end_str, 10);
|
|
+ if (*end_str == '\0') {
|
|
+ if (button < 0 || button >= DRAGLOCK_MAX_BUTTONS)
|
|
+ return 1;
|
|
+ /* we allow for button 0 so stacked xorg.conf.d snippets can
|
|
+ * disable the config again */
|
|
+ if (button == 0) {
|
|
+ dl->mode = DRAGLOCK_DISABLED;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return draglock_set_meta(dl, button);
|
|
+ }
|
|
+
|
|
+ dl->mode = DRAGLOCK_DISABLED;
|
|
+
|
|
+ /* check for a set of button pairs, config is
|
|
+ * "<int> <int> <int> <int>..." */
|
|
+ str = config;
|
|
+ while (*str != '\0') {
|
|
+ button = strtol(str, &end_str, 10);
|
|
+ if (*end_str == '\0')
|
|
+ return 1;
|
|
+
|
|
+ str = end_str;
|
|
+ target = strtol(str, &end_str, 10);
|
|
+ if (end_str == str)
|
|
+ return 1;
|
|
+ if (button <= 0 || button >= DRAGLOCK_MAX_BUTTONS || target >= DRAGLOCK_MAX_BUTTONS)
|
|
+ return 1;
|
|
+
|
|
+ pairs[button] = target;
|
|
+ str = end_str;
|
|
+ }
|
|
+
|
|
+ return draglock_set_pairs(dl, pairs, ARRAY_SIZE(pairs));
|
|
+}
|
|
+
|
|
+int
|
|
+draglock_init_from_string(struct draglock *dl, const char *config)
|
|
+{
|
|
+ dl->mode = DRAGLOCK_DISABLED;
|
|
+
|
|
+ dl->meta_button = 0;
|
|
+ dl->meta_state = false;
|
|
+ memset(dl->lock_pair, 0, sizeof(dl->lock_pair));
|
|
+ memset(dl->lock_state, 0, sizeof(dl->lock_state));
|
|
+
|
|
+ return draglock_parse_config(dl, config);
|
|
+}
|
|
+
|
|
+enum draglock_mode
|
|
+draglock_get_mode(const struct draglock *dl)
|
|
+{
|
|
+ return dl->mode;
|
|
+}
|
|
+
|
|
+int
|
|
+draglock_get_meta(const struct draglock *dl)
|
|
+{
|
|
+ if (dl->mode == DRAGLOCK_META)
|
|
+ return dl->meta_button;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+size_t
|
|
+draglock_get_pairs(const struct draglock *dl, int *array, size_t sz)
|
|
+{
|
|
+ unsigned int i;
|
|
+ size_t last = 0;
|
|
+
|
|
+ if (dl->mode != DRAGLOCK_PAIRS)
|
|
+ return 0;
|
|
+
|
|
+ /* size 1 array with the meta button */
|
|
+ if (dl->meta_button) {
|
|
+ *array = dl->meta_button;
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ /* size N array with a[0] == 0, the rest ordered by button number */
|
|
+ memset(array, 0, sz * sizeof(array[0]));
|
|
+ for (i = 0; i < sz && i < ARRAY_SIZE(dl->lock_pair); i++) {
|
|
+ array[i] = dl->lock_pair[i];
|
|
+ if (array[i] != 0 && i > last)
|
|
+ last = i;
|
|
+ }
|
|
+ return last;
|
|
+}
|
|
+
|
|
+int
|
|
+draglock_set_meta(struct draglock *dl, int meta_button)
|
|
+{
|
|
+ if (meta_button < 0 || meta_button >= DRAGLOCK_MAX_BUTTONS)
|
|
+ return 1;
|
|
+
|
|
+ dl->meta_button = meta_button;
|
|
+ dl->mode = meta_button ? DRAGLOCK_META : DRAGLOCK_DISABLED;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int
|
|
+draglock_set_pairs(struct draglock *dl, const int *array, size_t sz)
|
|
+{
|
|
+ unsigned int i;
|
|
+
|
|
+ if (sz == 0 || array[0] != 0)
|
|
+ return 1;
|
|
+
|
|
+ for (i = 0; i < sz; i++) {
|
|
+ if (array[i] < 0 || array[i] >= DRAGLOCK_MAX_BUTTONS)
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ dl->mode = DRAGLOCK_DISABLED;
|
|
+ for (i = 0; i < sz; i++) {
|
|
+ dl->lock_pair[i] = array[i];
|
|
+ if (dl->lock_pair[i])
|
|
+ dl->mode = DRAGLOCK_PAIRS;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+draglock_filter_meta(struct draglock *dl, int *button, int *press)
|
|
+{
|
|
+ int b = *button,
|
|
+ is_press = *press;
|
|
+
|
|
+ if (b == dl->meta_button) {
|
|
+ if (is_press)
|
|
+ dl->meta_state = true;
|
|
+ *button = 0;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ switch (dl->lock_state[b]) {
|
|
+ case DRAGLOCK_BUTTON_STATE_NONE:
|
|
+ if (dl->meta_state && is_press) {
|
|
+ dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_DOWN_1;
|
|
+ dl->meta_state = false;
|
|
+ }
|
|
+ break;
|
|
+ case DRAGLOCK_BUTTON_STATE_DOWN_1:
|
|
+ if (!is_press) {
|
|
+ dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_UP_1;
|
|
+ b = 0;
|
|
+ }
|
|
+ break;
|
|
+ case DRAGLOCK_BUTTON_STATE_UP_1:
|
|
+ if (is_press) {
|
|
+ dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_DOWN_2;
|
|
+ b = 0;
|
|
+ }
|
|
+ break;
|
|
+ case DRAGLOCK_BUTTON_STATE_DOWN_2:
|
|
+ if (!is_press) {
|
|
+ dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_NONE;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ *button = b;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+draglock_filter_pair(struct draglock *dl, int *button, int *press)
|
|
+{
|
|
+ int b = *button,
|
|
+ is_press = *press;
|
|
+
|
|
+ if (dl->lock_pair[b] == 0)
|
|
+ return 0;
|
|
+
|
|
+ switch (dl->lock_state[b]) {
|
|
+ case DRAGLOCK_BUTTON_STATE_NONE:
|
|
+ if (is_press) {
|
|
+ dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_DOWN_1;
|
|
+ b = dl->lock_pair[b];
|
|
+ }
|
|
+ break;
|
|
+ case DRAGLOCK_BUTTON_STATE_DOWN_1:
|
|
+ if (!is_press) {
|
|
+ dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_UP_1;
|
|
+ b = 0;
|
|
+ }
|
|
+ break;
|
|
+ case DRAGLOCK_BUTTON_STATE_UP_1:
|
|
+ if (is_press) {
|
|
+ dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_DOWN_2;
|
|
+ b = 0;
|
|
+ }
|
|
+ break;
|
|
+ case DRAGLOCK_BUTTON_STATE_DOWN_2:
|
|
+ if (!is_press) {
|
|
+ dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_NONE;
|
|
+ b = dl->lock_pair[b];
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ *button = b;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int
|
|
+draglock_filter_button(struct draglock *dl, int *button, int *is_press)
|
|
+{
|
|
+ if (*button == 0)
|
|
+ return 0;
|
|
+
|
|
+ switch(dl->mode) {
|
|
+ case DRAGLOCK_DISABLED:
|
|
+ return 0;
|
|
+ case DRAGLOCK_META:
|
|
+ return draglock_filter_meta(dl, button, is_press);
|
|
+ case DRAGLOCK_PAIRS:
|
|
+ return draglock_filter_pair(dl, button, is_press);
|
|
+ default:
|
|
+ abort();
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/src/draglock.h b/src/draglock.h
|
|
new file mode 100644
|
|
index 0000000..acc1314
|
|
--- /dev/null
|
|
+++ b/src/draglock.h
|
|
@@ -0,0 +1,159 @@
|
|
+/*
|
|
+ * Copyright © 2015 Red Hat, Inc.
|
|
+ *
|
|
+ * 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.
|
|
+ */
|
|
+
|
|
+#ifdef HAVE_CONFIG_H
|
|
+#include "config.h"
|
|
+#endif
|
|
+
|
|
+#ifndef DRAGLOCK_H
|
|
+#define DRAGLOCK_H 1
|
|
+
|
|
+#include <stdbool.h>
|
|
+#include <stdlib.h>
|
|
+
|
|
+/* 32 buttons are enough for everybody™
|
|
+ * Note that this is the limit of physical buttons as well as the highest
|
|
+ * allowed target button.
|
|
+ */
|
|
+#define DRAGLOCK_MAX_BUTTONS 32
|
|
+
|
|
+enum draglock_mode
|
|
+{
|
|
+ DRAGLOCK_DISABLED,
|
|
+ DRAGLOCK_META,
|
|
+ DRAGLOCK_PAIRS
|
|
+};
|
|
+
|
|
+enum draglock_button_state
|
|
+{
|
|
+ DRAGLOCK_BUTTON_STATE_NONE,
|
|
+ DRAGLOCK_BUTTON_STATE_DOWN_1,
|
|
+ DRAGLOCK_BUTTON_STATE_UP_1,
|
|
+ DRAGLOCK_BUTTON_STATE_DOWN_2,
|
|
+};
|
|
+
|
|
+struct draglock
|
|
+{
|
|
+ enum draglock_mode mode;
|
|
+ int meta_button; /* meta key to lock any button */
|
|
+ bool meta_state; /* meta_button state */
|
|
+ unsigned int lock_pair[DRAGLOCK_MAX_BUTTONS + 1];/* specify a meta/lock pair */
|
|
+ enum draglock_button_state lock_state[DRAGLOCK_MAX_BUTTONS + 1]; /* state of any locked buttons */
|
|
+};
|
|
+
|
|
+/**
|
|
+ * Initialize the draglock struct based on the config string. The string is
|
|
+ * either a single number to configure DRAGLOCK_META mode or a list of
|
|
+ * number pairs, with pair[0] as button and pair[1] as target lock number to
|
|
+ * configure DRAGLOCK_PAIRS mode.
|
|
+ *
|
|
+ * If config is NULL, the empty string, "0" or an even-numbered list of 0,
|
|
+ * the drag lock mode is DRAGLOCK_DISABLED.
|
|
+ *
|
|
+ * @return 0 on success or nonzero on error
|
|
+ */
|
|
+int
|
|
+draglock_init_from_string(struct draglock *dl, const char *config);
|
|
+
|
|
+/**
|
|
+ * Get the current drag lock mode.
|
|
+ *
|
|
+ * If the mode is DRAGLOCK_META, a meta button click will cause the next
|
|
+ * subsequent button click to be held logically down until the release of
|
|
+ * the second button click of that same button. Events from the meta button
|
|
+ * are always discarded.
|
|
+ *
|
|
+ * If the mode is DRAGLOCK_PAIRS, any button may be configured with a
|
|
+ * 'target' button number. A click of that button causes the target button
|
|
+ * to be held logically down until the release of the second button click.
|
|
+ */
|
|
+enum draglock_mode
|
|
+draglock_get_mode(const struct draglock *dl);
|
|
+
|
|
+/**
|
|
+ * @return the meta button number or 0 if the current mode is not
|
|
+ * DRAGLOCK_META.
|
|
+ */
|
|
+int
|
|
+draglock_get_meta(const struct draglock *dl);
|
|
+
|
|
+/**
|
|
+ * Get the drag lock button mapping pairs. The array is filled with the
|
|
+ * button number as index and the mapped target button number as value, i.e.
|
|
+ * array[3] == 8 means button 3 will draglock button 8.
|
|
+ *
|
|
+ * A value of 0 indicates draglock is disabled for that button.
|
|
+ *
|
|
+ * @note Button numbers start at 1, array[0] is always 0.
|
|
+ *
|
|
+ * @param[in|out] array Caller-allocated array to hold the button mappings.
|
|
+ * @param[in] sz Maximum number of elements in array
|
|
+ *
|
|
+ * @return The number of valid elements in array or 0 if the current mode is
|
|
+ * not DRAGLOCK_PAIRS
|
|
+ */
|
|
+size_t
|
|
+draglock_get_pairs(const struct draglock *dl, int *array, size_t sz);
|
|
+
|
|
+/**
|
|
+ * Set the drag lock config to the DRAGLOCK_META mode, with the given
|
|
+ * button as meta button.
|
|
+ *
|
|
+ * If the button is 0 the mode becomes DRAGLOCK_DISABLED.
|
|
+ *
|
|
+ * @return 0 on success, nonzero otherwise
|
|
+ */
|
|
+int
|
|
+draglock_set_meta(struct draglock *dl, int meta_button);
|
|
+
|
|
+/**
|
|
+ * Set the drag lock config to the DRAGLOCK_PAIRS mode. The array
|
|
+ * must be filled with the button number as index and the mapped target
|
|
+ * button number as value, i.e.
|
|
+ * array[3] == 8 means button 3 will draglock button 8.
|
|
+ *
|
|
+ * A value of 0 indicates draglock is disabled for that button. If all
|
|
+ * buttons are 0, the mode becomes DRAGLOCK_DISABLED.
|
|
+ *
|
|
+ * @note Button numbers start at 1, array[0] is always 0.
|
|
+ *
|
|
+ * @return 0 on successor nonzero otherwise
|
|
+ */
|
|
+int
|
|
+draglock_set_pairs(struct draglock *dl, const int *array, size_t sz);
|
|
+
|
|
+/**
|
|
+ * Process the given button event through the drag lock state machine.
|
|
+ * If the event is to be discarded by the caller, button is set to 0.
|
|
+ * Otherwise, button is set to the button event to process and is_press is
|
|
+ * set to the button state to process.
|
|
+ *
|
|
+ * @param[in|out] button The button number to process
|
|
+ * @param[in|out] is_press nonzero for press, zero for release
|
|
+ *
|
|
+ * @return 0 on success or 1 on error
|
|
+ */
|
|
+int
|
|
+draglock_filter_button(struct draglock *dl, int *button, int *is_press);
|
|
+
|
|
+#endif /* DRAGLOCK_H */
|
|
diff --git a/src/libinput.c b/src/libinput.c
|
|
index 49f73c9..10b9b1d 100644
|
|
--- a/src/libinput.c
|
|
+++ b/src/libinput.c
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright © 2013 Red Hat, Inc.
|
|
+ * Copyright © 2013-2015 Red Hat, Inc.
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software
|
|
* and its documentation for any purpose is hereby granted without
|
|
@@ -41,6 +41,7 @@
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
+#include "draglock.h"
|
|
#include "libinput-properties.h"
|
|
|
|
#ifndef XI86_SERVER_FD
|
|
@@ -112,6 +113,8 @@ struct xf86libinput {
|
|
|
|
unsigned char btnmap[MAX_BUTTONS + 1];
|
|
} options;
|
|
+
|
|
+ struct draglock draglock;
|
|
};
|
|
|
|
/*
|
|
@@ -770,12 +773,18 @@ static void
|
|
xf86libinput_handle_button(InputInfoPtr pInfo, struct libinput_event_pointer *event)
|
|
{
|
|
DeviceIntPtr dev = pInfo->dev;
|
|
+ struct xf86libinput *driver_data = pInfo->private;
|
|
int button;
|
|
int is_press;
|
|
|
|
button = btn_linux2xorg(libinput_event_pointer_get_button(event));
|
|
is_press = (libinput_event_pointer_get_button_state(event) == LIBINPUT_BUTTON_STATE_PRESSED);
|
|
- xf86PostButtonEvent(dev, Relative, button, is_press, 0, 0);
|
|
+
|
|
+ if (draglock_get_mode(&driver_data->draglock) != DRAGLOCK_DISABLED)
|
|
+ draglock_filter_button(&driver_data->draglock, &button, &is_press);
|
|
+
|
|
+ if (button)
|
|
+ xf86PostButtonEvent(dev, Relative, button, is_press, 0, 0);
|
|
}
|
|
|
|
static void
|
|
@@ -1403,6 +1412,20 @@ xf86libinput_parse_buttonmap_option(InputInfoPtr pInfo,
|
|
free(mapping);
|
|
}
|
|
|
|
+static inline void
|
|
+xf86libinput_parse_draglock_option(InputInfoPtr pInfo,
|
|
+ struct xf86libinput *driver_data)
|
|
+{
|
|
+ char *str;
|
|
+
|
|
+ str = xf86CheckStrOption(pInfo->options, "DragLockButtons",NULL);
|
|
+ if (draglock_init_from_string(&driver_data->draglock, str) != 0)
|
|
+ xf86IDrvMsg(pInfo, X_ERROR,
|
|
+ "Invalid DragLockButtons option: \"%s\"\n",
|
|
+ str);
|
|
+ free(str);
|
|
+}
|
|
+
|
|
static void
|
|
xf86libinput_parse_options(InputInfoPtr pInfo,
|
|
struct xf86libinput *driver_data,
|
|
@@ -1428,6 +1451,8 @@ xf86libinput_parse_options(InputInfoPtr pInfo,
|
|
xf86libinput_parse_buttonmap_option(pInfo,
|
|
options->btnmap,
|
|
sizeof(options->btnmap));
|
|
+ if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_POINTER))
|
|
+ xf86libinput_parse_draglock_option(pInfo, driver_data);
|
|
}
|
|
|
|
static int
|
|
@@ -1621,6 +1646,9 @@ static Atom prop_middle_emulation_default;
|
|
static Atom prop_disable_while_typing;
|
|
static Atom prop_disable_while_typing_default;
|
|
|
|
+/* driver properties */
|
|
+static Atom prop_draglock;
|
|
+
|
|
/* general properties */
|
|
static Atom prop_float;
|
|
static Atom prop_device;
|
|
@@ -2060,6 +2088,85 @@ LibinputSetPropertyDisableWhileTyping(DeviceIntPtr dev,
|
|
return Success;
|
|
}
|
|
|
|
+static inline int
|
|
+prop_draglock_set_meta(struct xf86libinput *driver_data,
|
|
+ const BYTE *values,
|
|
+ int len,
|
|
+ BOOL checkonly)
|
|
+{
|
|
+ struct draglock *dl,
|
|
+ dummy; /* for checkonly */
|
|
+ int meta;
|
|
+
|
|
+ if (len > 1)
|
|
+ return BadImplementation; /* should not happen */
|
|
+
|
|
+ dl = (checkonly) ? &dummy : &driver_data->draglock;
|
|
+ meta = len > 0 ? values[0] : 0;
|
|
+
|
|
+ return draglock_set_meta(dl, meta) == 0 ? Success: BadValue;
|
|
+}
|
|
+
|
|
+static inline int
|
|
+prop_draglock_set_pairs(struct xf86libinput *driver_data,
|
|
+ const BYTE* pairs,
|
|
+ int len,
|
|
+ BOOL checkonly)
|
|
+{
|
|
+ struct draglock *dl,
|
|
+ dummy; /* for checkonly */
|
|
+ int data[MAX_BUTTONS + 1] = {0};
|
|
+ int i;
|
|
+ int highest = 0;
|
|
+
|
|
+ if (len >= ARRAY_SIZE(data))
|
|
+ return BadMatch;
|
|
+
|
|
+ if (len < 2 || len % 2)
|
|
+ return BadImplementation; /* should not happen */
|
|
+
|
|
+ dl = (checkonly) ? &dummy : &driver_data->draglock;
|
|
+
|
|
+ for (i = 0; i < len; i += 2) {
|
|
+ if (pairs[i] > MAX_BUTTONS)
|
|
+ return BadValue;
|
|
+
|
|
+ data[pairs[i]] = pairs[i+1];
|
|
+ highest = max(highest, pairs[i]);
|
|
+ }
|
|
+
|
|
+ return draglock_set_pairs(dl, data, highest + 1) == 0 ? Success : BadValue;
|
|
+}
|
|
+
|
|
+static inline int
|
|
+LibinputSetPropertyDragLockButtons(DeviceIntPtr dev,
|
|
+ Atom atom,
|
|
+ XIPropertyValuePtr val,
|
|
+ BOOL checkonly)
|
|
+{
|
|
+ InputInfoPtr pInfo = dev->public.devicePrivate;
|
|
+ struct xf86libinput *driver_data = pInfo->private;
|
|
+
|
|
+ if (val->format != 8 || val->type != XA_INTEGER)
|
|
+ return BadMatch;
|
|
+
|
|
+ /* either a single value, or pairs of values */
|
|
+ if (val->size > 1 && val->size % 2)
|
|
+ return BadMatch;
|
|
+
|
|
+ if (!xf86libinput_check_device(dev, atom))
|
|
+ return BadMatch;
|
|
+
|
|
+ if (val->size <= 1)
|
|
+ return prop_draglock_set_meta(driver_data,
|
|
+ (BYTE*)val->data,
|
|
+ val->size, checkonly);
|
|
+ else
|
|
+ return prop_draglock_set_pairs(driver_data,
|
|
+ (BYTE*)val->data,
|
|
+ val->size, checkonly);
|
|
+}
|
|
+
|
|
static int
|
|
LibinputSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
|
|
BOOL checkonly)
|
|
@@ -2097,6 +2204,8 @@ LibinputSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
|
|
rc = LibinputSetPropertyMiddleEmulation(dev, atom, val, checkonly);
|
|
else if (atom == prop_disable_while_typing)
|
|
rc = LibinputSetPropertyDisableWhileTyping(dev, atom, val, checkonly);
|
|
+ else if (atom == prop_draglock)
|
|
+ rc = LibinputSetPropertyDragLockButtons(dev, atom, val, checkonly);
|
|
else if (atom == prop_device || atom == prop_product_id ||
|
|
atom == prop_tap_default ||
|
|
atom == prop_tap_drag_lock_default ||
|
|
@@ -2565,6 +2674,37 @@ LibinputInitDisableWhileTypingProperty(DeviceIntPtr dev,
|
|
}
|
|
|
|
static void
|
|
+LibinputInitDragLockProperty(DeviceIntPtr dev,
|
|
+ struct xf86libinput *driver_data)
|
|
+{
|
|
+ size_t sz;
|
|
+ int dl_values[MAX_BUTTONS + 1];
|
|
+
|
|
+ if (!libinput_device_has_capability(driver_data->device,
|
|
+ LIBINPUT_DEVICE_CAP_POINTER))
|
|
+ return;
|
|
+
|
|
+ switch (draglock_get_mode(&driver_data->draglock)) {
|
|
+ case DRAGLOCK_DISABLED:
|
|
+ sz = 0; /* will be an empty property */
|
|
+ break;
|
|
+ case DRAGLOCK_META:
|
|
+ dl_values[0] = draglock_get_meta(&driver_data->draglock);
|
|
+ sz = 1;
|
|
+ break;
|
|
+ case DRAGLOCK_PAIRS:
|
|
+ sz = draglock_get_pairs(&driver_data->draglock,
|
|
+ dl_values, sizeof(dl_values));
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ prop_draglock = LibinputMakeProperty(dev,
|
|
+ LIBINPUT_PROP_DRAG_LOCK_BUTTONS,
|
|
+ XA_INTEGER, 8,
|
|
+ sz, dl_values);
|
|
+}
|
|
+
|
|
+static void
|
|
LibinputInitProperty(DeviceIntPtr dev)
|
|
{
|
|
InputInfoPtr pInfo = dev->public.devicePrivate;
|
|
@@ -2613,4 +2753,6 @@ LibinputInitProperty(DeviceIntPtr dev)
|
|
return;
|
|
|
|
XISetDevicePropertyDeletable(dev, prop_product_id, FALSE);
|
|
+
|
|
+ LibinputInitDragLockProperty(dev, driver_data);
|
|
}
|
|
diff --git a/test/.gitignore b/test/.gitignore
|
|
new file mode 100644
|
|
index 0000000..48a46e3
|
|
--- /dev/null
|
|
+++ b/test/.gitignore
|
|
@@ -0,0 +1 @@
|
|
+test-draglock
|
|
diff --git a/test/Makefile.am b/test/Makefile.am
|
|
new file mode 100644
|
|
index 0000000..6f94abe
|
|
--- /dev/null
|
|
+++ b/test/Makefile.am
|
|
@@ -0,0 +1,13 @@
|
|
+AM_CPPFLAGS = $(XORG_CFLAGS) \
|
|
+ $(CWARNFLAGS) \
|
|
+ -I$(top_srcdir)/include \
|
|
+ -I$(top_srcdir)/src
|
|
+
|
|
+tests = test-draglock
|
|
+
|
|
+noinst_PROGRAMS = $(tests)
|
|
+
|
|
+test_draglock_SOURCES = test-draglock.c
|
|
+test_draglock_LDADD = ../src/libdraglock.la
|
|
+
|
|
+TESTS = $(tests)
|
|
diff --git a/test/test-draglock.c b/test/test-draglock.c
|
|
new file mode 100644
|
|
index 0000000..96ef5bb
|
|
--- /dev/null
|
|
+++ b/test/test-draglock.c
|
|
@@ -0,0 +1,540 @@
|
|
+/*
|
|
+ * Copyright © 2013-2015 Red Hat, Inc.
|
|
+ *
|
|
+ * 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.
|
|
+ */
|
|
+
|
|
+#include "draglock.h"
|
|
+
|
|
+#include <assert.h>
|
|
+#include <string.h>
|
|
+
|
|
+static void
|
|
+test_config_empty(void)
|
|
+{
|
|
+ struct draglock dl;
|
|
+ int rc;
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, NULL);
|
|
+ assert(dl.mode == DRAGLOCK_DISABLED);
|
|
+ assert(rc == 0);
|
|
+}
|
|
+
|
|
+static void
|
|
+test_config_invalid(void)
|
|
+{
|
|
+ struct draglock dl;
|
|
+ int rc;
|
|
+
|
|
+ /* no trailing space */
|
|
+ rc = draglock_init_from_string(&dl, "1 ");
|
|
+ assert(rc != 0);
|
|
+ assert(dl.mode == DRAGLOCK_DISABLED);
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "256");
|
|
+ assert(rc != 0);
|
|
+ assert(dl.mode == DRAGLOCK_DISABLED);
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "-1");
|
|
+ assert(rc != 0);
|
|
+ assert(dl.mode == DRAGLOCK_DISABLED);
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "1 2 3");
|
|
+ assert(rc != 0);
|
|
+ assert(dl.mode == DRAGLOCK_DISABLED);
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "0 2");
|
|
+ assert(rc != 0);
|
|
+ assert(dl.mode == DRAGLOCK_DISABLED);
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "0 0");
|
|
+ assert(rc != 0);
|
|
+ assert(dl.mode == DRAGLOCK_DISABLED);
|
|
+}
|
|
+
|
|
+static void
|
|
+test_config_disable(void)
|
|
+{
|
|
+ struct draglock dl;
|
|
+ int rc;
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "");
|
|
+ assert(rc == 0);
|
|
+ assert(dl.mode == DRAGLOCK_DISABLED);
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "0");
|
|
+ assert(rc == 0);
|
|
+ assert(dl.mode == DRAGLOCK_DISABLED);
|
|
+}
|
|
+
|
|
+static void
|
|
+test_config_meta_button(void)
|
|
+{
|
|
+ struct draglock dl;
|
|
+ int rc;
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "1");
|
|
+ assert(rc == 0);
|
|
+ assert(dl.mode == DRAGLOCK_META);
|
|
+ assert(dl.meta_button == 1);
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "2");
|
|
+ assert(rc == 0);
|
|
+ assert(dl.mode == DRAGLOCK_META);
|
|
+ assert(dl.meta_button == 2);
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "10");
|
|
+ assert(rc == 0);
|
|
+ assert(dl.mode == DRAGLOCK_META);
|
|
+ assert(dl.meta_button == 10);
|
|
+}
|
|
+
|
|
+static void
|
|
+test_config_button_pairs(void)
|
|
+{
|
|
+ struct draglock dl;
|
|
+ int rc;
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "1 1");
|
|
+ assert(rc == 0);
|
|
+ assert(dl.mode == DRAGLOCK_PAIRS);
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "1 2 3 4 5 6 7 8");
|
|
+ assert(rc == 0);
|
|
+ assert(dl.mode == DRAGLOCK_PAIRS);
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "1 2 3 4 5 0 7 8");
|
|
+ assert(rc == 0);
|
|
+ assert(dl.mode == DRAGLOCK_PAIRS);
|
|
+
|
|
+ /* all disabled */
|
|
+ rc = draglock_init_from_string(&dl, "1 0 3 0 5 0 7 0");
|
|
+ assert(rc == 0);
|
|
+ assert(dl.mode == DRAGLOCK_DISABLED);
|
|
+}
|
|
+
|
|
+static void
|
|
+test_config_get(void)
|
|
+{
|
|
+ struct draglock dl;
|
|
+ int rc;
|
|
+ const int sz = 32;
|
|
+ int map[sz];
|
|
+
|
|
+ draglock_init_from_string(&dl, "");
|
|
+ rc = draglock_get_meta(&dl);
|
|
+ assert(rc == 0);
|
|
+ rc = draglock_get_pairs(&dl, map, sz);
|
|
+ assert(rc == 0);
|
|
+
|
|
+ draglock_init_from_string(&dl, "8");
|
|
+ rc = draglock_get_meta(&dl);
|
|
+ assert(rc == 8);
|
|
+ rc = draglock_get_pairs(&dl, map, sz);
|
|
+ assert(rc == 0);
|
|
+
|
|
+ draglock_init_from_string(&dl, "1 2 3 4 5 6");
|
|
+ rc = draglock_get_meta(&dl);
|
|
+ assert(rc == 0);
|
|
+ rc = draglock_get_pairs(&dl, map, sz);
|
|
+ assert(rc == 5);
|
|
+ assert(map[0] == 0);
|
|
+ assert(map[1] == 2);
|
|
+ assert(map[2] == 0);
|
|
+ assert(map[3] == 4);
|
|
+ assert(map[4] == 0);
|
|
+ assert(map[5] == 6);
|
|
+}
|
|
+
|
|
+static void
|
|
+test_set_meta(void)
|
|
+{
|
|
+ struct draglock dl;
|
|
+ int rc;
|
|
+
|
|
+ draglock_init_from_string(&dl, "");
|
|
+
|
|
+ rc = draglock_set_meta(&dl, 0);
|
|
+ assert(rc == 0);
|
|
+ assert(dl.mode == DRAGLOCK_DISABLED);
|
|
+
|
|
+ rc = draglock_set_meta(&dl, 1);
|
|
+ assert(rc == 0);
|
|
+ assert(dl.mode == DRAGLOCK_META);
|
|
+
|
|
+ rc = draglock_set_meta(&dl, -1);
|
|
+ assert(rc == 1);
|
|
+ rc = draglock_set_meta(&dl, 32);
|
|
+ assert(rc == 1);
|
|
+}
|
|
+
|
|
+static void
|
|
+test_set_pairs(void)
|
|
+{
|
|
+ struct draglock dl;
|
|
+ int rc;
|
|
+ const int sz = 32;
|
|
+ int map[sz];
|
|
+
|
|
+ draglock_init_from_string(&dl, "");
|
|
+ memset(map, 0, sizeof(map));
|
|
+
|
|
+ rc = draglock_set_pairs(&dl, map, sz);
|
|
+ assert(rc == 0);
|
|
+ assert(dl.mode == DRAGLOCK_DISABLED);
|
|
+
|
|
+ rc = draglock_set_pairs(&dl, map, 1);
|
|
+ assert(rc == 0);
|
|
+ assert(dl.mode == DRAGLOCK_DISABLED);
|
|
+
|
|
+ map[0] = 1;
|
|
+ rc = draglock_set_pairs(&dl, map, 1);
|
|
+ assert(rc == 1);
|
|
+
|
|
+ map[0] = 0;
|
|
+ map[1] = 2;
|
|
+ rc = draglock_set_pairs(&dl, map, sz);
|
|
+ assert(rc == 0);
|
|
+ assert(dl.mode == DRAGLOCK_PAIRS);
|
|
+
|
|
+ map[0] = 0;
|
|
+ map[1] = 0;
|
|
+ map[10] = 8;
|
|
+ rc = draglock_set_pairs(&dl, map, sz);
|
|
+ assert(rc == 0);
|
|
+ assert(dl.mode == DRAGLOCK_PAIRS);
|
|
+}
|
|
+
|
|
+static void
|
|
+test_filter_meta_passthrough(void)
|
|
+{
|
|
+ struct draglock dl;
|
|
+ int rc;
|
|
+ int button, press;
|
|
+ int i;
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "10");
|
|
+
|
|
+ for (i = 0; i < 10; i++) {
|
|
+ button = i;
|
|
+ press = 1;
|
|
+
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == i);
|
|
+ assert(press == 1);
|
|
+
|
|
+ press = 1;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == i);
|
|
+ assert(press == 1);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+test_filter_meta_click_meta_only(void)
|
|
+{
|
|
+ struct draglock dl;
|
|
+ int rc;
|
|
+ int button, press;
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "10");
|
|
+
|
|
+ button = 10;
|
|
+ press = 1;
|
|
+
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == 0);
|
|
+
|
|
+ button = 10;
|
|
+ press = 0;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == 0);
|
|
+}
|
|
+
|
|
+static void
|
|
+test_filter_meta(void)
|
|
+{
|
|
+ struct draglock dl;
|
|
+ int rc;
|
|
+ int button, press;
|
|
+ int i;
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "10");
|
|
+
|
|
+ for (i = 1; i < 10; i++) {
|
|
+ /* meta down */
|
|
+ button = 10;
|
|
+ press = 1;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == 0);
|
|
+
|
|
+ /* meta up */
|
|
+ button = 10;
|
|
+ press = 0;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == 0);
|
|
+
|
|
+ /* button down -> passthrough */
|
|
+ button = i;
|
|
+ press = 1;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == i);
|
|
+
|
|
+ /* button up -> eaten */
|
|
+ button = i;
|
|
+ press = 0;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == 0);
|
|
+
|
|
+ /* button down -> eaten */
|
|
+ button = i;
|
|
+ press = 1;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == 0);
|
|
+
|
|
+ /* button up -> passthrough */
|
|
+ button = i;
|
|
+ press = 0;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == i);
|
|
+ assert(press == 0);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+test_filter_meta_extra_click(void)
|
|
+{
|
|
+ struct draglock dl;
|
|
+ int rc;
|
|
+ int button, press;
|
|
+ int i;
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "10");
|
|
+
|
|
+ for (i = 1; i < 10; i++) {
|
|
+ /* meta down */
|
|
+ button = 10;
|
|
+ press = 1;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == 0);
|
|
+
|
|
+ /* meta up */
|
|
+ button = 10;
|
|
+ press = 0;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == 0);
|
|
+
|
|
+ /* button down -> passthrough */
|
|
+ button = i;
|
|
+ press = 1;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == i);
|
|
+
|
|
+ /* button up -> eaten */
|
|
+ button = i;
|
|
+ press = 0;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == 0);
|
|
+
|
|
+ /* meta down */
|
|
+ button = 10;
|
|
+ press = 1;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == 0);
|
|
+
|
|
+ /* meta up */
|
|
+ button = 10;
|
|
+ press = 0;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == 0);
|
|
+
|
|
+ /* button down -> eaten */
|
|
+ button = i;
|
|
+ press = 1;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == 0);
|
|
+
|
|
+ /* button up -> passthrough */
|
|
+ button = i;
|
|
+ press = 0;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == i);
|
|
+ assert(press == 0);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+test_filter_meta_interleaved(void)
|
|
+{
|
|
+ struct draglock dl;
|
|
+ int rc;
|
|
+ int button, press;
|
|
+ int i;
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "10");
|
|
+
|
|
+ for (i = 1; i < 10; i++) {
|
|
+ /* meta down */
|
|
+ button = 10;
|
|
+ press = 1;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == 0);
|
|
+
|
|
+ /* meta up */
|
|
+ button = 10;
|
|
+ press = 0;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == 0);
|
|
+
|
|
+ /* button down -> passthrough */
|
|
+ button = i;
|
|
+ press = 1;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == i);
|
|
+
|
|
+ /* button up -> eaten */
|
|
+ button = i;
|
|
+ press = 0;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == 0);
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < 10; i++) {
|
|
+ /* button down -> eaten */
|
|
+ button = i;
|
|
+ press = 1;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == 0);
|
|
+
|
|
+ /* button up -> passthrough */
|
|
+ button = i;
|
|
+ press = 0;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ assert(button == i);
|
|
+ assert(press == 0);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+test_filter_pairs(void)
|
|
+{
|
|
+ struct draglock dl;
|
|
+ int rc;
|
|
+ int button, press;
|
|
+ int i;
|
|
+
|
|
+ rc = draglock_init_from_string(&dl, "1 11 2 0 3 13 4 0 5 15 6 0 7 17 8 0 9 19");
|
|
+
|
|
+ for (i = 1; i < 10; i++) {
|
|
+ button = i;
|
|
+ press = 1;
|
|
+
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ if (i % 2)
|
|
+ assert(button == i + 10);
|
|
+ else
|
|
+ assert(button == i);
|
|
+ assert(press == 1);
|
|
+
|
|
+ button = i;
|
|
+ press = 0;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ if (i % 2) {
|
|
+ assert(button == 0);
|
|
+ } else {
|
|
+ assert(button == i);
|
|
+ assert(press == 0);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (i = 1; i < 10; i++) {
|
|
+ button = i;
|
|
+ press = 1;
|
|
+
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ if (i % 2) {
|
|
+ assert(button == 0);
|
|
+ } else {
|
|
+ assert(button == i);
|
|
+ assert(press == 1);
|
|
+ }
|
|
+
|
|
+ button = i;
|
|
+ press = 0;
|
|
+ rc = draglock_filter_button(&dl, &button, &press);
|
|
+ assert(rc == 0);
|
|
+ if (i % 2)
|
|
+ assert(button == i + 10);
|
|
+ else
|
|
+ assert(button == i);
|
|
+ assert(press == 0);
|
|
+ }
|
|
+}
|
|
+
|
|
+int
|
|
+main(int argc, char **argv)
|
|
+{
|
|
+ test_config_empty();
|
|
+ test_config_invalid();
|
|
+ test_config_disable();
|
|
+ test_config_meta_button();
|
|
+ test_config_button_pairs();
|
|
+
|
|
+ test_config_get();
|
|
+ test_set_meta();
|
|
+ test_set_pairs();
|
|
+
|
|
+ test_filter_meta_passthrough();
|
|
+ test_filter_meta_click_meta_only();
|
|
+ test_filter_meta();
|
|
+ test_filter_meta_extra_click();
|
|
+ test_filter_meta_interleaved();
|
|
+
|
|
+ test_filter_pairs();
|
|
+
|
|
+ return 0;
|
|
+}
|
|
--
|
|
2.4.3
|
|
|