[mutter] clutter/evdev: implement slow keys support
- From: Olivier Fourdan <ofourdan src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] clutter/evdev: implement slow keys support
- Date: Thu, 16 Nov 2017 13:35:42 +0000 (UTC)
commit fa28481736929d8e04daa7435e23b5fab7a49952
Author: Olivier Fourdan <ofourdan redhat com>
Date: Thu Oct 12 17:16:00 2017 +0200
clutter/evdev: implement slow keys support
Delay emitting clutter key press events when slow key is enabled.
https://bugzilla.gnome.org/show_bug.cgi?id=788564
clutter/clutter/evdev/clutter-input-device-evdev.c | 152 ++++++++++++++++++++
clutter/clutter/evdev/clutter-input-device-evdev.h | 1 +
2 files changed, 153 insertions(+), 0 deletions(-)
---
diff --git a/clutter/clutter/evdev/clutter-input-device-evdev.c
b/clutter/clutter/evdev/clutter-input-device-evdev.c
index 6dcb818..0cc37c1 100644
--- a/clutter/clutter/evdev/clutter-input-device-evdev.c
+++ b/clutter/clutter/evdev/clutter-input-device-evdev.c
@@ -54,6 +54,16 @@ enum {
static GParamSpec *obj_props[N_PROPS] = { 0 };
+typedef struct _SlowKeysEventPending
+{
+ ClutterInputDeviceEvdev *device;
+ ClutterEvent *event;
+ ClutterEmitInputDeviceEvent emit_event_func;
+ guint timer;
+} SlowKeysEventPending;
+
+static void clear_slow_keys (ClutterInputDeviceEvdev *device);
+
static void
clutter_input_device_evdev_finalize (GObject *object)
{
@@ -67,6 +77,8 @@ clutter_input_device_evdev_finalize (GObject *object)
_clutter_device_manager_evdev_release_device_id (manager_evdev, device);
+ clear_slow_keys (device_evdev);
+
G_OBJECT_CLASS (clutter_input_device_evdev_parent_class)->finalize (object);
}
@@ -210,6 +222,130 @@ clutter_input_device_evdev_is_grouped (ClutterInputDevice *device,
}
static void
+clutter_input_device_evdev_bell_notify (void)
+{
+ ClutterBackend *backend;
+
+ backend = clutter_get_default_backend ();
+ clutter_backend_bell_notify (backend);
+}
+
+static void
+clutter_input_device_evdev_free_pending_slow_key (gpointer data)
+{
+ SlowKeysEventPending *slow_keys_event = data;
+
+ clutter_event_free (slow_keys_event->event);
+ if (slow_keys_event->timer)
+ g_source_remove (slow_keys_event->timer);
+ g_free (slow_keys_event);
+}
+
+static void
+clear_slow_keys (ClutterInputDeviceEvdev *device)
+{
+ g_list_free_full (device->slow_keys_list, clutter_input_device_evdev_free_pending_slow_key);
+ g_list_free (device->slow_keys_list);
+ device->slow_keys_list = NULL;
+}
+
+static guint
+get_slow_keys_delay (ClutterInputDevice *device)
+{
+ ClutterKbdA11ySettings a11y_settings;
+
+ clutter_device_manager_get_kbd_a11y_settings (device->device_manager,
+ &a11y_settings);
+ /* Settings use int, we use uint, make sure we dont go negative */
+ return MAX (0, a11y_settings.slowkeys_delay);
+}
+
+static gboolean
+trigger_slow_keys (gpointer data)
+{
+ SlowKeysEventPending *slow_keys_event = data;
+ ClutterInputDeviceEvdev *device = slow_keys_event->device;
+ ClutterKeyEvent *key_event = (ClutterKeyEvent *) slow_keys_event->event;
+
+ /* Alter timestamp and emit the event */
+ key_event->time = us2ms (g_get_monotonic_time ());
+ slow_keys_event->emit_event_func (slow_keys_event->event,
+ CLUTTER_INPUT_DEVICE (device));
+
+ /* Then remote the pending event */
+ device->slow_keys_list = g_list_remove (device->slow_keys_list, slow_keys_event);
+ clutter_input_device_evdev_free_pending_slow_key (slow_keys_event);
+
+ if (device->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT)
+ clutter_input_device_evdev_bell_notify ();
+
+ return G_SOURCE_REMOVE;
+}
+
+static gint
+find_pending_event_by_keycode (gconstpointer a,
+ gconstpointer b)
+{
+ const SlowKeysEventPending *pa = a;
+ const ClutterKeyEvent *ka = (ClutterKeyEvent *) pa->event;
+ const ClutterKeyEvent *kb = b;
+
+ return kb->hardware_keycode - ka->hardware_keycode;
+}
+
+static void
+start_slow_keys (ClutterEvent *event,
+ ClutterInputDeviceEvdev *device,
+ ClutterEmitInputDeviceEvent emit_event_func)
+{
+ SlowKeysEventPending *slow_keys_event;
+ ClutterKeyEvent *key_event = (ClutterKeyEvent *) event;
+
+ /* Synthetic key events are for autorepeat, ignore those... */
+ if (key_event->flags & CLUTTER_EVENT_FLAG_SYNTHETIC)
+ return;
+
+ slow_keys_event = g_new0 (SlowKeysEventPending, 1);
+ slow_keys_event->device = device;
+ slow_keys_event->event = clutter_event_copy (event);
+ slow_keys_event->emit_event_func = emit_event_func;
+ slow_keys_event->timer =
+ clutter_threads_add_timeout (get_slow_keys_delay (CLUTTER_INPUT_DEVICE (device)),
+ trigger_slow_keys,
+ slow_keys_event);
+ device->slow_keys_list = g_list_append (device->slow_keys_list, slow_keys_event);
+
+ if (device->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS)
+ clutter_input_device_evdev_bell_notify ();
+}
+
+static void
+stop_slow_keys (ClutterEvent *event,
+ ClutterInputDeviceEvdev *device,
+ ClutterEmitInputDeviceEvent emit_event_func)
+{
+ GList *item;
+
+ /* Check if we have a slow key event queued for this key event */
+ item = g_list_find_custom (device->slow_keys_list, event, find_pending_event_by_keycode);
+ if (item)
+ {
+ SlowKeysEventPending *slow_keys_event = item->data;
+
+ device->slow_keys_list = g_list_delete_link (device->slow_keys_list, item);
+ clutter_input_device_evdev_free_pending_slow_key (slow_keys_event);
+
+ if (device->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT)
+ clutter_input_device_evdev_bell_notify ();
+
+ return;
+ }
+
+ /* If no key press event was pending, just emit the key release as-is */
+ emit_event_func (event, CLUTTER_INPUT_DEVICE (device));
+}
+
+static void
clutter_input_device_evdev_process_kbd_a11y_event (ClutterEvent *event,
ClutterInputDevice *device,
ClutterEmitInputDeviceEvent emit_event_func)
@@ -219,6 +355,17 @@ clutter_input_device_evdev_process_kbd_a11y_event (ClutterEvent *e
if (!device_evdev->a11y_flags & CLUTTER_A11Y_KEYBOARD_ENABLED)
goto emit_event;
+ if ((device_evdev->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_ENABLED) &&
+ (get_slow_keys_delay (device) != 0))
+ {
+ if (event->type == CLUTTER_KEY_PRESS)
+ start_slow_keys (event, device_evdev, emit_event_func);
+ else if (event->type == CLUTTER_KEY_RELEASE)
+ stop_slow_keys (event, device_evdev, emit_event_func);
+
+ return;
+ }
+
emit_event:
emit_event_func (event, device);
}
@@ -227,6 +374,11 @@ void
clutter_input_device_evdev_apply_kbd_a11y_settings (ClutterInputDeviceEvdev *device,
ClutterKbdA11ySettings *settings)
{
+ ClutterKeyboardA11yFlags changed_flags = (device->a11y_flags ^ settings->controls);
+
+ if (changed_flags & (CLUTTER_A11Y_KEYBOARD_ENABLED | CLUTTER_A11Y_SLOW_KEYS_ENABLED))
+ clear_slow_keys (device);
+
/* Keep our own copy of keyboard a11y features flags to see what changes */
device->a11y_flags = settings->controls;
}
diff --git a/clutter/clutter/evdev/clutter-input-device-evdev.h
b/clutter/clutter/evdev/clutter-input-device-evdev.h
index b8ce760..a054e0d 100644
--- a/clutter/clutter/evdev/clutter-input-device-evdev.h
+++ b/clutter/clutter/evdev/clutter-input-device-evdev.h
@@ -73,6 +73,7 @@ struct _ClutterInputDeviceEvdev
/* Keyboard a11y */
ClutterKeyboardA11yFlags a11y_flags;
+ GList *slow_keys_list;
};
GType _clutter_input_device_evdev_get_type (void) G_GNUC_CONST;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]