From 5571f2d2cc8c021e59c0be36820c46683127712c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 9 Jul 2015 08:14:35 +1000 Subject: [PATCH] touchpad: hook up disable-while-typing configuration This is not a frequent toggle, so we don't need to jump through too many hoops here. We simply enable/disable on command and once any current timeouts have expired the new setting takes effect. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad.c | 107 +++++++++++++-- src/evdev-mt-touchpad.h | 3 + test/touchpad.c | 287 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 381 insertions(+), 16 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 4e290f80..a5695844 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -528,7 +528,8 @@ tp_palm_tap_is_palm(struct tp_dispatch *tp, struct tp_touch *t) static int tp_palm_detect_dwt(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) { - if (tp->dwt.keyboard_active && + if (tp->dwt.dwt_enabled && + tp->dwt.keyboard_active && t->state == TOUCH_BEGIN) { t->palm.state = PALM_TYPING; t->palm.first = t->point; @@ -1127,6 +1128,9 @@ tp_keyboard_event(uint64_t time, struct libinput_event *event, void *data) struct libinput_event_keyboard *kbdev; unsigned int timeout; + if (!tp->dwt.dwt_enabled) + return; + if (event->type != LIBINPUT_EVENT_KEYBOARD_KEY) return; @@ -1157,6 +1161,22 @@ tp_keyboard_event(uint64_t time, struct libinput_event *event, void *data) time + timeout); } +static bool +tp_dwt_device_is_blacklisted(struct evdev_device *device) +{ + unsigned int bus = libevdev_get_id_bustype(device->evdev); + + /* evemu will set the right bus type */ + if (bus == BUS_BLUETOOTH || bus == BUS_VIRTUAL) + return true; + + /* Wacom makes touchpads, but not internal ones */ + if (libevdev_get_id_vendor(device->evdev) == VENDOR_ID_WACOM) + return true; + + return false; +} + static bool tp_want_dwt(struct evdev_device *touchpad, struct evdev_device *keyboard) @@ -1164,11 +1184,8 @@ tp_want_dwt(struct evdev_device *touchpad, unsigned int bus_tp = libevdev_get_id_bustype(touchpad->evdev), bus_kbd = libevdev_get_id_bustype(keyboard->evdev); - if (bus_tp == BUS_BLUETOOTH || bus_kbd == BUS_BLUETOOTH) - return false; - - /* evemu will set the right bus type */ - if (bus_tp == BUS_VIRTUAL || bus_kbd == BUS_VIRTUAL) + if (tp_dwt_device_is_blacklisted(touchpad) || + tp_dwt_device_is_blacklisted(keyboard)) return false; /* If the touchpad is on serio, the keyboard is too, so ignore any @@ -1176,10 +1193,6 @@ tp_want_dwt(struct evdev_device *touchpad, if (bus_tp == BUS_I8042 && bus_kbd != bus_tp) return false; - /* Wacom makes touchpads, but not internal ones */ - if (libevdev_get_id_vendor(touchpad->evdev) == VENDOR_ID_WACOM) - return false; - /* everything else we don't really know, so we have to assume they go together */ @@ -1499,6 +1512,77 @@ tp_init_scroll(struct tp_dispatch *tp, struct evdev_device *device) return 0; } +static int +tp_dwt_config_is_available(struct libinput_device *device) +{ + return 1; +} + +static enum libinput_config_status +tp_dwt_config_set(struct libinput_device *device, + enum libinput_config_dwt_state enable) +{ + struct evdev_device *evdev = (struct evdev_device*)device; + struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch; + + switch(enable) { + case LIBINPUT_CONFIG_DWT_ENABLED: + case LIBINPUT_CONFIG_DWT_DISABLED: + break; + default: + return LIBINPUT_CONFIG_STATUS_INVALID; + } + + tp->dwt.dwt_enabled = (enable == LIBINPUT_CONFIG_DWT_ENABLED); + + return LIBINPUT_CONFIG_STATUS_SUCCESS; +} + +static enum libinput_config_dwt_state +tp_dwt_config_get(struct libinput_device *device) +{ + struct evdev_device *evdev = (struct evdev_device*)device; + struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch; + + return tp->dwt.dwt_enabled ? + LIBINPUT_CONFIG_DWT_ENABLED : + LIBINPUT_CONFIG_DWT_DISABLED; +} + +static bool +tp_dwt_default_enabled(struct tp_dispatch *tp) +{ + return true; +} + +static enum libinput_config_dwt_state +tp_dwt_config_get_default(struct libinput_device *device) +{ + struct evdev_device *evdev = (struct evdev_device*)device; + struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch; + + return tp_dwt_default_enabled(tp) ? + LIBINPUT_CONFIG_DWT_ENABLED : + LIBINPUT_CONFIG_DWT_DISABLED; +} + +static int +tp_init_dwt(struct tp_dispatch *tp, + struct evdev_device *device) +{ + if (tp_dwt_device_is_blacklisted(device)) + return 0; + + tp->dwt.config.is_available = tp_dwt_config_is_available; + tp->dwt.config.set_enabled = tp_dwt_config_set; + tp->dwt.config.get_enabled = tp_dwt_config_get; + tp->dwt.config.get_default_enabled = tp_dwt_config_get_default; + tp->dwt.dwt_enabled = tp_dwt_default_enabled(tp); + device->base.config.dwt = &tp->dwt.config; + + return 0; +} + static int tp_init_palmdetect(struct tp_dispatch *tp, struct evdev_device *device) @@ -1674,6 +1758,9 @@ tp_init(struct tp_dispatch *tp, if (tp_init_buttons(tp, device) != 0) return -1; + if (tp_init_dwt(tp, device) != 0) + return -1; + if (tp_init_palmdetect(tp, device) != 0) return -1; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index fc6d38e2..1cc4925e 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -322,6 +322,9 @@ struct tp_dispatch { } sendevents; struct { + struct libinput_device_config_dwt config; + bool dwt_enabled; + bool keyboard_active; struct libinput_event_listener keyboard_listener; struct libinput_timer keyboard_timer; diff --git a/test/touchpad.c b/test/touchpad.c index 06d5a7b4..34ca80d0 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -2205,12 +2205,7 @@ END_TEST static inline bool has_disable_while_typing(struct litest_device *device) { - if (libevdev_get_id_vendor(device->evdev) == VENDOR_ID_WACOM) - return false; - if (libevdev_get_id_bustype(device->evdev) == BUS_BLUETOOTH) - return false; - - return true; + return libinput_device_config_dwt_is_available(device->libinput_device); } START_TEST(touchpad_dwt) @@ -2623,6 +2618,278 @@ START_TEST(touchpad_dwt_edge_scroll_interrupt) } END_TEST +START_TEST(touchpad_dwt_config_default_on) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + enum libinput_config_status status; + enum libinput_config_dwt_state state; + + if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_WACOM || + libevdev_get_id_bustype(dev->evdev) == BUS_BLUETOOTH) { + ck_assert(!libinput_device_config_dwt_is_available(device)); + return; + } + + ck_assert(libinput_device_config_dwt_is_available(device)); + state = libinput_device_config_dwt_get_enabled(device); + ck_assert_int_eq(state, LIBINPUT_CONFIG_DWT_ENABLED); + state = libinput_device_config_dwt_get_default_enabled(device); + ck_assert_int_eq(state, LIBINPUT_CONFIG_DWT_ENABLED); + + status = libinput_device_config_dwt_set_enabled(device, + LIBINPUT_CONFIG_DWT_ENABLED); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + status = libinput_device_config_dwt_set_enabled(device, + LIBINPUT_CONFIG_DWT_DISABLED); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + status = libinput_device_config_dwt_set_enabled(device, 3); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID); +} +END_TEST + +START_TEST(touchpad_dwt_config_default_off) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + enum libinput_config_status status; + enum libinput_config_dwt_state state; + + ck_assert(!libinput_device_config_dwt_is_available(device)); + state = libinput_device_config_dwt_get_enabled(device); + ck_assert_int_eq(state, LIBINPUT_CONFIG_DWT_DISABLED); + state = libinput_device_config_dwt_get_default_enabled(device); + ck_assert_int_eq(state, LIBINPUT_CONFIG_DWT_DISABLED); + + status = libinput_device_config_dwt_set_enabled(device, + LIBINPUT_CONFIG_DWT_ENABLED); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED); + status = libinput_device_config_dwt_set_enabled(device, + LIBINPUT_CONFIG_DWT_DISABLED); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + status = libinput_device_config_dwt_set_enabled(device, 3); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID); +} +END_TEST + +static inline void +disable_dwt(struct litest_device *dev) +{ + enum libinput_config_status status, + expected = LIBINPUT_CONFIG_STATUS_SUCCESS; + status = libinput_device_config_dwt_set_enabled(dev->libinput_device, + LIBINPUT_CONFIG_DWT_DISABLED); + litest_assert_int_eq(status, expected); +} + +static inline void +enable_dwt(struct litest_device *dev) +{ + enum libinput_config_status status, + expected = LIBINPUT_CONFIG_STATUS_SUCCESS; + status = libinput_device_config_dwt_set_enabled(dev->libinput_device, + LIBINPUT_CONFIG_DWT_ENABLED); + litest_assert_int_eq(status, expected); +} + +START_TEST(touchpad_dwt_disabled) +{ + struct litest_device *touchpad = litest_current_device(); + struct litest_device *keyboard; + struct libinput *li = touchpad->libinput; + + if (!has_disable_while_typing(touchpad)) + return; + + disable_dwt(touchpad); + + keyboard = litest_add_device(li, LITEST_KEYBOARD); + litest_disable_tap(touchpad->libinput_device); + litest_drain_events(li); + + litest_keyboard_key(keyboard, KEY_A, true); + litest_keyboard_key(keyboard, KEY_A, false); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY); + + litest_touch_down(touchpad, 0, 50, 50); + litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 10, 1); + litest_touch_up(touchpad, 0); + + litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); + + litest_delete_device(keyboard); +} +END_TEST + +START_TEST(touchpad_dwt_disable_during_touch) +{ + struct litest_device *touchpad = litest_current_device(); + struct litest_device *keyboard; + struct libinput *li = touchpad->libinput; + + if (!has_disable_while_typing(touchpad)) + return; + + enable_dwt(touchpad); + + keyboard = litest_add_device(li, LITEST_KEYBOARD); + litest_disable_tap(touchpad->libinput_device); + litest_drain_events(li); + + litest_keyboard_key(keyboard, KEY_A, true); + litest_keyboard_key(keyboard, KEY_A, false); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY); + + litest_touch_down(touchpad, 0, 50, 50); + litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 10, 1); + litest_assert_empty_queue(li); + + disable_dwt(touchpad); + + /* touch already down -> keeps being ignored */ + litest_touch_move_to(touchpad, 0, 70, 50, 50, 70, 10, 1); + litest_touch_up(touchpad, 0); + + litest_assert_empty_queue(li); + + litest_delete_device(keyboard); +} +END_TEST + +START_TEST(touchpad_dwt_disable_before_touch) +{ + struct litest_device *touchpad = litest_current_device(); + struct litest_device *keyboard; + struct libinput *li = touchpad->libinput; + + if (!has_disable_while_typing(touchpad)) + return; + + enable_dwt(touchpad); + + keyboard = litest_add_device(li, LITEST_KEYBOARD); + litest_disable_tap(touchpad->libinput_device); + litest_drain_events(li); + + litest_keyboard_key(keyboard, KEY_A, true); + litest_keyboard_key(keyboard, KEY_A, false); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY); + + disable_dwt(touchpad); + libinput_dispatch(li); + + /* touch down during timeout -> still discarded */ + litest_touch_down(touchpad, 0, 50, 50); + litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 10, 1); + litest_assert_empty_queue(li); + + litest_delete_device(keyboard); +} +END_TEST + +START_TEST(touchpad_dwt_enable_during_touch) +{ + struct litest_device *touchpad = litest_current_device(); + struct litest_device *keyboard; + struct libinput *li = touchpad->libinput; + + if (!has_disable_while_typing(touchpad)) + return; + + disable_dwt(touchpad); + + keyboard = litest_add_device(li, LITEST_KEYBOARD); + litest_disable_tap(touchpad->libinput_device); + litest_drain_events(li); + + litest_keyboard_key(keyboard, KEY_A, true); + litest_keyboard_key(keyboard, KEY_A, false); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY); + + litest_touch_down(touchpad, 0, 50, 50); + litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 10, 1); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); + + enable_dwt(touchpad); + + /* touch already down -> still sends events */ + litest_touch_move_to(touchpad, 0, 70, 50, 50, 70, 10, 1); + litest_touch_up(touchpad, 0); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); + + litest_delete_device(keyboard); +} +END_TEST + +START_TEST(touchpad_dwt_enable_before_touch) +{ + struct litest_device *touchpad = litest_current_device(); + struct litest_device *keyboard; + struct libinput *li = touchpad->libinput; + + if (!has_disable_while_typing(touchpad)) + return; + + disable_dwt(touchpad); + + keyboard = litest_add_device(li, LITEST_KEYBOARD); + litest_disable_tap(touchpad->libinput_device); + litest_drain_events(li); + + litest_keyboard_key(keyboard, KEY_A, true); + litest_keyboard_key(keyboard, KEY_A, false); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY); + + enable_dwt(touchpad); + libinput_dispatch(li); + + litest_touch_down(touchpad, 0, 50, 50); + litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 10, 1); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); + + litest_delete_device(keyboard); +} +END_TEST + +START_TEST(touchpad_dwt_enable_during_tap) +{ + struct litest_device *touchpad = litest_current_device(); + struct litest_device *keyboard; + struct libinput *li = touchpad->libinput; + + if (!has_disable_while_typing(touchpad)) + return; + + litest_enable_tap(touchpad->libinput_device); + disable_dwt(touchpad); + + keyboard = litest_add_device(li, LITEST_KEYBOARD); + litest_drain_events(li); + + litest_keyboard_key(keyboard, KEY_A, true); + litest_keyboard_key(keyboard, KEY_A, false); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY); + + litest_touch_down(touchpad, 0, 50, 50); + libinput_dispatch(li); + enable_dwt(touchpad); + libinput_dispatch(li); + litest_touch_up(touchpad, 0); + libinput_dispatch(li); + + litest_timeout_tap(); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON); + + litest_touch_down(touchpad, 0, 50, 50); + litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 10, 1); + litest_touch_up(touchpad, 0); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); + + litest_delete_device(keyboard); +} +END_TEST static int has_thumb_detect(struct litest_device *dev) { @@ -3197,6 +3464,14 @@ litest_setup_tests(void) litest_add("touchpad:dwt", touchpad_dwt_click, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:dwt", touchpad_dwt_edge_scroll, LITEST_TOUCHPAD, LITEST_CLICKPAD); litest_add("touchpad:dwt", touchpad_dwt_edge_scroll_interrupt, LITEST_TOUCHPAD, LITEST_CLICKPAD); + litest_add("touchpad:dwt", touchpad_dwt_config_default_on, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:dwt", touchpad_dwt_config_default_off, LITEST_ANY, LITEST_TOUCHPAD); + litest_add("touchpad:dwt", touchpad_dwt_disabled, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:dwt", touchpad_dwt_disable_during_touch, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:dwt", touchpad_dwt_disable_before_touch, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:dwt", touchpad_dwt_enable_during_touch, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:dwt", touchpad_dwt_enable_before_touch, LITEST_TOUCHPAD, LITEST_ANY); + litest_add("touchpad:dwt", touchpad_dwt_enable_during_tap, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:thumb", touchpad_thumb_begin_no_motion, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:thumb", touchpad_thumb_update_no_motion, LITEST_TOUCHPAD, LITEST_ANY);