summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2019-03-20 10:56:51 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2019-10-17 12:21:41 +1000
commit63f99230130ae012a71cec90ee0abccb1b43abd3 (patch)
treed07692d299c13e2bab75d05383c8bfa91524f6f2 /src
parent12eb14846a139ae8d4915c338302095a53c69e91 (diff)
downloadlibinput-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.c5
-rw-r--r--src/evdev.c81
-rw-r--r--src/evdev.h16
-rw-r--r--src/libinput-private.h4
-rw-r--r--src/libinput.c39
-rw-r--r--src/libinput.h75
-rw-r--r--src/libinput.sym6
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;