3fbf9fe2c24725bd897ae84ac50d09aa2cb170f9
[platform/core/uifw/at-spi2-atk.git] / test / simple-at.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 <ctype.h>
25 #include <unistd.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <cspi/spi.h>
29 #include "../util/mag_client.h"
30 #include "../cspi/spi-private.h" /* A hack for now */
31
32 static void report_focus_event    (AccessibleEvent *event, void *user_data);
33 static void report_generic_event  (AccessibleEvent *event, void *user_data);
34 static void report_button_press   (AccessibleEvent *event, void *user_data);
35 static void check_property_change (AccessibleEvent *event, void *user_data);
36 static SPIBoolean report_command_key_event  (AccessibleKeystroke *stroke, void *user_data);
37 static SPIBoolean report_ordinary_key_event (AccessibleKeystroke *stroke, void *user_data);
38 static void get_environment_vars (void);
39
40 static int _festival_init ();
41 static void _festival_say (const char *text, const char *voice, SPIBoolean shutup);
42 static void _festival_write (const char *buff, int fd);
43
44 static SPIBoolean use_magnifier = FALSE;
45 static SPIBoolean use_festival = FALSE;
46 static SPIBoolean festival_chatty = FALSE;
47
48 static AccessibleEventListener *focus_listener;
49 static AccessibleEventListener *property_listener;
50 static AccessibleEventListener *generic_listener;
51 static AccessibleEventListener *button_listener;
52 static AccessibleKeystrokeListener *command_key_listener;
53 static AccessibleKeystrokeListener *ordinary_key_listener;
54
55 int
56 main (int argc, char **argv)
57 {
58   int i, j;
59   int n_desktops;
60   int n_apps;
61   Accessible *desktop;
62   Accessible *application;
63   char *s;
64
65   if ((argc > 1) && (!strncmp (argv[1], "-h", 2)))
66   {
67     printf ("Usage: simple-at\n");
68     printf ("\tEnvironment variables used:\n\t\tFESTIVAL\n\t\tMAGNIFIER\n\t\tFESTIVAL_CHATTY\n");
69     exit (0);
70   }
71
72   SPI_init ();
73
74   focus_listener = createAccessibleEventListener (report_focus_event, NULL);
75   property_listener = createAccessibleEventListener (check_property_change, NULL); 
76   generic_listener = createAccessibleEventListener (report_generic_event, NULL); 
77   button_listener = createAccessibleEventListener (report_button_press, NULL);
78   registerGlobalEventListener (focus_listener, "focus:");
79   registerGlobalEventListener (property_listener, "object:property-change:accessible-selection"); 
80   registerGlobalEventListener (generic_listener, "object:selection-changed"); 
81   registerGlobalEventListener (generic_listener, "object:children-changed"); 
82   registerGlobalEventListener (generic_listener, "object:visible-data-changed"); 
83   registerGlobalEventListener (generic_listener, "object:text-selection-changed"); 
84   registerGlobalEventListener (generic_listener, "object:text-caret-moved"); 
85   registerGlobalEventListener (generic_listener, "object:text-changed"); 
86   registerGlobalEventListener (button_listener, "Gtk:GtkWidget:button-press-event");
87   n_desktops = getDesktopCount ();
88
89   for (i=0; i<n_desktops; ++i)
90     {
91       desktop = getDesktop (i);
92       s = Accessible_getName (desktop);
93       fprintf (stderr, "desktop %d name: %s\n", i, s);
94       SPI_freeString (s);
95       n_apps = Accessible_getChildCount (desktop);
96       for (j=0; j<n_apps; ++j)
97         {
98           application = Accessible_getChildAtIndex (desktop, j);
99           s = Accessible_getName (application);
100           fprintf (stderr, "app %d name: %s\n", j, s);
101           SPI_freeString (s);
102           Accessible_unref (application);
103         }
104       Accessible_unref (desktop);
105     }
106
107   /* prepare the keyboard snoopers */
108   command_key_listener = createAccessibleKeystrokeListener (report_command_key_event, NULL);
109   ordinary_key_listener = createAccessibleKeystrokeListener (report_ordinary_key_event, NULL);
110   
111   /* will listen only to Alt-key combinations, and only to KeyPress events */
112   registerAccessibleKeystrokeListener(command_key_listener,
113                                       (AccessibleKeySet *) SPI_KEYSET_ALL_KEYS,
114                                       SPI_KEYMASK_ALT,
115                                       (unsigned long) ( KeyPress ),
116                                       SPI_KEYLISTENER_ALL_WINDOWS);
117   
118   /* will listen only to unshifted key events, both press and release */
119   registerAccessibleKeystrokeListener(ordinary_key_listener,
120                                       (AccessibleKeySet *) SPI_KEYSET_ALL_KEYS,
121                                       SPI_KEYMASK_UNMODIFIED,
122                                       (unsigned long) ( KeyPress | KeyRelease),
123                                       SPI_KEYLISTENER_NOSYNC);
124                                       
125   /* will listen only to shifted key events, both press and release */
126   registerAccessibleKeystrokeListener(ordinary_key_listener,
127                                       (AccessibleKeySet *) SPI_KEYSET_ALL_KEYS,
128                                       SPI_KEYMASK_SHIFT,
129                                       (unsigned long) ( KeyPress | KeyRelease),
130                                       SPI_KEYLISTENER_NOSYNC);
131
132   get_environment_vars ();
133
134   SPI_event_main ();
135
136   setenv ("AT_BRIDGE_SHUTDOWN", "1", TRUE);
137
138   return SPI_exit ();
139 }
140
141 static void
142 get_environment_vars (void)
143 {
144   if (g_getenv ("FESTIVAL"))
145     {
146       fprintf (stderr, "Using festival\n");
147       use_festival = TRUE;
148       if (g_getenv ("FESTIVAL_CHATTY"))
149         {
150           festival_chatty = TRUE;
151         }
152     }
153   if (g_getenv ("MAGNIFIER"))
154     {
155       fprintf (stderr, "Using magnifier\n");
156       use_magnifier = TRUE;
157     }  
158 }
159
160 void
161 report_focussed_accessible (Accessible *obj, SPIBoolean shutup_previous_speech)
162 {
163   char *s;
164   int len;
165
166   if (use_festival)
167     {
168       if (festival_chatty)          
169         {
170           _festival_say (Accessible_getRole (obj), "voice_don_diphone", shutup_previous_speech);
171         }
172       fprintf (stderr, "getting Name\n");
173       s = Accessible_getName (obj);
174       _festival_say (s, "voice_kal_diphone",
175                      shutup_previous_speech || festival_chatty);
176       SPI_freeString (s);
177     }
178   
179   if (Accessible_isComponent (obj))
180     {
181       long x, y, width, height;
182       AccessibleComponent *component = Accessible_getComponent (obj);
183       AccessibleComponent_getExtents (component, &x, &y, &width, &height,
184                                       SPI_COORD_TYPE_SCREEN);
185       fprintf (stderr, "Bounding box: (%ld, %ld) ; (%ld, %ld)\n",
186                x, y, x+width, y+height);
187       if (use_magnifier) {
188               magnifier_set_roi ((short) 0, x, y, width, height);
189       }
190     }
191
192   if (Accessible_isValue (obj))
193     {
194       AccessibleValue *value = Accessible_getValue (obj);
195       fprintf (stderr, "Current value = %f, min = %f; max = %f\n",
196                AccessibleValue_getCurrentValue (value),
197                AccessibleValue_getMinimumValue (value),
198                AccessibleValue_getMaximumValue (value));
199     }
200   /* if this is a text object, speak the first sentence. */
201
202   if (Accessible_isText(obj))
203
204   {
205      AccessibleText *text_interface;
206      long start_offset, end_offset;
207      char *first_sentence = "empty";
208      text_interface = Accessible_getText (obj);
209      first_sentence = AccessibleText_getTextAtOffset (
210                text_interface, (long) 0, SPI_TEXT_BOUNDARY_SENTENCE_START, &start_offset, &end_offset);
211      if (first_sentence)
212        {
213          _festival_say(first_sentence, "voice_don_diphone", FALSE);
214          SPI_freeString (first_sentence);
215        }
216      len = AccessibleText_getCharacterCount (text_interface);
217      s = AccessibleText_getText (text_interface, 0, len);
218      fprintf (stderr, "done reporting on focussed object, text=%s\n", s);
219   }
220 }
221
222 void
223 report_focus_event (AccessibleEvent *event, void *user_data)
224 {
225   char *s;
226
227   g_return_if_fail (event->source != NULL);
228
229   s = Accessible_getName (event->source);
230   if (cspi_warn_ev (cspi_ev (), "Report focus event"))
231     {
232       fprintf (stderr, "%s event from %s\n", event->type, s);
233       SPI_freeString (s);
234       report_focussed_accessible (event->source, TRUE);
235     }
236   Accessible_getParent (event->source);
237 }
238
239 void
240 report_generic_event (AccessibleEvent *event, void *user_data)
241 {
242   fprintf (stderr, "%s event received\n", event->type);
243 }
244
245 void
246 report_button_press (AccessibleEvent *event, void *user_data)
247 {
248   char *s;
249
250   g_return_if_fail (event->source != NULL);
251
252   s = Accessible_getName (event->source);
253
254   fprintf (stderr, "%s event from %s\n", event->type, s);
255   SPI_freeString (s);
256   s = Accessible_getDescription (event->source);
257   fprintf (stderr, "Object description %s\n", s);
258   SPI_freeString (s);
259 }
260
261 void
262 check_property_change (AccessibleEvent *event, void *user_data)
263 {
264   AccessibleSelection *selection = Accessible_getSelection (event->source);
265   int n_selections;
266   int i;
267   char *s;
268   if (selection)
269   {
270     n_selections = (int) AccessibleSelection_getNSelectedChildren (selection);
271     s = Accessible_getName (event->source);
272     fprintf (stderr, "(Property) %s event from %s, %d selected children\n",
273              event->type, s, n_selections);
274     SPI_freeString (s);
275   /* for now, speak entire selection set */
276     for (i=0; i<n_selections; ++i)
277       {
278         Accessible *obj = AccessibleSelection_getSelectedChild (selection, (long) i);
279         g_return_if_fail (obj);
280         s = Accessible_getName (obj);
281         fprintf (stderr, "Child %d, name=%s\n", i, s);
282         SPI_freeString (s);
283         report_focussed_accessible (obj, i==0);
284     }
285   }
286 }
287
288 static void
289 simple_at_exit ()
290 {
291   deregisterGlobalEventListenerAll (focus_listener);
292   AccessibleEventListener_unref    (focus_listener);
293
294   deregisterGlobalEventListenerAll (property_listener);
295   AccessibleEventListener_unref    (property_listener);
296
297   deregisterGlobalEventListenerAll (generic_listener);
298   AccessibleEventListener_unref    (generic_listener);
299
300   deregisterGlobalEventListenerAll (button_listener);
301   AccessibleEventListener_unref    (button_listener);
302
303   deregisterAccessibleKeystrokeListener (command_key_listener, SPI_KEYMASK_ALT);
304   AccessibleKeystrokeListener_unref (command_key_listener);
305
306   deregisterAccessibleKeystrokeListener (ordinary_key_listener, SPI_KEYMASK_UNMODIFIED);
307   deregisterAccessibleKeystrokeListener (ordinary_key_listener, SPI_KEYMASK_SHIFT);
308   AccessibleKeystrokeListener_unref (ordinary_key_listener);
309   
310   SPI_event_quit ();
311 }
312
313 static SPIBoolean
314 is_command_key (AccessibleKeystroke *key)
315 {
316   switch (key->keyID)
317     {
318     case 'Q':
319     case 'q':
320             simple_at_exit(); 
321             return TRUE; /* not reached */
322     case 'M':
323     case 'm':
324             use_magnifier = ! use_magnifier;
325             return TRUE;
326     case 'F':
327     case 'f':
328             use_festival = ! use_festival;
329             return TRUE;
330     default:
331             return FALSE;
332     }
333 }
334
335 static SPIBoolean
336 report_command_key_event (AccessibleKeystroke *key, void *user_data)
337 {
338   fprintf (stderr, "Command KeyEvent %s%c (keycode %d)\n",
339           (key->modifiers & SPI_KEYMASK_ALT)?"Alt-":"",
340           ((key->modifiers & SPI_KEYMASK_SHIFT)^(key->modifiers & SPI_KEYMASK_SHIFTLOCK))?
341           (char) toupper((int) key->keyID) : (char) tolower((int) key->keyID),
342           (int) key->keycode);
343   return is_command_key (key);
344 }
345
346
347 static SPIBoolean
348 report_ordinary_key_event (AccessibleKeystroke *key, void *user_data)
349 {
350   fprintf (stderr, "Received key event:\tsym %ld\n\tmods %x\n\tcode %d\n\ttime %ld\n",
351            (long) key->keyID,
352            (unsigned int) key->modifiers,
353            (int) key->keycode,
354            (long int) key->timestamp);
355   return FALSE;
356 }
357
358 static int
359 _festival_init ()
360 {
361   int fd;
362   struct sockaddr_in name;
363   int tries = 2;
364
365   name.sin_family = AF_INET;
366   name.sin_port = htons (1314);
367   name.sin_addr.s_addr = htonl(INADDR_ANY);
368   fd = socket (PF_INET, SOCK_STREAM, 0);
369
370   while (connect(fd, (struct sockaddr *) &name, sizeof (name)) < 0) {
371     if (!tries--) {
372       perror ("connect");
373       return -1;
374     }
375   }
376
377   _festival_write ("(audio_mode'async)\n", fd);
378   _festival_write ("(Parameter.set 'Duration_Model 'Tree_ZScore)\n", fd);
379   _festival_write ("(Parameter.set 'Duration_Stretch 0.75)\n", fd);
380   return fd;
381 }
382
383 static void 
384 _festival_say (const char *text, const char *voice, SPIBoolean shutup)
385 {
386   static int fd = 0;
387   gchar *quoted;
388   gchar *p;
389   gchar prefix[50];
390   static gchar voice_spec[32];
391   
392   if (!fd)
393     {
394       fd = _festival_init ();
395     }
396
397   fprintf (stderr, "saying text: %s\n", text);
398   
399   quoted = g_malloc(64+strlen(text)*2);
400
401   sprintf (prefix, "(SayText \"");
402
403   strncpy(quoted, prefix, 10);
404   p = quoted+strlen(prefix);
405   while (*text) {
406     if ( *text == '\\' || *text == '"' )
407       *p = '\\';
408     *p++ = *text++;
409   }
410   *p++ = '"';
411   *p++ = ')';
412   *p++ = '\n';
413   *p = 0;
414
415   if (shutup) _festival_write ("(audio_mode'shutup)\n", fd);
416   if (voice && (strncmp (voice, (char *) (voice_spec+1), strlen(voice))))
417     {
418       snprintf (voice_spec, 32, "(%s)\n", voice); 
419       _festival_write (voice_spec, fd);
420       _festival_write ("(Parameter.set 'Duration_Model 'Tree_ZScore)\n", fd);
421       _festival_write ("(Parameter.set 'Duration_Stretch 0.75)\n", fd);
422     }
423
424   _festival_write (quoted, fd);
425
426   g_free(quoted);
427 }
428
429 static void
430 _festival_write (const gchar *command_string, int fd)
431 {
432   fprintf(stderr, command_string);
433   if (fd < 0) {
434     perror("socket");
435     return;
436   }
437   write(fd, command_string, strlen(command_string));
438 }
439