/* libke.c * * Copyright 2001 - 2005 Sun Microsystems, Inc., * Copyright 2001 - 2005 BAUM Retec, A.G. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #define XK_MISCELLANY #define XK_LATIN1 #include #include #include #include #include #include #include #include "libke.h" #include "sru-module.h" #define SRU_DEBUG_MODULE "kbd" /*#define SRU_DEBUG_SCOPES "keyboard:init:numpad:cursor:modifier:hit:mouse:command:grab:event:entry" */ #include "sru-debug.h" #define KE_LAYER_DEFAULT 0 #define KE_LAYER_TIMEOUT 5000 #define KE_LOG_AT_SPI_KEYBOARD_EVENT(scope) \ sru_debug_log (scope, \ "%s of keystring=\"%s\"\tkeycode=\"%d(0x%x)\"" \ "\tkeysym=\"%ld(0x%x)\" with \"%s\" modifier(s) at index: %d",\ ke_debug_return_at_spi_key_mask (key->type), key->keystring,\ (gint) key->keycode, (gint) key->keycode, \ (glong) key->keyID, (guint) key->keyID, \ ke_debug_return_at_spi_key_flags (key->modifiers), index); typedef SPIBoolean (*KEAccessibleKeystrokeListenerCB) (const AccessibleKeystroke *key, gint index); typedef long KEKeyFlag; typedef long KECount; /* FIXME start */ #define SPI_true TRUE #define SPI_false FALSE /* FIXME end */ typedef struct { KeySym keysym; KEKeyModifier modifier; }KEKeysymKeyModifier; static gboolean ke_keyboard_grabbing = FALSE; static gint ke_crt_layer = KE_LAYER_DEFAULT; static KECount ke_cnt_kbd_listeners = 0; static KECount ke_cnt_numpad_changes = 0; static KECallbacks ke_callbacks; static GArray *ke_commands_array = NULL; static AccessibleKeystrokeListener *kbd_listener = NULL; static AccessibleKeystrokeListener *ke_mouse_listener = NULL; SRU_MODULE_FLAG_DEFS(ke_module_flag); static SPIBoolean ke_try_report_at_spi_cursor_event (const AccessibleKeystroke *key, gint index); static SPIBoolean ke_try_report_at_spi_numpad_event (const AccessibleKeystroke *key, gint index); static SPIBoolean ke_try_report_at_spi_modifier_event (const AccessibleKeystroke *key, gint index); static SPIBoolean ke_try_report_at_spi_command_event (const AccessibleKeystroke *key, gint index); static SPIBoolean ke_try_report_at_spi_grab_event (const AccessibleKeystroke *key, gint index); static SPIBoolean ke_try_report_at_spi_hit_event (const AccessibleKeystroke *key, gint index); typedef struct { const AccessibleKeystrokeListener *listener; AccessibleKeyListenerSyncType sync_type; const AccessibleKeySet *acc_set; AccessibleKeyEventMask mask; KEKeyFlag flags; KEKeyFlag opt_flags; }KERegisterInfo; #define KE_HIT_FUNCTIONS \ { \ ke_try_report_at_spi_command_event, \ ke_try_report_at_spi_grab_event, \ ke_try_report_at_spi_hit_event, \ NULL \ } #define KE_MODIFIER_FUNCTIONS \ { \ ke_try_report_at_spi_command_event, \ ke_try_report_at_spi_grab_event, \ ke_try_report_at_spi_modifier_event, \ NULL \ } #define KE_CURSOR_FUNCTIONS \ { \ ke_try_report_at_spi_command_event, \ ke_try_report_at_spi_grab_event, \ ke_try_report_at_spi_hit_event, \ ke_try_report_at_spi_cursor_event, \ NULL \ } #define KE_NUMPAD_FUNCTIONS \ { \ ke_try_report_at_spi_numpad_event, \ NULL \ } #define KE_MAX_FUNCTIONS_NO 5 /* 5 = maximum size of defines above */ struct { KeySym keysym; gpointer data; KEAccessibleKeystrokeListenerCB process[KE_MAX_FUNCTIONS_NO]; }ke_keys_info[] = { { XK_a, N_("A"), KE_HIT_FUNCTIONS }, { XK_b, N_("B"), KE_HIT_FUNCTIONS }, { XK_c, N_("C"), KE_HIT_FUNCTIONS }, { XK_d, N_("D"), KE_HIT_FUNCTIONS }, { XK_e, N_("E"), KE_HIT_FUNCTIONS }, { XK_f, N_("F"), KE_HIT_FUNCTIONS }, { XK_g, N_("G"), KE_HIT_FUNCTIONS }, { XK_h, N_("H"), KE_HIT_FUNCTIONS }, { XK_i, N_("I"), KE_HIT_FUNCTIONS }, { XK_j, N_("J"), KE_HIT_FUNCTIONS }, { XK_k, N_("K"), KE_HIT_FUNCTIONS }, { XK_l, N_("L"), KE_HIT_FUNCTIONS }, { XK_m, N_("M"), KE_HIT_FUNCTIONS }, { XK_n, N_("N"), KE_HIT_FUNCTIONS }, { XK_o, N_("O"), KE_HIT_FUNCTIONS }, { XK_p, N_("P"), KE_HIT_FUNCTIONS }, { XK_q, N_("Q"), KE_HIT_FUNCTIONS }, { XK_r, N_("R"), KE_HIT_FUNCTIONS }, { XK_s, N_("S"), KE_HIT_FUNCTIONS }, { XK_t, N_("T"), KE_HIT_FUNCTIONS }, { XK_u, N_("U"), KE_HIT_FUNCTIONS }, { XK_v, N_("V"), KE_HIT_FUNCTIONS }, { XK_w, N_("W"), KE_HIT_FUNCTIONS }, { XK_x, N_("X"), KE_HIT_FUNCTIONS }, { XK_y, N_("Y"), KE_HIT_FUNCTIONS }, { XK_z, N_("Z"), KE_HIT_FUNCTIONS }, { XK_0, N_("0"), KE_HIT_FUNCTIONS }, { XK_1, N_("1"), KE_HIT_FUNCTIONS }, { XK_2, N_("2"), KE_HIT_FUNCTIONS }, { XK_3, N_("3"), KE_HIT_FUNCTIONS }, { XK_4, N_("4"), KE_HIT_FUNCTIONS }, { XK_5, N_("5"), KE_HIT_FUNCTIONS }, { XK_6, N_("6"), KE_HIT_FUNCTIONS }, { XK_7, N_("7"), KE_HIT_FUNCTIONS }, { XK_8, N_("8"), KE_HIT_FUNCTIONS }, { XK_9, N_("9"), KE_HIT_FUNCTIONS }, { XK_F1, N_("F1"), KE_HIT_FUNCTIONS }, { XK_F2, N_("F2"), KE_HIT_FUNCTIONS }, { XK_F3, N_("F3"), KE_HIT_FUNCTIONS }, { XK_F4, N_("F4"), KE_HIT_FUNCTIONS }, { XK_F5, N_("F5"), KE_HIT_FUNCTIONS }, { XK_F6, N_("F6"), KE_HIT_FUNCTIONS }, { XK_F7, N_("F7"), KE_HIT_FUNCTIONS }, { XK_F8, N_("F8"), KE_HIT_FUNCTIONS }, { XK_F9, N_("F9"), KE_HIT_FUNCTIONS }, { XK_F10, N_("F10"), KE_HIT_FUNCTIONS }, { XK_F11, N_("F11"), KE_HIT_FUNCTIONS }, { XK_F12, N_("F12"), KE_HIT_FUNCTIONS }, { XK_Super_L, N_("Window Left"), KE_MODIFIER_FUNCTIONS }, { XK_Super_R, N_("Window Right"), KE_MODIFIER_FUNCTIONS }, { XK_Alt_L, N_("Alt Left"), KE_MODIFIER_FUNCTIONS }, { XK_Alt_R, N_("Alt Right"), KE_MODIFIER_FUNCTIONS }, { XK_Shift_L, N_("Shift Left"), KE_MODIFIER_FUNCTIONS }, { XK_Shift_R, N_("Shift Right"), KE_MODIFIER_FUNCTIONS }, { XK_Control_L, N_("Control Left"), KE_MODIFIER_FUNCTIONS }, { XK_Control_R, N_("Control Right"), KE_MODIFIER_FUNCTIONS }, { XK_Caps_Lock, N_("CapsLock"), KE_MODIFIER_FUNCTIONS }, { XK_Num_Lock, N_("NumLock"), KE_MODIFIER_FUNCTIONS }, { XK_Home, N_("Home"), KE_CURSOR_FUNCTIONS }, { XK_End, N_("End"), KE_CURSOR_FUNCTIONS }, { XK_Left, N_("Left"), KE_CURSOR_FUNCTIONS }, { XK_Right, N_("Right"), KE_CURSOR_FUNCTIONS }, { XK_Up, N_("Up"), KE_CURSOR_FUNCTIONS }, { XK_Down, N_("Down"), KE_CURSOR_FUNCTIONS }, { XK_Page_Up, N_("Page Up"), KE_CURSOR_FUNCTIONS }, { XK_Page_Down, N_("Page Down"), KE_CURSOR_FUNCTIONS }, { XK_BackSpace, N_("BackSpace"), KE_CURSOR_FUNCTIONS }, { XK_Delete, N_("Delete"), KE_CURSOR_FUNCTIONS }, { XK_Escape, N_("Escape"), KE_CURSOR_FUNCTIONS }, { XK_KP_0, GINT_TO_POINTER (0), KE_NUMPAD_FUNCTIONS }, { XK_KP_1, GINT_TO_POINTER (1), KE_NUMPAD_FUNCTIONS }, { XK_KP_2, GINT_TO_POINTER (2), KE_NUMPAD_FUNCTIONS }, { XK_KP_3, GINT_TO_POINTER (3), KE_NUMPAD_FUNCTIONS }, { XK_KP_4, GINT_TO_POINTER (4), KE_NUMPAD_FUNCTIONS }, { XK_KP_5, GINT_TO_POINTER (5), KE_NUMPAD_FUNCTIONS }, { XK_KP_6, GINT_TO_POINTER (6), KE_NUMPAD_FUNCTIONS }, { XK_KP_7, GINT_TO_POINTER (7), KE_NUMPAD_FUNCTIONS }, { XK_KP_8, GINT_TO_POINTER (8), KE_NUMPAD_FUNCTIONS }, { XK_KP_9, GINT_TO_POINTER (9), KE_NUMPAD_FUNCTIONS }, { XK_KP_Decimal, GINT_TO_POINTER (10), KE_NUMPAD_FUNCTIONS }, { XK_KP_Separator, GINT_TO_POINTER (10), KE_NUMPAD_FUNCTIONS }, { XK_KP_Enter, GINT_TO_POINTER (11), KE_NUMPAD_FUNCTIONS }, { XK_KP_Add, GINT_TO_POINTER (12), KE_NUMPAD_FUNCTIONS }, { XK_KP_Subtract, GINT_TO_POINTER (13), KE_NUMPAD_FUNCTIONS }, { XK_KP_Multiply, GINT_TO_POINTER (14), KE_NUMPAD_FUNCTIONS }, { XK_KP_Divide, GINT_TO_POINTER (15), KE_NUMPAD_FUNCTIONS } }; #ifdef SR_DEBUG static gchar* ke_debug_return_key_event_from_key_action (KEKeyAction action) { struct { KEKeyAction action; gchar *name; }actions_names[] = { { KE_KEY_PRESSED, "PRESSED" }, { KE_KEY_RELEASED, "RELEASED" } }; gint i; for (i = 0; i < G_N_ELEMENTS (actions_names); i++) if (action == actions_names[i].action) { g_assert (actions_names[i].name); return actions_names[i].name; } return "NONE"; } static G_CONST_RETURN gchar* ke_debug_return_at_spi_key_mask (AccessibleKeyEventMask mask) { struct { AccessibleKeyEventMask mask; gchar *name; }masks_names[] = { { SPI_KEY_PRESSED, "PRESSED" }, { SPI_KEY_RELEASED, "RELEASED" } }; gint i; for (i = 0; i < G_N_ELEMENTS (masks_names); i++) if (mask == masks_names[i].mask) { g_assert (masks_names[i].name); return masks_names[i].name; } return "NONE"; } static G_CONST_RETURN gchar* ke_debug_return_at_spi_key_flags (KEKeyFlag flags) { struct { KEKeyFlag flag; gchar *name; }flags_names[] = { { SPI_KEYMASK_ALT, "ALT" }, { SPI_KEYMASK_CONTROL, "CTRL" }, { SPI_KEYMASK_SHIFT, "SHIFT" }, { SPI_KEYMASK_SHIFTLOCK, "CAPSLOCK" }, { SPI_KEYMASK_NUMLOCK, "NUMLOCK" } }; gint i; static gchar rv[200]; /* 200 = enough space for all flags names, delimitators etc */ gchar *crt = rv; gboolean first = TRUE; KEKeyFlag shown_flags = SPI_KEYMASK_UNMODIFIED; for (i = 0; i < G_N_ELEMENTS (flags_names); i++) if ((flags & flags_names[i].flag) == flags_names[i].flag) { g_assert (flags_names[i].name); shown_flags |= flags_names[i].flag; if (!first) crt = g_stpcpy (crt, " | "); first = FALSE; crt = g_stpcpy (crt, flags_names[i].name); } if ((flags & shown_flags) != flags) { if (!first) crt = g_stpcpy (crt, " | "); crt = g_stpcpy (crt, "OTHERS"); } if (crt == rv) strcpy (rv, "NONE"); return rv; } static G_CONST_RETURN gchar* ke_debug_return_ke_key_modifiers (KEKeyModifier modifiers) { struct { KEKeyModifier modifier; gchar *name; }modifiers_names[] = { { KE_MODIFIER_ALT, "ALT" }, { KE_MODIFIER_CONTROL, "CTRL" }, { KE_MODIFIER_SHIFT, "SHIFT" } }; gint i; static gchar rv[200]; /* 200 = enough space for all modifiers names, delimitators etc */ gchar *crt = rv; gboolean first = TRUE; KEKeyModifier shown_modifiers = KE_MODIFIER_UNMODIFIED; for (i = 0; i < G_N_ELEMENTS (modifiers_names); i++) if (modifiers & modifiers_names[i].modifier) { g_assert (modifiers_names[i].name); shown_modifiers |= modifiers_names[i].modifier; if (!first) crt = g_stpcpy (crt, " | "); first = FALSE; crt = g_stpcpy (crt, modifiers_names[i].name); } if ((modifiers & shown_modifiers) != modifiers) { if (!first) crt = g_stpcpy (crt, " | "); crt = g_stpcpy (crt, "OTHERS"); } if (crt == rv) strcpy (rv, "NONE"); return rv; } #endif static KEKeyModifier ke_get_ke_modifiers_from_at_spi_flags (KEKeyFlag flags) { KEKeyModifier modifiers = KE_MODIFIER_UNMODIFIED; if (flags & SPI_KEYMASK_ALT) modifiers |= KE_MODIFIER_ALT; if (flags & SPI_KEYMASK_CONTROL) modifiers |= KE_MODIFIER_CONTROL; if (flags & SPI_KEYMASK_SHIFT) modifiers |= KE_MODIFIER_SHIFT; return modifiers; } static KeySym ke_get_keysym_from_keys_info (const gchar *key) { gint i; g_assert (ke_keys_info); for (i = 0; i < G_N_ELEMENTS (ke_keys_info); i++) if (strcmp (ke_keys_info[i].data, key) == 0) return ke_keys_info[i].keysym; return NoSymbol; } static KeyCode ke_get_keycode_from_keysym (KeySym keysym) { static Display *display; KeyCode keycode = 0; if (!display) display = GDK_DISPLAY (); if (!display) g_printerr (_("Unable to get display\n")); else keycode = XKeysymToKeycode (display, keysym); sru_debug_log ("keyboard", "keysym:\"%ld\" has keycode:\"%d\"", keysym, keycode); return keycode; } static gint ke_get_key_index_for_keycode (KeyCode keycode) { gint i, rv = -1; static Display *display = NULL; if (!display) display = GDK_DISPLAY (); if (!display) g_printerr (_("Unable to get display\n")); else { for (i = 0; i < G_N_ELEMENTS (ke_keys_info); i++) if (keycode == XKeysymToKeycode (display, ke_keys_info[i].keysym)) { rv = i; break; } } sru_debug_log ("keyboard", "keycode:\"%d\" has index:\"%d\"", keycode, rv); return rv; } static KEKeyModifier ke_get_ke_action_from_at_spi_type (AccessibleDeviceEventType type) { if (type == SPI_KEY_PRESSED) return KE_KEY_PRESSED; else if (type == SPI_KEY_RELEASED) return KE_KEY_RELEASED; else g_assert_not_reached (); return KE_KEY_RELEASED; } static KECount ke_register_listeners (KERegisterInfo *info) { gint i, cnt; SPIBoolean retval; KEKeyFlag old_opt_flags; KEKeyFlag all_flags[] = { SPI_KEYMASK_ALT, SPI_KEYMASK_CONTROL, SPI_KEYMASK_SHIFT, SPI_KEYMASK_SHIFTLOCK, SPI_KEYMASK_NUMLOCK }; g_assert (info->listener); cnt = 0; retval = SPI_registerAccessibleKeystrokeListener( (AccessibleKeystrokeListener*)info->listener, (AccessibleKeySet*)info->acc_set, info->flags, info->mask, info->sync_type); if (retval) cnt = 1; /*FIXME is FALSE returned if registration fails only for some keys ???*/ /* FIXME else --- unref the listener???? */ sru_debug_log ("init", "\"%s\" with flags \"%s\"", retval ? "succeeded" : "failed", ke_debug_return_at_spi_key_flags (info->flags)); old_opt_flags = info->opt_flags; for (i = 0; i < G_N_ELEMENTS (all_flags); i++) { if (info->opt_flags & all_flags[i]) { KEKeyFlag old_flags = info->flags; g_assert ((info->opt_flags & all_flags[i]) == all_flags[i]); info->flags |= all_flags[i]; info->opt_flags = info->opt_flags & ~all_flags[i]; cnt += ke_register_listeners (info); info->flags = old_flags; } } g_assert (info->opt_flags == SPI_KEYMASK_UNMODIFIED); info->opt_flags = old_opt_flags; return cnt; } static void ke_report_layer_key (gint layer, gint key) { g_assert (ke_callbacks.layer_key); g_assert (0 <= layer && layer <= 15); g_assert (0 <= key && key <= 15); sru_debug_log ("numpad", "layer %02d key %02d", layer, key); ke_callbacks.layer_key (layer, key); } static void ke_report_layer_changed (gint layer) { g_assert (ke_callbacks.layer_ch); g_assert (0 <= layer && layer <= 15); ke_crt_layer = layer; sru_debug_log ("numpad", "layer changed %02d", ke_crt_layer); ke_callbacks.layer_ch (ke_crt_layer); } static void ke_report_layer_back () { g_assert (ke_callbacks.layer_back); g_assert (0 <= ke_crt_layer && ke_crt_layer <= 15); sru_debug_log ("numpad", "layer back %02d", ke_crt_layer); ke_callbacks.layer_back (ke_crt_layer); } static void ke_report_modifier (const gchar *modifier, KEKeyAction action) { g_assert (modifier && ke_callbacks.modifier); sru_debug_log ("modifier", "modifier \"%s\" was %s", modifier, ke_debug_return_key_event_from_key_action (action)); ke_callbacks.modifier (modifier, action); } static void ke_report_cursor (const gchar *cursor) { g_assert (cursor && ke_callbacks.cursor); sru_debug_log ("cursor", "cursor \"%s\"", cursor); ke_callbacks.cursor (cursor); } static void ke_report_keyboard_grab (const gchar *key, KEKeyModifier modifiers) { g_assert (key && ke_callbacks.grab); sru_debug_log ("grab", "key \"%s\" with modifiers %s", key, ke_debug_return_ke_key_modifiers (modifiers)); ke_callbacks.grab (key, modifiers); } static void ke_report_keyboard_hit () { g_assert (ke_callbacks.hit); sru_debug_log ("hit", "hit"); ke_callbacks.hit (); } static void ke_report_command (const gchar *key, KEKeyModifier modifiers) { g_assert (key && ke_callbacks.command); sru_debug_log ("command", "key \"%s\" with modifiers %s", key, ke_debug_return_ke_key_modifiers (modifiers)); ke_callbacks.command (key, modifiers); } static void ke_report_mouse_moved (gint x, gint y) { g_assert (ke_callbacks.mouse_move); sru_debug_log ("mouse", "mouse moved to (%d-%d)", x, y); ke_callbacks.mouse_move (x, y); } static void ke_report_at_spi_mouse_moved (const AccessibleEvent *event, void *data) { g_assert (event); ke_report_mouse_moved (event->detail1, event->detail2); } static SPIBoolean ke_report_at_spi_grab_event (const AccessibleKeystroke *key, gint index) { g_assert (key && key->keystring); g_assert (index >= 0 && index < G_N_ELEMENTS (ke_keys_info)); g_assert (ke_keys_info[index].data); KE_LOG_AT_SPI_KEYBOARD_EVENT ("grab"); if (key->type == SPI_KEY_PRESSED) ke_report_keyboard_grab (ke_keys_info[index].data, ke_get_ke_modifiers_from_at_spi_flags (key->modifiers)); return SPI_true; } static SPIBoolean ke_try_report_at_spi_grab_event (const AccessibleKeystroke *key, gint index) { if (ke_keyboard_grabbing) return ke_report_at_spi_grab_event (key, index); return SPI_false; } static SPIBoolean ke_report_at_spi_hit_event (const AccessibleKeystroke *key, gint index) { g_assert (key && key->keystring); KE_LOG_AT_SPI_KEYBOARD_EVENT ("hit"); if (key->type == SPI_KEY_PRESSED) ke_report_keyboard_hit (); return SPI_false; } static SPIBoolean ke_try_report_at_spi_hit_event (const AccessibleKeystroke *key, gint index) { return ke_report_at_spi_hit_event (key, index); } static SPIBoolean ke_report_at_spi_modifier_event (const AccessibleKeystroke *key, gint index) { g_assert (key && key->keystring); g_assert (index >= 0 && index < G_N_ELEMENTS (ke_keys_info)); g_assert (ke_keys_info[index].data); KE_LOG_AT_SPI_KEYBOARD_EVENT ("modifier"); if (key->type == SPI_KEY_PRESSED) ke_report_modifier (ke_keys_info[index].data, ke_get_ke_action_from_at_spi_type (key->type)); return SPI_false; } static SPIBoolean ke_try_report_at_spi_modifier_event (const AccessibleKeystroke *key, gint index) { return ke_report_at_spi_modifier_event (key, index); } static SPIBoolean ke_report_at_spi_cursor_event (const AccessibleKeystroke *key, gint index) { g_assert (key && key->keystring); g_assert (index >=0 && index < G_N_ELEMENTS (ke_keys_info)); g_assert (ke_keys_info[index].data); KE_LOG_AT_SPI_KEYBOARD_EVENT ("cursor"); if (key->type == SPI_KEY_PRESSED) ke_report_cursor (ke_keys_info[index].data); return SPI_false; } static SPIBoolean ke_try_report_at_spi_cursor_event (const AccessibleKeystroke *key, gint index) { return ke_report_at_spi_cursor_event (key, index); } static gboolean ke_layer_timeout (gpointer data) { if (ke_cnt_numpad_changes == GPOINTER_TO_INT (data)) /* is for last numpad event */ { ke_cnt_numpad_changes++; /* == (changing_layer = FALSE) */ ke_report_layer_back (); } return FALSE; } static SPIBoolean ke_report_at_spi_numpad_event (const AccessibleKeystroke *key, gint index) { gint position; g_assert (key && key->keystring); g_assert (index >=0 && index < G_N_ELEMENTS (ke_keys_info)); KE_LOG_AT_SPI_KEYBOARD_EVENT ("numpad"); if (key->type == SPI_KEY_RELEASED) return SPI_true; position = GPOINTER_TO_INT (ke_keys_info[index].data); g_assert (position >= 0 && position <= 15); if (ke_cnt_numpad_changes % 2) /* == (changing_layer == TRUE) */ { ke_report_layer_changed (position); ke_cnt_numpad_changes++; /* == (changing_layer = FALSE) */ } else if (position == 0) { sru_debug_log ("numpad", "layer will be changed..."); ke_cnt_numpad_changes++; /* == (changing_layer = TRUE) */ g_timeout_add (KE_LAYER_TIMEOUT, ke_layer_timeout, GINT_TO_POINTER (ke_cnt_numpad_changes)); } else { ke_report_layer_key (ke_crt_layer, position); } return SPI_true; } static SPIBoolean ke_try_report_at_spi_numpad_event (const AccessibleKeystroke *key, gint index) { return ke_report_at_spi_numpad_event (key, index); } static SPIBoolean ke_report_at_spi_command_event (const AccessibleKeystroke *key, gint index) { g_assert (key && key->keystring); g_assert (index >=0 && index < G_N_ELEMENTS (ke_keys_info)); g_assert (ke_keys_info[index].data); KE_LOG_AT_SPI_KEYBOARD_EVENT ("command"); if (key->type == SPI_KEY_PRESSED) ke_report_command (ke_keys_info[index].data, ke_get_ke_modifiers_from_at_spi_flags (key->modifiers)); return SPI_true; } static gboolean ke_at_spi_event_is_command (const AccessibleKeystroke *key) { gint i; KEKeyModifier modifiers; g_assert (ke_commands_array && key); modifiers = ke_get_ke_modifiers_from_at_spi_flags (key->modifiers); for (i = 0; i < ke_commands_array->len; i++) { KEKeysymKeyModifier info; KeyCode keycode; info = g_array_index (ke_commands_array, KEKeysymKeyModifier, i); keycode = ke_get_keycode_from_keysym (info.keysym); if (key->keycode == keycode && info.modifier == modifiers) return TRUE; } return FALSE; } static SPIBoolean ke_try_report_at_spi_command_event (const AccessibleKeystroke *key, gint index) { if (ke_at_spi_event_is_command (key)) return ke_report_at_spi_command_event (key, index); return SPI_false; } static SPIBoolean ke_report_at_spi_keyboard_event (const AccessibleKeystroke *key, void *data) { gint index, i; SPIBoolean rv = SPI_false; KEKeyFlag all = SPI_KEYMASK_ALT | SPI_KEYMASK_CONTROL | SPI_KEYMASK_SHIFT | SPI_KEYMASK_SHIFTLOCK | SPI_KEYMASK_NUMLOCK | SPI_KEYMASK_UNMODIFIED; g_assert (key && key->keystring); sru_debug_log ("event", "start processing event from at-spi..."); /* FIXME start */ if ((key->modifiers & (~all))) { g_printerr (_("Keyboard event contains a strange modifier\n")); if (key->modifiers & SPI_KEYMASK_MOD2) { g_printerr (_("Keyboard \"MOD2\" modifier will be changed with \"NUMLOCK\" modifier\n")); ((AccessibleKeystroke*)key)->modifiers = (key->modifiers & (~SPI_KEYMASK_MOD2)) | SPI_KEYMASK_NUMLOCK; } } /* FIXME end */ index = ke_get_key_index_for_keycode (key->keycode); KE_LOG_AT_SPI_KEYBOARD_EVENT ("event"); if (index < 0) rv = ke_try_report_at_spi_hit_event (key, index); else { for (i = 0; ke_keys_info[index].process[i]; i++) if (ke_keys_info[index].process[i] (key, index)) { rv = SPI_true; break; } } sru_debug_log ("event", "end of processing event from at-spi"); return rv; } static gboolean ke_register_listeners_for_keyboard () { gboolean rv = FALSE; g_assert (kbd_listener == NULL); ke_cnt_kbd_listeners = 0; kbd_listener = SPI_createAccessibleKeystrokeListener ( ke_report_at_spi_keyboard_event, NULL); if (kbd_listener) { KERegisterInfo data; data.listener = kbd_listener; data.acc_set = SPI_KEYSET_ALL_KEYS; data.flags = SPI_KEYMASK_UNMODIFIED; /* data->sync_type = SPI_KEYLISTENER_ALL_WINDOWS | SPI_KEYLISTENER_CANCONSUME; */ data.sync_type = SPI_KEYLISTENER_CANCONSUME | SPI_KEYLISTENER_NOSYNC; data.mask = SPI_KEY_PRESSED | SPI_KEY_RELEASED; data.opt_flags = SPI_KEYMASK_ALT | SPI_KEYMASK_CONTROL | SPI_KEYMASK_SHIFT | SPI_KEYMASK_SHIFTLOCK | SPI_KEYMASK_NUMLOCK | SPI_KEYMASK_UNMODIFIED; sru_debug_log ("init", "start registering listeners for all keys..."); ke_cnt_kbd_listeners = ke_register_listeners (&data); sru_debug_log ("init", "end registering listeners for all keys for %ld flags combinations", ke_cnt_kbd_listeners); rv = TRUE; } else { g_printerr (_("Unable to create the listener for keyboard\n")); sru_debug_log ("init", "unable to create listener"); } if (kbd_listener) AccessibleKeystrokeListener_unref (kbd_listener); return rv; } gboolean ke_mouse_move (gint x, gint y) { gboolean rv = FALSE; g_assert (sru_module_flag_check_initialized (ke_module_flag)); sru_debug_log ("entry", "start of \"ke_mouse_move\" function"); sru_debug_log ("mouse", "mouse will be moved to (%d-%d)", x, y); rv = SPI_generateMouseEvent (x, y, "abs") ? TRUE : FALSE; sru_debug_log ("mouse", "mouse moved %s", rv ? "succeeded" : "failed"); sru_debug_log ("entry", "end of \"ke_mouse_move\" function"); return rv; } gboolean ke_mouse_button_action (KEMouseButton button, KEMouseButtonAction action) { gboolean rv = FALSE; gchar maction[] = "b "; g_assert (sru_module_flag_check_initialized (ke_module_flag)); sru_debug_log ("entry", "start of \"ke_mouse_button_action\" function"); if (button == KE_MOUSE_BUTTON_LEFT) maction[1] = '1'; else if (button == KE_MOUSE_BUTTON_RIGHT) maction[1] = '2'; else if (button == KE_MOUSE_BUTTON_MIDDLE) maction[1] = '3'; else g_assert_not_reached (); if (action == KE_MOUSE_BUTTON_PRESS) maction[2] = 'p'; else if (action == KE_MOUSE_BUTTON_RELEASE) maction[2] = 'r'; else if (action == KE_MOUSE_BUTTON_CLICK) maction[2] = 'c'; else if (action == KE_MOUSE_BUTTON_DOUBLECLICK) maction[2] = 'd'; else g_assert_not_reached (); sru_debug_log ("mouse", "mouse will execute \"%s\"", maction); rv = SPI_generateMouseEvent (-1, -1, maction) ? TRUE : FALSE; sru_debug_log ("mouse", "mouse execution %s", rv ? "succeeded" : "failed"); sru_debug_log ("entry", "end of \"ke_mouse_button_action\" function"); return rv; } static gboolean ke_register_listener_for_mouse () { SPIBoolean rv = FALSE; ke_mouse_listener = SPI_createAccessibleEventListener ( ke_report_at_spi_mouse_moved, NULL); if (ke_mouse_listener) { rv = SPI_registerGlobalEventListener (ke_mouse_listener, "mouse:abs"); sru_debug_log ("mouse", "registering the listener for mouse events %s", rv ? "succeeded" : "failed"); } if (ke_mouse_listener) AccessibleEventListener_unref (ke_mouse_listener); if (!rv) g_printerr (_("Unable to create the listener for mouse events\n")); return rv; } gboolean ke_init (const KECallbacks *callbacks) { g_assert (callbacks); g_assert (sru_module_flag_check_uninitialized (ke_module_flag)); SRU_DEBUG_ADD_MODULE_AND_SCOPES; sru_debug_log ("entry", "start of \"ke_init\" function"); ke_crt_layer = KE_LAYER_DEFAULT; ke_cnt_numpad_changes = 0; kbd_listener = NULL; ke_mouse_listener = NULL; ke_keyboard_grabbing = FALSE; ke_cnt_kbd_listeners = 0; ke_commands_array = g_array_new (FALSE, TRUE, sizeof (KEKeysymKeyModifier)); ke_callbacks = *callbacks; ke_register_listeners_for_keyboard (); ke_register_listener_for_mouse (); sru_module_flag_set_initialized (ke_module_flag); sru_debug_log ("entry", "end of \"ke_init\" function"); return TRUE; } static void ke_deregister_listener (AccessibleKeystrokeListener *listener, KECount cnt) { KECount i; g_assert (listener && cnt >= 0); for (i = 0; i < cnt; i++) AccessibleKeystrokeListener_unref (listener); } static void ke_deregister_listeners_for_keyboard () { ke_deregister_listener (kbd_listener, ke_cnt_kbd_listeners); } static void ke_deregister_listener_for_mouse () { g_assert (ke_mouse_listener); AccessibleEventListener_unref (ke_mouse_listener); } void ke_terminate (void) { g_assert (sru_module_flag_check_initialized (ke_module_flag)); sru_debug_log ("entry", "start of \"ke_terminate\" function"); if (kbd_listener) ke_deregister_listeners_for_keyboard (); if (ke_mouse_listener) ke_deregister_listener_for_mouse (); g_assert (ke_commands_array && ke_commands_array->len == 0); g_array_free (ke_commands_array, TRUE); g_assert (ke_keyboard_grabbing == FALSE); sru_module_flag_set_uninitialized (ke_module_flag); sru_debug_log ("entry", "end of \"ke_terminate\" function"); } gboolean ke_command_add (const gchar *key, KEKeyModifier modifier) { gint i; KEKeysymKeyModifier info; g_assert (sru_module_flag_check_initialized (ke_module_flag)); sru_debug_log ("entry", "start of \"ke_command_add\" function"); info.keysym = ke_get_keysym_from_keys_info (key); g_assert (info.keysym != NoSymbol); info.modifier = modifier; g_assert ((info.modifier & (~(KE_MODIFIER_ALT | KE_MODIFIER_CONTROL | KE_MODIFIER_SHIFT))) == 0); #ifdef SR_DEBUG for (i = 0; i < ke_commands_array->len; i++) { KEKeysymKeyModifier info2; info2 = g_array_index (ke_commands_array, KEKeysymKeyModifier, i); if (info.keysym == info2.keysym && info.modifier == info2.modifier) { g_assert_not_reached (); return FALSE; } } #endif sru_debug_log ("command", "key \"%s\" with modifiers %s added as command", key, ke_debug_return_ke_key_modifiers (modifier)); g_array_append_val (ke_commands_array, info); sru_debug_log ("entry", "end of \"ke_command_add\" function"); return TRUE; } void ke_commands_remove_all () { g_assert (sru_module_flag_check_initialized (ke_module_flag)); g_assert (ke_commands_array); sru_debug_log ("entry", "start of \"ke_commands_remove_all\" function"); sru_debug_log ("command", "all commands removed"); g_array_set_size (ke_commands_array, 0); sru_debug_log ("entry", "end of \"ke_commands_remove_all\" function"); } gboolean ke_start_keyboard_grab () { g_assert (sru_module_flag_check_initialized (ke_module_flag)); g_assert (ke_keyboard_grabbing == FALSE); sru_debug_log ("entry", "start of \"ke_start_keyboard_grab\" function"); ke_keyboard_grabbing = TRUE; sru_debug_log ("entry", "end of \"ke_start_keyboard_grab\" function"); return TRUE; } void ke_stop_keyboard_grab () { g_assert (sru_module_flag_check_initialized (ke_module_flag)); g_assert (ke_keyboard_grabbing == TRUE); sru_debug_log ("entry", "start of \"ke_end_keyboard_grab\" function"); ke_keyboard_grabbing = FALSE; sru_debug_log ("entry", "end of \"ke_end_keyboard_grab\" function"); }