evdev: Implement keyboard repeat
The kernel keyboard repeat functionality isn't configurable and libinput rightfully ignores it. This implements keyboard repeat in userspace allowing for consumers to set the initial delay and repeat intervals. https://bugzilla.gnome.org/show_bug.cgi?id=725102
This commit is contained in:
parent
133f95fd0d
commit
a6bd53ec42
@ -72,6 +72,15 @@ struct _ClutterSeatEvdev
|
||||
xkb_led_index_t num_lock_led;
|
||||
xkb_led_index_t scroll_lock_led;
|
||||
uint32_t button_state;
|
||||
|
||||
/* keyboard repeat */
|
||||
gboolean repeat;
|
||||
guint32 repeat_delay;
|
||||
guint32 repeat_interval;
|
||||
guint32 repeat_key;
|
||||
guint32 repeat_count;
|
||||
guint32 repeat_timer;
|
||||
ClutterInputDevice *repeat_device;
|
||||
};
|
||||
|
||||
typedef struct _ClutterEventSource ClutterEventSource;
|
||||
@ -206,6 +215,20 @@ remove_key (GArray *keys,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clear_repeat_timer (ClutterSeatEvdev *seat)
|
||||
{
|
||||
if (seat->repeat_timer)
|
||||
{
|
||||
g_source_remove (seat->repeat_timer);
|
||||
seat->repeat_timer = 0;
|
||||
g_clear_object (&seat->repeat_device);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
keyboard_repeat (gpointer data);
|
||||
|
||||
static void
|
||||
clutter_seat_evdev_sync_leds (ClutterSeatEvdev *seat);
|
||||
|
||||
@ -227,7 +250,10 @@ notify_key_device (ClutterInputDevice *input_device,
|
||||
* associated with the device yet. */
|
||||
stage = _clutter_input_device_get_stage (input_device);
|
||||
if (!stage)
|
||||
return;
|
||||
{
|
||||
clear_repeat_timer (seat);
|
||||
return;
|
||||
}
|
||||
|
||||
event = _clutter_key_event_new_from_evdev (input_device,
|
||||
seat->core_keyboard,
|
||||
@ -253,12 +279,71 @@ notify_key_device (ClutterInputDevice *input_device,
|
||||
}
|
||||
}
|
||||
else
|
||||
changed_state = 0;
|
||||
{
|
||||
changed_state = 0;
|
||||
clutter_event_set_flags (event, CLUTTER_EVENT_FLAG_SYNTHETIC);
|
||||
}
|
||||
|
||||
queue_event (event);
|
||||
|
||||
if (update_keys && (changed_state & XKB_STATE_LEDS))
|
||||
clutter_seat_evdev_sync_leds (seat);
|
||||
|
||||
if (state == 0 || /* key release */
|
||||
!seat->repeat ||
|
||||
!xkb_keymap_key_repeats (xkb_state_get_keymap (seat->xkb), event->key.hardware_keycode))
|
||||
{
|
||||
clear_repeat_timer (seat);
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == 1) /* key press */
|
||||
seat->repeat_count = 0;
|
||||
|
||||
seat->repeat_count += 1;
|
||||
seat->repeat_key = key;
|
||||
|
||||
switch (seat->repeat_count)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
{
|
||||
guint32 interval;
|
||||
|
||||
clear_repeat_timer (seat);
|
||||
seat->repeat_device = g_object_ref (input_device);
|
||||
|
||||
if (seat->repeat_count == 1)
|
||||
interval = seat->repeat_delay;
|
||||
else
|
||||
interval = seat->repeat_interval;
|
||||
|
||||
seat->repeat_timer =
|
||||
clutter_threads_add_timeout_full (CLUTTER_PRIORITY_EVENTS,
|
||||
interval,
|
||||
keyboard_repeat,
|
||||
seat,
|
||||
NULL);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
keyboard_repeat (gpointer data)
|
||||
{
|
||||
ClutterSeatEvdev *seat = data;
|
||||
guint32 time;
|
||||
|
||||
g_return_val_if_fail (seat->repeat_device != NULL, G_SOURCE_REMOVE);
|
||||
|
||||
time = g_source_get_time (g_main_context_find_source_by_id (NULL, seat->repeat_timer)) / 1000;
|
||||
|
||||
notify_key_device (seat->repeat_device, time, seat->repeat_key, AUTOREPEAT_VALUE, FALSE);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -642,6 +727,10 @@ clutter_seat_evdev_new (ClutterDeviceManagerEvdev *manager_evdev,
|
||||
xkb_keymap_unref (keymap);
|
||||
}
|
||||
|
||||
seat->repeat = TRUE;
|
||||
seat->repeat_delay = 250; /* ms */
|
||||
seat->repeat_interval = 33; /* ms */
|
||||
|
||||
return seat;
|
||||
}
|
||||
|
||||
@ -661,6 +750,8 @@ clutter_seat_evdev_free (ClutterSeatEvdev *seat)
|
||||
xkb_state_unref (seat->xkb);
|
||||
g_array_free (seat->keys, TRUE);
|
||||
|
||||
clear_repeat_timer (seat);
|
||||
|
||||
libinput_seat_unref (seat->libinput_seat);
|
||||
|
||||
g_free (seat);
|
||||
@ -773,6 +864,9 @@ clutter_device_manager_evdev_remove_device (ClutterDeviceManager *manager,
|
||||
seat->devices = g_slist_remove (seat->devices, device);
|
||||
priv->devices = g_slist_remove (priv->devices, device);
|
||||
|
||||
if (seat->repeat_timer && seat->repeat_device == device)
|
||||
clear_repeat_timer (seat);
|
||||
|
||||
g_object_unref (device);
|
||||
}
|
||||
|
||||
@ -1480,3 +1574,34 @@ clutter_evdev_set_pointer_constrain_callback (ClutterDeviceManager *e
|
||||
priv->constrain_data = user_data;
|
||||
priv->constrain_data_notify = user_data_notify;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_evdev_set_keyboard_repeat:
|
||||
* @evdev: the #ClutterDeviceManager created by the evdev backend
|
||||
* @repeat: whether to enable or disable keyboard repeat events
|
||||
* @delay: the delay in ms between the hardware key press event and
|
||||
* the first synthetic event
|
||||
* @interval: the period in ms between consecutive synthetic key
|
||||
* press events
|
||||
*
|
||||
* Enables or disables sythetic key press events, allowing for initial
|
||||
* delay and interval period to be specified.
|
||||
*/
|
||||
void
|
||||
clutter_evdev_set_keyboard_repeat (ClutterDeviceManager *evdev,
|
||||
gboolean repeat,
|
||||
guint32 delay,
|
||||
guint32 interval)
|
||||
{
|
||||
ClutterDeviceManagerEvdev *manager_evdev;
|
||||
ClutterSeatEvdev *seat;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER_EVDEV (evdev));
|
||||
|
||||
manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (evdev);
|
||||
seat = manager_evdev->priv->main_seat;
|
||||
|
||||
seat->repeat = repeat;
|
||||
seat->repeat_delay = delay;
|
||||
seat->repeat_interval = interval;
|
||||
}
|
||||
|
@ -85,6 +85,10 @@ void clutter_evdev_set_pointer_constrain_callback (ClutterDeviceManager
|
||||
void clutter_evdev_set_keyboard_map (ClutterDeviceManager *evdev,
|
||||
struct xkb_keymap *keymap);
|
||||
|
||||
void clutter_evdev_set_keyboard_repeat (ClutterDeviceManager *evdev,
|
||||
gboolean repeat,
|
||||
guint32 delay,
|
||||
guint32 interval);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user