Commit 06b55b21 authored by Bastien Nocera's avatar Bastien Nocera

gtk: Add accel with keycode parsing functions

Which handle accelerators with keycodes as well as keyvals,
so we can use it in applications that use GtkCellRendererAccel's
"Other" mode of operations (namely gnome-control-center and
gnome-settings-daemon).

https://bugzilla.gnome.org/show_bug.cgi?id=662755
parent 0f167e8b
...@@ -35,8 +35,11 @@ gtk_about_dialog_set_website_label ...@@ -35,8 +35,11 @@ gtk_about_dialog_set_website_label
gtk_about_dialog_set_wrap_license gtk_about_dialog_set_wrap_license
gtk_accelerator_get_default_mod_mask gtk_accelerator_get_default_mod_mask
gtk_accelerator_get_label gtk_accelerator_get_label
gtk_accelerator_get_label_with_keycode
gtk_accelerator_name gtk_accelerator_name
gtk_accelerator_name_with_keycode
gtk_accelerator_parse gtk_accelerator_parse
gtk_accelerator_parse_with_keycode
gtk_accelerator_set_default_mod_mask gtk_accelerator_set_default_mod_mask
gtk_accelerator_valid gtk_accelerator_valid
gtk_accel_flags_get_type gtk_accel_flags_get_type
......
...@@ -1165,42 +1165,58 @@ is_primary (const gchar *string) ...@@ -1165,42 +1165,58 @@ is_primary (const gchar *string)
(string[8] == '>')); (string[8] == '>'));
} }
static inline gboolean
is_keycode (const gchar *string)
{
return (string[0] == '0' &&
string[1] == 'x' &&
g_ascii_isxdigit (string[2]) &&
g_ascii_isxdigit (string[3]));
}
/** /**
* gtk_accelerator_parse: * gtk_accelerator_parse_with_keycode:
* @accelerator: string representing an accelerator * @accelerator: string representing an accelerator
* @accelerator_key: (out) (allow-none): return location for accelerator * @accelerator_key: (out) (allow-none): return location for accelerator
* keyval, or %NULL * keyval, or %NULL
* @accelerator_codes: (out) (allow-none): return location for accelerator
* keycodes, or %NULL
* @accelerator_mods: (out) (allow-none): return location for accelerator * @accelerator_mods: (out) (allow-none): return location for accelerator
* modifier mask, %NULL * modifier mask, %NULL
* *
* Parses a string representing an accelerator. The * Parses a string representing an accelerator, similarly to
* format looks like "<Control>a" or "<Shift><Alt>F1" * gtk_accelerator_parse() but handles keycodes as well. This is only
* or "<Release>z" (the last one is for key release). * useful for system-level components, applications should use
* gtk_accelerator_parse() instead.
* *
* The parser is fairly liberal and allows lower or upper case, * If a keycode is present in the accelerator and no @accelerator_codes
* and also abbreviations such as "<Ctl>" and "<Ctrl>". * is given, the parse will fail.
* Key names are parsed using gdk_keyval_from_name(). For character
* keys the name is not the symbol, but the lowercase name, e.g. one
* would use "<Ctrl>minus" instead of "<Ctrl>-".
* *
* If the parse fails, @accelerator_key and @accelerator_mods will * If the parse fails, @accelerator_key, @accelerator_mods and
* be set to 0 (zero). * @accelerator_codes will be set to 0 (zero).
*
* Since: 3.4
*/ */
void void
gtk_accelerator_parse (const gchar *accelerator, gtk_accelerator_parse_with_keycode (const gchar *accelerator,
guint *accelerator_key, guint *accelerator_key,
GdkModifierType *accelerator_mods) guint **accelerator_codes,
GdkModifierType *accelerator_mods)
{ {
guint keyval; guint keyval;
GdkModifierType mods; GdkModifierType mods;
gint len; gint len;
gboolean error;
if (accelerator_key) if (accelerator_key)
*accelerator_key = 0; *accelerator_key = 0;
if (accelerator_mods) if (accelerator_mods)
*accelerator_mods = 0; *accelerator_mods = 0;
if (accelerator_codes)
*accelerator_codes = NULL;
g_return_if_fail (accelerator != NULL); g_return_if_fail (accelerator != NULL);
error = FALSE;
keyval = 0; keyval = 0;
mods = 0; mods = 0;
len = strlen (accelerator); len = strlen (accelerator);
...@@ -1301,18 +1317,174 @@ gtk_accelerator_parse (const gchar *accelerator, ...@@ -1301,18 +1317,174 @@ gtk_accelerator_parse (const gchar *accelerator,
} }
else else
{ {
keyval = gdk_keyval_from_name (accelerator); if (len >= 4 && is_keycode (accelerator))
{
char keystring[5];
gchar *endptr;
gint tmp_keycode;
keyval = GDK_KEY_VoidSymbol;
memcpy (keystring, accelerator, 4);
keystring [4] = '\000';
tmp_keycode = strtol (keystring, &endptr, 16);
if (endptr == NULL || *endptr != '\000')
{
error = TRUE;
goto out;
}
else if (accelerator_codes != NULL)
{
/* 0x00 is an invalid keycode too. */
if (tmp_keycode == 0)
{
error = TRUE;
goto out;
}
else
{
*accelerator_codes = g_new0 (guint, 2);
(*accelerator_codes)[0] = tmp_keycode;
}
}
else
{
/* There was a keycode in the string, but
* we cannot store it, so we have an error */
error = TRUE;
goto out;
}
}
else
{
keyval = gdk_keyval_from_name (accelerator);
if (keyval == GDK_KEY_VoidSymbol)
{
error = TRUE;
goto out;
}
}
if (keyval != GDK_KEY_VoidSymbol && accelerator_codes != NULL)
{
GdkKeymapKey *keys;
gint n_keys, i, j;
if (!gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), keyval, &keys, &n_keys))
{
/* Not in keymap */
error = TRUE;
goto out;
}
else
{
*accelerator_codes = g_new0 (guint, n_keys + 1);
for (i = 0, j = 0; i < n_keys; ++i)
{
if (keys[i].level == 0)
(*accelerator_codes)[j++] = keys[i].keycode;
}
if (j == 0)
{
g_free (*accelerator_codes);
*accelerator_codes = NULL;
/* Not in keymap */
error = TRUE;
goto out;
}
g_free (keys);
}
}
accelerator += len; accelerator += len;
len -= len; len -= len;
} }
} }
out:
if (error)
keyval = mods = 0;
if (accelerator_key) if (accelerator_key)
*accelerator_key = gdk_keyval_to_lower (keyval); *accelerator_key = gdk_keyval_to_lower (keyval);
if (accelerator_mods) if (accelerator_mods)
*accelerator_mods = mods; *accelerator_mods = mods;
} }
/**
* gtk_accelerator_parse:
* @accelerator: string representing an accelerator
* @accelerator_key: (out) (allow-none): return location for accelerator
* keyval, or %NULL
* @accelerator_mods: (out) (allow-none): return location for accelerator
* modifier mask, %NULL
*
* Parses a string representing an accelerator. The
* format looks like "&lt;Control&gt;a" or "&lt;Shift&gt;&lt;Alt&gt;F1"
* or "&lt;Release&gt;z" (the last one is for key release).
*
* The parser is fairly liberal and allows lower or upper case,
* and also abbreviations such as "&lt;Ctl&gt;" and "&lt;Ctrl&gt;".
* Key names are parsed using gdk_keyval_from_name(). For character
* keys the name is not the symbol, but the lowercase name, e.g. one
* would use "&lt;Ctrl&gt;minus" instead of "&lt;Ctrl&gt;-".
*
* If the parse fails, @accelerator_key and @accelerator_mods will
* be set to 0 (zero).
*/
void
gtk_accelerator_parse (const gchar *accelerator,
guint *accelerator_key,
GdkModifierType *accelerator_mods)
{
gtk_accelerator_parse_with_keycode (accelerator, accelerator_key, NULL, accelerator_mods);
}
/**
* gtk_accelerator_name_with_keycode:
* @display: (allow-none): a #GdkDisplay or %NULL to use the default display
* @accelerator_key: accelerator keyval
* @accelerator_mods: accelerator modifier mask
*
* Converts an accelerator keyval and modifier mask
* into a string parseable by gtk_accelerator_parse_full(),
* similarly to gtk_accelerator_name() but handling keycodes.
* This is only useful for system-level components, applications
* should use gtk_accelerator_parse() instead.
*
* Returns: a newly allocated accelerator name.
*
* Since: 3.4
*/
gchar *
gtk_accelerator_name_with_keycode (GdkDisplay *display,
guint accelerator_key,
guint keycode,
GdkModifierType accelerator_mods)
{
gchar *gtk_name;
if (display == NULL)
display = gdk_display_manager_get_default_display (gdk_display_manager_get ());
gdk_keymap_add_virtual_modifiers (gdk_keymap_get_for_display (display), &accelerator_mods);
gtk_name = gtk_accelerator_name (accelerator_key, accelerator_mods);
if (!accelerator_key)
{
gchar *name;
name = g_strdup_printf ("%s0x%02x", gtk_name, keycode);
g_free (gtk_name);
return name;
}
return gtk_name;
}
/** /**
* gtk_accelerator_name: * gtk_accelerator_name:
* @accelerator_key: accelerator keyval * @accelerator_key: accelerator keyval
...@@ -1457,6 +1629,49 @@ gtk_accelerator_name (guint accelerator_key, ...@@ -1457,6 +1629,49 @@ gtk_accelerator_name (guint accelerator_key,
return accelerator; return accelerator;
} }
/**
* gtk_accelerator_get_label_with_keycode:
* @display: (allow-none): a #GdkDisplay or %NULL to use the default display
* @accelerator_key: accelerator keyval
* @accelerator_mods: accelerator modifier mask
*
* Converts an accelerator keyval and modifier mask
* into a (possibly translated) string that can be displayed to
* a user, similarly to gtk_accelerator_get_label(), but handling
* keycodes.
*
* This is only useful for system-level components, applications
* should use gtk_accelerator_parse() instead.
*
* Returns: a newly-allocated string representing the accelerator.
*
* Since: 3.4
*/
gchar *
gtk_accelerator_get_label_with_keycode (GdkDisplay *display,
guint accelerator_key,
guint keycode,
GdkModifierType accelerator_mods)
{
gchar *gtk_label;
if (display == NULL)
display = gdk_display_manager_get_default_display (gdk_display_manager_get ());
gdk_keymap_add_virtual_modifiers (gdk_keymap_get_for_display (display), &accelerator_mods);
gtk_label = gtk_accelerator_get_label (accelerator_key, accelerator_mods);
if (!accelerator_key)
{
gchar *label;
label = g_strdup_printf ("%s0x%02x", gtk_label, keycode);
g_free (gtk_label);
return label;
}
return gtk_label;
}
/** /**
* gtk_accelerator_get_label: * gtk_accelerator_get_label:
* @accelerator_key: accelerator keyval * @accelerator_key: accelerator keyval
......
...@@ -163,10 +163,22 @@ gboolean gtk_accelerator_valid (guint keyval, ...@@ -163,10 +163,22 @@ gboolean gtk_accelerator_valid (guint keyval,
void gtk_accelerator_parse (const gchar *accelerator, void gtk_accelerator_parse (const gchar *accelerator,
guint *accelerator_key, guint *accelerator_key,
GdkModifierType *accelerator_mods); GdkModifierType *accelerator_mods);
void gtk_accelerator_parse_with_keycode (const gchar *accelerator,
guint *accelerator_key,
guint **accelerator_codes,
GdkModifierType *accelerator_mods);
gchar* gtk_accelerator_name (guint accelerator_key, gchar* gtk_accelerator_name (guint accelerator_key,
GdkModifierType accelerator_mods); GdkModifierType accelerator_mods);
gchar* gtk_accelerator_name_with_keycode (GdkDisplay *display,
guint accelerator_key,
guint keycode,
GdkModifierType accelerator_mods);
gchar* gtk_accelerator_get_label (guint accelerator_key, gchar* gtk_accelerator_get_label (guint accelerator_key,
GdkModifierType accelerator_mods); GdkModifierType accelerator_mods);
gchar* gtk_accelerator_get_label_with_keycode (GdkDisplay *display,
guint accelerator_key,
guint keycode,
GdkModifierType accelerator_mods);
void gtk_accelerator_set_default_mod_mask (GdkModifierType default_mod_mask); void gtk_accelerator_set_default_mod_mask (GdkModifierType default_mod_mask);
GdkModifierType GdkModifierType
gtk_accelerator_get_default_mod_mask (void); gtk_accelerator_get_default_mod_mask (void);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment