2001-11-13 Michael Meeks <michael@ximian.com>
[platform/core/uifw/at-spi2-atk.git] / test / keysynth-demo.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2001 Sun Microsystems Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <stdlib.h>
24 #include <gtk/gtk.h>
25 #include <gdk/gdkx.h>
26 #include "spi.h"
27
28 #define LABELMAXLEN 20
29 #define MIN_KEYCODE 9
30 #define CAPSLOCK_KEYCODE 66
31 #define SHIFT_L_KEYCODE 50
32 #define SHIFT_R_KEYCODE 62
33
34 /* these can be increased to access more keys */
35 #define MAX_ROWS 5
36 #define MAX_COLUMNS 14
37
38 static KeystrokeListener *key_listener;
39 static KeystrokeListener *switch_listener;
40
41 static boolean shift_latched = False;
42 static boolean caps_lock = False;
43 static GtkButton **buttons[MAX_ROWS];
44
45 static void
46 label_buttons(boolean shifted)
47 {
48   int i, j;
49   KeySym keysym;
50   KeyCode keycode = MIN_KEYCODE;
51   char label[LABELMAXLEN] = " ";
52   char *button_label;
53   char *keysymstring;
54   
55   for (i=0; i<MAX_ROWS; ++i)
56     {
57       for (j=0; j<MAX_COLUMNS; ++j, ++keycode)
58         {
59           keysym = (KeySym) XKeycodeToKeysym (GDK_DISPLAY(), keycode, shifted ? 1 : 0);
60           /* Note: these routines are not i18n-savvy,  we need to use XIM, other methods here */
61           if (keysym && g_ascii_isprint((int)keysym))
62             {
63               snprintf (label, 2, "%c", (int) keysym); 
64             }
65           else
66             {
67               keysymstring = XKeysymToString (keysym);
68               if (keysymstring)
69                 { 
70                   /* KP_ means keypad... we won't expose this difference */
71                   if (!strncmp (keysymstring, "KP_", 3))
72                        strncpy (label, (char *)(keysymstring+3), LABELMAXLEN);
73                   else strncpy (label, keysymstring, LABELMAXLEN);
74                 }
75               else *label = 0;
76             }
77           button_label =        
78           *label==' ' ? "   space   " : label;
79           gtk_button_set_label (buttons[i][j], button_label);    
80         }
81     }
82 }
83
84 static void
85 show_shift (GtkButton *button, boolean *is_shifted)
86 {
87  label_buttons (*is_shifted ^ caps_lock);       
88 }
89
90 static void
91 do_shift (GtkButton *button)
92 {
93   static KeyCode shift_keycode = 0;
94   if (!shift_keycode) shift_keycode = XKeysymToKeycode(GDK_DISPLAY(), (KeySym) 0xFFE1);
95   /* Note: in a real onscreen keyboard shift keycode should not be hard-coded! */
96   shift_latched = !shift_latched;
97   generateKeyEvent (shift_keycode, shift_latched ? KEY_PRESS : KEY_RELEASE);
98   if (buttons) label_buttons (caps_lock || shift_latched);
99 }
100
101 static void
102 keysynth_exit()
103 {
104   if (shift_latched) do_shift (NULL);
105   deregisterKeystrokeListener (key_listener, KEYMASK_ALT );
106   deregisterKeystrokeListener (switch_listener, KEYMASK_UNMODIFIED );
107   SPI_exit ();
108 }
109
110 static void
111 keysynth_realize (GtkWidget *widget)
112 {
113   XWMHints wm_hints;
114   Atom wm_window_protocols[2];
115   static gboolean initialized = FALSE;
116   
117   if (!initialized)
118     {
119       wm_window_protocols[0] = gdk_x11_get_xatom_by_name ("WM_DELETE_WINDOW");
120       wm_window_protocols[1] = gdk_x11_get_xatom_by_name ("_NET_WM_PING");
121     }
122   
123   wm_hints.flags = InputHint;
124   wm_hints.input = False;
125   
126   XSetWMHints (GDK_WINDOW_XDISPLAY (widget->window),
127                GDK_WINDOW_XWINDOW (widget->window), &wm_hints);
128   
129   XSetWMProtocols (GDK_WINDOW_XDISPLAY (widget->window),
130                    GDK_WINDOW_XWINDOW (widget->window), wm_window_protocols, 2);
131 }
132
133 static void
134 button_exit(GtkButton *notused, void *alsonotused)
135 {
136   keysynth_exit();
137 }
138
139 static boolean
140 is_command_key (void *p)
141 {
142   KeyStroke *key = (KeyStroke *)p;
143   switch (key->keyID)
144     {
145     case 'Q':
146     case 'q':
147             keysynth_exit(); 
148             return TRUE; /* not reached */
149     }
150 }
151
152 static boolean
153 switch_callback (void *p)
154 {
155   return FALSE;
156 }
157
158 static void
159 synth_keycode (GtkButton *button, KeyCode *keycode)
160 {
161   if (shift_latched) do_shift (button);
162   if (*keycode)
163     {
164       if (*keycode == CAPSLOCK_KEYCODE)
165         {
166           caps_lock = !caps_lock;            
167           label_buttons (caps_lock || shift_latched);
168         }
169       generateKeyEvent ((long) *keycode, KEY_PRESSRELEASE);
170     }      
171 }
172
173 static void
174 create_vkbd()
175 {
176   GtkWidget *window, *button, *container, *hbox;
177   int i, j;
178   KeyCode *keycodeptr, keycode = MIN_KEYCODE;
179   static boolean true_val = True;
180   static boolean false_val = False;
181
182   window = g_object_connect (gtk_widget_new (gtk_window_get_type (),
183                                              "user_data", NULL,
184                                              "can_focus", FALSE,
185                                              "type", GTK_WINDOW_TOPLEVEL,
186                                              "window-position", GTK_WIN_POS_CENTER,
187                                              "title", "test",
188                                              "allow_grow", FALSE,
189                                              "allow_shrink", FALSE,
190                                              "border_width", 10,
191                                              NULL),
192                              "signal::realize", keysynth_realize, NULL,
193                              "signal::destroy", keysynth_exit, NULL,
194                              NULL);
195   
196   container = gtk_widget_new (GTK_TYPE_VBOX,
197                               "GtkWidget::parent", window,
198                               "GtkWidget::visible", TRUE,
199                               NULL);
200   for (i=0; i<MAX_ROWS; ++i)
201     {
202       hbox = gtk_widget_new (gtk_hbox_get_type(),
203                              "GtkWidget::parent", container,
204                              "GtkWidget::visible", TRUE,
205                              NULL);
206       buttons[i] = g_new0 (GtkButton*, MAX_COLUMNS);
207       for (j=0; j<MAX_COLUMNS; ++j)
208         {
209           keycodeptr = (KeyCode *) g_new0 (KeyCode, 1);
210           *keycodeptr = keycode;
211           buttons[i][j] = g_object_connect (gtk_widget_new (gtk_button_get_type (),
212                                                      "GtkWidget::parent", hbox,
213                                                      "GtkWidget::visible", TRUE,
214                                                      NULL),
215                                      "signal::clicked",
216                                      synth_keycode, keycodeptr,
217                                      NULL);
218           if (keycode == SHIFT_L_KEYCODE || keycode == SHIFT_R_KEYCODE)
219             {
220               g_object_connect (buttons[i][j], "signal::pressed", show_shift,
221                                 &true_val, NULL);  
222               g_object_connect (buttons[i][j], "signal::released", show_shift,
223                                 &false_val, NULL);  
224             }
225           ++keycode;
226         }
227     } 
228   hbox = gtk_widget_new (gtk_hbox_get_type(),
229                          "GtkWidget::parent", container,
230                          "GtkWidget::visible", TRUE,
231                          NULL);
232   button = g_object_connect (gtk_widget_new (gtk_button_get_type (),
233                                              "GtkButton::label", "Quit",
234                                              "GtkWidget::parent", hbox,
235                                              "GtkWidget::visible", TRUE,
236                                              NULL),
237                              "signal::clicked",
238                              button_exit, NULL,
239                              NULL);
240   button = g_object_connect (gtk_widget_new (gtk_button_get_type (),
241                                              "GtkButton::label", "ShiftLatch",
242                                              "GtkWidget::parent", hbox,
243                                              "GtkWidget::visible", TRUE,
244                                              NULL),
245                              "signal::clicked",
246                              do_shift, NULL,
247                              NULL);
248   label_buttons (caps_lock || shift_latched);
249   gtk_widget_show (window);
250 }
251
252 int
253 main(int argc, char **argv)
254 {
255   KeySet spacebar_set;
256   
257   if ((argc > 1) && (!strncmp(argv[1],"-h",2)))
258   {
259     printf ("Usage: keysynth-demo\n");
260     exit(0);
261   }
262
263   gtk_init (&argc, &argv); /* must call, because this program uses GTK+ */
264
265   SPI_init();
266
267   key_listener = createKeystrokeListener(is_command_key);
268   /* will listen only to Alt-key combinations */
269   registerKeystrokeListener(key_listener,
270                             (KeySet *) ALL_KEYS,
271                             KEYMASK_ALT,
272                             (unsigned long) ( KeyPress | KeyRelease),
273                             KEYLISTENER_CANCONSUME | KEYLISTENER_ALLWINDOWS);
274   create_vkbd();  
275
276   /* register a listener on the spacebar, to serve as a 'single switch' */
277   spacebar_set.keysyms = g_new0 (unsigned long, 1);
278   spacebar_set.keycodes = g_new0 (unsigned short, 1);
279   spacebar_set.len = 1;
280   spacebar_set.keysyms[0] = (unsigned long) ' ';
281   spacebar_set.keycodes[0] = (unsigned short) 0;
282   switch_listener = createKeystrokeListener(switch_callback);
283   /* registerKeystrokeListener(switch_listener,
284                             &spacebar_set,
285                             KEYMASK_UNMODIFIED,
286                             (unsigned long) ( KeyPress | KeyRelease),
287                             KEYLISTENER_CANCONSUME);
288   */
289   
290   SPI_event_main(TRUE);
291 }