diff --git a/src/evdev-lid.c b/src/evdev-lid.c index fe98e6e1..1edb12b0 100644 --- a/src/evdev-lid.c +++ b/src/evdev-lid.c @@ -64,6 +64,23 @@ lid_switch_notify_toggle(struct lid_switch_dispatch *dispatch, } } +static void +lid_switch_update_kernel_state(struct lid_switch_dispatch *dispatch, + uint64_t time) +{ + int fd; + const struct input_event ev[2] = { + {{ 0, 0 }, EV_SW, SW_LID, 0 }, + {{ 0, 0 }, EV_SYN, SYN_REPORT, 0 }, + }; + + if (dispatch->reliability != RELIABILITY_WRITE_OPEN) + return; + + fd = libevdev_get_fd(dispatch->device->evdev); + (void)write(fd, ev, sizeof(ev)); +} + static void lid_switch_keyboard_event(uint64_t time, struct libinput_event *event, @@ -77,17 +94,7 @@ lid_switch_keyboard_event(uint64_t time, if (event->type != LIBINPUT_EVENT_KEYBOARD_KEY) return; - if (dispatch->reliability == RELIABILITY_WRITE_OPEN) { - int fd = libevdev_get_fd(dispatch->device->evdev); - struct input_event ev[2] = { - {{ 0, 0 }, EV_SW, SW_LID, 0 }, - {{ 0, 0 }, EV_SYN, SYN_REPORT, 0 }, - }; - - (void)write(fd, ev, sizeof(ev)); - /* In case write() fails, we sync the lid state manually - * regardless. */ - } + lid_switch_update_kernel_state(dispatch, time); /* Posting the event here means we preempt the keyboard events that * caused us to wake up, so the lid event is always passed on before @@ -246,11 +253,16 @@ lid_switch_interface_device_removed(struct evdev_device *device, struct lid_switch_dispatch *dispatch = lid_dispatch(device->dispatch); if (removed_device == dispatch->keyboard.keyboard) { + uint64_t time; + libinput_device_remove_event_listener( &dispatch->keyboard.listener); libinput_device_init_event_listener( &dispatch->keyboard.listener); dispatch->keyboard.keyboard = NULL; + + time = libinput_now(evdev_libinput_context(device)); + lid_switch_update_kernel_state(dispatch, time); } } diff --git a/test/test-lid.c b/test/test-lid.c index 4bf4c059..2257976e 100644 --- a/test/test-lid.c +++ b/test/test-lid.c @@ -555,6 +555,41 @@ START_TEST(lid_update_hw_on_key_closed_on_init) } END_TEST +START_TEST(lid_force_open_if_no_keyboard) +{ + struct litest_device *sw = litest_current_device(); + struct libinput *li; + struct litest_device *keyboard; + + litest_lid_action(sw, LIBINPUT_SWITCH_STATE_ON); + keyboard = litest_add_device(sw->libinput, LITEST_KEYBOARD); + + /* separate context for the right state on init */ + li = litest_create_context(); + libinput_path_add_device(li, + libevdev_uinput_get_devnode(sw->uinput)); + + /* We only have the switch device in this context, not the keyboard. + * So don't expect any switch event to be in the pipe and don't + * expect the event to change if we type or toggle the state + */ + while (libinput_next_event_type(li) != LIBINPUT_EVENT_NONE) { + ck_assert_int_ne(libinput_next_event_type(li), + LIBINPUT_EVENT_SWITCH_TOGGLE); + libinput_event_destroy(libinput_get_event(li)); + } + + litest_event(keyboard, EV_KEY, KEY_A, 1); + litest_event(keyboard, EV_SYN, SYN_REPORT, 0); + litest_event(keyboard, EV_KEY, KEY_A, 0); + litest_event(keyboard, EV_SYN, SYN_REPORT, 0); + litest_lid_action(sw, LIBINPUT_SWITCH_STATE_OFF); + litest_assert_empty_queue(li); + + libinput_unref(li); + litest_delete_device(keyboard); +} +END_TEST void litest_setup_tests_lid(void) { @@ -576,4 +611,5 @@ litest_setup_tests_lid(void) 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:buggy", lid_force_open_if_no_keyboard, LITEST_LID_SWITCH_SURFACE3); }