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 <[email protected]> > > 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 <[email protected]> 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@_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 = 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; > >+} > > _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
