diff --git a/src/evdev.c b/src/evdev.c index fe42b44f..861a2987 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -154,14 +154,17 @@ evdev_pointer_notify_physical_button(struct evdev_device *device, state)) return; - evdev_pointer_notify_button(device, time, button, state); + evdev_pointer_notify_button(device, + time, + (unsigned int)button, + state); } -void -evdev_pointer_notify_button(struct evdev_device *device, - uint64_t time, - int button, - enum libinput_button_state state) +static void +evdev_pointer_post_button(struct evdev_device *device, + uint64_t time, + unsigned int button, + enum libinput_button_state state) { int down_count; @@ -182,6 +185,59 @@ evdev_pointer_notify_button(struct evdev_device *device, } +static void +evdev_button_scroll_timeout(uint64_t time, void *data) +{ + struct evdev_device *device = data; + + device->scroll.button_scroll_active = true; +} + +static void +evdev_button_scroll_button(struct evdev_device *device, + uint64_t time, int is_press) +{ + device->scroll.button_scroll_btn_pressed = is_press; + + if (is_press) { + libinput_timer_set(&device->scroll.timer, + time + DEFAULT_MIDDLE_BUTTON_SCROLL_TIMEOUT); + device->scroll.button_down_time = time; + } else { + libinput_timer_cancel(&device->scroll.timer); + if (device->scroll.button_scroll_active) { + evdev_stop_scroll(device, time, + LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS); + device->scroll.button_scroll_active = false; + } else { + /* If the button is released quickly enough emit the + * button press/release events. */ + evdev_pointer_post_button(device, + device->scroll.button_down_time, + device->scroll.button, + LIBINPUT_BUTTON_STATE_PRESSED); + evdev_pointer_post_button(device, time, + device->scroll.button, + LIBINPUT_BUTTON_STATE_RELEASED); + } + } +} + +void +evdev_pointer_notify_button(struct evdev_device *device, + uint64_t time, + unsigned int button, + enum libinput_button_state state) +{ + if (device->scroll.method == LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN && + button == device->scroll.button) { + evdev_button_scroll_button(device, time, state); + return; + } + + evdev_pointer_post_button(device, time, button, state); +} + void evdev_device_led_update(struct evdev_device *device, enum libinput_led leds) { @@ -482,44 +538,6 @@ get_key_type(uint16_t code) return EVDEV_KEY_TYPE_NONE; } -static void -evdev_button_scroll_timeout(uint64_t time, void *data) -{ - struct evdev_device *device = data; - - device->scroll.button_scroll_active = true; -} - -static void -evdev_button_scroll_button(struct evdev_device *device, - uint64_t time, int is_press) -{ - device->scroll.button_scroll_btn_pressed = is_press; - - if (is_press) { - libinput_timer_set(&device->scroll.timer, - time + DEFAULT_MIDDLE_BUTTON_SCROLL_TIMEOUT); - device->scroll.button_down_time = time; - } else { - libinput_timer_cancel(&device->scroll.timer); - if (device->scroll.button_scroll_active) { - evdev_stop_scroll(device, time, - LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS); - device->scroll.button_scroll_active = false; - } else { - /* If the button is released quickly enough emit the - * button press/release events. */ - evdev_pointer_notify_button(device, - device->scroll.button_down_time, - device->scroll.button, - LIBINPUT_BUTTON_STATE_PRESSED); - evdev_pointer_notify_button(device, time, - device->scroll.button, - LIBINPUT_BUTTON_STATE_RELEASED); - } - } -} - static void evdev_process_touch_button(struct evdev_device *device, uint64_t time, int value) @@ -580,11 +598,6 @@ evdev_process_key(struct evdev_device *device, LIBINPUT_KEY_STATE_RELEASED); break; case EVDEV_KEY_TYPE_BUTTON: - if (device->scroll.method == LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN && - e->code == device->scroll.button) { - evdev_button_scroll_button(device, time, e->value); - break; - } evdev_pointer_notify_physical_button( device, time, diff --git a/src/evdev.h b/src/evdev.h index 488ef769..76eeb8c2 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -398,7 +398,7 @@ evdev_keyboard_notify_key(struct evdev_device *device, void evdev_pointer_notify_button(struct evdev_device *device, uint64_t time, - int button, + unsigned int button, enum libinput_button_state state); void evdev_pointer_notify_physical_button(struct evdev_device *device, diff --git a/test/pointer.c b/test/pointer.c index 8c7ad462..2a37b053 100644 --- a/test/pointer.c +++ b/test/pointer.c @@ -923,6 +923,58 @@ START_TEST(pointer_scroll_button_no_event_before_timeout) } END_TEST +START_TEST(pointer_scroll_button_middle_emulation) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + struct libinput *li = dev->libinput; + enum libinput_config_status status; + int i; + + status = libinput_device_config_middle_emulation_set_enabled(device, + LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED); + + if (status == LIBINPUT_CONFIG_STATUS_UNSUPPORTED) + return; + + status = libinput_device_config_scroll_set_method(device, + LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + status = libinput_device_config_scroll_set_button(device, BTN_MIDDLE); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + litest_drain_events(li); + + litest_button_click(dev, BTN_LEFT, 1); + litest_button_click(dev, BTN_RIGHT, 1); + libinput_dispatch(li); + litest_timeout_buttonscroll(); + libinput_dispatch(li); + + for (i = 0; i < 10; i++) { + litest_event(dev, EV_REL, REL_Y, -1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + } + + libinput_dispatch(li); + + litest_button_click(dev, BTN_LEFT, 0); + litest_button_click(dev, BTN_RIGHT, 0); + libinput_dispatch(li); + + litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, -1); + litest_assert_empty_queue(li); + + /* Restore default scroll behavior */ + libinput_device_config_scroll_set_method(dev->libinput_device, + libinput_device_config_scroll_get_default_method( + dev->libinput_device)); + libinput_device_config_scroll_set_button(dev->libinput_device, + libinput_device_config_scroll_get_default_button( + dev->libinput_device)); +} +END_TEST + START_TEST(pointer_scroll_nowheel_defaults) { struct litest_device *dev = litest_current_device(); @@ -1631,6 +1683,7 @@ litest_setup_tests(void) litest_add("pointer:scroll", pointer_scroll_wheel, LITEST_WHEEL, LITEST_TABLET); litest_add("pointer:scroll", pointer_scroll_button, LITEST_RELATIVE|LITEST_BUTTON, LITEST_ANY); litest_add("pointer:scroll", pointer_scroll_button_no_event_before_timeout, LITEST_RELATIVE|LITEST_BUTTON, LITEST_ANY); + litest_add("pointer:scroll", pointer_scroll_button_middle_emulation, LITEST_RELATIVE|LITEST_BUTTON, LITEST_ANY); litest_add("pointer:scroll", pointer_scroll_nowheel_defaults, LITEST_RELATIVE|LITEST_BUTTON, LITEST_WHEEL); litest_add("pointer:scroll", pointer_scroll_natural_defaults, LITEST_WHEEL, LITEST_TABLET); litest_add("pointer:scroll", pointer_scroll_natural_enable_config, LITEST_WHEEL, LITEST_TABLET);