API revisions: tweaks to key event API, added some reserved slots for
[platform/core/uifw/at-spi2-atk.git] / registryd / deviceeventcontroller.c
index 25af77e..a9ffd9d 100644 (file)
@@ -24,7 +24,7 @@
 
 #include <config.h>
 
-#define SPI_DEBUG
+#undef SPI_DEBUG
 
 #ifdef SPI_DEBUG
 #  include <stdio.h>
@@ -32,6 +32,8 @@
 
 #include <X11/Xlib.h>
 #include <X11/extensions/XTest.h>
+#define XK_MISCELLANY
+#include <X11/keysymdef.h>
 #include <gdk/gdkx.h> /* TODO: hide dependency (wrap in single porting file) */
 #include <gdk/gdkwindow.h>
 
@@ -45,8 +47,6 @@ static GObjectClass *spi_device_event_controller_parent_class;
 
 static gboolean kbd_registered = FALSE;
 
-static Display *display;
-
 static Window root_window;
 
 typedef enum {
@@ -75,7 +75,7 @@ struct _DEControllerKeyListener {
   Accessibility_KeySet *keys;
   Accessibility_ControllerEventMask mask;
   Accessibility_KeyEventTypeSeq *typeseq;
-  gboolean is_system_global;   
+  Accessibility_EventListenerMode *mode;       
 };
 
 typedef struct _DEControllerKeyListener DEControllerKeyListener;
@@ -91,7 +91,24 @@ static void spi_controller_register_device_listener (SpiDeviceEventController *c
  * Private methods
  */
 
-static DEControllerGrabMask * 
+static Display *
+spi_get_display (void )
+{
+ static Display *display = NULL;
+ /* We must open a new connection to the server to avoid clashing with the GDK event loop */
+ /*
+  * TODO: fixme, this makes the foolish assumption that registryd uses
+  * the same display as the apps, and the the DISPLAY environment variable is set.
+  */
+ if (!display)
+   {
+     display = XOpenDisplay (g_getenv ("DISPLAY"));
+   }
+ return display;
+}
+
+static DEControllerGrabMask *
 spi_grabmask_clone (DEControllerGrabMask *grabmask)
 {
   DEControllerGrabMask *clone = g_new0 (DEControllerGrabMask, 1);
@@ -144,7 +161,7 @@ spi_dec_key_listener_new (CORBA_Object l,
                          const Accessibility_KeySet *keys,
                          const Accessibility_ControllerEventMask mask,
                          const Accessibility_KeyEventTypeSeq *typeseq,
-                         const CORBA_boolean is_system_global,
+                         const Accessibility_EventListenerMode *mode,
                          CORBA_Environment *ev)
 {
   DEControllerKeyListener *key_listener = g_new0 (DEControllerKeyListener, 1);
@@ -153,12 +170,15 @@ spi_dec_key_listener_new (CORBA_Object l,
   key_listener->keys = ORBit_copy_value (keys, TC_Accessibility_KeySet);
   key_listener->mask = mask;
   key_listener->typeseq = ORBit_copy_value (typeseq, TC_Accessibility_KeyEventTypeSeq);
-  key_listener->is_system_global = is_system_global;
+  if (mode)
+    key_listener->mode = ORBit_copy_value (mode, TC_Accessibility_EventListenerMode);
+  else
+    key_listener->mode = NULL;
 
 #ifdef SPI_DEBUG
   g_print ("new listener, with mask %x, is_global %d, keys %p\n",
           (unsigned int) key_listener->mask,
-           (int) key_listener->is_system_global,
+           (int) mode->global,
           (void *) key_listener->keys);
 #endif
   return key_listener; 
@@ -218,7 +238,7 @@ spi_controller_register_global_keygrabs (SpiDeviceEventController *controller,
          /* X Grabs require keycodes, not keysyms */
          if (keyval >= 0)
            {
-             keyval = XKeysymToKeycode(display, (KeySym) keyval);                  
+             keyval = XKeysymToKeycode(spi_get_display (), (KeySym) keyval);               
            }
          grabmask.keyval = keyval;
           list_ptr = g_list_find_custom (controller->keygrabs_list, &grabmask,
@@ -251,7 +271,7 @@ spi_controller_register_device_listener (SpiDeviceEventController *controller,
   case SPI_DEVICE_TYPE_KBD:
       key_listener = (DEControllerKeyListener *) listener;       
       controller->key_listeners = g_list_prepend (controller->key_listeners, key_listener);
-      if (key_listener->is_system_global)
+      if (key_listener->mode->global)
         {
          spi_controller_register_global_keygrabs (controller, key_listener);   
        }
@@ -305,14 +325,10 @@ spi_controller_register_with_devices (SpiDeviceEventController *controller)
   /* calls to device-specific implementations and routines go here */
   /* register with: keyboard hardware code handler */
   /* register with: (translated) keystroke handler */
-#ifdef SPI_DEBUG
-  fprintf (stderr, "About to request events on window %ld of display %p\n",
-          (unsigned long) GDK_ROOT_WINDOW(), GDK_DISPLAY());
-#endif
+
   /* We must open a new connection to the server to avoid clashing with the GDK event loop */
-  display = XOpenDisplay (g_getenv ("DISPLAY"));
-  root_window = DefaultRootWindow (display);           
-  XSelectInput (display,
+  root_window = DefaultRootWindow (spi_get_display ());                
+  XSelectInput (spi_get_display (),
                root_window,
                KeyPressMask | KeyReleaseMask);
   /* register with: mouse hardware device handler? */
@@ -387,10 +403,11 @@ spi_key_event_matches_listener (const Accessibility_DeviceEvent *key_event,
                            DEControllerKeyListener *listener,
                            CORBA_boolean is_system_global)
 {
+  g_print ("checking keycode %d\n", (int) key_event->hw_code);
   if ((key_event->modifiers == (CORBA_unsigned_short) (listener->mask & 0xFFFF)) &&
        spi_key_set_contains_key (listener->keys, key_event) &&
        spi_key_eventtype_seq_contains_event (listener->typeseq, key_event) && 
-      (is_system_global == listener->is_system_global))
+      (is_system_global == listener->mode->global))
     {
       return TRUE;
     }
@@ -436,6 +453,8 @@ spi_keystroke_from_x_key_event (XKeyEvent *x_key_event)
 {
   Accessibility_DeviceEvent key_event;
   KeySym keysym;
+  const int cbuf_bytes = 20;
+  char cbuf [cbuf_bytes];
   
   keysym = XLookupKeysym (x_key_event, 0);
   key_event.id = (CORBA_long)(keysym);
@@ -449,6 +468,37 @@ spi_keystroke_from_x_key_event (XKeyEvent *x_key_event)
       key_event.type = Accessibility_KEY_RELEASED;
     } 
   key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
+  key_event.is_text = CORBA_FALSE;
+  switch (keysym)
+    {
+      case ' ':
+        key_event.event_string = CORBA_string_dup ("space");
+        break;
+      case XK_Tab:
+        key_event.event_string = CORBA_string_dup ("Tab");
+       break;
+      case XK_BackSpace:
+        key_event.event_string = CORBA_string_dup ("Backspace");
+       break;
+      case XK_Return:
+        key_event.event_string = CORBA_string_dup ("Return");
+       break;
+      default:
+        if (XLookupString (x_key_event, cbuf, cbuf_bytes, &keysym, NULL) > 0)
+          {
+            key_event.event_string = CORBA_string_dup (cbuf);
+           if (isgraph (keysym))
+             {
+               key_event.is_text = CORBA_TRUE; /* FIXME: incorrect for some composed chars? */
+             }
+          }
+        else
+          {
+            key_event.event_string = CORBA_string_dup ("");
+          }
+    }
+
+  key_event.timestamp = (CORBA_unsigned_long) x_key_event->time;
 #ifdef SPI_KEYEVENT_DEBUG
   fprintf (stderr,
      "Key %lu pressed (%c), modifiers %d\n",
@@ -482,13 +532,12 @@ spi_check_key_event (SpiDeviceEventController *controller)
          CORBA_exception_init (&ev);
        }
 
-       while (XPending(display))
+       while (XPending(spi_get_display ()))
          {
-           XNextEvent (display, x_event);
+           XNextEvent (spi_get_display (), x_event);
            if (XFilterEvent (x_event, None)) continue;   
            if (x_event->type == KeyPress || x_event->type == KeyRelease)
              {
-               fprintf (stderr, "x event type=%d\n", x_event->type);      
                key_event = spi_keystroke_from_x_key_event ((XKeyEvent *) x_event);
                /* relay to listeners, and decide whether to consume it or not */
                is_consumed = spi_notify_keylisteners (controller->key_listeners, &key_event, CORBA_TRUE, &ev);
@@ -502,14 +551,14 @@ spi_check_key_event (SpiDeviceEventController *controller)
 
            if (is_consumed)
              {
-               XAllowEvents (display, AsyncKeyboard, CurrentTime);
+               XAllowEvents (spi_get_display (), AsyncKeyboard, CurrentTime);
              }
            else
              {
-               XAllowEvents (display, ReplayKeyboard, CurrentTime);
+               XAllowEvents (spi_get_display (), ReplayKeyboard, CurrentTime);
              }
          }
-       XUngrabKey (display, AnyKey, AnyModifier, root_window);
+       XUngrabKey (spi_get_display (), AnyKey, AnyModifier, root_window);
 
        return spi_controller_grab_keyboard (controller);
 }
@@ -548,7 +597,7 @@ spi_controller_grab_keyboard (SpiDeviceEventController *controller)
 #endif
       if (!(maskVal & ControlMask))
        {
-         XGrabKey (display,
+         XGrabKey (spi_get_display (),
                    keyVal, 
                    maskVal,
                    root_window,
@@ -573,11 +622,11 @@ spi_device_event_controller_object_finalize (GObject *object)
 {
 
 #ifdef SPI_DEBUG
-        fprintf(stderr, "spi_device_event_controller_object_finalize called\n");
+  fprintf(stderr, "spi_device_event_controller_object_finalize called\n");
 #endif
-       /* disconnect any special listeners, get rid of outstanding keygrabs */
+  /* disconnect any special listeners, get rid of outstanding keygrabs */
        
-        spi_device_event_controller_parent_class->finalize (object);
+  spi_device_event_controller_parent_class->finalize (object);
 }
 
 /*
@@ -590,18 +639,18 @@ impl_register_keystroke_listener (PortableServer_Servant     servant,
                                  const Accessibility_KeySet *keys,
                                  const Accessibility_ControllerEventMask mask,
                                  const Accessibility_KeyEventTypeSeq *type,
-                                 const CORBA_boolean is_system_global,
+                                 const Accessibility_EventListenerMode *mode,
                                  CORBA_Environment         *ev)
 {
-       SpiDeviceEventController *controller = SPI_DEVICE_EVENT_CONTROLLER (
-               bonobo_object_from_servant (servant));
-       DEControllerKeyListener *dec_listener;
+  SpiDeviceEventController *controller = SPI_DEVICE_EVENT_CONTROLLER (
+         bonobo_object_from_servant (servant));
+  DEControllerKeyListener *dec_listener;
 #ifdef SPI_DEBUG
-       fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n",
-                (void *) l, (unsigned long) mask);
+  fprintf (stderr, "registering keystroke listener %p with maskVal %lu\n",
+          (void *) l, (unsigned long) mask);
 #endif
-       dec_listener = spi_dec_key_listener_new (l, keys, mask, type, is_system_global, ev);
-       spi_controller_register_device_listener (controller, (DEControllerListener *) dec_listener, ev);
+  dec_listener = spi_dec_key_listener_new (l, keys, mask, type, mode, ev);
+  spi_controller_register_device_listener (controller, (DEControllerListener *) dec_listener, ev);
 }
 
 /*
@@ -614,7 +663,6 @@ impl_deregister_keystroke_listener (PortableServer_Servant     servant,
                                    const Accessibility_KeySet *keys,
                                    const Accessibility_ControllerEventMask mask,
                                    const Accessibility_KeyEventTypeSeq *type,
-                                   const CORBA_boolean is_system_global,
                                    CORBA_Environment         *ev)
 {
        SpiDeviceEventController *controller = SPI_DEVICE_EVENT_CONTROLLER (
@@ -623,7 +671,7 @@ impl_deregister_keystroke_listener (PortableServer_Servant     servant,
                                                                          keys,
                                                                          mask,
                                                                          type,
-                                                                         is_system_global,
+                                                                         NULL,
                                                                          ev);
 #ifdef SPI_DEREGISTER_DEBUG
        fprintf (stderr, "deregistering keystroke listener %p with maskVal %lu\n",
@@ -657,48 +705,53 @@ impl_register_mouse_listener (PortableServer_Servant     servant,
 static KeyCode
 keycode_for_keysym (long keysym)
 {
-  return XKeysymToKeycode (display, (KeySym) keysym);
+  return XKeysymToKeycode (spi_get_display (), (KeySym) keysym);
 }
 
+#define SPI_DEBUG
+
 /*
  * CORBA Accessibility::DeviceEventController::registerKeystrokeListener
  *     method implementation
  */
 static void
-impl_generate_key_event (PortableServer_Servant     servant,
-                        const CORBA_long           keycode,
-                        const Accessibility_KeySynthType synth_type,
-                        CORBA_Environment          *ev)
+impl_generate_keyboard_event (PortableServer_Servant     servant,
+                             const CORBA_long           keycode,
+                             const CORBA_char          *keystring,
+                             const Accessibility_KeySynthType synth_type,
+                             CORBA_Environment          *ev)
 {
-       long key_synth_code;
+  long key_synth_code;
 #ifdef SPI_DEBUG
-       fprintf (stderr, "synthesizing keystroke %ld\n", (long) keycode);
+  fprintf (stderr, "synthesizing keystroke %ld, type %d\n", (long) keycode, (int) synth_type);
 #endif
-       /* TODO: hide/wrap/remove X dependency */
+  /* TODO: hide/wrap/remove X dependency */
 
-       /* TODO: be accessX-savvy so that keyrelease occurs after sufficient timeout */
+  /* TODO: be accessX-savvy so that keyrelease occurs after sufficient timeout */
        
-       /*
-        * TODO: when initializing, query for XTest extension before using,
-        * and fall back to XSendEvent() if XTest is not available.
-        */
+  /*
+   * TODO: when initializing, query for XTest extension before using,
+   * and fall back to XSendEvent() if XTest is not available.
+   */
+  
+  /* TODO: implement keystring mode also */
        
-       switch (synth_type)
-       {
-       case Accessibility_KEY_PRESS:
-               XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) keycode, True, CurrentTime);
-               break;
-       case Accessibility_KEY_PRESSRELEASE:
-               XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) keycode, True, CurrentTime);
-       case Accessibility_KEY_RELEASE:
-               XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) keycode, False, CurrentTime);
-               break;
-       case Accessibility_KEY_SYM:
-               key_synth_code = keycode_for_keysym (keycode);
-               XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) key_synth_code, True, CurrentTime);
-               XTestFakeKeyEvent (GDK_DISPLAY(), (unsigned int) key_synth_code, False, CurrentTime);
-               break;
-       }
+  switch (synth_type)
+    {
+      case Accessibility_KEY_PRESS:
+         XTestFakeKeyEvent (spi_get_display (), (unsigned int) keycode, True, CurrentTime);
+         break;
+      case Accessibility_KEY_PRESSRELEASE:
+         XTestFakeKeyEvent (spi_get_display (), (unsigned int) keycode, True, CurrentTime);
+      case Accessibility_KEY_RELEASE:
+         XTestFakeKeyEvent (spi_get_display (), (unsigned int) keycode, False, CurrentTime);
+         break;
+      case Accessibility_KEY_SYM:
+         key_synth_code = keycode_for_keysym (keycode);
+         XTestFakeKeyEvent (spi_get_display (), (unsigned int) key_synth_code, True, CurrentTime);
+         XTestFakeKeyEvent (spi_get_display (), (unsigned int) key_synth_code, False, CurrentTime);
+         break;
+   }
 }
 
 /* Accessibility::DeviceEventController::generateMouseEvent */
@@ -756,7 +809,7 @@ spi_device_event_controller_class_init (SpiDeviceEventControllerClass *klass)
         epv->registerKeystrokeListener = impl_register_keystroke_listener;
         epv->deregisterKeystrokeListener = impl_deregister_keystroke_listener;
 /*        epv->registerMouseListener = impl_register_mouse_listener; */
-        epv->generateKeyEvent = impl_generate_key_event;
+        epv->generateKeyboardEvent = impl_generate_keyboard_event;
         epv->generateMouseEvent = impl_generate_mouse_event;
        epv->notifyListenersSync = impl_notify_listeners_sync;
        epv->notifyListenersAsync = impl_notify_listeners_async;