From 33e928e472abf3d393ddb65d92b0cebc508df4c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Dapena=20Paz?= Date: Mon, 16 Jul 2012 20:08:20 +0100 Subject: [PATCH] wayland: Initial version of keyboard key event handling Review comment: I think the implementation of the vfuncs in gdkkeys-wayland.c depend on that we're using the keysysm as the hardware keycode. I think that needs to be evaluated for the future. But for now this patch gives reasonably complete keyboard input. Signed-off-by: Rob Bradford --- gdk/wayland/gdkdevice-wayland.c | 187 +++++++++++++ gdk/wayland/gdkkeys-wayland.c | 473 ++------------------------------ 2 files changed, 205 insertions(+), 455 deletions(-) diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c index 8e3f87f4bc..3f7091c303 100644 --- a/gdk/wayland/gdkdevice-wayland.c +++ b/gdk/wayland/gdkdevice-wayland.c @@ -1233,6 +1233,177 @@ keyboard_handle_leave (void *data, _gdk_wayland_display_deliver_event (device->display, event); } +static gboolean +keyboard_repeat (gpointer data); + +static GdkModifierType +get_modifier (struct xkb_state *state) +{ + GdkModifierType modifiers = 0; + modifiers |= (xkb_state_mod_name_is_active (state, XKB_MOD_NAME_SHIFT, XKB_STATE_EFFECTIVE) > 0)?GDK_SHIFT_MASK:0; + modifiers |= (xkb_state_mod_name_is_active (state, XKB_MOD_NAME_CAPS, XKB_STATE_EFFECTIVE) > 0)?GDK_LOCK_MASK:0; + modifiers |= (xkb_state_mod_name_is_active (state, XKB_MOD_NAME_CTRL, XKB_STATE_EFFECTIVE) > 0)?GDK_CONTROL_MASK:0; + modifiers |= (xkb_state_mod_name_is_active (state, XKB_MOD_NAME_ALT, XKB_STATE_EFFECTIVE) > 0)?GDK_MOD1_MASK:0; + modifiers |= (xkb_state_mod_name_is_active (state, "Mod2", XKB_STATE_EFFECTIVE) > 0)?GDK_MOD2_MASK:0; + modifiers |= (xkb_state_mod_name_is_active (state, "Mod3", XKB_STATE_EFFECTIVE) > 0)?GDK_MOD3_MASK:0; + modifiers |= (xkb_state_mod_name_is_active (state, XKB_MOD_NAME_LOGO, XKB_STATE_EFFECTIVE) > 0)?GDK_MOD4_MASK:0; + modifiers |= (xkb_state_mod_name_is_active (state, "Mod5", XKB_STATE_EFFECTIVE) > 0)?GDK_MOD5_MASK:0; + + return modifiers; +} + +static void +translate_keyboard_string (GdkEventKey *event) +{ + gunichar c = 0; + gchar buf[7]; + + /* Fill in event->string crudely, since various programs + * depend on it. + */ + event->string = NULL; + + if (event->keyval != GDK_KEY_VoidSymbol) + c = gdk_keyval_to_unicode (event->keyval); + + if (c) + { + gsize bytes_written; + gint len; + + /* Apply the control key - Taken from Xlib + */ + if (event->state & GDK_CONTROL_MASK) + { + if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F; + else if (c == '2') + { + event->string = g_memdup ("\0\0", 2); + event->length = 1; + buf[0] = '\0'; + return; + } + else if (c >= '3' && c <= '7') c -= ('3' - '\033'); + else if (c == '8') c = '\177'; + else if (c == '/') c = '_' & 0x1F; + } + + len = g_unichar_to_utf8 (c, buf); + buf[len] = '\0'; + + event->string = g_locale_from_utf8 (buf, len, + NULL, &bytes_written, + NULL); + if (event->string) + event->length = bytes_written; + } + else if (event->keyval == GDK_KEY_Escape) + { + event->length = 1; + event->string = g_strdup ("\033"); + } + else if (event->keyval == GDK_KEY_Return || + event->keyval == GDK_KEY_KP_Enter) + { + event->length = 1; + event->string = g_strdup ("\r"); + } + + if (!event->string) + { + event->length = 0; + event->string = g_strdup (""); + } +} + +static gboolean +deliver_key_event(GdkWaylandDevice *device, + uint32_t time, uint32_t key, uint32_t state) +{ + GdkEvent *event; + struct xkb_state *xkb_state; + GdkKeymap *keymap; + xkb_keysym_t sym; + uint32_t num_syms; + const xkb_keysym_t *syms; + + keymap = device->keymap; + xkb_state = _gdk_wayland_keymap_get_xkb_state (keymap); + + num_syms = xkb_key_get_syms (xkb_state, key, &syms); + sym = XKB_KEY_NoSymbol; + if (num_syms == 1) + sym = syms[0]; + + device->time = time; + device->modifiers = get_modifier (xkb_state); + + event = gdk_event_new (state ? GDK_KEY_PRESS : GDK_KEY_RELEASE); + event->key.window = device->keyboard_focus?g_object_ref (device->keyboard_focus):NULL; + gdk_event_set_device (event, device->keyboard); + event->button.time = time; + event->key.state = device->modifiers; + event->key.group = 0; + event->key.hardware_keycode = sym; + event->key.keyval = sym; + + event->key.is_modifier = device->modifiers > 0; + + translate_keyboard_string (&event->key); + + _gdk_wayland_display_deliver_event (device->display, event); + + GDK_NOTE (EVENTS, + g_message ("keyboard event, code %d, sym %d, " + "string %s, mods 0x%x", + event->key.hardware_keycode, event->key.keyval, + event->key.string, event->key.state)); + + device->repeat_count++; + device->repeat_key = key; + + if (state == 0) + { + if (device->repeat_timer) + { + g_source_remove (device->repeat_timer); + device->repeat_timer = 0; + } + return FALSE; + } + else if (device->modifiers) + { + return FALSE; + } + else switch (device->repeat_count) + { + case 1: + if (device->repeat_timer) + { + g_source_remove (device->repeat_timer); + device->repeat_timer = 0; + } + + device->repeat_timer = + gdk_threads_add_timeout (400, keyboard_repeat, device); + return TRUE; + case 2: + device->repeat_timer = + gdk_threads_add_timeout (80, keyboard_repeat, device); + return FALSE; + default: + return TRUE; + } +} + +static gboolean +keyboard_repeat (gpointer data) +{ + GdkWaylandDevice *device = data; + + return deliver_key_event (device, device->time, device->repeat_key, 1); +} + static void keyboard_handle_key (void *data, struct wl_keyboard *keyboard, @@ -1241,6 +1412,13 @@ keyboard_handle_key (void *data, uint32_t key, uint32_t state_w) { + GdkWaylandDevice *device = data; + GdkWaylandDisplay *wayland_display = + GDK_WAYLAND_DISPLAY (device->display); + + device->repeat_count = 0; + _gdk_wayland_display_update_serial (wayland_display, serial); + deliver_key_event (data, time, key + 8, state_w); } static void @@ -1252,6 +1430,15 @@ keyboard_handle_modifiers (void *data, uint32_t mods_locked, uint32_t group) { + GdkWaylandDevice *device = data; + GdkKeymap *keymap; + struct xkb_state *xkb_state; + + keymap = device->keymap; + xkb_state = _gdk_wayland_keymap_get_xkb_state (keymap); + device->modifiers = mods_depressed | mods_latched | mods_locked; + + xkb_state_update_mask (xkb_state, mods_depressed, mods_latched, mods_locked, group, 0, 0); } static const struct wl_pointer_listener pointer_listener = { diff --git a/gdk/wayland/gdkkeys-wayland.c b/gdk/wayland/gdkkeys-wayland.c index 819ff9c308..b63079dbd0 100644 --- a/gdk/wayland/gdkkeys-wayland.c +++ b/gdk/wayland/gdkkeys-wayland.c @@ -101,68 +101,15 @@ gdk_wayland_keymap_get_entries_for_keyval (GdkKeymap *keymap, GdkKeymapKey **keys, gint *n_keys) { -#if 0 - 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++) + if (n_keys) + *n_keys = 1; + if (keys) { - 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++; - } - } + *keys = g_new0 (GdkKeymapKey, 1); + (*keys)->keycode = keyval; } - *n_keys = retval->len; - *keys = (GdkKeymapKey *) g_array_free (retval, FALSE); - - return *n_keys > 0; -#endif - return FALSE; + return TRUE; } static gboolean @@ -172,247 +119,28 @@ gdk_wayland_keymap_get_entries_for_keycode (GdkKeymap *keymap, guint **keyvals, gint *n_entries) { -#if 0 - 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 (n_entries) + *n_entries = 1; if (keys) { - *n_entries = key_array->len; - *keys = (GdkKeymapKey*) g_array_free (key_array, FALSE); + *keys = g_new0 (GdkKeymapKey, 1); + (*keys)->keycode = hardware_keycode; } - if (keyvals) { - *n_entries = keyval_array->len; - *keyvals = (guint*) g_array_free (keyval_array, FALSE); + *keyvals = g_new0 (guint, 1); + (*keyvals)[0] = hardware_keycode; } - - return *n_entries > 0; -#endif - return FALSE; + return TRUE; } static guint gdk_wayland_keymap_lookup_key (GdkKeymap *keymap, const GdkKeymapKey *key) { -#if 0 - struct xkb_desc *xkb; - - xkb = GDK_WAYLAND_KEYMAP (keymap)->xkb; - - return XkbKeySymEntry (xkb, key->keycode, key->level, key->group); -#endif - return 0; + return key->keycode; } -#if 0 -/* This is copied straight from XFree86 Xlib, to: - * - add the group and level return. - * - change the interpretation of mods_rtrn as described - * in the docs for gdk_keymap_translate_keyboard_state() - * It's unchanged for ease of diff against the Xlib sources; don't - * reformat it. - */ -static int -MyEnhancedXkbTranslateKeyCode(struct xkb_desc * xkb, - KeyCode key, - unsigned int mods, - unsigned int * mods_rtrn, - uint32_t * keysym_rtrn, - int * group_rtrn, - int * level_rtrn) -{ - struct xkb_key_type *type; - int col,nKeyGroups; - unsigned preserve,effectiveGroup; - uint32_t *syms; - - if (mods_rtrn!=NULL) - *mods_rtrn = 0; - - nKeyGroups= XkbKeyNumGroups(xkb,key); - if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) { - if (keysym_rtrn!=NULL) - *keysym_rtrn = 0; - return 0; - } - - syms = XkbKeySymsPtr(xkb,key); - - /* find the offset of the effective group */ - col = 0; - effectiveGroup= XkbGroupForCoreState(mods); - if ( effectiveGroup>=nKeyGroups ) { - unsigned groupInfo= XkbKeyGroupInfo(xkb,key); - switch (XkbOutOfRangeGroupAction(groupInfo)) { - default: - effectiveGroup %= nKeyGroups; - break; - case XkbClampIntoRange: - effectiveGroup = nKeyGroups-1; - break; - case XkbRedirectIntoRange: - effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo); - if (effectiveGroup>=nKeyGroups) - effectiveGroup= 0; - break; - } - } - col= effectiveGroup*XkbKeyGroupsWidth(xkb,key); - type = XkbKeyKeyType(xkb,key,effectiveGroup); - - preserve= 0; - if (type->map) { /* find the column (shift level) within the group */ - register int i; - struct xkb_kt_map_entry *entry; - /* ---- Begin section modified for GDK ---- */ - int found = 0; - - for (i=0,entry=type->map;imap_count;i++,entry++) { - if (mods_rtrn) { - int bits = 0; - unsigned long tmp = entry->mods.mask; - while (tmp) { - if ((tmp & 1) == 1) - bits++; - tmp >>= 1; - } - /* We always add one-modifiers levels to mods_rtrn since - * they can't wipe out bits in the state unless the - * level would be triggered. But return other modifiers - * - */ - if (bits == 1 || (mods&type->mods.mask)==entry->mods.mask) - *mods_rtrn |= entry->mods.mask; - } - - if (!found&&entry->active&&((mods&type->mods.mask)==entry->mods.mask)) { - col+= entry->level; - if (type->preserve) - preserve= type->preserve[i].mask; - - if (level_rtrn) - *level_rtrn = entry->level; - - found = 1; - } - } - /* ---- End section modified for GDK ---- */ - } - - if (keysym_rtrn!=NULL) - *keysym_rtrn= syms[col]; - if (mods_rtrn) { - /* ---- Begin section modified for GDK ---- */ - *mods_rtrn &= ~preserve; - /* ---- End section modified for GDK ---- */ - - /* ---- Begin stuff GDK comments out of the original Xlib version ---- */ - /* This is commented out because xkb_info is a private struct */ - -#if 0 - /* The Motif VTS doesn't get the help callback called if help - * is bound to Shift+, and it appears as though it - * is XkbTranslateKeyCode that is causing the problem. The - * core X version of XTranslateKey always OR's in ShiftMask - * and LockMask for mods_rtrn, so this "fix" keeps this behavior - * and solves the VTS problem. - */ - if ((xkb->dpy)&&(xkb->dpy->xkb_info)&& - (xkb->dpy->xkb_info->xlib_ctrls&XkbLC_AlwaysConsumeShiftAndLock)) { *mods_rtrn|= (ShiftMask|LockMask); - } -#endif - - /* ---- End stuff GDK comments out of the original Xlib version ---- */ - } - - /* ---- Begin stuff GDK adds to the original Xlib version ---- */ - - if (group_rtrn) - *group_rtrn = effectiveGroup; - - /* ---- End stuff GDK adds to the original Xlib version ---- */ - - return (syms[col] != 0); -} -#endif - static gboolean gdk_wayland_keymap_translate_keyboard_state (GdkKeymap *keymap, guint hardware_keycode, @@ -423,20 +151,11 @@ gdk_wayland_keymap_translate_keyboard_state (GdkKeymap *keymap, gint *level, GdkModifierType *consumed_modifiers) { -#if 0 - GdkWaylandKeymap *wayland_keymap; - uint32_t tmp_keyval = 0; - guint tmp_modifiers; - struct xkb_desc *xkb; - g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE); g_return_val_if_fail (group < 4, FALSE); - wayland_keymap = GDK_WAYLAND_KEYMAP (keymap); - xkb = wayland_keymap->xkb; - if (keyval) - *keyval = 0; + *keyval = hardware_keycode; if (effective_group) *effective_group = 0; if (level) @@ -444,138 +163,21 @@ gdk_wayland_keymap_translate_keyboard_state (GdkKeymap *keymap, if (consumed_modifiers) *consumed_modifiers = 0; - if (hardware_keycode < xkb->min_key_code || - hardware_keycode > xkb->max_key_code) - return FALSE; - - - /* replace bits 13 and 14 with the provided group */ - state &= ~(1 << 13 | 1 << 14); - state |= group << 13; - - MyEnhancedXkbTranslateKeyCode (xkb, - hardware_keycode, - state, - &tmp_modifiers, - &tmp_keyval, - effective_group, - level); - - if (state & ~tmp_modifiers & XKB_COMMON_LOCK_MASK) - tmp_keyval = gdk_keyval_to_upper (tmp_keyval); - - /* We need to augment the consumed modifiers with LockMask, since - * we handle that ourselves, and also with the group bits - */ - tmp_modifiers |= XKB_COMMON_LOCK_MASK | 1 << 13 | 1 << 14; - - - if (consumed_modifiers) - *consumed_modifiers = tmp_modifiers; - - if (keyval) - *keyval = tmp_keyval; - - return tmp_keyval != 0; -#endif - return FALSE; + return TRUE; } -#if 0 -static void -update_modmap (GdkWaylandKeymap *wayland_keymap) -{ - static struct { - const gchar *name; - uint32_t atom; - GdkModifierType mask; - } vmods[] = { - { "Meta", 0, GDK_META_MASK }, - { "Super", 0, GDK_SUPER_MASK }, - { "Hyper", 0, GDK_HYPER_MASK }, - { NULL, 0, 0 } - }; - - gint i, j, k; - - if (!vmods[0].atom) - for (i = 0; vmods[i].name; i++) - vmods[i].atom = xkb_atom(vmods[i].name); - - for (i = 0; i < 8; i++) - wayland_keymap->modmap[i] = 1 << i; - - for (i = 0; i < XkbNumVirtualMods; i++) - { - for (j = 0; vmods[j].atom; j++) - { - if (wayland_keymap->xkb->names->vmods[i] == vmods[j].atom) - { - for (k = 0; k < 8; k++) - { - if (wayland_keymap->xkb->server->vmods[i] & (1 << k)) - wayland_keymap->modmap[k] |= vmods[j].mask; - } - } - } - } -} -#endif - static void gdk_wayland_keymap_add_virtual_modifiers (GdkKeymap *keymap, GdkModifierType *state) { - GdkWaylandKeymap *wayland_keymap; - int i; - - wayland_keymap = GDK_WAYLAND_KEYMAP (keymap); - - for (i = 4; i < 8; i++) - { - if ((1 << i) & *state) - { - if (wayland_keymap->modmap[i] & GDK_SUPER_MASK) - *state |= GDK_SUPER_MASK; - if (wayland_keymap->modmap[i] & GDK_HYPER_MASK) - *state |= GDK_HYPER_MASK; - if (wayland_keymap->modmap[i] & GDK_META_MASK) - *state |= GDK_META_MASK; - } - } + return; } static gboolean gdk_wayland_keymap_map_virtual_modifiers (GdkKeymap *keymap, GdkModifierType *state) { - const guint vmods[] = { - GDK_SUPER_MASK, GDK_HYPER_MASK, GDK_META_MASK - }; - int i, j; - GdkWaylandKeymap *wayland_keymap; - gboolean retval = TRUE; - - wayland_keymap = GDK_WAYLAND_KEYMAP (keymap); - - for (j = 0; j < 3; j++) - { - if (*state & vmods[j]) - { - for (i = 4; i < 8; i++) - { - if (wayland_keymap->modmap[i] & vmods[j]) - { - if (*state & (1 << i)) - retval = FALSE; - else - *state |= 1 << i; - } - } - } - } - - return retval; + return TRUE; } static void @@ -603,45 +205,6 @@ _gdk_wayland_keymap_init (GdkWaylandKeymap *keymap) { } -#if 0 -static void -update_keymaps (GdkWaylandKeymap *keymap) -{ - struct xkb_desc *xkb = keymap->xkb; - gint keycode, total_syms, i, modifier; - uint32_t *entry; - guint mask; - - for (keycode = xkb->min_key_code; keycode <= xkb->max_key_code; keycode++) - { - total_syms = XkbKeyNumSyms (xkb, keycode); - - entry = XkbKeySymsPtr (xkb, keycode); - mask = 0; - for (i = 0; i < total_syms; i++) - { - switch (entry[i]) { - case GDK_KEY_Meta_L: - case GDK_KEY_Meta_R: - mask |= GDK_META_MASK; - break; - case GDK_KEY_Hyper_L: - case GDK_KEY_Hyper_R: - mask |= GDK_HYPER_MASK; - break; - case GDK_KEY_Super_L: - case GDK_KEY_Super_R: - mask |= GDK_SUPER_MASK; - break; - } - } - - modifier = g_bit_nth_lsf(xkb->map->modmap[keycode], -1); - keymap->modmap[modifier] |= mask; - } -} -#endif - GdkKeymap * _gdk_wayland_keymap_new () {