mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-25 22:10:05 +01:00
Merge branch 'wip/logitech-marble-mouse-middleemulation'
This commit is contained in:
commit
4ce0fe4a2d
8 changed files with 330 additions and 55 deletions
89
src/evdev.c
89
src/evdev.c
|
|
@ -48,7 +48,7 @@
|
|||
#endif
|
||||
|
||||
#define DEFAULT_WHEEL_CLICK_ANGLE 15
|
||||
#define DEFAULT_MIDDLE_BUTTON_SCROLL_TIMEOUT ms2us(200)
|
||||
#define DEFAULT_BUTTON_SCROLL_TIMEOUT ms2us(200)
|
||||
|
||||
enum evdev_key_type {
|
||||
EVDEV_KEY_TYPE_NONE,
|
||||
|
|
@ -221,27 +221,51 @@ evdev_button_scroll_timeout(uint64_t time, void *data)
|
|||
{
|
||||
struct evdev_device *device = data;
|
||||
|
||||
device->scroll.button_scroll_active = true;
|
||||
device->scroll.button_scroll_state = BUTTONSCROLL_READY;
|
||||
}
|
||||
|
||||
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);
|
||||
enum timer_flags flags = TIMER_FLAG_NONE;
|
||||
|
||||
device->scroll.button_scroll_state = BUTTONSCROLL_BUTTON_DOWN;
|
||||
|
||||
/* Special case: if middle button emulation is enabled and
|
||||
* our scroll button is the left or right button, we only
|
||||
* get here *after* the middle button timeout has expired
|
||||
* for that button press. The time passed is the button-down
|
||||
* time though (which is in the past), so we have to allow
|
||||
* for a negative timer to be set.
|
||||
*/
|
||||
if (device->middlebutton.enabled &&
|
||||
(device->scroll.button == BTN_LEFT ||
|
||||
device->scroll.button == BTN_RIGHT)) {
|
||||
flags = TIMER_FLAG_ALLOW_NEGATIVE;
|
||||
}
|
||||
|
||||
libinput_timer_set_flags(&device->scroll.timer,
|
||||
time + DEFAULT_BUTTON_SCROLL_TIMEOUT,
|
||||
flags);
|
||||
device->scroll.button_down_time = time;
|
||||
log_debug(evdev_libinput_context(device),
|
||||
"btnscroll: down\n");
|
||||
} 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
|
||||
switch(device->scroll.button_scroll_state) {
|
||||
case BUTTONSCROLL_IDLE:
|
||||
log_bug_libinput(evdev_libinput_context(device),
|
||||
"invalid state IDLE for button up\n");
|
||||
break;
|
||||
case BUTTONSCROLL_BUTTON_DOWN:
|
||||
case BUTTONSCROLL_READY:
|
||||
log_debug(evdev_libinput_context(device),
|
||||
"btnscroll: cancel\n");
|
||||
|
||||
/* If the button is released quickly enough or
|
||||
* without scroll events, emit the
|
||||
* button press/release events. */
|
||||
evdev_pointer_post_button(device,
|
||||
device->scroll.button_down_time,
|
||||
|
|
@ -250,7 +274,16 @@ evdev_button_scroll_button(struct evdev_device *device,
|
|||
evdev_pointer_post_button(device, time,
|
||||
device->scroll.button,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
break;
|
||||
case BUTTONSCROLL_SCROLLING:
|
||||
log_debug(evdev_libinput_context(device),
|
||||
"btnscroll: up\n");
|
||||
evdev_stop_scroll(device, time,
|
||||
LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS);
|
||||
break;
|
||||
}
|
||||
|
||||
device->scroll.button_scroll_state = BUTTONSCROLL_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -359,18 +392,29 @@ evdev_post_trackpoint_scroll(struct evdev_device *device,
|
|||
struct normalized_coords unaccel,
|
||||
uint64_t time)
|
||||
{
|
||||
if (device->scroll.method != LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN ||
|
||||
!device->scroll.button_scroll_btn_pressed)
|
||||
if (device->scroll.method != LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN)
|
||||
return false;
|
||||
|
||||
if (device->scroll.button_scroll_active)
|
||||
switch(device->scroll.button_scroll_state) {
|
||||
case BUTTONSCROLL_IDLE:
|
||||
return false;
|
||||
case BUTTONSCROLL_BUTTON_DOWN:
|
||||
/* if the button is down but scroll is not active, we're within the
|
||||
timeout where swallow motion events but don't post scroll buttons */
|
||||
log_debug(evdev_libinput_context(device),
|
||||
"btnscroll: discarding\n");
|
||||
return true;
|
||||
case BUTTONSCROLL_READY:
|
||||
device->scroll.button_scroll_state = BUTTONSCROLL_SCROLLING;
|
||||
/* fallthrough */
|
||||
case BUTTONSCROLL_SCROLLING:
|
||||
evdev_post_scroll(device, time,
|
||||
LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS,
|
||||
&unaccel);
|
||||
/* if the button is down but scroll is not active, we're within the
|
||||
timeout where swallow motion events but don't post scroll buttons */
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
assert(!"invalid scroll button state");
|
||||
}
|
||||
|
||||
static inline bool
|
||||
|
|
@ -2245,6 +2289,7 @@ evdev_read_model_flags(struct evdev_device *device)
|
|||
MODEL(HP_ZBOOK_STUDIO_G3),
|
||||
MODEL(HP_PAVILION_DM4_TOUCHPAD),
|
||||
MODEL(APPLE_TOUCHPAD_ONEBUTTON),
|
||||
MODEL(LOGITECH_MARBLE_MOUSE),
|
||||
#undef MODEL
|
||||
{ "ID_INPUT_TRACKBALL", EVDEV_MODEL_TRACKBALL },
|
||||
{ NULL, EVDEV_MODEL_DEFAULT },
|
||||
|
|
@ -2643,7 +2688,9 @@ evdev_configure_device(struct evdev_device *device)
|
|||
/* want natural-scroll config option */
|
||||
device->scroll.natural_scrolling_enabled = true;
|
||||
/* want button scrolling config option */
|
||||
device->scroll.want_button = 1;
|
||||
if (libevdev_has_event_code(evdev, EV_REL, REL_X) ||
|
||||
libevdev_has_event_code(evdev, EV_REL, REL_Y))
|
||||
device->scroll.want_button = 1;
|
||||
}
|
||||
|
||||
if (udev_tags & EVDEV_UDEV_TAG_KEYBOARD) {
|
||||
|
|
@ -2842,6 +2889,10 @@ evdev_pre_configure_model_quirks(struct evdev_device *device)
|
|||
* https://bugs.freedesktop.org/show_bug.cgi?id=98100 */
|
||||
if (device->model_flags & EVDEV_MODEL_HP_ZBOOK_STUDIO_G3)
|
||||
libevdev_set_abs_maximum(device->evdev, ABS_MT_SLOT, 1);
|
||||
|
||||
/* Logitech Marble Mouse claims to have a middle button */
|
||||
if (device->model_flags & EVDEV_MODEL_LOGITECH_MARBLE_MOUSE)
|
||||
libevdev_disable_event_code(device->evdev, EV_KEY, BTN_MIDDLE);
|
||||
}
|
||||
|
||||
struct evdev_device *
|
||||
|
|
|
|||
11
src/evdev.h
11
src/evdev.h
|
|
@ -126,6 +126,14 @@ enum evdev_device_model {
|
|||
EVDEV_MODEL_HP_ZBOOK_STUDIO_G3 = (1 << 23),
|
||||
EVDEV_MODEL_HP_PAVILION_DM4_TOUCHPAD = (1 << 24),
|
||||
EVDEV_MODEL_APPLE_TOUCHPAD_ONEBUTTON = (1 << 25),
|
||||
EVDEV_MODEL_LOGITECH_MARBLE_MOUSE = (1 << 26),
|
||||
};
|
||||
|
||||
enum evdev_button_scroll_state {
|
||||
BUTTONSCROLL_IDLE,
|
||||
BUTTONSCROLL_BUTTON_DOWN, /* button is down */
|
||||
BUTTONSCROLL_READY, /* ready for scroll events */
|
||||
BUTTONSCROLL_SCROLLING, /* have sent scroll events */
|
||||
};
|
||||
|
||||
struct mt_slot {
|
||||
|
|
@ -187,8 +195,7 @@ struct evdev_device {
|
|||
uint32_t want_button;
|
||||
/* Checks if buttons are down and commits the setting */
|
||||
void (*change_scroll_method)(struct evdev_device *device);
|
||||
bool button_scroll_active;
|
||||
bool button_scroll_btn_pressed;
|
||||
enum evdev_button_scroll_state button_scroll_state;
|
||||
double threshold;
|
||||
double direction_lock_threshold;
|
||||
uint32_t direction;
|
||||
|
|
|
|||
22
src/timer.c
22
src/timer.c
|
|
@ -67,19 +67,23 @@ libinput_timer_arm_timer_fd(struct libinput *libinput)
|
|||
}
|
||||
|
||||
void
|
||||
libinput_timer_set(struct libinput_timer *timer, uint64_t expire)
|
||||
libinput_timer_set_flags(struct libinput_timer *timer,
|
||||
uint64_t expire,
|
||||
uint32_t flags)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
uint64_t now = libinput_now(timer->libinput);
|
||||
if (expire < now)
|
||||
log_bug_libinput(timer->libinput,
|
||||
"timer offset negative (-%" PRIu64 ")\n",
|
||||
now - expire);
|
||||
else if ((expire - now) > ms2us(5000))
|
||||
if (expire < now) {
|
||||
if ((flags & TIMER_FLAG_ALLOW_NEGATIVE) == 0)
|
||||
log_bug_libinput(timer->libinput,
|
||||
"timer offset negative (-%" PRIu64 ")\n",
|
||||
now - expire);
|
||||
} else if ((expire - now) > ms2us(5000)) {
|
||||
log_bug_libinput(timer->libinput,
|
||||
"timer offset more than 5s, now %"
|
||||
PRIu64 " expire %" PRIu64 "\n",
|
||||
now, expire);
|
||||
}
|
||||
#endif
|
||||
|
||||
assert(expire);
|
||||
|
|
@ -91,6 +95,12 @@ libinput_timer_set(struct libinput_timer *timer, uint64_t expire)
|
|||
libinput_timer_arm_timer_fd(timer->libinput);
|
||||
}
|
||||
|
||||
void
|
||||
libinput_timer_set(struct libinput_timer *timer, uint64_t expire)
|
||||
{
|
||||
libinput_timer_set_flags(timer, expire, TIMER_FLAG_NONE);
|
||||
}
|
||||
|
||||
void
|
||||
libinput_timer_cancel(struct libinput_timer *timer)
|
||||
{
|
||||
|
|
|
|||
10
src/timer.h
10
src/timer.h
|
|
@ -47,6 +47,16 @@ libinput_timer_init(struct libinput_timer *timer, struct libinput *libinput,
|
|||
void
|
||||
libinput_timer_set(struct libinput_timer *timer, uint64_t expire);
|
||||
|
||||
enum timer_flags {
|
||||
TIMER_FLAG_NONE = 0,
|
||||
TIMER_FLAG_ALLOW_NEGATIVE = (1 << 0),
|
||||
};
|
||||
|
||||
void
|
||||
libinput_timer_set_flags(struct libinput_timer *timer,
|
||||
uint64_t expire,
|
||||
uint32_t flags);
|
||||
|
||||
void
|
||||
libinput_timer_cancel(struct libinput_timer *timer);
|
||||
|
||||
|
|
|
|||
|
|
@ -1482,6 +1482,18 @@ START_TEST(device_quirks_apple_magicmouse)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_quirks_logitech_marble_mouse)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
ck_assert(!libinput_device_pointer_has_button(dev->libinput_device,
|
||||
BTN_MIDDLE));
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_capability_at_least_one)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -1648,6 +1660,7 @@ litest_setup_tests_device(void)
|
|||
litest_add_for_device("device:quirks", device_quirks_no_abs_mt_y, LITEST_ANKER_MOUSE_KBD);
|
||||
litest_add_for_device("device:quirks", device_quirks_cyborg_rat_mode_button, LITEST_CYBORG_RAT);
|
||||
litest_add_for_device("device:quirks", device_quirks_apple_magicmouse, LITEST_MAGICMOUSE);
|
||||
litest_add_for_device("device:quirks", device_quirks_logitech_marble_mouse, LITEST_LOGITECH_TRACKBALL);
|
||||
|
||||
litest_add("device:capability", device_capability_at_least_one, LITEST_ANY, LITEST_ANY);
|
||||
litest_add("device:capability", device_capability_check_invalid, LITEST_ANY, LITEST_ANY);
|
||||
|
|
|
|||
|
|
@ -371,13 +371,15 @@ START_TEST(pointer_button)
|
|||
test_button_event(dev, BTN_LEFT, 1);
|
||||
test_button_event(dev, BTN_LEFT, 0);
|
||||
|
||||
if (libevdev_has_event_code(dev->evdev, EV_KEY, BTN_RIGHT)) {
|
||||
if (libinput_device_pointer_has_button(dev->libinput_device,
|
||||
BTN_RIGHT)) {
|
||||
test_button_event(dev, BTN_RIGHT, 1);
|
||||
test_button_event(dev, BTN_RIGHT, 0);
|
||||
}
|
||||
|
||||
/* Skip middle button test on trackpoints (used for scrolling) */
|
||||
if (libevdev_has_event_code(dev->evdev, EV_KEY, BTN_MIDDLE)) {
|
||||
if (libinput_device_pointer_has_button(dev->libinput_device,
|
||||
BTN_MIDDLE)) {
|
||||
test_button_event(dev, BTN_MIDDLE, 1);
|
||||
test_button_event(dev, BTN_MIDDLE, 0);
|
||||
}
|
||||
|
|
@ -904,9 +906,7 @@ START_TEST(pointer_left_handed)
|
|||
BTN_LEFT,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
|
||||
if (libevdev_has_event_code(dev->evdev,
|
||||
EV_KEY,
|
||||
BTN_MIDDLE)) {
|
||||
if (libinput_device_pointer_has_button(d, BTN_MIDDLE)) {
|
||||
litest_button_click(dev, BTN_MIDDLE, 1);
|
||||
litest_button_click(dev, BTN_MIDDLE, 0);
|
||||
litest_assert_button_event(li,
|
||||
|
|
@ -952,6 +952,11 @@ START_TEST(pointer_left_handed_during_click_multiple_buttons)
|
|||
struct libinput *li = dev->libinput;
|
||||
enum libinput_config_status status;
|
||||
|
||||
if (!libinput_device_pointer_has_button(d, BTN_MIDDLE))
|
||||
return;
|
||||
|
||||
litest_disable_middleemu(dev);
|
||||
|
||||
litest_drain_events(li);
|
||||
litest_button_click(dev, BTN_LEFT, 1);
|
||||
libinput_dispatch(li);
|
||||
|
|
@ -1001,11 +1006,15 @@ START_TEST(pointer_scroll_button)
|
|||
litest_button_scroll(dev, BTN_LEFT, -9, 1);
|
||||
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, -9);
|
||||
|
||||
/* scroll smaller than the threshold should not generate events */
|
||||
/* scroll smaller than the threshold should not generate axis events */
|
||||
litest_button_scroll(dev, BTN_LEFT, 1, 1);
|
||||
/* left press without movement should not generate events */
|
||||
litest_button_scroll(dev, BTN_LEFT, 0, 0);
|
||||
|
||||
litest_button_scroll(dev, BTN_LEFT, 0, 0);
|
||||
litest_assert_button_event(li, BTN_LEFT,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_button_event(li,
|
||||
BTN_LEFT,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
/* Restore default scroll behavior */
|
||||
|
|
@ -1046,6 +1055,11 @@ START_TEST(pointer_scroll_button_no_event_before_timeout)
|
|||
struct libinput *li = device->libinput;
|
||||
int i;
|
||||
|
||||
if (!libinput_device_pointer_has_button(device->libinput_device,
|
||||
BTN_MIDDLE))
|
||||
return;
|
||||
|
||||
litest_disable_middleemu(device);
|
||||
disable_button_scrolling(device);
|
||||
|
||||
libinput_device_config_scroll_set_method(device->libinput_device,
|
||||
|
|
@ -1066,6 +1080,12 @@ START_TEST(pointer_scroll_button_no_event_before_timeout)
|
|||
litest_timeout_buttonscroll();
|
||||
libinput_dispatch(li);
|
||||
litest_button_click(device, BTN_LEFT, false);
|
||||
|
||||
litest_assert_button_event(li, BTN_LEFT,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_button_event(li,
|
||||
BTN_LEFT,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
litest_assert_empty_queue(li);
|
||||
}
|
||||
END_TEST
|
||||
|
|
@ -1126,19 +1146,41 @@ START_TEST(pointer_scroll_nowheel_defaults)
|
|||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput_device *device = dev->libinput_device;
|
||||
enum libinput_config_scroll_method method;
|
||||
enum libinput_config_scroll_method method, expected;
|
||||
uint32_t button;
|
||||
|
||||
/* button scrolling is only enabled if there is a
|
||||
middle button present */
|
||||
if (libinput_device_pointer_has_button(device, BTN_MIDDLE))
|
||||
expected = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN;
|
||||
else
|
||||
expected = LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
|
||||
|
||||
method = libinput_device_config_scroll_get_method(device);
|
||||
ck_assert_int_eq(method, LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN);
|
||||
ck_assert_int_eq(method, expected);
|
||||
|
||||
method = libinput_device_config_scroll_get_default_method(device);
|
||||
ck_assert_int_eq(method, LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN);
|
||||
ck_assert_int_eq(method, expected);
|
||||
|
||||
button = libinput_device_config_scroll_get_button(device);
|
||||
ck_assert_int_eq(button, BTN_MIDDLE);
|
||||
button = libinput_device_config_scroll_get_default_button(device);
|
||||
ck_assert_int_eq(button, BTN_MIDDLE);
|
||||
if (method == LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) {
|
||||
button = libinput_device_config_scroll_get_button(device);
|
||||
ck_assert_int_eq(button, BTN_MIDDLE);
|
||||
button = libinput_device_config_scroll_get_default_button(device);
|
||||
ck_assert_int_eq(button, BTN_MIDDLE);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(pointer_scroll_defaults_logitech_marble)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput_device *device = dev->libinput_device;
|
||||
enum libinput_config_scroll_method method;
|
||||
|
||||
method = libinput_device_config_scroll_get_method(device);
|
||||
ck_assert_int_eq(method, LIBINPUT_CONFIG_SCROLL_NO_SCROLL);
|
||||
method = libinput_device_config_scroll_get_default_method(device);
|
||||
ck_assert_int_eq(method, LIBINPUT_CONFIG_SCROLL_NO_SCROLL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
|
@ -1614,7 +1656,8 @@ START_TEST(middlebutton_middleclick)
|
|||
|
||||
disable_button_scrolling(device);
|
||||
|
||||
if (!libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE))
|
||||
if (!libinput_device_pointer_has_button(device->libinput_device,
|
||||
BTN_MIDDLE))
|
||||
return;
|
||||
|
||||
status = libinput_device_config_middle_emulation_set_enabled(
|
||||
|
|
@ -1678,7 +1721,8 @@ START_TEST(middlebutton_middleclick_during)
|
|||
|
||||
disable_button_scrolling(device);
|
||||
|
||||
if (!libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE))
|
||||
if (!libinput_device_pointer_has_button(device->libinput_device,
|
||||
BTN_MIDDLE))
|
||||
return;
|
||||
|
||||
status = libinput_device_config_middle_emulation_set_enabled(
|
||||
|
|
@ -1740,22 +1784,21 @@ START_TEST(middlebutton_default_enabled)
|
|||
struct libinput_device *device = dev->libinput_device;
|
||||
enum libinput_config_status status;
|
||||
int available;
|
||||
enum libinput_config_middle_emulation_state deflt, state;
|
||||
enum libinput_config_middle_emulation_state state;
|
||||
|
||||
if (!libinput_device_pointer_has_button(dev->libinput_device,
|
||||
BTN_MIDDLE))
|
||||
return;
|
||||
|
||||
available = libinput_device_config_middle_emulation_is_available(device);
|
||||
ck_assert(available);
|
||||
|
||||
if (libevdev_has_event_code(dev->evdev, EV_KEY, BTN_MIDDLE))
|
||||
deflt = LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED;
|
||||
else
|
||||
deflt = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED;
|
||||
|
||||
state = libinput_device_config_middle_emulation_get_enabled(device);
|
||||
ck_assert_int_eq(state, deflt);
|
||||
ck_assert_int_eq(state, LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED);
|
||||
|
||||
state = libinput_device_config_middle_emulation_get_default_enabled(
|
||||
device);
|
||||
ck_assert_int_eq(state, deflt);
|
||||
ck_assert_int_eq(state, LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED);
|
||||
|
||||
status = libinput_device_config_middle_emulation_set_enabled(device,
|
||||
LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED);
|
||||
|
|
@ -1815,7 +1858,7 @@ START_TEST(middlebutton_default_touchpad)
|
|||
available = libinput_device_config_middle_emulation_is_available(device);
|
||||
ck_assert(!available);
|
||||
|
||||
if (libevdev_has_event_code(dev->evdev, EV_KEY, BTN_MIDDLE))
|
||||
if (libinput_device_pointer_has_button(device, BTN_MIDDLE))
|
||||
return;
|
||||
|
||||
state = libinput_device_config_middle_emulation_get_enabled(
|
||||
|
|
@ -1870,6 +1913,134 @@ START_TEST(middlebutton_default_disabled)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(middlebutton_button_scrolling)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput_device *device = dev->libinput_device;
|
||||
struct libinput *li = dev->libinput;
|
||||
enum libinput_config_status status;
|
||||
struct libinput_event *ev;
|
||||
struct libinput_event_pointer *pev;
|
||||
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);
|
||||
if (status == LIBINPUT_CONFIG_STATUS_UNSUPPORTED)
|
||||
return;
|
||||
|
||||
status = libinput_device_config_scroll_set_button(device, BTN_LEFT);
|
||||
if (status == LIBINPUT_CONFIG_STATUS_UNSUPPORTED)
|
||||
return;
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_event(dev, EV_KEY, BTN_LEFT, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
/* middle emulation discards */
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_timeout_middlebutton();
|
||||
libinput_dispatch(li);
|
||||
|
||||
/* scroll discards */
|
||||
litest_assert_empty_queue(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);
|
||||
}
|
||||
|
||||
ev = libinput_get_event(li);
|
||||
do {
|
||||
pev = litest_is_axis_event(ev,
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
|
||||
LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS);
|
||||
ck_assert_double_gt(libinput_event_pointer_get_axis_value(pev,
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL),
|
||||
0.0);
|
||||
libinput_event_destroy(ev);
|
||||
ev = libinput_get_event(li);
|
||||
} while (ev);
|
||||
|
||||
litest_event(dev, EV_KEY, BTN_LEFT, 0);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
ev = libinput_get_event(li);
|
||||
pev = litest_is_axis_event(ev,
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
|
||||
LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS);
|
||||
ck_assert_double_eq(libinput_event_pointer_get_axis_value(pev,
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL),
|
||||
0.0);
|
||||
libinput_event_destroy(ev);
|
||||
|
||||
/* no button release */
|
||||
litest_assert_empty_queue(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(middlebutton_button_scrolling_middle)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput_device *device = dev->libinput_device;
|
||||
struct libinput *li = dev->libinput;
|
||||
enum libinput_config_status status;
|
||||
|
||||
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);
|
||||
if (status == LIBINPUT_CONFIG_STATUS_UNSUPPORTED)
|
||||
return;
|
||||
|
||||
status = libinput_device_config_scroll_set_button(device, BTN_LEFT);
|
||||
if (status == LIBINPUT_CONFIG_STATUS_UNSUPPORTED)
|
||||
return;
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
/* button scrolling should not stop middle emulation */
|
||||
|
||||
litest_event(dev, EV_KEY, BTN_LEFT, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_event(dev, EV_KEY, BTN_RIGHT, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_assert_button_event(li,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
|
||||
litest_event(dev, EV_KEY, BTN_LEFT, 0);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_event(dev, EV_KEY, BTN_RIGHT, 0);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_assert_button_event(li,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(pointer_time_usec)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -1915,10 +2086,12 @@ litest_setup_tests_pointer(void)
|
|||
litest_add_for_device("pointer:button", pointer_button_has_no_button, LITEST_KEYBOARD);
|
||||
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_noscroll, LITEST_ABSOLUTE|LITEST_BUTTON, LITEST_RELATIVE);
|
||||
litest_add("pointer:scroll", pointer_scroll_button_noscroll, LITEST_ANY, LITEST_RELATIVE|LITEST_BUTTON);
|
||||
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_for_device("pointer:scroll", pointer_scroll_defaults_logitech_marble , LITEST_LOGITECH_TRACKBALL);
|
||||
litest_add("pointer:scroll", pointer_scroll_natural_defaults, LITEST_WHEEL, LITEST_TABLET);
|
||||
litest_add("pointer:scroll", pointer_scroll_natural_defaults_noscroll, LITEST_ANY, LITEST_WHEEL);
|
||||
litest_add("pointer:scroll", pointer_scroll_natural_enable_config, LITEST_WHEEL, LITEST_TABLET);
|
||||
|
|
@ -1955,6 +2128,8 @@ litest_setup_tests_pointer(void)
|
|||
litest_add("pointer:middlebutton", middlebutton_default_touchpad, LITEST_TOUCHPAD, LITEST_CLICKPAD);
|
||||
litest_add("pointer:middlebutton", middlebutton_default_disabled, LITEST_ANY, LITEST_BUTTON);
|
||||
litest_add_for_device("pointer:middlebutton", middlebutton_default_alps, LITEST_ALPS_SEMI_MT);
|
||||
litest_add("pointer:middlebutton", middlebutton_button_scrolling, LITEST_RELATIVE|LITEST_BUTTON, LITEST_CLICKPAD);
|
||||
litest_add("pointer:middlebutton", middlebutton_button_scrolling_middle, LITEST_RELATIVE|LITEST_BUTTON, LITEST_CLICKPAD);
|
||||
|
||||
litest_add_ranged("pointer:state", pointer_absolute_initial_state, LITEST_ABSOLUTE, LITEST_ANY, &axis_range);
|
||||
|
||||
|
|
|
|||
|
|
@ -85,10 +85,15 @@ START_TEST(trackpoint_scroll)
|
|||
litest_button_scroll(dev, BTN_MIDDLE, -9, 1);
|
||||
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, -9);
|
||||
|
||||
/* scroll smaller than the threshold should not generate events */
|
||||
/* scroll smaller than the threshold should not generate axis events */
|
||||
litest_button_scroll(dev, BTN_MIDDLE, 1, 1);
|
||||
/* long middle press without movement should not generate events */
|
||||
|
||||
litest_button_scroll(dev, BTN_MIDDLE, 0, 0);
|
||||
litest_assert_button_event(li, BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_button_event(li,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,6 +169,10 @@ libinput:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*:pvrThinkPadX1Carbon3rd
|
|||
libinput:name:*Logitech M570*:dmi:*
|
||||
LIBINPUT_MODEL_TRACKBALL=1
|
||||
|
||||
# Logitech Marble Mouse trackball
|
||||
libinput:mouse:input:b0003v046DpC408*
|
||||
LIBINPUT_MODEL_LOGITECH_MARBLE_MOUSE=1
|
||||
|
||||
##########################################
|
||||
# Microsoft
|
||||
##########################################
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue