diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 58595785d1d42b6af0f425878830ea3dba946541..eb3dde3cdecc8f7c1790a3376fc4232ede544e97 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -1479,6 +1479,10 @@ tp_remove_sendevents(struct tp_dispatch *tp) if (tp->lid_switch.lid_switch) libinput_device_remove_event_listener( &tp->lid_switch.listener); + + if (tp->tablet_mode_switch.tablet_mode_switch) + libinput_device_remove_event_listener( + &tp->tablet_mode_switch.listener); } static void @@ -1861,23 +1865,34 @@ tp_pair_trackpoint(struct evdev_device *touchpad, } static void -tp_lid_switch_event(uint64_t time, struct libinput_event *event, void *data) +tp_switch_event(uint64_t time, struct libinput_event *event, void *data) { struct tp_dispatch *tp = data; struct libinput_event_switch *swev; + const char *which = NULL; if (libinput_event_get_type(event) != LIBINPUT_EVENT_SWITCH_TOGGLE) return; swev = libinput_event_get_switch_event(event); + + switch (libinput_event_switch_get_switch(swev)) { + case LIBINPUT_SWITCH_LID: + which = "lid"; + break; + case LIBINPUT_SWITCH_TABLET_MODE: + which = "tablet-mode"; + break; + } + switch (libinput_event_switch_get_switch_state(swev)) { case LIBINPUT_SWITCH_STATE_OFF: tp_resume(tp, tp->device); - evdev_log_debug(tp->device, "lid: resume touchpad\n"); + evdev_log_debug(tp->device, "%s: resume touchpad\n", which); break; case LIBINPUT_SWITCH_STATE_ON: tp_suspend(tp, tp->device); - evdev_log_debug(tp->device, "lid: suspend touchpad\n"); + evdev_log_debug(tp->device, "%s: suspend touchpad\n", which); break; } } @@ -1899,11 +1914,39 @@ tp_pair_lid_switch(struct evdev_device *touchpad, libinput_device_add_event_listener(&lid_switch->base, &tp->lid_switch.listener, - tp_lid_switch_event, tp); + tp_switch_event, tp); tp->lid_switch.lid_switch = lid_switch; } } +static void +tp_pair_tablet_mode_switch(struct evdev_device *touchpad, + struct evdev_device *tablet_mode_switch) +{ + struct tp_dispatch *tp = (struct tp_dispatch*)touchpad->dispatch; + + if ((tablet_mode_switch->tags & EVDEV_TAG_TABLET_MODE_SWITCH) == 0) + return; + + if (tp->tablet_mode_switch.tablet_mode_switch == NULL) { + evdev_log_debug(touchpad, + "tablet_mode_switch: activated for %s<->%s\n", + touchpad->devname, + tablet_mode_switch->devname); + + libinput_device_add_event_listener(&tablet_mode_switch->base, + &tp->tablet_mode_switch.listener, + tp_switch_event, tp); + tp->tablet_mode_switch.tablet_mode_switch = tablet_mode_switch; + + if (evdev_device_switch_get_state(tablet_mode_switch, + LIBINPUT_SWITCH_TABLET_MODE) + == LIBINPUT_SWITCH_STATE_ON) { + tp_suspend(tp, touchpad); + } + } +} + static void tp_interface_device_added(struct evdev_device *device, struct evdev_device *added_device) @@ -1913,6 +1956,7 @@ tp_interface_device_added(struct evdev_device *device, tp_pair_trackpoint(device, added_device); tp_dwt_pair_keyboard(device, added_device); tp_pair_lid_switch(device, added_device); + tp_pair_tablet_mode_switch(device, added_device); if (tp->sendevents.current_mode != LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE) @@ -1954,6 +1998,12 @@ tp_interface_device_removed(struct evdev_device *device, tp->lid_switch.lid_switch = NULL; } + if (removed_device == tp->tablet_mode_switch.tablet_mode_switch) { + libinput_device_remove_event_listener( + &tp->tablet_mode_switch.listener); + tp->tablet_mode_switch.tablet_mode_switch = NULL; + } + if (tp->sendevents.current_mode != LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE) return; diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 4c667effbcbdbe124f77303b6c59a2350e9063ea..efbdb3bfa3aea1c67d464ddfd607ce57022ed780 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -407,6 +407,11 @@ struct tp_dispatch { struct libinput_event_listener listener; struct evdev_device *lid_switch; } lid_switch; + + struct { + struct libinput_event_listener listener; + struct evdev_device *tablet_mode_switch; + } tablet_mode_switch; }; static inline struct tp_dispatch* diff --git a/src/evdev.c b/src/evdev.c index f9d8d34aec4ad75544d4cac9a3d19cef6f832d95..46f8ad57025bf5555a64a4f3cf532212115224c3 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -185,6 +185,25 @@ fallback_lid_notify_toggle(struct fallback_dispatch *dispatch, } } +enum libinput_switch_state +evdev_device_switch_get_state(struct evdev_device *device, + enum libinput_switch sw) +{ + struct fallback_dispatch *dispatch = fallback_dispatch(device->dispatch); + + switch (sw) { + case LIBINPUT_SWITCH_TABLET_MODE: + break; + default: + /* Internal function only, so we can abort here */ + abort(); + } + + return dispatch->tablet_mode.state ? + LIBINPUT_SWITCH_STATE_ON : + LIBINPUT_SWITCH_STATE_OFF; +} + void evdev_pointer_notify_physical_button(struct evdev_device *device, uint64_t time, diff --git a/src/evdev.h b/src/evdev.h index 4895c2ec63a192a29137086e906c638548821063..5192927c118267428676894633691e61a79bf025 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -524,6 +524,10 @@ struct libinput_tablet_pad_mode_group * evdev_device_tablet_pad_get_mode_group(struct evdev_device *device, unsigned int index); +enum libinput_switch_state +evdev_device_switch_get_state(struct evdev_device *device, + enum libinput_switch sw); + double evdev_device_transform_x(struct evdev_device *device, double x, diff --git a/test/test-switch.c b/test/test-switch.c index 59809798dfffef870e66c84e8dd3eeb2a6576136..77ba55932d3e423536bf325c1362bda874683ac1 100644 --- a/test/test-switch.c +++ b/test/test-switch.c @@ -36,6 +36,13 @@ switch_has_lid(struct litest_device *dev) LIBINPUT_SWITCH_LID); } +static inline bool +switch_has_tablet_mode(struct litest_device *dev) +{ + return libinput_device_switch_has_switch(dev->libinput_device, + LIBINPUT_SWITCH_TABLET_MODE); +} + START_TEST(switch_has_cap) { struct litest_device *dev = litest_current_device(); @@ -228,30 +235,29 @@ START_TEST(switch_not_down_on_init) END_TEST static inline struct litest_device * -lid_init_paired_touchpad(struct libinput *li) +switch_init_paired_touchpad(struct libinput *li) { enum litest_device_type which = LITEST_SYNAPTICS_I2C; return litest_add_device(li, which); } -START_TEST(lid_disable_touchpad) +START_TEST(switch_disable_touchpad) { struct litest_device *sw = litest_current_device(); struct litest_device *touchpad; struct libinput *li = sw->libinput; + enum libinput_switch which = _i; /* ranged test */ - if (!switch_has_lid(sw)) + if (!libinput_device_switch_has_switch(sw->libinput_device, which)) return; - touchpad = lid_init_paired_touchpad(li); + touchpad = switch_init_paired_touchpad(li); litest_disable_tap(touchpad->libinput_device); litest_drain_events(li); - /* lid is down - no events */ - litest_switch_action(sw, - LIBINPUT_SWITCH_LID, - LIBINPUT_SWITCH_STATE_ON); + /* switch is on - no events */ + litest_switch_action(sw, which, LIBINPUT_SWITCH_STATE_ON); litest_assert_only_typed_events(li, LIBINPUT_EVENT_SWITCH_TOGGLE); litest_touch_down(touchpad, 0, 50, 50); @@ -259,10 +265,8 @@ START_TEST(lid_disable_touchpad) litest_touch_up(touchpad, 0); litest_assert_empty_queue(li); - /* lid is up - motion events */ - litest_switch_action(sw, - LIBINPUT_SWITCH_LID, - LIBINPUT_SWITCH_STATE_OFF); + /* switch is off - motion events */ + litest_switch_action(sw, which, LIBINPUT_SWITCH_STATE_OFF); litest_assert_only_typed_events(li, LIBINPUT_EVENT_SWITCH_TOGGLE); litest_touch_down(touchpad, 0, 50, 50); @@ -274,16 +278,17 @@ START_TEST(lid_disable_touchpad) } END_TEST -START_TEST(lid_disable_touchpad_during_touch) +START_TEST(switch_disable_touchpad_during_touch) { struct litest_device *sw = litest_current_device(); struct litest_device *touchpad; struct libinput *li = sw->libinput; + enum libinput_switch which = _i; /* ranged test */ - if (!switch_has_lid(sw)) + if (!libinput_device_switch_has_switch(sw->libinput_device, which)) return; - touchpad = lid_init_paired_touchpad(li); + touchpad = switch_init_paired_touchpad(li); litest_disable_tap(touchpad->libinput_device); litest_drain_events(li); @@ -291,9 +296,7 @@ START_TEST(lid_disable_touchpad_during_touch) litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 5, 1); litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); - litest_switch_action(sw, - LIBINPUT_SWITCH_LID, - LIBINPUT_SWITCH_STATE_ON); + litest_switch_action(sw, which, LIBINPUT_SWITCH_STATE_ON); litest_assert_only_typed_events(li, LIBINPUT_EVENT_SWITCH_TOGGLE); litest_touch_move_to(touchpad, 0, 70, 50, 50, 50, 5, 1); @@ -304,23 +307,22 @@ START_TEST(lid_disable_touchpad_during_touch) } END_TEST -START_TEST(lid_disable_touchpad_edge_scroll) +START_TEST(switch_disable_touchpad_edge_scroll) { struct litest_device *sw = litest_current_device(); struct litest_device *touchpad; struct libinput *li = sw->libinput; + enum libinput_switch which = _i; /* ranged test */ - if (!switch_has_lid(sw)) + if (!libinput_device_switch_has_switch(sw->libinput_device, which)) return; - touchpad = lid_init_paired_touchpad(li); + touchpad = switch_init_paired_touchpad(li); litest_enable_edge_scroll(touchpad); litest_drain_events(li); - litest_switch_action(sw, - LIBINPUT_SWITCH_LID, - LIBINPUT_SWITCH_STATE_ON); + litest_switch_action(sw, which, LIBINPUT_SWITCH_STATE_ON); litest_assert_only_typed_events(li, LIBINPUT_EVENT_SWITCH_TOGGLE); litest_touch_down(touchpad, 0, 99, 20); @@ -342,17 +344,18 @@ START_TEST(lid_disable_touchpad_edge_scroll) } END_TEST -START_TEST(lid_disable_touchpad_edge_scroll_interrupt) +START_TEST(switch_disable_touchpad_edge_scroll_interrupt) { struct litest_device *sw = litest_current_device(); struct litest_device *touchpad; struct libinput *li = sw->libinput; struct libinput_event *event; + enum libinput_switch which = _i; /* ranged test */ - if (!switch_has_lid(sw)) + if (!libinput_device_switch_has_switch(sw->libinput_device, which)) return; - touchpad = lid_init_paired_touchpad(li); + touchpad = switch_init_paired_touchpad(li); litest_enable_edge_scroll(touchpad); litest_drain_events(li); @@ -364,9 +367,7 @@ START_TEST(lid_disable_touchpad_edge_scroll_interrupt) libinput_dispatch(li); litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS); - litest_switch_action(sw, - LIBINPUT_SWITCH_LID, - LIBINPUT_SWITCH_STATE_ON); + litest_switch_action(sw, which, LIBINPUT_SWITCH_STATE_ON); libinput_dispatch(li); event = libinput_get_event(li); @@ -376,38 +377,36 @@ START_TEST(lid_disable_touchpad_edge_scroll_interrupt) libinput_event_destroy(event); event = libinput_get_event(li); - litest_is_switch_event(event, - LIBINPUT_SWITCH_LID, - LIBINPUT_SWITCH_STATE_ON); + litest_is_switch_event(event, which, LIBINPUT_SWITCH_STATE_ON); libinput_event_destroy(event); litest_delete_device(touchpad); } END_TEST -START_TEST(lid_disable_touchpad_already_open) +START_TEST(switch_disable_touchpad_already_open) { struct litest_device *sw = litest_current_device(); struct litest_device *touchpad; struct libinput *li = sw->libinput; + enum libinput_switch which = _i; /* ranged test */ - if (!switch_has_lid(sw)) + if (!libinput_device_switch_has_switch(sw->libinput_device, which)) return; - touchpad = lid_init_paired_touchpad(li); + touchpad = switch_init_paired_touchpad(li); + litest_disable_tap(touchpad->libinput_device); litest_drain_events(li); - /* default: lid is up - motion events */ + /* default: switch is off - motion events */ 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); - /* open lid - motion events */ - litest_switch_action(sw, - LIBINPUT_SWITCH_LID, - LIBINPUT_SWITCH_STATE_OFF); + /* disable switch - motion events */ + litest_switch_action(sw, which, LIBINPUT_SWITCH_STATE_OFF); litest_assert_empty_queue(li); litest_touch_down(touchpad, 0, 50, 50); @@ -495,27 +494,34 @@ START_TEST(lid_open_on_key_touchpad_enabled) } END_TEST -START_TEST(lid_suspend_with_keyboard) +START_TEST(switch_suspend_with_keyboard) { struct libinput *li; struct litest_device *keyboard; struct litest_device *sw; + enum libinput_switch which = _i; /* ranged test */ li = litest_create_context(); - sw = litest_add_device(li, LITEST_LID_SWITCH); + switch(which) { + case LIBINPUT_SWITCH_LID: + sw = litest_add_device(li, LITEST_LID_SWITCH); + break; + case LIBINPUT_SWITCH_TABLET_MODE: + sw = litest_add_device(li, LITEST_THINKPAD_EXTRABUTTONS); + break; + default: + abort(); + } + libinput_dispatch(li); keyboard = litest_add_device(li, LITEST_KEYBOARD); libinput_dispatch(li); - litest_switch_action(sw, - LIBINPUT_SWITCH_LID, - LIBINPUT_SWITCH_STATE_ON); + litest_switch_action(sw, which, LIBINPUT_SWITCH_STATE_ON); litest_drain_events(li); - litest_switch_action(sw, - LIBINPUT_SWITCH_LID, - LIBINPUT_SWITCH_STATE_OFF); + litest_switch_action(sw, which, LIBINPUT_SWITCH_STATE_OFF); litest_drain_events(li); litest_delete_device(keyboard); @@ -528,14 +534,25 @@ START_TEST(lid_suspend_with_keyboard) } END_TEST -START_TEST(lid_suspend_with_touchpad) +START_TEST(switch_suspend_with_touchpad) { struct libinput *li; struct litest_device *touchpad, *sw; + enum libinput_switch which = _i; /* ranged test */ li = litest_create_context(); - sw = litest_add_device(li, LITEST_LID_SWITCH); + switch(which) { + case LIBINPUT_SWITCH_LID: + sw = litest_add_device(li, LITEST_LID_SWITCH); + break; + case LIBINPUT_SWITCH_TABLET_MODE: + sw = litest_add_device(li, LITEST_THINKPAD_EXTRABUTTONS); + break; + default: + abort(); + } + litest_drain_events(li); touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C); @@ -671,6 +688,44 @@ START_TEST(lid_key_press) } END_TEST +START_TEST(tablet_mode_disable_touchpad_on_init) +{ + struct litest_device *sw = litest_current_device(); + struct litest_device *touchpad; + struct libinput *li = sw->libinput; + + if (!switch_has_tablet_mode(sw)) + return; + + litest_switch_action(sw, + LIBINPUT_SWITCH_TABLET_MODE, + LIBINPUT_SWITCH_STATE_ON); + litest_drain_events(li); + + /* touchpad comes with switch already on - no events */ + touchpad = switch_init_paired_touchpad(li); + litest_disable_tap(touchpad->libinput_device); + litest_drain_events(li); + + 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_empty_queue(li); + + litest_switch_action(sw, + LIBINPUT_SWITCH_TABLET_MODE, + LIBINPUT_SWITCH_STATE_OFF); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_SWITCH_TOGGLE); + + 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(touchpad); +} +END_TEST + void litest_setup_tests_lid(void) { @@ -684,20 +739,20 @@ litest_setup_tests_lid(void) litest_add_ranged("switch:toggle", switch_toggle_double, LITEST_SWITCH, LITEST_ANY, &switches); litest_add_ranged("switch:toggle", switch_down_on_init, LITEST_SWITCH, LITEST_ANY, &switches); litest_add("switch:toggle", switch_not_down_on_init, LITEST_SWITCH, LITEST_ANY); - litest_add("lid:disable_touchpad", lid_disable_touchpad, LITEST_SWITCH, LITEST_ANY); - litest_add("lid:disable_touchpad", lid_disable_touchpad_during_touch, LITEST_SWITCH, LITEST_ANY); - litest_add("lid:disable_touchpad", lid_disable_touchpad_edge_scroll, LITEST_SWITCH, LITEST_ANY); - litest_add("lid:disable_touchpad", lid_disable_touchpad_edge_scroll_interrupt, LITEST_SWITCH, LITEST_ANY); - litest_add("lid:disable_touchpad", lid_disable_touchpad_already_open, LITEST_SWITCH, LITEST_ANY); + litest_add_ranged("switch:touchpad", switch_disable_touchpad, LITEST_SWITCH, LITEST_ANY, &switches); + litest_add_ranged("switch:touchpad", switch_disable_touchpad_during_touch, LITEST_SWITCH, LITEST_ANY, &switches); + litest_add_ranged("switch:touchpad", switch_disable_touchpad_edge_scroll, LITEST_SWITCH, LITEST_ANY, &switches); + litest_add_ranged("switch:touchpad", switch_disable_touchpad_edge_scroll_interrupt, LITEST_SWITCH, LITEST_ANY, &switches); + litest_add_ranged("switch:touchpad", switch_disable_touchpad_already_open, LITEST_SWITCH, LITEST_ANY, &switches); + + litest_add_ranged_no_device("switch:keyboard", switch_suspend_with_keyboard, &switches); + litest_add_ranged_no_device("switch:touchpad", switch_suspend_with_touchpad, &switches); litest_add("lid:keyboard", lid_open_on_key, LITEST_SWITCH, LITEST_ANY); litest_add("lid:keyboard", lid_open_on_key_touchpad_enabled, LITEST_SWITCH, LITEST_ANY); - - litest_add_no_device("lid:keyboard", lid_suspend_with_keyboard); - litest_add_no_device("lid:disable_touchpad", lid_suspend_with_touchpad); - litest_add_for_device("lid:buggy", lid_update_hw_on_key, LITEST_LID_SWITCH_SURFACE3); litest_add_for_device("lid:buggy", lid_update_hw_on_key_closed_on_init, LITEST_LID_SWITCH_SURFACE3); - litest_add_for_device("lid:keypress", lid_key_press, LITEST_GPIO_KEYS); + + litest_add("tablet-mode:touchpad", tablet_mode_disable_touchpad_on_init, LITEST_SWITCH, LITEST_ANY); }