From 7d29070faf4dadb8949b6abbc5e1f9b1f806a146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 7 Jan 2011 12:10:41 -0500 Subject: [PATCH] Implement GdkKeymap using libxkbcommon --- gdk/wayland/gdkdevice-wayland.h | 3 +- gdk/wayland/gdkdevicemanager-wayland.c | 29 ++-- gdk/wayland/gdkdisplay-wayland.c | 5 +- gdk/wayland/gdkkeys-wayland.c | 218 ++++++++++++++++++++++--- gdk/wayland/gdkprivate-wayland.h | 4 +- 5 files changed, 218 insertions(+), 41 deletions(-) diff --git a/gdk/wayland/gdkdevice-wayland.h b/gdk/wayland/gdkdevice-wayland.h index 88fac43a6e..a8d4dd99d0 100644 --- a/gdk/wayland/gdkdevice-wayland.h +++ b/gdk/wayland/gdkdevice-wayland.h @@ -20,8 +20,8 @@ #ifndef __GDK_DEVICE_CORE_H__ #define __GDK_DEVICE_CORE_H__ +#include #include -#include G_BEGIN_DECLS @@ -45,7 +45,6 @@ struct _GdkWaylandDevice GdkWindow *pointer_focus; GdkWindow *keyboard_focus; struct wl_input_device *device; - struct xkb_desc *xkb; int32_t x, y, surface_x, surface_y; }; diff --git a/gdk/wayland/gdkdevicemanager-wayland.c b/gdk/wayland/gdkdevicemanager-wayland.c index c432ec7ea8..d1543f9a70 100644 --- a/gdk/wayland/gdkdevicemanager-wayland.c +++ b/gdk/wayland/gdkdevicemanager-wayland.c @@ -28,6 +28,7 @@ #include "gdkprivate-wayland.h" #include "gdkeventsource.h" +#include static void gdk_device_manager_core_finalize (GObject *object); @@ -116,6 +117,8 @@ input_handle_key(void *data, struct wl_input_device *input_device, GdkWaylandDevice *device = data; GdkEvent *event; uint32_t code, modifier, level; + struct xkb_desc *xkb; + GdkKeymap *keymap; event = gdk_event_new (state ? GDK_KEY_PRESS : GDK_KEY_RELEASE); event->key.window = g_object_ref (device->keyboard_focus); @@ -125,16 +128,19 @@ input_handle_key(void *data, struct wl_input_device *input_device, event->key.group = 0; event->key.hardware_keycode = key; - code = key + device->xkb->min_key_code; + keymap = gdk_keymap_get_for_display (device->display); + xkb = _gdk_wayland_keymap_get_xkb_desc (keymap); + + code = key + xkb->min_key_code; level = 0; if (device->modifiers & ShiftMask && - XkbKeyGroupWidth(device->xkb, code, 0) > 1) + XkbKeyGroupWidth(xkb, code, 0) > 1) level = 1; - event->key.keyval = XkbKeySymEntry(device->xkb, code, level, 0); + event->key.keyval = XkbKeySymEntry(xkb, code, level, 0); - modifier = device->xkb->map->modmap[code]; + modifier = xkb->map->modmap[code]; if (state) device->modifiers |= modifier; else @@ -269,10 +275,15 @@ static void update_modifiers(GdkWaylandDevice *device, struct wl_array *keys) { uint32_t *k, *end; + GdkKeymap *keymap; + struct xkb_desc *xkb; + + keymap = gdk_keymap_get_for_display (device->display); + xkb = _gdk_wayland_keymap_get_xkb_desc (keymap); end = keys->data + keys->size; for (k = keys->data; k < end; k++) - device->modifiers |= device->xkb->map->modmap[*k]; + device->modifiers |= xkb->map->modmap[*k]; fprintf (stderr, "modifiers: 0x%x\n", device->modifiers); } @@ -335,7 +346,6 @@ gdk_device_manager_core_add_device (GdkDeviceManager *device_manager, GdkDisplay *display; GdkDeviceManagerCore *device_manager_core = GDK_DEVICE_MANAGER_CORE(device_manager); - struct xkb_rule_names names; GdkWaylandDevice *device; device = g_new0 (GdkWaylandDevice, 1); @@ -366,13 +376,6 @@ gdk_device_manager_core_add_device (GdkDeviceManager *device_manager, GDK_DEVICE_CORE (device->keyboard)->device = device; device->device = wl_device; - names.rules = "evdev"; - names.model = "pc105"; - names.layout = "us"; - names.variant = ""; - names.options = ""; - device->xkb = xkb_compile_keymap_from_rules(&names); - wl_input_device_add_listener(device->device, &input_device_listener, device); diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c index fefa1f55cd..34740d18d4 100644 --- a/gdk/wayland/gdkdisplay-wayland.c +++ b/gdk/wayland/gdkdisplay-wayland.c @@ -709,10 +709,7 @@ gdk_wayland_display_get_keymap (GdkDisplay *display) display_wayland = GDK_DISPLAY_WAYLAND (display); if (!display_wayland->keymap) - display_wayland->keymap = - g_object_new (_gdk_wayland_keymap_get_type(), NULL); - - display_wayland->keymap->display = display; + display_wayland->keymap = _gdk_wayland_keymap_new (display); return display_wayland->keymap; } diff --git a/gdk/wayland/gdkkeys-wayland.c b/gdk/wayland/gdkkeys-wayland.c index 87b139814a..f18bf0e291 100644 --- a/gdk/wayland/gdkkeys-wayland.c +++ b/gdk/wayland/gdkkeys-wayland.c @@ -49,6 +49,7 @@ typedef struct _GdkWaylandKeymapClass GdkWaylandKeymapClass; struct _GdkWaylandKeymap { GdkKeymap parent_instance; + struct xkb_desc *xkb; }; struct _GdkWaylandKeymapClass @@ -57,7 +58,7 @@ struct _GdkWaylandKeymapClass }; #define GDK_TYPE_WAYLAND_KEYMAP (_gdk_wayland_keymap_get_type ()) -#define GDK_WAYLAND_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_KEYMAP, GdkWaylandKeyMap)) +#define GDK_WAYLAND_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_KEYMAP, GdkWaylandKeymap)) #define GDK_IS_WAYLAND_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_KEYMAP)) G_DEFINE_TYPE (GdkWaylandKeymap, _gdk_wayland_keymap, GDK_TYPE_KEYMAP) @@ -94,39 +95,190 @@ gdk_wayland_keymap_get_num_lock_state (GdkKeymap *keymap) static gboolean gdk_wayland_keymap_get_entries_for_keyval (GdkKeymap *keymap, - guint keyval, - GdkKeymapKey **keys, - gint *n_keys) + guint keyval, + GdkKeymapKey **keys, + gint *n_keys) { - return FALSE; + GArray *retval; + uint32_t keycode; + struct xkb_desc *xkb; + + xkb = GDK_WAYLAND_KEYMAP (keymap)->xkb; + keycode = xkb->min_key_code; + + retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey)); + + for (keycode = xkb->min_key_code; keycode <= xkb->max_key_code; keycode++) + { + gint max_shift_levels = XkbKeyGroupsWidth (xkb, keycode); + + gint group = 0; + gint level = 0; + gint total_syms = XkbKeyNumSyms (xkb, keycode); + gint i = 0; + uint32_t *entry; + + /* entry is an array with all syms for group 0, all + * syms for group 1, etc. and for each group the + * shift level syms are in order + */ + entry = XkbKeySymsPtr (xkb, keycode); + + for (i = 0; i < total_syms; i++) + { + /* check out our cool loop invariant */ + g_assert (i == (group * max_shift_levels + level)); + + if (entry[i] == keyval) + { + /* Found a match */ + GdkKeymapKey key; + + key.keycode = keycode; + key.group = group; + key.level = level; + + g_array_append_val (retval, key); + + g_assert (XkbKeySymEntry (xkb, keycode, level, group) == + keyval); + } + + level++; + + if (level == max_shift_levels) + { + level = 0; + group++; + } + } + } + + *n_keys = retval->len; + *keys = (GdkKeymapKey *) g_array_free (retval, FALSE); + + return *n_keys > 0; } static gboolean gdk_wayland_keymap_get_entries_for_keycode (GdkKeymap *keymap, - guint hardware_keycode, - GdkKeymapKey **keys, - guint **keyvals, - gint *n_entries) + guint hardware_keycode, + GdkKeymapKey **keys, + guint **keyvals, + gint *n_entries) { - return FALSE; + GArray *key_array; + GArray *keyval_array; + struct xkb_desc *xkb; + gint max_shift_levels; + gint group = 0; + gint level = 0; + gint total_syms; + gint i; + uint32_t *entry; + + g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE); + g_return_val_if_fail (n_entries != NULL, FALSE); + + xkb = GDK_WAYLAND_KEYMAP (keymap)->xkb; + + if (hardware_keycode < xkb->min_key_code || + hardware_keycode > xkb->max_key_code) + { + if (keys) + *keys = NULL; + if (keyvals) + *keyvals = NULL; + + *n_entries = 0; + return FALSE; + } + + if (keys) + key_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey)); + else + key_array = NULL; + + if (keyvals) + keyval_array = g_array_new (FALSE, FALSE, sizeof (guint)); + else + keyval_array = NULL; + + /* See sec 15.3.4 in XKB docs */ + max_shift_levels = XkbKeyGroupsWidth (xkb, hardware_keycode); + total_syms = XkbKeyNumSyms (xkb, hardware_keycode); + + /* entry is an array with all syms for group 0, all + * syms for group 1, etc. and for each group the + * shift level syms are in order + */ + entry = XkbKeySymsPtr (xkb, hardware_keycode); + + for (i = 0; i < total_syms; i++) + { + /* check out our cool loop invariant */ + g_assert (i == (group * max_shift_levels + level)); + + if (key_array) + { + GdkKeymapKey key; + + key.keycode = hardware_keycode; + key.group = group; + key.level = level; + + g_array_append_val (key_array, key); + } + + if (keyval_array) + g_array_append_val (keyval_array, entry[i]); + + ++level; + + if (level == max_shift_levels) + { + level = 0; + ++group; + } + } + + *n_entries = 0; + + if (keys) + { + *n_entries = key_array->len; + *keys = (GdkKeymapKey*) g_array_free (key_array, FALSE); + } + + if (keyvals) + { + *n_entries = keyval_array->len; + *keyvals = (guint*) g_array_free (keyval_array, FALSE); + } + + return *n_entries > 0; } static guint gdk_wayland_keymap_lookup_key (GdkKeymap *keymap, - const GdkKeymapKey *key) + const GdkKeymapKey *key) { - return 0; + struct xkb_desc *xkb; + + xkb = GDK_WAYLAND_KEYMAP (keymap)->xkb; + + return XkbKeySymEntry (xkb, key->keycode, key->level, key->group); } static gboolean gdk_wayland_keymap_translate_keyboard_state (GdkKeymap *keymap, - guint hardware_keycode, - GdkModifierType state, - gint group, - guint *keyval, - gint *effective_group, - gint *level, - GdkModifierType *consumed_modifiers) + guint hardware_keycode, + GdkModifierType state, + gint group, + guint *keyval, + gint *effective_group, + gint *level, + GdkModifierType *consumed_modifiers) { return FALSE; } @@ -134,13 +286,13 @@ gdk_wayland_keymap_translate_keyboard_state (GdkKeymap *keymap, static void gdk_wayland_keymap_add_virtual_modifiers (GdkKeymap *keymap, - GdkModifierType *state) + GdkModifierType *state) { } static gboolean gdk_wayland_keymap_map_virtual_modifiers (GdkKeymap *keymap, - GdkModifierType *state) + GdkModifierType *state) { return FALSE; } @@ -169,3 +321,27 @@ static void _gdk_wayland_keymap_init (GdkWaylandKeymap *keymap) { } + +GdkKeymap * +_gdk_wayland_keymap_new (GdkDisplay *display) +{ + GdkWaylandKeymap *keymap; + struct xkb_rule_names names; + + keymap = g_object_new (_gdk_wayland_keymap_get_type(), NULL); + GDK_KEYMAP (keymap)->display = display; + + names.rules = "evdev"; + names.model = "pc105"; + names.layout = "us"; + names.variant = ""; + names.options = ""; + keymap->xkb = xkb_compile_keymap_from_rules(&names); + + return GDK_KEYMAP (keymap); +} + +struct xkb_desc *_gdk_wayland_keymap_get_xkb_desc (GdkKeymap *keymap) +{ + return GDK_WAYLAND_KEYMAP (keymap)->xkb; +} diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h index ef13fea1ba..dcd9fa9227 100644 --- a/gdk/wayland/gdkprivate-wayland.h +++ b/gdk/wayland/gdkprivate-wayland.h @@ -46,7 +46,9 @@ #define GDK_WINDOW_IS_WAYLAND(win) (GDK_IS_WINDOW_IMPL_WAYLAND (((GdkWindow *)win)->impl)) GType _gdk_wayland_window_get_type (void); -GType _gdk_wayland_keymap_get_type (void); + +GdkKeymap *_gdk_wayland_keymap_new (GdkDisplay *display); +struct xkb_desc *_gdk_wayland_keymap_get_xkb_desc (GdkKeymap *keymap); GdkCursor *_gdk_wayland_display_get_cursor_for_type (GdkDisplay *display, GdkCursorType cursor_type);