diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2019-03-20 10:56:51 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2019-10-17 12:21:41 +1000 |
commit | 63f99230130ae012a71cec90ee0abccb1b43abd3 (patch) | |
tree | d07692d299c13e2bab75d05383c8bfa91524f6f2 /src | |
parent | 12eb14846a139ae8d4915c338302095a53c69e91 (diff) | |
download | libinput-63f99230130ae012a71cec90ee0abccb1b43abd3.tar.gz |
Add a scroll button lock feature
Scroll button locking is an accessibility feature. When enabled, the scroll
button does not need to be held down, the first click holds it logically down,
to be released on the second click of that same button.
This is implemented as simple event filter, so we still get the same behavior
from the emulated logical button, i.e. a physical double click results in a
single logical click of that button provided no scrolling was triggered.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Diffstat (limited to 'src')
-rw-r--r-- | src/evdev-fallback.c | 5 | ||||
-rw-r--r-- | src/evdev.c | 81 | ||||
-rw-r--r-- | src/evdev.h | 16 | ||||
-rw-r--r-- | src/libinput-private.h | 4 | ||||
-rw-r--r-- | src/libinput.c | 39 | ||||
-rw-r--r-- | src/libinput.h | 75 | ||||
-rw-r--r-- | src/libinput.sym | 6 |
7 files changed, 225 insertions, 1 deletions
diff --git a/src/evdev-fallback.c b/src/evdev-fallback.c index 1a9113bc..a40421f0 100644 --- a/src/evdev-fallback.c +++ b/src/evdev-fallback.c @@ -1499,7 +1499,8 @@ fallback_change_scroll_method(struct evdev_device *device) struct fallback_dispatch *dispatch = fallback_dispatch(device->dispatch); if (device->scroll.want_method == device->scroll.method && - device->scroll.want_button == device->scroll.button) + device->scroll.want_button == device->scroll.button && + device->scroll.want_lock_enabled == device->scroll.lock_enabled) return; if (fallback_any_button_down(dispatch, device)) @@ -1507,6 +1508,8 @@ fallback_change_scroll_method(struct evdev_device *device) device->scroll.method = device->scroll.want_method; device->scroll.button = device->scroll.want_button; + device->scroll.lock_enabled = device->scroll.want_lock_enabled; + evdev_set_button_scroll_lock_enabled(device, device->scroll.lock_enabled); } static int diff --git a/src/evdev.c b/src/evdev.c index 60a599e7..20b8dac9 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -198,6 +198,34 @@ static void evdev_button_scroll_button(struct evdev_device *device, uint64_t time, int is_press) { + /* Where the button lock is enabled, we wrap the buttons into + their own little state machine and filter out the events. + */ + switch (device->scroll.lock_state) { + case BUTTONSCROLL_LOCK_DISABLED: + break; + case BUTTONSCROLL_LOCK_IDLE: + assert(is_press); + device->scroll.lock_state = BUTTONSCROLL_LOCK_FIRSTDOWN; + evdev_log_debug(device, "scroll lock: first down\n"); + break; /* handle event */ + case BUTTONSCROLL_LOCK_FIRSTDOWN: + assert(!is_press); + device->scroll.lock_state = BUTTONSCROLL_LOCK_FIRSTUP; + evdev_log_debug(device, "scroll lock: first up\n"); + return; /* filter release event */ + case BUTTONSCROLL_LOCK_FIRSTUP: + assert(is_press); + device->scroll.lock_state = BUTTONSCROLL_LOCK_SECONDDOWN; + evdev_log_debug(device, "scroll lock: second down\n"); + return; /* filter press event */ + case BUTTONSCROLL_LOCK_SECONDDOWN: + assert(!is_press); + device->scroll.lock_state = BUTTONSCROLL_LOCK_IDLE; + evdev_log_debug(device, "scroll lock: idle\n"); + break; /* handle event */ + } + if (is_press) { enum timer_flags flags = TIMER_FLAG_NONE; @@ -705,6 +733,56 @@ evdev_scroll_get_default_button(struct libinput_device *device) return 0; } +static enum libinput_config_status +evdev_scroll_set_button_lock(struct libinput_device *device, + enum libinput_config_scroll_button_lock_state state) +{ + struct evdev_device *evdev = evdev_device(device); + + switch (state) { + case LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED: + evdev->scroll.want_lock_enabled = false; + break; + case LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED: + evdev->scroll.want_lock_enabled = true; + break; + default: + return LIBINPUT_CONFIG_STATUS_INVALID; + } + + evdev->scroll.change_scroll_method(evdev); + + return LIBINPUT_CONFIG_STATUS_SUCCESS; +} + +static enum libinput_config_scroll_button_lock_state +evdev_scroll_get_button_lock(struct libinput_device *device) +{ + struct evdev_device *evdev = evdev_device(device); + + if (evdev->scroll.lock_state == BUTTONSCROLL_LOCK_DISABLED) + return LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED; + else + return LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED; +} + +static enum libinput_config_scroll_button_lock_state +evdev_scroll_get_default_button_lock(struct libinput_device *device) +{ + return LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED; +} + + +void +evdev_set_button_scroll_lock_enabled(struct evdev_device *device, + bool enabled) +{ + if (enabled) + device->scroll.lock_state = BUTTONSCROLL_LOCK_IDLE; + else + device->scroll.lock_state = BUTTONSCROLL_LOCK_DISABLED; +} + void evdev_init_button_scroll(struct evdev_device *device, void (*change_scroll_method)(struct evdev_device *)) @@ -726,6 +804,9 @@ evdev_init_button_scroll(struct evdev_device *device, device->scroll.config.set_button = evdev_scroll_set_button; device->scroll.config.get_button = evdev_scroll_get_button; device->scroll.config.get_default_button = evdev_scroll_get_default_button; + device->scroll.config.set_button_lock = evdev_scroll_set_button_lock; + device->scroll.config.get_button_lock = evdev_scroll_get_button_lock; + device->scroll.config.get_default_button_lock = evdev_scroll_get_default_button_lock; device->base.config.scroll_method = &device->scroll.config; device->scroll.method = evdev_scroll_get_default_method((struct libinput_device *)device); device->scroll.want_method = device->scroll.method; diff --git a/src/evdev.h b/src/evdev.h index 7de1fea9..0af0ba36 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -125,6 +125,14 @@ enum evdev_button_scroll_state { BUTTONSCROLL_SCROLLING, /* have sent scroll events */ }; +enum evdev_button_scroll_lock_state { + BUTTONSCROLL_LOCK_DISABLED, + BUTTONSCROLL_LOCK_IDLE, + BUTTONSCROLL_LOCK_FIRSTDOWN, + BUTTONSCROLL_LOCK_FIRSTUP, + BUTTONSCROLL_LOCK_SECONDDOWN, +}; + enum evdev_debounce_state { /** * Initial state, no debounce but monitoring events @@ -224,6 +232,10 @@ struct evdev_device { struct wheel_angle wheel_click_angle; struct wheel_tilt_flags is_tilt; + + enum evdev_button_scroll_lock_state lock_state; + bool want_lock_enabled; + bool lock_enabled; } scroll; struct { @@ -557,6 +569,10 @@ void evdev_init_button_scroll(struct evdev_device *device, void (*change_scroll_method)(struct evdev_device *)); +void +evdev_set_button_scroll_lock_enabled(struct evdev_device *device, + bool enabled); + int evdev_update_key_down_count(struct evdev_device *device, int code, diff --git a/src/libinput-private.h b/src/libinput-private.h index 1950e663..abb47894 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -272,6 +272,10 @@ struct libinput_device_config_scroll_method { uint32_t button); uint32_t (*get_button)(struct libinput_device *device); uint32_t (*get_default_button)(struct libinput_device *device); + enum libinput_config_status (*set_button_lock)(struct libinput_device *device, + enum libinput_config_scroll_button_lock_state); + enum libinput_config_scroll_button_lock_state (*get_button_lock)(struct libinput_device *device); + enum libinput_config_scroll_button_lock_state (*get_default_button_lock)(struct libinput_device *device); }; struct libinput_device_config_click_method { diff --git a/src/libinput.c b/src/libinput.c index 6d00a006..9570dc68 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -4149,6 +4149,45 @@ libinput_device_config_scroll_get_default_button(struct libinput_device *device) return device->config.scroll_method->get_default_button(device); } +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_scroll_set_button_lock(struct libinput_device *device, + enum libinput_config_scroll_button_lock_state state) +{ + if ((libinput_device_config_scroll_get_methods(device) & + LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) == 0) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + + switch (state) { + case LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED: + case LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED: + break; + default: + return LIBINPUT_CONFIG_STATUS_INVALID; + } + + return device->config.scroll_method->set_button_lock(device, state); +} + +LIBINPUT_EXPORT enum libinput_config_scroll_button_lock_state +libinput_device_config_scroll_get_button_lock(struct libinput_device *device) +{ + if ((libinput_device_config_scroll_get_methods(device) & + LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) == 0) + return LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED; + + return device->config.scroll_method->get_button_lock(device); +} + +LIBINPUT_EXPORT enum libinput_config_scroll_button_lock_state +libinput_device_config_scroll_get_default_button_lock(struct libinput_device *device) +{ + if ((libinput_device_config_scroll_get_methods(device) & + LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) == 0) + return LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED; + + return device->config.scroll_method->get_default_button_lock(device); +} + LIBINPUT_EXPORT int libinput_device_config_dwt_is_available(struct libinput_device *device) { diff --git a/src/libinput.h b/src/libinput.h index 59463f43..54d40de6 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -5594,6 +5594,81 @@ libinput_device_config_scroll_get_button(struct libinput_device *device); uint32_t libinput_device_config_scroll_get_default_button(struct libinput_device *device); +enum libinput_config_scroll_button_lock_state { + LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED, + LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED, +}; + +/** + * @ingroup config + * + * Set the scroll button lock. If the state is + * @ref LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED, the button must + * physically be held down for button scrolling to work. + * If the state is + * @ref LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED, the button is considered + * logically down after the first press and release sequence, and logically + * up after the second press and release sequence. + * + * @param device The device to configure + * @param state The state to set the scroll button lock to + * + * @return A config status code. Disabling the scroll button lock on + * device that does not support button scrolling always succeeds. + * + * @see libinput_device_config_scroll_set_button + * @see libinput_device_config_scroll_get_button + * @see libinput_device_config_scroll_get_default_button + */ +enum libinput_config_status +libinput_device_config_scroll_set_button_lock(struct libinput_device *device, + enum libinput_config_scroll_button_lock_state state); + +/** + * @ingroup config + * + * Get the current scroll button lock state. + * + * If @ref LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN scroll method is not + * supported, or no button is set, this function returns @ref + * LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED. + * + * @note The return value is independent of the currently selected + * scroll-method. For the scroll button lock to activate, a device must have + * the @ref LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN method enabled, and a + * non-zero button set as scroll button. + * + * @param device The device to configure + * @return The scroll button lock state + * + * @see libinput_device_config_scroll_set_button + * @see libinput_device_config_scroll_set_button_lock + * @see libinput_device_config_scroll_get_button_lock + * @see libinput_device_config_scroll_get_default_button_lock + */ +enum libinput_config_scroll_button_lock_state +libinput_device_config_scroll_get_button_lock(struct libinput_device *device); + +/** + * @ingroup config + * + * Get the default scroll button lock state. + * + * If @ref LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN scroll method is not + * supported, or no button is set, this function returns @ref + * LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED. + * + * @param device The device to configure + * @return The default scroll button lock state + * + * @see libinput_device_config_scroll_set_button + * @see libinput_device_config_scroll_set_button_lock + * @see libinput_device_config_scroll_get_button_lock + * @see libinput_device_config_scroll_get_default_button_lock + */ +enum libinput_config_scroll_button_lock_state +libinput_device_config_scroll_get_default_button_lock(struct libinput_device *device); + /** * @ingroup config * diff --git a/src/libinput.sym b/src/libinput.sym index ef9d9178..1698a066 100644 --- a/src/libinput.sym +++ b/src/libinput.sym @@ -305,3 +305,9 @@ LIBINPUT_1.14 { libinput_event_tablet_tool_size_major_has_changed; libinput_event_tablet_tool_size_minor_has_changed; } LIBINPUT_1.11; + +LIBINPUT_1.15 { + libinput_device_config_scroll_set_button_lock; + libinput_device_config_scroll_get_button_lock; + libinput_device_config_scroll_get_default_button_lock; +} LIBINPUT_1.14; |