Added a diagnostic test to simple-at which (when compiled with
[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 <netinet/in.h>
28 #include <sys/un.h>
29 #include "../util/mag_client.h"
30 #include "../cspi/spi-private.h" /* A hack for now */
31
32 #undef PRINT_TREE
33
34 static void report_focus_event    (const AccessibleEvent *event, void *user_data);
35 static void report_generic_event  (const AccessibleEvent *event, void *user_data);
36 static void report_text_event     (const AccessibleEvent *event, void *user_data);
37 static void report_button_press   (const AccessibleEvent *event, void *user_data);
38 static void check_property_change (const AccessibleEvent *event, void *user_data);
39 static SPIBoolean report_command_key_event  (const AccessibleKeystroke *stroke, void *user_data);
40 static SPIBoolean report_ordinary_key_event (const AccessibleKeystroke *stroke, void *user_data);
41 static void get_environment_vars (void);
42
43 static int _festival_init ();
44 static void _festival_say (const char *text, const char *voice, SPIBoolean shutup);
45 static void _festival_write (const char *buff, int fd);
46
47 #ifdef PRINT_TREE
48 static void print_accessible_tree (Accessible *accessible, char *prefix);
49 #endif
50
51 static SPIBoolean use_magnifier = FALSE;
52 static SPIBoolean use_festival = FALSE;
53 static SPIBoolean festival_chatty = FALSE;
54
55 static AccessibleEventListener *focus_listener;
56 static AccessibleEventListener *property_listener;
57 static AccessibleEventListener *generic_listener;
58 static AccessibleEventListener *button_listener;
59 static AccessibleEventListener *text_listener;
60 static AccessibleKeystrokeListener *command_key_listener;
61 static AccessibleKeystrokeListener *ordinary_key_listener;
62 static AccessibleKeySet            *command_keyset;
63
64 int
65 main (int argc, char **argv)
66 {
67   int i, j;
68   int n_desktops;
69   int n_apps;
70   char *s;
71   Accessible *desktop;
72   Accessible *application;
73   const char *modules;
74
75   if ((argc > 1) && (!strncmp (argv[1], "-h", 2)))
76     {
77       printf ("Usage: simple-at\n");
78       printf ("\tEnvironment variables used:\n\t\tFESTIVAL\n\t\tMAGNIFIER\n\t\tFESTIVAL_CHATTY\n");
79       exit (0);
80     }
81
82   modules = g_getenv ("GTK_MODULES");
83   if (!modules || modules [0] == '\0')
84     {
85       putenv ("GTK_MODULES=");
86     }
87   modules = NULL;
88
89   SPI_init ();
90
91   focus_listener = SPI_createAccessibleEventListener (report_focus_event, NULL);
92   property_listener = SPI_createAccessibleEventListener (check_property_change, NULL); 
93   generic_listener = SPI_createAccessibleEventListener (report_generic_event, NULL); 
94   text_listener = SPI_createAccessibleEventListener (report_text_event, NULL); 
95   button_listener = SPI_createAccessibleEventListener (report_button_press, NULL);
96   SPI_registerGlobalEventListener (focus_listener, "focus:");
97   SPI_registerGlobalEventListener (property_listener, "object:property-change:accessible-selection"); 
98   SPI_registerGlobalEventListener (generic_listener, "object:selection-changed"); 
99   SPI_registerGlobalEventListener (generic_listener, "object:children-changed"); 
100   SPI_registerGlobalEventListener (generic_listener, "object:visible-data-changed"); 
101   SPI_registerGlobalEventListener (generic_listener, "object:text-selection-changed"); 
102   SPI_registerGlobalEventListener (text_listener, "object:text-caret-moved"); 
103   SPI_registerGlobalEventListener (generic_listener, "object:text-changed"); 
104   SPI_registerGlobalEventListener (button_listener, "Gtk:GtkWidget:button-press-event");
105   n_desktops = SPI_getDesktopCount ();
106
107   for (i=0; i<n_desktops; ++i)
108     {
109       desktop = SPI_getDesktop (i);
110       s = Accessible_getName (desktop);
111       fprintf (stderr, "desktop %d name: %s\n", i, s);
112       SPI_freeString (s);
113       n_apps = Accessible_getChildCount (desktop);
114       for (j=0; j<n_apps; ++j)
115         {
116           application = Accessible_getChildAtIndex (desktop, j);
117           s = Accessible_getName (application);
118           fprintf (stderr, "app %d name: %s\n", j, s);
119 #ifdef PRINT_TREE
120           print_accessible_tree (application, "*");
121 #endif
122           SPI_freeString (s);
123           Accessible_unref (application);
124         }
125       Accessible_unref (desktop);
126     }
127
128   /* prepare the keyboard snoopers */
129   command_key_listener = SPI_createAccessibleKeystrokeListener (report_command_key_event, NULL);
130   ordinary_key_listener = SPI_createAccessibleKeystrokeListener (report_ordinary_key_event, NULL);
131
132   command_keyset = SPI_createAccessibleKeySet (11, "qmf23456789", NULL, NULL);
133   
134   /* will listen only to Control-Alt-q KeyPress events */
135   SPI_registerAccessibleKeystrokeListener(command_key_listener,
136                                           command_keyset,
137                                           SPI_KEYMASK_ALT | SPI_KEYMASK_CONTROL,
138                                           (unsigned long) ( SPI_KEY_PRESSED ),
139                                           SPI_KEYLISTENER_ALL_WINDOWS);
140
141   /* will listen only to CAPSLOCK key events, both press and release */
142   SPI_registerAccessibleKeystrokeListener(ordinary_key_listener,
143                                           (AccessibleKeySet *) SPI_KEYSET_ALL_KEYS,
144                                           SPI_KEYMASK_SHIFTLOCK,
145                                           (unsigned long) ( SPI_KEY_PRESSED | SPI_KEY_RELEASED ),
146                                           SPI_KEYLISTENER_NOSYNC);
147
148   get_environment_vars ();
149
150   SPI_event_main ();
151
152   putenv ("AT_BRIDGE_SHUTDOWN=1");
153
154   return SPI_exit ();
155 }
156
157 static void
158 get_environment_vars (void)
159 {
160   if (g_getenv ("FESTIVAL"))
161     {
162       fprintf (stderr, "Using festival\n");
163       use_festival = TRUE;
164       if (g_getenv ("FESTIVAL_CHATTY"))
165         {
166           festival_chatty = TRUE;
167         }
168     }
169   if (g_getenv ("MAGNIFIER"))
170     {
171       fprintf (stderr, "Using magnifier\n");
172       use_magnifier = TRUE;
173     }  
174   else
175     {
176       fprintf (stderr, "Not using magnifier\n");
177     }
178
179   if (!use_festival)
180     {
181       fprintf (stderr, "No speech output\n");
182     }
183 }
184
185 #ifdef PRINT_TREE
186 static void
187 print_accessible_tree (Accessible *accessible, char *prefix)
188 {
189         int n_children;
190         int i;
191         char *name;
192         char *role_name;
193         char *parent_name;
194         char *parent_role;
195         char child_prefix[100];
196         Accessible *child;
197         Accessible *parent;
198         
199         strncpy (child_prefix, prefix, 98);
200         strcat (child_prefix, "*");
201         parent = Accessible_getParent (accessible);
202         if (parent)
203           {
204                 parent_name = Accessible_getName (parent);
205                 parent_role = Accessible_getRoleName (parent);
206           }
207         Accessible_unref (parent);
208         name = Accessible_getName (accessible);
209         role_name = Accessible_getRoleName (accessible);
210         fprintf (stdout, "%sAccessible [%s] \"%s\"; parent [%s] %s\n",
211                  prefix, role_name, name, parent_role, parent_name);
212         SPI_freeString (name);
213         SPI_freeString (role_name);
214         SPI_freeString (parent_name);
215         n_children = Accessible_getChildCount (accessible);
216         for (i = 0; i < n_children; ++i)
217                 {
218                         child = Accessible_getChildAtIndex (accessible, i);
219                         print_accessible_tree (child, child_prefix);
220                         Accessible_unref (child);
221                 }
222 }
223 #endif
224
225 void
226 report_focussed_accessible (Accessible *obj, SPIBoolean shutup_previous_speech)
227 {
228   char *s;
229   int len;
230   long x, y, width, height;
231
232   if (use_festival)
233     {
234       if (festival_chatty)          
235         {
236           s = Accessible_getRoleName (obj);     
237           _festival_say (s, "voice_don_diphone", shutup_previous_speech);
238           SPI_freeString (s);
239         }
240       fprintf (stderr, "getting Name\n");
241       s = Accessible_getName (obj);
242       _festival_say (s, "voice_kal_diphone",
243                      shutup_previous_speech || festival_chatty);
244       SPI_freeString (s);
245     }
246   
247   if (Accessible_isComponent (obj))
248     {
249       AccessibleComponent *component = Accessible_getComponent (obj);
250       AccessibleComponent_getExtents (component, &x, &y, &width, &height,
251                                       SPI_COORD_TYPE_SCREEN);
252       fprintf (stderr, "Bounding box: (%ld, %ld) ; (%ld, %ld)\n",
253                x, y, x+width, y+height);
254       if (Accessible_isText (obj))
255         {
256           long x0, y0, xN, yN, w0, h0, wN, hN, nchars;
257           AccessibleText *text = Accessible_getText (obj);
258           nchars = AccessibleText_getCharacterCount (text);
259           if (nchars > 0) 
260             {
261               AccessibleText_getCharacterExtents (text, 0, &x0, &y0, &w0, &h0,
262                                               SPI_COORD_TYPE_SCREEN);
263               AccessibleText_getCharacterExtents (text, nchars-1, &xN, &yN, &wN, &hN, 
264                                                   SPI_COORD_TYPE_SCREEN);
265               x = MIN (x0, xN);
266               width = MAX (x0 + w0, xN + wN) - x;
267               fprintf (stderr, "Text bounding box: (%ld, %ld) ; (%ld, %ld)\n",
268                        x, y, x+width, y+height);
269             }
270         }
271       if (use_magnifier) {
272         magnifier_set_roi ((short) 0, x, y, width, height);
273       }
274     }
275
276   if (Accessible_isValue (obj))
277     {
278       AccessibleValue *value = Accessible_getValue (obj);
279       fprintf (stderr, "Current value = %f, min = %f; max = %f\n",
280                AccessibleValue_getCurrentValue (value),
281                AccessibleValue_getMinimumValue (value),
282                AccessibleValue_getMaximumValue (value));
283     }
284   /* if this is a text object, speak the first sentence. */
285
286   if (Accessible_isText(obj))
287
288   {
289      AccessibleText *text_interface;
290      long start_offset, end_offset;
291      char *first_sentence = "empty";
292      text_interface = Accessible_getText (obj);
293      first_sentence = AccessibleText_getTextAtOffset (
294                text_interface, (long) 0, SPI_TEXT_BOUNDARY_SENTENCE_START, &start_offset, &end_offset);
295      if (first_sentence && use_festival)
296        {
297          _festival_say(first_sentence, "voice_don_diphone", FALSE);
298          SPI_freeString (first_sentence);
299        }
300      len = AccessibleText_getCharacterCount (text_interface);
301      s = AccessibleText_getText (text_interface, 0, len);
302      fprintf (stderr, "done reporting on focussed object, text=%s\n", s);
303   }
304 }
305
306 void
307 report_focus_event (const AccessibleEvent *event, void *user_data)
308 {
309   char *s;
310
311   g_return_if_fail (event->source != NULL);
312
313   s = Accessible_getName (event->source);
314   if (s)
315     {
316       fprintf (stderr, "%s event from %s\n", event->type, s);
317       SPI_freeString (s);
318       report_focussed_accessible (event->source, TRUE);
319     }
320   Accessible_getParent (event->source);
321 }
322
323 void
324 report_generic_event (const AccessibleEvent *event, void *user_data)
325 {
326   fprintf (stderr, "%s event received\n", event->type);
327 }
328
329 void
330 report_text_event (const AccessibleEvent *event, void *user_data)
331 {
332   fprintf (stderr, "%s event received\n", event->type);
333   if (use_magnifier)
334     {
335       AccessibleText *text = Accessible_getText (event->source);
336       long offset = AccessibleText_getCaretOffset (text);
337       long x, y, w, h;
338       fprintf (stderr, "offset %d\n", (int) offset);
339       AccessibleText_getCharacterExtents (text, offset, &x, &y, &w, &h, 
340                                           SPI_COORD_TYPE_SCREEN);
341       fprintf (stderr, "new roi %d %d %d %d\n", (int) x, (int) y, (int) w, (int) h);
342       magnifier_set_roi ((short) 0, x, y, w, h);
343     }
344 }
345
346 void
347 report_button_press (const AccessibleEvent *event, void *user_data)
348 {
349   char *s;
350
351   g_return_if_fail (event->source != NULL);
352
353   s = Accessible_getName (event->source);
354
355   fprintf (stderr, "%s event from %s\n", event->type, s);
356   SPI_freeString (s);
357   s = Accessible_getDescription (event->source);
358   fprintf (stderr, "Object description %s\n", s);
359   SPI_freeString (s);
360 }
361
362 void
363 check_property_change (const AccessibleEvent *event, void *user_data)
364 {
365   AccessibleSelection *selection = Accessible_getSelection (event->source);
366   int n_selections;
367   int i;
368   char *s;
369   if (selection)
370   {
371     n_selections = (int) AccessibleSelection_getNSelectedChildren (selection);
372     s = Accessible_getName (event->source);
373     fprintf (stderr, "(Property) %s event from %s, %d selected children\n",
374              event->type, s, n_selections);
375     SPI_freeString (s);
376   /* for now, speak entire selection set */
377     for (i=0; i<n_selections; ++i)
378       {
379         Accessible *obj = AccessibleSelection_getSelectedChild (selection, (long) i);
380         g_return_if_fail (obj);
381         s = Accessible_getName (obj);
382         fprintf (stderr, "Child %d, name=%s\n", i, s);
383         SPI_freeString (s);
384         report_focussed_accessible (obj, i==0);
385     }
386   }
387 }
388
389 static void
390 simple_at_exit ()
391 {
392   SPI_deregisterGlobalEventListenerAll (focus_listener);
393   AccessibleEventListener_unref        (focus_listener);
394
395   SPI_deregisterGlobalEventListenerAll (property_listener);
396   AccessibleEventListener_unref        (property_listener);
397
398   SPI_deregisterGlobalEventListenerAll (generic_listener);
399   AccessibleEventListener_unref        (generic_listener);
400
401   SPI_deregisterGlobalEventListenerAll (text_listener);
402   AccessibleEventListener_unref        (text_listener);
403
404   SPI_deregisterGlobalEventListenerAll (button_listener);
405   AccessibleEventListener_unref        (button_listener);
406
407   SPI_deregisterAccessibleKeystrokeListener (command_key_listener, SPI_KEYMASK_ALT | SPI_KEYMASK_CONTROL);
408   AccessibleKeystrokeListener_unref         (command_key_listener);
409   SPI_freeAccessibleKeySet                  (command_keyset);
410
411   SPI_deregisterAccessibleKeystrokeListener (ordinary_key_listener, SPI_KEYMASK_SHIFTLOCK);
412   AccessibleKeystrokeListener_unref         (ordinary_key_listener);
413
414   SPI_event_quit ();
415 }
416
417 static SPIBoolean
418 is_command_key (const AccessibleKeystroke *key)
419 {
420   switch (key->keyID)
421     {
422     case 'Q':
423     case 'q':
424             simple_at_exit(); 
425             return TRUE; /* not reached */
426     case 'M':
427     case 'm':
428             use_magnifier = ! use_magnifier;
429             fprintf (stderr, "%ssing magnifier\n", use_magnifier ? "U" : "Not u");
430             return TRUE;
431     case 'F':
432     case 'f':
433             use_festival = ! use_festival;
434             fprintf (stderr, "%speech output\n", use_festival ? "S" : "No s");
435             return TRUE;
436     default:
437             return FALSE;
438     }
439 }
440
441 static SPIBoolean
442 report_command_key_event (const AccessibleKeystroke *key, void *user_data)
443 {
444   fprintf (stderr, "Command KeyEvent %s%c (keycode %d); string=%s; time=%lx\n",
445           (key->modifiers & SPI_KEYMASK_ALT)?"Alt-":"",
446           ((key->modifiers & SPI_KEYMASK_SHIFT)^(key->modifiers & SPI_KEYMASK_SHIFTLOCK))?
447           (char) toupper((int) key->keyID) : (char) tolower((int) key->keyID),
448           (int) key->keycode,
449           key->keystring,
450           (long int) key->timestamp);
451   return is_command_key (key);
452 }
453
454
455 static SPIBoolean
456 report_ordinary_key_event (const AccessibleKeystroke *key, void *user_data)
457 {
458   fprintf (stderr, "Received key event:\tsym %ld\n\tmods %x\n\tcode %d\n\tstring=\'%s\'\n\ttime %lx\n",
459            (long) key->keyID,
460            (unsigned int) key->modifiers,
461            (int) key->keycode,
462            key->keystring,
463            (long int) key->timestamp);
464   return FALSE;
465 }
466
467 static int
468 _festival_init ()
469 {
470   int fd;
471   struct sockaddr_in name;
472   int tries = 2;
473
474   name.sin_family = AF_INET;
475   name.sin_port = htons (1314);
476   name.sin_addr.s_addr = htonl(INADDR_ANY);
477   fd = socket (PF_INET, SOCK_STREAM, 0);
478
479   while (connect(fd, (struct sockaddr *) &name, sizeof (name)) < 0) {
480     if (!tries--) {
481       perror ("connect");
482       return -1;
483     }
484   }
485
486   _festival_write ("(audio_mode'async)\n", fd);
487   _festival_write ("(Parameter.set 'Duration_Model 'Tree_ZScore)\n", fd);
488   _festival_write ("(Parameter.set 'Duration_Stretch 0.75)\n", fd);
489   return fd;
490 }
491
492 static void 
493 _festival_say (const char *text, const char *voice, SPIBoolean shutup)
494 {
495   static int fd = 0;
496   gchar *quoted;
497   gchar *p;
498   gchar prefix[50];
499   static gchar voice_spec[32];
500   
501   if (!fd)
502     {
503       fd = _festival_init ();
504     }
505
506   fprintf (stderr, "saying text: %s\n", text);
507   
508   quoted = g_malloc(64+strlen(text)*2);
509
510   sprintf (prefix, "(SayText \"");
511
512   strncpy(quoted, prefix, 10);
513   p = quoted+strlen(prefix);
514   while (*text) {
515     if ( *text == '\\' || *text == '"' )
516       *p = '\\';
517     *p++ = *text++;
518   }
519   *p++ = '"';
520   *p++ = ')';
521   *p++ = '\n';
522   *p = 0;
523
524   if (shutup) _festival_write ("(audio_mode'shutup)\n", fd);
525   if (voice && (strncmp (voice, (char *) (voice_spec+1), strlen(voice))))
526     {
527       snprintf (voice_spec, 32, "(%s)\n", voice); 
528       _festival_write (voice_spec, fd);
529       _festival_write ("(Parameter.set 'Duration_Model 'Tree_ZScore)\n", fd);
530       _festival_write ("(Parameter.set 'Duration_Stretch 0.75)\n", fd);
531     }
532
533   _festival_write (quoted, fd);
534
535   g_free(quoted);
536 }
537
538 static void
539 _festival_write (const gchar *command_string, int fd)
540 {
541   fprintf(stderr, command_string);
542   if (fd < 0) {
543     perror("socket");
544     return;
545   }
546   write(fd, command_string, strlen(command_string));
547 }
548