X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=test%2Fkeysynth-demo.c;h=c2df9ca116c979de9e99e165a76a9ad2900ae754;hb=8d44f439f509885221b67efc841a1b429cdd8236;hp=9bf71301b71ec8d3dc4fa72f844f429a8f771a46;hpb=e30f7b7a51a42a19765deedc3de17f489fca1d48;p=platform%2Fcore%2Fuifw%2Fat-spi2-atk.git diff --git a/test/keysynth-demo.c b/test/keysynth-demo.c index 9bf7130..c2df9ca 100644 --- a/test/keysynth-demo.c +++ b/test/keysynth-demo.c @@ -20,6 +20,8 @@ * Boston, MA 02111-1307, USA. */ +#include +#include #include #include #include @@ -28,19 +30,203 @@ #define LABELMAXLEN 20 #define MIN_KEYCODE 9 #define CAPSLOCK_KEYCODE 66 +#define SHIFT_L_KEYCODE 50 +#define SHIFT_R_KEYCODE 62 /* these can be increased to access more keys */ -#define MAX_ROWS 5 +#define MAX_ROWS 6 /* The last row only holds Quit and ShiftLatch, special-purpose keys */ #define MAX_COLUMNS 14 -static KeystrokeListener *key_listener; +static AccessibleKeystrokeListener *key_listener; +static AccessibleKeystrokeListener *switch_listener; -static boolean shift_latched = False; -static boolean caps_lock = False; +static SPIBoolean shift_latched = False; +static SPIBoolean caps_lock = False; static GtkButton **buttons[MAX_ROWS]; +typedef enum { + SCAN_IDLE, + SCAN_LINES, + SCAN_LINES_DONE, + SCAN_KEYS, + SCAN_KEYS_DONE +} ScanTimerState; + +typedef struct { + ScanTimerState timer_state; + gint scan_row; + gint scan_column; +} ScanState; + +GdkColor * +button_default_bg_color (GtkButton *button) +{ + static GdkColor bg_color; + static gboolean initialized = FALSE; + if (!initialized) + { + bg_color = gtk_widget_get_style (GTK_WIDGET (button))->bg[GTK_STATE_NORMAL]; + initialized = TRUE; + } + return &bg_color; +} + +GdkColor * +button_default_selected_color (GtkButton *button) +{ + static GdkColor selected_color; + static gboolean initialized = FALSE; + if (!initialized) + { + selected_color = gtk_widget_get_style (GTK_WIDGET (button))->bg[GTK_STATE_SELECTED]; + initialized = TRUE; + } + return &selected_color; +} + +void +select_key (gint lineno, gint keyno) +{ + /* + * Before we do this, we need to make sure we've saved the default normal bg. + * The button_default_bg_color() call caches this for us (as a side-effect). + * Probably we should do this a cleaner way... + */ + button_default_bg_color (buttons [lineno][keyno]); + gtk_widget_modify_bg (GTK_WIDGET (buttons [lineno][keyno]), + GTK_STATE_NORMAL, + button_default_selected_color (buttons [lineno][keyno])); +} + +void +deselect_key (gint lineno, gint keyno) +{ + gtk_widget_modify_bg (GTK_WIDGET (buttons [lineno][keyno]), + GTK_STATE_NORMAL, + button_default_bg_color (buttons [lineno][keyno])); +} + +void +deselect_line (gint lineno) +{ + int i; + int max_columns = MAX_COLUMNS; + if (lineno == MAX_ROWS-1) max_columns = 2; + for (i=0; itimer_state = SCAN_IDLE; + deselect_key (state->scan_row, state->scan_column); + return FALSE; +} + +static gboolean +increment_scan (gpointer data) +{ + ScanState *state = (ScanState *) data; + int max_columns; + switch (state->timer_state) + { + case SCAN_IDLE: +/* happens if switch-break occurs before the timer fires, after SCAN_KEYS_DONE*/ + return FALSE; + case SCAN_LINES: + deselect_line (state->scan_row); + state->scan_row = (++state->scan_row < MAX_ROWS) ? state->scan_row : 0; + select_line (state->scan_row); + g_print ("line %d\n", state->scan_row); + break; + case SCAN_KEYS: + deselect_key (state->scan_row, state->scan_column); + if (state->scan_row == MAX_ROWS-1) max_columns = 2; + else max_columns = MAX_COLUMNS; /* last row has only two keys */ + state->scan_column = (++state->scan_column < max_columns) ? state->scan_column : 0; + select_key (state->scan_row, state->scan_column); + g_print ("row %d\n", state->scan_column); + break; + case SCAN_LINES_DONE: + case SCAN_KEYS_DONE: + return FALSE; + default: + } + return TRUE; +} + +static void +scan_start (unsigned int timestamp) +{ + ScanState *state = scan_state(); + switch (state->timer_state) + { + case SCAN_IDLE: + state->timer_state = SCAN_LINES; + state->scan_column = 0; + state->scan_row = 0; + g_timeout_add_full (G_PRIORITY_HIGH_IDLE, 600, increment_scan, state, NULL); + select_line (state->scan_row); + break; + case SCAN_LINES_DONE: + state->timer_state = SCAN_KEYS; + g_timeout_add_full (G_PRIORITY_HIGH_IDLE, 600, increment_scan, state, NULL); + deselect_line (state->scan_row); + select_key (state->scan_row, state->scan_column); + break; + case SCAN_KEYS_DONE: + gtk_button_clicked (buttons[state->scan_row][state->scan_column]); + deselect_key (state->scan_row, state->scan_column); + state->timer_state = SCAN_IDLE; + break; + default: + g_print("unexpected state for 'scan start'\n"); + } +} + +static void +scan_stop (unsigned int timestamp) +{ + /* find the element correspondin to this event's timestamp */ + ScanState *state = scan_state(); + switch (state->timer_state) + { + case SCAN_LINES: + state->timer_state = SCAN_LINES_DONE; + break; + case SCAN_KEYS: + state->timer_state = SCAN_KEYS_DONE; + g_timeout_add_full (G_PRIORITY_HIGH_IDLE, 1200, timeout_scan, state, NULL); + break; + case SCAN_IDLE: + break; + default: + g_print("unexpected state for 'scan stop'\n"); + } +} + static void -label_buttons() +label_buttons(SPIBoolean shifted) { int i, j; KeySym keysym; @@ -48,13 +234,11 @@ label_buttons() char label[LABELMAXLEN] = " "; char *button_label; char *keysymstring; - boolean shifted; - for (i=0; iwindow), + GDK_WINDOW_XWINDOW (widget->window), &wm_hints); + + XSetWMProtocols (GDK_WINDOW_XDISPLAY (widget->window), + GDK_WINDOW_XWINDOW (widget->window), wm_window_protocols, 2); } -static boolean -is_command_key (void *p) +static void +button_exit (GtkButton *notused, void *alsonotused) +{ + keysynth_exit (); +} + +static SPIBoolean +is_command_key (AccessibleKeystroke *key, void *user_data) { - KeyStroke *key = (KeyStroke *)p; switch (key->keyID) { case 'Q': case 'q': - keysynth_exit(); + keysynth_exit (); return TRUE; /* not reached */ } + return FALSE; +} + +static SPIBoolean +switch_callback (AccessibleKeystroke *key, void *user_data) +{ + static SPIBoolean is_down = FALSE; + + if (key->type == SPI_KEY_RELEASED) + { + g_print ("spacebar up\n"); + is_down = FALSE; + scan_stop (key->timestamp); + } + else + if (!is_down) + { + g_print ("spacebar down\n"); + is_down = TRUE; + scan_start (key->timestamp); + } + /* catch the first, ignore the rest (will repeat) until keyrelease */ + return FALSE; } static void synth_keycode (GtkButton *button, KeyCode *keycode) { - if (*keycode) generateKeyEvent ((long) *keycode, KEY_PRESSRELEASE); - if (shift_latched) do_shift (button); - if (*keycode == CAPSLOCK_KEYCODE) + static KeyCode shift_keycode = 0; + if (!shift_keycode) shift_keycode = XKeysymToKeycode(GDK_DISPLAY(), (KeySym) 0xFFE1); + /* Note: in a real onscreen keyboard shift keycode should not be hard-coded! */ + if (*keycode) { - caps_lock = !caps_lock; - label_buttons (); + if (*keycode == CAPSLOCK_KEYCODE) + { + caps_lock = !caps_lock; + label_buttons (caps_lock || shift_latched); + } + if (shift_latched) + generateKeyEvent (shift_keycode, SPI_KEY_PRESS); + + generateKeyEvent ((long) *keycode, SPI_KEY_PRESSRELEASE); + + if (shift_latched) + { + generateKeyEvent (shift_keycode, SPI_KEY_RELEASE); + toggle_shift_latch (button); + } } } static void create_vkbd() { - GtkWidget *window, *button, *container, *hbox; + GtkWidget *window, *container, *hbox; int i, j; KeyCode *keycodeptr, keycode = MIN_KEYCODE; + static SPIBoolean true_val = True; + static SPIBoolean false_val = False; window = g_object_connect (gtk_widget_new (gtk_window_get_type (), "user_data", NULL, "can_focus", FALSE, - "type", GTK_WINDOW_POPUP, + "type", GTK_WINDOW_TOPLEVEL, "window-position", GTK_WIN_POS_CENTER, "title", "test", "allow_grow", FALSE, "allow_shrink", FALSE, "border_width", 10, NULL), + "signal::realize", keysynth_realize, NULL, "signal::destroy", keysynth_exit, NULL, NULL); @@ -154,7 +406,7 @@ create_vkbd() "GtkWidget::parent", window, "GtkWidget::visible", TRUE, NULL); - for (i=0; i 1) && (!strncmp(argv[1],"-h",2))) - { - printf ("Usage: keysynth-demo\n"); - exit(0); - } + AccessibleKeySet switch_set; + + if ((argc > 1) && (!strncmp (argv[1], "-h", 2))) + { + printf ("Usage: keysynth-demo\n"); + exit (1); + } gtk_init (&argc, &argv); /* must call, because this program uses GTK+ */ - SPI_init(); + SPI_init (); - key_listener = createKeystrokeListener(is_command_key); + key_listener = createAccessibleKeystrokeListener (is_command_key, NULL); /* will listen only to Alt-key combinations */ - registerKeystrokeListener(key_listener, - (KeySet *) ALL_KEYS, - KEYMASK_ALT, - (unsigned long) ( KeyPress | KeyRelease), - KEYLISTENER_CANCONSUME); - create_vkbd(); - - SPI_event_main(TRUE); + registerAccessibleKeystrokeListener (key_listener, + (AccessibleKeySet *) SPI_KEYSET_ALL_KEYS, + SPI_KEYMASK_ALT, + (unsigned long) ( KeyPress | KeyRelease), + SPI_KEYLISTENER_CANCONSUME | SPI_KEYLISTENER_ALL_WINDOWS); + create_vkbd (); + + /* + * Register a listener on an 'unused' key, to serve as a 'single switch'. + * On most Intel boxes there is at least one 'special' system key that does not + * have a non-zero keycode assigned in the Xserver, so we will intercept any keycode + * that is 'zero'. Often these the are the "windows" or the "menu" keys. + */ + switch_set.keysyms = g_new0 (unsigned long, 1); + switch_set.keycodes = g_new0 (unsigned short, 1); + switch_set.len = 1; + switch_set.keysyms[0] = (unsigned long) 0; + switch_set.keycodes[0] = (unsigned short) 0; + switch_listener = createAccessibleKeystrokeListener (switch_callback, NULL); + registerAccessibleKeystrokeListener (switch_listener, + &switch_set, + SPI_KEYMASK_UNMODIFIED, + (unsigned long) ( KeyPress | KeyRelease), + SPI_KEYLISTENER_CANCONSUME); + + SPI_event_main (); + + return SPI_exit (); }