From 5e4a6b2c8e490a93f91c65a20d781027963b862e Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Wed, 26 Jan 2011 11:59:12 +0900 Subject: [PATCH] Port modifier handling code from application into library. --- eek/eek-key.c | 25 ++++++--- eek/eek-keyboard.c | 127 +++++++++++++++++++++++++++++++++++++++++++-- eek/eek-keyboard.h | 70 +++++++++++++++++-------- eek/eek-keysym.c | 30 +++++++++++ eek/eek-keysym.h | 48 +++++++++++++++++ eek/eek-types.h | 16 ++++++ src/eekboard.c | 44 ++++------------ 7 files changed, 291 insertions(+), 69 deletions(-) diff --git a/eek/eek-key.c b/eek/eek-key.c index 576db771..027a9c3d 100644 --- a/eek/eek-key.c +++ b/eek/eek-key.c @@ -502,6 +502,20 @@ eek_key_get_keysyms (EekKey *key, EEK_KEY_GET_CLASS(key)->get_keysyms (key, keysyms, num_groups, num_levels); } +static EekKeyboard * +get_keyboard (EekKey *key) +{ + EekElement *parent; + + parent = eek_element_get_parent (EEK_ELEMENT(key)); + g_return_val_if_fail (EEK_IS_SECTION(parent), NULL); + + parent = eek_element_get_parent (parent); + g_return_val_if_fail (EEK_IS_KEYBOARD(parent), NULL); + + return EEK_KEYBOARD(parent); +} + /** * eek_key_get_keysym: * @key: an #EekKey @@ -513,17 +527,14 @@ guint eek_key_get_keysym (EekKey *key) { gint group, level; - EekElement *parent; + EekKeyboard *keyboard; g_return_val_if_fail (EEK_IS_KEY (key), EEK_INVALID_KEYSYM); - parent = eek_element_get_parent (EEK_ELEMENT(key)); - g_return_val_if_fail (EEK_IS_SECTION(parent), EEK_INVALID_KEYSYM); + keyboard = get_keyboard (key); + g_return_val_if_fail (keyboard, EEK_INVALID_KEYSYM); - parent = eek_element_get_parent (parent); - g_return_val_if_fail (EEK_IS_KEYBOARD(parent), EEK_INVALID_KEYSYM); - - eek_keyboard_get_keysym_index (EEK_KEYBOARD(parent), &group, &level); + eek_keyboard_get_keysym_index (keyboard, &group, &level); return eek_key_get_keysym_at_index (key, group, level); } diff --git a/eek/eek-keyboard.c b/eek/eek-keyboard.c index 5c3757fb..cf668d79 100644 --- a/eek/eek-keyboard.c +++ b/eek/eek-keyboard.c @@ -34,6 +34,7 @@ #include "eek-keyboard.h" #include "eek-section.h" #include "eek-key.h" +#include "eek-keysym.h" #include "eek-marshallers.h" enum { @@ -41,6 +42,7 @@ enum { PROP_GROUP, PROP_LEVEL, PROP_LAYOUT, + PROP_MODIFIER_BEHAVIOR, PROP_LAST }; @@ -64,6 +66,8 @@ struct _EekKeyboardPrivate gint group; gint level; EekLayout *layout; + EekModifierBehavior modifier_behavior; + EekModifierType modifiers; }; static void @@ -180,6 +184,10 @@ eek_keyboard_set_property (GObject *object, priv->layout = g_value_get_object (value); g_object_ref (priv->layout); break; + case PROP_MODIFIER_BEHAVIOR: + eek_keyboard_set_modifier_behavior (EEK_KEYBOARD(object), + g_value_get_int (value)); + break; default: g_object_set_property (object, g_param_spec_get_name (pspec), @@ -208,6 +216,10 @@ eek_keyboard_get_property (GObject *object, case PROP_LAYOUT: g_value_set_object (value, priv->layout); break; + case PROP_MODIFIER_BEHAVIOR: + g_value_set_int (value, + eek_keyboard_get_modifier_behavior (EEK_KEYBOARD(object))); + break; default: g_object_get_property (object, g_param_spec_get_name (pspec), @@ -224,6 +236,60 @@ eek_keyboard_real_keysym_index_changed (EekKeyboard *self, /* g_debug ("keysym-index-changed"); */ } +static void +set_level_from_modifiers (EekKeyboard *self) +{ + EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(self); + guint level = 0; + + if (priv->modifiers & EEK_MOD5_MASK) + level |= 2; + if (priv->modifiers & EEK_SHIFT_MASK) + level |= 1; + eek_keyboard_set_level (self, level); +} + +static void +eek_keyboard_real_key_pressed (EekKeyboard *self, + EekKey *key) +{ + EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(self); + guint keysym; + EekModifierType modifier; + + if (priv->modifier_behavior == EEK_MODIFIER_BEHAVIOR_LATCH) + priv->modifiers = 0; + + keysym = eek_key_get_keysym_at_index (key, priv->group, priv->level); + modifier = eek_keysym_to_modifier (keysym); + + if (modifier != 0) { + if (priv->modifier_behavior == EEK_MODIFIER_BEHAVIOR_NONE || + priv->modifier_behavior == EEK_MODIFIER_BEHAVIOR_LATCH) + priv->modifiers |= modifier; + else if (priv->modifier_behavior == EEK_MODIFIER_BEHAVIOR_LOCK) + priv->modifiers ^= modifier; + } + set_level_from_modifiers (self); +} + +static void +eek_keyboard_real_key_released (EekKeyboard *self, + EekKey *key) +{ + EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(self); + guint keysym; + EekModifierType modifier; + + keysym = eek_key_get_keysym_at_index (key, priv->group, priv->level); + modifier = eek_keysym_to_modifier (keysym); + if (modifier != 0) { + if (priv->modifier_behavior == EEK_MODIFIER_BEHAVIOR_NONE) + priv->modifiers &= ~modifier; + } + set_level_from_modifiers (self); +} + static void eek_keyboard_class_init (EekKeyboardClass *klass) { @@ -238,6 +304,9 @@ eek_keyboard_class_init (EekKeyboardClass *klass) klass->create_section = eek_keyboard_real_create_section; klass->find_key_by_keycode = eek_keyboard_real_find_key_by_keycode; + /* signals */ + klass->key_pressed = eek_keyboard_real_key_pressed; + klass->key_released = eek_keyboard_real_key_released; klass->keysym_index_changed = eek_keyboard_real_keysym_index_changed; gobject_class->get_property = eek_keyboard_get_property; @@ -285,6 +354,20 @@ eek_keyboard_class_init (EekKeyboardClass *klass) PROP_LAYOUT, pspec); + /** + * EekKeyboard:modifier-behavior: + * + * The modifier handling mode of #EekKeyboard. + */ + pspec = g_param_spec_int ("modifier-behavior", + "Modifier behavior", + "Modifier handling mode of the keyboard", + 0, G_MAXINT, EEK_MODIFIER_BEHAVIOR_NONE, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_MODIFIER_BEHAVIOR, + pspec); + /** * EekKeyboard::key-pressed: * @keyboard: an #EekKeyboard @@ -296,8 +379,8 @@ eek_keyboard_class_init (EekKeyboardClass *klass) signals[KEY_PRESSED] = g_signal_new ("key-pressed", G_TYPE_FROM_CLASS(gobject_class), - G_SIGNAL_RUN_FIRST, - 0, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(EekKeyboardClass, key_pressed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, @@ -316,8 +399,8 @@ eek_keyboard_class_init (EekKeyboardClass *klass) signals[KEY_RELEASED] = g_signal_new ("key-released", G_TYPE_FROM_CLASS(gobject_class), - G_SIGNAL_RUN_FIRST, - 0, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(EekKeyboardClass, key_released), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, @@ -356,6 +439,8 @@ eek_keyboard_init (EekKeyboard *self) priv = self->priv = EEK_KEYBOARD_GET_PRIVATE(self); priv->group = priv->level = 0; priv->layout = NULL; + priv->modifier_behavior = EEK_MODIFIER_BEHAVIOR_NONE; + priv->modifiers = 0; } /** @@ -508,3 +593,37 @@ eek_keyboard_get_size (EekKeyboard *keyboard, *width = bounds.width; *height = bounds.height; } + +void +eek_keyboard_set_modifier_behavior (EekKeyboard *keyboard, + EekModifierBehavior modifier_behavior) +{ + EekKeyboardPrivate *priv; + + g_return_if_fail (EEK_IS_KEYBOARD(keyboard)); + priv = EEK_KEYBOARD_GET_PRIVATE(keyboard); + + priv->modifier_behavior = modifier_behavior; +} + +EekModifierBehavior +eek_keyboard_get_modifier_behavior (EekKeyboard *keyboard) +{ + EekKeyboardPrivate *priv; + + g_assert (EEK_IS_KEYBOARD(keyboard)); + priv = EEK_KEYBOARD_GET_PRIVATE(keyboard); + + return priv->modifier_behavior; +} + +EekModifierType +eek_keyboard_get_modifiers (EekKeyboard *keyboard) +{ + EekKeyboardPrivate *priv; + + g_assert (EEK_IS_KEYBOARD(keyboard)); + priv = EEK_KEYBOARD_GET_PRIVATE(keyboard); + + return priv->modifiers; +} diff --git a/eek/eek-keyboard.h b/eek/eek-keyboard.h index 2d8c8515..c6dc92b8 100644 --- a/eek/eek-keyboard.h +++ b/eek/eek-keyboard.h @@ -24,6 +24,7 @@ #include "eek-container.h" #include "eek-types.h" #include "eek-layout.h" +#include "eek-keysym.h" G_BEGIN_DECLS @@ -75,6 +76,10 @@ struct _EekKeyboardClass guint keycode); /* signals */ + void (* key_pressed) (EekKeyboard *self, + EekKey *key); + void (* key_released) (EekKeyboard *self, + EekKey *key); void (* keysym_index_changed) (EekKeyboard *self, gint group, gint level); @@ -84,33 +89,52 @@ struct _EekKeyboardClass gpointer pdummy[23]; }; -GType eek_keyboard_get_type (void) G_GNUC_CONST; +GType eek_keyboard_get_type + (void) G_GNUC_CONST; -EekKeyboard *eek_keyboard_new (EekLayout *layout, - gdouble initial_width, - gdouble initial_height); -EekLayout *eek_keyboard_get_layout (EekKeyboard *keyboard); -void eek_keyboard_get_size (EekKeyboard *keyboard, - gdouble *width, - gdouble *height); -void eek_keyboard_set_keysym_index (EekKeyboard *keyboard, - gint group, - gint level); -void eek_keyboard_get_keysym_index (EekKeyboard *keyboard, - gint *group, - gint *level); +EekKeyboard *eek_keyboard_new (EekLayout *layout, + gdouble initial_width, + gdouble initial_height); +EekLayout *eek_keyboard_get_layout + (EekKeyboard *keyboard); +void eek_keyboard_get_size + (EekKeyboard *keyboard, + gdouble *width, + gdouble *height); +void eek_keyboard_set_keysym_index + (EekKeyboard *keyboard, + gint group, + gint level); +void eek_keyboard_get_keysym_index + (EekKeyboard *keyboard, + gint *group, + gint *level); -void eek_keyboard_set_group (EekKeyboard *keyboard, - gint group); -void eek_keyboard_set_level (EekKeyboard *keyboard, - gint level); -gint eek_keyboard_get_group (EekKeyboard *keyboard); -gint eek_keyboard_get_level (EekKeyboard *keyboard); +void eek_keyboard_set_group + (EekKeyboard *keyboard, + gint group); +void eek_keyboard_set_level + (EekKeyboard *keyboard, + gint level); +gint eek_keyboard_get_group + (EekKeyboard *keyboard); +gint eek_keyboard_get_level + (EekKeyboard *keyboard); -EekSection *eek_keyboard_create_section (EekKeyboard *keyboard); +void eek_keyboard_set_modifier_behavior + (EekKeyboard *keyboard, + EekModifierBehavior modifier_behavior); +EekModifierBehavior eek_keyboard_get_modifier_behavior + (EekKeyboard *keyboard); +EekModifierType eek_keyboard_get_modifiers + (EekKeyboard *keyboard); -EekKey *eek_keyboard_find_key_by_keycode (EekKeyboard *keyboard, - guint keycode); +EekSection *eek_keyboard_create_section + (EekKeyboard *keyboard); + +EekKey *eek_keyboard_find_key_by_keycode + (EekKeyboard *keyboard, + guint keycode); G_END_DECLS #endif /* EEK_KEYBOARD_H */ diff --git a/eek/eek-keysym.c b/eek/eek-keysym.c index 678e8a86..791469d2 100644 --- a/eek/eek-keysym.c +++ b/eek/eek-keysym.c @@ -169,3 +169,33 @@ eek_keysym_get_category (guint keysym) return category; return EEK_KEYSYM_CATEGORY_UNKNOWN; } + +EekModifierType +eek_keysym_to_modifier (guint keysym) +{ + switch (keysym) { + case EEK_KEY_Shift_L: + case EEK_KEY_Shift_R: + case EEK_KEY_Caps_Lock: + case EEK_KEY_Shift_Lock: + return EEK_SHIFT_MASK; + case EEK_KEY_ISO_Level3_Shift: + return EEK_MOD5_MASK; + case EEK_KEY_Control_L: + case EEK_KEY_Control_R: + return EEK_CONTROL_MASK; + case EEK_KEY_Alt_L: + case EEK_KEY_Alt_R: + return EEK_MOD1_MASK; + case EEK_KEY_Meta_L: + case EEK_KEY_Meta_R: + return EEK_META_MASK; + case EEK_KEY_Super_L: + case EEK_KEY_Super_R: + return EEK_SUPER_MASK; + case EEK_KEY_Hyper_L: + case EEK_KEY_Hyper_R: + return EEK_HYPER_MASK; + } + return 0; +} diff --git a/eek/eek-keysym.h b/eek/eek-keysym.h index ba1425fe..b591264a 100644 --- a/eek/eek-keysym.h +++ b/eek/eek-keysym.h @@ -58,4 +58,52 @@ typedef enum { gchar *eek_keysym_to_string (guint keysym); EekKeysymCategory eek_keysym_get_category (guint keysym); +typedef enum +{ + EEK_SHIFT_MASK = 1 << 0, + EEK_LOCK_MASK = 1 << 1, + EEK_CONTROL_MASK = 1 << 2, + EEK_MOD1_MASK = 1 << 3, + EEK_MOD2_MASK = 1 << 4, + EEK_MOD3_MASK = 1 << 5, + EEK_MOD4_MASK = 1 << 6, + EEK_MOD5_MASK = 1 << 7, + EEK_BUTTON1_MASK = 1 << 8, + EEK_BUTTON2_MASK = 1 << 9, + EEK_BUTTON3_MASK = 1 << 10, + EEK_BUTTON4_MASK = 1 << 11, + EEK_BUTTON5_MASK = 1 << 12, + + /* The next few modifiers are used by XKB, so we skip to the end. + * Bits 15 - 25 are currently unused. Bit 29 is used internally. + */ + + EEK_SUPER_MASK = 1 << 26, + EEK_HYPER_MASK = 1 << 27, + EEK_META_MASK = 1 << 28, + + EEK_RELEASE_MASK = 1 << 30, + + EEK_MODIFIER_MASK = 0x5c001fff +} EekModifierType; + +#define EEK_KEY_Shift_L 0xffe1 +#define EEK_KEY_Shift_R 0xffe2 +#define EEK_KEY_ISO_Level3_Shift 0xfe03 +#define EEK_KEY_Caps_Lock 0xffe5 +#define EEK_KEY_Shift_Lock 0xffe6 +#define EEK_KEY_Control_L 0xffe3 +#define EEK_KEY_Control_R 0xffe4 +#define EEK_KEY_Alt_L 0xffe9 +#define EEK_KEY_Alt_R 0xffea +#define EEK_KEY_Meta_L 0xffe7 +#define EEK_KEY_Meta_R 0xffe8 +#define EEK_KEY_Super_L 0xffeb +#define EEK_KEY_Super_R 0xffec +#define EEK_KEY_Hyper_L 0xffed +#define EEK_KEY_Hyper_R 0xffee + +EekModifierType eek_keysym_to_modifier (guint keysym); +#define eek_keysym_is_modifier(keysym) (eek_keysym_to_modifier ((keysym)) != 0) + #endif /* EEK_KEYSYM_H */ diff --git a/eek/eek-types.h b/eek/eek-types.h index 48c665ae..bef6f9f8 100644 --- a/eek/eek-types.h +++ b/eek/eek-types.h @@ -46,6 +46,22 @@ typedef enum { EEK_ORIENTATION_INVALID = -1 } EekOrientation; +/** + * EekModifierBehavior: + * @EEK_MODIFIER_BEHAVIOR_NONE: do nothing when a modifier key is pressed + * @EEK_MODIFIER_BEHAVIOR_LOCK: toggle the modifier status each time a + * modifier key are pressed + * @EEK_MODIFIER_BEHAVIOR_LATCH: enable the modifier when a modifier + * key is pressed and keep it enabled until any key is pressed. + * + * Modifier handling mode. + */ +typedef enum { + EEK_MODIFIER_BEHAVIOR_NONE, + EEK_MODIFIER_BEHAVIOR_LOCK, + EEK_MODIFIER_BEHAVIOR_LATCH +} EekModifierBehavior; + typedef struct _EekElement EekElement; typedef struct _EekContainer EekContainer; typedef struct _EekKey EekKey; diff --git a/src/eekboard.c b/src/eekboard.c index 8b137184..e623c5b4 100644 --- a/src/eekboard.c +++ b/src/eekboard.c @@ -104,7 +104,6 @@ struct _Eekboard { EekKeyboard *keyboard; EekLayout *layout; /* FIXME: eek_keyboard_get_layout() */ - guint modifiers; }; typedef struct _Eekboard Eekboard; @@ -432,44 +431,17 @@ on_key_pressed (EekKeyboard *keyboard, gpointer user_data) { Eekboard *eekboard = user_data; - gint group, level; guint keysym; keysym = eek_key_get_keysym (key); - EEKBOARD_NOTE("%s %X", eek_keysym_to_string (keysym), eekboard->modifiers); + EEKBOARD_NOTE("%s %X", + eek_keysym_to_string (keysym), + eek_keyboard_get_modifiers (keyboard)); - switch (keysym) { - case XK_Shift_L: - case XK_Shift_R: - eekboard->modifiers ^= ShiftMask; - eek_keyboard_get_keysym_index (keyboard, &group, &level); - eek_keyboard_set_keysym_index (keyboard, group, - (eekboard->modifiers & Mod5Mask) ? 2 : - (eekboard->modifiers & ShiftMask) ? 1 : - 0); - break; - case XK_ISO_Level3_Shift: - eekboard->modifiers ^= Mod5Mask; - eek_keyboard_get_keysym_index (keyboard, &group, &level); - eek_keyboard_set_keysym_index (keyboard, group, - (eekboard->modifiers & Mod5Mask) ? 2 : - (eekboard->modifiers & ShiftMask) ? 1 : - 0); - break; - case XK_Control_L: - case XK_Control_R: - eekboard->modifiers ^= ControlMask; - break; - case XK_Alt_L: - case XK_Alt_R: - eekboard->modifiers ^= Mod1Mask; - break; - default: - fakekey_press_keysym (eekboard->fakekey, keysym, eekboard->modifiers); - eekboard->modifiers = 0; - eek_keyboard_get_keysym_index (keyboard, &group, &level); - eek_keyboard_set_keysym_index (keyboard, group, 0); - } + if (!eek_keysym_is_modifier (keysym)) + fakekey_press_keysym (eekboard->fakekey, + keysym, + eek_keyboard_get_modifiers (keyboard)); } static void @@ -1066,6 +1038,8 @@ create_widget (Eekboard *eekboard, eekboard->keyboard = eek_keyboard_new (eekboard->layout, initial_width, initial_height); + eek_keyboard_set_modifier_behavior (eekboard->keyboard, + EEK_MODIFIER_BEHAVIOR_LATCH); eekboard->on_key_pressed_id = g_signal_connect (eekboard->keyboard, "key-pressed", G_CALLBACK(on_key_pressed), eekboard);