Port modifier handling code from application into library.

This commit is contained in:
Daiki Ueno
2011-01-26 11:59:12 +09:00
parent 79986e47b6
commit 5e4a6b2c8e
7 changed files with 291 additions and 69 deletions

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;

View File

@ -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);