[PATCH xf86-input-libinput 1/2] Add drag lock support
Peter Hutterer
peter.hutterer at who-t.net
Wed Aug 12 14:54:26 PDT 2015
On Wed, Aug 12, 2015 at 10:43:02AM +0200, Hans de Goede wrote:
> Hi,
>
> On 12-08-15 03:28, Peter Hutterer wrote:
> >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 at who-t.net>
>
> I had to think a bit about why you are not doing this in libinput, I assume that
> is because for wayland you want the compositor to do this so that some form of
> visual feedback can be provided, correct ?
yep, sorry, I thought I had that added (and the link to the bug report
https://bugs.freedesktop.org/show_bug.cgi?id=85577). amended this now and
added the requested paragraph.
>
> Assuming that that is your reasoning, please at a paragraph explaining that to
> the commit message. Otherwise this looks good and is:
>
> Reviewed-by: Hans de Goede <hdegoede at redhat.com>
thanks.
Cheers,
Peter
>
> >---
> > 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/xf86libinput.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 6085a9a..60703e6 100644
> >--- a/src/Makefile.am
> >+++ b/src/Makefile.am
> >@@ -30,8 +30,10 @@ AM_CPPFLAGS =-I$(top_srcdir)/include $(LIBINPUT_CFLAGS)
> >
> > @DRIVER_NAME at _drv_la_LTLIBRARIES = @DRIVER_NAME at _drv.la
> > @DRIVER_NAME at _drv_la_LDFLAGS = -module -avoid-version
> >- at DRIVER_NAME@_drv_la_LIBADD = $(LIBINPUT_LIBS)
> >+ at DRIVER_NAME@_drv_la_LIBADD = $(LIBINPUT_LIBS) libdraglock.la
> > @DRIVER_NAME at _drv_ladir = @inputdir@
> >
> > @DRIVER_NAME at _drv_la_SOURCES = xf86libinput.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/xf86libinput.c b/src/xf86libinput.c
> >index 041aedf..8500792 100644
> >--- a/src/xf86libinput.c
> >+++ b/src/xf86libinput.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
> >@@ -40,6 +40,7 @@
> >
> > #include <X11/Xatom.h>
> >
> >+#include "draglock.h"
> > #include "libinput-properties.h"
> >
> > #ifndef XI86_SERVER_FD
> >@@ -111,6 +112,8 @@ struct xf86libinput {
> >
> > unsigned char btnmap[MAX_BUTTONS + 1];
> > } options;
> >+
> >+ struct draglock draglock;
> > };
> >
> > /*
> >@@ -769,12 +772,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
> >@@ -1402,6 +1411,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,
> >@@ -1427,6 +1450,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
> >@@ -1620,6 +1645,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;
> >@@ -2059,6 +2087,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)
> >@@ -2096,6 +2203,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 ||
> >@@ -2564,6 +2673,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;
> >@@ -2612,4 +2752,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;
> >+}
> >
More information about the xorg-devel
mailing list