From: satrmb <10471-satrmb_true-email-is-private_contact-via-web@gitlab.freedesktop.org> Date: Mon, 2 Sep 2024 14:29:02 +0000 (+0200) Subject: touchpad: add sticky mode to drag-lock X-Git-Tag: 1.27.0~154 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=910d59e836b430376c811bd4841621dc99542a94;p=platform%2Fupstream%2Flibinput.git touchpad: add sticky mode to drag-lock Sticky mode removes the timeout from drag-lock, only a tap ends a drag. Timeout mode remains available without changes. Sticky mode is exposed as a new value for the existing drag-lock setting. Part-of: --- diff --git a/doc/user/configuration.rst b/doc/user/configuration.rst index 8ce31f21..e9260a3b 100644 --- a/doc/user/configuration.rst +++ b/doc/user/configuration.rst @@ -28,7 +28,7 @@ options exposed by libinput are: - how many tapping fingers are supported by this device - a toggle to enable/disable tapping - a toggle to enable/disable tap-and-drag, see :ref:`tapndrag`. -- a toggle to enable/disable tap-and-drag drag lock see :ref:`tapndrag` +- a toggle to enable/disable tap-and-drag drag lock, see :ref:`tapndrag` - The default order is 1, 2, 3 finger tap mapping to left, right, middle click, respectively. This order can be changed to left, middle, right click, respectively. diff --git a/doc/user/tapping.rst b/doc/user/tapping.rst index 85b55f1f..5c02ca6e 100644 --- a/doc/user/tapping.rst +++ b/doc/user/tapping.rst @@ -56,11 +56,13 @@ tap-and-drag enabled by default. single-finger drag. Also optional is a feature called "drag lock". With drag lock disabled, lifting -the finger will stop any drag process. When enabled, libinput will ignore a -finger up event during a drag process, provided the finger is set down again -within a implementation-specific timeout. Drag lock can be enabled and -disabled with **libinput_device_config_tap_set_drag_lock_enabled()**. -Note that drag lock only applies if tap-and-drag is be enabled. +the finger will stop any drag process. When enabled, the drag +process continues even after lifting a finger but can be ended +with an additional tap. If timeout-based drag-locks are enabled +the drag process will also automatically end once the finger has +been lifted for an implementation-specific timeout. Drag lock can be +enabled and disabled with **libinput_device_config_tap_set_drag_lock_enabled()**. +Note that drag lock only applies if tap-and-drag is enabled. .. figure:: tap-n-drag.svg :align: center @@ -78,6 +80,9 @@ If drag lock is enabled, the release of the mouse buttons after the finger release (e) is triggered by a timeout. To release the button immediately, simply tap again (f). +If drag lock is enabled in sticky mode there is no timeout after +releasing a finger and an extra tap is required to release the button. + If two fingers are supported by the hardware, a second finger can be used to drag while the first is held in-place. diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index 299cd554..3c76c3d6 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -815,7 +815,7 @@ tp_tap_dragging_handle_event(struct tp_dispatch *tp, break; } case TAP_EVENT_RELEASE: - if (tp->tap.drag_lock_enabled) { + if (tp->tap.drag_lock != LIBINPUT_CONFIG_DRAG_LOCK_DISABLED) { enum tp_tap_state dest[3] = { TAP_STATE_1FGTAP_DRAGGING_WAIT, TAP_STATE_2FGTAP_DRAGGING_WAIT, @@ -823,7 +823,8 @@ tp_tap_dragging_handle_event(struct tp_dispatch *tp, }; assert(nfingers_tapped >= 1 && nfingers_tapped <= 3); tp->tap.state = dest[nfingers_tapped - 1]; - tp_tap_set_draglock_timer(tp, time); + if (tp->tap.drag_lock == LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_TIMEOUT) + tp_tap_set_draglock_timer(tp, time); } else { tp_tap_notify(tp, time, @@ -1517,7 +1518,7 @@ tp_tap_config_set_draglock_enabled(struct libinput_device *device, struct evdev_dispatch *dispatch = evdev_device(device)->dispatch; struct tp_dispatch *tp = tp_dispatch(dispatch); - tp->tap.drag_lock_enabled = enabled; + tp->tap.drag_lock = enabled; return LIBINPUT_CONFIG_STATUS_SUCCESS; } @@ -1528,7 +1529,7 @@ tp_tap_config_get_draglock_enabled(struct libinput_device *device) struct evdev_dispatch *dispatch = evdev_device(device)->dispatch; struct tp_dispatch *tp = tp_dispatch(dispatch); - return tp->tap.drag_lock_enabled; + return tp->tap.drag_lock; } static inline enum libinput_config_drag_lock_state @@ -1570,7 +1571,7 @@ tp_init_tap(struct tp_dispatch *tp) tp->tap.map = LIBINPUT_CONFIG_TAP_MAP_LRM; tp->tap.want_map = tp->tap.map; tp->tap.drag_enabled = tp_drag_default(tp->device); - tp->tap.drag_lock_enabled = tp_drag_lock_default(tp->device); + tp->tap.drag_lock = tp_drag_lock_default(tp->device); snprintf(timer_name, sizeof(timer_name), diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 26588dbb..55547014 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -435,7 +435,7 @@ struct tp_dispatch { enum libinput_config_tap_button_map want_map; bool drag_enabled; - bool drag_lock_enabled; + enum libinput_config_drag_lock_state drag_lock; unsigned int nfingers_down; /* number of fingers down for tapping (excl. thumb/palm) */ } tap; diff --git a/src/libinput.c b/src/libinput.c index 9ad2e808..42a58d39 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -4067,7 +4067,8 @@ LIBINPUT_EXPORT enum libinput_config_status libinput_device_config_tap_set_drag_lock_enabled(struct libinput_device *device, enum libinput_config_drag_lock_state enable) { - if (enable != LIBINPUT_CONFIG_DRAG_LOCK_ENABLED && + if (enable != LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY && + enable != LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_TIMEOUT && enable != LIBINPUT_CONFIG_DRAG_LOCK_DISABLED) return LIBINPUT_CONFIG_STATUS_INVALID; diff --git a/src/libinput.h b/src/libinput.h index 1a9d4f29..5365ff80 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -4929,24 +4929,33 @@ libinput_device_config_tap_get_default_drag_enabled(struct libinput_device *devi enum libinput_config_drag_lock_state { /** Drag lock is to be disabled, or is currently disabled */ LIBINPUT_CONFIG_DRAG_LOCK_DISABLED, - /** Drag lock is to be enabled, or is currently disabled */ - LIBINPUT_CONFIG_DRAG_LOCK_ENABLED, + /** Drag lock is to be enabled in timeout mode, + * or is currently enabled in timeout mode */ + LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_TIMEOUT, + /** legacy spelling for LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_TIMEOUT */ + LIBINPUT_CONFIG_DRAG_LOCK_ENABLED = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_TIMEOUT, + /** Drag lock is to be enabled in sticky mode, + * or is currently enabled in sticky mode */ + LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY, }; /** * @ingroup config * * Enable or disable drag-lock during tapping on this device. When enabled, - * a finger may be lifted and put back on the touchpad within a timeout and - * the drag process continues. When disabled, lifting the finger during a - * tap-and-drag will immediately stop the drag. See the libinput - * documentation for more details. + * a finger may be lifted and put back on the touchpad and the drag process + * continues. A timeout for lifting the finger is optional. When disabled, + * lifting the finger during a tap-and-drag will immediately stop the drag. + * See the libinput documentation for more details. * - * Enabling drag lock on a device that has tapping disabled is permitted, - * but has no effect until tapping is enabled. + * Enabling drag lock on a device that has tapping or tap-and-drag disabled is + * permitted, but has no effect until tapping and tap-and-drag are enabled. * * @param device The device to configure - * @param enable @ref LIBINPUT_CONFIG_DRAG_LOCK_ENABLED to enable drag lock + * @param enable @ref LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY to enable drag + * lock in sticky mode, + * @ref LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_TIMEOUT to enable drag lock in timeout + * mode, * or @ref LIBINPUT_CONFIG_DRAG_LOCK_DISABLED to disable drag lock * * @return A config status code. Disabling drag lock on a device that does not @@ -4966,11 +4975,14 @@ libinput_device_config_tap_set_drag_lock_enabled(struct libinput_device *device, * device does not support tapping, this function always returns * @ref LIBINPUT_CONFIG_DRAG_LOCK_DISABLED. * - * Drag lock may be enabled even when tapping is disabled. + * Drag lock may be enabled even when tapping or tap-and-drag is disabled. * * @param device The device to configure * - * @retval LIBINPUT_CONFIG_DRAG_LOCK_ENABLED If drag lock is currently enabled + * @retval LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY If drag lock is currently + * enabled in sticky mode + * @retval LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_TIMEOUT If drag lock is currently + * enabled in timeout mode * @retval LIBINPUT_CONFIG_DRAG_LOCK_DISABLED If drag lock is currently disabled * * @see libinput_device_config_tap_set_drag_lock_enabled @@ -4986,13 +4998,15 @@ libinput_device_config_tap_get_drag_lock_enabled(struct libinput_device *device) * If the device does not support tapping, this function always returns * @ref LIBINPUT_CONFIG_DRAG_LOCK_DISABLED. * - * Drag lock may be enabled by default even when tapping is disabled by - * default. + * Drag lock may be enabled by default even when tapping or tap-and-drag is + * disabled by default. * * @param device The device to configure * - * @retval LIBINPUT_CONFIG_DRAG_LOCK_ENABLED If drag lock is enabled by - * default + * @retval LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY If drag lock is enabled in + * sticky mode by default + * @retval LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_TIMEOUT If drag lock is enabled in + * timeout mode by default * @retval LIBINPUT_CONFIG_DRAG_LOCK_DISABLED If drag lock is disabled by * default * diff --git a/test/litest.h b/test/litest.h index 6108be50..f411c0ac 100644 --- a/test/litest.h +++ b/test/litest.h @@ -1179,6 +1179,18 @@ litest_enable_buttonareas(struct litest_device *dev) litest_assert_int_eq(status, expected); } +static inline void +litest_enable_drag_lock_sticky(struct libinput_device *device) +{ + enum libinput_config_status status, expected; + + expected = LIBINPUT_CONFIG_STATUS_SUCCESS; + status = libinput_device_config_tap_set_drag_lock_enabled(device, + LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY); + + litest_assert_int_eq(status, expected); +} + static inline void litest_enable_drag_lock(struct libinput_device *device) { @@ -1186,7 +1198,7 @@ litest_enable_drag_lock(struct libinput_device *device) expected = LIBINPUT_CONFIG_STATUS_SUCCESS; status = libinput_device_config_tap_set_drag_lock_enabled(device, - LIBINPUT_CONFIG_DRAG_LOCK_ENABLED); + LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_TIMEOUT); litest_assert_int_eq(status, expected); } diff --git a/test/test-touchpad-tap.c b/test/test-touchpad-tap.c index f8651562..8cf539f9 100644 --- a/test/test-touchpad-tap.c +++ b/test/test-touchpad-tap.c @@ -1579,6 +1579,81 @@ START_TEST(touchpad_tap_n_drag_draglock_timeout) } END_TEST +START_TEST(touchpad_tap_n_drag_draglock_sticky) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + int nfingers = _i; /* ranged test */ + unsigned int button = 0; + + if (nfingers > litest_slot_count(dev)) + return; + + litest_enable_tap(dev->libinput_device); + litest_enable_drag_lock_sticky(dev->libinput_device); + litest_disable_hold_gestures(dev->libinput_device); + + switch (nfingers) { + case 1: + button = BTN_LEFT; + break; + case 2: + button = BTN_RIGHT; + break; + case 3: + button = BTN_MIDDLE; + break; + default: + abort(); + } + + litest_drain_events(li); + + switch (nfingers) { + case 3: + litest_touch_down(dev, 2, 60, 30); + _fallthrough_; + case 2: + litest_touch_down(dev, 1, 50, 30); + _fallthrough_; + case 1: + litest_touch_down(dev, 0, 40, 30); + break; + } + switch (nfingers) { + case 3: + litest_touch_up(dev, 2); + _fallthrough_; + case 2: + litest_touch_up(dev, 1); + _fallthrough_; + case 1: + litest_touch_up(dev, 0); + break; + } + litest_touch_down(dev, 0, 50, 50); + libinput_dispatch(li); + litest_timeout_tap(); + + litest_assert_button_event(li, button, + LIBINPUT_BUTTON_STATE_PRESSED); + + litest_assert_empty_queue(li); + litest_touch_up(dev, 0); + libinput_dispatch(li); + + litest_timeout_tapndrag(); + litest_assert_empty_queue(li); + + litest_touch_down(dev, 0, 50, 50); + litest_touch_up(dev, 0); + litest_assert_button_event(li, button, + LIBINPUT_BUTTON_STATE_RELEASED); + + litest_assert_empty_queue(li); +} +END_TEST + START_TEST(touchpad_tap_n_drag_2fg) { /* Test: tap with 1-3 fingers (multiple times), then a 1fg move @@ -4133,14 +4208,27 @@ START_TEST(touchpad_drag_lock_default_disabled) status = libinput_device_config_tap_set_drag_lock_enabled(device, LIBINPUT_CONFIG_DRAG_LOCK_ENABLED); ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + /* ENABLED is a legacy spelling for ENABLED_TIMEOUT */ + ck_assert_int_eq(libinput_device_config_tap_get_drag_lock_enabled(device), + LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_TIMEOUT); status = libinput_device_config_tap_set_drag_lock_enabled(device, LIBINPUT_CONFIG_DRAG_LOCK_DISABLED); ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + ck_assert_int_eq(libinput_device_config_tap_get_drag_lock_enabled(device), + LIBINPUT_CONFIG_DRAG_LOCK_DISABLED); status = libinput_device_config_tap_set_drag_lock_enabled(device, - LIBINPUT_CONFIG_DRAG_LOCK_ENABLED); + LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_TIMEOUT); ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + ck_assert_int_eq(libinput_device_config_tap_get_drag_lock_enabled(device), + LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_TIMEOUT); + + status = libinput_device_config_tap_set_drag_lock_enabled(device, + LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + ck_assert_int_eq(libinput_device_config_tap_get_drag_lock_enabled(device), + LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY); status = libinput_device_config_tap_set_drag_lock_enabled(device, 3); @@ -4163,6 +4251,14 @@ START_TEST(touchpad_drag_lock_default_unavailable) LIBINPUT_CONFIG_DRAG_LOCK_ENABLED); ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED); + status = libinput_device_config_tap_set_drag_lock_enabled(device, + LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_TIMEOUT); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED); + + status = libinput_device_config_tap_set_drag_lock_enabled(device, + LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED); + status = libinput_device_config_tap_set_drag_lock_enabled(device, LIBINPUT_CONFIG_DRAG_LOCK_DISABLED); ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); @@ -5658,6 +5754,7 @@ TEST_COLLECTION(touchpad_tap) litest_add_ranged(touchpad_tap_n_drag_draglock, LITEST_TOUCHPAD, LITEST_ANY, &range_multifinger_tap); litest_add_ranged(touchpad_tap_n_drag_draglock_tap, LITEST_TOUCHPAD, LITEST_ANY, &range_multifinger_doubletap); litest_add_ranged(touchpad_tap_n_drag_draglock_timeout, LITEST_TOUCHPAD, LITEST_ANY, &range_multifinger_tap); + litest_add_ranged(touchpad_tap_n_drag_draglock_sticky, LITEST_TOUCHPAD, LITEST_ANY, &range_multifinger_tap); /* Real buttons don't interfere with tapping, so don't run those for pads with buttons */ diff --git a/tools/libinput-debug-events.man b/tools/libinput-debug-events.man index e602edec..b8f0727f 100644 --- a/tools/libinput-debug-events.man +++ b/tools/libinput-debug-events.man @@ -64,8 +64,10 @@ Enable or disable tap-to-click .B \-\-enable-drag|\-\-disable\-drag Enable or disable tap-and-drag .TP 8 -.B \-\-enable\-drag-lock|\-\-disable\-drag\-lock -Enable or disable drag-lock +.B \-\-enable\-drag\-lock|\-\-disable\-drag\-lock +Enable (in timeout mode) or disable drag-lock +.B \-\-enable\-drag\-lock=[sticky|timeout] +Enable drag-lock in sticky or timeout mode .TP 8 .B \-\-enable\-natural\-scrolling|\-\-disable\-natural\-scrolling Enable or disable natural scrolling diff --git a/tools/shared.c b/tools/shared.c index 25f9c43f..0fc2c454 100644 --- a/tools/shared.c +++ b/tools/shared.c @@ -158,10 +158,20 @@ tools_parse_option(int option, options->drag = 0; break; case OPT_DRAG_LOCK_ENABLE: - options->drag_lock = 1; + if (optarg) { + if (streq(optarg, "sticky")) { + options->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY; + } else if (streq(optarg, "timeout")) { + options->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_TIMEOUT; + } else { + return 1; + } + } else { + options->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_TIMEOUT; + } break; case OPT_DRAG_LOCK_DISABLE: - options->drag_lock = 0; + options->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED; break; case OPT_NATURAL_SCROLL_ENABLE: options->natural_scroll = 1; diff --git a/tools/shared.h b/tools/shared.h index cedb3159..8e874b52 100644 --- a/tools/shared.h +++ b/tools/shared.h @@ -74,7 +74,7 @@ enum configuration_options { { "disable-tap", no_argument, 0, OPT_TAP_DISABLE }, \ { "enable-drag", no_argument, 0, OPT_DRAG_ENABLE }, \ { "disable-drag", no_argument, 0, OPT_DRAG_DISABLE }, \ - { "enable-drag-lock", no_argument, 0, OPT_DRAG_LOCK_ENABLE }, \ + { "enable-drag-lock", optional_argument, 0, OPT_DRAG_LOCK_ENABLE }, \ { "disable-drag-lock", no_argument, 0, OPT_DRAG_LOCK_DISABLE }, \ { "enable-natural-scrolling", no_argument, 0, OPT_NATURAL_SCROLL_ENABLE }, \ { "disable-natural-scrolling", no_argument, 0, OPT_NATURAL_SCROLL_DISABLE }, \ diff --git a/tools/test_tool_option_parsing.py b/tools/test_tool_option_parsing.py index 9c0f6287..8f5a006e 100755 --- a/tools/test_tool_option_parsing.py +++ b/tools/test_tool_option_parsing.py @@ -219,6 +219,7 @@ options = { "set-profile": ["adaptive", "flat"], "set-tap-map": ["lrm", "lmr"], "set-clickfinger-map": ["lrm", "lmr"], + "enable-drag-lock": ["sticky", "timeout"], }, # options with a range (and increment) "ranges": {