From: Peter Hutterer Date: Thu, 31 Jan 2019 01:09:53 +0000 (+1000) Subject: touchpad: release all button presses on device suspend X-Git-Tag: 1.12.901~71 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=caa8f3fe61b9eeb4a5c9d189da86f7c5e6b4500f;p=platform%2Fupstream%2Flibinput.git touchpad: release all button presses on device suspend This leaves a bug open, on a Lenovo T440 generation touchpad with top software buttons, the button will not be leased correctly. This is caused by device->is_suspended=true by the time we try to clear the state and the button events thus getting filtered. This used to affect all touchpads, this patch just moves it so it only affects the T440-like devices now. Fixes #233 Signed-off-by: Peter Hutterer --- diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 84c54413..69800e22 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -1143,31 +1143,32 @@ tp_notify_clickpadbutton(struct tp_dispatch *tp, enum libinput_button_state state) { /* If we've a trackpoint, send top buttons through the trackpoint */ - if (is_topbutton && tp->buttons.trackpoint) { - struct evdev_dispatch *dispatch = tp->buttons.trackpoint->dispatch; - struct input_event event; - struct input_event syn_report = {{ 0, 0 }, EV_SYN, SYN_REPORT, 0 }; - - event.time = us2tv(time); - event.type = EV_KEY; - event.code = button; - event.value = (state == LIBINPUT_BUTTON_STATE_PRESSED) ? 1 : 0; - syn_report.time = event.time; - dispatch->interface->process(dispatch, - tp->buttons.trackpoint, - &event, - time); - dispatch->interface->process(dispatch, - tp->buttons.trackpoint, - &syn_report, - time); - return 1; + if (tp->buttons.trackpoint) { + if (is_topbutton) { + struct evdev_dispatch *dispatch = tp->buttons.trackpoint->dispatch; + struct input_event event; + struct input_event syn_report = {{ 0, 0 }, EV_SYN, SYN_REPORT, 0 }; + + event.time = us2tv(time); + event.type = EV_KEY; + event.code = button; + event.value = (state == LIBINPUT_BUTTON_STATE_PRESSED) ? 1 : 0; + syn_report.time = event.time; + dispatch->interface->process(dispatch, + tp->buttons.trackpoint, + &event, + time); + dispatch->interface->process(dispatch, + tp->buttons.trackpoint, + &syn_report, + time); + return 1; + } + /* Ignore button events not for the trackpoint while suspended */ + if (tp->device->is_suspended) + return 0; } - /* Ignore button events not for the trackpoint while suspended */ - if (tp->device->is_suspended) - return 0; - /* A button click always terminates edge scrolling, even if we * don't end up sending a button event. */ tp_edge_scroll_stop_events(tp, time); diff --git a/test/test-device.c b/test/test-device.c index 134a709d..43de33da 100644 --- a/test/test-device.c +++ b/test/test-device.c @@ -1496,6 +1496,72 @@ START_TEST(device_seat_phys_name) } END_TEST +START_TEST(device_button_down_remove) +{ + struct litest_device *lidev = litest_current_device(); + struct litest_device *dev; + struct libinput *li; + + for (int code = 0; code < KEY_MAX; code++) { + struct libinput_event *event; + struct libinput_event_pointer *p; + bool have_down = false, + have_up = false; + const char *keyname; + int button_down = 0, button_up = 0; + + keyname = libevdev_event_code_get_name(EV_KEY, code); + if (!keyname || + !strneq(keyname, "BTN_", 4) || + strneq(keyname, "BTN_TOOL_", 9)) + continue; + + if (!libevdev_has_event_code(lidev->evdev, EV_KEY, code)) + continue; + + li = litest_create_context(); + dev = litest_add_device(li, lidev->which); + litest_drain_events(li); + + /* Clickpads require a touch down to trigger the button + * press */ + if (libevdev_has_property(lidev->evdev, INPUT_PROP_BUTTONPAD)) { + litest_touch_down(dev, 0, 20, 90); + libinput_dispatch(li); + } + + litest_event(dev, EV_KEY, code, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + + litest_delete_device(dev); + libinput_dispatch(li); + + while ((event = libinput_get_event(li))) { + if (libinput_event_get_type(event) != + LIBINPUT_EVENT_POINTER_BUTTON) { + libinput_event_destroy(event); + continue; + } + + p = libinput_event_get_pointer_event(event); + if (libinput_event_pointer_get_button_state(p)) { + ck_assert(button_down == 0); + button_down = libinput_event_pointer_get_button(p); + } else { + ck_assert(button_up == 0); + button_up = libinput_event_pointer_get_button(p); + ck_assert_int_eq(button_down, button_up); + } + libinput_event_destroy(event); + } + + libinput_unref(li); + ck_assert_int_eq(have_down, have_up); + } +} +END_TEST + TEST_COLLECTION(device) { struct range abs_range = { 0, ABS_MISC }; @@ -1571,4 +1637,6 @@ TEST_COLLECTION(device) litest_add("device:output", device_no_output, LITEST_KEYS, LITEST_ANY); litest_add("device:seat", device_seat_phys_name, LITEST_ANY, LITEST_ANY); + + litest_add("device:button", device_button_down_remove, LITEST_BUTTON, LITEST_ANY); }