/** * egg_accelerator_parse_virtual: * @accelerator: string representing an accelerator * @accelerator_key: return location for accelerator keyval * @accelerator_mods: return location for accelerator modifier mask * * Parses a string representing a virtual accelerator. The format * looks like "<Control>a" or "<Shift><Alt>F1" or * "<Release>z" (the last one is for key release). The parser * is fairly liberal and allows lower or upper case, and also * abbreviations such as "<Ctl>" and "<Ctrl>". * * If the parse fails, @accelerator_key and @accelerator_mods will * be set to 0 (zero) and %FALSE will be returned. If the string contains * only modifiers, @accelerator_key will be set to 0 but %TRUE will be * returned. * * The virtual vs. concrete accelerator distinction is a relic of * how the X Window System works; there are modifiers Mod2-Mod5 that * can represent various keyboard keys (numlock, meta, hyper, etc.), * the virtual modifier represents the keyboard key, the concrete * modifier the actual Mod2-Mod5 bits in the key press event. * * Returns: %TRUE on success. */ gboolean egg_accelerator_parse_virtual (const gchar *accelerator, guint *accelerator_key, EggVirtualModifierType *accelerator_mods) { guint keyval; unsigned mods; gint len; gboolean bad_keyval; if (accelerator_key) *accelerator_key = 0; if (accelerator_mods) *accelerator_mods = (EggVirtualModifierType)0; g_return_val_if_fail (accelerator != NULL, FALSE); bad_keyval = FALSE; keyval = 0; mods = 0; len = strlen (accelerator); while (len) { if (*accelerator == '<') { if (len >= 9 && is_release (accelerator)) { accelerator += 9; len -= 9; mods |= EGG_VIRTUAL_RELEASE_MASK; } else if (len >= 9 && is_control (accelerator)) { accelerator += 9; len -= 9; mods |= EGG_VIRTUAL_CONTROL_MASK; } else if (len >= 7 && is_shift (accelerator)) { accelerator += 7; len -= 7; mods |= EGG_VIRTUAL_SHIFT_MASK; } else if (len >= 6 && is_shft (accelerator)) { accelerator += 6; len -= 6; mods |= EGG_VIRTUAL_SHIFT_MASK; } else if (len >= 6 && is_ctrl (accelerator)) { accelerator += 6; len -= 6; mods |= EGG_VIRTUAL_CONTROL_MASK; } else if (len >= 6 && is_modx (accelerator)) { static const guint mod_vals[] = { EGG_VIRTUAL_ALT_MASK, EGG_VIRTUAL_MOD2_MASK, EGG_VIRTUAL_MOD3_MASK, EGG_VIRTUAL_MOD4_MASK, EGG_VIRTUAL_MOD5_MASK }; len -= 6; accelerator += 4; mods |= mod_vals[*accelerator - '1']; accelerator += 2; } else if (len >= 5 && is_ctl (accelerator)) { accelerator += 5; len -= 5; mods |= EGG_VIRTUAL_CONTROL_MASK; } else if (len >= 5 && is_alt (accelerator)) { accelerator += 5; len -= 5; mods |= EGG_VIRTUAL_ALT_MASK; } else if (len >= 6 && is_meta (accelerator)) { accelerator += 6; len -= 6; mods |= EGG_VIRTUAL_META_MASK; } else if (len >= 7 && is_hyper (accelerator)) { accelerator += 7; len -= 7; mods |= EGG_VIRTUAL_HYPER_MASK; } else if (len >= 7 && is_super (accelerator)) { accelerator += 7; len -= 7; mods |= EGG_VIRTUAL_SUPER_MASK; } else { gchar last_ch; last_ch = *accelerator; while (last_ch && last_ch != '>') { last_ch = *accelerator; accelerator += 1; len -= 1; } } } else { keyval = gdk_keyval_from_name (accelerator); if (keyval == 0) bad_keyval = TRUE; accelerator += len; len -= len; } } if (accelerator_key) *accelerator_key = gdk_keyval_to_lower (keyval); if (accelerator_mods) *accelerator_mods = (EggVirtualModifierType)mods; return !bad_keyval; }
static gboolean grab_key_callback(GtkWidget* widget, GdkEventKey* event, void* data) { GdkModifierType accel_mods = 0; guint accel_keyval; EggCellRendererKeys *keys; char *path; gboolean edited; gboolean cleared; GdkModifierType consumed_modifiers; guint upper; GdkModifierType ignored_modifiers; keys = EGG_CELL_RENDERER_KEYS(data); if (is_modifier(event->hardware_keycode)) { return TRUE; } edited = FALSE; cleared = FALSE; consumed_modifiers = 0; gdk_keymap_translate_keyboard_state(gdk_keymap_get_default(), event->hardware_keycode, event->state, event->group, NULL, NULL, NULL, &consumed_modifiers); upper = event->keyval; accel_keyval = gdk_keyval_to_lower(upper); if (accel_keyval == GDK_ISO_Left_Tab) { accel_keyval = GDK_Tab; } /* Put shift back if it changed the case of the key, not otherwise. */ if (upper != accel_keyval && (consumed_modifiers & GDK_SHIFT_MASK)) { consumed_modifiers &= ~(GDK_SHIFT_MASK); } egg_keymap_resolve_virtual_modifiers(gdk_keymap_get_default(), EGG_VIRTUAL_NUM_LOCK_MASK | EGG_VIRTUAL_SCROLL_LOCK_MASK | EGG_VIRTUAL_LOCK_MASK, &ignored_modifiers); /* http://bugzilla.gnome.org/show_bug.cgi?id=139605 * mouse keys should effect keybindings */ ignored_modifiers |= GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | GDK_BUTTON5_MASK; /* filter consumed/ignored modifiers */ if (keys->accel_mode == EGG_CELL_RENDERER_KEYS_MODE_GTK) { accel_mods = event->state & GDK_MODIFIER_MASK & ~(consumed_modifiers | ignored_modifiers); } else if (keys->accel_mode == EGG_CELL_RENDERER_KEYS_MODE_X) { accel_mods = event->state & GDK_MODIFIER_MASK & ~(ignored_modifiers); } else { g_assert_not_reached(); } if (accel_mods == 0 && accel_keyval == GDK_Escape) { goto out; /* cancel */ } /* clear the accelerator on Backspace */ if (accel_mods == 0 && accel_keyval == GDK_BackSpace) { cleared = TRUE; goto out; } if (keys->accel_mode == EGG_CELL_RENDERER_KEYS_MODE_GTK) { if (!gtk_accelerator_valid (accel_keyval, accel_mods)) { accel_keyval = 0; accel_mods = 0; } } edited = TRUE; out: gdk_keyboard_ungrab(event->time); gdk_pointer_ungrab(event->time); path = g_strdup(g_object_get_data(G_OBJECT(keys->edit_widget), EGG_CELL_RENDERER_TEXT_PATH)); gtk_cell_editable_editing_done(GTK_CELL_EDITABLE(keys->edit_widget)); gtk_cell_editable_remove_widget(GTK_CELL_EDITABLE(keys->edit_widget)); keys->edit_widget = NULL; keys->grab_widget = NULL; if (edited) { g_signal_emit_by_name(G_OBJECT(keys), "accel_edited", path, accel_keyval, accel_mods, event->hardware_keycode); } else if (cleared) { g_signal_emit_by_name(G_OBJECT(keys), "accel_cleared", path); } g_free (path); return TRUE; }
/** * egg_virtual_accelerator_name: * @accelerator_key: accelerator keyval * @accelerator_mods: accelerator modifier mask * @returns: a newly-allocated accelerator name * * Converts an accelerator keyval and modifier mask * into a string parseable by egg_accelerator_parse_virtual(). * For example, if you pass in #GDK_q and #EGG_VIRTUAL_CONTROL_MASK, * this function returns "<Control>q". * * The caller of this function must free the returned string. */ gchar* egg_virtual_accelerator_name (guint accelerator_key, guint keycode, EggVirtualModifierType accelerator_mods) { static const gchar text_release[] = "<Release>"; static const gchar text_shift[] = "<Shift>"; static const gchar text_control[] = "<Control>"; static const gchar text_mod1[] = "<Alt>"; static const gchar text_mod2[] = "<Mod2>"; static const gchar text_mod3[] = "<Mod3>"; static const gchar text_mod4[] = "<Mod4>"; static const gchar text_mod5[] = "<Mod5>"; static const gchar text_meta[] = "<Meta>"; static const gchar text_super[] = "<Super>"; static const gchar text_hyper[] = "<Hyper>"; guint l; gchar *keyval_name; gchar *accelerator; accelerator_mods &= EGG_VIRTUAL_MODIFIER_MASK; if (!accelerator_key) { keyval_name = g_strdup_printf ("0x%02x", keycode); } else { keyval_name = gdk_keyval_name (gdk_keyval_to_lower (accelerator_key)); if (!keyval_name) keyval_name = ""; } l = 0; if (accelerator_mods & EGG_VIRTUAL_RELEASE_MASK) l += sizeof (text_release) - 1; if (accelerator_mods & EGG_VIRTUAL_SHIFT_MASK) l += sizeof (text_shift) - 1; if (accelerator_mods & EGG_VIRTUAL_CONTROL_MASK) l += sizeof (text_control) - 1; if (accelerator_mods & EGG_VIRTUAL_ALT_MASK) l += sizeof (text_mod1) - 1; if (accelerator_mods & EGG_VIRTUAL_MOD2_MASK) l += sizeof (text_mod2) - 1; if (accelerator_mods & EGG_VIRTUAL_MOD3_MASK) l += sizeof (text_mod3) - 1; if (accelerator_mods & EGG_VIRTUAL_MOD4_MASK) l += sizeof (text_mod4) - 1; if (accelerator_mods & EGG_VIRTUAL_MOD5_MASK) l += sizeof (text_mod5) - 1; if (accelerator_mods & EGG_VIRTUAL_META_MASK) l += sizeof (text_meta) - 1; if (accelerator_mods & EGG_VIRTUAL_HYPER_MASK) l += sizeof (text_hyper) - 1; if (accelerator_mods & EGG_VIRTUAL_SUPER_MASK) l += sizeof (text_super) - 1; l += strlen (keyval_name); accelerator = g_new (gchar, l + 1); l = 0; accelerator[l] = 0; if (accelerator_mods & EGG_VIRTUAL_RELEASE_MASK) { strcpy (accelerator + l, text_release); l += sizeof (text_release) - 1; } if (accelerator_mods & EGG_VIRTUAL_SHIFT_MASK) { strcpy (accelerator + l, text_shift); l += sizeof (text_shift) - 1; } if (accelerator_mods & EGG_VIRTUAL_CONTROL_MASK) { strcpy (accelerator + l, text_control); l += sizeof (text_control) - 1; } if (accelerator_mods & EGG_VIRTUAL_ALT_MASK) { strcpy (accelerator + l, text_mod1); l += sizeof (text_mod1) - 1; } if (accelerator_mods & EGG_VIRTUAL_MOD2_MASK) { strcpy (accelerator + l, text_mod2); l += sizeof (text_mod2) - 1; } if (accelerator_mods & EGG_VIRTUAL_MOD3_MASK) { strcpy (accelerator + l, text_mod3); l += sizeof (text_mod3) - 1; } if (accelerator_mods & EGG_VIRTUAL_MOD4_MASK) { strcpy (accelerator + l, text_mod4); l += sizeof (text_mod4) - 1; } if (accelerator_mods & EGG_VIRTUAL_MOD5_MASK) { strcpy (accelerator + l, text_mod5); l += sizeof (text_mod5) - 1; } if (accelerator_mods & EGG_VIRTUAL_META_MASK) { strcpy (accelerator + l, text_meta); l += sizeof (text_meta) - 1; } if (accelerator_mods & EGG_VIRTUAL_HYPER_MASK) { strcpy (accelerator + l, text_hyper); l += sizeof (text_hyper) - 1; } if (accelerator_mods & EGG_VIRTUAL_SUPER_MASK) { strcpy (accelerator + l, text_super); l += sizeof (text_super) - 1; } strcpy (accelerator + l, keyval_name); return accelerator; }
/** * egg_accelerator_parse_virtual: * @accelerator: string representing an accelerator * @accelerator_key: return location for accelerator keyval * @accelerator_mods: return location for accelerator modifier mask * * Parses a string representing a virtual accelerator. The format * looks like "<Control>a" or "<Shift><Alt>F1" or * "<Release>z" (the last one is for key release). The parser * is fairly liberal and allows lower or upper case, and also * abbreviations such as "<Ctl>" and "<Ctrl>". * * If the parse fails, @accelerator_key and @accelerator_mods will * be set to 0 (zero) and %FALSE will be returned. If the string contains * only modifiers, @accelerator_key will be set to 0 but %TRUE will be * returned. * * The virtual vs. concrete accelerator distinction is a relic of * how the X Window System works; there are modifiers Mod2-Mod5 that * can represent various keyboard keys (numlock, meta, hyper, etc.), * the virtual modifier represents the keyboard key, the concrete * modifier the actual Mod2-Mod5 bits in the key press event. * * Returns: %TRUE on success. */ gboolean egg_accelerator_parse_virtual (const gchar *accelerator, guint *accelerator_key, guint *keycode, EggVirtualModifierType *accelerator_mods) { guint keyval; GdkModifierType mods; gint len; gboolean bad_keyval; if (accelerator_key) *accelerator_key = 0; if (accelerator_mods) *accelerator_mods = 0; if (keycode) *keycode = 0; g_return_val_if_fail (accelerator != NULL, FALSE); bad_keyval = FALSE; keyval = 0; mods = 0; len = strlen (accelerator); while (len) { if (*accelerator == '<') { if (len >= 9 && is_release (accelerator)) { accelerator += 9; len -= 9; mods |= EGG_VIRTUAL_RELEASE_MASK; } else if (len >= 9 && is_control (accelerator)) { accelerator += 9; len -= 9; mods |= EGG_VIRTUAL_CONTROL_MASK; } else if (len >= 7 && is_shift (accelerator)) { accelerator += 7; len -= 7; mods |= EGG_VIRTUAL_SHIFT_MASK; } else if (len >= 6 && is_shft (accelerator)) { accelerator += 6; len -= 6; mods |= EGG_VIRTUAL_SHIFT_MASK; } else if (len >= 6 && is_ctrl (accelerator)) { accelerator += 6; len -= 6; mods |= EGG_VIRTUAL_CONTROL_MASK; } else if (len >= 6 && is_modx (accelerator)) { static const guint mod_vals[] = { EGG_VIRTUAL_ALT_MASK, EGG_VIRTUAL_MOD2_MASK, EGG_VIRTUAL_MOD3_MASK, EGG_VIRTUAL_MOD4_MASK, EGG_VIRTUAL_MOD5_MASK }; len -= 6; accelerator += 4; mods |= mod_vals[*accelerator - '1']; accelerator += 2; } else if (len >= 5 && is_ctl (accelerator)) { accelerator += 5; len -= 5; mods |= EGG_VIRTUAL_CONTROL_MASK; } else if (len >= 5 && is_alt (accelerator)) { accelerator += 5; len -= 5; mods |= EGG_VIRTUAL_ALT_MASK; } else if (len >= 6 && is_meta (accelerator)) { accelerator += 6; len -= 6; mods |= EGG_VIRTUAL_META_MASK; } else if (len >= 7 && is_hyper (accelerator)) { accelerator += 7; len -= 7; mods |= EGG_VIRTUAL_HYPER_MASK; } else if (len >= 7 && is_super (accelerator)) { accelerator += 7; len -= 7; mods |= EGG_VIRTUAL_SUPER_MASK; } else { gchar last_ch; last_ch = *accelerator; while (last_ch && last_ch != '>') { last_ch = *accelerator; accelerator += 1; len -= 1; } } } else { keyval = gdk_keyval_from_name (accelerator); if (keyval == 0) { /* If keyval is 0, than maybe it's a keycode. Check for 0x## */ if (len >= 4 && is_keycode (accelerator)) { char keystring[5]; gchar *endptr; gint tmp_keycode; memcpy (keystring, accelerator, 4); keystring [4] = '\000'; tmp_keycode = strtol (keystring, &endptr, 16); if (endptr == NULL || *endptr != '\000') { bad_keyval = TRUE; } else if (keycode != NULL) { *keycode = tmp_keycode; /* 0x00 is an invalid keycode too. */ if (*keycode == 0) bad_keyval = TRUE; } } } else if (keycode != NULL) *keycode = XKeysymToKeycode (GDK_DISPLAY(), keyval); accelerator += len; len -= len; } } if (accelerator_key) *accelerator_key = gdk_keyval_to_lower (keyval); if (accelerator_mods) *accelerator_mods = mods; return !bad_keyval; }
static gboolean grab_key_callback (GtkWidget *widget, GdkEventKey *event, GtkCellRendererAccel *accel) { GdkModifierType accel_mods = 0; guint accel_key; gchar *path; gboolean edited; gboolean cleared; GdkModifierType consumed_modifiers; GdkDisplay *display; display = gtk_widget_get_display (widget); if (event->is_modifier) return TRUE; edited = FALSE; cleared = FALSE; gdk_keymap_translate_keyboard_state (gdk_keymap_get_for_display (display), event->hardware_keycode, event->state, event->group, NULL, NULL, NULL, &consumed_modifiers); accel_key = gdk_keyval_to_lower (event->keyval); if (accel_key == GDK_ISO_Left_Tab) accel_key = GDK_Tab; accel_mods = event->state & gtk_accelerator_get_default_mod_mask (); /* Filter consumed modifiers */ if (accel->accel_mode == GTK_CELL_RENDERER_ACCEL_MODE_GTK) accel_mods &= ~consumed_modifiers; /* Put shift back if it changed the case of the key, not otherwise. */ if (accel_key != event->keyval) accel_mods |= GDK_SHIFT_MASK; if (accel_mods == 0) { switch (event->keyval) { case GDK_Escape: goto out; /* cancel */ case GDK_BackSpace: /* clear the accelerator on Backspace */ cleared = TRUE; goto out; default: break; } } if (accel->accel_mode == GTK_CELL_RENDERER_ACCEL_MODE_GTK) { if (!gtk_accelerator_valid (accel_key, accel_mods)) { gtk_widget_error_bell (widget); return TRUE; } } edited = TRUE; out: gtk_grab_remove (accel->grab_widget); gdk_display_keyboard_ungrab (display, event->time); gdk_display_pointer_ungrab (display, event->time); path = g_strdup (g_object_get_data (G_OBJECT (accel->edit_widget), "gtk-cell-renderer-text")); gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (accel->edit_widget)); gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (accel->edit_widget)); accel->edit_widget = NULL; accel->grab_widget = NULL; if (edited) g_signal_emit (accel, signals[ACCEL_EDITED], 0, path, accel_key, accel_mods, event->hardware_keycode); else if (cleared) g_signal_emit (accel, signals[ACCEL_CLEARED], 0, path); g_free (path); return TRUE; }
static char * key_get_key_name (int keyval) { return gdk_keyval_name (gdk_keyval_to_lower (keyval)); }