}
static inline bool
-tp_key_ignore_for_dwt(unsigned int keycode)
+tp_key_is_modifier(unsigned int keycode)
{
switch (keycode) {
/* Ignore modifiers to be responsive to ctrl-click, alt-tab, etc. */
case KEY_LEFTMETA:
return true;
default:
- break;
+ return false;
}
+}
+static inline bool
+tp_key_ignore_for_dwt(unsigned int keycode)
+{
/* Ignore keys not part of the "typewriter set", i.e. F-keys,
* multimedia keys, numpad, etc.
*/
- if (keycode >= KEY_F1)
- return true;
- return false;
+ if (tp_key_is_modifier(keycode))
+ return false;
+
+ return keycode >= KEY_F1;
}
static void
struct libinput_event_keyboard *kbdev;
unsigned int timeout;
unsigned int key;
+ bool is_modifier;
if (event->type != LIBINPUT_EVENT_KEYBOARD_KEY)
return;
if (libinput_event_keyboard_get_key_state(kbdev) !=
LIBINPUT_KEY_STATE_PRESSED) {
long_clear_bit(tp->dwt.key_mask, key);
+ long_clear_bit(tp->dwt.mod_mask, key);
return;
}
if (!tp->dwt.dwt_enabled)
return;
+ if (tp_key_ignore_for_dwt(key))
+ return;
+
/* modifier keys don't trigger disable-while-typing so things like
* ctrl+zoom or ctrl+click are possible */
- if (tp_key_ignore_for_dwt(key))
+ is_modifier = tp_key_is_modifier(key);
+ if (is_modifier) {
+ long_set_bit(tp->dwt.mod_mask, key);
return;
+ }
if (!tp->dwt.keyboard_active) {
+ /* This is the first non-modifier key press. Check if the
+ * modifier mask is set. If any modifier is down we don't
+ * trigger dwt because it's likely to be combination like
+ * Ctrl+S or similar */
+
+ if (long_any_bit_set(tp->dwt.mod_mask,
+ ARRAY_LENGTH(tp->dwt.mod_mask)))
+ return;
+
tp_edge_scroll_stop_events(tp, time);
tp_gesture_cancel(tp, time);
tp_tap_suspend(tp, time);
return;
memset(tp->dwt.key_mask, 0, sizeof(tp->dwt.key_mask));
+ memset(tp->dwt.mod_mask, 0, sizeof(tp->dwt.mod_mask));
libinput_device_remove_event_listener(&tp->dwt.keyboard_listener);
}
}
END_TEST
+START_TEST(touchpad_dwt_modifier_combo_no_dwt)
+{
+ struct litest_device *touchpad = litest_current_device();
+ struct litest_device *keyboard;
+ struct libinput *li = touchpad->libinput;
+ unsigned int modifiers[] = {
+ KEY_LEFTCTRL,
+ KEY_RIGHTCTRL,
+ KEY_LEFTALT,
+ KEY_RIGHTALT,
+ KEY_LEFTSHIFT,
+ KEY_RIGHTSHIFT,
+ KEY_FN,
+ KEY_CAPSLOCK,
+ KEY_TAB,
+ KEY_COMPOSE,
+ KEY_RIGHTMETA,
+ KEY_LEFTMETA,
+ };
+ unsigned int *key;
+
+ if (!has_disable_while_typing(touchpad))
+ return;
+
+ keyboard = dwt_init_paired_keyboard(li, touchpad);
+ litest_disable_tap(touchpad->libinput_device);
+ litest_drain_events(li);
+
+ ARRAY_FOR_EACH(modifiers, key) {
+ litest_keyboard_key(keyboard, *key, true);
+ litest_keyboard_key(keyboard, KEY_A, true);
+ litest_keyboard_key(keyboard, KEY_A, false);
+ litest_keyboard_key(keyboard, KEY_B, true);
+ litest_keyboard_key(keyboard, KEY_B, false);
+ litest_keyboard_key(keyboard, *key, false);
+ libinput_dispatch(li);
+
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY);
+
+ litest_touch_down(touchpad, 0, 50, 50);
+ litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 5, 1);
+ litest_touch_up(touchpad, 0);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
+ }
+
+ litest_delete_device(keyboard);
+}
+END_TEST
+
+START_TEST(touchpad_dwt_modifier_combo_dwt_after)
+{
+ struct litest_device *touchpad = litest_current_device();
+ struct litest_device *keyboard;
+ struct libinput *li = touchpad->libinput;
+ unsigned int modifiers[] = {
+ KEY_LEFTCTRL,
+ KEY_RIGHTCTRL,
+ KEY_LEFTALT,
+ KEY_RIGHTALT,
+ KEY_LEFTSHIFT,
+ KEY_RIGHTSHIFT,
+ KEY_FN,
+ KEY_CAPSLOCK,
+ KEY_TAB,
+ KEY_COMPOSE,
+ KEY_RIGHTMETA,
+ KEY_LEFTMETA,
+ };
+ unsigned int *key;
+
+ if (!has_disable_while_typing(touchpad))
+ return;
+
+ keyboard = dwt_init_paired_keyboard(li, touchpad);
+ litest_disable_tap(touchpad->libinput_device);
+ litest_drain_events(li);
+
+ ARRAY_FOR_EACH(modifiers, key) {
+ litest_keyboard_key(keyboard, *key, true);
+ litest_keyboard_key(keyboard, KEY_A, true);
+ litest_keyboard_key(keyboard, KEY_A, false);
+ litest_keyboard_key(keyboard, *key, false);
+ libinput_dispatch(li);
+
+ litest_keyboard_key(keyboard, KEY_A, true);
+ litest_keyboard_key(keyboard, KEY_A, false);
+ libinput_dispatch(li);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY);
+
+ litest_touch_down(touchpad, 0, 50, 50);
+ litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 5, 1);
+ litest_touch_up(touchpad, 0);
+ litest_assert_empty_queue(li);
+
+ litest_timeout_dwt_long();
+ libinput_dispatch(li);
+ }
+
+ litest_delete_device(keyboard);
+}
+END_TEST
+
+START_TEST(touchpad_dwt_modifier_combo_dwt_remains)
+{
+ struct litest_device *touchpad = litest_current_device();
+ struct litest_device *keyboard;
+ struct libinput *li = touchpad->libinput;
+ unsigned int modifiers[] = {
+ KEY_LEFTCTRL,
+ KEY_RIGHTCTRL,
+ KEY_LEFTALT,
+ KEY_RIGHTALT,
+ KEY_LEFTSHIFT,
+ KEY_RIGHTSHIFT,
+ KEY_FN,
+ KEY_CAPSLOCK,
+ KEY_TAB,
+ KEY_COMPOSE,
+ KEY_RIGHTMETA,
+ KEY_LEFTMETA,
+ };
+ unsigned int *key;
+
+ if (!has_disable_while_typing(touchpad))
+ return;
+
+ keyboard = dwt_init_paired_keyboard(li, touchpad);
+ litest_disable_tap(touchpad->libinput_device);
+ litest_drain_events(li);
+
+ ARRAY_FOR_EACH(modifiers, key) {
+ litest_keyboard_key(keyboard, KEY_A, true);
+ litest_keyboard_key(keyboard, KEY_A, false);
+ libinput_dispatch(li);
+
+ /* this can't really be tested directly. The above key
+ * should enable dwt, the next key continues and extends the
+ * timeout as usual (despite the modifier combo). but
+ * testing for timeout differences is fickle, so all we can
+ * test though is that dwt is still on after the modifier
+ * combo and does not get disabled immediately.
+ */
+ litest_keyboard_key(keyboard, *key, true);
+ litest_keyboard_key(keyboard, KEY_A, true);
+ litest_keyboard_key(keyboard, KEY_A, false);
+ litest_keyboard_key(keyboard, *key, false);
+ libinput_dispatch(li);
+
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY);
+
+ litest_touch_down(touchpad, 0, 50, 50);
+ litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 5, 1);
+ litest_touch_up(touchpad, 0);
+ litest_assert_empty_queue(li);
+
+ litest_timeout_dwt_long();
+ libinput_dispatch(li);
+ }
+
+ litest_delete_device(keyboard);
+}
+END_TEST
+
START_TEST(touchpad_dwt_fkeys_no_dwt)
{
struct litest_device *touchpad = litest_current_device();
litest_add("touchpad:dwt", touchpad_dwt_type, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:dwt", touchpad_dwt_type_short_timeout, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:dwt", touchpad_dwt_modifier_no_dwt, LITEST_TOUCHPAD, LITEST_ANY);
+ litest_add("touchpad:dwt", touchpad_dwt_modifier_combo_no_dwt, LITEST_TOUCHPAD, LITEST_ANY);
+ litest_add("touchpad:dwt", touchpad_dwt_modifier_combo_dwt_after, LITEST_TOUCHPAD, LITEST_ANY);
+ litest_add("touchpad:dwt", touchpad_dwt_modifier_combo_dwt_remains, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:dwt", touchpad_dwt_fkeys_no_dwt, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:dwt", touchpad_dwt_tap, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:dwt", touchpad_dwt_tap_drag, LITEST_TOUCHPAD, LITEST_ANY);