diff --git a/configure.ac b/configure.ac
index 860324ac..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.
@@ -57,6 +57,8 @@ 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])
+AC_CHECK_LIB([rt], [clock_gettime])
if test "x$GCC" = "xyes"; then
GCC_CXXFLAGS="-Wall -Wextra -Wno-unused-parameter -g -fvisibility=hidden"
@@ -119,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}
+ ])
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 @@
+
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 @@
-
+
+
diff --git a/src/Makefile.am b/src/Makefile.am
index b880a699..44108367 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -29,8 +29,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/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c
index 2ac231c7..bd3c0e25 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;
@@ -581,11 +503,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;
@@ -603,11 +527,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 {
@@ -792,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-tap.c b/src/evdev-mt-touchpad-tap.c
index 25412184..0f1f837d 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,55 +459,58 @@ 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;
- if (!tp->tap.enabled)
- return;
-
current = tp->tap.state;
switch(tp->tap.state) {
case TAP_STATE_IDLE:
- tp_tap_idle_handle_event(tp, event, time);
+ if (!tp->tap.enabled)
+ break;
+
+ 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,21 +599,87 @@ 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;
+ }
+}
+
+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.c b/src/evdev-mt-touchpad.c
index ced92378..1636e7a2 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -25,12 +25,11 @@
#include
#include
#include
+#include
#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
@@ -42,30 +41,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
-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 *
@@ -87,7 +64,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;
@@ -171,6 +149,7 @@ tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t)
t->dirty = true;
t->is_pointer = false;
+ t->palm.is_palm = false;
t->state = TOUCH_END;
t->pinned.is_pinned = false;
assert(tp->nfingers_down >= 1);
@@ -362,6 +341,7 @@ static int
tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
{
return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) &&
+ !t->palm.is_palm &&
!t->pinned.is_pinned && tp_button_touch_active(tp, t);
}
@@ -380,6 +360,47 @@ 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, 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, 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)) {
+ 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;
+ }
+
+ /* 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->palm.is_palm = true;
+ t->palm.time = time;
+ t->palm.x = t->x;
+ t->palm.y = t->y;
+}
+
static void
tp_process_state(struct tp_dispatch *tp, uint64_t time)
{
@@ -392,8 +413,11 @@ 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_palm_detect(tp, t, time);
tp_motion_hysteresis(tp, t);
tp_motion_history_push(t);
@@ -465,11 +489,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 &&
@@ -546,23 +570,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
@@ -601,7 +625,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);
}
@@ -666,9 +690,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) {
@@ -683,35 +708,34 @@ 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 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 = (400/25.4) / res_x;
+ tp->accel.y_scale_coeff = (400/25.4) / 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;
}
@@ -724,6 +748,35 @@ tp_init_scroll(struct tp_dispatch *tp)
return 0;
}
+static int
+tp_init_palmdetect(struct tp_dispatch *tp,
+ struct evdev_device *device)
+{
+ 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;
+
+ return 0;
+}
+
+
static int
tp_init(struct tp_dispatch *tp,
struct evdev_device *device)
@@ -760,6 +813,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 7afb3c46..47791201 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,
@@ -88,6 +86,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 +135,16 @@ struct tp_touch {
enum button_event curr;
struct libinput_timer timer;
} button;
+
+ struct {
+ enum tp_tap_touch_state state;
+ } tap;
+
+ struct {
+ bool is_palm;
+ int32_t x, y; /* first coordinates if is_palm == true */
+ uint32_t time; /* first timestamp if is_palm == true */
+ } palm;
};
struct tp_dispatch {
@@ -152,10 +166,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;
@@ -193,10 +203,16 @@ 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;
} tap;
+
+ struct {
+ int32_t right_edge;
+ int32_t left_edge;
+ } palm;
};
#define tp_for_each_touch(_tp, _t) \
@@ -237,4 +253,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/src/evdev.c b/src/evdev.c
index 6fc4ecfb..1b95bb7e 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -866,6 +866,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])
{
@@ -936,7 +954,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/evdev.h b/src/evdev.h
index 63624dd8..bfa47b17 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -145,6 +145,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/filter.c b/src/filter.c
index 3221d193..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,
@@ -38,26 +39,34 @@ 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.
*/
-#define DEFAULT_CONSTANT_ACCELERATION 10.0
-#define DEFAULT_THRESHOLD 4.0
-#define DEFAULT_ACCELERATION 2.0
+#define DEFAULT_THRESHOLD 0.4 /* 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;
};
@@ -67,72 +76,15 @@ 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;
};
-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,
@@ -152,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 *
@@ -174,7 +126,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
@@ -218,7 +170,7 @@ calculate_velocity(struct pointer_accelerator *accel, uint64_t time)
}
}
- return result;
+ return result; /* units/ms */
}
static double
@@ -245,28 +197,7 @@ calculate_acceleration(struct pointer_accelerator *accel,
factor = factor / 6.0;
- 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);
+ return factor; /* unitless factor */
}
static void
@@ -276,8 +207,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);
@@ -286,8 +217,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;
@@ -332,15 +261,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)
{
@@ -352,27 +272,39 @@ 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 */
+ double factor; /* unitless factor */
- velocity *= DEFAULT_CONSTANT_ACCELERATION;
+ if (threshold < 0.1)
+ threshold = 0.1;
+ 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;
- 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;
- velocity /= threshold;
- if (velocity >= accel) {
+ return 1.0;
+
+ factor = velocity/threshold;
+ if (factor >= accel)
return accel;
- } else {
- smooth_accel_coefficient =
- calc_penumbral_gradient(velocity / accel);
- return 1.0 + (smooth_accel_coefficient * (accel - 1.0));
- }
+
+ /* 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));
}
diff --git a/src/filter.h b/src/filter.h
index c0219eeb..31ac7ebe 100644
--- a/src/filter.h
+++ b/src/filter.h
@@ -25,8 +25,10 @@
#include "config.h"
+#include
+
struct motion_params {
- double dx, dy;
+ double dx, dy; /* in units/ms @ 400dpi */
};
struct motion_filter;
@@ -35,6 +37,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 +63,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.
diff --git a/src/libinput-private.h b/src/libinput-private.h
index dbdf5e6d..6ec36376 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -83,12 +83,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;
};
struct libinput_tool {
diff --git a/src/libinput-util.h b/src/libinput-util.h
index fc8e8a08..8c28eb49 100644
--- a/src/libinput-util.h
+++ b/src/libinput-util.h
@@ -24,6 +24,7 @@
#define LIBINPUT_UTIL_H
#include
+#include
#include "libinput.h"
@@ -116,4 +117,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 */
diff --git a/src/libinput.c b/src/libinput.c
index 5d26bc91..e013f490 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -1446,6 +1446,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)
{
@@ -1522,3 +1540,58 @@ 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;
+}
+
+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 14e533e7..2e6ab06b 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -541,7 +541,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.
@@ -559,7 +559,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.
@@ -1102,7 +1102,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
@@ -1535,12 +1535,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
*
@@ -1648,8 +1689,113 @@ 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);
+
+/**
+ * @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 */
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
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) {
diff --git a/test/Makefile.am b/test/Makefile.am
index 0b86d350..64596275 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -2,16 +2,17 @@ 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)
-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 \
- $(top_srcdir)/src/libinput-util.c \
+ ../src/libinput-util.h \
+ ../src/libinput-util.c \
litest.h \
litest-int.h \
litest-bcm5974.c \
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/litest-int.h b/test/litest-int.h
index e64f8b85..c6c3e4a6 100644
--- a/test/litest-int.h
+++ b/test/litest-int.h
@@ -101,7 +101,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-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 }
diff --git a/test/litest.c b/test/litest.c
index 958d2cfe..6ce5e6b5 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -365,7 +365,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)
@@ -399,7 +399,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)
@@ -596,13 +596,14 @@ 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
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;
@@ -632,7 +633,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;
@@ -676,7 +678,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;
@@ -696,8 +699,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++)
@@ -816,7 +819,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);
@@ -904,13 +908,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,
@@ -920,6 +925,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);
@@ -932,6 +938,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);
@@ -960,6 +967,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;
}
diff --git a/test/litest.h b/test/litest.h
index 9e159a34..2b3c5d78 100644
--- a/test/litest.h
+++ b/test/litest.h
@@ -119,16 +119,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_tablet_proximity_in(struct litest_device *d,
int x, int y,
diff --git a/test/misc.c b/test/misc.c
index c4eaf911..c73ccdc0 100644
--- a/test/misc.c
+++ b/test/misc.c
@@ -26,6 +26,7 @@
#include
#include
#include
+#include
#include
#include "litest.h"
@@ -95,7 +96,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 +150,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 +211,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 +271,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 +320,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,
@@ -428,6 +429,46 @@ START_TEST(context_ref_counting)
}
END_TEST
+START_TEST(device_ids)
+{
+ struct litest_device *dev = litest_current_device();
+ const char *name;
+ unsigned 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
+
+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);
@@ -436,6 +477,8 @@ int main (int argc, char **argv) {
litest_add_no_device("events:conversion", event_conversion_touch);
litest_add_no_device("bitfield_helpers", bitfield_helpers);
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);
}
diff --git a/test/pointer.c b/test/pointer.c
index 7d5668f8..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). */
@@ -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;
@@ -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..6f6eec0a 100644
--- a/test/touch.c
+++ b/test/touch.c
@@ -72,15 +72,15 @@ 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 },
};
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;
diff --git a/test/touchpad.c b/test/touchpad.c
index 288805ef..c1bdbd53 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;
@@ -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
@@ -320,11 +334,89 @@ 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();
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
@@ -359,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
@@ -599,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
@@ -639,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
@@ -827,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);
@@ -1027,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;
@@ -1051,7 +1151,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;
@@ -1098,19 +1198,212 @@ 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 */
- test_2fg_scroll(dev, 1, 1, 200);
+ test_2fg_scroll(dev, 0.1, 0.1, 200);
+ litest_assert_empty_queue(li);
+}
+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
+
+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);
+ 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;
+
+ 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);
+
+ 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;
+
+ 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);
+
+ 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;
+
+ if (!touchpad_has_palm_detect_size(dev))
+ return;
+
+ 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();
+ struct libinput *li = dev->libinput;
+ 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);
+ 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
+
+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;
+
+ if (!touchpad_has_palm_detect_size(dev))
+ return;
+
+ /* 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
@@ -1127,11 +1420,20 @@ 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);
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);
@@ -1155,5 +1457,12 @@ 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_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);
}
diff --git a/tools/event-debug.c b/tools/event-debug.c
index acf9d815..0eb4bcaf 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:
@@ -561,7 +561,7 @@ handle_and_print_events(struct libinput *li)
return rc;
}
-void
+static void
mainloop(struct libinput *li)
{
struct pollfd fds[2];
diff --git a/tools/event-gui.c b/tools/event-gui.c
index 7bc38281..cd01f989 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);
@@ -243,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
@@ -258,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];
@@ -268,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;
@@ -442,7 +441,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,
};