From 4b089fbd67951d33c1031316813d768316262b5c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 15 Apr 2014 14:27:58 +0200 Subject: [PATCH 01/16] touchpad: set ntouches for single-touch pads depending on key bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A single-touch touchpad that provides BTN_TOOL_TRIPLETAP has 3 touches, etc. There aren't a lot of these out there, but some touchpads don't have slots but do provide two- or three-finger detection. Signed-off-by: Peter Hutterer Signed-off-by: Hans de Goede Reviewed-by: Jonas Ådahl Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 109441d2..b4a89e30 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -715,9 +715,29 @@ tp_init_slots(struct tp_dispatch *tp, tp->slot = absinfo->value; tp->has_mt = true; } else { - tp->ntouches = 5; /* FIXME: based on DOUBLETAP, etc. */ + struct map { + unsigned int code; + int ntouches; + } max_touches[] = { + { BTN_TOOL_QUINTTAP, 5 }, + { BTN_TOOL_QUADTAP, 4 }, + { BTN_TOOL_TRIPLETAP, 3 }, + { BTN_TOOL_DOUBLETAP, 2 }, + }; + struct map *m; + tp->slot = 0; tp->has_mt = false; + tp->ntouches = 1; + + ARRAY_FOR_EACH(max_touches, m) { + if (libevdev_has_event_code(device->evdev, + EV_KEY, + m->code)) { + tp->ntouches = m->ntouches; + break; + } + } } tp->touches = calloc(tp->ntouches, sizeof(struct tp_touch)); From cba4560566b6b998027de716bfd15693a83cbe3e Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 15 Apr 2014 14:27:59 +0200 Subject: [PATCH 02/16] touchpad: after a click, lock the finger to its current position MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On clickpads, clicking the pad usually causes some motion events. To avoid erroneous movements, lock all fingers into position on the click and don't allow for motion events until a finger moves past a given threshold (currently 2% of the touchpad diagonal). Signed-off-by: Peter Hutterer Signed-off-by: Hans de Goede Reviewed-by: Jonas Ådahl Reviewed-by: Hans de Goede Reviewed-by: Peter Hutterer --- src/evdev-mt-touchpad.c | 80 ++++++++++++++++++++--------------------- src/evdev-mt-touchpad.h | 12 ++++++- 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index b4a89e30..54a95ef3 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -32,6 +32,7 @@ #define DEFAULT_MIN_ACCEL_FACTOR 0.16 #define DEFAULT_MAX_ACCEL_FACTOR 1.0 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0 +#define DEFAULT_BUTTON_MOTION_THRESHOLD 0.02 /* 2% of size */ static inline int tp_hysteresis(int in, int center, int margin) @@ -158,6 +159,7 @@ tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t) tp_motion_history_reset(t); t->dirty = true; t->state = TOUCH_BEGIN; + t->pinned.is_pinned = false; tp->nfingers_down++; assert(tp->nfingers_down >= 1); tp->queued |= TOUCHPAD_EVENT_MOTION; @@ -182,6 +184,7 @@ tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t) t->dirty = true; t->is_pointer = false; t->state = TOUCH_END; + t->pinned.is_pinned = false; assert(tp->nfingers_down >= 1); tp->nfingers_down--; tp->queued |= TOUCHPAD_EVENT_MOTION; @@ -346,50 +349,43 @@ tp_process_key(struct tp_dispatch *tp, } static void -tp_unpin_finger(struct tp_dispatch *tp) +tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t) { - struct tp_touch *t; - tp_for_each_touch(tp, t) { - if (t->is_pinned) { - t->is_pinned = false; + unsigned int xdist, ydist; + struct tp_touch *tmp = NULL; - if (t->state != TOUCH_END && - tp->nfingers_down == 1) - t->is_pointer = true; + if (!t->pinned.is_pinned) + return; + + xdist = abs(t->x - t->pinned.center_x); + ydist = abs(t->y - t->pinned.center_y); + + if (xdist * xdist + ydist * ydist < + tp->buttons.motion_dist * tp->buttons.motion_dist) + return; + + t->pinned.is_pinned = false; + + tp_for_each_touch(tp, tmp) { + if (tmp->is_pointer) break; - } } + + if (t->state != TOUCH_END && !tmp->is_pointer) + t->is_pointer = true; } static void -tp_pin_finger(struct tp_dispatch *tp) +tp_pin_fingers(struct tp_dispatch *tp) { - struct tp_touch *t, - *pinned = NULL; + struct tp_touch *t; tp_for_each_touch(tp, t) { - if (t->is_pinned) { - pinned = t; - break; - } + t->is_pointer = false; + t->pinned.is_pinned = true; + t->pinned.center_x = t->x; + t->pinned.center_y = t->y; } - - assert(!pinned); - - pinned = tp_current_touch(tp); - - if (tp->nfingers_down != 1) { - tp_for_each_touch(tp, t) { - if (t == pinned) - continue; - - if (t->y > pinned->y) - pinned = t; - } - } - - pinned->is_pinned = true; - pinned->is_pointer = false; } static void @@ -409,16 +405,19 @@ tp_process_state(struct tp_dispatch *tp, uint32_t time) tp_motion_hysteresis(tp, t); tp_motion_history_push(t); + + tp_unpin_finger(tp, t); } - /* We have a physical button down event on a clickpad. For drag and - drop, this means we try to identify which finger pressed the - physical button and "pin" it, i.e. remove pointer-moving - capabilities from it. + /* + * We have a physical button down event on a clickpad. To avoid + * spurious pointer moves by the clicking finger we pin all fingers. + * We unpin fingers when they move more then a certain threshold to + * to allow drag and drop. */ if ((tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) && !tp->buttons.has_buttons) - tp_pin_finger(tp); + tp_pin_fingers(tp); } static void @@ -441,9 +440,6 @@ tp_post_process_state(struct tp_dispatch *tp, uint32_t time) tp->buttons.old_state = tp->buttons.state; - if (tp->queued & TOUCHPAD_EVENT_BUTTON_RELEASE) - tp_unpin_finger(tp); - tp->queued = TOUCHPAD_EVENT_NONE; } @@ -798,6 +794,8 @@ tp_init(struct tp_dispatch *tp, tp->hysteresis.margin_y = diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR; + tp->buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD; + if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE) || libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) tp->buttons.has_buttons = true; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 2bdb3295..e5fbd7a9 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -77,7 +77,6 @@ struct tp_touch { bool dirty; bool fake; /* a fake touch */ bool is_pointer; /* the pointer-controlling touch */ - bool is_pinned; /* holds the phys. button */ int32_t x; int32_t y; uint32_t millis; @@ -92,6 +91,16 @@ struct tp_touch { int32_t center_x; int32_t center_y; } hysteresis; + + /* A pinned touchpoint is the one that pressed the physical button + * on a clickpad. After the release, it won't move until the center + * moves more than a threshold away from the original coordinates + */ + struct { + bool is_pinned; + int32_t center_x; + int32_t center_y; + } pinned; }; struct tp_dispatch { @@ -122,6 +131,7 @@ struct tp_dispatch { bool has_buttons; /* true for physical LMR buttons */ uint32_t state; uint32_t old_state; + uint32_t motion_dist; /* for pinned touches */ } buttons; /* physical buttons */ struct { From ae875520d1f8ae8ebf7beb98e8fcfc88bcef8c5a Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 15 Apr 2014 14:28:00 +0200 Subject: [PATCH 03/16] touchpad: reset the tap timer_fd to -1 on destroy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No real effect, just for safety Signed-off-by: Peter Hutterer Signed-off-by: Hans de Goede Reviewed-by: Jonas Ådahl Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad-tap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index 5fa712f6..bcc5700c 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -615,6 +615,8 @@ tp_destroy_tap(struct tp_dispatch *tp) libinput_remove_source(tp->device->base.seat->libinput, tp->tap.source); tp->tap.source = NULL; } - if (tp->tap.timer_fd > -1) + if (tp->tap.timer_fd > -1) { close(tp->tap.timer_fd); + tp->tap.timer_fd = -1; + } } From 21d7b2b50acf7971dbf86e378d4897e73b64fe18 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 27 Mar 2014 13:09:06 +1000 Subject: [PATCH 04/16] touchpad: move button-related code into a separate file This is about to become more complicated with the support for software button areas. Move it to a separate file to have it logically grouped together. No functional changes. Signed-off-by: Peter Hutterer Signed-off-by: Hans de Goede Reviewed-by: Hans de Goede --- src/Makefile.am | 1 + src/evdev-mt-touchpad-buttons.c | 145 ++++++++++++++++++++++++++++++++ src/evdev-mt-touchpad.c | 102 +--------------------- src/evdev-mt-touchpad.h | 11 +++ 4 files changed, 161 insertions(+), 98 deletions(-) create mode 100644 src/evdev-mt-touchpad-buttons.c diff --git a/src/Makefile.am b/src/Makefile.am index 471bc1d9..68e02dec 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,6 +14,7 @@ libinput_la_SOURCES = \ evdev-mt-touchpad.c \ evdev-mt-touchpad.h \ evdev-mt-touchpad-tap.c \ + evdev-mt-touchpad-buttons.c \ evdev-touchpad.c \ filter.c \ filter.h \ diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c new file mode 100644 index 00000000..640c699d --- /dev/null +++ b/src/evdev-mt-touchpad-buttons.c @@ -0,0 +1,145 @@ +/* + * Copyright © 2014 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 the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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 + +#include "evdev-mt-touchpad.h" + +#define DEFAULT_BUTTON_MOTION_THRESHOLD 0.02 /* 2% of size */ + +int +tp_process_button(struct tp_dispatch *tp, + const struct input_event *e, + uint32_t time) +{ + uint32_t mask = 1 << (e->code - BTN_LEFT); + if (e->value) { + tp->buttons.state |= mask; + tp->queued |= TOUCHPAD_EVENT_BUTTON_PRESS; + } else { + tp->buttons.state &= ~mask; + tp->queued |= TOUCHPAD_EVENT_BUTTON_RELEASE; + } + + return 0; +} + +int +tp_init_buttons(struct tp_dispatch *tp, + struct evdev_device *device) +{ + int width, height; + double diagonal; + + if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE) || + libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) + tp->buttons.has_buttons = true; + + width = abs(device->abs.max_x - device->abs.min_x); + height = abs(device->abs.max_y - device->abs.min_y); + diagonal = sqrt(width*width + height*height); + + tp->buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD; + + return 0; +} + +static int +tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint32_t time) +{ + uint32_t current, old, button; + enum libinput_pointer_button_state state; + + current = tp->buttons.state; + old = tp->buttons.old_state; + + if (current == old) + return 0; + + switch (tp->nfingers_down) { + case 1: button = BTN_LEFT; break; + case 2: button = BTN_RIGHT; break; + case 3: button = BTN_MIDDLE; break; + default: + return 0; + } + + if (current) + state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED; + else + state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED; + + pointer_notify_button(&tp->device->base, + time, + button, + state); + return 1; +} + +static int +tp_post_physical_buttons(struct tp_dispatch *tp, uint32_t time) +{ + uint32_t current, old, button; + + current = tp->buttons.state; + old = tp->buttons.old_state; + button = BTN_LEFT; + + while (current || old) { + enum libinput_pointer_button_state state; + + if ((current & 0x1) ^ (old & 0x1)) { + if (!!(current & 0x1)) + state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED; + else + state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED; + + pointer_notify_button(&tp->device->base, + time, + button, + state); + } + + button++; + current >>= 1; + old >>= 1; + } + + return 0; +} + +int +tp_post_button_events(struct tp_dispatch *tp, uint32_t time) +{ + int rc; + + if ((tp->queued & + (TOUCHPAD_EVENT_BUTTON_PRESS|TOUCHPAD_EVENT_BUTTON_RELEASE)) == 0) + return 0; + + if (tp->buttons.has_buttons) + rc = tp_post_physical_buttons(tp, time); + else + rc = tp_post_clickfinger_buttons(tp, time); + + return rc; +} diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 54a95ef3..c86b0578 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -32,7 +32,6 @@ #define DEFAULT_MIN_ACCEL_FACTOR 0.16 #define DEFAULT_MAX_ACCEL_FACTOR 1.0 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0 -#define DEFAULT_BUTTON_MOTION_THRESHOLD 0.02 /* 2% of size */ static inline int tp_hysteresis(int in, int center, int margin) @@ -323,20 +322,11 @@ tp_process_key(struct tp_dispatch *tp, const struct input_event *e, uint32_t time) { - uint32_t mask; - switch (e->code) { case BTN_LEFT: case BTN_MIDDLE: case BTN_RIGHT: - mask = 1 << (e->code - BTN_LEFT); - if (e->value) { - tp->buttons.state |= mask; - tp->queued |= TOUCHPAD_EVENT_BUTTON_PRESS; - } else { - tp->buttons.state &= ~mask; - tp->queued |= TOUCHPAD_EVENT_BUTTON_RELEASE; - } + tp_process_button(tp, e, time); break; case BTN_TOUCH: case BTN_TOOL_DOUBLETAP: @@ -534,87 +524,6 @@ tp_post_scroll_events(struct tp_dispatch *tp, uint32_t time) return 0; } -static int -tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint32_t time) -{ - uint32_t current, old, button; - enum libinput_pointer_button_state state; - - current = tp->buttons.state; - old = tp->buttons.old_state; - - if (current == old) - return 0; - - switch (tp->nfingers_down) { - case 1: button = BTN_LEFT; break; - case 2: button = BTN_RIGHT; break; - case 3: button = BTN_MIDDLE; break; - default: - return 0; - } - - if (current) - state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED; - else - state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED; - - pointer_notify_button(&tp->device->base, - time, - button, - state); - return 1; -} - -static int -tp_post_physical_buttons(struct tp_dispatch *tp, uint32_t time) -{ - uint32_t current, old, button; - - current = tp->buttons.state; - old = tp->buttons.old_state; - button = BTN_LEFT; - - while (current || old) { - enum libinput_pointer_button_state state; - - if ((current & 0x1) ^ (old & 0x1)) { - if (!!(current & 0x1)) - state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED; - else - state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED; - - pointer_notify_button(&tp->device->base, - time, - button, - state); - } - - button++; - current >>= 1; - old >>= 1; - } - - return 0; -} - -static int -tp_post_button_events(struct tp_dispatch *tp, uint32_t time) -{ - int rc; - - if ((tp->queued & - (TOUCHPAD_EVENT_BUTTON_PRESS|TOUCHPAD_EVENT_BUTTON_RELEASE)) == 0) - return 0; - - if (tp->buttons.has_buttons) - rc = tp_post_physical_buttons(tp, time); - else - rc = tp_post_clickfinger_buttons(tp, time); - - return rc; -} - static void tp_post_events(struct tp_dispatch *tp, uint32_t time) { @@ -794,12 +703,6 @@ tp_init(struct tp_dispatch *tp, tp->hysteresis.margin_y = diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR; - tp->buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD; - - if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE) || - libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) - tp->buttons.has_buttons = true; - if (tp_init_scroll(tp) != 0) return -1; @@ -809,6 +712,9 @@ tp_init(struct tp_dispatch *tp, if (tp_init_tap(tp) != 0) return -1; + if (tp_init_buttons(tp, device) != 0) + return -1; + return 0; } diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index e5fbd7a9..d84c9e8e 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -168,4 +168,15 @@ tp_init_tap(struct tp_dispatch *tp); void tp_destroy_tap(struct tp_dispatch *tp); +int +tp_init_buttons(struct tp_dispatch *tp, struct evdev_device *device); + +int +tp_process_button(struct tp_dispatch *tp, + const struct input_event *e, + uint32_t time); + +int +tp_post_button_events(struct tp_dispatch *tp, uint32_t time); + #endif From 1c0805a559c2388ea3ccb1117d2c6633b0ee1963 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 28 Mar 2014 15:51:08 +1000 Subject: [PATCH 05/16] doc: add state machine SVG to EXTRA_DIST Signed-off-by: Peter Hutterer Signed-off-by: Hans de Goede Reviewed-by: Hans de Goede --- doc/Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index 31b673b3..75fa98a4 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,3 +1,5 @@ +EXTRA_DIST = touchpad-tap-state-machine.svg + if HAVE_DOXYGEN noinst_DATA = html/index.html @@ -12,7 +14,7 @@ clean-local: $(AM_V_at)rm -rf html doc_src= $(shell find html -type f -printf "html/%P\n" 2>/dev/null) -EXTRA_DIST = $(builddir)/html/index.html $(doc_src) +EXTRA_DIST += $(builddir)/html/index.html $(doc_src) endif From 2f9607a4893b3ee7d98a9a8f8dac9971529a0d95 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 27 Mar 2014 15:51:12 +1000 Subject: [PATCH 06/16] touchpad: save the active clickfinger button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid having a button left press and a button right release if the number of fingers changes. Signed-off-by: Peter Hutterer Signed-off-by: Hans de Goede Reviewed-by: Jonas Ådahl Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad-buttons.c | 24 ++++++++++++++---------- src/evdev-mt-touchpad.h | 1 + 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 640c699d..21241de7 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -75,23 +75,27 @@ tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint32_t time) if (current == old) return 0; - switch (tp->nfingers_down) { + if (current) { + switch (tp->nfingers_down) { case 1: button = BTN_LEFT; break; case 2: button = BTN_RIGHT; break; case 3: button = BTN_MIDDLE; break; default: return 0; + } + tp->buttons.active = button; + state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED; + } else { + button = tp->buttons.active; + tp->buttons.active = 0; + state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED; } - if (current) - state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED; - else - state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED; - - pointer_notify_button(&tp->device->base, - time, - button, - state); + if (button) + pointer_notify_button(&tp->device->base, + time, + button, + state); return 1; } diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index d84c9e8e..85cf7e54 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -132,6 +132,7 @@ struct tp_dispatch { uint32_t state; uint32_t old_state; uint32_t motion_dist; /* for pinned touches */ + unsigned int active; /* currently active button, for release event */ } buttons; /* physical buttons */ struct { From e192ecc6e934fd5f77dbc9d8a21746947e8fa61d Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 28 Mar 2014 09:44:11 +1000 Subject: [PATCH 07/16] touchpad: Add clickpad-style software buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Almost all non Apple touchpads have visible markings for software button areas, so limit clickfinger behavior to Apple clickpads, and implement software button areas for others. This is a slightly fancier implementation than the simplest model and ported over from libtouchpad. It implements a state machine for the software buttons with left and right buttons currently implemented. Buttons are oriented left-to-right, in a horizontal bar. No random button placement allowed. In general, the procedure is: - if a finger sets down in the left button area, a click is a left click - if a finger sets down in the right button area, a click is a right click - if a finger leaves the button area, a click is a left click - if a finger starts outside the button area, a click is a left click Two timeouts are used to handle buttons more smoothly: - if a finger sets down in a button area but "immediately" moves over to a different area, that area takes effect on a click. - if a finger leaves a button area and "immediately" clicks or moves back into the area, the button still takes effect on a click. - if a finger changes between areas and stays there for a timeout, that area takes effect on a click. Note the button area states are named BOTTOM_foo to make it easier to later add support for a top button area such as can be found on the Thinkpad [2-5]40 series. Co-authored-by: Hans de Goede Signed-off-by: Peter Hutterer Signed-off-by: Hans de Goede Reviewed-by: Jonas Ådahl Reviewed-by: Hans de Goede Reviewed-by: Peter Hutterer --- doc/Makefile.am | 2 +- doc/touchpad-softbutton-state-machine.svg | 173 ++++++++ src/evdev-mt-touchpad-buttons.c | 455 +++++++++++++++++++++- src/evdev-mt-touchpad.c | 15 + src/evdev-mt-touchpad.h | 49 +++ src/libinput.h | 40 ++ test/touchpad.c | 12 +- 7 files changed, 739 insertions(+), 7 deletions(-) create mode 100644 doc/touchpad-softbutton-state-machine.svg diff --git a/doc/Makefile.am b/doc/Makefile.am index 75fa98a4..a33638da 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,4 +1,4 @@ -EXTRA_DIST = touchpad-tap-state-machine.svg +EXTRA_DIST = touchpad-tap-state-machine.svg touchpad-softbutton-state-machine.svg if HAVE_DOXYGEN diff --git a/doc/touchpad-softbutton-state-machine.svg b/doc/touchpad-softbutton-state-machine.svg new file mode 100644 index 00000000..1838e354 --- /dev/null +++ b/doc/touchpad-softbutton-state-machine.svg @@ -0,0 +1,173 @@ + + + + + + + + +NONE + +on-entry: + +curr = none + + + + +BOTTOM_NEW + +on-entry: + +curr = button + +start inner timeout + + + + +AREA + +on-entry: + +curr =area + + + + +finger in + +area + + + + +BOTTOM + + + + +finger + +up + + + + +phys + +button + +press + + + + + + +inner + +timeout + + + + + + + + +finger in + +AREA + + + + + + +BOTTOM_TO_AREA + +on-entry: + +start outer timeout + + + + + + +outer + +timeout + + + + + + + + +finger in + +bottom + + + + + + + + +finger in + +area + + + + + + + + +finger in + +bottom + +button != curr + + + + + + + + +ANY + + + + + + + + + + + + +finger in + +bottom + +button == curr + + + + + + + + + + + diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 21241de7..1ddd8df9 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -20,11 +20,345 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include +#include +#include #include +#include +#include +#include +#include #include "evdev-mt-touchpad.h" #define DEFAULT_BUTTON_MOTION_THRESHOLD 0.02 /* 2% of size */ +#define DEFAULT_BUTTON_ENTER_TIMEOUT 100 /* ms */ +#define DEFAULT_BUTTON_LEAVE_TIMEOUT 300 /* ms */ + +/***************************************** + * BEFORE YOU EDIT THIS FILE, look at the state diagram in + * doc/touchpad-softbutton-state-machine.svg, or online at + * https://drive.google.com/file/d/0B1NwWmji69nocUs1cVJTbkdwMFk/edit?usp=sharing + * (it's a http://draw.io diagram) + * + * Any changes in this file must be represented in the diagram. + * + * The state machine only affects the soft button area code. + */ + +#define CASE_RETURN_STRING(a) case a: return #a; + +static inline const char* +button_state_to_str(enum button_state state) { + switch(state) { + CASE_RETURN_STRING(BUTTON_STATE_NONE); + CASE_RETURN_STRING(BUTTON_STATE_AREA); + CASE_RETURN_STRING(BUTTON_STATE_BOTTOM); + CASE_RETURN_STRING(BUTTON_STATE_BOTTOM_NEW); + CASE_RETURN_STRING(BUTTON_STATE_BOTTOM_TO_AREA); + } + return NULL; +} + +static inline const char* +button_event_to_str(enum button_event event) { + switch(event) { + CASE_RETURN_STRING(BUTTON_EVENT_IN_BOTTOM_R); + CASE_RETURN_STRING(BUTTON_EVENT_IN_BOTTOM_L); + CASE_RETURN_STRING(BUTTON_EVENT_IN_AREA); + CASE_RETURN_STRING(BUTTON_EVENT_UP); + CASE_RETURN_STRING(BUTTON_EVENT_PRESS); + CASE_RETURN_STRING(BUTTON_EVENT_RELEASE); + CASE_RETURN_STRING(BUTTON_EVENT_TIMEOUT); + } + return NULL; +} + +static inline bool +is_inside_button_area(struct tp_dispatch *tp, struct tp_touch *t) +{ + return t->y >= tp->buttons.area.top_edge; +} + +static inline bool +is_inside_right_area(struct tp_dispatch *tp, struct tp_touch *t) +{ + return is_inside_button_area(tp, t) && + t->x > tp->buttons.area.rightbutton_left_edge; +} + +static inline bool +is_inside_left_area(struct tp_dispatch *tp, struct tp_touch *t) +{ + return is_inside_button_area(tp, t) && + !is_inside_right_area(tp, t); +} + +static void +tp_button_set_timer(struct tp_dispatch *tp, uint32_t timeout) +{ + struct itimerspec its; + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + its.it_value.tv_sec = timeout / 1000; + its.it_value.tv_nsec = (timeout % 1000) * 1000 * 1000; + timerfd_settime(tp->buttons.timer_fd, TFD_TIMER_ABSTIME, &its, NULL); +} + +static void +tp_button_set_enter_timer(struct tp_dispatch *tp, struct tp_touch *t) +{ + t->button.timeout = t->millis + DEFAULT_BUTTON_ENTER_TIMEOUT; + tp_button_set_timer(tp, t->button.timeout); +} + +static void +tp_button_set_leave_timer(struct tp_dispatch *tp, struct tp_touch *t) +{ + t->button.timeout = t->millis + DEFAULT_BUTTON_LEAVE_TIMEOUT; + tp_button_set_timer(tp, t->button.timeout); +} + +static void +tp_button_clear_timer(struct tp_dispatch *tp, struct tp_touch *t) +{ + t->button.timeout = 0; +} + +/* + * tp_button_set_state, change state and implement on-entry behavior + * as described in the state machine diagram. + */ +static void +tp_button_set_state(struct tp_dispatch *tp, struct tp_touch *t, + enum button_state new_state, enum button_event event) +{ + tp_button_clear_timer(tp, t); + + t->button.state = new_state; + switch (t->button.state) { + case BUTTON_STATE_NONE: + t->button.curr = 0; + break; + case BUTTON_STATE_AREA: + t->button.curr = BUTTON_EVENT_IN_AREA; + break; + case BUTTON_STATE_BOTTOM: + break; + case BUTTON_STATE_BOTTOM_NEW: + t->button.curr = event; + tp_button_set_enter_timer(tp, t); + break; + case BUTTON_STATE_BOTTOM_TO_AREA: + tp_button_set_leave_timer(tp, t); + break; + } +} + +static void +tp_button_none_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum button_event event) +{ + switch (event) { + case BUTTON_EVENT_IN_BOTTOM_R: + case BUTTON_EVENT_IN_BOTTOM_L: + tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW, event); + break; + case BUTTON_EVENT_IN_AREA: + tp_button_set_state(tp, t, BUTTON_STATE_AREA, event); + break; + case BUTTON_EVENT_UP: + tp_button_set_state(tp, t, BUTTON_STATE_NONE, event); + break; + case BUTTON_EVENT_PRESS: + case BUTTON_EVENT_RELEASE: + case BUTTON_EVENT_TIMEOUT: + break; + } +} + +static void +tp_button_area_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum button_event event) +{ + switch (event) { + case BUTTON_EVENT_IN_BOTTOM_R: + case BUTTON_EVENT_IN_BOTTOM_L: + case BUTTON_EVENT_IN_AREA: + break; + case BUTTON_EVENT_UP: + tp_button_set_state(tp, t, BUTTON_STATE_NONE, event); + break; + case BUTTON_EVENT_PRESS: + case BUTTON_EVENT_RELEASE: + case BUTTON_EVENT_TIMEOUT: + break; + } +} + +static void +tp_button_bottom_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum button_event event) +{ + switch (event) { + case BUTTON_EVENT_IN_BOTTOM_R: + case BUTTON_EVENT_IN_BOTTOM_L: + if (event != t->button.curr) + tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW, + event); + break; + case BUTTON_EVENT_IN_AREA: + tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_TO_AREA, event); + break; + case BUTTON_EVENT_UP: + tp_button_set_state(tp, t, BUTTON_STATE_NONE, event); + break; + case BUTTON_EVENT_PRESS: + case BUTTON_EVENT_RELEASE: + case BUTTON_EVENT_TIMEOUT: + break; + } +} + +static void +tp_button_bottom_new_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum button_event event) +{ + switch(event) { + case BUTTON_EVENT_IN_BOTTOM_R: + case BUTTON_EVENT_IN_BOTTOM_L: + if (event != t->button.curr) + tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW, + event); + break; + case BUTTON_EVENT_IN_AREA: + tp_button_set_state(tp, t, BUTTON_STATE_AREA, event); + break; + case BUTTON_EVENT_UP: + tp_button_set_state(tp, t, BUTTON_STATE_NONE, event); + break; + case BUTTON_EVENT_PRESS: + tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM, event); + break; + case BUTTON_EVENT_RELEASE: + break; + case BUTTON_EVENT_TIMEOUT: + tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM, event); + break; + } +} + +static void +tp_button_bottom_to_area_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum button_event event) +{ + switch(event) { + case BUTTON_EVENT_IN_BOTTOM_R: + case BUTTON_EVENT_IN_BOTTOM_L: + if (event == t->button.curr) + tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM, + event); + else + tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM_NEW, + event); + break; + case BUTTON_EVENT_IN_AREA: + break; + case BUTTON_EVENT_UP: + tp_button_set_state(tp, t, BUTTON_STATE_NONE, event); + break; + case BUTTON_EVENT_PRESS: + case BUTTON_EVENT_RELEASE: + break; + case BUTTON_EVENT_TIMEOUT: + tp_button_set_state(tp, t, BUTTON_STATE_AREA, event); + break; + } +} + +static void +tp_button_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum button_event event, + uint32_t time) +{ + enum button_state current = t->button.state; + + switch(t->button.state) { + case BUTTON_STATE_NONE: + tp_button_none_handle_event(tp, t, event); + break; + case BUTTON_STATE_AREA: + tp_button_area_handle_event(tp, t, event); + break; + case BUTTON_STATE_BOTTOM: + tp_button_bottom_handle_event(tp, t, event); + break; + case BUTTON_STATE_BOTTOM_NEW: + tp_button_bottom_new_handle_event(tp, t, event); + break; + case BUTTON_STATE_BOTTOM_TO_AREA: + tp_button_bottom_to_area_handle_event(tp, t, event); + break; + } + + if (current != t->button.state) + log_debug("button state: from %s, event %s to %s\n", + button_state_to_str(current), + button_event_to_str(event), + button_state_to_str(t->button.state)); +} + +int +tp_button_handle_state(struct tp_dispatch *tp, uint32_t time) +{ + struct tp_touch *t; + + tp_for_each_touch(tp, t) { + if (t->state == TOUCH_NONE) + continue; + + if (t->state == TOUCH_END) { + tp_button_handle_event(tp, t, BUTTON_EVENT_UP, time); + } else if (t->dirty) { + if (is_inside_right_area(tp, t)) + tp_button_handle_event(tp, t, BUTTON_EVENT_IN_BOTTOM_R, time); + else if (is_inside_left_area(tp, t)) + tp_button_handle_event(tp, t, BUTTON_EVENT_IN_BOTTOM_L, time); + else + tp_button_handle_event(tp, t, BUTTON_EVENT_IN_AREA, time); + } + if (tp->queued & TOUCHPAD_EVENT_BUTTON_RELEASE) + tp_button_handle_event(tp, t, BUTTON_EVENT_RELEASE, time); + if (tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) + tp_button_handle_event(tp, t, BUTTON_EVENT_PRESS, time); + } + + return 0; +} + +static int +tp_button_handle_timeout(struct tp_dispatch *tp, uint32_t now) +{ + struct tp_touch *t; + uint32_t min_timeout = INT_MAX; + + tp_for_each_touch(tp, t) { + if (t->button.timeout != 0 && t->button.timeout <= now) { + tp_button_clear_timer(tp, t); + tp_button_handle_event(tp, t, BUTTON_EVENT_TIMEOUT, now); + } + if (t->button.timeout != 0) + min_timeout = min(t->button.timeout, min_timeout); + } + + return min_timeout == INT_MAX ? 0 : min_timeout; +} int tp_process_button(struct tp_dispatch *tp, @@ -43,6 +377,28 @@ tp_process_button(struct tp_dispatch *tp, return 0; } +static void +tp_button_timeout_handler(void *data) +{ + struct tp_dispatch *tp = data; + uint64_t expires; + int len; + struct timespec ts; + uint32_t now; + + len = read(tp->buttons.timer_fd, &expires, sizeof expires); + if (len != sizeof expires) + /* This will only happen if the application made the fd + * non-blocking, but this function should only be called + * upon the timeout, so lets continue anyway. */ + log_error("timerfd read error: %s\n", strerror(errno)); + + clock_gettime(CLOCK_MONOTONIC, &ts); + now = ts.tv_sec * 1000 + ts.tv_nsec / 1000000; + + tp_button_handle_timeout(tp, now); +} + int tp_init_buttons(struct tp_dispatch *tp, struct evdev_device *device) @@ -60,9 +416,48 @@ tp_init_buttons(struct tp_dispatch *tp, tp->buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD; + if (libevdev_get_id_vendor(device->evdev) == 0x5ac) /* Apple */ + tp->buttons.use_clickfinger = true; + + tp->buttons.use_softbuttons = !tp->buttons.use_clickfinger && + !tp->buttons.has_buttons; + + if (tp->buttons.use_softbuttons) { + tp->buttons.area.top_edge = height * .8 + device->abs.min_y; + tp->buttons.area.rightbutton_left_edge = width/2 + device->abs.min_x; + tp->buttons.timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); + + if (tp->buttons.timer_fd == -1) + return -1; + + tp->buttons.source = + libinput_add_fd(tp->device->base.seat->libinput, + tp->buttons.timer_fd, + tp_button_timeout_handler, + tp); + if (tp->buttons.source == NULL) + return -1; + } else { + tp->buttons.area.top_edge = INT_MAX; + } + return 0; } +void +tp_destroy_buttons(struct tp_dispatch *tp) +{ + if (tp->buttons.source) { + libinput_remove_source(tp->device->base.seat->libinput, + tp->buttons.source); + tp->buttons.source = NULL; + } + if (tp->buttons.timer_fd > -1) { + close(tp->buttons.timer_fd); + tp->buttons.timer_fd = -1; + } +} + static int tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint32_t time) { @@ -131,10 +526,63 @@ tp_post_physical_buttons(struct tp_dispatch *tp, uint32_t time) return 0; } +static int +tp_post_softbutton_buttons(struct tp_dispatch *tp, uint32_t time) +{ + uint32_t current, old, button; + enum libinput_pointer_button_state state; + + current = tp->buttons.state; + old = tp->buttons.old_state; + + if (current == old) + return 0; + + if (tp->nfingers_down == 0 || tp->nfingers_down > 2) + return 0; + + if (current) { + struct tp_touch *t; + button = 0; + + tp_for_each_touch(tp, t) { + if (t->button.curr == BUTTON_EVENT_IN_BOTTOM_R) + button |= 0x2; + else if (t->button.curr == BUTTON_EVENT_IN_BOTTOM_L) + button |= 0x1; + } + + switch (button) { + case 0: /* only in area */ + case 1: /* only left area */ + button = BTN_LEFT; + break; + case 2: /* only right area */ + button = BTN_RIGHT; + break; + case 3: /* left + right area */ + button = BTN_MIDDLE; + break; + } + + tp->buttons.active = button; + state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED; + } else { + state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED; + button = tp->buttons.active; + } + + pointer_notify_button(&tp->device->base, + time, + button, + state); + return 1; +} + int tp_post_button_events(struct tp_dispatch *tp, uint32_t time) { - int rc; + int rc = 0; if ((tp->queued & (TOUCHPAD_EVENT_BUTTON_PRESS|TOUCHPAD_EVENT_BUTTON_RELEASE)) == 0) @@ -142,8 +590,11 @@ tp_post_button_events(struct tp_dispatch *tp, uint32_t time) if (tp->buttons.has_buttons) rc = tp_post_physical_buttons(tp, time); - else + else if (tp->buttons.use_clickfinger) rc = tp_post_clickfinger_buttons(tp, time); + else if (tp->buttons.use_softbuttons) + rc = tp_post_softbutton_buttons(tp, time); + return rc; } diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index c86b0578..7f73f6ee 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -399,6 +399,8 @@ tp_process_state(struct tp_dispatch *tp, uint32_t time) tp_unpin_finger(tp, t); } + tp_button_handle_state(tp, time); + /* * We have a physical button down event on a clickpad. To avoid * spurious pointer moves by the clicking finger we pin all fingers. @@ -596,6 +598,7 @@ tp_destroy(struct evdev_dispatch *dispatch) (struct tp_dispatch*)dispatch; tp_destroy_tap(tp); + tp_destroy_buttons(tp); if (tp->filter) tp->filter->interface->destroy(tp->filter); @@ -608,10 +611,18 @@ static struct evdev_dispatch_interface tp_interface = { tp_destroy }; +static void +tp_init_touch(struct tp_dispatch *tp, + struct tp_touch *t) +{ + t->button.state = BUTTON_STATE_NONE; +} + static int tp_init_slots(struct tp_dispatch *tp, struct evdev_device *device) { + size_t i; const struct input_absinfo *absinfo; absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_SLOT); @@ -649,6 +660,9 @@ tp_init_slots(struct tp_dispatch *tp, if (!tp->touches) return -1; + for (i = 0; i < tp->ntouches; i++) + tp_init_touch(tp, &tp->touches[i]); + return 0; } @@ -690,6 +704,7 @@ tp_init(struct tp_dispatch *tp, tp->base.interface = &tp_interface; tp->device = device; tp->tap.timer_fd = -1; + tp->buttons.timer_fd = -1; if (tp_init_slots(tp, device) != 0) return -1; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 85cf7e54..8d8dd840 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -46,6 +46,24 @@ enum touch_state { TOUCH_END }; +enum button_event { + BUTTON_EVENT_IN_BOTTOM_R = 30, + BUTTON_EVENT_IN_BOTTOM_L, + BUTTON_EVENT_IN_AREA, + BUTTON_EVENT_UP, + BUTTON_EVENT_PRESS, + BUTTON_EVENT_RELEASE, + BUTTON_EVENT_TIMEOUT, +}; + +enum button_state { + BUTTON_STATE_NONE, + BUTTON_STATE_AREA, + BUTTON_STATE_BOTTOM, + BUTTON_STATE_BOTTOM_NEW, + BUTTON_STATE_BOTTOM_TO_AREA, +}; + enum scroll_state { SCROLL_STATE_NONE, SCROLL_STATE_SCROLLING @@ -101,6 +119,14 @@ struct tp_touch { int32_t center_x; int32_t center_y; } pinned; + + /* Software-button state and timeout if applicable */ + struct { + enum button_state state; + /* We use button_event here so we can use == on events */ + enum button_event curr; + uint32_t timeout; + } button; }; struct tp_dispatch { @@ -129,10 +155,27 @@ struct tp_dispatch { struct { bool has_buttons; /* true for physical LMR buttons */ + bool use_clickfinger; /* number of fingers decides button number */ + bool use_softbuttons; /* use software-button area */ uint32_t state; uint32_t old_state; uint32_t motion_dist; /* for pinned touches */ unsigned int active; /* currently active button, for release event */ + + /* Only used if has_buttons is false. The software button area is always + * a horizontal strip across the touchpad. Depending on the + * rightbutton_left_edge value, the buttons are split according to the + * edge settings. + */ + struct { + int32_t top_edge; + int32_t rightbutton_left_edge; + } area; + + unsigned int timeout; /* current timeout in ms */ + + int timer_fd; + struct libinput_source *source; } buttons; /* physical buttons */ struct { @@ -172,6 +215,9 @@ tp_destroy_tap(struct tp_dispatch *tp); int tp_init_buttons(struct tp_dispatch *tp, struct evdev_device *device); +void +tp_destroy_buttons(struct tp_dispatch *tp); + int tp_process_button(struct tp_dispatch *tp, const struct input_event *e, @@ -180,4 +226,7 @@ tp_process_button(struct tp_dispatch *tp, int tp_post_button_events(struct tp_dispatch *tp, uint32_t time); +int +tp_button_handle_state(struct tp_dispatch *tp, uint32_t time); + #endif diff --git a/src/libinput.h b/src/libinput.h index 85c7d717..d771e21c 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -38,6 +38,46 @@ extern "C" { * behind an API. */ +/** + * @page tpbuttons Touchpad button behavior + * + * For touchpad devices without physical buttons, libinput enables an + * emulated right button area through either of two methods. + * + * Software button areas + * ===================== + * On most touchpads, the bottom area of the touchpad is split into a a left + * and a right-button area. Pressing the touchpad down with a finger in + * those areas will generate clicks as shown in the diagram below: + * + * @code + +------------------------+ + | | + | | + | LEFT | + | | + | | + +------------------------+ + | LEFT | RIGHT | + +------------------------+ + * @endcode + * + * Generally, the touchpad will emulate a right-button click if the finger + * was set down in the right button area and did not leave the + * right button area before clicking, even if another finger was already + * down on the touchpad in another area. + * A middle click is generated by clicking the touchpad when one finger is + * in the bottom left button area, and one finger is in the botton right + * button area. + * The exact behavior of the touchpad is implementation-dependent. + * + * Clickfinger + * =========== + * On Apple touchpads, no button areas are provided. Instead, use a + * two-finger click for a right button click, and a three-finger click for a + * middle button click. + */ + /** * @ingroup fixed_point * diff --git a/test/touchpad.c b/test/touchpad.c index f4d78391..bbae6cd8 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -217,7 +217,7 @@ END_TEST START_TEST(touchpad_1fg_clickfinger) { - struct litest_device *dev = litest_current_device(); + struct litest_device *dev = litest_create_device(LITEST_BCM5974); struct libinput *li = dev->libinput; struct libinput_event *event; struct libinput_event_pointer *ptrev; @@ -237,12 +237,14 @@ START_TEST(touchpad_1fg_clickfinger) LIBINPUT_POINTER_BUTTON_STATE_PRESSED); assert_button_event(li, BTN_LEFT, LIBINPUT_POINTER_BUTTON_STATE_RELEASED); + + litest_delete_device(dev); } END_TEST START_TEST(touchpad_2fg_clickfinger) { - struct litest_device *dev = litest_current_device(); + struct litest_device *dev = litest_create_device(LITEST_BCM5974); struct libinput *li = dev->libinput; struct libinput_event *event; struct libinput_event_pointer *ptrev; @@ -264,6 +266,8 @@ START_TEST(touchpad_2fg_clickfinger) LIBINPUT_POINTER_BUTTON_STATE_PRESSED); assert_button_event(li, BTN_RIGHT, LIBINPUT_POINTER_BUTTON_STATE_RELEASED); + + litest_delete_device(dev); } END_TEST @@ -362,8 +366,8 @@ int main(int argc, char **argv) { litest_add("touchpad:tap", touchpad_1fg_tap_n_drag, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:tap", touchpad_2fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); - litest_add("touchpad:clickfinger", touchpad_1fg_clickfinger, LITEST_TOUCHPAD, LITEST_ANY); - litest_add("touchpad:clickfinger", touchpad_2fg_clickfinger, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add_no_device("touchpad:clickfinger", touchpad_1fg_clickfinger); + litest_add_no_device("touchpad:clickfinger", touchpad_2fg_clickfinger); litest_add("touchpad:click", touchpad_btn_left, LITEST_TOUCHPAD, LITEST_CLICKPAD); litest_add("touchpad:click", clickpad_btn_left, LITEST_CLICKPAD, LITEST_ANY); From 55d84420e2cc9e7a79aae63d025528e0b2d5a5a1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 4 Apr 2014 17:22:02 +0200 Subject: [PATCH 08/16] touchpad: Rework is_pointer handling We don't want touches in the button area to cause the pointer to move. So instead of making a touch the pointer when it moves to TOUCH_BEGIN, wait with making it the pointer until its buttons state moves to BUTTON_STATE_AREA. Note that a touch in the main area of the touchpad will move to BUTTON_STATE_AREA immediately. If software-buttons are not enabled, any finger is in the BUTTON_STATE_AREA. While at it also refactor the is_pointer setting in general, removing code duplicition wrt checking that another touch is not already the pointer on unpinning a finger, and add safeguards that unpinning does not make a finger which is not in button state BUTTON_STATE_AREA the pointer, nor that the button code makes a pinned finger the pointer. All these sanity checks are combined into a new tp_button_active function, since they should be taken into account for 2 finger scrolling, etc. too. Signed-off-by: Hans de Goede Signed-off-by: Peter Hutterer Reviewed-by: Peter Hutterer --- src/evdev-mt-touchpad-buttons.c | 7 +++++ src/evdev-mt-touchpad.c | 50 +++++++++++++++++---------------- src/evdev-mt-touchpad.h | 6 ++++ test/touchpad.c | 8 +++--- 4 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 1ddd8df9..618377be 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -142,6 +142,7 @@ tp_button_set_state(struct tp_dispatch *tp, struct tp_touch *t, break; case BUTTON_STATE_AREA: t->button.curr = BUTTON_EVENT_IN_AREA; + tp_set_pointer(tp, t); break; case BUTTON_STATE_BOTTOM: break; @@ -598,3 +599,9 @@ tp_post_button_events(struct tp_dispatch *tp, uint32_t time) return rc; } + +int +tp_button_touch_active(struct tp_dispatch *tp, struct tp_touch *t) +{ + return t->button.state == BUTTON_STATE_AREA; +} diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 7f73f6ee..b15de29f 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -152,8 +152,6 @@ tp_get_touch(struct tp_dispatch *tp, unsigned int slot) static inline void tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t) { - struct tp_touch *tmp = NULL; - if (t->state != TOUCH_UPDATE) { tp_motion_history_reset(t); t->dirty = true; @@ -162,15 +160,6 @@ tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t) tp->nfingers_down++; assert(tp->nfingers_down >= 1); tp->queued |= TOUCHPAD_EVENT_MOTION; - - tp_for_each_touch(tp, tmp) { - if (tmp->is_pointer) - break; - } - - if (!tmp->is_pointer) { - t->is_pointer = true; - } } } @@ -342,7 +331,6 @@ static void tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t) { unsigned int xdist, ydist; - struct tp_touch *tmp = NULL; if (!t->pinned.is_pinned) return; @@ -350,19 +338,11 @@ tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t) xdist = abs(t->x - t->pinned.center_x); ydist = abs(t->y - t->pinned.center_y); - if (xdist * xdist + ydist * ydist < - tp->buttons.motion_dist * tp->buttons.motion_dist) - return; - - t->pinned.is_pinned = false; - - tp_for_each_touch(tp, tmp) { - if (tmp->is_pointer) - break; + if (xdist * xdist + ydist * ydist >= + tp->buttons.motion_dist * tp->buttons.motion_dist) { + t->pinned.is_pinned = false; + tp_set_pointer(tp, t); } - - if (t->state != TOUCH_END && !tmp->is_pointer) - t->is_pointer = true; } static void @@ -378,6 +358,28 @@ tp_pin_fingers(struct tp_dispatch *tp) } } +static int +tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t) +{ + return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) && + !t->pinned.is_pinned && tp_button_touch_active(tp, t); +} + +void +tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t) +{ + struct tp_touch *tmp = NULL; + + /* Only set the touch as pointer if we don't have one yet */ + tp_for_each_touch(tp, tmp) { + if (tmp->is_pointer) + return; + } + + if (tp_touch_active(tp, t)) + t->is_pointer = true; +} + static void tp_process_state(struct tp_dispatch *tp, uint32_t time) { diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 8d8dd840..5509e935 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -200,6 +200,9 @@ struct tp_dispatch { void tp_get_delta(struct tp_touch *t, double *dx, double *dy); +void +tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t); + int tp_tap_handle_state(struct tp_dispatch *tp, uint32_t time); @@ -229,4 +232,7 @@ tp_post_button_events(struct tp_dispatch *tp, uint32_t time); int tp_button_handle_state(struct tp_dispatch *tp, uint32_t time); +int +tp_button_touch_active(struct tp_dispatch *tp, struct tp_touch *t); + #endif diff --git a/test/touchpad.c b/test/touchpad.c index bbae6cd8..959978e5 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -70,10 +70,10 @@ START_TEST(touchpad_2fg_no_motion) litest_drain_events(li); - litest_touch_down(dev, 0, 50, 50); - litest_touch_down(dev, 1, 70, 70); - litest_touch_move_to(dev, 0, 50, 50, 80, 50, 5); - litest_touch_move_to(dev, 1, 70, 70, 80, 50, 5); + litest_touch_down(dev, 0, 20, 20); + litest_touch_down(dev, 1, 70, 20); + litest_touch_move_to(dev, 0, 20, 20, 80, 80, 5); + litest_touch_move_to(dev, 1, 70, 20, 80, 50, 5); litest_touch_up(dev, 0); litest_touch_up(dev, 1); From f6c3731f8a28629498f84dc5a0c0d14b82297f7f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 7 Apr 2014 13:44:07 +0200 Subject: [PATCH 09/16] touchpad: Use INPUT_PROP_BUTTONPAD instead of checking for buttons And warn if INPUT_PROP_BUTTONPAD mismatches right/middle buttons presence. Also fix the bcm5974 to properly advertise INPUT_PROP_BUTTONPAD. Signed-off-by: Hans de Goede Reviewed-by: Peter Hutterer --- src/evdev-mt-touchpad-buttons.c | 34 +++++++++++++++++---------------- src/evdev-mt-touchpad.c | 4 ++-- src/evdev-mt-touchpad.h | 7 +++---- test/litest-bcm5974.c | 1 + 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 618377be..a124e126 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -407,9 +407,17 @@ tp_init_buttons(struct tp_dispatch *tp, int width, height; double diagonal; + tp->buttons.is_clickpad = libevdev_has_property(device->evdev, + INPUT_PROP_BUTTONPAD); + if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE) || - libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) - tp->buttons.has_buttons = true; + libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) { + if (tp->buttons.is_clickpad) + log_bug("clickpad advertising right button (kernel bug?)\n"); + } else { + if (!tp->buttons.is_clickpad) + log_bug("non clickpad without right button (kernel bug)?\n"); + } width = abs(device->abs.max_x - device->abs.min_x); height = abs(device->abs.max_y - device->abs.min_y); @@ -420,10 +428,7 @@ tp_init_buttons(struct tp_dispatch *tp, if (libevdev_get_id_vendor(device->evdev) == 0x5ac) /* Apple */ tp->buttons.use_clickfinger = true; - tp->buttons.use_softbuttons = !tp->buttons.use_clickfinger && - !tp->buttons.has_buttons; - - if (tp->buttons.use_softbuttons) { + if (tp->buttons.is_clickpad && !tp->buttons.use_clickfinger) { tp->buttons.area.top_edge = height * .8 + device->abs.min_y; tp->buttons.area.rightbutton_left_edge = width/2 + device->abs.min_x; tp->buttons.timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); @@ -583,21 +588,18 @@ tp_post_softbutton_buttons(struct tp_dispatch *tp, uint32_t time) int tp_post_button_events(struct tp_dispatch *tp, uint32_t time) { - int rc = 0; - if ((tp->queued & (TOUCHPAD_EVENT_BUTTON_PRESS|TOUCHPAD_EVENT_BUTTON_RELEASE)) == 0) return 0; - if (tp->buttons.has_buttons) - rc = tp_post_physical_buttons(tp, time); - else if (tp->buttons.use_clickfinger) - rc = tp_post_clickfinger_buttons(tp, time); - else if (tp->buttons.use_softbuttons) - rc = tp_post_softbutton_buttons(tp, time); + if (tp->buttons.is_clickpad) { + if (tp->buttons.use_clickfinger) + return tp_post_clickfinger_buttons(tp, time); + else + return tp_post_softbutton_buttons(tp, time); + } - - return rc; + return tp_post_physical_buttons(tp, time); } int diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index b15de29f..c9a142f4 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -410,7 +410,7 @@ tp_process_state(struct tp_dispatch *tp, uint32_t time) * to allow drag and drop. */ if ((tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) && - !tp->buttons.has_buttons) + tp->buttons.is_clickpad) tp_pin_fingers(tp); } @@ -500,7 +500,7 @@ static int tp_post_scroll_events(struct tp_dispatch *tp, uint32_t time) { /* don't scroll if a clickpad is held down */ - if (!tp->buttons.has_buttons && + if (tp->buttons.is_clickpad && (tp->buttons.state || tp->buttons.old_state)) return 0; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 5509e935..78a74dfe 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -154,19 +154,18 @@ struct tp_dispatch { } accel; struct { - bool has_buttons; /* true for physical LMR buttons */ + bool is_clickpad; /* true for clickpads */ bool use_clickfinger; /* number of fingers decides button number */ - bool use_softbuttons; /* use software-button area */ uint32_t state; uint32_t old_state; uint32_t motion_dist; /* for pinned touches */ unsigned int active; /* currently active button, for release event */ - /* Only used if has_buttons is false. The software button area is always + /* Only used for clickpads. The software button area is always * a horizontal strip across the touchpad. Depending on the * rightbutton_left_edge value, the buttons are split according to the * edge settings. - */ + */ struct { int32_t top_edge; int32_t rightbutton_left_edge; diff --git a/test/litest-bcm5974.c b/test/litest-bcm5974.c index 25d59ac2..43605aaf 100644 --- a/test/litest-bcm5974.c +++ b/test/litest-bcm5974.c @@ -92,6 +92,7 @@ static int events[] = { EV_KEY, BTN_TOOL_DOUBLETAP, EV_KEY, BTN_TOOL_TRIPLETAP, EV_KEY, BTN_TOOL_QUADTAP, + INPUT_PROP_MAX, INPUT_PROP_BUTTONPAD, -1, -1 }; From a4bd36071e8540719593bac2d6fbf3f1d19501d8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 7 Apr 2014 13:50:11 +0200 Subject: [PATCH 10/16] touchpad: Ignore non left clicks on clickpads We should never get any non left button events on clickpads, but if we do these might confuse our state, so complain about it and ignore these. Signed-off-by: Hans de Goede Reviewed-by: Peter Hutterer --- src/evdev-mt-touchpad-buttons.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index a124e126..c65cd8a3 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -367,6 +367,14 @@ tp_process_button(struct tp_dispatch *tp, uint32_t time) { uint32_t mask = 1 << (e->code - BTN_LEFT); + + /* Ignore other buttons on clickpads */ + if (tp->buttons.is_clickpad && e->code != BTN_LEFT) { + log_bug("received %s button event on a clickpad (kernel bug?)\n", + libevdev_event_code_get_name(EV_KEY, e->code)); + return 0; + } + if (e->value) { tp->buttons.state |= mask; tp->queued |= TOUCHPAD_EVENT_BUTTON_PRESS; From b9f6aed51560170e75dd8281a656809f55f33fc1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 7 Apr 2014 16:09:03 +0200 Subject: [PATCH 11/16] touchpad: post_button_events: Remove TOUCHPAD_EVENT_BUTTON_PRESS/RELEASE test We already check for old != current everywhere, so this is not needed; And in tp_post_softbutton_buttons we want to do delay button down reporting if we don't have touch info yet in which case this check actually gets in the way. Signed-off-by: Hans de Goede Reviewed-by: Peter Hutterer --- src/evdev-mt-touchpad-buttons.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index c65cd8a3..f278eadc 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -596,10 +596,6 @@ tp_post_softbutton_buttons(struct tp_dispatch *tp, uint32_t time) int tp_post_button_events(struct tp_dispatch *tp, uint32_t time) { - if ((tp->queued & - (TOUCHPAD_EVENT_BUTTON_PRESS|TOUCHPAD_EVENT_BUTTON_RELEASE)) == 0) - return 0; - if (tp->buttons.is_clickpad) { if (tp->buttons.use_clickfinger) return tp_post_clickfinger_buttons(tp, time); From bfe05ed4a679ae2a5e3ff3b6882cbb3d046baec2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 7 Apr 2014 16:49:36 +0200 Subject: [PATCH 12/16] touchpad: softbuttons: Deal with a click arriving before any touches It is possible for a click to get reported before any related touch events get reported, here is the relevant part of an evemu-record session on a T440s: E: 3.985585 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- E: 3.997419 0003 0039 -001 # EV_ABS / ABS_MT_TRACKING_ID -1 E: 3.997419 0001 014a 0000 # EV_KEY / BTN_TOUCH 0 E: 3.997419 0003 0018 0000 # EV_ABS / ABS_PRESSURE 0 E: 3.997419 0001 0145 0000 # EV_KEY / BTN_TOOL_FINGER 0 E: 3.997419 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- E: 5.117881 0001 0110 0001 # EV_KEY / BTN_LEFT 1 E: 5.117881 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- E: 5.133422 0003 0039 0187 # EV_ABS / ABS_MT_TRACKING_ID 187 E: 5.133422 0003 0035 3098 # EV_ABS / ABS_MT_POSITION_X 3098 E: 5.133422 0003 0036 3282 # EV_ABS / ABS_MT_POSITION_Y 3282 E: 5.133422 0003 003a 0046 # EV_ABS / ABS_MT_PRESSURE 46 E: 5.133422 0001 014a 0001 # EV_KEY / BTN_TOUCH 1 E: 5.133422 0003 0000 3102 # EV_ABS / ABS_X 3102 E: 5.133422 0003 0001 3282 # EV_ABS / ABS_Y 3282 E: 5.133422 0003 0018 0046 # EV_ABS / ABS_PRESSURE 46 E: 5.133422 0001 0145 0001 # EV_KEY / BTN_TOOL_FINGER 1 E: 5.133422 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- Notice the BTN_LEFT event all by itself! To deal with this if a physical click registers before we get any touches, wait for the first touch to resolve the click. Also see the new activity diagram for the tp_post_softbutton_buttons method which has been added to doc/touchpad-softbutton-state-machine.svg Signed-off-by: Hans de Goede Reviewed-by: Peter Hutterer --- doc/touchpad-softbutton-state-machine.svg | 421 ++++++++++++++++------ src/evdev-mt-touchpad-buttons.c | 57 ++- src/evdev-mt-touchpad.h | 1 + 3 files changed, 357 insertions(+), 122 deletions(-) diff --git a/doc/touchpad-softbutton-state-machine.svg b/doc/touchpad-softbutton-state-machine.svg index 1838e354..11423435 100644 --- a/doc/touchpad-softbutton-state-machine.svg +++ b/doc/touchpad-softbutton-state-machine.svg @@ -1,173 +1,390 @@ - + - - - + + + - + NONE - + on-entry: - + curr = none - + - + BOTTOM_NEW - + on-entry: - + curr = button - + start inner timeout - + - + AREA - + on-entry: - + curr =area - + - + finger in - + area - + - + BOTTOM - + - + finger - + up - + - + phys - + button - + press - - - + + + - + inner - + timeout - - - - - + + + + + - + finger in - + AREA - - - + + + - + BOTTOM_TO_AREA - + on-entry: - + start outer timeout - - - + + + - + outer - + timeout - - - - - + + + + + - + finger in - + bottom - - - - - + + + + + - + finger in - + area - - - - - + + + + + - + finger in - + bottom - + button != curr - - - - - + + + + + + + + + - -ANY - - - - - - - - - - - - + finger in - + bottom - + button == curr - - - - - - - - + + + + + + + + + + + + + + + + + + + + + +Check state of + +all touches + + + + + + + + + +tp_post_softbutton_buttons() + + + + +!buttons.click_pend + +&& current == old + + + + + + +yes + + + + + + +no + + + + + + +current = buttons.state & 0x01 + +old = buttons.old_state & 0x01 + +button = 0 + + + + + + +All touches are in state none + + + + + + +no + + + + + + +yes + + + + +buttons.click_pend = 1 + + + + + + +(Some touches are in right) && + +(Some touches are in left) + + + + + + +yes + + + + +button = BTN_MIDDLE + + + + + + +current + + + + + + +no + + + + + + +yes + + + + +Some touches are in right + + + + + + +yes + + + + + + +no + + + + +button = BTN_RIGHT + + + + +button = BTN_LEFT + + + + + + +no + + + + +buttons.active = button + +state = BUTTON_PRESSED + + + + + + + + + + +button = buttons.active + +buttons.active = 0 + +state = BUTTON_RELEASED + + + + +buttons.click_pend = 0 + + + + + + + + +button + + + + + + +no + + + + + + +yes + + + + +pointer_notify_button( + +button, state) + + + + + + + diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index f278eadc..de3f36c4 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -545,51 +545,68 @@ tp_post_softbutton_buttons(struct tp_dispatch *tp, uint32_t time) { uint32_t current, old, button; enum libinput_pointer_button_state state; + enum { AREA = 0x01, LEFT = 0x02, RIGHT = 0x04 }; current = tp->buttons.state; old = tp->buttons.old_state; + button = 0; - if (current == old) - return 0; - - if (tp->nfingers_down == 0 || tp->nfingers_down > 2) + if (!tp->buttons.click_pending && current == old) return 0; if (current) { struct tp_touch *t; - button = 0; tp_for_each_touch(tp, t) { - if (t->button.curr == BUTTON_EVENT_IN_BOTTOM_R) - button |= 0x2; - else if (t->button.curr == BUTTON_EVENT_IN_BOTTOM_L) - button |= 0x1; + switch (t->button.curr) { + case BUTTON_EVENT_IN_AREA: + button |= AREA; + break; + case BUTTON_EVENT_IN_BOTTOM_L: + button |= LEFT; + break; + case BUTTON_EVENT_IN_BOTTOM_R: + button |= RIGHT; + break; + default: + break; + } } switch (button) { - case 0: /* only in area */ - case 1: /* only left area */ - button = BTN_LEFT; - break; - case 2: /* only right area */ + case 0: + /* No touches, wait for a touch before processing */ + tp->buttons.click_pending = true; + return 0; + case RIGHT: + case RIGHT | AREA: + /* Some touches in right, no touches in left */ button = BTN_RIGHT; break; - case 3: /* left + right area */ + case LEFT | RIGHT: + case LEFT | RIGHT | AREA: + /* Some touches in left and some in right */ button = BTN_MIDDLE; break; + default: + button = BTN_LEFT; } tp->buttons.active = button; state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED; } else { - state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED; button = tp->buttons.active; + tp->buttons.active = 0; + state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED; } - pointer_notify_button(&tp->device->base, - time, - button, - state); + tp->buttons.click_pending = false; + + if (button) + pointer_notify_button(&tp->device->base, + time, + button, + state); return 1; } diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 78a74dfe..41f9daf7 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -156,6 +156,7 @@ struct tp_dispatch { struct { bool is_clickpad; /* true for clickpads */ bool use_clickfinger; /* number of fingers decides button number */ + bool click_pending; uint32_t state; uint32_t old_state; uint32_t motion_dist; /* for pinned touches */ From 55b2ea65f3c4e592a02344f9d8185f59a0394cfb Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 8 Apr 2014 08:34:20 +0200 Subject: [PATCH 13/16] touchpad: Ignore fingers in button area for 2 finger scroll Signed-off-by: Hans de Goede Reviewed-by: Peter Hutterer --- src/evdev-mt-touchpad.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index c9a142f4..c61d8730 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -446,7 +446,7 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint32_t time) double tmpx, tmpy; tp_for_each_touch(tp, t) { - if (t->dirty) { + if (tp_touch_active(tp, t) && t->dirty) { nchanged++; tp_get_delta(t, &tmpx, &tmpy); @@ -499,12 +499,21 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint32_t time) static int tp_post_scroll_events(struct tp_dispatch *tp, uint32_t time) { + struct tp_touch *t; + int nfingers_down = 0; + /* don't scroll if a clickpad is held down */ if (tp->buttons.is_clickpad && (tp->buttons.state || tp->buttons.old_state)) return 0; - if (tp->nfingers_down != 2) { + /* Only count active touches for 2 finger scrolling */ + tp_for_each_touch(tp, t) { + if (tp_touch_active(tp, t)) + nfingers_down++; + } + + if (nfingers_down != 2) { /* terminate scrolling with a zero scroll event to notify * caller that it really ended now */ if (tp->scroll.state != SCROLL_STATE_NONE) { From a70ef98d57d3467c43cdd95ce944d0b31c35c907 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 8 Apr 2014 08:39:11 +0200 Subject: [PATCH 14/16] touchpad: Remove clickpad clicked test from 2 finger scrolling handling This is no longer needed now that we take the button area and pinned fingers into account. Signed-off-by: Hans de Goede Reviewed-by: Peter Hutterer --- src/evdev-mt-touchpad.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index c61d8730..e2c865e5 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -502,11 +502,6 @@ tp_post_scroll_events(struct tp_dispatch *tp, uint32_t time) struct tp_touch *t; int nfingers_down = 0; - /* don't scroll if a clickpad is held down */ - if (tp->buttons.is_clickpad && - (tp->buttons.state || tp->buttons.old_state)) - return 0; - /* Only count active touches for 2 finger scrolling */ tp_for_each_touch(tp, t) { if (tp_touch_active(tp, t)) From ed6ccad449fe07494616e5bf362670907fbbcc8a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 8 Apr 2014 12:39:24 +0200 Subject: [PATCH 15/16] touchpad: handle_timeouts: Remove unused return value Signed-off-by: Hans de Goede Reviewed-by: Peter Hutterer --- src/evdev-mt-touchpad-buttons.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index de3f36c4..68cda782 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -343,22 +343,17 @@ tp_button_handle_state(struct tp_dispatch *tp, uint32_t time) return 0; } -static int +static void tp_button_handle_timeout(struct tp_dispatch *tp, uint32_t now) { struct tp_touch *t; - uint32_t min_timeout = INT_MAX; tp_for_each_touch(tp, t) { if (t->button.timeout != 0 && t->button.timeout <= now) { tp_button_clear_timer(tp, t); tp_button_handle_event(tp, t, BUTTON_EVENT_TIMEOUT, now); } - if (t->button.timeout != 0) - min_timeout = min(t->button.timeout, min_timeout); } - - return min_timeout == INT_MAX ? 0 : min_timeout; } int From 89165da6d6b90d466edf3283b710c0931bdcc8dd Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 8 Apr 2014 12:29:45 +0200 Subject: [PATCH 16/16] Change internal timestamps to uint64_t to properly deal with wrapping We store timestamps in ms since system boot (CLOCK_MONOTONIC). This will wrap after circa 50 days. I've considered making our code wrapping safe, but that won't work. We also use our internal timestamps to program timer-fds for timeouts. And we store ms in a single integer but the kernel uses 2 integers, one for seconds and one for usec/nanosec. So at 32 bits our ms containing integer will wrap in 50 days, while the kernels seconds storing integer lasts a lot longer. So when we wrap our ms timestamps, we will be programming the timer-fds with a seconds value in the past. So change all our internal timestamps to uint64_t to avoid the wrapping when programming the timer-fds. Note that we move from 64-bit timestamps to 32-bit timestamps when calling the foo_notify_bar functions from libinput-private.h. Having 64 bit timestamps has no use past this point, since the wayland input protocol uses 32 bit timestamps (and clients will have to deal with wrapping). Signed-off-by: Hans de Goede Reviewed-by: Peter Hutterer --- src/evdev-mt-touchpad-buttons.c | 22 ++++++++--------- src/evdev-mt-touchpad-tap.c | 42 ++++++++++++++++----------------- src/evdev-mt-touchpad.c | 24 +++++++++---------- src/evdev-mt-touchpad.h | 14 +++++------ src/evdev-touchpad.c | 26 ++++++++++---------- src/evdev.c | 12 +++++----- src/evdev.h | 2 +- src/filter.c | 16 ++++++------- src/filter.h | 6 ++--- 9 files changed, 82 insertions(+), 82 deletions(-) diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 68cda782..65fa21be 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -95,7 +95,7 @@ is_inside_left_area(struct tp_dispatch *tp, struct tp_touch *t) } static void -tp_button_set_timer(struct tp_dispatch *tp, uint32_t timeout) +tp_button_set_timer(struct tp_dispatch *tp, uint64_t timeout) { struct itimerspec its; its.it_interval.tv_sec = 0; @@ -286,7 +286,7 @@ static void tp_button_handle_event(struct tp_dispatch *tp, struct tp_touch *t, enum button_event event, - uint32_t time) + uint64_t time) { enum button_state current = t->button.state; @@ -316,7 +316,7 @@ tp_button_handle_event(struct tp_dispatch *tp, } int -tp_button_handle_state(struct tp_dispatch *tp, uint32_t time) +tp_button_handle_state(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *t; @@ -344,7 +344,7 @@ tp_button_handle_state(struct tp_dispatch *tp, uint32_t time) } static void -tp_button_handle_timeout(struct tp_dispatch *tp, uint32_t now) +tp_button_handle_timeout(struct tp_dispatch *tp, uint64_t now) { struct tp_touch *t; @@ -359,7 +359,7 @@ tp_button_handle_timeout(struct tp_dispatch *tp, uint32_t now) int tp_process_button(struct tp_dispatch *tp, const struct input_event *e, - uint32_t time) + uint64_t time) { uint32_t mask = 1 << (e->code - BTN_LEFT); @@ -388,7 +388,7 @@ tp_button_timeout_handler(void *data) uint64_t expires; int len; struct timespec ts; - uint32_t now; + uint64_t now; len = read(tp->buttons.timer_fd, &expires, sizeof expires); if (len != sizeof expires) @@ -398,7 +398,7 @@ tp_button_timeout_handler(void *data) log_error("timerfd read error: %s\n", strerror(errno)); clock_gettime(CLOCK_MONOTONIC, &ts); - now = ts.tv_sec * 1000 + ts.tv_nsec / 1000000; + now = ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000; tp_button_handle_timeout(tp, now); } @@ -468,7 +468,7 @@ tp_destroy_buttons(struct tp_dispatch *tp) } static int -tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint32_t time) +tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint64_t time) { uint32_t current, old, button; enum libinput_pointer_button_state state; @@ -504,7 +504,7 @@ tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint32_t time) } static int -tp_post_physical_buttons(struct tp_dispatch *tp, uint32_t time) +tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t time) { uint32_t current, old, button; @@ -536,7 +536,7 @@ tp_post_physical_buttons(struct tp_dispatch *tp, uint32_t time) } static int -tp_post_softbutton_buttons(struct tp_dispatch *tp, uint32_t time) +tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time) { uint32_t current, old, button; enum libinput_pointer_button_state state; @@ -606,7 +606,7 @@ tp_post_softbutton_buttons(struct tp_dispatch *tp, uint32_t time) } int -tp_post_button_events(struct tp_dispatch *tp, uint32_t time) +tp_post_button_events(struct tp_dispatch *tp, uint64_t time) { if (tp->buttons.is_clickpad) { if (tp->buttons.use_clickfinger) diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index bcc5700c..eee334f2 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -97,7 +97,7 @@ tap_event_to_str(enum tap_event event) { static void tp_tap_notify(struct tp_dispatch *tp, - uint32_t time, + uint64_t time, int nfingers, enum libinput_pointer_button_state state) { @@ -118,9 +118,9 @@ tp_tap_notify(struct tp_dispatch *tp, } static void -tp_tap_set_timer(struct tp_dispatch *tp, uint32_t time) +tp_tap_set_timer(struct tp_dispatch *tp, uint64_t time) { - uint32_t timeout = time + DEFAULT_TAP_TIMEOUT_PERIOD; + uint64_t timeout = time + DEFAULT_TAP_TIMEOUT_PERIOD; struct itimerspec its; its.it_interval.tv_sec = 0; @@ -139,7 +139,7 @@ tp_tap_clear_timer(struct tp_dispatch *tp) } static void -tp_tap_idle_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t time) +tp_tap_idle_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) { switch (event) { @@ -160,7 +160,7 @@ tp_tap_idle_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t } static void -tp_tap_touch_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t time) +tp_tap_touch_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) { switch (event) { @@ -185,7 +185,7 @@ tp_tap_touch_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t } static void -tp_tap_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t time) +tp_tap_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) { switch (event) { @@ -206,7 +206,7 @@ tp_tap_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t } static void -tp_tap_tapped_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t time) +tp_tap_tapped_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) { switch (event) { @@ -230,7 +230,7 @@ tp_tap_tapped_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_ } static void -tp_tap_touch2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t time) +tp_tap_touch2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) { switch (event) { @@ -256,7 +256,7 @@ tp_tap_touch2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_ } static void -tp_tap_touch2_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t time) +tp_tap_touch2_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) { switch (event) { @@ -278,7 +278,7 @@ tp_tap_touch2_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, ui } static void -tp_tap_touch3_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t time) +tp_tap_touch3_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) { switch (event) { @@ -303,7 +303,7 @@ tp_tap_touch3_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_ } static void -tp_tap_touch3_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t time) +tp_tap_touch3_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) { switch (event) { @@ -324,7 +324,7 @@ tp_tap_touch3_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, ui } static void -tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t time) +tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) { switch (event) { case TAP_EVENT_TOUCH: @@ -349,7 +349,7 @@ tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp, enum tap_event } static void -tp_tap_dragging_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t time) +tp_tap_dragging_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) { switch (event) { @@ -372,7 +372,7 @@ tp_tap_dragging_handle_event(struct tp_dispatch *tp, enum tap_event event, uint3 } static void -tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t time) +tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) { switch (event) { @@ -395,7 +395,7 @@ tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp, enum tap_event event, } static void -tp_tap_dragging2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t time) +tp_tap_dragging2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) { switch (event) { @@ -418,7 +418,7 @@ tp_tap_dragging2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint } static void -tp_tap_dead_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t time) +tp_tap_dead_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) { switch (event) { @@ -435,7 +435,7 @@ tp_tap_dead_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t } static void -tp_tap_handle_event(struct tp_dispatch *tp, enum tap_event event, uint32_t time) +tp_tap_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) { enum tp_tap_state current; if (!tp->tap.enabled) @@ -503,7 +503,7 @@ tp_tap_exceeds_motion_threshold(struct tp_dispatch *tp, struct tp_touch *t) } int -tp_tap_handle_state(struct tp_dispatch *tp, uint32_t time) +tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *t; int filter_motion = 0; @@ -554,7 +554,7 @@ tp_tap_timeout_handler(void *data) uint64_t expires; int len; struct timespec ts; - uint32_t now; + uint64_t now; len = read(touchpad->tap.timer_fd, &expires, sizeof expires); if (len != sizeof expires) @@ -564,13 +564,13 @@ tp_tap_timeout_handler(void *data) log_error("timerfd read error: %s\n", strerror(errno)); clock_gettime(CLOCK_MONOTONIC, &ts); - now = ts.tv_sec * 1000 + ts.tv_nsec / 1000000; + now = ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000; tp_tap_handle_timeout(touchpad, now); } unsigned int -tp_tap_handle_timeout(struct tp_dispatch *tp, uint32_t time) +tp_tap_handle_timeout(struct tp_dispatch *tp, uint64_t time) { if (!tp->tap.enabled) return 0; diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index e2c865e5..a4dfc7e9 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -51,7 +51,7 @@ static double tp_accel_profile(struct motion_filter *filter, void *data, double velocity, - uint32_t time) + uint64_t time) { struct tp_dispatch *tp = (struct tp_dispatch *) data; @@ -80,7 +80,7 @@ tp_motion_history_offset(struct tp_touch *t, int offset) static void tp_filter_motion(struct tp_dispatch *tp, - double *dx, double *dy, uint32_t time) + double *dx, double *dy, uint64_t time) { struct motion_params motion; @@ -206,7 +206,7 @@ tp_get_delta(struct tp_touch *t, double *dx, double *dy) static void tp_process_absolute(struct tp_dispatch *tp, const struct input_event *e, - uint32_t time) + uint64_t time) { struct tp_touch *t = tp_current_touch(tp); @@ -238,7 +238,7 @@ tp_process_absolute(struct tp_dispatch *tp, static void tp_process_absolute_st(struct tp_dispatch *tp, const struct input_event *e, - uint32_t time) + uint64_t time) { struct tp_touch *t = tp_current_touch(tp); @@ -261,7 +261,7 @@ tp_process_absolute_st(struct tp_dispatch *tp, static void tp_process_fake_touch(struct tp_dispatch *tp, const struct input_event *e, - uint32_t time) + uint64_t time) { struct tp_touch *t; unsigned int fake_touches; @@ -309,7 +309,7 @@ tp_process_fake_touch(struct tp_dispatch *tp, static void tp_process_key(struct tp_dispatch *tp, const struct input_event *e, - uint32_t time) + uint64_t time) { switch (e->code) { case BTN_LEFT: @@ -381,7 +381,7 @@ tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t) } static void -tp_process_state(struct tp_dispatch *tp, uint32_t time) +tp_process_state(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *t; struct tp_touch *first = tp_get_touch(tp, 0); @@ -415,7 +415,7 @@ tp_process_state(struct tp_dispatch *tp, uint32_t time) } static void -tp_post_process_state(struct tp_dispatch *tp, uint32_t time) +tp_post_process_state(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *t; @@ -438,7 +438,7 @@ tp_post_process_state(struct tp_dispatch *tp, uint32_t time) } static void -tp_post_twofinger_scroll(struct tp_dispatch *tp, uint32_t time) +tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *t; int nchanged = 0; @@ -497,7 +497,7 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint32_t time) } static int -tp_post_scroll_events(struct tp_dispatch *tp, uint32_t time) +tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *t; int nfingers_down = 0; @@ -533,7 +533,7 @@ tp_post_scroll_events(struct tp_dispatch *tp, uint32_t time) } static void -tp_post_events(struct tp_dispatch *tp, uint32_t time) +tp_post_events(struct tp_dispatch *tp, uint64_t time) { struct tp_touch *t = tp_current_touch(tp); double dx, dy; @@ -574,7 +574,7 @@ static void tp_process(struct evdev_dispatch *dispatch, struct evdev_device *device, struct input_event *e, - uint32_t time) + uint64_t time) { struct tp_dispatch *tp = (struct tp_dispatch *)dispatch; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 41f9daf7..41e3ca43 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -97,7 +97,7 @@ struct tp_touch { bool is_pointer; /* the pointer-controlling touch */ int32_t x; int32_t y; - uint32_t millis; + uint64_t millis; struct { struct tp_motion samples[TOUCHPAD_HISTORY_LENGTH]; @@ -125,7 +125,7 @@ struct tp_touch { enum button_state state; /* We use button_event here so we can use == on events */ enum button_event curr; - uint32_t timeout; + uint64_t timeout; } button; }; @@ -204,10 +204,10 @@ void tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t); int -tp_tap_handle_state(struct tp_dispatch *tp, uint32_t time); +tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time); unsigned int -tp_tap_handle_timeout(struct tp_dispatch *tp, uint32_t time); +tp_tap_handle_timeout(struct tp_dispatch *tp, uint64_t time); int tp_init_tap(struct tp_dispatch *tp); @@ -224,13 +224,13 @@ tp_destroy_buttons(struct tp_dispatch *tp); int tp_process_button(struct tp_dispatch *tp, const struct input_event *e, - uint32_t time); + uint64_t time); int -tp_post_button_events(struct tp_dispatch *tp, uint32_t time); +tp_post_button_events(struct tp_dispatch *tp, uint64_t time); int -tp_button_handle_state(struct tp_dispatch *tp, uint32_t time); +tp_button_handle_state(struct tp_dispatch *tp, uint64_t time); int tp_button_touch_active(struct tp_dispatch *tp, struct tp_touch *t); diff --git a/src/evdev-touchpad.c b/src/evdev-touchpad.c index 1a484419..18b63530 100644 --- a/src/evdev-touchpad.c +++ b/src/evdev-touchpad.c @@ -211,7 +211,7 @@ static double touchpad_profile(struct motion_filter *filter, void *data, double velocity, - uint32_t time) + uint64_t time) { struct touchpad_dispatch *touchpad = (struct touchpad_dispatch *) data; @@ -273,7 +273,7 @@ touchpad_get_delta(struct touchpad_dispatch *touchpad, double *dx, double *dy) static void filter_motion(struct touchpad_dispatch *touchpad, - double *dx, double *dy, uint32_t time) + double *dx, double *dy, uint64_t time) { struct motion_params motion; @@ -287,7 +287,7 @@ filter_motion(struct touchpad_dispatch *touchpad, } static void -notify_button_pressed(struct touchpad_dispatch *touchpad, uint32_t time) +notify_button_pressed(struct touchpad_dispatch *touchpad, uint64_t time) { pointer_notify_button( &touchpad->device->base, @@ -297,7 +297,7 @@ notify_button_pressed(struct touchpad_dispatch *touchpad, uint32_t time) } static void -notify_button_released(struct touchpad_dispatch *touchpad, uint32_t time) +notify_button_released(struct touchpad_dispatch *touchpad, uint64_t time) { pointer_notify_button( &touchpad->device->base, @@ -307,16 +307,16 @@ notify_button_released(struct touchpad_dispatch *touchpad, uint32_t time) } static void -notify_tap(struct touchpad_dispatch *touchpad, uint32_t time) +notify_tap(struct touchpad_dispatch *touchpad, uint64_t time) { notify_button_pressed(touchpad, time); notify_button_released(touchpad, time); } static void -process_fsm_events(struct touchpad_dispatch *touchpad, uint32_t time) +process_fsm_events(struct touchpad_dispatch *touchpad, uint64_t time) { - uint32_t timeout = UINT32_MAX; + uint64_t timeout = UINT64_MAX; enum fsm_event event; unsigned int i; @@ -398,7 +398,7 @@ process_fsm_events(struct touchpad_dispatch *touchpad, uint32_t time) } } - if (timeout != UINT32_MAX) { + if (timeout != UINT64_MAX) { struct itimerspec its; its.it_interval.tv_sec = 0; @@ -447,7 +447,7 @@ fsm_timeout_handler(void *data) uint64_t expires; int len; struct timespec ts; - uint32_t now; + uint64_t now; len = read(touchpad->fsm.timer.fd, &expires, sizeof expires); if (len != sizeof expires) @@ -458,7 +458,7 @@ fsm_timeout_handler(void *data) if (touchpad->fsm.events_count == 0) { clock_gettime(CLOCK_MONOTONIC, &ts); - now = ts.tv_sec * 1000 + ts.tv_nsec / 1000000; + now = ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000; push_fsm_event(touchpad, FSM_EVENT_TIMEOUT); process_fsm_events(touchpad, now); @@ -466,7 +466,7 @@ fsm_timeout_handler(void *data) } static void -touchpad_update_state(struct touchpad_dispatch *touchpad, uint32_t time) +touchpad_update_state(struct touchpad_dispatch *touchpad, uint64_t time) { int motion_index; int center_x, center_y; @@ -618,7 +618,7 @@ static inline void process_key(struct touchpad_dispatch *touchpad, struct evdev_device *device, struct input_event *e, - uint32_t time) + uint64_t time) { uint32_t code; @@ -685,7 +685,7 @@ static void touchpad_process(struct evdev_dispatch *dispatch, struct evdev_device *device, struct input_event *e, - uint32_t time) + uint64_t time) { struct touchpad_dispatch *touchpad = (struct touchpad_dispatch *) dispatch; diff --git a/src/evdev.c b/src/evdev.c index 57dcca76..08a18fd8 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -110,7 +110,7 @@ evdev_device_transform_y(struct evdev_device *device, } static void -evdev_flush_pending_event(struct evdev_device *device, uint32_t time) +evdev_flush_pending_event(struct evdev_device *device, uint64_t time) { int32_t cx, cy; li_fixed_t x, y; @@ -309,7 +309,7 @@ evdev_process_key(struct evdev_device *device, struct input_event *e, int time) static void evdev_process_touch(struct evdev_device *device, struct input_event *e, - uint32_t time) + uint64_t time) { switch (e->code) { case ABS_MT_SLOT: @@ -358,7 +358,7 @@ evdev_process_absolute_motion(struct evdev_device *device, static inline void evdev_process_relative(struct evdev_device *device, - struct input_event *e, uint32_t time) + struct input_event *e, uint64_t time) { struct libinput_device *base = &device->base; @@ -406,7 +406,7 @@ evdev_process_relative(struct evdev_device *device, static inline void evdev_process_absolute(struct evdev_device *device, struct input_event *e, - uint32_t time) + uint64_t time) { if (device->is_mt) { evdev_process_touch(device, e, time); @@ -441,7 +441,7 @@ static void fallback_process(struct evdev_dispatch *dispatch, struct evdev_device *device, struct input_event *event, - uint32_t time) + uint64_t time) { int need_frame = 0; @@ -491,7 +491,7 @@ static inline void evdev_process_event(struct evdev_device *device, struct input_event *e) { struct evdev_dispatch *dispatch = device->dispatch; - uint32_t time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000; + uint64_t time = e->time.tv_sec * 1000ULL + e->time.tv_usec / 1000; dispatch->interface->process(dispatch, device, e, time); } diff --git a/src/evdev.h b/src/evdev.h index 36daf3c7..bb88074e 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -101,7 +101,7 @@ struct evdev_dispatch_interface { void (*process)(struct evdev_dispatch *dispatch, struct evdev_device *device, struct input_event *event, - uint32_t time); + uint64_t time); /* Destroy an event dispatch handler and free all its resources. */ void (*destroy)(struct evdev_dispatch *dispatch); diff --git a/src/filter.c b/src/filter.c index 397e0f63..2b1a6755 100644 --- a/src/filter.c +++ b/src/filter.c @@ -32,7 +32,7 @@ void filter_dispatch(struct motion_filter *filter, struct motion_params *motion, - void *data, uint32_t time) + void *data, uint64_t time) { filter->interface->filter(filter, motion, data, time); } @@ -48,7 +48,7 @@ filter_dispatch(struct motion_filter *filter, struct pointer_tracker { double dx; double dy; - uint32_t time; + uint64_t time; int dir; }; @@ -128,7 +128,7 @@ get_direction(int dx, int dy) static void feed_trackers(struct pointer_accelerator *accel, double dx, double dy, - uint32_t time) + uint64_t time) { int i, current; struct pointer_tracker *trackers = accel->trackers; @@ -157,7 +157,7 @@ tracker_by_offset(struct pointer_accelerator *accel, unsigned int offset) } static double -calculate_tracker_velocity(struct pointer_tracker *tracker, uint32_t time) +calculate_tracker_velocity(struct pointer_tracker *tracker, uint64_t time) { int dx; int dy; @@ -170,7 +170,7 @@ calculate_tracker_velocity(struct pointer_tracker *tracker, uint32_t time) } static double -calculate_velocity(struct pointer_accelerator *accel, uint32_t time) +calculate_velocity(struct pointer_accelerator *accel, uint64_t time) { struct pointer_tracker *tracker; double velocity; @@ -224,14 +224,14 @@ calculate_velocity(struct pointer_accelerator *accel, uint32_t time) static double acceleration_profile(struct pointer_accelerator *accel, - void *data, double velocity, uint32_t time) + void *data, double velocity, uint64_t time) { return accel->profile(&accel->base, data, velocity, time); } static double calculate_acceleration(struct pointer_accelerator *accel, - void *data, double velocity, uint32_t time) + void *data, double velocity, uint64_t time) { double factor; @@ -273,7 +273,7 @@ apply_softening(struct pointer_accelerator *accel, static void accelerator_filter(struct motion_filter *filter, struct motion_params *motion, - void *data, uint32_t time) + void *data, uint64_t time) { struct pointer_accelerator *accel = (struct pointer_accelerator *) filter; diff --git a/src/filter.h b/src/filter.h index 6b2a1d20..0ef3d032 100644 --- a/src/filter.h +++ b/src/filter.h @@ -34,13 +34,13 @@ struct motion_filter; void filter_dispatch(struct motion_filter *filter, struct motion_params *motion, - void *data, uint32_t time); + void *data, uint64_t time); struct motion_filter_interface { void (*filter)(struct motion_filter *filter, struct motion_params *motion, - void *data, uint32_t time); + void *data, uint64_t time); void (*destroy)(struct motion_filter *filter); }; @@ -54,7 +54,7 @@ create_linear_acceleration_filter(double speed); typedef double (*accel_profile_func_t)(struct motion_filter *filter, void *data, double velocity, - uint32_t time); + uint64_t time); struct motion_filter * create_pointer_accelator_filter(accel_profile_func_t filter);