diff options
-rw-r--r-- | meson.build | 1 | ||||
-rw-r--r-- | src/evdev-mt-touchpad.c | 34 | ||||
-rw-r--r-- | src/evdev-mt-touchpad.h | 1 | ||||
-rw-r--r-- | test/litest-device-alps-3fg.c | 179 | ||||
-rw-r--r-- | test/litest.h | 4 |
5 files changed, 217 insertions, 2 deletions
diff --git a/meson.build b/meson.build index af4c87e8..f588862c 100644 --- a/meson.build +++ b/meson.build @@ -770,6 +770,7 @@ if get_option('tests') 'test/litest-device-acer-hawaii-keyboard.c', 'test/litest-device-acer-hawaii-touchpad.c', 'test/litest-device-aiptek-tablet.c', + 'test/litest-device-alps-3fg.c', 'test/litest-device-alps-semi-mt.c', 'test/litest-device-alps-dualpoint.c', 'test/litest-device-anker-mouse-kbd.c', diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 4ffc4a39..a1b2c3d4 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -525,10 +525,14 @@ tp_process_absolute(struct tp_dispatch *tp, tp->slot = e->value; break; case ABS_MT_TRACKING_ID: - if (e->value != -1) + if (e->value != -1) { + tp->nactive_slots += 1; tp_new_touch(tp, t, time); - else + } else { + assert(tp->nactive_slots >= 1); + tp->nactive_slots -= 1; tp_end_sequence(tp, t, time); + } break; case ABS_MT_PRESSURE: t->pressure = e->value; @@ -638,6 +642,32 @@ tp_process_fake_touches(struct tp_dispatch *tp, EVDEV_MODEL_SYNAPTICS_SERIAL_TOUCHPAD) tp_restore_synaptics_touches(tp, time); + /* ALPS touchpads always set 3 slots in the kernel, even + * where they support less than that. So we get BTN_TOOL_TRIPLETAP + * but never slot 2 because our slot count is wrong. + * This also means that the third touch falls through the cracks and + * is ignored. + * + * All touchpad devices have at least one slot so we only do this + * for 2 touches or higher. + */ + if (nfake_touches > 1 && tp->has_mt && + nfake_touches > tp->nactive_slots && + tp->nactive_slots < tp->num_slots) { + evdev_log_bug_kernel(tp->device, + "Wrong slot count (%d), reducing to %d\n", + tp->num_slots, + tp->nactive_slots); + /* This should be safe since we fill the slots from the + * first one so hiding the excessive slots shouldn't matter. + * There are sequences where we could accidentally lose an + * actual touch point but that requires specially crafted + * sequences and let's deal with that when it happens. + */ + tp->num_slots = tp->nactive_slots; + } + + start = tp->has_mt ? tp->num_slots : 0; for (i = start; i < tp->ntouches; i++) { t = tp_get_touch(tp, i); diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index a8ac5d5b..0099c0ae 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -268,6 +268,7 @@ struct tp_dispatch { struct libinput_timer arbitration_timer; } arbitration; + unsigned int nactive_slots; /* number of active slots */ unsigned int num_slots; /* number of slots */ unsigned int ntouches; /* no slots inc. fakes */ struct tp_touch *touches; /* len == ntouches */ diff --git a/test/litest-device-alps-3fg.c b/test/litest-device-alps-3fg.c new file mode 100644 index 00000000..16a11ee1 --- /dev/null +++ b/test/litest-device-alps-3fg.c @@ -0,0 +1,179 @@ +/* + * Copyright © 2020 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include <assert.h> + +#include "libinput-util.h" + +#include "litest.h" +#include "litest-int.h" + +struct alps { + unsigned int first, second; + unsigned int active_touches; +}; + +static bool +alps_create(struct litest_device *d) +{ + d->private = zalloc(sizeof(struct alps)); + return true; /* we want litest to create our device */ +} + +static bool +touch_down(struct litest_device *d, unsigned int slot, double x, double y) +{ + struct alps *alps = d->private; + + alps->active_touches++; + + if (alps->active_touches == 1) + alps->first = slot; + if (alps->active_touches == 2) + alps->second = slot; + + /* This device announces 4 slots but only does two slots. So + * anything over 2 slots we just drop for events, + * litest takes care of BTN_TOOL_* for us. */ + if (alps->active_touches > 2) { + /* Need to send SYN_REPORT to flush litest's BTN_TOOL_* updates */ + litest_event(d, EV_SYN, SYN_REPORT, 0); + return true; + } + + return false; +} + +static bool +touch_move(struct litest_device *d, unsigned int slot, double x, double y) +{ + struct alps *alps = d->private; + + if (alps->active_touches > 2 && + slot != alps->first && + slot != alps->second) + return true; + + return false; +} + +static bool +touch_up(struct litest_device *d, unsigned int slot) +{ + struct alps *alps = d->private; + + assert(alps->active_touches >= 1); + alps->active_touches--; + + /* Need to send SYN_REPORT to flush litest's BTN_TOOL_* updates */ + if (alps->active_touches > 2 && + slot != alps->first && + slot != alps->second) { + litest_event(d, EV_SYN, SYN_REPORT, 0); + return true; + } + + if (slot == alps->first) + alps->first = UINT_MAX; + if (slot == alps->second) + alps->second = UINT_MAX; + + return false; +} + +static struct input_event down[] = { + { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; + +static struct input_event move[] = { + { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN }, + { .type = EV_SYN, .code = SYN_REPORT, .value = 0 }, + { .type = -1, .code = -1 }, +}; + +static struct litest_device_interface interface = { + .touch_down_events = down, + .touch_move_events = move, + + .touch_down = touch_down, + .touch_move = touch_move, + .touch_up = touch_up, +}; + +static struct input_id input_id = { + .bustype = 0x11, + .vendor = 0x2, + .product = 0x8, + .version = 0x700, +}; + +static int events[] = { + EV_KEY, BTN_LEFT, + EV_KEY, BTN_RIGHT, + EV_KEY, BTN_MIDDLE, + EV_KEY, BTN_TOOL_FINGER, + EV_KEY, BTN_TOUCH, + EV_KEY, BTN_TOOL_DOUBLETAP, + EV_KEY, BTN_TOOL_TRIPLETAP, + EV_KEY, BTN_TOOL_QUADTAP, + EV_KEY, BTN_TOOL_QUINTTAP, + INPUT_PROP_MAX, INPUT_PROP_POINTER, + -1, -1, +}; + +/* Note: we use the user-supplied resolution here, see #408 */ +static struct input_absinfo absinfo[] = { + { ABS_X, 0, 4095, 0, 0, 37 }, + { ABS_Y, 0, 2047, 0, 0, 26 }, + { ABS_PRESSURE, 0, 127, 0, 0, 0 }, + { ABS_MT_SLOT, 0, 3, 0, 0, 0 }, + { ABS_MT_POSITION_X, 0, 4095, 0, 0, 37 }, + { ABS_MT_POSITION_Y, 0, 2047, 0, 0, 26 }, + { ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 }, + { .value = -1 } +}; + +TEST_DEVICE("alps-3fg", + .type = LITEST_ALPS_3FG, + .features = LITEST_TOUCHPAD | LITEST_BUTTON, + .interface = &interface, + + .name = "AlpsPS/2 ALPS GlidePoint", + .id = &input_id, + .events = events, + .absinfo = absinfo, + .create = alps_create, +) diff --git a/test/litest.h b/test/litest.h index ac32433f..67cec9bc 100644 --- a/test/litest.h +++ b/test/litest.h @@ -300,6 +300,7 @@ enum litest_device_type { LITEST_DELL_CANVAS_TOTEM, LITEST_DELL_CANVAS_TOTEM_TOUCH, LITEST_WACOM_ISDV4_4200_PEN, + LITEST_ALPS_3FG, }; #define LITEST_DEVICELESS -2 @@ -1151,6 +1152,9 @@ litest_send_file(int sock, int fd) static inline int litest_slot_count(struct litest_device *dev) { + if (dev->which == LITEST_ALPS_3FG) + return 2; + return libevdev_get_num_slots(dev->evdev); } |