diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2016-06-30 15:49:40 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2016-07-04 09:41:33 +1000 |
commit | 0526044f6d4ebb614699d87f23de3d3256a568ff (patch) | |
tree | be0cc527eef0185697bf7e7a35151774a85e249e | |
parent | 9e477d21bce17561c37688b25f1dc990df131265 (diff) |
touchpad: remove software middle button when emulation is enabled
Expose the middle button emulation on software buttons as proper config
option. When enabled, remove the middle button software button area.
https://bugs.freedesktop.org/show_bug.cgi?id=96663
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r-- | doc/clickpad-softbuttons.dox | 4 | ||||
-rw-r--r-- | src/evdev-middle-button.c | 6 | ||||
-rw-r--r-- | src/evdev-mt-touchpad-buttons.c | 92 | ||||
-rw-r--r-- | src/evdev-mt-touchpad.c | 2 | ||||
-rw-r--r-- | src/evdev-mt-touchpad.h | 3 | ||||
-rw-r--r-- | src/evdev.h | 9 | ||||
-rw-r--r-- | src/libinput.h | 4 | ||||
-rw-r--r-- | test/litest.h | 26 | ||||
-rw-r--r-- | test/pointer.c | 16 | ||||
-rw-r--r-- | test/touchpad-buttons.c | 233 |
10 files changed, 382 insertions, 13 deletions
diff --git a/doc/clickpad-softbuttons.dox b/doc/clickpad-softbuttons.dox index cf4c8c9e..ec0381e1 100644 --- a/doc/clickpad-softbuttons.dox +++ b/doc/clickpad-softbuttons.dox @@ -37,6 +37,10 @@ location of the button is not visibly obvious. @image html software-buttons.svg "Left, right and middle-button click with software button areas" +@note If middle button emulation is enabled on a clickpad, only left and right +button areas are available. For more details, see +libinput_device_config_middle_emulation_set_enabled(). + If fingers are down in the main area in addition to fingers in the left or right button area, those fingers are are ignored. A release event always releases the buttons logically down, regardless of diff --git a/src/evdev-middle-button.c b/src/evdev-middle-button.c index 48650a45..09f77de4 100644 --- a/src/evdev-middle-button.c +++ b/src/evdev-middle-button.c @@ -643,7 +643,7 @@ evdev_middlebutton_handle_timeout(uint64_t now, void *data) evdev_middlebutton_handle_event(device, now, MIDDLEBUTTON_EVENT_TIMEOUT); } -static int +int evdev_middlebutton_is_available(struct libinput_device *device) { return 1; @@ -671,7 +671,7 @@ evdev_middlebutton_set(struct libinput_device *device, return LIBINPUT_CONFIG_STATUS_SUCCESS; } -static enum libinput_config_middle_emulation_state +enum libinput_config_middle_emulation_state evdev_middlebutton_get(struct libinput_device *device) { struct evdev_device *evdev = (struct evdev_device*)device; @@ -681,7 +681,7 @@ evdev_middlebutton_get(struct libinput_device *device) LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; } -static enum libinput_config_middle_emulation_state +enum libinput_config_middle_emulation_state evdev_middlebutton_get_default(struct libinput_device *device) { struct evdev_device *evdev = (struct evdev_device*)device; diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index a9b75216..a2f31217 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -564,6 +564,13 @@ tp_init_softbuttons(struct tp_dispatch *tp, tp->buttons.bottom_area.top_edge = height * .85 + yoffset; } + tp->buttons.bottom_area.middlebutton_left_edge = INT_MAX; + tp->buttons.bottom_area.rightbutton_left_edge = width/2 + xoffset; + + /* if middlebutton emulation is enabled, don't init a software area */ + if (device->middlebutton.want_enabled) + return; + /* The middle button is 25% of the touchpad and centered. Many * touchpads don't have markings for the middle button at all so we * need to make it big enough to reliably hit it but not too big so @@ -699,6 +706,80 @@ tp_button_config_click_get_default_method(struct libinput_device *device) return tp_click_get_default_method(tp); } +void +tp_clickpad_middlebutton_apply_config(struct evdev_device *device) +{ + struct tp_dispatch *tp = (struct tp_dispatch*)device->dispatch; + + if (!tp->buttons.is_clickpad || + tp->buttons.state != 0) + return; + + if (device->middlebutton.want_enabled == + device->middlebutton.enabled) + return; + + device->middlebutton.enabled = device->middlebutton.want_enabled; + if (tp->buttons.click_method == + LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS) + tp_init_softbuttons(tp, device); +} + +static int +tp_clickpad_middlebutton_is_available(struct libinput_device *device) +{ + return evdev_middlebutton_is_available(device); +} + +static enum libinput_config_status +tp_clickpad_middlebutton_set(struct libinput_device *device, + enum libinput_config_middle_emulation_state enable) +{ + struct evdev_device *evdev = (struct evdev_device*)device; + + switch (enable) { + case LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED: + evdev->middlebutton.want_enabled = true; + break; + case LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED: + evdev->middlebutton.want_enabled = false; + break; + default: + return LIBINPUT_CONFIG_STATUS_INVALID; + } + + tp_clickpad_middlebutton_apply_config(evdev); + + return LIBINPUT_CONFIG_STATUS_SUCCESS; +} + +static enum libinput_config_middle_emulation_state +tp_clickpad_middlebutton_get(struct libinput_device *device) +{ + return evdev_middlebutton_get(device); +} + +static enum libinput_config_middle_emulation_state +tp_clickpad_middlebutton_get_default(struct libinput_device *device) +{ + return evdev_middlebutton_get_default(device); +} + +static inline void +tp_init_clickpad_middlebutton_emulation(struct tp_dispatch *tp, + struct evdev_device *device) +{ + device->middlebutton.enabled_default = false; + device->middlebutton.want_enabled = false; + device->middlebutton.enabled = false; + + device->middlebutton.config.available = tp_clickpad_middlebutton_is_available; + device->middlebutton.config.set = tp_clickpad_middlebutton_set; + device->middlebutton.config.get = tp_clickpad_middlebutton_get; + device->middlebutton.config.get_default = tp_clickpad_middlebutton_get_default; + device->base.config.middle_emulation = &device->middlebutton.config; +} + static inline void tp_init_middlebutton_emulation(struct tp_dispatch *tp, struct evdev_device *device) @@ -706,8 +787,12 @@ tp_init_middlebutton_emulation(struct tp_dispatch *tp, bool enable_by_default, want_config_option; - if (tp->buttons.is_clickpad) + /* On clickpads we provide the config option but disable by default. + When enabled, the middle software button disappears */ + if (tp->buttons.is_clickpad) { + tp_init_clickpad_middlebutton_emulation(tp, device); return; + } /* init middle button emulation on non-clickpads, but only if we * don't have a middle button. Exception: ALPS touchpads don't know @@ -1038,7 +1123,10 @@ tp_post_clickpadbutton_buttons(struct tp_dispatch *tp, uint64_t time) return 0; } - if ((area & MIDDLE) || ((area & LEFT) && (area & RIGHT))) { + if ((tp->device->middlebutton.enabled || is_top) && + (area & LEFT) && (area & RIGHT)) { + button = BTN_MIDDLE; + } else if (area & MIDDLE) { button = BTN_MIDDLE; } else if (area & RIGHT) { button = BTN_RIGHT; diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 21d83ad6..4dd6b641 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -1145,6 +1145,8 @@ tp_handle_state(struct tp_dispatch *tp, tp_process_state(tp, time); tp_post_events(tp, time); tp_post_process_state(tp, time); + + tp_clickpad_middlebutton_apply_config(tp->device); } static void diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 3f3b728a..fe1f1b36 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -527,4 +527,7 @@ tp_gesture_stop_twofinger_scroll(struct tp_dispatch *tp, uint64_t time); bool tp_palm_tap_is_palm(const struct tp_dispatch *tp, const struct tp_touch *t); +void +tp_clickpad_middlebutton_apply_config(struct evdev_device *device); + #endif diff --git a/src/evdev.h b/src/evdev.h index f0fb2f9d..2b60faaf 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -465,6 +465,15 @@ evdev_init_middlebutton(struct evdev_device *device, bool enabled, bool want_config); +enum libinput_config_middle_emulation_state +evdev_middlebutton_get(struct libinput_device *device); + +int +evdev_middlebutton_is_available(struct libinput_device *device); + +enum libinput_config_middle_emulation_state +evdev_middlebutton_get_default(struct libinput_device *device); + static inline double evdev_convert_to_mm(const struct input_absinfo *absinfo, double v) { diff --git a/src/libinput.h b/src/libinput.h index ed3eb7d7..abc737e5 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -4307,6 +4307,10 @@ libinput_device_config_middle_emulation_is_available( * * The middle button emulation behavior when combined with other device * buttons, including a physical middle button is device-dependent. + * For example, @ref clickpad_softbuttons provides a middle button area when + * middle button emulation is disabled. That middle button area disappears + * when middle button emulation is enabled - a middle click can then only be + * triggered by a simultaneous left + right click. * * @note Some devices provide middle mouse button emulation but do not allow * enabling/disabling that emulation. diff --git a/test/litest.h b/test/litest.h index c8309285..dd299bb3 100644 --- a/test/litest.h +++ b/test/litest.h @@ -799,6 +799,32 @@ litest_disable_drag_lock(struct libinput_device *device) litest_assert_int_eq(status, expected); } +static inline void +litest_enable_middleemu(struct litest_device *dev) +{ + struct libinput_device *device = dev->libinput_device; + enum libinput_config_status status, expected; + + expected = LIBINPUT_CONFIG_STATUS_SUCCESS; + status = libinput_device_config_middle_emulation_set_enabled(device, + LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED); + + litest_assert_int_eq(status, expected); +} + +static inline void +litest_disable_middleemu(struct litest_device *dev) +{ + struct libinput_device *device = dev->libinput_device; + enum libinput_config_status status, expected; + + expected = LIBINPUT_CONFIG_STATUS_SUCCESS; + status = libinput_device_config_middle_emulation_set_enabled(device, + LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED); + + litest_assert_int_eq(status, expected); +} + #define CK_DOUBLE_EQ_EPSILON 1E-3 #define ck_assert_double_eq(X,Y) \ do { \ diff --git a/test/pointer.c b/test/pointer.c index ea1157e5..f8651a7a 100644 --- a/test/pointer.c +++ b/test/pointer.c @@ -1603,7 +1603,7 @@ START_TEST(middlebutton_default_clickpad) int available; available = libinput_device_config_middle_emulation_is_available(device); - ck_assert(!available); + ck_assert(available); state = libinput_device_config_middle_emulation_get_enabled(device); ck_assert_int_eq(state, LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED); @@ -1613,7 +1613,7 @@ START_TEST(middlebutton_default_clickpad) status = libinput_device_config_middle_emulation_set_enabled(device, LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED); - ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); status = libinput_device_config_middle_emulation_set_enabled(device, LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED); @@ -1763,12 +1763,12 @@ litest_setup_tests(void) litest_add("pointer:accel", pointer_accel_profile_invalid, LITEST_RELATIVE, LITEST_ANY); litest_add("pointer:accel", pointer_accel_profile_flat_motion_relative, LITEST_RELATIVE, LITEST_TOUCHPAD); - litest_add("pointer:middlebutton", middlebutton, LITEST_BUTTON, LITEST_ANY); - litest_add("pointer:middlebutton", middlebutton_nostart_while_down, LITEST_BUTTON, LITEST_ANY); - litest_add("pointer:middlebutton", middlebutton_timeout, LITEST_BUTTON, LITEST_ANY); - litest_add("pointer:middlebutton", middlebutton_doubleclick, LITEST_BUTTON, LITEST_ANY); - litest_add("pointer:middlebutton", middlebutton_middleclick, LITEST_BUTTON, LITEST_ANY); - litest_add("pointer:middlebutton", middlebutton_middleclick_during, LITEST_BUTTON, LITEST_ANY); + litest_add("pointer:middlebutton", middlebutton, LITEST_BUTTON, LITEST_CLICKPAD); + litest_add("pointer:middlebutton", middlebutton_nostart_while_down, LITEST_BUTTON, LITEST_CLICKPAD); + litest_add("pointer:middlebutton", middlebutton_timeout, LITEST_BUTTON, LITEST_CLICKPAD); + litest_add("pointer:middlebutton", middlebutton_doubleclick, LITEST_BUTTON, LITEST_CLICKPAD); + litest_add("pointer:middlebutton", middlebutton_middleclick, LITEST_BUTTON, LITEST_CLICKPAD); + litest_add("pointer:middlebutton", middlebutton_middleclick_during, LITEST_BUTTON, LITEST_CLICKPAD); litest_add("pointer:middlebutton", middlebutton_default_enabled, LITEST_BUTTON, LITEST_TOUCHPAD|LITEST_POINTINGSTICK); litest_add("pointer:middlebutton", middlebutton_default_clickpad, LITEST_CLICKPAD, LITEST_ANY); litest_add("pointer:middlebutton", middlebutton_default_touchpad, LITEST_TOUCHPAD, LITEST_CLICKPAD); diff --git a/test/touchpad-buttons.c b/test/touchpad-buttons.c index 080c6702..d72278b1 100644 --- a/test/touchpad-buttons.c +++ b/test/touchpad-buttons.c @@ -1578,6 +1578,232 @@ START_TEST(clickpad_topsoftbuttons_clickfinger_dev_disabled) } END_TEST +START_TEST(clickpad_middleemulation_config_delayed) +{ + 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 enabled; + + enabled = libinput_device_config_middle_emulation_get_enabled(device); + ck_assert(!enabled); + + litest_touch_down(dev, 0, 30, 95); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + libinput_dispatch(li); + + /* actual config is delayed, but status is immediate */ + status = libinput_device_config_middle_emulation_set_enabled(device, + LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + enabled = libinput_device_config_middle_emulation_get_enabled(device); + ck_assert(enabled); + + status = libinput_device_config_middle_emulation_set_enabled(device, + LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + enabled = libinput_device_config_middle_emulation_get_enabled(device); + ck_assert(!enabled); +} +END_TEST + +START_TEST(clickpad_middleemulation_click) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_enable_buttonareas(dev); + litest_enable_middleemu(dev); + litest_drain_events(li); + + litest_touch_down(dev, 0, 30, 95); + litest_touch_down(dev, 1, 80, 95); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + 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_touch_up(dev, 0); + litest_touch_up(dev, 1); + + litest_assert_button_event(li, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_RELEASED); + + libinput_dispatch(li); + + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(clickpad_middleemulation_click_middle_left) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_enable_buttonareas(dev); + litest_enable_middleemu(dev); + litest_drain_events(li); + + litest_touch_down(dev, 0, 49, 95); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + litest_assert_button_event(li, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + + litest_assert_button_event(li, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + + libinput_dispatch(li); + + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(clickpad_middleemulation_click_middle_right) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_enable_buttonareas(dev); + litest_enable_middleemu(dev); + litest_drain_events(li); + + litest_touch_down(dev, 0, 51, 95); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + litest_assert_button_event(li, + BTN_RIGHT, + LIBINPUT_BUTTON_STATE_PRESSED); + + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + + litest_assert_button_event(li, + BTN_RIGHT, + LIBINPUT_BUTTON_STATE_RELEASED); + + libinput_dispatch(li); + + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(clickpad_middleemulation_click_enable_while_down) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_enable_buttonareas(dev); + litest_drain_events(li); + + litest_touch_down(dev, 0, 49, 95); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + litest_assert_button_event(li, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_PRESSED); + + litest_enable_middleemu(dev); + + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + + litest_assert_button_event(li, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_RELEASED); + + libinput_dispatch(li); + + litest_assert_empty_queue(li); + + litest_touch_down(dev, 0, 49, 95); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + + litest_assert_button_event(li, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, + BTN_LEFT, + LIBINPUT_BUTTON_STATE_RELEASED); + + libinput_dispatch(li); +} +END_TEST + +START_TEST(clickpad_middleemulation_click_disable_while_down) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_enable_buttonareas(dev); + litest_enable_middleemu(dev); + + litest_drain_events(li); + + litest_touch_down(dev, 0, 30, 95); + litest_touch_down(dev, 1, 70, 95); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + litest_assert_button_event(li, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_PRESSED); + + litest_disable_middleemu(dev); + + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + + litest_assert_button_event(li, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_RELEASED); + libinput_dispatch(li); + + litest_assert_empty_queue(li); + + litest_touch_down(dev, 0, 49, 95); + litest_event(dev, EV_KEY, BTN_LEFT, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_event(dev, EV_KEY, BTN_LEFT, 0); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + litest_touch_up(dev, 0); + + litest_assert_button_event(li, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, + BTN_MIDDLE, + LIBINPUT_BUTTON_STATE_RELEASED); + + libinput_dispatch(li); +} +END_TEST + void litest_setup_tests(void) { @@ -1629,4 +1855,11 @@ litest_setup_tests(void) litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_move_out_ignore, LITEST_TOPBUTTONPAD, LITEST_ANY); litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_clickfinger, LITEST_TOPBUTTONPAD, LITEST_ANY); litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_clickfinger_dev_disabled, LITEST_TOPBUTTONPAD, LITEST_ANY); + + litest_add("touchpad:middleemulation", clickpad_middleemulation_config_delayed, LITEST_CLICKPAD, LITEST_ANY); + litest_add("touchpad:middleemulation", clickpad_middleemulation_click, LITEST_CLICKPAD, LITEST_ANY); + litest_add("touchpad:middleemulation", clickpad_middleemulation_click_middle_left, LITEST_CLICKPAD, LITEST_ANY); + litest_add("touchpad:middleemulation", clickpad_middleemulation_click_middle_right, LITEST_CLICKPAD, LITEST_ANY); + litest_add("touchpad:middleemulation", clickpad_middleemulation_click_enable_while_down, LITEST_CLICKPAD, LITEST_ANY); + litest_add("touchpad:middleemulation", clickpad_middleemulation_click_disable_while_down, LITEST_CLICKPAD, LITEST_ANY); } |