static gboolean window_key_press_event (GtkWidget *win, GdkEventKey *event, GsShell *shell) { GsShellPrivate *priv = gs_shell_get_instance_private (shell); GdkKeymap *keymap; GdkModifierType state; gboolean is_rtl; GtkWidget *button; button = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_back")); if (!gtk_widget_is_visible (button) || !gtk_widget_is_sensitive (button)) return GDK_EVENT_PROPAGATE; state = event->state; keymap = gdk_keymap_get_default (); gdk_keymap_add_virtual_modifiers (keymap, &state); state = state & gtk_accelerator_get_default_mod_mask (); is_rtl = gtk_widget_get_direction (button) == GTK_TEXT_DIR_RTL; if ((!is_rtl && state == GDK_MOD1_MASK && event->keyval == GDK_KEY_Left) || (is_rtl && state == GDK_MOD1_MASK && event->keyval == GDK_KEY_Right) || event->keyval == GDK_KEY_Back) { gtk_widget_activate (button); return GDK_EVENT_STOP; } return GDK_EVENT_PROPAGATE; }
static gboolean window_key_press_event (GtkWidget *win, GdkEventKey *event, GnomeControlCenter *self) { GdkKeymap *keymap; gboolean retval; GdkModifierType state; if (event->state == 0) return FALSE; retval = FALSE; state = event->state; keymap = gdk_keymap_get_default (); gdk_keymap_add_virtual_modifiers (keymap, &state); state = state & gtk_accelerator_get_default_mod_mask (); if (state == GDK_CONTROL_MASK) { switch (event->keyval) { case GDK_KEY_s: case GDK_KEY_S: case GDK_KEY_f: case GDK_KEY_F: if (gtk_widget_get_visible (self->priv->search_entry)) { gtk_widget_grab_focus (self->priv->search_entry); retval = TRUE; } break; case GDK_KEY_Q: case GDK_KEY_q: g_object_unref (self); retval = TRUE; break; case GDK_KEY_W: case GDK_KEY_w: if (notebook_get_selected_page (self->priv->notebook) != self->priv->scrolled_window) shell_show_overview_page (self); retval = TRUE; break; } } return retval; }
static NimfEvent * translate_xkey_event (XEvent *xevent) { g_debug (G_STRLOC ": %s", G_STRFUNC); GdkKeymap *keymap = gdk_keymap_get_default (); GdkModifierType consumed, state; NimfEvent *nimf_event = nimf_event_new (NIMF_EVENT_NOTHING); if (xevent->type == KeyPress) nimf_event->key.type = NIMF_EVENT_KEY_PRESS; else nimf_event->key.type = NIMF_EVENT_KEY_RELEASE; nimf_event->key.state = (NimfModifierType) xevent->xkey.state; #if GTK_CHECK_VERSION (3, 6, 0) gint group = gdk_x11_keymap_get_group_for_state (keymap, xevent->xkey.state); #else gint group = XkbGroupForCoreState (xevent->xkey.state); #endif nimf_event->key.hardware_keycode = xevent->xkey.keycode; nimf_event->key.keyval = NIMF_KEY_VoidSymbol; gdk_keymap_translate_keyboard_state (keymap, nimf_event->key.hardware_keycode, nimf_event->key.state, group, &nimf_event->key.keyval, NULL, NULL, &consumed); state = nimf_event->key.state & ~consumed; gdk_keymap_add_virtual_modifiers (keymap, &state); nimf_event->key.state |= (NimfModifierType) state; return nimf_event; }
/** * _gtk_key_hash_lookup: * @key_hash: a #GtkKeyHash * @hardware_keycode: hardware keycode field from a #GdkEventKey * @state: state field from a #GdkEventKey * @mask: mask of modifiers to consider when matching against the * modifiers in entries. * @group: group field from a #GdkEventKey * * Looks up the best matching entry or entries in the hash table for * a given event. The results are sorted so that entries with less * modifiers come before entries with more modifiers. * * The matches returned by this function can be exact (i.e. keycode, level * and group all match) or fuzzy (i.e. keycode and level match, but group * does not). As long there are any exact matches, only exact matches * are returned. If there are no exact matches, fuzzy matches will be * returned, as long as they are not shadowing a possible exact match. * This means that fuzzy matches won’t be considered if their keyval is * present in the current group. * * Return value: A newly-allocated #GSList of matching entries. * Free with g_slist_free() when no longer needed. */ GSList * _gtk_key_hash_lookup (GtkKeyHash *key_hash, guint16 hardware_keycode, GdkModifierType state, GdkModifierType mask, gint group) { GHashTable *keycode_hash = key_hash_get_keycode_hash (key_hash); GSList *keys = g_hash_table_lookup (keycode_hash, GUINT_TO_POINTER ((guint)hardware_keycode)); GSList *results = NULL; GSList *l; gboolean have_exact = FALSE; guint keyval; gint effective_group; gint level; GdkModifierType modifiers; GdkModifierType consumed_modifiers; GdkModifierType shift_group_mask; gboolean group_mod_is_accel_mod = FALSE; const GdkModifierType xmods = GDK_MOD2_MASK|GDK_MOD3_MASK|GDK_MOD4_MASK|GDK_MOD5_MASK; const GdkModifierType vmods = GDK_SUPER_MASK|GDK_HYPER_MASK|GDK_META_MASK; /* We don't want Caps_Lock to affect keybinding lookups. */ state &= ~GDK_LOCK_MASK; _gtk_translate_keyboard_accel_state (key_hash->keymap, hardware_keycode, state, mask, group, &keyval, &effective_group, &level, &consumed_modifiers); /* if the group-toggling modifier is part of the default accel mod * mask, and it is active, disable it for matching */ shift_group_mask = gdk_keymap_get_modifier_mask (key_hash->keymap, GDK_MODIFIER_INTENT_SHIFT_GROUP); if (mask & shift_group_mask) group_mod_is_accel_mod = TRUE; gdk_keymap_map_virtual_modifiers (key_hash->keymap, &mask); gdk_keymap_add_virtual_modifiers (key_hash->keymap, &state); GTK_NOTE (KEYBINDINGS, g_message ("Looking up keycode = %u, modifiers = 0x%04x,\n" " keyval = %u, group = %d, level = %d, consumed_modifiers = 0x%04x", hardware_keycode, state, keyval, effective_group, level, consumed_modifiers)); if (keys) { GSList *tmp_list = keys; while (tmp_list) { GtkKeyHashEntry *entry = tmp_list->data; /* If the virtual Super, Hyper or Meta modifiers are present, * they will also be mapped to some of the Mod2 - Mod5 modifiers, * so we compare them twice, ignoring either set. * We accept combinations involving virtual modifiers only if they * are mapped to separate modifiers; i.e. if Super and Hyper are * both mapped to Mod4, then pressing a key that is mapped to Mod4 * will not match a Super+Hyper entry. */ modifiers = entry->modifiers; if (gdk_keymap_map_virtual_modifiers (key_hash->keymap, &modifiers) && ((modifiers & ~consumed_modifiers & mask & ~vmods) == (state & ~consumed_modifiers & mask & ~vmods) || (modifiers & ~consumed_modifiers & mask & ~xmods) == (state & ~consumed_modifiers & mask & ~xmods))) { gint i; if (keyval == entry->keyval && /* Exact match */ /* but also match for group if it is an accel mod, because * otherwise we can get multiple exact matches, some being * bogus */ (!group_mod_is_accel_mod || (state & shift_group_mask) == (entry->modifiers & shift_group_mask))) { GTK_NOTE (KEYBINDINGS, g_message (" found exact match, keyval = %u, modifiers = 0x%04x", entry->keyval, entry->modifiers)); if (!have_exact) { g_slist_free (results); results = NULL; } have_exact = TRUE; results = g_slist_prepend (results, entry); } if (!have_exact) { for (i = 0; i < entry->n_keys; i++) { if (entry->keys[i].keycode == hardware_keycode && entry->keys[i].level == level && /* Only match for group if it's an accel mod */ (!group_mod_is_accel_mod || entry->keys[i].group == effective_group)) { GTK_NOTE (KEYBINDINGS, g_message (" found group = %d, level = %d", entry->keys[i].group, entry->keys[i].level)); results = g_slist_prepend (results, entry); break; } } } } tmp_list = tmp_list->next; } } if (!have_exact && results) { /* If there are fuzzy matches, check that the current group doesn't also * define these keyvals; if yes, discard results because a widget up in * the stack may have an exact match and we don't want to 'steal' it. */ guint oldkeyval = 0; GtkKeyHashEntry *keyhashentry; results = sort_lookup_results_by_keyval (results); for (l = results; l; l = l->next) { keyhashentry = l->data; if (l == results || oldkeyval != keyhashentry->keyval) { oldkeyval = keyhashentry->keyval; if (keyval_in_group (key_hash->keymap, oldkeyval, group)) { g_slist_free (results); return NULL; } } } } results = sort_lookup_results (results); for (l = results; l; l = l->next) l->data = ((GtkKeyHashEntry *)l->data)->value; return results; }
static GdkFilterReturn filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) { XEvent *xevent = (XEvent *) gdk_xevent; GdkKeymap *keymap = gdk_keymap_get_default(); guint keyval; GdkModifierType consumed, modifiers; guint mod_mask = gtk_accelerator_get_default_mod_mask(); GSList *iter; (void) event; (void) data; switch (xevent->type) { case KeyPress: modifiers = xevent->xkey.state; TRACE (g_print ("Got KeyPress keycode: %d, modifiers: 0x%x\n", xevent->xkey.keycode, xevent->xkey.state)); gdk_keymap_translate_keyboard_state( keymap, xevent->xkey.keycode, modifiers, /* See top comment why we don't use this here: XkbGroupForCoreState (xevent->xkey.state) */ WE_ONLY_USE_ONE_GROUP, &keyval, NULL, NULL, &consumed); /* Map non-virtual to virtual modifiers */ modifiers &= ~consumed; gdk_keymap_add_virtual_modifiers(keymap, &modifiers); modifiers &= mod_mask; TRACE (g_print ("Translated keyval: %d, vmodifiers: 0x%x, name: %s\n", keyval, modifiers, gtk_accelerator_name(keyval, modifiers))); /* * Set the last event time for use when showing * windows to avoid anti-focus-stealing code. */ processing_event = TRUE; last_event_time = xevent->xkey.time; iter = bindings; while (iter != NULL) { /* NOTE: ``iter`` might be removed from the list * in the callback. */ struct Binding *binding = iter->data; iter = iter->next; if (keyvalues_equal(binding->keyval, keyval) && modifiers_equal(binding->modifiers, modifiers)) { TRACE (g_print ("Calling handler for '%s'...\n", binding->keystring)); (binding->handler) (binding->keystring, binding->user_data); } } processing_event = FALSE; break; case KeyRelease: TRACE (g_print ("Got KeyRelease! \n")); break; } return GDK_FILTER_CONTINUE; }