From 0ab5a0f11443e29efaf790d66f3b33c84410369c Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Thu, 22 Jul 2010 17:33:43 +0900 Subject: [PATCH] Implement "Monitor Key Typing" using AT-SPI C. --- configure.ac | 2 + eek/eek-gtk-keyboard.c | 113 ++++++++++++++++++++++++++++++++--------- src/Makefile.am | 8 +-- src/eekboard.c | 61 ++++++++++++---------- 4 files changed, 132 insertions(+), 52 deletions(-) diff --git a/configure.ac b/configure.ac index 5d6a2c5e..0e08ebd2 100644 --- a/configure.ac +++ b/configure.ac @@ -41,6 +41,8 @@ PKG_CHECK_MODULES([LIBXKLAVIER], [libxklavier x11], , [AC_MSG_ERROR([Libxklavier not found])]) PKG_CHECK_MODULES([LIBFAKEKEY], [libfakekey], , [AC_MSG_ERROR([libfakekey not found])]) +PKG_CHECK_MODULES([CSPI], [cspi-1.0], , + [AC_MSG_ERROR([AT-SPI C not found])]) AC_MSG_CHECKING([whether you enable Vala language support]) AC_ARG_ENABLE(vala, diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c index 6315a961..aac8cb93 100644 --- a/eek/eek-gtk-keyboard.c +++ b/eek/eek-gtk-keyboard.c @@ -179,6 +179,9 @@ struct _DrawingContext }; typedef struct _DrawingContext DrawingContext; +static void on_key_pressed (EekKey *key, gpointer user_data); +static void on_key_released (EekKey *key, gpointer user_data); + static void prepare_keyboard_pixmap_key_callback (EekElement *element, gpointer user_data) @@ -193,6 +196,11 @@ prepare_keyboard_pixmap_key_callback (EekElement *element, eek_element_get_bounds (element, &bounds); + g_signal_connect (key, "pressed", G_CALLBACK(on_key_pressed), + context->keyboard); + g_signal_connect (key, "released", G_CALLBACK(on_key_released), + context->keyboard); + outline = eek_key_get_outline (key); texture = g_hash_table_lookup (priv->outline_textures, outline); if (!texture) { @@ -414,6 +422,71 @@ key_shrink (EekGtkKeyboard *keyboard, EekKey *key) bounds.height * SCALE * priv->scale); } +static void +on_key_pressed (EekKey *key, gpointer user_data) +{ + EekGtkKeyboard *keyboard = user_data; + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard); + + key_enlarge (EEK_GTK_KEYBOARD(keyboard), key); + priv->key = key; +} + +static void +on_key_released (EekKey *key, gpointer user_data) +{ + EekGtkKeyboard *keyboard = user_data; + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard); + + if (priv->key) + key_shrink (EEK_GTK_KEYBOARD(keyboard), EEK_KEY(priv->key)); + priv->key = NULL; +} + +static void +press_key (EekGtkKeyboard *keyboard, EekKey *key) +{ + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard); + if (priv->key != key) { + if (priv->key) + g_signal_emit_by_name (priv->key, "released", keyboard); + g_signal_emit_by_name (key, "pressed", keyboard); + } +} + +static void +release_key (EekGtkKeyboard *keyboard) +{ + EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard); + + if (priv->key) + g_signal_emit_by_name (priv->key, "released", keyboard); +} + +static gboolean +on_key_event (GtkWidget *widget, + GdkEventKey *event, + gpointer user_data) +{ + EekGtkKeyboard *keyboard = user_data; + EekKey *key; + + key = eek_keyboard_find_key_by_keycode (EEK_KEYBOARD(keyboard), + event->hardware_keycode); + if (!key) + return FALSE; + switch (event->type) { + case GDK_KEY_PRESS: + press_key (keyboard, key); + return TRUE; + case GDK_KEY_RELEASE: + release_key (keyboard); + return TRUE; + default: + return FALSE; + } +} + static gboolean on_button_event (GtkWidget *widget, GdkEventButton *event, @@ -434,29 +507,18 @@ on_button_event (GtkWidget *widget, key = eek_container_find_by_position (EEK_CONTAINER(section), x, y); - if (key) - switch (event->type) { - case GDK_BUTTON_PRESS: - if (priv->key == key) - return FALSE; - if (priv->key) { - key_shrink (EEK_GTK_KEYBOARD(keyboard), EEK_KEY(priv->key)); - g_signal_emit_by_name (keyboard, "key-released", priv->key); - } - key_enlarge (EEK_GTK_KEYBOARD(keyboard), EEK_KEY(key)); - g_signal_emit_by_name (keyboard, "key-pressed", key); - priv->key = key; - return TRUE; - case GDK_BUTTON_RELEASE: - if (!priv->key) - return FALSE; - key_shrink (EEK_GTK_KEYBOARD(keyboard), EEK_KEY(priv->key)); - g_signal_emit_by_name (keyboard, "key-released", priv->key); - priv->key = NULL; - return TRUE; - default: - return FALSE; - } + if (!key) + return FALSE; + switch (event->type) { + case GDK_BUTTON_PRESS: + press_key (EEK_GTK_KEYBOARD(keyboard), EEK_KEY(key)); + return TRUE; + case GDK_BUTTON_RELEASE: + release_key (EEK_GTK_KEYBOARD(keyboard)); + return TRUE; + default: + return FALSE; + } } return FALSE; } @@ -498,12 +560,17 @@ eek_gtk_keyboard_get_widget (EekGtkKeyboard *keyboard) gtk_widget_set_events (priv->widget, GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); g_signal_connect (priv->widget, "expose_event", G_CALLBACK (on_expose_event), keyboard); g_signal_connect (priv->widget, "size-allocate", G_CALLBACK (on_size_allocate), keyboard); + g_signal_connect (priv->widget, "key-press-event", + G_CALLBACK (on_key_event), keyboard); + g_signal_connect (priv->widget, "key-release-event", + G_CALLBACK (on_key_event), keyboard); g_signal_connect (priv->widget, "button-press-event", G_CALLBACK (on_button_event), keyboard); g_signal_connect (priv->widget, "button-release-event", diff --git a/src/Makefile.am b/src/Makefile.am index f9b100af..1a449b59 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,17 +24,19 @@ eekboard_CFLAGS = \ $(GTK2_CFLAGS) \ $(XKB_CFLAGS) \ $(LIBXKLAVIER_CFLAGS) \ - $(LIBFAKEKEY_CFLAGS) + $(LIBFAKEKEY_CFLAGS) \ + $(CSPI_CFLAGS) eekboard_LDFLAGS = \ $(top_builddir)/eek/libeek.la \ $(top_builddir)/eek/libeek-xkl.la \ $(top_builddir)/eek/libeek-gtk.la \ $(GOBJECT2_LIBS) \ - $(GTK2_CFLAGS) \ + $(GTK2_LIBS) \ $(XKB_LIBS) \ $(LIBXKLAVIER_LIBS) \ - $(LIBFAKEKEY_LIBS) + $(LIBFAKEKEY_LIBS) \ + $(CSPI_LIBS) if HAVE_CLUTTER eekboard_CFLAGS += $(CLUTTER_CFLAGS) $(CLUTTER_GTK_CFLAGS) diff --git a/src/eekboard.c b/src/eekboard.c index 213eb7d1..d42f0995 100644 --- a/src/eekboard.c +++ b/src/eekboard.c @@ -32,9 +32,7 @@ #include #include #include -#if 0 -#include -#endif +#include #include #include @@ -83,7 +81,6 @@ struct _Eekboard { FakeKey *fakekey; GtkWidget *widget; gint width, height; - guint key_event_listener; XklEngine *engine; XklConfigRegistry *registry; GtkUIManager *ui_manager; @@ -142,11 +139,9 @@ static void on_about (GtkAction *action, GtkWidget *window); static void on_quit (GtkAction * action, GtkWidget *window); -#if 0 static void on_monitor_key_event_toggled (GtkToggleAction *action, GtkWidget *window); -#endif static void eekboard_free (Eekboard *eekboard); static GtkWidget *create_widget (Eekboard *eekboard, gint initial_width, @@ -166,9 +161,7 @@ static const char ui_description[] = " " " " " " -#if 0 " " -#endif " " " " " " @@ -216,12 +209,10 @@ static const GtkActionEntry action_entry[] = { {"About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK (on_about)} }; -#if 0 static const GtkToggleActionEntry toggle_action_entry[] = { {"MonitorKeyEvent", NULL, N_("Monitor Key Typing"), NULL, NULL, G_CALLBACK(on_monitor_key_event_toggled), FALSE} }; -#endif static gchar *opt_model = NULL; static gchar *opt_layouts = NULL; @@ -280,32 +271,50 @@ on_quit (GtkAction * action, GtkWidget *window) gtk_main_quit (); } -#if 0 -static gint -key_snoop (AtkKeyEventStruct *event, gpointer func_data) +static SPIBoolean +keystroke_listener (const AccessibleKeystroke *stroke, + void *user_data) { - return FALSE; + Eekboard *eekboard = user_data; + EekKey *key; + + //g_return_val_if_fail (stroke->modifiers == SPI_KEYMASK_UNMODIFIED, FALSE); + key = eek_keyboard_find_key_by_keycode (eekboard->keyboard, + stroke->keycode); + g_return_val_if_fail (key, FALSE); + if (stroke->type == SPI_KEY_PRESSED) + g_signal_emit_by_name (key, "pressed"); + else + g_signal_emit_by_name (key, "released"); + return TRUE; } +static AccessibleEventListener* keystrokeListener; + static void on_monitor_key_event_toggled (GtkToggleAction *action, - GtkWidget *window) + GtkWidget *window) { Eekboard *eekboard = g_object_get_data (G_OBJECT(window), "eekboard"); + if (!keystrokeListener) { + keystrokeListener = + SPI_createAccessibleKeystrokeListener (keystroke_listener, + eekboard); + } if (gtk_toggle_action_get_active (action)) { - if (eekboard->key_event_listener == 0) - eekboard->key_event_listener = - atk_add_key_event_listener (key_snoop, eekboard); - g_warning ("failed to enable ATK key event listener"); + if (!SPI_registerAccessibleKeystrokeListener (keystrokeListener, + SPI_KEYSET_ALL_KEYS, + 0, + SPI_KEY_PRESSED | + SPI_KEY_RELEASED, + SPI_KEYLISTENER_NOSYNC)) + g_warning ("failed to register keystroke listener"); } else - if (eekboard->key_event_listener != 0) { - atk_remove_key_event_listener (eekboard->key_event_listener); - eekboard->key_event_listener = 0; - } + if (!SPI_deregisterAccessibleKeystrokeListener (keystrokeListener, 0)) + g_warning ("failed to deregister keystroke listener"); } -#endif static void on_key_pressed (EekKeyboard *keyboard, @@ -861,11 +870,9 @@ create_menus (Eekboard *eekboard, gtk_action_group_add_actions (action_group, action_entry, G_N_ELEMENTS (action_entry), window); -#if 0 gtk_action_group_add_toggle_actions (action_group, toggle_action_entry, G_N_ELEMENTS (toggle_action_entry), window); -#endif gtk_ui_manager_insert_action_group (eekboard->ui_manager, action_group, 0); gtk_ui_manager_add_ui_from_string (eekboard->ui_manager, ui_description, -1, NULL); @@ -1154,6 +1161,8 @@ main (int argc, char *argv[]) bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); #endif + SPI_init (); + env = g_getenv ("EEKBOARD_DISABLE_CLUTTER"); if (env && g_strcmp0 (env, "1") == 0) use_clutter = FALSE;