/* * Copyright (C) 2010-2011 Daiki Ueno * Copyright (C) 2010-2011 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA */ /** * SECTION:eek-keysym * @short_description: an #EekSymbol represents an X keysym */ #include "config.h" #include #include #include "eek-keysym.h" #include "eek-serializable.h" /* modifier keys */ #define EEK_KEYSYM_Shift_L 0xffe1 #define EEK_KEYSYM_Shift_R 0xffe2 #define EEK_KEYSYM_ISO_Level3_Shift 0xfe03 #define EEK_KEYSYM_Caps_Lock 0xffe5 #define EEK_KEYSYM_Shift_Lock 0xffe6 #define EEK_KEYSYM_Control_L 0xffe3 #define EEK_KEYSYM_Control_R 0xffe4 #define EEK_KEYSYM_Alt_L 0xffe9 #define EEK_KEYSYM_Alt_R 0xffea #define EEK_KEYSYM_Meta_L 0xffe7 #define EEK_KEYSYM_Meta_R 0xffe8 #define EEK_KEYSYM_Super_L 0xffeb #define EEK_KEYSYM_Super_R 0xffec #define EEK_KEYSYM_Hyper_L 0xffed #define EEK_KEYSYM_Hyper_R 0xffee typedef struct _EekKeysymPrivate { guint xkeysym; } EekKeysymPrivate; struct _EekKeysymEntry { guint xkeysym; const gchar *name; }; typedef struct _EekKeysymEntry EekKeysymEntry; #include "eek-special-keysym-entries.h" #include "eek-unicode-keysym-entries.h" #include "eek-xkeysym-keysym-entries.h" static void eek_serializable_iface_init (EekSerializableIface *iface); G_DEFINE_TYPE_EXTENDED (EekKeysym, eek_keysym, EEK_TYPE_SYMBOL, 0, /* GTypeFlags */ G_ADD_PRIVATE (EekKeysym) G_IMPLEMENT_INTERFACE (EEK_TYPE_SERIALIZABLE, eek_serializable_iface_init)) static EekSerializableIface *eek_keysym_parent_serializable_iface; static void eek_keysym_real_serialize (EekSerializable *self, GVariantBuilder *builder) { EekKeysymPrivate *priv = eek_keysym_get_instance_private ( EEK_KEYSYM(self)); eek_keysym_parent_serializable_iface->serialize (self, builder); g_variant_builder_add (builder, "u", priv->xkeysym); } static gsize eek_keysym_real_deserialize (EekSerializable *self, GVariant *variant, gsize index) { EekKeysymPrivate *priv = eek_keysym_get_instance_private ( EEK_KEYSYM(self)); index = eek_keysym_parent_serializable_iface->deserialize (self, variant, index); g_variant_get_child (variant, index++, "u", &priv->xkeysym); return index; } static void eek_serializable_iface_init (EekSerializableIface *iface) { eek_keysym_parent_serializable_iface = g_type_interface_peek_parent (iface); iface->serialize = eek_keysym_real_serialize; iface->deserialize = eek_keysym_real_deserialize; } static gchar * unichar_to_utf8 (gunichar uc) { if (g_unichar_isgraph (uc)) { gchar *buf; gint len; len = g_unichar_to_utf8 (uc, NULL); buf = g_malloc0 (len + 1); g_unichar_to_utf8 (uc, buf); return buf; } return g_strdup (""); } static int keysym_entry_compare_by_xkeysym (const void *key0, const void *key1) { const EekKeysymEntry *entry0 = key0, *entry1 = key1; return (gint) (entry0->xkeysym - entry1->xkeysym); } static EekKeysymEntry * find_keysym_entry_by_xkeysym (guint xkeysym, const EekKeysymEntry *entries, gint num_entries) { EekKeysymEntry key; key.xkeysym = xkeysym; return bsearch (&key, entries, num_entries, sizeof (EekKeysymEntry), keysym_entry_compare_by_xkeysym); } static gboolean get_unichar (guint xkeysym, gunichar *uc) { /* Check for Latin-1 characters (1:1 mapping) */ if ((xkeysym >= 0x0020 && xkeysym <= 0x007e) || (xkeysym >= 0x00a0 && xkeysym <= 0x00ff)) { *uc = xkeysym; return TRUE; } /* Also check for directly encoded 24-bit UCS characters: */ if ((xkeysym & 0xff000000) == 0x01000000) { *uc = xkeysym & 0x00ffffff; return TRUE; } return FALSE; } G_INLINE_FUNC EekModifierType get_modifier_mask (guint xkeysym) { switch (xkeysym) { case EEK_KEYSYM_Shift_L: case EEK_KEYSYM_Shift_R: case EEK_KEYSYM_Caps_Lock: case EEK_KEYSYM_Shift_Lock: return EEK_SHIFT_MASK; case EEK_KEYSYM_ISO_Level3_Shift: return EEK_BUTTON1_MASK; case EEK_KEYSYM_Control_L: case EEK_KEYSYM_Control_R: return EEK_CONTROL_MASK; case EEK_KEYSYM_Alt_L: case EEK_KEYSYM_Alt_R: return EEK_MOD1_MASK; case EEK_KEYSYM_Meta_L: case EEK_KEYSYM_Meta_R: return EEK_META_MASK; case EEK_KEYSYM_Super_L: case EEK_KEYSYM_Super_R: return EEK_SUPER_MASK; case EEK_KEYSYM_Hyper_L: case EEK_KEYSYM_Hyper_R: return EEK_HYPER_MASK; } return 0; } static void eek_keysym_class_init (EekKeysymClass *klass) { /* void */ } static void eek_keysym_init (EekKeysym *self) { /* void */ } /** * eek_keysym_new_with_modifier: * @xkeysym: an X keysym value * @modifier_mask: modifier assigned to @xkeysym * * Create an #EekKeysym with given X keysym value @xkeysym and * modifier @modifier_mask. */ EekKeysym * eek_keysym_new_with_modifier (guint xkeysym, EekModifierType modifier_mask) { EekKeysym *keysym; EekKeysymPrivate *priv; EekKeysymEntry *special_entry, *xkeysym_entry, *unicode_entry, *unichar_entry; gchar *name, *label; gunichar uc; special_entry = find_keysym_entry_by_xkeysym (xkeysym, special_keysym_entries, G_N_ELEMENTS(special_keysym_entries)); xkeysym_entry = find_keysym_entry_by_xkeysym (xkeysym, xkeysym_keysym_entries, G_N_ELEMENTS(xkeysym_keysym_entries)); unicode_entry = find_keysym_entry_by_xkeysym (xkeysym, unicode_keysym_entries, G_N_ELEMENTS(unicode_keysym_entries)); unichar_entry = NULL; if (get_unichar (xkeysym, &uc)) { unichar_entry = g_slice_new (EekKeysymEntry); unichar_entry->xkeysym = xkeysym; unichar_entry->name = unichar_to_utf8 (uc); } name = NULL; if (xkeysym_entry) { name = g_strdup (xkeysym_entry->name); } else if (unichar_entry) { name = g_strdup (unichar_entry->name); } else if (unicode_entry) { name = g_strdup (unicode_entry->name); } else { name = g_strdup (""); } /* label */ if (special_entry) label = g_strdup (special_entry->name); else if (unichar_entry) label = g_strdup (unichar_entry->name); else if (unicode_entry) label = g_strdup (unicode_entry->name); else label = g_strdup (name); keysym = g_object_new (EEK_TYPE_KEYSYM, "name", name, "label", label, "modifier-mask", modifier_mask, NULL); g_free (name); g_free (label); if (unichar_entry) { g_free ((gpointer) unichar_entry->name); g_slice_free (EekKeysymEntry, unichar_entry); } priv = eek_keysym_get_instance_private (keysym); priv->xkeysym = xkeysym; return keysym; } /** * eek_keysym_new: * @xkeysym: an X keysym value * * Create an #EekKeysym with given X keysym value @xkeysym. */ EekKeysym * eek_keysym_new (guint xkeysym) { return eek_keysym_new_with_modifier (xkeysym, get_modifier_mask (xkeysym)); } /** * eek_keysym_new_from_name: * @name: an X keysym name * * Create an #EekKeysym with an X keysym value looked up by @name. */ EekKeysym * eek_keysym_new_from_name (const gchar *name) { gint i; for (i = 0; i < G_N_ELEMENTS(xkeysym_keysym_entries); i++) if (g_strcmp0 (xkeysym_keysym_entries[i].name, name) == 0) return eek_keysym_new (xkeysym_keysym_entries[i].xkeysym); // g_warning ("can't find keysym entry for %s", name); return g_object_new (EEK_TYPE_KEYSYM, "name", name, "label", name, "modifier-mask", 0, NULL); } /** * eek_keysym_get_xkeysym: * @keysym: an #EekKeysym * * Get an X keysym value associated with @keysym */ guint eek_keysym_get_xkeysym (EekKeysym *keysym) { EekKeysymPrivate *priv; g_assert (EEK_IS_KEYSYM(keysym)); priv = eek_keysym_get_instance_private (keysym); return priv->xkeysym; }