From c4de28fce3186ba4605c417b42cd95212d78a1c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sat, 28 Jun 2014 22:40:23 +0200 Subject: [PATCH 01/50] test/Makefile.am: Also add LIBUDEV_CFLAGS to AM_CPPFLAGS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonas Ådahl --- test/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/Makefile.am b/test/Makefile.am index b5dc33c5..8bfdf201 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -2,7 +2,8 @@ if BUILD_TESTS AM_CPPFLAGS = -I$(top_srcdir)/include \ -I$(top_srcdir)/src \ $(CHECK_CFLAGS) \ - $(LIBEVDEV_CFLAGS) + $(LIBEVDEV_CFLAGS) \ + $(LIBUDEV_CFLAGS) AM_CFLAGS = $(GCC_CFLAGS) AM_CXXFLAGS = $(GCC_CXXFLAGS) From 053c16c5a3b4733746ae19a7b10a9678899ed470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sat, 28 Jun 2014 22:41:29 +0200 Subject: [PATCH 02/50] Fix coding style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonas Ådahl --- src/libinput.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libinput.h b/src/libinput.h index 99a3b2f5..ff67ce7c 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -815,7 +815,7 @@ libinput_udev_create_context(const struct libinput_interface *interface, */ int libinput_udev_assign_seat(struct libinput *libinput, - const char *seat_id); + const char *seat_id); /** * @ingroup base From 14ad471ff5797ca5a77a377aeaad07833af63144 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 30 Jun 2014 14:27:18 +0200 Subject: [PATCH 03/50] touchpad: Simplify tp_hysteresis Once we get beyond the: if (abs(diff) <= margin) return center; test, then diff is either > margin or < -margin, otherwise the test would have triggered. So the "return center + diff;" at the end will never be reached, and the "else if (diff < -margin)" can be turned into a simple "else". This commit does not just simplify tp_hysteresis, but (arguably more important) also makes it clearer to the reader what it does. Signed-off-by: Hans de Goede Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index ced92378..9e858f13 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -42,9 +42,8 @@ tp_hysteresis(int in, int center, int margin) if (diff > margin) return center + diff - margin; - else if (diff < -margin) + else return center + diff + margin; - return center + diff; } static double From 8fa5d0bf51083756e1a7ead11afae490a09542ab Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 20 Jun 2014 14:16:13 +1000 Subject: [PATCH 04/50] touchpad: disable tapping for fingers exceeding the timeout/motion threshold The current code triggers multi-finger tapping even if the finger released was previously held on the touchpad for a while. For an event sequence of: 1. first finger down 2. first finger move past threshold/wait past timeout 3. second finger down 4. first finger up The second finger initiates the two-finger tap state, but the button event is sent when the first finger releases - despite that finger not meeting the usual tap constraints. This sequence can happen whenever a user swaps fingers. Add the finger state to the actual touchpoints and update them whenever the constrains are broken. Then, discard button events if the respective touch did not meet the conditions. http://bugs.freedesktop.org/76760 Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- doc/touchpad-tap-state-machine.svg | 1527 ++++++++++++++-------------- src/evdev-mt-touchpad-tap.c | 162 ++- src/evdev-mt-touchpad.h | 10 + test/touchpad.c | 81 ++ 4 files changed, 957 insertions(+), 823 deletions(-) diff --git a/doc/touchpad-tap-state-machine.svg b/doc/touchpad-tap-state-machine.svg index 50ebc713..10739c68 100644 --- a/doc/touchpad-tap-state-machine.svg +++ b/doc/touchpad-tap-state-machine.svg @@ -1,771 +1,756 @@ -IDLETOUCHfirstfinger downfinger upbutton -1presstimeoutmove > thresholdsecondfinger downTOUCH_2secondfinger upbutton -2pressmove > -thresholdtimeoutbutton 1releasebutton -2releaseTAPPEDtimeoutfirstfinger downDRAGGINGfirstfinger upbtn1releaseIDLEthirdfinger downTOUCH_3secondfinger upbutton 3pressbutton 3releasemove > thresholdIDLEtimeoutthirdfinger upfirstfinger upIDLEfourthfinger downDRAGGING_OR_DOUBLETAPtimeoutfirstfinger upbutton -1releasebutton -1pressbtn1releasesecondfinger downmove > thresholdHOLDfirstfinger upsecondfinger downTOUCH_2_HOLDsecondfinger upfirstfinger upthirdfinger downTOUCH_3_HOLDsecondfinger upthirdfinger upfourthfinger downDEADsecondfinger upthirdfinger upfourthfinger downfirstfinger upfirstfinger upfirstfinger upIDLEif fingercount == 0secondfinger upDRAGGING_2firstfinger upsecondfinger downthirdfinger downbtn1releasephysbuttonpressfourthfinger downphysbuttonpressbutton 1releaseDRAGGING_WAITtimeoutfirstfinger down + + + + + + + + + + + + + IDLE + + + + TOUCH + + + + first + finger down + + + + + + finger up + + + + + + button 1 + press + + + + timeout + + + + + + move > + threshold + + + + + + second + finger down + + + + + + TOUCH_2 + + + + second + finger up + + + + + + button 2 + press + + + + move > + threshold + + + + timeout + + + + + + + + button 1 + release + + + + button 2 + release + + + + + + + + TAPPED + + + + timeout + + + + + + first + finger down + + + + + + DRAGGING + + + + first + finger up + + + + btn1 + release + + + + + + + + + + IDLE + + + + third + finger down + + + + + + TOUCH_3 + + + + + + button 3 + press + + + + button 3 + release + + + + + + move > + threshold + + + + + + IDLE + + + + timeout + + + + + + first + finger up + + + + + + IDLE + + + + fourth + finger down + + + + + + + + DRAGGING_OR_DOUBLETAP + + + + + + timeout + + + + + + first + finger up + + + + + + button 1 + release + + + + button 1 + press + + + + btn1 + release + + + + + + + + + + + + second + finger down + + + + + + move > + threshold + + + + + + + + HOLD + + + + first + finger up + + + + + + + + second + finger down + + + + + + + + + + TOUCH_2_HOLD + + + + second + finger up + + + + + + first + finger up + + + + + + + + + + third + finger down + + + + + + + + + + TOUCH_3_HOLD + + + + + + fourth + finger down + + + + DEAD + + + + + + + + + + any finger up + + + + fourth + finger up + + + + any finger up + + + + + + + + yes + + + + any finger up + + + + + + + + + + + + IDLE + + + + if finger + count == 0 + + + + + + + + + + second + finger up + + + + DRAGGING_2 + + + + + + + + first + finger up + + + + + + + + + + second + finger down + + + + + + + + + + third + finger down + + + + + + btn1 + release + + + + + + phys + button + press + + + + + + + + + + + + + + + + phys + button + press + + + + + + button 1 + release + + + + + + + + + + + + + + DRAGGING_WAIT + + + + timeout + + + + + + + + + + first + finger down + + + + + + TOUCH_TOUCH + + + + TOUCH_IDLE + + + + + + + + + + + + TOUCH_DEAD + + + + + + + + + + + + + + yes + + + + TOUCH_DEAD + + + + + + + + + + TOUCH_IDLE + + + + + + TOUCH_TOUCH + + + + + + + + TOUCH_IDLE + + + + + + TOUCH_IDLE + + + + + + TOUCH_IDLE + + + + + + TOUCH_TOUCH + + + + + + that finger + TOUCH_IDLE + + + + + + TOUCH_DEAD + + + + + + + + + + that finger + TOUCH_IDLE + + + + + + + + no + + + + TOUCH_TOUCH + + + + + + TOUCH_IDLE + + + + + + TOUCH_TOUCH + + + + + + TOUCH_DEAD + + + + + + + + TOUCH_IDLE + + + + + + TOUCH_TOUCH + + + + + + + + TOUCH_TOUCH + + + + + + TOUCH_IDLE + + + + + + TOUCH_IDLE + + + + + + TOUCH_TOUCH + + + + + + TOUCH_IDLE + + + + + + TOUCH_TOUCH + + + + + + that finger + TOUCH_IDLE + + + + + + TOUCH_DEAD + + + + + + TOUCH_DEAD + + + + TOUCH_DEAD + + + + TOUCH_DEAD + + + + + + TOUCH_DEAD + + + + + + TOUCH_DEAD + + + + + + state == + TOUCH_TOUCH + + + + that finger state == + TOUCH_TOUCH + + + + + + no + + + + TOUCH_DEAD + + + + + + TOUCH_DEAD + + + + TOUCH_DEAD + + + diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index 25412184..8a129634 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -95,12 +95,16 @@ tap_event_to_str(enum tap_event event) { static void tp_tap_notify(struct tp_dispatch *tp, + struct tp_touch *t, uint64_t time, int nfingers, enum libinput_button_state state) { int32_t button; + if (t && t->tap.state == TAP_TOUCH_STATE_DEAD) + return; + switch (nfingers) { case 1: button = BTN_LEFT; break; case 2: button = BTN_RIGHT; break; @@ -128,7 +132,9 @@ tp_tap_clear_timer(struct tp_dispatch *tp) } static void -tp_tap_idle_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_idle_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { struct libinput *libinput = tp->device->base.seat->libinput; @@ -151,7 +157,9 @@ tp_tap_idle_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t } static void -tp_tap_touch_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_touch_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -161,7 +169,7 @@ tp_tap_touch_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t break; case TAP_EVENT_RELEASE: tp->tap.state = TAP_STATE_TAPPED; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_PRESSED); tp_tap_set_timer(tp, time); break; case TAP_EVENT_TIMEOUT: @@ -176,7 +184,9 @@ tp_tap_touch_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t } static void -tp_tap_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_hold_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -197,7 +207,9 @@ tp_tap_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t } static void -tp_tap_tapped_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_tapped_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { struct libinput *libinput = tp->device->base.seat->libinput; @@ -213,17 +225,19 @@ tp_tap_tapped_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_ break; case TAP_EVENT_TIMEOUT: tp->tap.state = TAP_STATE_IDLE; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_DEAD; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; } } static void -tp_tap_touch2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_touch2_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -233,8 +247,8 @@ tp_tap_touch2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_ break; case TAP_EVENT_RELEASE: tp->tap.state = TAP_STATE_HOLD; - tp_tap_notify(tp, time, 2, LIBINPUT_BUTTON_STATE_PRESSED); - tp_tap_notify(tp, time, 2, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 2, LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_notify(tp, t, time, 2, LIBINPUT_BUTTON_STATE_RELEASED); tp_tap_clear_timer(tp); break; case TAP_EVENT_MOTION: @@ -249,7 +263,9 @@ tp_tap_touch2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_ } static void -tp_tap_touch2_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_touch2_hold_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -271,7 +287,9 @@ 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, uint64_t time) +tp_tap_touch3_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -286,8 +304,8 @@ tp_tap_touch3_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_ break; case TAP_EVENT_RELEASE: tp->tap.state = TAP_STATE_TOUCH_2_HOLD; - tp_tap_notify(tp, time, 3, LIBINPUT_BUTTON_STATE_PRESSED); - tp_tap_notify(tp, time, 3, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 3, LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_notify(tp, t, time, 3, LIBINPUT_BUTTON_STATE_RELEASED); break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_DEAD; @@ -296,7 +314,9 @@ tp_tap_touch3_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_ } static void -tp_tap_touch3_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_touch3_hold_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -317,7 +337,9 @@ 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, uint64_t time) +tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { case TAP_EVENT_TOUCH: @@ -325,9 +347,9 @@ tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp, enum tap_event break; case TAP_EVENT_RELEASE: tp->tap.state = TAP_STATE_IDLE; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_PRESSED); - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_PRESSED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); tp_tap_clear_timer(tp); break; case TAP_EVENT_MOTION: @@ -336,13 +358,15 @@ tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp, enum tap_event break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_DEAD; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; } } static void -tp_tap_dragging_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_dragging_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -359,13 +383,15 @@ tp_tap_dragging_handle_event(struct tp_dispatch *tp, enum tap_event event, uint6 break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_DEAD; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; } } static void -tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -378,17 +404,19 @@ tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp, enum tap_event event, break; case TAP_EVENT_TIMEOUT: tp->tap.state = TAP_STATE_IDLE; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_DEAD; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; } } static void -tp_tap_dragging2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_dragging2_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, uint64_t time) { switch (event) { @@ -397,7 +425,7 @@ tp_tap_dragging2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint break; case TAP_EVENT_TOUCH: tp->tap.state = TAP_STATE_DEAD; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; case TAP_EVENT_MOTION: case TAP_EVENT_TIMEOUT: @@ -405,13 +433,16 @@ tp_tap_dragging2_handle_event(struct tp_dispatch *tp, enum tap_event event, uint break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_DEAD; - tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); + tp_tap_notify(tp, t, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; } } static void -tp_tap_dead_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_dead_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, + uint64_t time) { switch (event) { @@ -428,7 +459,10 @@ tp_tap_dead_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t } static void -tp_tap_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) +tp_tap_handle_event(struct tp_dispatch *tp, + struct tp_touch *t, + enum tap_event event, + uint64_t time) { struct libinput *libinput = tp->device->base.seat->libinput; enum tp_tap_state current; @@ -440,43 +474,43 @@ tp_tap_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) switch(tp->tap.state) { case TAP_STATE_IDLE: - tp_tap_idle_handle_event(tp, event, time); + tp_tap_idle_handle_event(tp, t, event, time); break; case TAP_STATE_TOUCH: - tp_tap_touch_handle_event(tp, event, time); + tp_tap_touch_handle_event(tp, t, event, time); break; case TAP_STATE_HOLD: - tp_tap_hold_handle_event(tp, event, time); + tp_tap_hold_handle_event(tp, t, event, time); break; case TAP_STATE_TAPPED: - tp_tap_tapped_handle_event(tp, event, time); + tp_tap_tapped_handle_event(tp, t, event, time); break; case TAP_STATE_TOUCH_2: - tp_tap_touch2_handle_event(tp, event, time); + tp_tap_touch2_handle_event(tp, t, event, time); break; case TAP_STATE_TOUCH_2_HOLD: - tp_tap_touch2_hold_handle_event(tp, event, time); + tp_tap_touch2_hold_handle_event(tp, t, event, time); break; case TAP_STATE_TOUCH_3: - tp_tap_touch3_handle_event(tp, event, time); + tp_tap_touch3_handle_event(tp, t, event, time); break; case TAP_STATE_TOUCH_3_HOLD: - tp_tap_touch3_hold_handle_event(tp, event, time); + tp_tap_touch3_hold_handle_event(tp, t, event, time); break; case TAP_STATE_DRAGGING_OR_DOUBLETAP: - tp_tap_dragging_or_doubletap_handle_event(tp, event, time); + tp_tap_dragging_or_doubletap_handle_event(tp, t, event, time); break; case TAP_STATE_DRAGGING: - tp_tap_dragging_handle_event(tp, event, time); + tp_tap_dragging_handle_event(tp, t, event, time); break; case TAP_STATE_DRAGGING_WAIT: - tp_tap_dragging_wait_handle_event(tp, event, time); + tp_tap_dragging_wait_handle_event(tp, t, event, time); break; case TAP_STATE_DRAGGING_2: - tp_tap_dragging2_handle_event(tp, event, time); + tp_tap_dragging2_handle_event(tp, t, event, time); break; case TAP_STATE_DEAD: - tp_tap_dead_handle_event(tp, event, time); + tp_tap_dead_handle_event(tp, t, event, time); break; } @@ -508,19 +542,34 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time) int filter_motion = 0; if (tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) - tp_tap_handle_event(tp, TAP_EVENT_BUTTON, time); + tp_tap_handle_event(tp, NULL, TAP_EVENT_BUTTON, time); tp_for_each_touch(tp, t) { if (!t->dirty || t->state == TOUCH_NONE) continue; - if (t->state == TOUCH_BEGIN) - tp_tap_handle_event(tp, TAP_EVENT_TOUCH, time); - else if (t->state == TOUCH_END) - tp_tap_handle_event(tp, TAP_EVENT_RELEASE, time); - else if (tp->tap.state != TAP_STATE_IDLE && - tp_tap_exceeds_motion_threshold(tp, t)) - tp_tap_handle_event(tp, TAP_EVENT_MOTION, time); + if (tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) + t->tap.state = TAP_TOUCH_STATE_DEAD; + + if (t->state == TOUCH_BEGIN) { + t->tap.state = TAP_TOUCH_STATE_TOUCH; + tp_tap_handle_event(tp, t, TAP_EVENT_TOUCH, time); + } else if (t->state == TOUCH_END) { + tp_tap_handle_event(tp, t, TAP_EVENT_RELEASE, time); + t->tap.state = TAP_TOUCH_STATE_DEAD; + } else if (tp->tap.state != TAP_STATE_IDLE && + tp_tap_exceeds_motion_threshold(tp, t)) { + struct tp_touch *tmp; + + /* Any touch exceeding the threshold turns all + * touches into DEAD */ + tp_for_each_touch(tp, tmp) { + if (tmp->tap.state == TAP_TOUCH_STATE_TOUCH) + tmp->tap.state = TAP_TOUCH_STATE_DEAD; + } + + tp_tap_handle_event(tp, t, TAP_EVENT_MOTION, time); + } } /** @@ -550,8 +599,17 @@ static void tp_tap_handle_timeout(uint64_t time, void *data) { struct tp_dispatch *tp = data; + struct tp_touch *t; - tp_tap_handle_event(tp, TAP_EVENT_TIMEOUT, time); + tp_tap_handle_event(tp, NULL, TAP_EVENT_TIMEOUT, time); + + tp_for_each_touch(tp, t) { + if (t->state == TOUCH_NONE || + t->tap.state == TAP_TOUCH_STATE_IDLE) + continue; + + t->tap.state = TAP_TOUCH_STATE_DEAD; + } } int diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 7afb3c46..494725a6 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -88,6 +88,12 @@ enum tp_tap_state { TAP_STATE_DEAD, /**< finger count exceeded */ }; +enum tp_tap_touch_state { + TAP_TOUCH_STATE_IDLE = 16, /**< not in touch */ + TAP_TOUCH_STATE_TOUCH, /**< touching, may tap */ + TAP_TOUCH_STATE_DEAD, /**< exceeded motion/timeout */ +}; + struct tp_motion { int32_t x; int32_t y; @@ -131,6 +137,10 @@ struct tp_touch { enum button_event curr; struct libinput_timer timer; } button; + + struct { + enum tp_tap_touch_state state; + } tap; }; struct tp_dispatch { diff --git a/test/touchpad.c b/test/touchpad.c index 288805ef..3e5ee202 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -320,6 +320,82 @@ START_TEST(touchpad_2fg_tap_click_apple) } END_TEST +START_TEST(touchpad_no_2fg_tap_after_move) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_drain_events(dev->libinput); + + /* one finger down, move past threshold, + second finger down, first finger up + -> no event + */ + litest_touch_down(dev, 0, 50, 50); + litest_touch_move_to(dev, 0, 50, 50, 90, 90, 10); + litest_drain_events(dev->libinput); + + litest_touch_down(dev, 1, 70, 50); + litest_touch_up(dev, 0); + + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(touchpad_no_2fg_tap_after_timeout) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_drain_events(dev->libinput); + + /* one finger down, wait past tap timeout, + second finger down, first finger up + -> no event + */ + litest_touch_down(dev, 0, 50, 50); + libinput_dispatch(dev->libinput); + msleep(300); + libinput_dispatch(dev->libinput); + litest_drain_events(dev->libinput); + + litest_touch_down(dev, 1, 70, 50); + litest_touch_up(dev, 0); + + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(touchpad_no_first_fg_tap_after_move) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + + litest_drain_events(dev->libinput); + + /* one finger down, second finger down, + second finger moves beyond threshold, + first finger up + -> no event + */ + litest_touch_down(dev, 0, 50, 50); + litest_touch_down(dev, 1, 70, 50); + libinput_dispatch(dev->libinput); + litest_touch_move_to(dev, 1, 70, 50, 90, 90, 10); + libinput_dispatch(dev->libinput); + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + libinput_dispatch(dev->libinput); + + while ((event = libinput_get_event(li))) { + ck_assert_int_ne(libinput_event_get_type(event), + LIBINPUT_EVENT_POINTER_BUTTON); + libinput_event_destroy(event); + } +} +END_TEST + START_TEST(touchpad_1fg_double_tap_click) { struct litest_device *dev = litest_current_device(); @@ -1127,6 +1203,11 @@ int main(int argc, char **argv) { litest_add("touchpad:tap", touchpad_1fg_tap_click, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:tap", touchpad_2fg_tap_click, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_APPLE_CLICKPAD); litest_add("touchpad:tap", touchpad_2fg_tap_click_apple, LITEST_APPLE_CLICKPAD, LITEST_ANY); + litest_add("touchpad:tap", touchpad_no_2fg_tap_after_move, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("touchpad:tap", touchpad_no_2fg_tap_after_timeout, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("touchpad:tap", touchpad_no_first_fg_tap_after_move, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("touchpad:tap", touchpad_no_first_fg_tap_after_move, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + /* Real buttons don't interfere with tapping, so don't run those for pads with buttons */ litest_add("touchpad:tap", touchpad_1fg_double_tap_click, LITEST_CLICKPAD, LITEST_ANY); From 6b6f24ee1c77399c6e8dffae80cff2ec35ca3e73 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 27 Jun 2014 12:55:29 +1000 Subject: [PATCH 05/50] Add functions to get the device name, PID and VID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Those three are the ones that matter for logging or device identification in callers, so let's provide them. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede Reviewed-by: Jonas Ådahl --- src/evdev.c | 18 ++++++++++++++++++ src/evdev.h | 9 +++++++++ src/libinput.c | 18 ++++++++++++++++++ src/libinput.h | 41 +++++++++++++++++++++++++++++++++++++++++ test/misc.c | 20 ++++++++++++++++++++ 5 files changed, 106 insertions(+) diff --git a/src/evdev.c b/src/evdev.c index f72bd43e..183c2000 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -857,6 +857,24 @@ evdev_device_get_sysname(struct evdev_device *device) return device->sysname; } +const char * +evdev_device_get_name(struct evdev_device *device) +{ + return device->devname; +} + +unsigned int +evdev_device_get_id_product(struct evdev_device *device) +{ + return libevdev_get_id_product(device->evdev); +} + +unsigned int +evdev_device_get_id_vendor(struct evdev_device *device) +{ + return libevdev_get_id_vendor(device->evdev); +} + void evdev_device_calibrate(struct evdev_device *device, float calibration[6]) { diff --git a/src/evdev.h b/src/evdev.h index 4a83a78a..fad1f84c 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -141,6 +141,15 @@ evdev_device_get_output(struct evdev_device *device); const char * evdev_device_get_sysname(struct evdev_device *device); +const char * +evdev_device_get_name(struct evdev_device *device); + +unsigned int +evdev_device_get_id_product(struct evdev_device *device); + +unsigned int +evdev_device_get_id_vendor(struct evdev_device *device); + void evdev_device_calibrate(struct evdev_device *device, float calibration[6]); diff --git a/src/libinput.c b/src/libinput.c index 44f4f23d..1918b48a 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -1161,6 +1161,24 @@ libinput_device_get_sysname(struct libinput_device *device) return evdev_device_get_sysname((struct evdev_device *) device); } +LIBINPUT_EXPORT const char * +libinput_device_get_name(struct libinput_device *device) +{ + return evdev_device_get_name((struct evdev_device *) device); +} + +LIBINPUT_EXPORT unsigned int +libinput_device_get_id_product(struct libinput_device *device) +{ + return evdev_device_get_id_product((struct evdev_device *) device); +} + +LIBINPUT_EXPORT unsigned int +libinput_device_get_id_vendor(struct libinput_device *device) +{ + return evdev_device_get_id_vendor((struct evdev_device *) device); +} + LIBINPUT_EXPORT const char * libinput_device_get_output_name(struct libinput_device *device) { diff --git a/src/libinput.h b/src/libinput.h index ff67ce7c..ff8caf48 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -1248,12 +1248,53 @@ libinput_device_get_user_data(struct libinput_device *device); * * Get the system name of the device. * + * To get the descriptive device name, use libinput_device_get_name(). + * * @param device A previously obtained device * @return System name of the device + * */ const char * libinput_device_get_sysname(struct libinput_device *device); +/** + * @ingroup device + * + * The descriptive device name as advertised by the kernel and/or the + * hardware itself. To get the sysname for this device, use + * libinput_device_get_sysname(). + * + * The lifetime of the returned string is tied to the struct + * libinput_device. The string may be the empty string but is never NULL. + * + * @param device A previously obtained device + * @return The device name + */ +const char * +libinput_device_get_name(struct libinput_device *device); + +/** + * @ingroup device + * + * Get the product ID for this device. + * + * @param device A previously obtained device + * @return The product ID of this device + */ +unsigned int +libinput_device_get_id_product(struct libinput_device *device); + +/** + * @ingroup device + * + * Get the vendor ID for this device. + * + * @param device A previously obtained device + * @return The vendor ID of this device + */ +unsigned int +libinput_device_get_id_vendor(struct libinput_device *device); + /** * @ingroup device * diff --git a/test/misc.c b/test/misc.c index bea7e889..e467a5c2 100644 --- a/test/misc.c +++ b/test/misc.c @@ -390,6 +390,25 @@ START_TEST(context_ref_counting) } END_TEST +START_TEST(device_ids) +{ + struct litest_device *dev = litest_current_device(); + const char *name; + int pid, vid; + + name = libevdev_get_name(dev->evdev); + pid = libevdev_get_id_product(dev->evdev); + vid = libevdev_get_id_vendor(dev->evdev); + + ck_assert_str_eq(name, + libinput_device_get_name(dev->libinput_device)); + ck_assert_int_eq(pid, + libinput_device_get_id_product(dev->libinput_device)); + ck_assert_int_eq(vid, + libinput_device_get_id_vendor(dev->libinput_device)); +} +END_TEST + int main (int argc, char **argv) { litest_add_no_device("events:conversion", event_conversion_device_notify); litest_add_no_device("events:conversion", event_conversion_pointer); @@ -397,6 +416,7 @@ int main (int argc, char **argv) { litest_add_no_device("events:conversion", event_conversion_key); litest_add_no_device("events:conversion", event_conversion_touch); litest_add_no_device("context:refcount", context_ref_counting); + litest_add("device:id", device_ids, LITEST_ANY, LITEST_ANY); return litest_run(argc, argv); } From bb3edf4c940e66bf5064be61fea0857aa623d58d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 1 Jul 2014 14:53:18 +0200 Subject: [PATCH 06/50] touchpad: Switch to smooth simple acceleration code from filter.c The old touchpad accel code was clamping touchpad acceleration between 0.2 and 0.4, and on the test devices I have the constant_factor ended up such that in practice the accel was almost always 0.2, so rather than having a velocity based acceleration curve, in essence it was just always using an acceleration of 0.2 . This commit introduces actual velocity based acceleration based on the recently added smooth simple acceleration code from filter.c . Before feeding motion events to filter.c, they first get adjusted for touchpad resolution. For touchpads where the driver does not provide resolution info, scale based on the diagonal-size in units instead. While at it rename tp_init_accel's dispatch parameter from touchpad to tp to be consistent with all other functions. Since the acceleration is also used for scrolling also adjust the scroll start threshold for these changes. Note that switching to the smooth simple accel code, as an added bonus gives the tp code an accel profile with a threshold and a speed parameter, which is exactly what is needed for the upcoming configuration interface support. Signed-off-by: Hans de Goede Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad.c | 78 ++++++++++++++--------------------------- src/evdev-mt-touchpad.h | 4 --- 2 files changed, 26 insertions(+), 56 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 9e858f13..fc2a5ab3 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -28,9 +28,7 @@ #include "evdev-mt-touchpad.h" -#define DEFAULT_CONSTANT_ACCEL_NUMERATOR 100 -#define DEFAULT_MIN_ACCEL_FACTOR 0.20 -#define DEFAULT_MAX_ACCEL_FACTOR 0.40 +#define DEFAULT_ACCEL_NUMERATOR 1200.0 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0 static inline int @@ -46,27 +44,6 @@ tp_hysteresis(int in, int center, int margin) return center + diff + margin; } -static double -tp_accel_profile(struct motion_filter *filter, - void *data, - double velocity, - uint64_t time) -{ - struct tp_dispatch *tp = - (struct tp_dispatch *) data; - - double accel_factor; - - accel_factor = velocity * tp->accel.constant_factor; - - if (accel_factor > tp->accel.max_factor) - accel_factor = tp->accel.max_factor; - else if (accel_factor < tp->accel.min_factor) - accel_factor = tp->accel.min_factor; - - return accel_factor; -} - static inline struct tp_motion * tp_motion_history_offset(struct tp_touch *t, int offset) { @@ -464,11 +441,11 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time) tp_filter_motion(tp, &dx, &dy, time); - /* Require at least three px scrolling to start */ - if (dy <= -3.0 || dy >= 3.0) + /* Require at least five px scrolling to start */ + if (dy <= -5.0 || dy >= 5.0) tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); - if (dx <= -3.0 || dx >= 3.0) + if (dx <= -5.0 || dx >= 5.0) tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); if (dy != 0.0 && @@ -665,9 +642,10 @@ tp_init_slots(struct tp_dispatch *tp, return 0; } -static void -calculate_scale_coefficients(struct tp_dispatch *tp) +static int +tp_init_accel(struct tp_dispatch *tp, double diagonal) { + struct motion_filter *accel; int res_x, res_y; if (tp->has_mt) { @@ -682,35 +660,31 @@ calculate_scale_coefficients(struct tp_dispatch *tp) ABS_Y); } - if (res_x <= 0 || res_y <= 0) { - tp->accel.x_scale_coeff = 1.0; - tp->accel.y_scale_coeff = 1.0; - } else if (res_x > res_y) { - tp->accel.x_scale_coeff = res_y / (double) res_x; - tp->accel.y_scale_coeff = 1.0f; + /* + * Not all touchpads report the same amount of units/mm (resolution). + * Normalize motion events to a resolution of 10 units/mm as base + * (unaccelerated) speed. This also evens out any differences in x + * and y resolution, so that a circle on the touchpad does not turn + * into an elipse on the screen. + */ + if (res_x > 1 && res_y > 1) { + tp->accel.x_scale_coeff = 10.0 / res_x; + tp->accel.y_scale_coeff = 10.0 / res_y; } else { - tp->accel.y_scale_coeff = res_x / (double) res_y; - tp->accel.x_scale_coeff = 1.0f; + /* + * For touchpads where the driver does not provide resolution, fall + * back to scaling motion events based on the diagonal size in units. + */ + tp->accel.x_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal; + tp->accel.y_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal; } -} -static int -tp_init_accel(struct tp_dispatch *touchpad, double diagonal) -{ - struct motion_filter *accel; - - calculate_scale_coefficients(touchpad); - - touchpad->accel.constant_factor = - DEFAULT_CONSTANT_ACCEL_NUMERATOR / diagonal; - touchpad->accel.min_factor = DEFAULT_MIN_ACCEL_FACTOR; - touchpad->accel.max_factor = DEFAULT_MAX_ACCEL_FACTOR; - - accel = create_pointer_accelator_filter(tp_accel_profile); + accel = create_pointer_accelator_filter( + pointer_accel_profile_smooth_simple); if (accel == NULL) return -1; - touchpad->filter = accel; + tp->filter = accel; return 0; } diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 494725a6..6fb9ca4d 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -162,10 +162,6 @@ struct tp_dispatch { struct motion_filter *filter; struct { - double constant_factor; - double min_factor; - double max_factor; - double x_scale_coeff; double y_scale_coeff; } accel; From fccbe88f05d897add812864888fb2b26d69b6335 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 3 Jul 2014 09:53:35 +1000 Subject: [PATCH 07/50] touchpad: log the sysname of the device that looks like a bad clickpad Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad-buttons.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 2ac231c7..b84198ce 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -581,11 +581,13 @@ tp_init_buttons(struct tp_dispatch *tp, libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) { if (tp->buttons.is_clickpad) log_bug_kernel(libinput, - "clickpad advertising right button\n"); + "%s: clickpad advertising right button\n", + device->sysname); } else { if (!tp->buttons.is_clickpad) log_bug_kernel(libinput, - "non clickpad without right button?\n"); + "%s: non clickpad without right button?\n", + device->sysname); } absinfo_x = device->abs.absinfo_x; From 3758f38bfda6be47da940a11e2c4cf862f9bf6e4 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 3 Jul 2014 09:54:29 +1000 Subject: [PATCH 08/50] tools: draw the circle for abs events in the right position Signed-off-by: Peter Hutterer --- tools/event-gui.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/event-gui.c b/tools/event-gui.c index d65a8d15..78a61672 100644 --- a/tools/event-gui.c +++ b/tools/event-gui.c @@ -142,8 +142,7 @@ draw(GtkWidget *widget, cairo_t *cr, gpointer data) cairo_set_source_rgb(cr, .2, .4, .8); cairo_save(cr); - cairo_move_to(cr, w->absx, w->absy); - cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); + cairo_arc(cr, w->absx, w->absy, 10, 0, 2 * M_PI); cairo_fill(cr); cairo_restore(cr); From 86d3628d55cd9632e887640079f57daeff6b0dfb Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 3 Jul 2014 09:57:12 +1000 Subject: [PATCH 09/50] tools: fix touch/abs event coordinate transformation in event-gui Signed-off-by: Peter Hutterer --- tools/event-gui.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/event-gui.c b/tools/event-gui.c index 78a61672..0aa91298 100644 --- a/tools/event-gui.c +++ b/tools/event-gui.c @@ -242,11 +242,11 @@ static void handle_event_absmotion(struct libinput_event *ev, struct window *w) { struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev); - double x = libinput_event_pointer_get_absolute_x(p), - y = libinput_event_pointer_get_absolute_y(p); + double x = libinput_event_pointer_get_absolute_x_transformed(p, w->width), + y = libinput_event_pointer_get_absolute_y_transformed(p, w->height); - w->absx = clip((int)x, 0, w->width); - w->absy = clip((int)y, 0, w->height); + w->absx = x; + w->absy = y; } static void @@ -267,8 +267,8 @@ handle_event_touch(struct libinput_event *ev, struct window *w) return; } - x = libinput_event_touch_get_x(t), - y = libinput_event_touch_get_y(t); + x = libinput_event_touch_get_x_transformed(t, w->width), + y = libinput_event_touch_get_y_transformed(t, w->height); touch->active = 1; touch->x = (int)x; From 36720c51516bbe87ad38f52e646877c6d5d40ba7 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 3 Jul 2014 09:59:26 +1000 Subject: [PATCH 10/50] Fix two doxygen refs pointing to nonexistent functions Signed-off-by: Peter Hutterer --- src/libinput.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libinput.h b/src/libinput.h index ff8caf48..73183da8 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -455,7 +455,7 @@ libinput_event_pointer_get_dy(struct libinput_event_pointer *event); * * Return the current absolute x coordinate of the pointer event, in mm from * the top left corner of the device. To get the corresponding output screen - * coordinate, use libinput_event_pointer_get_x_transformed(). + * coordinate, use libinput_event_pointer_get_absolute_x_transformed(). * * For pointer events that are not of type * LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE, this function returns 0. @@ -473,7 +473,7 @@ libinput_event_pointer_get_absolute_x(struct libinput_event_pointer *event); * * Return the current absolute y coordinate of the pointer event, in mm from * the top left corner of the device. To get the corresponding output screen - * coordinate, use libinput_event_pointer_get_x_transformed(). + * coordinate, use libinput_event_pointer_get_absolute_y_transformed(). * * For pointer events that are not of type * LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE, this function returns 0. From 5d36e8e817cb3501165dd2d1b36d3487fa523eab Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 3 Jul 2014 09:29:22 +1000 Subject: [PATCH 11/50] configure: check for -lm through AC_CHECK_LIB Saves us from manually appending it everywhere Signed-off-by: Peter Hutterer --- configure.ac | 1 + src/Makefile.am | 3 +-- test/Makefile.am | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 860324ac..ca317204 100644 --- a/configure.ac +++ b/configure.ac @@ -57,6 +57,7 @@ PKG_PROG_PKG_CONFIG() PKG_CHECK_MODULES(MTDEV, [mtdev >= 1.1.0]) PKG_CHECK_MODULES(LIBUDEV, [libudev]) PKG_CHECK_MODULES(LIBEVDEV, [libevdev >= 0.4]) +AC_CHECK_LIB([m], [atan2]) if test "x$GCC" = "xyes"; then GCC_CXXFLAGS="-Wall -Wextra -Wno-unused-parameter -g -fvisibility=hidden" diff --git a/src/Makefile.am b/src/Makefile.am index bf561845..76fe4c94 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -27,8 +27,7 @@ libinput_la_SOURCES = \ libinput_la_LIBADD = $(MTDEV_LIBS) \ $(LIBUDEV_LIBS) \ - $(LIBEVDEV_LIBS) \ - -lm + $(LIBEVDEV_LIBS) libinput_la_CFLAGS = -I$(top_srcdir)/include \ $(MTDEV_CFLAGS) \ $(LIBUDEV_CFLAGS) \ diff --git a/test/Makefile.am b/test/Makefile.am index 8bfdf201..16dac419 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -8,7 +8,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include \ AM_CFLAGS = $(GCC_CFLAGS) AM_CXXFLAGS = $(GCC_CXXFLAGS) -TEST_LIBS = liblitest.la $(CHECK_LIBS) $(LIBUDEV_LIBS) $(LIBEVDEV_LIBS) $(top_builddir)/src/libinput.la -lm +TEST_LIBS = liblitest.la $(CHECK_LIBS) $(LIBUDEV_LIBS) $(LIBEVDEV_LIBS) $(top_builddir)/src/libinput.la noinst_LTLIBRARIES = liblitest.la liblitest_la_SOURCES = \ $(top_srcdir)/src/libinput-util.h \ From f28eb5ecec98b1f6fe9de3933bb1bb718d45929e Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 3 Jul 2014 09:30:40 +1000 Subject: [PATCH 12/50] Add -lrt to the libs Needed for clock_gettime() Signed-off-by: Peter Hutterer --- configure.ac | 1 + src/libinput.pc.in | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index ca317204..3497cb6e 100644 --- a/configure.ac +++ b/configure.ac @@ -58,6 +58,7 @@ PKG_CHECK_MODULES(MTDEV, [mtdev >= 1.1.0]) PKG_CHECK_MODULES(LIBUDEV, [libudev]) PKG_CHECK_MODULES(LIBEVDEV, [libevdev >= 0.4]) AC_CHECK_LIB([m], [atan2]) +AC_CHECK_LIB([rt], [clock_gettime]) if test "x$GCC" = "xyes"; then GCC_CXXFLAGS="-Wall -Wextra -Wno-unused-parameter -g -fvisibility=hidden" diff --git a/src/libinput.pc.in b/src/libinput.pc.in index d2b11363..03e70e78 100644 --- a/src/libinput.pc.in +++ b/src/libinput.pc.in @@ -10,5 +10,5 @@ Description: Input device library Version: @LIBINPUT_VERSION@ Cflags: -I${includedir} Libs: -L${libdir} -linput -Libs.private: -lm +Libs.private: -lm -lrt Requires.private: libudev From 5ab2bcad6f8cae7cc249a6294e81a6ad346931b5 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 3 Jul 2014 09:32:02 +1000 Subject: [PATCH 13/50] Fix compiler warnings for missing initializers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit timer.c: In function ‘libinput_timer_arm_timer_fd’: timer.c:48: warning: missing initializer timer.c:48: warning: (near initialization for ‘its.it_value.tv_nsec’) Signed-off-by: Peter Hutterer --- src/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/timer.c b/src/timer.c index 3076bb7a..ad0fd7c8 100644 --- a/src/timer.c +++ b/src/timer.c @@ -45,7 +45,7 @@ libinput_timer_arm_timer_fd(struct libinput *libinput) { int r; struct libinput_timer *timer; - struct itimerspec its = { { 0 }, { 0 } }; + struct itimerspec its = { { 0, 0 }, { 0, 0 } }; uint64_t earliest_expire = UINT64_MAX; list_for_each(timer, &libinput->timer.list, link) { From 124aa9b0f86e59a9ecdebb4a998d51794e92878e Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 3 Jul 2014 10:52:40 +1000 Subject: [PATCH 14/50] configure: print a summary of the build options Signed-off-by: Peter Hutterer --- configure.ac | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/configure.ac b/configure.ac index 3497cb6e..65c915e6 100644 --- a/configure.ac +++ b/configure.ac @@ -121,3 +121,12 @@ AC_CONFIG_FILES([Makefile test/Makefile tools/Makefile]) AC_OUTPUT + +AC_MSG_RESULT([ + Prefix ${prefix} + + Build documentation ${have_doxygen} + Build tests ${build_tests} + Tests use valgrind ${VALGRIND} + Build GUI event tool ${build_eventgui} + ]) From 5cecefeea050642355fd35f39f46b5aa7ee304c5 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 3 Jul 2014 11:00:54 +1000 Subject: [PATCH 15/50] test: fix compiler warnings for comparison int vs unsigned int Signed-off-by: Peter Hutterer --- test/litest.c | 4 ++-- test/misc.c | 2 +- test/pointer.c | 2 +- test/touchpad.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/litest.c b/test/litest.c index 02f3d77b..5fd9e913 100644 --- a/test/litest.c +++ b/test/litest.c @@ -357,7 +357,7 @@ merge_absinfo(const struct input_absinfo *orig, const struct input_absinfo *override) { struct input_absinfo *abs; - int nelem, i; + unsigned int nelem, i; size_t sz = ABS_MAX + 1; if (!orig) @@ -391,7 +391,7 @@ static int* merge_events(const int *orig, const int *override) { int *events; - int nelem, i; + unsigned int nelem, i; size_t sz = KEY_MAX * 3; if (!orig) diff --git a/test/misc.c b/test/misc.c index e467a5c2..30b8d452 100644 --- a/test/misc.c +++ b/test/misc.c @@ -394,7 +394,7 @@ START_TEST(device_ids) { struct litest_device *dev = litest_current_device(); const char *name; - int pid, vid; + unsigned int pid, vid; name = libevdev_get_name(dev->evdev); pid = libevdev_get_id_product(dev->evdev); diff --git a/test/pointer.c b/test/pointer.c index 7d5668f8..8f1ab1fe 100644 --- a/test/pointer.c +++ b/test/pointer.c @@ -102,7 +102,7 @@ START_TEST(pointer_motion_relative) END_TEST static void -test_button_event(struct litest_device *dev, int button, int state) +test_button_event(struct litest_device *dev, unsigned int button, int state) { struct libinput *li = dev->libinput; struct libinput_event *event; diff --git a/test/touchpad.c b/test/touchpad.c index 3e5ee202..d7625e92 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -90,7 +90,7 @@ START_TEST(touchpad_2fg_no_motion) END_TEST static void -assert_button_event(struct libinput *li, int button, +assert_button_event(struct libinput *li, unsigned int button, enum libinput_button_state state) { struct libinput_event *event; @@ -1127,7 +1127,7 @@ test_2fg_scroll(struct litest_device *dev, int dx, int dy, int sleep) } static void -check_2fg_scroll(struct litest_device *dev, int axis, int dir) +check_2fg_scroll(struct litest_device *dev, unsigned int axis, int dir) { struct libinput *li = dev->libinput; struct libinput_event *event, *next_event; From 4b88bf30d43ab3ba731c9e78f011b78a484e12ed Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 16 May 2014 09:06:41 +1000 Subject: [PATCH 16/50] Add an enum for configuration return codes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Peter Hutterer Reviewed-by: Jonas Ådahl --- src/libinput.c | 20 ++++++++++++++++++++ src/libinput.h | 34 ++++++++++++++++++++++++++++++++++ test/misc.c | 23 +++++++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/src/libinput.c b/src/libinput.c index 1918b48a..6ea9e485 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -1255,3 +1255,23 @@ libinput_event_touch_get_base_event(struct libinput_event_touch *event) { return &event->base; } + +LIBINPUT_EXPORT const char * +libinput_config_status_to_str(enum libinput_config_status status) +{ + const char *str = NULL; + + switch(status) { + case LIBINPUT_CONFIG_STATUS_SUCCESS: + str = "Success"; + break; + case LIBINPUT_CONFIG_STATUS_UNSUPPORTED: + str = "Unsupported configuration option"; + break; + case LIBINPUT_CONFIG_STATUS_INVALID: + str = "Invalid argument range"; + break; + } + + return str; +} diff --git a/src/libinput.h b/src/libinput.h index 73183da8..ead30646 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -1402,6 +1402,40 @@ libinput_device_get_size(struct libinput_device *device, double *width, double *height); + +/** + * @defgroup config Device configuration + * + * Enable, disable, change and/or check for device-specific features. For + * all features, libinput assigns a default based on the hardware + * configuration. This default can be obtained with the respective + * get_default call. + * + * Some configuration option may be dependent on or mutually exclusive with + * with other options. The behavior in those cases is + * implementation-defined, the caller must ensure that the options are set + * in the right order. + */ + +enum libinput_config_status { + LIBINPUT_CONFIG_STATUS_SUCCESS = 0, /**< Config applied successfully */ + LIBINPUT_CONFIG_STATUS_UNSUPPORTED, /**< Configuration not available on + this device */ + LIBINPUT_CONFIG_STATUS_INVALID, /**< Invalid parameter range */ +}; + +/** + * @ingroup config Device configuration + * + * Return a string describing the error. + * + * @param status The status to translate to a string + * @return A human-readable string representing the error or NULL for an + * invalid status. + */ +const char * +libinput_config_status_to_str(enum libinput_config_status status); + #ifdef __cplusplus } #endif diff --git a/test/misc.c b/test/misc.c index 30b8d452..7e028321 100644 --- a/test/misc.c +++ b/test/misc.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "litest.h" @@ -409,6 +410,27 @@ START_TEST(device_ids) } END_TEST +START_TEST(config_status_string) +{ + const char *strs[3]; + const char *invalid; + size_t i, j; + + strs[0] = libinput_config_status_to_str(LIBINPUT_CONFIG_STATUS_SUCCESS); + strs[1] = libinput_config_status_to_str(LIBINPUT_CONFIG_STATUS_UNSUPPORTED); + strs[2] = libinput_config_status_to_str(LIBINPUT_CONFIG_STATUS_INVALID); + + for (i = 0; i < ARRAY_LENGTH(strs) - 1; i++) + for (j = i + 1; j < ARRAY_LENGTH(strs); j++) + ck_assert_str_ne(strs[i], strs[j]); + + invalid = libinput_config_status_to_str(LIBINPUT_CONFIG_STATUS_INVALID + 1); + ck_assert(invalid == NULL); + invalid = libinput_config_status_to_str(LIBINPUT_CONFIG_STATUS_SUCCESS - 1); + ck_assert(invalid == NULL); +} +END_TEST + int main (int argc, char **argv) { litest_add_no_device("events:conversion", event_conversion_device_notify); litest_add_no_device("events:conversion", event_conversion_pointer); @@ -417,6 +439,7 @@ int main (int argc, char **argv) { litest_add_no_device("events:conversion", event_conversion_touch); litest_add_no_device("context:refcount", context_ref_counting); litest_add("device:id", device_ids, LITEST_ANY, LITEST_ANY); + litest_add_no_device("config:status string", config_status_string); return litest_run(argc, argv); } From 401592870d3d6df3deb669387d58bf632fa0317f Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 7 Jan 2014 11:42:32 +1000 Subject: [PATCH 17/50] Add an interface to enable/disable tapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide an interface to enable/disable tapping, with a default mapping of 1/2/3 fingers mapping to L/R/M button events, respectively. Signed-off-by: Peter Hutterer Reviewed-by: Jonas Ådahl --- src/libinput-private.h | 13 ++++++++ src/libinput.c | 35 ++++++++++++++++++++ src/libinput.h | 73 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 120 insertions(+), 1 deletion(-) diff --git a/src/libinput-private.h b/src/libinput-private.h index 00901b4d..23c51405 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -81,12 +81,25 @@ struct libinput_seat { uint32_t button_count[KEY_CNT]; }; +struct libinput_device_config_tap { + int (*count)(struct libinput_device *device); + enum libinput_config_status (*set_enabled)(struct libinput_device *device, + int enable); + int (*get_enabled)(struct libinput_device *device); + int (*get_default)(struct libinput_device *device); +}; + +struct libinput_device_config { + struct libinput_device_config_tap *tap; +}; + struct libinput_device { struct libinput_seat *seat; struct list link; void *user_data; int terminated; int refcount; + struct libinput_device_config config; }; typedef void (*libinput_source_dispatch_t)(void *data); diff --git a/src/libinput.c b/src/libinput.c index 6ea9e485..ff4b01e1 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -1275,3 +1275,38 @@ libinput_config_status_to_str(enum libinput_config_status status) return str; } + +LIBINPUT_EXPORT int +libinput_device_config_tap_get_finger_count(struct libinput_device *device) +{ + return device->config.tap ? device->config.tap->count(device) : 0; +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_tap_set_enabled(struct libinput_device *device, + int enable) +{ + if (enable && + libinput_device_config_tap_get_finger_count(device) == 0) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + + return device->config.tap->set_enabled(device, enable); +} + +LIBINPUT_EXPORT int +libinput_device_config_tap_get_enabled(struct libinput_device *device) +{ + if (libinput_device_config_tap_get_finger_count(device) == 0) + return 0; + + return device->config.tap->get_enabled(device); +} + +LIBINPUT_EXPORT int +libinput_device_config_tap_get_default_enabled(struct libinput_device *device) +{ + if (libinput_device_config_tap_get_finger_count(device) == 0) + return 0; + + return device->config.tap->get_default(device); +} diff --git a/src/libinput.h b/src/libinput.h index ead30646..0d4b79cb 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -1436,8 +1436,79 @@ enum libinput_config_status { const char * libinput_config_status_to_str(enum libinput_config_status status); +/** + * @ingroup config + * + * Check if the device supports tap-to-click. See + * libinput_device_config_tap_set_enabled() for more information. + * + * @param device The device to configure + * @return The number of fingers that can generate a tap event, or 0 if the + * device does not support tapping. + * + * @see libinput_device_config_tap_set_enabled + * @see libinput_device_config_tap_get_enabled + * @see libinput_device_config_tap_set_enabled_get_default + */ +int +libinput_device_config_tap_get_finger_count(struct libinput_device *device); + +/** + * @ingroup config + * + * Enable or disable tap-to-click on this device, with a default mapping of + * 1, 2, 3 finger tap mapping to left, right, middle click, respectively. + * Tapping is limited by the number of simultaneous touches + * supported by the device, see + * libinput_device_config_tap_get_finger_count(). + * + * @param device The device to configure + * @param enable Non-zero to enable, zero to disable + * + * @return A config status code. Disabling tapping on a device that does not + * support tapping always succeeds. + * + * @see libinput_device_config_tap_get_finger_count + * @see libinput_device_config_tap_get_enabled + * @see libinput_device_config_tap_get_default_enabled + */ +enum libinput_config_status +libinput_device_config_tap_set_enabled(struct libinput_device *device, + int enable); + +/** + * @ingroup config + * + * Check if tap-to-click is enabled on this device. If the device does not + * support tapping, this function always returns 0. + * + * @param device The device to configure + * + * @return 1 if enabled, 0 otherwise. + * + * @see libinput_device_config_tap_get_finger_count + * @see libinput_device_config_tap_set_enabled + * @see libinput_device_config_tap_get_default_enabled + */ +int +libinput_device_config_tap_get_enabled(struct libinput_device *device); + +/** + * @ingroup config + * + * Return the default setting for whether tapping is enabled on this device. + * + * @param device The device to configure + * @return 1 if tapping is enabled by default, or 0 otherwise + * + * @see libinput_device_config_tap_get_finger_count + * @see libinput_device_config_tap_set_enabled + * @see libinput_device_config_tap_get_enabled + */ +int +libinput_device_config_tap_get_default_enabled(struct libinput_device *device); + #ifdef __cplusplus } #endif - #endif /* LIBINPUT_H */ From 2219c12c3aa45b80f235e761e87c17fb9ec70eae Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 4 Feb 2014 10:38:21 +1000 Subject: [PATCH 18/50] touchpad: hook up to the tapping configuration Now that we have run-time changes of the tap.enabled state move the check to the IDLE state only. Otherwise the tap machine may hang if tapping is disabled while a gesture is in progress. Two basic tests are added to check for the tap default setting - which is now "tap disabled by default", for two reasons: * if you don't know that tapping is a thing (or enabled by default), you get spurious button events that make the desktop feel buggy. * if you do know what tapping is and you want it, you usually know where to enable it, or at least you can search for it. Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad-tap.c | 67 ++++++++++++++++++++++++++++++++++--- src/evdev-mt-touchpad.h | 1 + test/touchpad.c | 54 ++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 5 deletions(-) diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index 8a129634..0f1f837d 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -467,13 +467,13 @@ tp_tap_handle_event(struct tp_dispatch *tp, struct libinput *libinput = tp->device->base.seat->libinput; enum tp_tap_state current; - if (!tp->tap.enabled) - return; - current = tp->tap.state; switch(tp->tap.state) { case TAP_STATE_IDLE: + if (!tp->tap.enabled) + break; + tp_tap_idle_handle_event(tp, t, event, time); break; case TAP_STATE_TOUCH: @@ -612,17 +612,74 @@ tp_tap_handle_timeout(uint64_t time, void *data) } } +static int +tp_tap_config_count(struct libinput_device *device) +{ + struct evdev_dispatch *dispatch; + struct tp_dispatch *tp; + + dispatch = ((struct evdev_device *) device)->dispatch; + tp = container_of(dispatch, tp, base); + + return min(tp->ntouches, 3); /* we only do up to 3 finger tap */ +} + +static enum libinput_config_status +tp_tap_config_set_enabled(struct libinput_device *device, int enabled) +{ + struct evdev_dispatch *dispatch; + struct tp_dispatch *tp; + + dispatch = ((struct evdev_device *) device)->dispatch; + tp = container_of(dispatch, tp, base); + + tp->tap.enabled = enabled; + + return LIBINPUT_CONFIG_STATUS_SUCCESS; +} + +static int +tp_tap_config_is_enabled(struct libinput_device *device) +{ + struct evdev_dispatch *dispatch; + struct tp_dispatch *tp; + + dispatch = ((struct evdev_device *) device)->dispatch; + tp = container_of(dispatch, tp, base); + + return tp->tap.enabled; +} + +static int +tp_tap_config_get_default(struct libinput_device *device) +{ + /** + * Tapping is disabled by default for two reasons: + * * if you don't know that tapping is a thing (or enabled by + * default), you get spurious mouse events that make the desktop + * feel buggy. + * * if you do know what tapping is and you want it, you + * usually know where to enable it, or at least you can search for + * it. + */ + return false; +} + int tp_init_tap(struct tp_dispatch *tp) { + tp->tap.config.count = tp_tap_config_count; + tp->tap.config.set_enabled = tp_tap_config_set_enabled; + tp->tap.config.get_enabled = tp_tap_config_is_enabled; + tp->tap.config.get_default = tp_tap_config_get_default; + tp->device->base.config.tap = &tp->tap.config; + tp->tap.state = TAP_STATE_IDLE; libinput_timer_init(&tp->tap.timer, tp->device->base.seat->libinput, tp_tap_handle_timeout, tp); - tp->tap.enabled = 1; /* FIXME */ - return 0; } diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 6fb9ca4d..c92c2b10 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -199,6 +199,7 @@ struct tp_dispatch { enum touchpad_event queued; struct { + struct libinput_device_config_tap config; bool enabled; struct libinput_timer timer; enum tp_tap_state state; diff --git a/test/touchpad.c b/test/touchpad.c index d7625e92..6a33a440 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -116,6 +116,8 @@ START_TEST(touchpad_1fg_tap) struct libinput *li = dev->libinput; struct libinput_event *event; + libinput_device_config_tap_set_enabled(dev->libinput_device, 1); + litest_drain_events(li); litest_touch_down(dev, 0, 50, 50); @@ -141,6 +143,8 @@ START_TEST(touchpad_1fg_tap_n_drag) struct libinput *li = dev->libinput; struct libinput_event *event; + libinput_device_config_tap_set_enabled(dev->libinput_device, 1); + litest_drain_events(li); litest_touch_down(dev, 0, 50, 50); @@ -191,6 +195,8 @@ START_TEST(touchpad_2fg_tap) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + libinput_device_config_tap_set_enabled(dev->libinput_device, 1); + litest_drain_events(dev->libinput); litest_touch_down(dev, 0, 50, 50); @@ -215,6 +221,8 @@ START_TEST(touchpad_2fg_tap_inverted) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + libinput_device_config_tap_set_enabled(dev->libinput_device, 1); + litest_drain_events(dev->libinput); litest_touch_down(dev, 0, 50, 50); @@ -239,6 +247,8 @@ START_TEST(touchpad_1fg_tap_click) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + libinput_device_config_tap_set_enabled(dev->libinput_device, 1); + litest_drain_events(dev->libinput); /* finger down, button click, finger up @@ -266,6 +276,8 @@ START_TEST(touchpad_2fg_tap_click) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + libinput_device_config_tap_set_enabled(dev->libinput_device, 1); + litest_drain_events(dev->libinput); /* two fingers down, button click, fingers up @@ -295,6 +307,8 @@ START_TEST(touchpad_2fg_tap_click_apple) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + libinput_device_config_tap_set_enabled(dev->libinput_device, 1); + litest_drain_events(dev->libinput); /* two fingers down, button click, fingers up @@ -401,6 +415,8 @@ START_TEST(touchpad_1fg_double_tap_click) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + libinput_device_config_tap_set_enabled(dev->libinput_device, 1); + litest_drain_events(dev->libinput); /* one finger down, up, down, button click, finger up @@ -435,6 +451,8 @@ START_TEST(touchpad_1fg_tap_n_drag_click) struct libinput *li = dev->libinput; struct libinput_event *event; + libinput_device_config_tap_set_enabled(dev->libinput_device, 1); + litest_drain_events(dev->libinput); /* one finger down, up, down, move, button click, finger up @@ -675,6 +693,8 @@ START_TEST(clickpad_softbutton_left_tap_n_drag) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + libinput_device_config_tap_set_enabled(dev->libinput_device, 1); + litest_drain_events(li); /* Tap in left button area, then finger down, button click @@ -715,6 +735,8 @@ START_TEST(clickpad_softbutton_right_tap_n_drag) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + libinput_device_config_tap_set_enabled(dev->libinput_device, 1); + litest_drain_events(li); /* Tap in right button area, then finger down, button click @@ -1191,6 +1213,34 @@ START_TEST(touchpad_2fg_scroll) } END_TEST +START_TEST(touchpad_tap_is_available) +{ + struct litest_device *dev = litest_current_device(); + + ck_assert_int_ge(libinput_device_config_tap_get_finger_count(dev->libinput_device), 1); + ck_assert_int_eq(libinput_device_config_tap_get_enabled(dev->libinput_device), 0); +} +END_TEST + +START_TEST(touchpad_tap_is_not_available) +{ + struct litest_device *dev = litest_current_device(); + + ck_assert_int_eq(libinput_device_config_tap_get_finger_count(dev->libinput_device), 0); + ck_assert_int_eq(libinput_device_config_tap_get_enabled(dev->libinput_device), 0); + ck_assert_int_eq(libinput_device_config_tap_set_enabled(dev->libinput_device, 1), + LIBINPUT_CONFIG_STATUS_UNSUPPORTED); +} +END_TEST + +START_TEST(touchpad_tap_default) +{ + struct litest_device *dev = litest_current_device(); + + ck_assert_int_eq(libinput_device_config_tap_get_default_enabled(dev->libinput_device), 0); +} +END_TEST + int main(int argc, char **argv) { litest_add("touchpad:motion", touchpad_1fg_motion, LITEST_TOUCHPAD, LITEST_ANY); @@ -1213,6 +1263,10 @@ int main(int argc, char **argv) { litest_add("touchpad:tap", touchpad_1fg_double_tap_click, LITEST_CLICKPAD, LITEST_ANY); litest_add("touchpad:tap", touchpad_1fg_tap_n_drag_click, LITEST_CLICKPAD, LITEST_ANY); + litest_add("touchpad:tap", touchpad_tap_default, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:tap", touchpad_tap_is_available, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:tap", touchpad_tap_is_not_available, LITEST_ANY, LITEST_TOUCHPAD); + litest_add_no_device("touchpad:clickfinger", touchpad_1fg_clickfinger); litest_add_no_device("touchpad:clickfinger", touchpad_2fg_clickfinger); From ebc087fbf616171190caf3c80d1da13873cf138b Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 2 Jul 2014 15:41:22 +1000 Subject: [PATCH 19/50] touchpad: reduce button size, use physical sizes where possible The current 20% is excessive. On the t440s, the button size amounts to ~14mm from the bottom. On the x220 it amounts to ~9mm, leaving only 31mm as actual touchpad. Reduce it to 15% instead, which amounts to 10.5mm on the t440 and 6mm on the x220. Cap the button height further by making buttons a maximum height of 10mm, anything larger than that is excessive anyway. Smaller buttons should be acceptable since we can rely on the bottom edge to be a haptic feedback and thus a good hit-target, somewhat simliar to how screen edges are good hit-targets. The top software buttons stay the same size, but prefer a physical size of 6mm instead (which is 1mm below the button marker line on the T440s). If no y resolution is available, fall back to the 8% which is 5.6mm on the T440s. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad-buttons.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index b84198ce..9848a32a 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -605,11 +605,28 @@ tp_init_buttons(struct tp_dispatch *tp, if (tp->buttons.is_clickpad && !tp->buttons.use_clickfinger) { int xoffset = absinfo_x->minimum, yoffset = absinfo_y->minimum; - tp->buttons.bottom_area.top_edge = height * .8 + yoffset; + int yres = absinfo_y->resolution; + + /* button height: 10mm or 15% of the touchpad height, + whichever is smaller */ + if (yres > 1 && (height * 0.15/yres) > 10) { + tp->buttons.bottom_area.top_edge = + absinfo_y->maximum - 10 * yres; + } else { + tp->buttons.bottom_area.top_edge = height * .85 + yoffset; + } + tp->buttons.bottom_area.rightbutton_left_edge = width/2 + xoffset; if (tp->buttons.has_topbuttons) { - tp->buttons.top_area.bottom_edge = height * .08 + yoffset; + /* T440s has the top button line 5mm from the top, + make the buttons 6mm high */ + if (yres > 1) { + tp->buttons.top_area.bottom_edge = + yoffset + 6 * yres; + } else { + tp->buttons.top_area.bottom_edge = height * .08 + yoffset; + } tp->buttons.top_area.rightbutton_left_edge = width * .58 + xoffset; tp->buttons.top_area.leftbutton_right_edge = width * .42 + xoffset; } else { From 280755a7c843625626ec1e4ccac42f879fe36ab2 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 2 Jul 2014 15:00:31 +1000 Subject: [PATCH 20/50] touchpad: drop the BOTTOM_TO_AREA/BOTTOM_NEW states The original intention of this state was to prevent an accidental move out of the bottom software button to start moving the cursor. That ends up actually preventing a number of normal moves that start low enough. Simply drop the state. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- doc/touchpad-softbutton-state-machine.svg | 888 +++++++++------------- src/evdev-mt-touchpad-buttons.c | 86 +-- src/evdev-mt-touchpad.h | 2 - 3 files changed, 362 insertions(+), 614 deletions(-) diff --git a/doc/touchpad-softbutton-state-machine.svg b/doc/touchpad-softbutton-state-machine.svg index 05254d0e..1d569bf6 100644 --- a/doc/touchpad-softbutton-state-machine.svg +++ b/doc/touchpad-softbutton-state-machine.svg @@ -1,532 +1,360 @@ + - - - - - - - -NONE - -on-entry: - -curr = none - - - - -BOTTOM_NEW - -on-entry: - -curr = button - -start enter timeout - - - - -AREA - -on-entry: - -curr =area - -set_pointer() - - - - -finger in - -area or top - - - - -BOTTOM - - - - -finger - -up - - - - -phys - -button - -press - - - - - - -enter - -timeout - - - - - - - - -finger in - -area or top - - - - - - -BOTTOM_TO_AREA - -on-entry: - -start leave timeout - - - - - - -leave - -timeout - - - - - - - - -finger in - -bottom - - - - - - - - -finger in - -area - - - - - - - - -finger in - -bottom - -button != curr - - - - - - - - - - - - -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 middle) || - -((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) - - - - - - - - - - -finger in - -top - - - - - - - -TOP_NEW - -on-entry: - -curr = button - -start enter timeout - - - - - - - -TOP - - - - - -phys - -button - -press - - - - -enter - -timeout - - - - -finger in - -top - -button != curr - - - - - - - - - - - - - - - - - - -finger in - -area or - -bottom - - - - - - - - -TOP_TO_IGNORE - -on-entry: - -start leave timeout - - - - -finger in - -area or bottom - - - - -finger in - -top - -button == curr - - - - - - - - - - - - - - -IGNORE - -on-entry: - -curr =none - - - - -leave - -timeout - - - - - - - - - - + + + + + + + NONE + on-entry: + curr = none + + + + BOTTOM + on-entry: + curr = button + + + + AREA + on-entry: + curr =area + set_pointer() + + + + finger in + area or top + + + + finger + up + + + + + + finger in + bottom + + + + + + + + finger in + area + + + + + + + + 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 middle) || + ((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) + + + + + + + + + + finger in + top + + + + + + TOP_NEW + on-entry: + curr = button + start enter timeout + + + + + + + TOP + + + + + phys + button + press + + + + enter + timeout + + + + finger in + top + button != curr + + + + + + + + + + + + + + + + + + finger in + area or + bottom + + + + + + + + TOP_TO_IGNORE + on-entry: + start leave timeout + + + + finger in + area or bottom + + + + finger in + top + button == curr + + + + + + + + + + + + + + IGNORE + on-entry: + curr =none + + + + leave + timeout + + + + + + + + + + diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 9848a32a..520a47f1 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -52,8 +52,6 @@ button_state_to_str(enum button_state 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); CASE_RETURN_STRING(BUTTON_STATE_TOP); CASE_RETURN_STRING(BUTTON_STATE_TOP_NEW); CASE_RETURN_STRING(BUTTON_STATE_TOP_TO_IGNORE); @@ -161,13 +159,7 @@ tp_button_set_state(struct tp_dispatch *tp, struct tp_touch *t, tp_set_pointer(tp, t); 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; case BUTTON_STATE_TOP: break; @@ -192,7 +184,7 @@ tp_button_none_handle_event(struct tp_dispatch *tp, 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); + tp_button_set_state(tp, t, BUTTON_STATE_BOTTOM, event); break; case BUTTON_EVENT_IN_TOP_R: case BUTTON_EVENT_IN_TOP_M: @@ -237,92 +229,28 @@ tp_button_area_handle_event(struct tp_dispatch *tp, static void tp_button_bottom_handle_event(struct tp_dispatch *tp, - struct tp_touch *t, - enum button_event event) + 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_TOP_R: - case BUTTON_EVENT_IN_TOP_M: - case BUTTON_EVENT_IN_TOP_L: - 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_TOP_R: - case BUTTON_EVENT_IN_TOP_M: - case BUTTON_EVENT_IN_TOP_L: - 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_TOP_R: case BUTTON_EVENT_IN_TOP_M: case BUTTON_EVENT_IN_TOP_L: 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: - break; case BUTTON_EVENT_TIMEOUT: - tp_button_set_state(tp, t, BUTTON_STATE_AREA, event); break; } } @@ -465,12 +393,6 @@ tp_button_handle_event(struct tp_dispatch *tp, 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; case BUTTON_STATE_TOP: tp_button_top_handle_event(tp, t, event); break; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index c92c2b10..80f3f606 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -64,8 +64,6 @@ enum button_state { BUTTON_STATE_NONE, BUTTON_STATE_AREA, BUTTON_STATE_BOTTOM, - BUTTON_STATE_BOTTOM_NEW, - BUTTON_STATE_BOTTOM_TO_AREA, BUTTON_STATE_TOP, BUTTON_STATE_TOP_NEW, BUTTON_STATE_TOP_TO_IGNORE, From d03488f4a332ef6f88e8d22baec6b6e3cdb0bb9b Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 4 Jul 2014 07:55:51 +1000 Subject: [PATCH 21/50] test: prefix custom test devices with "litest" Follow-up from 6c4778f891a77e06c0fccbfad1a1bfd4f64f86f3 Signed-off-by: Peter Hutterer --- test/keyboard.c | 2 +- test/misc.c | 10 +++++----- test/pointer.c | 2 +- test/touch.c | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/keyboard.c b/test/keyboard.c index bf5d55af..a55405cb 100644 --- a/test/keyboard.c +++ b/test/keyboard.c @@ -41,7 +41,7 @@ START_TEST(keyboard_seat_key_count) libinput = litest_create_context(); for (i = 0; i < num_devices; ++i) { - sprintf(device_name, "Generic keyboard (%d)", i); + sprintf(device_name, "litest Generic keyboard (%d)", i); devices[i] = litest_add_device_with_overrides(libinput, LITEST_KEYBOARD, device_name, diff --git a/test/misc.c b/test/misc.c index 7e028321..983c3f9b 100644 --- a/test/misc.c +++ b/test/misc.c @@ -95,7 +95,7 @@ START_TEST(event_conversion_device_notify) struct libinput_event *event; int device_added = 0, device_removed = 0; - uinput = create_simple_test_device("test device", + uinput = create_simple_test_device("litest test device", EV_REL, REL_X, EV_REL, REL_Y, EV_KEY, BTN_LEFT, @@ -149,7 +149,7 @@ START_TEST(event_conversion_pointer) struct libinput_event *event; int motion = 0, button = 0; - uinput = create_simple_test_device("test device", + uinput = create_simple_test_device("litest test device", EV_REL, REL_X, EV_REL, REL_Y, EV_KEY, BTN_LEFT, @@ -210,7 +210,7 @@ START_TEST(event_conversion_pointer_abs) struct libinput_event *event; int motion = 0, button = 0; - uinput = create_simple_test_device("test device", + uinput = create_simple_test_device("litest test device", EV_ABS, ABS_X, EV_ABS, ABS_Y, EV_KEY, BTN_LEFT, @@ -270,7 +270,7 @@ START_TEST(event_conversion_key) struct libinput_event *event; int key = 0; - uinput = create_simple_test_device("test device", + uinput = create_simple_test_device("litest test device", EV_KEY, KEY_A, EV_KEY, KEY_B, -1, -1); @@ -319,7 +319,7 @@ START_TEST(event_conversion_touch) struct libinput_event *event; int touch = 0; - uinput = create_simple_test_device("test device", + uinput = create_simple_test_device("litest test device", EV_KEY, BTN_TOUCH, EV_ABS, ABS_X, EV_ABS, ABS_Y, diff --git a/test/pointer.c b/test/pointer.c index 8f1ab1fe..3db0165b 100644 --- a/test/pointer.c +++ b/test/pointer.c @@ -223,7 +223,7 @@ START_TEST(pointer_seat_button_count) libinput = litest_create_context(); for (i = 0; i < num_devices; ++i) { - sprintf(device_name, "Generic mouse (%d)", i); + sprintf(device_name, "litest Generic mouse (%d)", i); devices[i] = litest_add_device_with_overrides(libinput, LITEST_MOUSE, device_name, diff --git a/test/touch.c b/test/touch.c index 2a7c966a..5d704c53 100644 --- a/test/touch.c +++ b/test/touch.c @@ -80,7 +80,7 @@ START_TEST(touch_abs_transform) }; dev = litest_create_device_with_overrides(LITEST_WACOM_TOUCH, - "Highres touch device", + "litest Highres touch device", NULL, abs, NULL); libinput = dev->libinput; @@ -129,7 +129,7 @@ START_TEST(touch_many_slots) }; dev = litest_create_device_with_overrides(LITEST_WACOM_TOUCH, - "Multi-touch device", + "litest Multi-touch device", NULL, abs, NULL); libinput = dev->libinput; From 03a1ef7540139d11420d4b8398236501bd3e6007 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 4 Jul 2014 09:39:05 +1000 Subject: [PATCH 22/50] filter: rename motion_filter_destroy to filter_destroy For better consistency with filter_dispatch(). And move the things around to keep the consumable API together. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad.c | 2 +- src/evdev.c | 2 +- src/filter.c | 18 +++++++++--------- src/filter.h | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index fc2a5ab3..0b06810c 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -577,7 +577,7 @@ tp_destroy(struct evdev_dispatch *dispatch) tp_destroy_tap(tp); tp_destroy_buttons(tp); - motion_filter_destroy(tp->filter); + filter_destroy(tp->filter); free(tp->touches); free(tp); } diff --git a/src/evdev.c b/src/evdev.c index 183c2000..f980812b 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -943,7 +943,7 @@ evdev_device_destroy(struct evdev_device *device) if (dispatch) dispatch->interface->destroy(dispatch); - motion_filter_destroy(device->pointer.filter); + filter_destroy(device->pointer.filter); libinput_seat_unref(device->base.seat); libevdev_free(device->evdev); free(device->mt.slots); diff --git a/src/filter.c b/src/filter.c index 3221d193..51cc0e92 100644 --- a/src/filter.c +++ b/src/filter.c @@ -38,6 +38,15 @@ filter_dispatch(struct motion_filter *filter, filter->interface->filter(filter, motion, data, time); } +void +filter_destroy(struct motion_filter *filter) +{ + if (!filter) + return; + + filter->interface->destroy(filter); +} + /* * Default parameters for pointer acceleration profiles. */ @@ -332,15 +341,6 @@ create_pointer_accelator_filter(accel_profile_func_t profile) return &filter->base; } -void -motion_filter_destroy(struct motion_filter *filter) -{ - if (!filter) - return; - - filter->interface->destroy(filter); -} - static inline double calc_penumbral_gradient(double x) { diff --git a/src/filter.h b/src/filter.h index c0219eeb..e670e1b2 100644 --- a/src/filter.h +++ b/src/filter.h @@ -35,6 +35,8 @@ void filter_dispatch(struct motion_filter *filter, struct motion_params *motion, void *data, uint64_t time); +void +filter_destroy(struct motion_filter *filter); struct motion_filter_interface { @@ -59,8 +61,6 @@ typedef double (*accel_profile_func_t)(struct motion_filter *filter, struct motion_filter * create_pointer_accelator_filter(accel_profile_func_t filter); -void -motion_filter_destroy(struct motion_filter *filter); /* * Pointer acceleration profiles. From e4d50a73a1e963bdcc9ca63dd1a760eb9d777d1f Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 8 Jul 2014 08:52:40 +1000 Subject: [PATCH 23/50] test: fix expected delta from relative motion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We send two delta events. One may get eaten or softened by the accel code but our expectation should be that both may get through, so the length of the expected vector is √((2dx)² + (2dy)²). That is the maximum length we expect though for deltas ranged [-1, 1]. Deltas above the threshold would fail this test but we can fix that when needed. Pointer acceleration is subject to timing changes. When running tests in valgrind pointer accel timeouts and tracker resets may happen so we can't guarantee a specific acceleration length. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- test/pointer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/pointer.c b/test/pointer.c index 3db0165b..aa75274b 100644 --- a/test/pointer.c +++ b/test/pointer.c @@ -63,7 +63,7 @@ test_relative_event(struct litest_device *dev, int dx, int dy) ptrev = libinput_event_get_pointer_event(event); ck_assert(ptrev != NULL); - expected_length = sqrt(dx*dx + dy*dy); + expected_length = sqrt(4 * dx*dx + 4 * dy*dy); expected_dir = atan2(dx, dy); ev_dx = libinput_event_pointer_get_dx(ptrev); @@ -72,7 +72,7 @@ test_relative_event(struct litest_device *dev, int dx, int dy) actual_dir = atan2(ev_dx, ev_dy); /* Check the length of the motion vector (tolerate 1.0 indifference). */ - ck_assert(fabs(expected_length - actual_length) < 1.0); + ck_assert(fabs(expected_length) >= actual_length); /* Check the direction of the motion vector (tolerate 2π/4 radians * indifference). */ From f2dfbc0b826db5e451bc25cae44b07e3b9c827f1 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 4 Jul 2014 12:52:04 +1000 Subject: [PATCH 24/50] filter: drop delta-softening MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I doubt this does what we think it does. It doesn't soften the delta changes, rather it introduces bumps in the smooth processing of the changes. abs(delta) below 1.0 is untouched, and abs(delta) beyond 3 or 4 isn't noticable much. But in the slow range around the 1/-1 mark there is a bump. For example, if our last_delta is 1.0 and delta is 1.1, the "softened" delta is set to 0.6. That is stored as last delta, so an input sequence of: 0.8, 0.9, 1.0, 1.1, 1.2, 1.0, 0.8, 1.1 results in "softened" deltas that don't match the input: 0.8, 0.9, 1.0, 0.6, 0.7, 1.0, 0.8, 0.6 A better approach at smoothing this out would be to calculate the softened as: current = current ± diff(last, current) * 0.5 or even weighted towards the new delta current = current ± diff(last, current) * 0.25 In tests, this makes little difference. Dropping this function altogether is sufficient to make the pointer pointer behave slightly better at low speeds though the increase is small enough to attribute to confirmation bias. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/filter.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/filter.c b/src/filter.c index 51cc0e92..1762f98a 100644 --- a/src/filter.c +++ b/src/filter.c @@ -257,27 +257,6 @@ calculate_acceleration(struct pointer_accelerator *accel, return factor; } -static double -soften_delta(double last_delta, double delta) -{ - if (delta < -1.0 || delta > 1.0) { - if (delta > last_delta) - return delta - 0.5; - else if (delta < last_delta) - return delta + 0.5; - } - - return delta; -} - -static void -apply_softening(struct pointer_accelerator *accel, - struct motion_params *motion) -{ - motion->dx = soften_delta(accel->last_dx, motion->dx); - motion->dy = soften_delta(accel->last_dy, motion->dy); -} - static void accelerator_filter(struct motion_filter *filter, struct motion_params *motion, @@ -295,8 +274,6 @@ accelerator_filter(struct motion_filter *filter, motion->dx = accel_value * motion->dx; motion->dy = accel_value * motion->dy; - apply_softening(accel, motion); - accel->last_dx = motion->dx; accel->last_dy = motion->dy; From 4da6dd52a433e8ba0a954a0e36bc653cf86651bd Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 4 Jul 2014 17:16:25 +0200 Subject: [PATCH 25/50] accel_profile_smooth_simple: Cleanup Cleanup the code a bit, and make sure accel is at least 1.0 . Signed-off-by: Hans de Goede Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- src/filter.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/filter.c b/src/filter.c index 1762f98a..487669c5 100644 --- a/src/filter.c +++ b/src/filter.c @@ -336,20 +336,23 @@ pointer_accel_profile_smooth_simple(struct motion_filter *filter, double accel = DEFAULT_ACCELERATION; double smooth_accel_coefficient; + if (threshold < 1.0) + threshold = 1.0; + if (accel < 1.0) + accel = 1.0; + velocity *= DEFAULT_CONSTANT_ACCELERATION; if (velocity < 1.0) return calc_penumbral_gradient(0.5 + velocity * 0.5) * 2.0 - 1.0; - if (threshold < 1.0) - threshold = 1.0; + if (velocity <= threshold) - return 1; + return 1.0; + velocity /= threshold; - if (velocity >= accel) { + if (velocity >= accel) return accel; - } else { - smooth_accel_coefficient = - calc_penumbral_gradient(velocity / accel); - return 1.0 + (smooth_accel_coefficient * (accel - 1.0)); - } + + smooth_accel_coefficient = calc_penumbral_gradient(velocity / accel); + return 1.0 + (smooth_accel_coefficient * (accel - 1.0)); } From 6e8f5f28e230f849f77dd3381cf21f76c080b261 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 4 Jul 2014 17:17:14 +0200 Subject: [PATCH 26/50] accel_profile_smooth_simple: Fix jump in acceleration curve There was an error in the value passed to the second calc_penumbral_gradient call causing a jump in the acceleration curve. This commit fixes this. Signed-off-by: Hans de Goede Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- src/filter.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/filter.c b/src/filter.c index 487669c5..8192dd0c 100644 --- a/src/filter.c +++ b/src/filter.c @@ -353,6 +353,8 @@ pointer_accel_profile_smooth_simple(struct motion_filter *filter, if (velocity >= accel) return accel; - smooth_accel_coefficient = calc_penumbral_gradient(velocity / accel); + /* Velocity is between 1.0 and accel, scale this to 0.0 - 1.0 */ + velocity = (velocity - 1.0) / (accel - 1.0); + smooth_accel_coefficient = calc_penumbral_gradient(velocity); return 1.0 + (smooth_accel_coefficient * (accel - 1.0)); } From 289949d0c43e4753ecc77ee05ee2092c893f7941 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 4 Jul 2014 16:59:50 +0200 Subject: [PATCH 27/50] accel_profile_smooth_simple: Make 0.0-1.0 accel range depend on threshold Instead of always going from an accel of 0.0 to 1.0 between a velocity of 0.0 and 1.0, make the lead-in length of the curve depend on the threshold setting, using half of the threshold for the lead-in. Signed-off-by: Hans de Goede Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- src/filter.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/filter.c b/src/filter.c index 8192dd0c..6fbd4d91 100644 --- a/src/filter.c +++ b/src/filter.c @@ -343,8 +343,8 @@ pointer_accel_profile_smooth_simple(struct motion_filter *filter, velocity *= DEFAULT_CONSTANT_ACCELERATION; - if (velocity < 1.0) - return calc_penumbral_gradient(0.5 + velocity * 0.5) * 2.0 - 1.0; + if (velocity < (threshold / 2.0)) + return calc_penumbral_gradient(0.5 + velocity / threshold) * 2.0 - 1.0; if (velocity <= threshold) return 1.0; From 066092a04fd2a9419c392575cd1675d91c550d8c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 8 Jul 2014 11:45:36 +1000 Subject: [PATCH 28/50] filter: annotate the various variables we have with units Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/filter.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/filter.c b/src/filter.c index 6fbd4d91..7db78bae 100644 --- a/src/filter.c +++ b/src/filter.c @@ -51,22 +51,22 @@ filter_destroy(struct motion_filter *filter) * Default parameters for pointer acceleration profiles. */ -#define DEFAULT_CONSTANT_ACCELERATION 10.0 -#define DEFAULT_THRESHOLD 4.0 -#define DEFAULT_ACCELERATION 2.0 +#define DEFAULT_CONSTANT_ACCELERATION 10.0 /* unitless factor */ +#define DEFAULT_THRESHOLD 4.0 /* in units/ms */ +#define DEFAULT_ACCELERATION 2.0 /* unitless factor */ /* * Pointer acceleration filter constants */ -#define MAX_VELOCITY_DIFF 1.0 +#define MAX_VELOCITY_DIFF 1.0 /* units/ms */ #define MOTION_TIMEOUT 300 /* (ms) */ #define NUM_POINTER_TRACKERS 16 struct pointer_tracker { - double dx; - double dy; - uint64_t time; + double dx; /* delta to most recent event, in device units */ + double dy; /* delta to most recent event, in device units */ + uint64_t time; /* ms */ int dir; }; @@ -76,10 +76,10 @@ struct pointer_accelerator { accel_profile_func_t profile; - double velocity; - double last_velocity; - int last_dx; - int last_dy; + double velocity; /* units/ms */ + double last_velocity; /* units/ms */ + int last_dx; /* device units */ + int last_dy; /* device units */ struct pointer_tracker *trackers; int cur_tracker; @@ -183,7 +183,7 @@ calculate_tracker_velocity(struct pointer_tracker *tracker, uint64_t time) dx = tracker->dx; dy = tracker->dy; distance = sqrt(dx*dx + dy*dy); - return distance / (double)(time - tracker->time); + return distance / (double)(time - tracker->time); /* units/ms */ } static double @@ -227,7 +227,7 @@ calculate_velocity(struct pointer_accelerator *accel, uint64_t time) } } - return result; + return result; /* units/ms */ } static double @@ -254,7 +254,7 @@ calculate_acceleration(struct pointer_accelerator *accel, factor = factor / 6.0; - return factor; + return factor; /* unitless factor */ } static void @@ -264,8 +264,8 @@ accelerator_filter(struct motion_filter *filter, { struct pointer_accelerator *accel = (struct pointer_accelerator *) filter; - double velocity; - double accel_value; + double velocity; /* units/ms */ + double accel_value; /* unitless factor */ feed_trackers(accel, motion->dx, motion->dy, time); velocity = calculate_velocity(accel, time); @@ -329,12 +329,12 @@ calc_penumbral_gradient(double x) double pointer_accel_profile_smooth_simple(struct motion_filter *filter, void *data, - double velocity, + double velocity, /* units/ms */ uint64_t time) { - double threshold = DEFAULT_THRESHOLD; - double accel = DEFAULT_ACCELERATION; - double smooth_accel_coefficient; + double threshold = DEFAULT_THRESHOLD; /* units/ms */ + double accel = DEFAULT_ACCELERATION; /* unitless factor */ + double smooth_accel_coefficient; /* unitless factor */ if (threshold < 1.0) threshold = 1.0; From b908e070e9a81e5ab6fa7840ce085a330a2c7eac Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 8 Jul 2014 12:05:36 +1000 Subject: [PATCH 29/50] filter: use a separate variable for the final accel factor velocity is in unit/ms, the threshold is in units/ms. Once we divide velocity/threshold, we're not in units/ms anymore but have a unitless factor. Use a separate variable to avoid confusion. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/filter.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/filter.c b/src/filter.c index 7db78bae..4b2bbadd 100644 --- a/src/filter.c +++ b/src/filter.c @@ -335,6 +335,7 @@ pointer_accel_profile_smooth_simple(struct motion_filter *filter, double threshold = DEFAULT_THRESHOLD; /* units/ms */ double accel = DEFAULT_ACCELERATION; /* unitless factor */ double smooth_accel_coefficient; /* unitless factor */ + double factor; /* unitless factor */ if (threshold < 1.0) threshold = 1.0; @@ -349,12 +350,12 @@ pointer_accel_profile_smooth_simple(struct motion_filter *filter, if (velocity <= threshold) return 1.0; - velocity /= threshold; - if (velocity >= accel) + factor = velocity/threshold; + if (factor >= accel) return accel; - /* Velocity is between 1.0 and accel, scale this to 0.0 - 1.0 */ - velocity = (velocity - 1.0) / (accel - 1.0); - smooth_accel_coefficient = calc_penumbral_gradient(velocity); + /* factor is between 1.0 and accel, scale this to 0.0 - 1.0 */ + factor = (factor - 1.0) / (accel - 1.0); + smooth_accel_coefficient = calc_penumbral_gradient(factor); return 1.0 + (smooth_accel_coefficient * (accel - 1.0)); } From 14ba84cdca6776772e50efd3753ac01080317669 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 8 Jul 2014 12:09:20 +1000 Subject: [PATCH 30/50] filter: drop constant acceleration This just moves a decimal point around, at the expense of making the approach harder to understand. The only time the const acceleration matters is when applied to the velocity but it only matters in relation to the threshold which is a fixed number. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/filter.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/filter.c b/src/filter.c index 4b2bbadd..5b0b8774 100644 --- a/src/filter.c +++ b/src/filter.c @@ -51,8 +51,7 @@ filter_destroy(struct motion_filter *filter) * Default parameters for pointer acceleration profiles. */ -#define DEFAULT_CONSTANT_ACCELERATION 10.0 /* unitless factor */ -#define DEFAULT_THRESHOLD 4.0 /* in units/ms */ +#define DEFAULT_THRESHOLD 0.4 /* in units/ms */ #define DEFAULT_ACCELERATION 2.0 /* unitless factor */ /* @@ -337,12 +336,11 @@ pointer_accel_profile_smooth_simple(struct motion_filter *filter, double smooth_accel_coefficient; /* unitless factor */ double factor; /* unitless factor */ - if (threshold < 1.0) - threshold = 1.0; + if (threshold < 0.1) + threshold = 0.1; if (accel < 1.0) accel = 1.0; - velocity *= DEFAULT_CONSTANT_ACCELERATION; if (velocity < (threshold / 2.0)) return calc_penumbral_gradient(0.5 + velocity / threshold) * 2.0 - 1.0; From 468e6288082ee61ac6a4663726a2728e413804e1 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 8 Jul 2014 13:02:31 +1000 Subject: [PATCH 31/50] touchpad: don't feed 0/0 deltas into the accel filters The resolution-based scaling may result in deltas of 0. The accel code doesn't handle 0 deltas too well. 0/0 deltas can't happen for EV_REL devices, so the code just isn't designed for it. Most notably, events with delta 0/0 have no direction. That messes up the history-based velocity calculation which stops whenever the current vector's direction changes from the one in the trackers. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 0b06810c..4f4633d7 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -63,7 +63,8 @@ tp_filter_motion(struct tp_dispatch *tp, motion.dx = *dx * tp->accel.x_scale_coeff; motion.dy = *dy * tp->accel.y_scale_coeff; - filter_dispatch(tp->filter, &motion, tp, time); + if (motion.dx != 0.0 || motion.dy != 0.0) + filter_dispatch(tp->filter, &motion, tp, time); *dx = motion.dx; *dy = motion.dy; From e874d09b49d34f4e67b7815cd3632f902c281432 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 8 Jul 2014 13:43:45 +1000 Subject: [PATCH 32/50] touchpad: normalize the touchpad resolution to 400dpi, not 10 units/mm In an attempt to bring method into the madness, normalize the touchpad deltas to those of a USB mouse with 400 dpi. This way the data we're dealing with in the acceleration code is of a known quantity. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad.c | 15 +++++++++------ src/filter.c | 9 ++++++++- src/filter.h | 2 +- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 4f4633d7..fed39b4e 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -663,14 +663,17 @@ tp_init_accel(struct tp_dispatch *tp, double diagonal) /* * Not all touchpads report the same amount of units/mm (resolution). - * Normalize motion events to a resolution of 10 units/mm as base - * (unaccelerated) speed. This also evens out any differences in x - * and y resolution, so that a circle on the touchpad does not turn - * into an elipse on the screen. + * Normalize motion events to a resolution of 15.74 units/mm + * (== 400 dpi) as base (unaccelerated) speed. This also evens out any + * differences in x and y resolution, so that a circle on the + * touchpad does not turn into an elipse on the screen. + * + * We pick 400dpi as thats one of the many default resolutions + * for USB mice, so we end up with a similar base speed on the device. */ if (res_x > 1 && res_y > 1) { - tp->accel.x_scale_coeff = 10.0 / res_x; - tp->accel.y_scale_coeff = 10.0 / res_y; + tp->accel.x_scale_coeff = (400/25.4) / res_x; + tp->accel.y_scale_coeff = (400/25.4) / res_y; } else { /* * For touchpads where the driver does not provide resolution, fall diff --git a/src/filter.c b/src/filter.c index 5b0b8774..e1fb2a96 100644 --- a/src/filter.c +++ b/src/filter.c @@ -341,7 +341,14 @@ pointer_accel_profile_smooth_simple(struct motion_filter *filter, if (accel < 1.0) accel = 1.0; - + /* We use units/ms as velocity but it has no real meaning unless all + devices have the same resolution. For touchpads, we normalize to + 400dpi (15.75 units/mm), but the resolution on USB mice is all + over the place. Though most mice these days have either 400 + dpi (15.75 units/mm), 800 dpi or 1000dpi, excluding gaming mice + that can usually adjust it on the fly anyway and currently go up + to 8200dpi. + */ if (velocity < (threshold / 2.0)) return calc_penumbral_gradient(0.5 + velocity / threshold) * 2.0 - 1.0; diff --git a/src/filter.h b/src/filter.h index e670e1b2..c0b27d0d 100644 --- a/src/filter.h +++ b/src/filter.h @@ -26,7 +26,7 @@ #include "config.h" struct motion_params { - double dx, dy; + double dx, dy; /* in units/ms @ 400dpi */ }; struct motion_filter; From dacc6383c71e57a5a4a71525116a42615cb56ea8 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Jul 2014 17:17:53 +1000 Subject: [PATCH 33/50] touchpad: fix coding style Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index fed39b4e..69b63e05 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -369,8 +369,9 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time) t->y = first->y; if (!t->dirty) t->dirty = first->dirty; - } else if (!t->dirty) + } else if (!t->dirty) { continue; + } tp_motion_hysteresis(tp, t); tp_motion_history_push(t); From a474a7648d0420dfee80bb9cf020e71cbd592da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 15 Jul 2014 23:25:28 +0200 Subject: [PATCH 34/50] configure.ac: Add subdir-objects to AM_INIT_AUTOMAKE paramaters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Silences a warning when running autogen.sh. This also adds a work-around for a bug in automake replacing $(top_srcdir) with ../ in test/Makefile.am. Signed-off-by: Jonas Ådahl --- configure.ac | 2 +- test/Makefile.am | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 65c915e6..fd402e20 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ AC_SUBST([LIBINPUT_VERSION], [libinput_version]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz]) +AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz subdir-objects]) # Before making a release, the LIBINPUT_LT_VERSION string should be # modified. diff --git a/test/Makefile.am b/test/Makefile.am index 16dac419..c3c293a0 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -11,8 +11,8 @@ AM_CXXFLAGS = $(GCC_CXXFLAGS) TEST_LIBS = liblitest.la $(CHECK_LIBS) $(LIBUDEV_LIBS) $(LIBEVDEV_LIBS) $(top_builddir)/src/libinput.la noinst_LTLIBRARIES = liblitest.la liblitest_la_SOURCES = \ - $(top_srcdir)/src/libinput-util.h \ - $(top_srcdir)/src/libinput-util.c \ + ../src/libinput-util.h \ + ../src/libinput-util.c \ litest.h \ litest-int.h \ litest-bcm5974.c \ From 85c4500494777a768a10cd4659ef2a6e91cb9258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 15 Jul 2014 21:53:26 +0200 Subject: [PATCH 35/50] event-debug: Silence compiler warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonas Ådahl --- tools/event-debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/event-debug.c b/tools/event-debug.c index 3eade366..fb22f3bd 100644 --- a/tools/event-debug.c +++ b/tools/event-debug.c @@ -199,7 +199,7 @@ static void print_event_header(struct libinput_event *ev) { struct libinput_device *dev = libinput_event_get_device(ev); - const char *type; + const char *type = NULL; switch(libinput_event_get_type(ev)) { case LIBINPUT_EVENT_NONE: @@ -428,7 +428,7 @@ handle_and_print_events(struct libinput *li) return rc; } -void +static void mainloop(struct libinput *li) { struct pollfd fds[2]; From 60ac2eb8130eb04e452f661c7aee68fe4d64caff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 14 Jul 2014 00:15:07 +0200 Subject: [PATCH 36/50] tools/event-gui: Silence a couple of compiler warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonas Ådahl --- tools/event-gui.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/event-gui.c b/tools/event-gui.c index 0aa91298..b4a65066 100644 --- a/tools/event-gui.c +++ b/tools/event-gui.c @@ -257,7 +257,7 @@ handle_event_touch(struct libinput_event *ev, struct window *w) struct touch *touch; double x, y; - if (slot == -1 || slot >= ARRAY_LENGTH(w->touches)) + if (slot == -1 || slot >= (int) ARRAY_LENGTH(w->touches)) return; touch = &w->touches[slot]; @@ -436,7 +436,7 @@ close_restricted(int fd, void *user_data) close(fd); } -const static struct libinput_interface interface = { +static const struct libinput_interface interface = { .open_restricted = open_restricted, .close_restricted = close_restricted, }; From 2eaefefdde52e540275a513eb25b254c81702d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 14 Jul 2014 23:33:51 +0200 Subject: [PATCH 37/50] test: Assert libevdev_uinput_write_event() call was successful MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonas Ådahl --- test/litest.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/litest.c b/test/litest.c index 5fd9e913..adcbf3ea 100644 --- a/test/litest.c +++ b/test/litest.c @@ -588,7 +588,8 @@ void litest_event(struct litest_device *d, unsigned int type, unsigned int code, int value) { - libevdev_uinput_write_event(d->uinput, type, code, value); + int ret = libevdev_uinput_write_event(d->uinput, type, code, value); + ck_assert_int_eq(ret, 0); } static int From 5cc4d2380c30d5a1de53a29393cdf293e854c00e Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 4 Jul 2014 10:43:52 +1000 Subject: [PATCH 38/50] Include stdint.h from filter.h Don't rely on the users to include it Signed-off-by: Peter Hutterer --- src/filter.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/filter.h b/src/filter.h index c0b27d0d..31ac7ebe 100644 --- a/src/filter.h +++ b/src/filter.h @@ -25,6 +25,8 @@ #include "config.h" +#include + struct motion_params { double dx, dy; /* in units/ms @ 400dpi */ }; From 369eec638efb5f08f81d23b9c122c082ebdd6c7b Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 15 Jul 2014 16:49:26 +1000 Subject: [PATCH 39/50] test: fix a missing finger release Signed-off-by: Peter Hutterer --- test/touchpad.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/touchpad.c b/test/touchpad.c index 6a33a440..b7b31d6b 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -925,6 +925,8 @@ START_TEST(clickpad_softbutton_left_2nd_fg_move) event = libinput_get_event(li); } + litest_touch_up(dev, 1); + litest_event(dev, EV_KEY, BTN_LEFT, 0); litest_event(dev, EV_SYN, SYN_REPORT, 0); litest_touch_up(dev, 0); From c193f7d13b1054c557976c0822086a92dae4c01f Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 15 Jul 2014 16:26:46 +1000 Subject: [PATCH 40/50] test: fix resolution on T440s multitouch axes Signed-off-by: Peter Hutterer --- test/litest-synaptics-t440.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/litest-synaptics-t440.c b/test/litest-synaptics-t440.c index 1b664940..e3f14413 100644 --- a/test/litest-synaptics-t440.c +++ b/test/litest-synaptics-t440.c @@ -91,8 +91,8 @@ static struct input_absinfo absinfo[] = { { ABS_PRESSURE, 0, 255, 0, 0, 0 }, { ABS_TOOL_WIDTH, 0, 15, 0, 0, 0 }, { ABS_MT_SLOT, 0, 1, 0, 0, 0 }, - { ABS_MT_POSITION_X, 1024, 5112, 0, 0, 75 }, - { ABS_MT_POSITION_Y, 2024, 4832, 0, 0, 129 }, + { ABS_MT_POSITION_X, 1024, 5112, 0, 0, 42 }, + { ABS_MT_POSITION_Y, 2024, 4832, 0, 0, 42 }, { ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 }, { ABS_MT_PRESSURE, 0, 255, 0, 0, 0 }, { .value = -1 } From 9de131f08253595821cb94a083dcc1ff62325467 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 16 Jul 2014 14:10:08 +1000 Subject: [PATCH 41/50] test: fix x/y resolution for a test device Signed-off-by: Peter Hutterer --- test/touch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/touch.c b/test/touch.c index 5d704c53..6f6eec0a 100644 --- a/test/touch.c +++ b/test/touch.c @@ -72,8 +72,8 @@ START_TEST(touch_abs_transform) bool tested = false; struct input_absinfo abs[] = { - { ABS_X, 0, 32767, 75, 0, 0 }, - { ABS_Y, 0, 32767, 129, 0, 0 }, + { ABS_X, 0, 32767, 75, 0, 10 }, + { ABS_Y, 0, 32767, 129, 0, 9 }, { ABS_MT_POSITION_X, 0, 32767, 0, 0, 10 }, { ABS_MT_POSITION_Y, 0, 32767, 0, 0, 9 }, { .value = -1 }, From 8665e3678ab07b7071c70d75b137e0528be70e84 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 15 Jul 2014 16:01:49 +1000 Subject: [PATCH 42/50] touchpad: check the pointer touch for history size The current touch may not be the pointer touch, so it's pointless checking the history size on that touch. Instead, search for the pointer touch first, check if it's dirty and then check the history size. Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 69b63e05..c7fd3a12 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -524,23 +524,23 @@ tp_post_events(struct tp_dispatch *tp, uint64_t time) if (tp_post_scroll_events(tp, time) != 0) return; - if (t->history.count >= TOUCHPAD_MIN_SAMPLES) { - if (!t->is_pointer) { - tp_for_each_touch(tp, t) { - if (t->is_pointer) - break; - } + if (!t->is_pointer) { + tp_for_each_touch(tp, t) { + if (t->is_pointer) + break; } - - if (!t->is_pointer) - return; - - tp_get_delta(t, &dx, &dy); - tp_filter_motion(tp, &dx, &dy, time); - - if (dx != 0.0 || dy != 0.0) - pointer_notify_motion(&tp->device->base, time, dx, dy); } + + if (!t->is_pointer || + !t->dirty || + t->history.count < TOUCHPAD_MIN_SAMPLES) + return; + + tp_get_delta(t, &dx, &dy); + tp_filter_motion(tp, &dx, &dy, time); + + if (dx != 0.0 || dy != 0.0) + pointer_notify_motion(&tp->device->base, time, dx, dy); } static void From 489630f58b2ac099bf235efc5dfd9cd854c223ee Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 18 Jul 2014 16:01:10 +1000 Subject: [PATCH 43/50] test: widen litest to use doubles for scaled variables Using a 0-100% range is useful but in some cases we need events with finer than 1% granularity. And fix up the two-finger test that now fails. This was a bug in the test anyway, the dx/dy supplied here was 1% of the touchpad width. Confined to integers this meant we only ever had the touch down, then the single move by 1%. That caused two events - not enough to satisfy tp_estimate_delta, so we always had a delta of 0/0 regardless of the size of the move. Now with doubles this fails, so drop it to 0.1% instead, which is small enough on all touchpads we currently have. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- test/litest-int.h | 2 +- test/litest.c | 15 +++++++++------ test/litest.h | 12 ++++++------ test/touchpad.c | 4 ++-- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/test/litest-int.h b/test/litest-int.h index 19e6e68d..581930b8 100644 --- a/test/litest-int.h +++ b/test/litest-int.h @@ -93,7 +93,7 @@ struct litest_device_interface { }; void litest_set_current_device(struct litest_device *device); -int litest_scale(const struct litest_device *d, unsigned int axis, int val); +int litest_scale(const struct litest_device *d, unsigned int axis, double val); void litest_generic_device_teardown(void); #endif diff --git a/test/litest.c b/test/litest.c index adcbf3ea..452cb770 100644 --- a/test/litest.c +++ b/test/litest.c @@ -595,7 +595,7 @@ litest_event(struct litest_device *d, unsigned int type, static int auto_assign_value(struct litest_device *d, const struct input_event *ev, - int slot, int x, int y) + int slot, double x, double y) { static int tracking_id; int value = ev->value; @@ -625,7 +625,8 @@ auto_assign_value(struct litest_device *d, void -litest_touch_down(struct litest_device *d, unsigned int slot, int x, int y) +litest_touch_down(struct litest_device *d, unsigned int slot, + double x, double y) { struct input_event *ev; @@ -669,7 +670,8 @@ litest_touch_up(struct litest_device *d, unsigned int slot) } void -litest_touch_move(struct litest_device *d, unsigned int slot, int x, int y) +litest_touch_move(struct litest_device *d, unsigned int slot, + double x, double y) { struct input_event *ev; @@ -689,8 +691,8 @@ litest_touch_move(struct litest_device *d, unsigned int slot, int x, int y) void litest_touch_move_to(struct litest_device *d, unsigned int slot, - int x_from, int y_from, - int x_to, int y_to, + double x_from, double y_from, + double x_to, double y_to, int steps) { for (int i = 0; i < steps - 1; i++) @@ -720,7 +722,8 @@ litest_keyboard_key(struct litest_device *d, unsigned int key, bool is_press) litest_button_click(d, key, is_press); } -int litest_scale(const struct litest_device *d, unsigned int axis, int val) +int +litest_scale(const struct litest_device *d, unsigned int axis, double val) { int min, max; ck_assert_int_ge(val, 0); diff --git a/test/litest.h b/test/litest.h index 3e75dd58..2363c7f9 100644 --- a/test/litest.h +++ b/test/litest.h @@ -108,16 +108,16 @@ void litest_event(struct litest_device *t, void litest_touch_up(struct litest_device *d, unsigned int slot); void litest_touch_move(struct litest_device *d, unsigned int slot, - int x, - int y); + double x, + double y); void litest_touch_down(struct litest_device *d, unsigned int slot, - int x, - int y); + double x, + double y); void litest_touch_move_to(struct litest_device *d, unsigned int slot, - int x_from, int y_from, - int x_to, int y_to, + double x_from, double y_from, + double x_to, double y_to, int steps); void litest_button_click(struct litest_device *d, unsigned int button, diff --git a/test/touchpad.c b/test/touchpad.c index b7b31d6b..3bd5fb67 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -1127,7 +1127,7 @@ START_TEST(clickpad_topsoftbuttons_move_out_ignore) END_TEST static void -test_2fg_scroll(struct litest_device *dev, int dx, int dy, int sleep) +test_2fg_scroll(struct litest_device *dev, double dx, double dy, int sleep) { struct libinput *li = dev->libinput; @@ -1210,7 +1210,7 @@ START_TEST(touchpad_2fg_scroll) check_2fg_scroll(dev, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, -10); /* 2fg scroll smaller than the threshold should not generate events */ - test_2fg_scroll(dev, 1, 1, 200); + test_2fg_scroll(dev, 0.1, 0.1, 200); litest_assert_empty_queue(li); } END_TEST From 475665efdf21641d5f18c02c3862138197c33466 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 15 Jul 2014 16:32:33 +1000 Subject: [PATCH 44/50] test: reduce sideways-component in two-finger scroll test This breaks when we have a device resolution set on the test devices, specificially on the T440. The current tests use a delta of 1% of the device which with the resolution set results in an effective delta of 3 - above the scroll threshold. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- test/touchpad.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/touchpad.c b/test/touchpad.c index 3bd5fb67..bd5d71eb 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -1198,15 +1198,13 @@ START_TEST(touchpad_2fg_scroll) litest_drain_events(li); - /* Note this mixes in a tiny amount of movement in the wrong direction, - which should be ignored */ - test_2fg_scroll(dev, 1, 40, 0); + test_2fg_scroll(dev, 0.1, 40, 0); check_2fg_scroll(dev, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 10); - test_2fg_scroll(dev, 1, -40, 0); + test_2fg_scroll(dev, 0.1, -40, 0); check_2fg_scroll(dev, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, -10); - test_2fg_scroll(dev, 40, 1, 0); + test_2fg_scroll(dev, 40, 0.1, 0); check_2fg_scroll(dev, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, 10); - test_2fg_scroll(dev, -40, 1, 0); + test_2fg_scroll(dev, -40, 0.1, 0); check_2fg_scroll(dev, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, -10); /* 2fg scroll smaller than the threshold should not generate events */ From e1484cb7f820ae8284140d3a5ece43b564f19b45 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 15 Jul 2014 15:35:20 +1000 Subject: [PATCH 45/50] test: set the abs resolution after creating the device Until uinput gets that capability (likely not before 3.17) all we can do is a racy approach of setting it after creating it. That won't work well for anything test where libinput is already listening to udev when the device is created, but it does work for those cases where libinput is started after the device was initialized. And it's a better alternative than not testing anything dependent on resolution settings. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- test/litest.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/test/litest.c b/test/litest.c index 452cb770..1ffbd53d 100644 --- a/test/litest.c +++ b/test/litest.c @@ -811,13 +811,14 @@ litest_assert_empty_queue(struct libinput *li) struct libevdev_uinput * litest_create_uinput_device_from_description(const char *name, const struct input_id *id, - const struct input_absinfo *abs, + const struct input_absinfo *abs_info, const int *events) { struct libevdev_uinput *uinput; struct libevdev *dev; int type, code; - int rc; + int rc, fd; + const struct input_absinfo *abs; const struct input_absinfo default_abs = { .value = 0, .minimum = 0, @@ -827,6 +828,7 @@ litest_create_uinput_device_from_description(const char *name, .resolution = 100 }; char buf[512]; + const char *devnode; dev = libevdev_new(); ck_assert(dev != NULL); @@ -839,6 +841,7 @@ litest_create_uinput_device_from_description(const char *name, libevdev_set_id_product(dev, id->product); } + abs = abs_info; while (abs && abs->value != -1) { rc = libevdev_enable_event_code(dev, EV_ABS, abs->value, abs); @@ -867,6 +870,31 @@ litest_create_uinput_device_from_description(const char *name, libevdev_free(dev); + /* uinput does not yet support setting the resolution, so we set it + * afterwards. This is of course racy as hell but the way we + * _generally_ use this function by the time libinput uses the + * device, we're finished here */ + + devnode = libevdev_uinput_get_devnode(uinput); + ck_assert_notnull(devnode); + fd = open(devnode, O_RDONLY); + ck_assert_int_gt(fd, -1); + rc = libevdev_new_from_fd(fd, &dev); + ck_assert_int_eq(rc, 0); + + abs = abs_info; + while (abs && abs->value != -1) { + if (abs->resolution != 0) { + rc = libevdev_kernel_set_abs_info(dev, + abs->value, + abs); + ck_assert_int_eq(rc, 0); + } + abs++; + } + close(fd); + libevdev_free(dev); + return uinput; } From 876a8959ab1abe8a231860703320bb5fcc43c603 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 14 Jul 2014 16:19:33 +1000 Subject: [PATCH 46/50] filter: move get_direction into shared header Makes it possible to use from the touchpad code. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/filter.c | 60 ++------------------------------------------- src/libinput-util.h | 58 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 58 deletions(-) diff --git a/src/filter.c b/src/filter.c index e1fb2a96..d65adfb7 100644 --- a/src/filter.c +++ b/src/filter.c @@ -29,6 +29,7 @@ #include #include "filter.h" +#include "libinput-util.h" void filter_dispatch(struct motion_filter *filter, @@ -84,63 +85,6 @@ struct pointer_accelerator { int cur_tracker; }; -enum directions { - N = 1 << 0, - NE = 1 << 1, - E = 1 << 2, - SE = 1 << 3, - S = 1 << 4, - SW = 1 << 5, - W = 1 << 6, - NW = 1 << 7, - UNDEFINED_DIRECTION = 0xff -}; - -static int -get_direction(int dx, int dy) -{ - int dir = UNDEFINED_DIRECTION; - int d1, d2; - double r; - - if (abs(dx) < 2 && abs(dy) < 2) { - if (dx > 0 && dy > 0) - dir = S | SE | E; - else if (dx > 0 && dy < 0) - dir = N | NE | E; - else if (dx < 0 && dy > 0) - dir = S | SW | W; - else if (dx < 0 && dy < 0) - dir = N | NW | W; - else if (dx > 0) - dir = NE | E | SE; - else if (dx < 0) - dir = NW | W | SW; - else if (dy > 0) - dir = SE | S | SW; - else if (dy < 0) - dir = NE | N | NW; - } else { - /* Calculate r within the interval [0 to 8) - * - * r = [0 .. 2π] where 0 is North - * d_f = r / 2π ([0 .. 1)) - * d_8 = 8 * d_f - */ - r = atan2(dy, dx); - r = fmod(r + 2.5*M_PI, 2*M_PI); - r *= 4*M_1_PI; - - /* Mark one or two close enough octants */ - d1 = (int)(r + 0.9) % 8; - d2 = (int)(r + 0.1) % 8; - - dir = (1 << d1) | (1 << d2); - } - - return dir; -} - static void feed_trackers(struct pointer_accelerator *accel, double dx, double dy, @@ -160,7 +104,7 @@ feed_trackers(struct pointer_accelerator *accel, trackers[current].dx = 0.0; trackers[current].dy = 0.0; trackers[current].time = time; - trackers[current].dir = get_direction(dx, dy); + trackers[current].dir = vector_get_direction(dx, dy); } static struct pointer_tracker * diff --git a/src/libinput-util.h b/src/libinput-util.h index 2558a3d9..c0235ef3 100644 --- a/src/libinput-util.h +++ b/src/libinput-util.h @@ -24,6 +24,7 @@ #define LIBINPUT_UTIL_H #include +#include #include "libinput.h" @@ -92,4 +93,61 @@ msleep(unsigned int ms) usleep(ms * 1000); } +enum directions { + N = 1 << 0, + NE = 1 << 1, + E = 1 << 2, + SE = 1 << 3, + S = 1 << 4, + SW = 1 << 5, + W = 1 << 6, + NW = 1 << 7, + UNDEFINED_DIRECTION = 0xff +}; + +static inline int +vector_get_direction(int dx, int dy) +{ + int dir = UNDEFINED_DIRECTION; + int d1, d2; + double r; + + if (abs(dx) < 2 && abs(dy) < 2) { + if (dx > 0 && dy > 0) + dir = S | SE | E; + else if (dx > 0 && dy < 0) + dir = N | NE | E; + else if (dx < 0 && dy > 0) + dir = S | SW | W; + else if (dx < 0 && dy < 0) + dir = N | NW | W; + else if (dx > 0) + dir = NE | E | SE; + else if (dx < 0) + dir = NW | W | SW; + else if (dy > 0) + dir = SE | S | SW; + else if (dy < 0) + dir = NE | N | NW; + } else { + /* Calculate r within the interval [0 to 8) + * + * r = [0 .. 2π] where 0 is North + * d_f = r / 2π ([0 .. 1)) + * d_8 = 8 * d_f + */ + r = atan2(dy, dx); + r = fmod(r + 2.5*M_PI, 2*M_PI); + r *= 4*M_1_PI; + + /* Mark one or two close enough octants */ + d1 = (int)(r + 0.9) % 8; + d2 = (int)(r + 0.1) % 8; + + dir = (1 << d1) | (1 << d2); + } + + return dir; +} + #endif /* LIBINPUT_UTIL_H */ From ec7fc30ae2176c7361c1eb26c4c53e98382cbb6d Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Jul 2014 17:34:08 +1000 Subject: [PATCH 47/50] touchpad: implement edge-based basic palm detection A large part of palm events are situated on the far edges of the touchpad. In a test run on a T440s while typing a long email all but 2 touch points were located in the outer ~5% of the touchpad. Define a 5% exclusion zone on the left and right edges in which new touchpoint is automatically assigned to be a palm. A finger may move into that exclusion zone without being marked as palm, it just can't start in one. On clickpads, the exclusion zone does not extend into the software buttons. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad-buttons.c | 6 ++ src/evdev-mt-touchpad.c | 47 +++++++++++++ src/evdev-mt-touchpad.h | 9 +++ test/touchpad.c | 117 ++++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+) diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 520a47f1..bd3c0e25 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -733,3 +733,9 @@ tp_button_touch_active(struct tp_dispatch *tp, struct tp_touch *t) { return t->button.state == BUTTON_STATE_AREA; } + +bool +tp_button_is_inside_softbutton_area(struct tp_dispatch *tp, struct tp_touch *t) +{ + return is_inside_top_button_area(tp, t) || is_inside_bottom_button_area(tp, t); +} diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index c7fd3a12..1325355c 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -148,6 +148,7 @@ tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t) t->dirty = true; t->is_pointer = false; + t->is_palm = false; t->state = TOUCH_END; t->pinned.is_pinned = false; assert(tp->nfingers_down >= 1); @@ -339,6 +340,7 @@ static int tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t) { return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) && + !t->is_palm && !t->pinned.is_pinned && tp_button_touch_active(tp, t); } @@ -357,6 +359,29 @@ tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t) t->is_pointer = true; } +static void +tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t) +{ + /* once a palm, always a palm */ + if (t->is_palm) + return; + + /* palm must start in exclusion zone, it's ok to move into + the zone without being a palm */ + if (t->state != TOUCH_BEGIN || + (t->x > tp->palm.left_edge && t->x < tp->palm.right_edge)) + return; + + /* don't detect palm in software button areas, it's + likely that legitimate touches start in the area + covered by the exclusion zone */ + if (tp->buttons.is_clickpad && + tp_button_is_inside_softbutton_area(tp, t)) + return; + + t->is_palm = true; +} + static void tp_process_state(struct tp_dispatch *tp, uint64_t time) { @@ -373,6 +398,8 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time) continue; } + tp_palm_detect(tp, t); + tp_motion_hysteresis(tp, t); tp_motion_history_push(t); @@ -702,6 +729,23 @@ tp_init_scroll(struct tp_dispatch *tp) return 0; } +static int +tp_init_palmdetect(struct tp_dispatch *tp, + struct evdev_device *device) +{ + int width; + + width = abs(device->abs.absinfo_x->maximum - + device->abs.absinfo_x->minimum); + + /* palm edges are 5% of the width on each side */ + tp->palm.right_edge = device->abs.absinfo_x->maximum - width * 0.05; + tp->palm.left_edge = device->abs.absinfo_x->minimum + width * 0.05; + + return 0; +} + + static int tp_init(struct tp_dispatch *tp, struct evdev_device *device) @@ -738,6 +782,9 @@ tp_init(struct tp_dispatch *tp, if (tp_init_buttons(tp, device) != 0) return -1; + if (tp_init_palmdetect(tp, device) != 0) + return -1; + return 0; } diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 80f3f606..689687ee 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -103,6 +103,7 @@ struct tp_touch { bool dirty; bool fake; /* a fake touch */ bool is_pointer; /* the pointer-controlling touch */ + bool is_palm; int32_t x; int32_t y; uint64_t millis; @@ -202,6 +203,11 @@ struct tp_dispatch { struct libinput_timer timer; enum tp_tap_state state; } tap; + + struct { + int32_t right_edge; + int32_t left_edge; + } palm; }; #define tp_for_each_touch(_tp, _t) \ @@ -242,4 +248,7 @@ tp_button_handle_state(struct tp_dispatch *tp, uint64_t time); int tp_button_touch_active(struct tp_dispatch *tp, struct tp_touch *t); +bool +tp_button_is_inside_softbutton_area(struct tp_dispatch *tp, struct tp_touch *t); + #endif diff --git a/test/touchpad.c b/test/touchpad.c index bd5d71eb..672cbf9b 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -1241,6 +1241,117 @@ START_TEST(touchpad_tap_default) } END_TEST +START_TEST(touchpad_palm_detect_at_edge) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_drain_events(li); + + litest_touch_down(dev, 0, 99, 50); + litest_touch_move_to(dev, 0, 99, 50, 99, 70, 5); + litest_touch_up(dev, 0); + + litest_assert_empty_queue(li); + + litest_touch_down(dev, 0, 5, 50); + litest_touch_move_to(dev, 0, 5, 50, 5, 70, 5); + litest_touch_up(dev, 0); +} +END_TEST + +START_TEST(touchpad_palm_detect_at_bottom_corners) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + /* Run for non-clickpads only: make sure the bottom corners trigger + palm detection too */ + litest_drain_events(li); + + litest_touch_down(dev, 0, 99, 95); + litest_touch_move_to(dev, 0, 99, 95, 99, 99, 10); + litest_touch_up(dev, 0); + + litest_assert_empty_queue(li); + + litest_touch_down(dev, 0, 5, 95); + litest_touch_move_to(dev, 0, 5, 95, 5, 99, 5); + litest_touch_up(dev, 0); +} +END_TEST + +START_TEST(touchpad_palm_detect_at_top_corners) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + /* Run for non-clickpads only: make sure the bottom corners trigger + palm detection too */ + litest_drain_events(li); + + litest_touch_down(dev, 0, 99, 5); + litest_touch_move_to(dev, 0, 99, 5, 99, 9, 10); + litest_touch_up(dev, 0); + + litest_assert_empty_queue(li); + + litest_touch_down(dev, 0, 5, 5); + litest_touch_move_to(dev, 0, 5, 5, 5, 9, 5); + litest_touch_up(dev, 0); +} +END_TEST + +START_TEST(touchpad_palm_detect_palm_stays_palm) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_drain_events(li); + + litest_touch_down(dev, 0, 99, 50); + litest_touch_move_to(dev, 0, 99, 50, 0, 70, 5); + litest_touch_up(dev, 0); + + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(touchpad_palm_detect_no_palm_moving_into_edges) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *ev; + enum libinput_event_type type; + + /* moving non-palm into the edge does not label it as palm */ + litest_drain_events(li); + + litest_touch_down(dev, 0, 50, 50); + litest_touch_move_to(dev, 0, 50, 50, 99, 50, 5); + + litest_drain_events(li); + + litest_touch_move_to(dev, 0, 99, 50, 99, 90, 5); + libinput_dispatch(li); + + type = libinput_next_event_type(li); + do { + + ck_assert_int_eq(type, LIBINPUT_EVENT_POINTER_MOTION); + ev = libinput_get_event(li); + libinput_event_destroy(ev); + + type = libinput_next_event_type(li); + libinput_dispatch(li); + } while (type != LIBINPUT_EVENT_NONE); + + litest_touch_up(dev, 0); + libinput_dispatch(li); + litest_assert_empty_queue(li); +} +END_TEST + int main(int argc, char **argv) { litest_add("touchpad:motion", touchpad_1fg_motion, LITEST_TOUCHPAD, LITEST_ANY); @@ -1290,5 +1401,11 @@ int main(int argc, char **argv) { litest_add("touchpad:scroll", touchpad_2fg_scroll, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("touchpad:palm", touchpad_palm_detect_at_edge, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:palm", touchpad_palm_detect_at_bottom_corners, LITEST_TOUCHPAD, LITEST_CLICKPAD); + litest_add("touchpad:palm", touchpad_palm_detect_at_top_corners, LITEST_TOUCHPAD, LITEST_TOPBUTTONPAD); + litest_add("touchpad:palm", touchpad_palm_detect_palm_stays_palm, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:palm", touchpad_palm_detect_no_palm_moving_into_edges, LITEST_TOUCHPAD, LITEST_ANY); + return litest_run(argc, argv); } From 9ecce8e2f73e9115f680755745d9c0d8c4e50a00 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 14 Jul 2014 16:06:51 +1000 Subject: [PATCH 48/50] touchpad: if a palm touch moves out of the edge zone within a timeout, unpalm On small touchpads a touch that is intended to traverse much of the screen width may start at the very edge, i.e. in the palm zone. In that case, and if the touch moves out of the palm zone quickly enough, drop the palm label and make it a normal touchpoint. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad.c | 25 ++++++++++++++++++------- src/evdev-mt-touchpad.h | 6 +++++- test/touchpad.c | 20 +++++++++++++++++--- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 1325355c..830e9fee 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -148,7 +148,7 @@ tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t) t->dirty = true; t->is_pointer = false; - t->is_palm = false; + t->palm.is_palm = false; t->state = TOUCH_END; t->pinned.is_pinned = false; assert(tp->nfingers_down >= 1); @@ -340,7 +340,7 @@ static int tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t) { return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) && - !t->is_palm && + !t->palm.is_palm && !t->pinned.is_pinned && tp_button_touch_active(tp, t); } @@ -360,11 +360,21 @@ tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t) } static void -tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t) +tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) { - /* once a palm, always a palm */ - if (t->is_palm) + const int PALM_TIMEOUT = 200; /* ms */ + + /* If labelled a touch as palm, we unlabel as palm when + we move out of the palm edge zone within the timeout. + */ + if (t->palm.is_palm) { + if (time < t->palm.time + PALM_TIMEOUT && + (t->x > tp->palm.left_edge && t->x < tp->palm.right_edge)) { + t->palm.is_palm = false; + tp_set_pointer(tp, t); + } return; + } /* palm must start in exclusion zone, it's ok to move into the zone without being a palm */ @@ -379,7 +389,8 @@ tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t) tp_button_is_inside_softbutton_area(tp, t)) return; - t->is_palm = true; + t->palm.is_palm = true; + t->palm.time = time; } static void @@ -398,7 +409,7 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time) continue; } - tp_palm_detect(tp, t); + tp_palm_detect(tp, t, time); tp_motion_hysteresis(tp, t); tp_motion_history_push(t); diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 689687ee..8255a1cd 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -103,7 +103,6 @@ struct tp_touch { bool dirty; bool fake; /* a fake touch */ bool is_pointer; /* the pointer-controlling touch */ - bool is_palm; int32_t x; int32_t y; uint64_t millis; @@ -140,6 +139,11 @@ struct tp_touch { struct { enum tp_tap_touch_state state; } tap; + + struct { + bool is_palm; + uint32_t time; /* first timestamp if is_palm == true */ + } palm; }; struct tp_dispatch { diff --git a/test/touchpad.c b/test/touchpad.c index 672cbf9b..18427c1a 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -1302,17 +1302,31 @@ START_TEST(touchpad_palm_detect_at_top_corners) } END_TEST -START_TEST(touchpad_palm_detect_palm_stays_palm) +START_TEST(touchpad_palm_detect_palm_becomes_pointer) { struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + struct libinput_event *ev; + enum libinput_event_type type; litest_drain_events(li); litest_touch_down(dev, 0, 99, 50); - litest_touch_move_to(dev, 0, 99, 50, 0, 70, 5); + litest_touch_move_to(dev, 0, 99, 70, 0, 70, 5); litest_touch_up(dev, 0); + libinput_dispatch(li); + + ev = libinput_get_event(li); + ck_assert_notnull(ev); + do { + type = libinput_event_get_type(ev); + ck_assert_int_eq(type, LIBINPUT_EVENT_POINTER_MOTION); + + libinput_event_destroy(ev); + ev = libinput_get_event(li); + } while (ev); + litest_assert_empty_queue(li); } END_TEST @@ -1404,7 +1418,7 @@ int main(int argc, char **argv) { litest_add("touchpad:palm", touchpad_palm_detect_at_edge, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:palm", touchpad_palm_detect_at_bottom_corners, LITEST_TOUCHPAD, LITEST_CLICKPAD); litest_add("touchpad:palm", touchpad_palm_detect_at_top_corners, LITEST_TOUCHPAD, LITEST_TOPBUTTONPAD); - litest_add("touchpad:palm", touchpad_palm_detect_palm_stays_palm, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:palm", touchpad_palm_detect_palm_becomes_pointer, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:palm", touchpad_palm_detect_no_palm_moving_into_edges, LITEST_TOUCHPAD, LITEST_ANY); return litest_run(argc, argv); From b3c578521e7b53bb9fd0516344d9c24b24e519a1 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 14 Jul 2014 16:38:46 +1000 Subject: [PATCH 49/50] touchpad: require a <45 degree movement for a palm to become a touch Any legitimate finger movement that starts in the palm area is expected to move out of the palm area at an angle roughly orthogonal to the edge of the touchpad. Check for the direction of the movement vector, and if it is within the accepted cardinal/ordinal directions then proceed. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad.c | 13 ++++++++++--- src/evdev-mt-touchpad.h | 1 + test/touchpad.c | 15 +++++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 830e9fee..2cf8b567 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -363,15 +363,20 @@ static void tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) { const int PALM_TIMEOUT = 200; /* ms */ + const int DIRECTIONS = NE|E|SE|SW|W|NW; /* If labelled a touch as palm, we unlabel as palm when - we move out of the palm edge zone within the timeout. + we move out of the palm edge zone within the timeout, provided + the direction is within 45 degrees of the horizontal. */ if (t->palm.is_palm) { if (time < t->palm.time + PALM_TIMEOUT && (t->x > tp->palm.left_edge && t->x < tp->palm.right_edge)) { - t->palm.is_palm = false; - tp_set_pointer(tp, t); + int dirs = vector_get_direction(t->x - t->palm.x, t->y - t->palm.y); + if ((dirs & DIRECTIONS) && !(dirs & ~DIRECTIONS)) { + t->palm.is_palm = false; + tp_set_pointer(tp, t); + } } return; } @@ -391,6 +396,8 @@ tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) t->palm.is_palm = true; t->palm.time = time; + t->palm.x = t->x; + t->palm.y = t->y; } static void diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 8255a1cd..47791201 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -142,6 +142,7 @@ struct tp_touch { struct { bool is_palm; + int32_t x, y; /* first coordinates if is_palm == true */ uint32_t time; /* first timestamp if is_palm == true */ } palm; }; diff --git a/test/touchpad.c b/test/touchpad.c index 18427c1a..1d95399c 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -1302,6 +1302,20 @@ START_TEST(touchpad_palm_detect_at_top_corners) } END_TEST +START_TEST(touchpad_palm_detect_palm_stays_palm) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_drain_events(li); + + litest_touch_down(dev, 0, 99, 20); + litest_touch_move_to(dev, 0, 99, 20, 75, 99, 5); + litest_touch_up(dev, 0); + litest_assert_empty_queue(li); +} +END_TEST + START_TEST(touchpad_palm_detect_palm_becomes_pointer) { struct litest_device *dev = litest_current_device(); @@ -1419,6 +1433,7 @@ int main(int argc, char **argv) { litest_add("touchpad:palm", touchpad_palm_detect_at_bottom_corners, LITEST_TOUCHPAD, LITEST_CLICKPAD); litest_add("touchpad:palm", touchpad_palm_detect_at_top_corners, LITEST_TOUCHPAD, LITEST_TOPBUTTONPAD); litest_add("touchpad:palm", touchpad_palm_detect_palm_becomes_pointer, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:palm", touchpad_palm_detect_palm_stays_palm, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:palm", touchpad_palm_detect_no_palm_moving_into_edges, LITEST_TOUCHPAD, LITEST_ANY); return litest_run(argc, argv); From 858f0095653ce4b5f4a099bd2afbdcf616e5764a Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 15 Jul 2014 14:01:00 +1000 Subject: [PATCH 50/50] touchpad: don't init edge palm detection on touchpads less than 8cm across On small touchpads, a touch that intends to go across the width of the touchpad is likely to start in the edge zone. Likewise, on those touchpads the chances of a palm event happening on the edge is small. A minimum width of 8cm determined by an elaborate process of completely unscientific guesswork: the x220 is roughly 7.5cm across and doesn't suffer much from edge events, the T440s is 10cm across and definitely suffers from it. So the trigger width likely somewhere in between which makes 8cm about as valid as any other guess. Note that this disables palm detection for resolution-less touchpads too - if we don't know how big the touchpad is we can't know if palm detection on the edges is necessary. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad.c | 13 +++++++++++++ test/touchpad.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 2cf8b567..1636e7a2 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "evdev-mt-touchpad.h" @@ -753,9 +754,21 @@ tp_init_palmdetect(struct tp_dispatch *tp, { int width; + /* We don't know how big the touchpad is */ + if (device->abs.absinfo_x->resolution == 1) + return 0; + width = abs(device->abs.absinfo_x->maximum - device->abs.absinfo_x->minimum); + /* Enable palm detection on touchpads >= 80 mm. Anything smaller + probably won't need it, until we find out it does */ + if (width/device->abs.absinfo_x->resolution < 80) { + tp->palm.right_edge = INT_MAX; + tp->palm.left_edge = INT_MIN; + return 0; + } + /* palm edges are 5% of the width on each side */ tp->palm.right_edge = device->abs.absinfo_x->maximum - width * 0.05; tp->palm.left_edge = device->abs.absinfo_x->minimum + width * 0.05; diff --git a/test/touchpad.c b/test/touchpad.c index 1d95399c..c1bdbd53 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -1241,11 +1241,24 @@ START_TEST(touchpad_tap_default) } END_TEST +static int +touchpad_has_palm_detect_size(struct litest_device *dev) +{ + double width, height; + + libinput_device_get_size(dev->libinput_device, &width, &height); + + return width >= 80; +} + START_TEST(touchpad_palm_detect_at_edge) { struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + if (!touchpad_has_palm_detect_size(dev)) + return; + litest_drain_events(li); litest_touch_down(dev, 0, 99, 50); @@ -1265,6 +1278,9 @@ START_TEST(touchpad_palm_detect_at_bottom_corners) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + if (!touchpad_has_palm_detect_size(dev)) + return; + /* Run for non-clickpads only: make sure the bottom corners trigger palm detection too */ litest_drain_events(li); @@ -1286,6 +1302,9 @@ START_TEST(touchpad_palm_detect_at_top_corners) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + if (!touchpad_has_palm_detect_size(dev)) + return; + /* Run for non-clickpads only: make sure the bottom corners trigger palm detection too */ litest_drain_events(li); @@ -1307,6 +1326,9 @@ START_TEST(touchpad_palm_detect_palm_stays_palm) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; + if (!touchpad_has_palm_detect_size(dev)) + return; + litest_drain_events(li); litest_touch_down(dev, 0, 99, 20); @@ -1323,6 +1345,9 @@ START_TEST(touchpad_palm_detect_palm_becomes_pointer) struct libinput_event *ev; enum libinput_event_type type; + if (!touchpad_has_palm_detect_size(dev)) + return; + litest_drain_events(li); litest_touch_down(dev, 0, 99, 50); @@ -1352,6 +1377,9 @@ START_TEST(touchpad_palm_detect_no_palm_moving_into_edges) struct libinput_event *ev; enum libinput_event_type type; + if (!touchpad_has_palm_detect_size(dev)) + return; + /* moving non-palm into the edge does not label it as palm */ litest_drain_events(li);