From 5f2e3042d908d98fe3f35fb5ef1e519846bdbcb4 Mon Sep 17 00:00:00 2001 From: Jonathan Blandford Date: Tue, 18 Nov 2003 17:23:06 +0000 Subject: [PATCH] Patch from Bastien Nocera to to handle keycodes as well as keysyms. Tue Nov 18 12:23:26 2003 Jonathan Blandford * eggcellrendererkeys.[ch]: Patch from Bastien Nocera to to handle keycodes as well as keysyms. * eggaccelerators.[ch]: handle keycodes. * gnome-keybinding-properties.c: handle keycodes. --- capplets/keybindings/ChangeLog | 9 ++ capplets/keybindings/eggaccelerators.c | 58 +++++++++++-- capplets/keybindings/eggaccelerators.h | 2 + capplets/keybindings/eggcellrendererkeys.c | 75 ++++++++++++---- capplets/keybindings/eggcellrendererkeys.h | 15 ++-- .../keybindings/gnome-keybinding-properties.c | 86 ++++++++++++++++--- 6 files changed, 207 insertions(+), 38 deletions(-) diff --git a/capplets/keybindings/ChangeLog b/capplets/keybindings/ChangeLog index d98dd452c..2a61ab010 100644 --- a/capplets/keybindings/ChangeLog +++ b/capplets/keybindings/ChangeLog @@ -1,3 +1,12 @@ +Tue Nov 18 12:23:26 2003 Jonathan Blandford + + * eggcellrendererkeys.[ch]: Patch from Bastien Nocera to to handle + keycodes as well as keysyms. + + * eggaccelerators.[ch]: handle keycodes. + + * gnome-keybinding-properties.c: handle keycodes. + 2003-10-28 Jody Goldberg * Release 2.5.0 diff --git a/capplets/keybindings/eggaccelerators.c b/capplets/keybindings/eggaccelerators.c index ca63e7815..ad72a9d99 100644 --- a/capplets/keybindings/eggaccelerators.c +++ b/capplets/keybindings/eggaccelerators.c @@ -20,6 +20,7 @@ #include "eggaccelerators.h" +#include #include #include #include @@ -175,6 +176,13 @@ is_hyper (const gchar *string) (string[6] == '>')); } +static inline gboolean +is_keycode (const gchar *string) +{ + return ((string[0] == '0') && + (string[1] == 'x')); +} + /** * egg_accelerator_parse_virtual: * @accelerator: string representing an accelerator @@ -203,6 +211,7 @@ is_hyper (const gchar *string) gboolean egg_accelerator_parse_virtual (const gchar *accelerator, guint *accelerator_key, + guint *keycode, EggVirtualModifierType *accelerator_mods) { guint keyval; @@ -214,6 +223,8 @@ egg_accelerator_parse_virtual (const gchar *accelerator, *accelerator_key = 0; if (accelerator_mods) *accelerator_mods = 0; + if (keycode) + *keycode = 0; g_return_val_if_fail (accelerator != NULL, FALSE); @@ -314,12 +325,37 @@ egg_accelerator_parse_virtual (const gchar *accelerator, else { keyval = gdk_keyval_from_name (accelerator); - + if (keyval == 0) - bad_keyval = TRUE; - + { + /* 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 + { + *keycode = tmp_keycode; + /* 0x00 is an invalid keycode too. */ + if (*keycode == 0) + bad_keyval = TRUE; + } + } + } + accelerator += len; - len -= len; + len -= len; } } @@ -347,6 +383,7 @@ egg_accelerator_parse_virtual (const gchar *accelerator, */ gchar* egg_virtual_accelerator_name (guint accelerator_key, + guint keycode, EggVirtualModifierType accelerator_mods) { static const gchar text_release[] = ""; @@ -366,9 +403,16 @@ egg_virtual_accelerator_name (guint accelerator_key, accelerator_mods &= EGG_VIRTUAL_MODIFIER_MASK; - keyval_name = gdk_keyval_name (gdk_keyval_to_lower (accelerator_key)); - if (!keyval_name) - keyval_name = ""; + 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) diff --git a/capplets/keybindings/eggaccelerators.h b/capplets/keybindings/eggaccelerators.h index e4df31785..d2276d2b2 100644 --- a/capplets/keybindings/eggaccelerators.h +++ b/capplets/keybindings/eggaccelerators.h @@ -70,6 +70,7 @@ typedef enum gboolean egg_accelerator_parse_virtual (const gchar *accelerator, guint *accelerator_key, + guint *keycode, EggVirtualModifierType *accelerator_mods); void egg_keymap_resolve_virtual_modifiers (GdkKeymap *keymap, EggVirtualModifierType virtual_mods, @@ -79,6 +80,7 @@ void egg_keymap_virtualize_modifiers (GdkKeymap *keymap, EggVirtualModifierType *virtual_mods); gchar* egg_virtual_accelerator_name (guint accelerator_key, + guint keycode, EggVirtualModifierType accelerator_mods); G_END_DECLS diff --git a/capplets/keybindings/eggcellrendererkeys.c b/capplets/keybindings/eggcellrendererkeys.c index b53e3617a..6e7d9d435 100644 --- a/capplets/keybindings/eggcellrendererkeys.c +++ b/capplets/keybindings/eggcellrendererkeys.c @@ -52,6 +52,7 @@ enum { PROP_ACCEL_KEY, PROP_ACCEL_MASK, + PROP_KEYCODE, PROP_ACCEL_MODE }; @@ -172,6 +173,16 @@ egg_cell_renderer_keys_class_init (EggCellRendererKeysClass *cell_keys_class) GDK_TYPE_MODIFIER_TYPE, 0, G_PARAM_READABLE | G_PARAM_WRITABLE)); + + g_object_class_install_property (object_class, + PROP_KEYCODE, + g_param_spec_uint ("keycode", + _("Accelerator keycode"), + _("Accelerator keycode"), + 0, + G_MAXINT, + 0, + G_PARAM_READABLE | G_PARAM_WRITABLE)); /* FIXME: Register the enum when moving to GTK+ */ g_object_class_install_property (object_class, @@ -184,10 +195,10 @@ egg_cell_renderer_keys_class_init (EggCellRendererKeysClass *cell_keys_class) 0, G_PARAM_READABLE | G_PARAM_WRITABLE)); - g_signal_new ("keys_edited", + g_signal_new ("accel_edited", EGG_TYPE_CELL_RENDERER_KEYS, G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EggCellRendererKeysClass, keys_edited), + G_STRUCT_OFFSET (EggCellRendererKeysClass, accel_edited), NULL, NULL, marshal_VOID__STRING_UINT_FLAGS_UINT, G_TYPE_NONE, 4, @@ -195,6 +206,15 @@ egg_cell_renderer_keys_class_init (EggCellRendererKeysClass *cell_keys_class) G_TYPE_UINT, GDK_TYPE_MODIFIER_TYPE, G_TYPE_UINT); + + g_signal_new ("accel_cleared", + EGG_TYPE_CELL_RENDERER_KEYS, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EggCellRendererKeysClass, accel_cleared), + NULL, NULL, + gtk_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); } @@ -213,12 +233,13 @@ egg_cell_renderer_keys_finalize (GObject *object) static gchar * convert_keysym_state_to_string (guint keysym, + guint keycode, EggVirtualModifierType mask) { - if (keysym == 0) + if (keysym == 0 && keycode == 0) return g_strdup (_("Disabled")); else - return egg_virtual_accelerator_name (keysym, mask); + return egg_virtual_accelerator_name (keysym, keycode, mask); } static void @@ -269,14 +290,22 @@ egg_cell_renderer_keys_set_property (GObject *object, case PROP_ACCEL_KEY: egg_cell_renderer_keys_set_accelerator (keys, g_value_get_uint (value), + keys->keycode, keys->accel_mask); break; case PROP_ACCEL_MASK: egg_cell_renderer_keys_set_accelerator (keys, keys->accel_key, + keys->keycode, g_value_get_flags (value)); break; + case PROP_KEYCODE: + egg_cell_renderer_keys_set_accelerator (keys, + keys->accel_key, + g_value_get_uint (value), + keys->accel_mask); + break; case PROP_ACCEL_MODE: egg_cell_renderer_keys_set_accel_mode (keys, g_value_get_int (value)); @@ -352,6 +381,7 @@ grab_key_callback (GtkWidget *widget, EggCellRendererKeys *keys; char *path; gboolean edited; + gboolean cleared; GdkModifierType consumed_modifiers; guint upper; GdkModifierType ignored_modifiers; @@ -362,6 +392,7 @@ grab_key_callback (GtkWidget *widget, return TRUE; edited = FALSE; + cleared = FALSE; consumed_modifiers = 0; gdk_keymap_translate_keyboard_state (gdk_keymap_get_default (), @@ -403,10 +434,11 @@ grab_key_callback (GtkWidget *widget, goto out; /* cancel */ /* clear the accelerator on Backspace */ - if (keys->edit_key != 0 && - accel_mods == 0 && - accel_keyval == GDK_BackSpace) - accel_keyval = 0; + if (accel_mods == 0 && accel_keyval == GDK_BackSpace) + { + cleared = TRUE; + goto out; + } if (keys->accel_mode == EGG_CELL_RENDERER_KEYS_MODE_GTK) { @@ -422,23 +454,27 @@ grab_key_callback (GtkWidget *widget, edited = TRUE; out: - path = g_strdup (g_object_get_data (G_OBJECT (keys->edit_widget), - EGG_CELL_RENDERER_TEXT_PATH)); - 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), "keys_edited", path, - accel_keyval, accel_mods, event->hardware_keycode); + { + 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; } @@ -583,6 +619,7 @@ egg_cell_renderer_keys_start_editing (GtkCellRenderer *cell, void egg_cell_renderer_keys_set_accelerator (EggCellRendererKeys *keys, guint keyval, + guint keycode, GdkModifierType mask) { char *text; @@ -609,13 +646,21 @@ egg_cell_renderer_keys_set_accelerator (EggCellRendererKeys *keys, g_object_notify (G_OBJECT (keys), "accel_mask"); changed = TRUE; } + + if (keycode != keys->keycode) + { + keys->keycode = keycode; + + g_object_notify (G_OBJECT (keys), "keycode"); + changed = TRUE; + } g_object_thaw_notify (G_OBJECT (keys)); if (changed) { /* sync string to the key values */ celltext = GTK_CELL_RENDERER_TEXT (keys); - text = convert_keysym_state_to_string (keys->accel_key, keys->accel_mask); + text = convert_keysym_state_to_string (keys->accel_key, keys->keycode, keys->accel_mask); g_object_set (keys, "text", text, NULL); g_free (text); } diff --git a/capplets/keybindings/eggcellrendererkeys.h b/capplets/keybindings/eggcellrendererkeys.h index aeddbf76c..6ea6d41fa 100644 --- a/capplets/keybindings/eggcellrendererkeys.h +++ b/capplets/keybindings/eggcellrendererkeys.h @@ -46,6 +46,7 @@ struct _EggCellRendererKeys { GtkCellRendererText parent; guint accel_key; + guint keycode; EggVirtualModifierType accel_mask; GtkWidget *edit_widget; GtkWidget *grab_widget; @@ -58,11 +59,14 @@ struct _EggCellRendererKeysClass { GtkCellRendererTextClass parent_class; - void (* keys_edited) (EggCellRendererKeys *keys, - const char *path_string, - guint keyval, - EggVirtualModifierType mask, - guint hardware_keycode); + void (* accel_edited) (EggCellRendererKeys *keys, + const char *path_string, + guint keyval, + EggVirtualModifierType mask, + guint hardware_keycode); + + void (* accel_cleared) (EggCellRendererKeys *keys, + const char *path_string); }; GType egg_cell_renderer_keys_get_type (void); @@ -70,6 +74,7 @@ GtkCellRenderer *egg_cell_renderer_keys_new (void); void egg_cell_renderer_keys_set_accelerator (EggCellRendererKeys *keys, guint keyval, + guint keycode, EggVirtualModifierType mask); void egg_cell_renderer_keys_get_accelerator (EggCellRendererKeys *keys, guint *keyval, diff --git a/capplets/keybindings/gnome-keybinding-properties.c b/capplets/keybindings/gnome-keybinding-properties.c index ec1f0db1d..ac520fd60 100644 --- a/capplets/keybindings/gnome-keybinding-properties.c +++ b/capplets/keybindings/gnome-keybinding-properties.c @@ -112,6 +112,7 @@ typedef struct { char *gconf_key; guint keyval; + guint keycode; EggVirtualModifierType mask; gboolean editable; GtkTreeModel *model; @@ -122,6 +123,7 @@ typedef struct static void reload_key_entries (gpointer wm_name, GladeXML *dialog); static char* binding_name (guint keyval, + guint keycode, EggVirtualModifierType mask, gboolean translate); @@ -195,11 +197,12 @@ create_dialog (void) static char* binding_name (guint keyval, + guint keycode, EggVirtualModifierType mask, gboolean translate) { - if (keyval != 0) - return egg_virtual_accelerator_name (keyval, mask); + if (keyval != 0 || keycode != 0) + return egg_virtual_accelerator_name (keyval, keycode, mask); else return translate ? g_strdup (_("Disabled")) : g_strdup ("disabled"); } @@ -207,6 +210,7 @@ binding_name (guint keyval, static gboolean binding_from_string (const char *str, guint *accelerator_key, + guint *keycode, EggVirtualModifierType *accelerator_mods) { g_return_val_if_fail (accelerator_key != NULL, FALSE); @@ -214,11 +218,12 @@ binding_from_string (const char *str, if (str == NULL || (str && strcmp (str, "disabled") == 0)) { *accelerator_key = 0; + *keycode = 0; *accelerator_mods = 0; return TRUE; } - egg_accelerator_parse_virtual (str, accelerator_key, accelerator_mods); + egg_accelerator_parse_virtual (str, accelerator_key, keycode, accelerator_mods); if (*accelerator_key == 0) return FALSE; @@ -249,6 +254,7 @@ accel_set_func (GtkTreeViewColumn *tree_column, "editable", FALSE, "accel_key", key_entry->keyval, "accel_mask", key_entry->mask, + "keycode", key_entry->keycode, "style", PANGO_STYLE_ITALIC, NULL); else @@ -257,6 +263,7 @@ accel_set_func (GtkTreeViewColumn *tree_column, "editable", TRUE, "accel_key", key_entry->keyval, "accel_mask", key_entry->mask, + "keycode", key_entry->keycode, "style", PANGO_STYLE_NORMAL, NULL); } @@ -295,7 +302,7 @@ keybinding_key_changed (GConfClient *client, key_entry = (KeyEntry *)user_data; key_value = gconf_value_get_string (entry->value); - binding_from_string (key_value, &key_entry->keyval, &key_entry->mask); + binding_from_string (key_value, &key_entry->keyval, &key_entry->keycode, &key_entry->mask); key_entry->editable = gconf_entry_get_is_writable (entry); /* update the model */ @@ -329,6 +336,7 @@ keyentry_sort_func (GtkTreeModel *model, if (key_entry_a != NULL) name_a = binding_name (key_entry_a->keyval, + key_entry_a->keycode, key_entry_a->mask, TRUE); else @@ -336,6 +344,7 @@ keyentry_sort_func (GtkTreeModel *model, if (key_entry_b != NULL) name_b = binding_name (key_entry_b->keyval, + key_entry_b->keycode, key_entry_b->mask, TRUE); else @@ -514,7 +523,7 @@ append_keys_to_tree (GladeXML *dialog, key_string, (GConfClientNotifyFunc) &keybinding_key_changed, key_entry, NULL, NULL); - binding_from_string (key_value, &key_entry->keyval, &key_entry->mask); + binding_from_string (key_value, &key_entry->keyval, &key_entry->keycode, &key_entry->mask); g_free (key_value); key_entry->description = g_strdup (gconf_schema_get_short_desc (schema)); @@ -632,6 +641,7 @@ cb_check_for_uniqueness (GtkTreeModel *model, if (tmp_key_entry != NULL && key_entry->keyval == tmp_key_entry->keyval && key_entry->mask == tmp_key_entry->mask && + key_entry->keycode == tmp_key_entry->keycode && /* be sure we don't claim a key is a dup of itself */ strcmp (key_entry->gconf_key, tmp_key_entry->gconf_key) != 0) { @@ -648,7 +658,7 @@ accel_edited_callback (GtkCellRendererText *cell, const char *path_string, guint keyval, EggVirtualModifierType mask, - guint keycode, + guint keycode, gpointer data) { GtkTreeView *view = (GtkTreeView *)data; @@ -674,12 +684,13 @@ accel_edited_callback (GtkCellRendererText *cell, tmp_key.model = model; tmp_key.keyval = keyval; + tmp_key.keycode = keycode; tmp_key.mask = mask; tmp_key.gconf_key = key_entry->gconf_key; tmp_key.description = NULL; tmp_key.editable = TRUE; /* kludge to stuff in a return flag */ - if (keyval != 0) /* any number of keys can be disabled */ + if (keyval != 0 || keycode != 0) /* any number of keys can be disabled */ gtk_tree_model_foreach (model, cb_check_for_uniqueness, &tmp_key); /* flag to see if the new accelerator was in use by something */ @@ -688,7 +699,7 @@ accel_edited_callback (GtkCellRendererText *cell, GtkWidget *dialog; char *name; - name = egg_virtual_accelerator_name (keyval, mask); + name = egg_virtual_accelerator_name (keyval, keycode, mask); dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))), @@ -705,12 +716,12 @@ accel_edited_callback (GtkCellRendererText *cell, /* set it back to its previous value. */ egg_cell_renderer_keys_set_accelerator (EGG_CELL_RENDERER_KEYS (cell), - key_entry->keyval, key_entry->mask); + key_entry->keyval, key_entry->keycode, key_entry->mask); gtk_tree_path_free (path); return; } - str = binding_name (keyval, mask, FALSE); + str = binding_name (keyval, keycode, mask, FALSE); gconf_client_set_string (gconf_client_get_default(), key_entry->gconf_key, @@ -738,6 +749,54 @@ accel_edited_callback (GtkCellRendererText *cell, gtk_tree_path_free (path); } +static void +accel_cleared_callback (GtkCellRendererText *cell, + const char *path_string, + gpointer data) +{ + GtkTreeView *view = (GtkTreeView *) data; + GtkTreePath *path = gtk_tree_path_new_from_string (path_string); + KeyEntry *key_entry; + GtkTreeIter iter; + GError *err = NULL; + GtkTreeModel *model; + + model = get_real_model (view); + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, + KEYENTRY_COLUMN, &key_entry, + -1); + + /* sanity check */ + if (key_entry == NULL) + { + gtk_tree_path_free (path); + return; + } + + /* Unset the key */ + gconf_client_set_string (gconf_client_get_default(), + key_entry->gconf_key, + "disabled", + &err); + if (err != NULL) + { + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))), + GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK, + _("Error unsetting accelerator in configuration database: %s\n"), + err->message); + gtk_dialog_run (GTK_DIALOG (dialog)); + + gtk_widget_destroy (dialog); + g_error_free (err); + key_entry->editable = FALSE; + } + +} static void theme_changed_func (gpointer uri, @@ -914,10 +973,15 @@ setup_dialog (GladeXML *dialog) NULL); g_signal_connect (G_OBJECT (renderer), - "keys_edited", + "accel_edited", G_CALLBACK (accel_edited_callback), WID ("shortcut_treeview")); + g_signal_connect (G_OBJECT (renderer), + "accel_cleared", + G_CALLBACK (accel_cleared_callback), + WID ("shortcut_treeview")); + column = gtk_tree_view_column_new_with_attributes (_("Shortcut"), renderer, NULL); gtk_tree_view_column_set_cell_data_func (column, renderer, accel_set_func, NULL, NULL); gtk_tree_view_column_set_resizable (column, FALSE);