From a6bde78168d6cd16d3169de25aaa7076e1ed0fef Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Mon, 22 Aug 2011 14:07:20 +0900 Subject: [PATCH] Highlight locked modifiers. --- eek/eek-gtk-keyboard.c | 161 +++++++++++++++++++++++++----- eek/eek-key.c | 114 ++++++++++++++++++++++ eek/eek-key.h | 13 ++- eek/eek-keyboard.c | 215 +++++++++++++++++++++++++++++++++++++++-- eek/eek-keyboard.h | 39 ++++++-- eek/eek-renderer.c | 4 +- eek/eek-section.c | 90 +++++++++++++++++ eek/eek-section.h | 10 +- 8 files changed, 604 insertions(+), 42 deletions(-) diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c index e6da289b..8de188d9 100644 --- a/eek/eek-gtk-keyboard.c +++ b/eek/eek-gtk-keyboard.c @@ -61,9 +61,11 @@ struct _EekGtkKeyboardPrivate { EekRenderer *renderer; EekKeyboard *keyboard; - EekKey *dragged_key; gulong key_pressed_handler; gulong key_released_handler; + gulong key_locked_handler; + gulong key_unlocked_handler; + gulong key_cancelled_handler; gulong symbol_index_changed_handler; EekTheme *theme; }; @@ -75,12 +77,23 @@ static void on_key_pressed (EekKeyboard *keyboard, static void on_key_released (EekKeyboard *keyboard, EekKey *key, gpointer user_data); +static void on_key_locked (EekKeyboard *keyboard, + EekKey *key, + gpointer user_data); +static void on_key_unlocked (EekKeyboard *keyboard, + EekKey *key, + gpointer user_data); +static void on_key_cancelled (EekKeyboard *keyboard, + EekKey *key, + gpointer user_data); static void on_symbol_index_changed (EekKeyboard *keyboard, gint group, gint level, gpointer user_data); static void render_pressed_key (GtkWidget *widget, EekKey *key); +static void render_locked_key (GtkWidget *widget, + EekKey *key); static void render_released_key (GtkWidget *widget, EekKey *key); @@ -106,6 +119,7 @@ eek_gtk_keyboard_real_draw (GtkWidget *self, EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); GtkAllocation allocation; EekColor background; + GList *head; gtk_widget_get_allocation (self, &allocation); @@ -149,9 +163,17 @@ eek_gtk_keyboard_real_draw (GtkWidget *self, eek_renderer_render_keyboard (priv->renderer, cr); - /* redraw dragged key */ - if (priv->dragged_key) - render_pressed_key (self, priv->dragged_key); + /* redraw pressed key */ + head = eek_keyboard_get_pressed_keys (priv->keyboard); + for (; head; head = g_list_next (head)) { + render_pressed_key (self, head->data); + } + + /* redraw locked key */ + head = eek_keyboard_get_locked_keys (priv->keyboard); + for (; head; head = g_list_next (head)) { + render_locked_key (self, ((EekModifierKey *)head->data)->key); + } return FALSE; } @@ -197,10 +219,8 @@ eek_gtk_keyboard_real_button_press_event (GtkWidget *self, key = eek_renderer_find_key_by_position (priv->renderer, (gdouble)event->x, (gdouble)event->y); - if (key && key != priv->dragged_key) { - priv->dragged_key = key; + if (key) g_signal_emit_by_name (key, "pressed", priv->keyboard); - } return TRUE; } @@ -209,10 +229,11 @@ eek_gtk_keyboard_real_button_release_event (GtkWidget *self, GdkEventButton *event) { EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); + GList *head; - if (priv->dragged_key) { - g_signal_emit_by_name (priv->dragged_key, "released", priv->keyboard); - priv->dragged_key = NULL; + head = eek_keyboard_get_pressed_keys (priv->keyboard); + for (; head; head = g_list_next (head)) { + g_signal_emit_by_name (head->data, "released", priv->keyboard); } return TRUE; } @@ -227,11 +248,17 @@ eek_gtk_keyboard_real_motion_notify_event (GtkWidget *self, key = eek_renderer_find_key_by_position (priv->renderer, (gdouble)event->x, (gdouble)event->y); - if (key && key != priv->dragged_key) { - if (priv->dragged_key) - render_released_key (GTK_WIDGET(self), priv->dragged_key); - priv->dragged_key = key; - g_signal_emit_by_name (key, "pressed", priv->keyboard); + if (key) { + GList *head = eek_keyboard_get_pressed_keys (priv->keyboard); + gboolean found = FALSE; + for (; head; head = g_list_next (head)) { + if (head->data == key) + found = TRUE; + else + g_signal_emit_by_name (head->data, "cancelled", priv->keyboard); + } + if (!found) + g_signal_emit_by_name (key, "pressed", priv->keyboard); } return TRUE; } @@ -241,10 +268,15 @@ eek_gtk_keyboard_real_unmap (GtkWidget *self) { EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self); - if (priv->dragged_key) { - g_signal_emit_by_name (priv->dragged_key, "released", priv->keyboard); - priv->dragged_key = NULL; + if (priv->keyboard) { + GList *head; + + head = eek_keyboard_get_pressed_keys (priv->keyboard); + for (; head; head = g_list_next (head)) { + g_signal_emit_by_name (head->data, "released", priv->keyboard); + } } + GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->unmap (self); } @@ -261,6 +293,15 @@ eek_gtk_keyboard_set_keyboard (EekGtkKeyboard *self, priv->key_released_handler = g_signal_connect (priv->keyboard, "key-released", G_CALLBACK(on_key_released), self); + priv->key_locked_handler = + g_signal_connect (priv->keyboard, "key-locked", + G_CALLBACK(on_key_locked), self); + priv->key_unlocked_handler = + g_signal_connect (priv->keyboard, "key-unlocked", + G_CALLBACK(on_key_unlocked), self); + priv->key_cancelled_handler = + g_signal_connect (priv->keyboard, "key-cancelled", + G_CALLBACK(on_key_cancelled), self); priv->symbol_index_changed_handler = g_signal_connect (priv->keyboard, "symbol-index-changed", G_CALLBACK(on_symbol_index_changed), self); @@ -306,16 +347,28 @@ eek_gtk_keyboard_dispose (GObject *object) priv->key_released_handler)) g_signal_handler_disconnect (priv->keyboard, priv->key_released_handler); + if (g_signal_handler_is_connected (priv->keyboard, + priv->key_locked_handler)) + g_signal_handler_disconnect (priv->keyboard, + priv->key_locked_handler); + if (g_signal_handler_is_connected (priv->keyboard, + priv->key_unlocked_handler)) + g_signal_handler_disconnect (priv->keyboard, + priv->key_unlocked_handler); + if (g_signal_handler_is_connected (priv->keyboard, + priv->key_cancelled_handler)) + g_signal_handler_disconnect (priv->keyboard, + priv->key_cancelled_handler); if (g_signal_handler_is_connected (priv->keyboard, priv->symbol_index_changed_handler)) g_signal_handler_disconnect (priv->keyboard, priv->symbol_index_changed_handler); - if (priv->dragged_key) { - g_signal_emit_by_name (priv->dragged_key, - "released", - priv->keyboard); - priv->dragged_key = NULL; + GList *head; + + head = eek_keyboard_get_pressed_keys (priv->keyboard); + for (; head; head = g_list_next (head)) { + g_signal_emit_by_name (head->data, "released", priv->keyboard); } g_object_unref (priv->keyboard); @@ -445,6 +498,23 @@ render_pressed_key (GtkWidget *widget, cairo_destroy (cr); } +static void +render_locked_key (GtkWidget *widget, + EekKey *key) +{ + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget); + EekBounds bounds; + cairo_t *cr; + + cr = gdk_cairo_create (GDK_DRAWABLE (gtk_widget_get_window (widget))); + + eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE); + cairo_translate (cr, bounds.x, bounds.y); + eek_renderer_render_key (priv->renderer, cr, key, 1.0, TRUE); + + cairo_destroy (cr); +} + static void render_released_key (GtkWidget *widget, EekKey *key) @@ -519,6 +589,51 @@ on_key_released (EekKeyboard *keyboard, #endif } +static void +on_key_cancelled (EekKeyboard *keyboard, + EekKey *key, + gpointer user_data) +{ + GtkWidget *widget = user_data; + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget); + + /* renderer may have not been set yet if the widget is a popup */ + if (!priv->renderer) + return; + + render_released_key (widget, key); +} + +static void +on_key_locked (EekKeyboard *keyboard, + EekKey *key, + gpointer user_data) +{ + GtkWidget *widget = user_data; + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget); + + /* renderer may have not been set yet if the widget is a popup */ + if (!priv->renderer) + return; + + render_locked_key (widget, key); +} + +static void +on_key_unlocked (EekKeyboard *keyboard, + EekKey *key, + gpointer user_data) +{ + GtkWidget *widget = user_data; + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget); + + /* renderer may have not been set yet if the widget is a popup */ + if (!priv->renderer) + return; + + render_released_key (widget, key); +} + static void on_symbol_index_changed (EekKeyboard *keyboard, gint group, diff --git a/eek/eek-key.c b/eek/eek-key.c index 589e5923..db8ae747 100644 --- a/eek/eek-key.c +++ b/eek/eek-key.c @@ -53,6 +53,9 @@ enum { enum { PRESSED, RELEASED, + LOCKED, + UNLOCKED, + CANCELLED, LAST_SIGNAL }; @@ -72,6 +75,7 @@ struct _EekKeyPrivate gint row; gulong oref; gboolean is_pressed; + gboolean is_locked; }; static void @@ -151,6 +155,13 @@ eek_key_real_is_pressed (EekKey *self) return priv->is_pressed; } +static gboolean +eek_key_real_is_locked (EekKey *self) +{ + EekKeyPrivate *priv = EEK_KEY_GET_PRIVATE(self); + return priv->is_locked; +} + static void eek_key_real_pressed (EekKey *self) { @@ -173,6 +184,39 @@ eek_key_real_released (EekKey *self) #endif } +static void +eek_key_real_locked (EekKey *self) +{ + EekKeyPrivate *priv = EEK_KEY_GET_PRIVATE(self); + + priv->is_locked = TRUE; +#if DEBUG + g_debug ("locked %X", eek_key_get_keycode (self)); +#endif +} + +static void +eek_key_real_unlocked (EekKey *self) +{ + EekKeyPrivate *priv = EEK_KEY_GET_PRIVATE(self); + + priv->is_locked = FALSE; +#if DEBUG + g_debug ("unlocked %X", eek_key_get_keycode (self)); +#endif +} + +static void +eek_key_real_cancelled (EekKey *self) +{ + EekKeyPrivate *priv = EEK_KEY_GET_PRIVATE(self); + + priv->is_pressed = FALSE; +#if DEBUG + g_debug ("cancelled %X", eek_key_get_keycode (self)); +#endif +} + static void eek_key_finalize (GObject *object) { @@ -271,6 +315,7 @@ eek_key_class_init (EekKeyClass *klass) klass->set_oref = eek_key_real_set_oref; klass->get_oref = eek_key_real_get_oref; klass->is_pressed = eek_key_real_is_pressed; + klass->is_locked = eek_key_real_is_locked; gobject_class->set_property = eek_key_set_property; gobject_class->get_property = eek_key_get_property; @@ -279,6 +324,9 @@ eek_key_class_init (EekKeyClass *klass) /* signals */ klass->pressed = eek_key_real_pressed; klass->released = eek_key_real_released; + klass->locked = eek_key_real_locked; + klass->unlocked = eek_key_real_unlocked; + klass->cancelled = eek_key_real_cancelled; /** * EekKey:keycode: @@ -375,6 +423,59 @@ eek_key_class_init (EekKeyClass *klass) NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + + /** + * EekKey::locked: + * @key: an #EekKey + * + * The ::locked signal is emitted each time @key is shifted to + * the locked state. The class handler runs before signal + * handlers to allow signal handlers to read the status of @key + * with eek_key_is_locked(). + */ + signals[LOCKED] = + g_signal_new (I_("locked"), + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET(EekKeyClass, locked), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + /** + * EekKey::unlocked: + * @key: an #EekKey + * + * The ::unlocked signal is emitted each time @key is shifted to + * the unlocked state. + */ + signals[UNLOCKED] = + g_signal_new (I_("unlocked"), + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(EekKeyClass, unlocked), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + /** + * EekKey::cancelled: + * @key: an #EekKey + * + * The ::cancelled signal is emitted each time @key is shifted to + * the cancelled state. + */ + signals[CANCELLED] = + g_signal_new (I_("cancelled"), + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(EekKeyClass, cancelled), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } static void @@ -643,3 +744,16 @@ eek_key_is_pressed (EekKey *key) g_assert (EEK_IS_KEY(key)); return EEK_KEY_GET_CLASS(key)->is_pressed (key); } + +/** + * eek_key_is_locked: + * @key: an #EekKey + * + * Return %TRUE if key is marked as locked. + */ +gboolean +eek_key_is_locked (EekKey *key) +{ + g_assert (EEK_IS_KEY(key)); + return EEK_KEY_GET_CLASS(key)->is_locked (key); +} diff --git a/eek/eek-key.h b/eek/eek-key.h index 5be5aa8d..6c1a7e09 100644 --- a/eek/eek-key.h +++ b/eek/eek-key.h @@ -62,7 +62,10 @@ struct _EekKey * @get_oref: virtual function for getting outline id of the key * @pressed: class handler for #EekKey::pressed signal * @released: class handler for #EekKey::released signal + * @locked: class handler for #EekKey::locked signal + * @unlocked: class handler for #EekKey::unlocked signal * @is_pressed: virtual function for getting whether the key is pressed + * @is_locked: virtual function for getting whether the key is locked */ struct _EekKeyClass { @@ -90,13 +93,18 @@ struct _EekKeyClass gboolean (* is_pressed) (EekKey *self); - /* signals */ void (* pressed) (EekKey *key); void (* released) (EekKey *key); + gboolean (* is_locked) (EekKey *self); + + void (* locked) (EekKey *key); + void (* unlocked) (EekKey *key); + void (* cancelled) (EekKey *key); + /*< private >*/ /* padding */ - gpointer pdummy[24]; + gpointer pdummy[20]; }; GType eek_key_get_type (void) G_GNUC_CONST; @@ -130,6 +138,7 @@ void eek_key_set_oref (EekKey *key, gulong eek_key_get_oref (EekKey *key); gboolean eek_key_is_pressed (EekKey *key); +gboolean eek_key_is_locked (EekKey *key); G_END_DECLS #endif /* EEK_KEY_H */ diff --git a/eek/eek-keyboard.c b/eek/eek-keyboard.c index 0622cbc9..7c5f7ada 100644 --- a/eek/eek-keyboard.c +++ b/eek/eek-keyboard.c @@ -47,6 +47,9 @@ enum { enum { KEY_PRESSED, KEY_RELEASED, + KEY_LOCKED, + KEY_UNLOCKED, + KEY_CANCELLED, LAST_SIGNAL }; @@ -57,12 +60,13 @@ G_DEFINE_TYPE (EekKeyboard, eek_keyboard, EEK_TYPE_CONTAINER); #define EEK_KEYBOARD_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_KEYBOARD, EekKeyboardPrivate)) - struct _EekKeyboardPrivate { EekLayout *layout; EekModifierBehavior modifier_behavior; EekModifierType modifiers; + GList *pressed_keys; + GList *locked_keys; GArray *outline_array; /* modifiers dynamically assigned at run time */ @@ -86,6 +90,30 @@ on_key_released (EekSection *section, g_signal_emit_by_name (keyboard, "key-released", key); } +static void +on_key_locked (EekSection *section, + EekKey *key, + EekKeyboard *keyboard) +{ + g_signal_emit_by_name (keyboard, "key-locked", key); +} + +static void +on_key_unlocked (EekSection *section, + EekKey *key, + EekKeyboard *keyboard) +{ + g_signal_emit_by_name (keyboard, "key-unlocked", key); +} + +static void +on_key_cancelled (EekSection *section, + EekKey *key, + EekKeyboard *keyboard) +{ + g_signal_emit_by_name (keyboard, "key-cancelled", key); +} + static void on_symbol_index_changed (EekSection *section, gint group, @@ -203,6 +231,45 @@ set_level_from_modifiers (EekKeyboard *self) eek_element_set_level (EEK_ELEMENT(self), level); } +static void +set_modifiers_with_key (EekKeyboard *self, + EekKey *key, + EekModifierType modifiers) +{ + EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(self); + EekModifierType enabled = (priv->modifiers ^ modifiers) & modifiers; + EekModifierType disabled = (priv->modifiers ^ modifiers) & priv->modifiers; + + if (enabled != 0) { + if (priv->modifier_behavior != EEK_MODIFIER_BEHAVIOR_NONE) { + EekModifierKey *modifier_key = g_slice_new (EekModifierKey); + modifier_key->modifiers = enabled; + modifier_key->key = key; + priv->locked_keys = + g_list_prepend (priv->locked_keys, modifier_key); + g_signal_emit_by_name (modifier_key->key, "locked"); + } + } else { + if (priv->modifier_behavior != EEK_MODIFIER_BEHAVIOR_NONE) { + GList *head; + for (head = priv->locked_keys; head; ) { + EekModifierKey *modifier_key = head->data; + if (modifier_key->modifiers & disabled) { + GList *next = g_list_next (head); + priv->locked_keys = + g_list_remove_link (priv->locked_keys, head); + g_signal_emit_by_name (modifier_key->key, "unlocked"); + g_list_free1 (head); + head = next; + } else + head = g_list_next (head); + } + } + } + + priv->modifiers = modifiers; +} + static void eek_keyboard_real_key_pressed (EekKeyboard *self, EekKey *key) @@ -211,13 +278,15 @@ eek_keyboard_real_key_pressed (EekKeyboard *self, EekSymbol *symbol; EekModifierType modifier; + priv->pressed_keys = g_list_prepend (priv->pressed_keys, key); + symbol = eek_key_get_symbol_with_fallback (key, 0, 0); if (!symbol) return; modifier = eek_symbol_get_modifier_mask (symbol); if (priv->modifier_behavior == EEK_MODIFIER_BEHAVIOR_NONE) { - priv->modifiers |= modifier; + set_modifiers_with_key (self, key, priv->modifiers | modifier); set_level_from_modifiers (self); } } @@ -230,6 +299,8 @@ eek_keyboard_real_key_released (EekKeyboard *self, EekSymbol *symbol; EekModifierType modifier; + EEK_KEYBOARD_GET_CLASS (self)->key_cancelled (self, key); + symbol = eek_key_get_symbol_with_fallback (key, 0, 0); if (!symbol) return; @@ -237,21 +308,42 @@ eek_keyboard_real_key_released (EekKeyboard *self, modifier = eek_symbol_get_modifier_mask (symbol); switch (priv->modifier_behavior) { case EEK_MODIFIER_BEHAVIOR_NONE: - priv->modifiers &= ~modifier; + set_modifiers_with_key (self, key, priv->modifiers & ~modifier); break; case EEK_MODIFIER_BEHAVIOR_LOCK: priv->modifiers ^= modifier; break; case EEK_MODIFIER_BEHAVIOR_LATCH: - if (modifier == priv->alt_gr_mask || modifier == EEK_SHIFT_MASK) - priv->modifiers ^= modifier; + if (modifier) + set_modifiers_with_key (self, key, priv->modifiers ^ modifier); else - priv->modifiers = (priv->modifiers ^ modifier) & modifier; + set_modifiers_with_key (self, key, + (priv->modifiers ^ modifier) & modifier); break; } set_level_from_modifiers (self); } +static void +eek_keyboard_real_key_cancelled (EekKeyboard *self, + EekKey *key) +{ + EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(self); + GList *head; + + for (head = priv->pressed_keys; head; ) { + EekKey *pressed_key = head->data; + if (pressed_key == key) { + GList *next = g_list_next (head); + priv->pressed_keys = + g_list_remove_link (priv->pressed_keys, head); + g_list_free1 (head); + head = next; + } else + head = g_list_next (head); + } +} + static void eek_keyboard_dispose (GObject *object) { @@ -271,6 +363,9 @@ eek_keyboard_finalize (GObject *object) EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(object); gint i; + g_list_free (priv->pressed_keys); + g_list_free (priv->locked_keys); + for (i = 0; i < priv->outline_array->len; i++) { EekOutline *outline = &g_array_index (priv->outline_array, EekOutline, @@ -291,6 +386,12 @@ eek_keyboard_real_child_added (EekContainer *self, G_CALLBACK(on_key_pressed), self); g_signal_connect (element, "key-released", G_CALLBACK(on_key_released), self); + g_signal_connect (element, "key-locked", + G_CALLBACK(on_key_locked), self); + g_signal_connect (element, "key-unlocked", + G_CALLBACK(on_key_unlocked), self); + g_signal_connect (element, "key-cancelled", + G_CALLBACK(on_key_cancelled), self); g_signal_connect (element, "symbol-index-changed", G_CALLBACK(on_symbol_index_changed), self); } @@ -301,6 +402,9 @@ eek_keyboard_real_child_removed (EekContainer *self, { g_signal_handlers_disconnect_by_func (element, on_key_pressed, self); g_signal_handlers_disconnect_by_func (element, on_key_released, self); + g_signal_handlers_disconnect_by_func (element, on_key_locked, self); + g_signal_handlers_disconnect_by_func (element, on_key_unlocked, self); + g_signal_handlers_disconnect_by_func (element, on_key_cancelled, self); } static void @@ -319,6 +423,7 @@ eek_keyboard_class_init (EekKeyboardClass *klass) /* signals */ klass->key_pressed = eek_keyboard_real_key_pressed; klass->key_released = eek_keyboard_real_key_released; + klass->key_cancelled = eek_keyboard_real_key_cancelled; container_class->child_added = eek_keyboard_real_child_added; container_class->child_removed = eek_keyboard_real_child_removed; @@ -396,6 +501,66 @@ eek_keyboard_class_init (EekKeyboardClass *klass) G_TYPE_NONE, 1, EEK_TYPE_KEY); + + /** + * EekKeyboard::key-locked: + * @keyboard: an #EekKeyboard + * @key: an #EekKey + * + * The ::key-locked signal is emitted each time a key in @keyboard + * is shifted to the locked state. + */ + signals[KEY_LOCKED] = + g_signal_new (I_("key-locked"), + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(EekKeyboardClass, key_locked), + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + EEK_TYPE_KEY); + + /** + * EekKeyboard::key-unlocked: + * @keyboard: an #EekKeyboard + * @key: an #EekKey + * + * The ::key-unlocked signal is emitted each time a key in @keyboard + * is shifted to the unlocked state. + */ + signals[KEY_UNLOCKED] = + g_signal_new (I_("key-unlocked"), + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(EekKeyboardClass, key_unlocked), + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + EEK_TYPE_KEY); + + /** + * EekKeyboard::key-cancelled: + * @keyboard: an #EekKeyboard + * @key: an #EekKey + * + * The ::key-cancelled signal is emitted each time a key in @keyboard + * is shifted to the cancelled state. + */ + signals[KEY_CANCELLED] = + g_signal_new (I_("key-cancelled"), + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(EekKeyboardClass, key_cancelled), + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + EEK_TYPE_KEY); } static void @@ -778,3 +943,41 @@ eek_keyboard_get_alt_gr_mask (EekKeyboard *keyboard) return priv->alt_gr_mask; } + +/** + * eek_keyboard_get_pressed_keys: + * @keyboard: an #EekKeyboard + * + * Get pressed keys. + * Returns: (transfer container) (element-type EekModifierKey): A list + * of pressed keys. + */ +GList * +eek_keyboard_get_pressed_keys (EekKeyboard *keyboard) +{ + EekKeyboardPrivate *priv; + + g_assert (EEK_IS_KEYBOARD(keyboard)); + priv = EEK_KEYBOARD_GET_PRIVATE(keyboard); + + return priv->pressed_keys; +} + +/** + * eek_keyboard_get_locked_keys: + * @keyboard: an #EekKeyboard + * + * Get locked keys. + * Returns: (transfer container) (element-type EekModifierKey): A list + * of locked keys. + */ +GList * +eek_keyboard_get_locked_keys (EekKeyboard *keyboard) +{ + EekKeyboardPrivate *priv; + + g_assert (EEK_IS_KEYBOARD(keyboard)); + priv = EEK_KEYBOARD_GET_PRIVATE(keyboard); + + return priv->locked_keys; +} diff --git a/eek/eek-keyboard.h b/eek/eek-keyboard.h index 3c521730..569865c6 100644 --- a/eek/eek-keyboard.h +++ b/eek/eek-keyboard.h @@ -63,6 +63,8 @@ struct _EekKeyboard * keyboard by keycode * @key_pressed: class handler for #EekKeyboard::key-pressed signal * @key_released: class handler for #EekKeyboard::key-released signal + * @key_locked: class handler for #EekKeyboard::key-locked signal + * @key_unlocked: class handler for #EekKeyboard::key-unlocked signal */ struct _EekKeyboardClass { @@ -74,25 +76,41 @@ struct _EekKeyboardClass gpointer get_symbol_index; /*< public >*/ - EekSection *(* create_section) (EekKeyboard *self); + EekSection *(* create_section) (EekKeyboard *self); - EekKey *(* find_key_by_keycode) (EekKeyboard *self, - guint keycode); + EekKey *(* find_key_by_keycode) (EekKeyboard *self, + guint keycode); /* signals */ - void (* key_pressed) (EekKeyboard *self, - EekKey *key); - void (* key_released) (EekKeyboard *self, - EekKey *key); + void (* key_pressed) (EekKeyboard *self, + EekKey *key); + void (* key_released) (EekKeyboard *self, + EekKey *key); /*< private >*/ /* obsolete members moved to EekElement */ gpointer symbol_index_changed; + /*< public >*/ + /* signals */ + void (* key_locked) (EekKeyboard *self, + EekKey *key); + void (* key_unlocked) (EekKeyboard *self, + EekKey *key); + void (* key_cancelled) (EekKeyboard *self, + EekKey *key); + + /*< private >*/ /* padding */ - gpointer pdummy[24]; + gpointer pdummy[21]; }; +struct _EekModifierKey { + EekModifierType modifiers; + EekKey *key; +}; +typedef struct _EekModifierKey EekModifierKey; + GType eek_keyboard_get_type (void) G_GNUC_CONST; @@ -168,5 +186,10 @@ void eek_keyboard_set_alt_gr_mask EekModifierType eek_keyboard_get_alt_gr_mask (EekKeyboard *keyboard); +GList *eek_keyboard_get_pressed_keys + (EekKeyboard *keyboard); +GList *eek_keyboard_get_locked_keys + (EekKeyboard *keyboard); + G_END_DECLS #endif /* EEK_KEYBOARD_H */ diff --git a/eek/eek-renderer.c b/eek/eek-renderer.c index 6fc0cbb8..c7592167 100644 --- a/eek/eek-renderer.c +++ b/eek/eek-renderer.c @@ -632,7 +632,7 @@ eek_renderer_real_render_key_outline (EekRenderer *self, { cairo_save (cr); eek_renderer_apply_transformation_for_key (self, cr, key, scale, rotate); - render_key_outline (self, cr, key, eek_key_is_pressed (key)); + render_key_outline (self, cr, key, eek_key_is_pressed (key) || eek_key_is_locked (key)); cairo_restore (cr); } @@ -645,7 +645,7 @@ eek_renderer_real_render_key (EekRenderer *self, { cairo_save (cr); eek_renderer_apply_transformation_for_key (self, cr, key, scale, rotate); - render_key (self, cr, key, eek_key_is_pressed (key)); + render_key (self, cr, key, eek_key_is_pressed (key) || eek_key_is_locked (key)); cairo_restore (cr); } diff --git a/eek/eek-section.c b/eek/eek-section.c index c42941a1..465abe22 100644 --- a/eek/eek-section.c +++ b/eek/eek-section.c @@ -47,6 +47,9 @@ enum { enum { KEY_PRESSED, KEY_RELEASED, + KEY_LOCKED, + KEY_UNLOCKED, + KEY_CANCELLED, LAST_SIGNAL }; @@ -144,6 +147,27 @@ on_released (EekKey *key, g_signal_emit_by_name (section, "key-released", key); } +static void +on_locked (EekKey *key, + EekSection *section) +{ + g_signal_emit_by_name (section, "key-locked", key); +} + +static void +on_unlocked (EekKey *key, + EekSection *section) +{ + g_signal_emit_by_name (section, "key-unlocked", key); +} + +static void +on_cancelled (EekKey *key, + EekSection *section) +{ + g_signal_emit_by_name (section, "key-cancelled", key); +} + static EekKey * eek_section_real_create_key (EekSection *self, gint column, @@ -310,6 +334,9 @@ eek_section_real_child_added (EekContainer *self, { g_signal_connect (element, "pressed", G_CALLBACK(on_pressed), self); g_signal_connect (element, "released", G_CALLBACK(on_released), self); + g_signal_connect (element, "locked", G_CALLBACK(on_locked), self); + g_signal_connect (element, "unlocked", G_CALLBACK(on_unlocked), self); + g_signal_connect (element, "cancelled", G_CALLBACK(on_cancelled), self); } static void @@ -318,6 +345,9 @@ eek_section_real_child_removed (EekContainer *self, { g_signal_handlers_disconnect_by_func (element, on_pressed, self); g_signal_handlers_disconnect_by_func (element, on_released, self); + g_signal_handlers_disconnect_by_func (element, on_locked, self); + g_signal_handlers_disconnect_by_func (element, on_unlocked, self); + g_signal_handlers_disconnect_by_func (element, on_cancelled, self); } static void @@ -401,6 +431,66 @@ eek_section_class_init (EekSectionClass *klass) G_TYPE_NONE, 1, EEK_TYPE_KEY); + + /** + * EekSection::key-locked: + * @section: an #EekSection + * @key: an #EekKey + * + * The ::key-locked signal is emitted each time a key in @section + * is shifted to the locked state. + */ + signals[KEY_LOCKED] = + g_signal_new (I_("key-locked"), + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(EekSectionClass, key_locked), + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + EEK_TYPE_KEY); + + /** + * EekSection::key-unlocked: + * @section: an #EekSection + * @key: an #EekKey + * + * The ::key-unlocked signal is emitted each time a key in @section + * is shifted to the unlocked state. + */ + signals[KEY_UNLOCKED] = + g_signal_new (I_("key-unlocked"), + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(EekSectionClass, key_unlocked), + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + EEK_TYPE_KEY); + + /** + * EekSection::key-cancelled: + * @section: an #EekSection + * @key: an #EekKey + * + * The ::key-cancelled signal is emitted each time a key in @section + * is shifted to the cancelled state. + */ + signals[KEY_CANCELLED] = + g_signal_new (I_("key-cancelled"), + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(EekSectionClass, key_cancelled), + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + EEK_TYPE_KEY); } static void diff --git a/eek/eek-section.h b/eek/eek-section.h index 316be873..1ee33751 100644 --- a/eek/eek-section.h +++ b/eek/eek-section.h @@ -61,6 +61,8 @@ struct _EekSection * section by keycode * @key_pressed: class handler for #EekSection::key-pressed signal * @key_released: class handler for #EekSection::key-released signal + * @key_locked: class handler for #EekSection::key-locked signal + * @key_unlocked: class handler for #EekSection::key-unlocked signal */ struct _EekSectionClass { @@ -93,10 +95,16 @@ struct _EekSectionClass EekKey *key); void (* key_released) (EekSection *self, EekKey *key); + void (* key_locked) (EekSection *self, + EekKey *key); + void (* key_unlocked) (EekSection *self, + EekKey *key); + void (* key_cancelled) (EekSection *self, + EekKey *key); /*< private >*/ /* padding */ - gpointer pdummy[22]; + gpointer pdummy[19]; }; GType eek_section_get_type (void) G_GNUC_CONST;