2003-04-24 Padraig O'Briain <padraig.obriain@sun.com>
[platform/core/uifw/at-spi2-atk.git] / registryd / deviceeventcontroller.c
index ef04e36..609deea 100644 (file)
@@ -2,7 +2,7 @@
  *
  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
  *
- * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2003 Sun Microsystems Inc.,
  * Copyright 2001, 2002 Ximian, Inc.
  *
  * This library is free software; you can redistribute it and/or
@@ -60,7 +60,8 @@ static unsigned int mouse_mask_state = 0;
 static unsigned int mouse_button_mask =
   Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask;
 static unsigned int key_modifier_mask =
-  Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask | LockMask | ControlMask;
+  Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask | LockMask | ControlMask | SPI_KEYMASK_NUMLOCK;
+static unsigned int _numlock_physical_mask = Mod2Mask; /* a guess, will be reset */
 
 static GQuark spi_dec_private_quark = 0;
 
@@ -186,11 +187,20 @@ spi_dec_set_unlatch_pending (SpiDEController *controller, unsigned mask)
   DEControllerPrivateData *priv = 
     g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
 #ifdef SPI_XKB_DEBUG
-  if (priv->xkb_latch_mask) fprintf (stderr, "unlatch pending! %x\n", mask);
+  if (priv->xkb_latch_mask) fprintf (stderr, "unlatch pending! %x\n", 
+                                    priv->xkb_latch_mask);
 #endif
   priv->pending_xkb_mod_relatch_mask |= priv->xkb_latch_mask; 
 }
  
+static void
+spi_dec_clear_unlatch_pending (SpiDEController *controller)
+{
+  DEControllerPrivateData *priv = 
+    g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
+  priv->xkb_latch_mask = 0; 
+}
 static gboolean
 spi_dec_button_update_and_emit (SpiDEController *controller, 
                                guint mask_return)
@@ -390,6 +400,13 @@ spi_dec_emit_modifier_event (SpiDEController *controller, guint prev_mask,
   fprintf (stderr, "MODIFIER CHANGE EVENT! %x to %x\n", 
           prev_mask, current_mask);
 #endif
+
+  /* set bits for the virtual modifiers like NUMLOCK */
+  if (prev_mask & _numlock_physical_mask) 
+    prev_mask |= SPI_KEYMASK_NUMLOCK;
+  if (current_mask & _numlock_physical_mask) 
+    current_mask |= SPI_KEYMASK_NUMLOCK;
+
   e.type = "keyboard:modifiers";  
   e.source = BONOBO_OBJREF (controller->registry->desktop);
   e.detail1 = prev_mask & key_modifier_mask;
@@ -468,10 +485,11 @@ spi_dec_init_mouse_listener (SpiRegistry *registry)
 
   if (display)
     {
-      XGrabButton (display, AnyButton, AnyModifier,
+      if (XGrabButton (display, AnyButton, AnyModifier,
                   gdk_x11_get_default_root_xwindow (),
                   True, ButtonPressMask | ButtonReleaseMask,
-                  GrabModeSync, GrabModeAsync, None, None);
+                  GrabModeSync, GrabModeAsync, None, None) != Success)
+       fprintf (stderr, "WARNING: could not grab mouse buttons!\n");
       XSync (display, False);
 #ifdef SPI_DEBUG
       fprintf (stderr, "mouse buttons grabbed\n");
@@ -479,6 +497,24 @@ spi_dec_init_mouse_listener (SpiRegistry *registry)
     }
 }
 
+/**
+ * Eventually we can use this to make the marshalling of mask types
+ * more sane, but for now we just use this to detect 
+ * the use of 'virtual' masks such as Mumlock and convert them to
+ * system-specific mask values (i.e. ModMask).
+ * 
+ **/
+static Accessibility_ControllerEventMask
+spi_dec_translate_mask (Accessibility_ControllerEventMask mask)
+{
+  DEControllerPrivateData *priv;
+
+  if (mask == SPI_KEYMASK_NUMLOCK) {
+    mask = _numlock_physical_mask;
+  }
+  return mask;
+}
+
 static DEControllerKeyListener *
 spi_dec_key_listener_new (CORBA_Object                            l,
                          const Accessibility_KeySet             *keys,
@@ -491,7 +527,7 @@ spi_dec_key_listener_new (CORBA_Object                            l,
   key_listener->listener.object = bonobo_object_dup_ref (l, ev);
   key_listener->listener.type = SPI_DEVICE_TYPE_KBD;
   key_listener->keys = ORBit_copy_value (keys, TC_Accessibility_KeySet);
-  key_listener->mask = mask;
+  key_listener->mask = spi_dec_translate_mask (mask);
   key_listener->listener.typeseq = ORBit_copy_value (typeseq, TC_Accessibility_EventTypeSeq);
   if (mode)
     key_listener->mode = ORBit_copy_value (mode, TC_Accessibility_EventListenerMode);
@@ -811,7 +847,7 @@ spi_device_event_controller_forward_mouse_event (SpiDEController *controller,
   int button = xbutton_event->button;
   
   unsigned int mouse_button_state = xbutton_event->state;
-  
+
   switch (button)
     {
     case 1:
@@ -881,7 +917,7 @@ spi_device_event_controller_forward_mouse_event (SpiDEController *controller,
   /* if client wants to consume this event, and XKB latch state was
    *   unset by this button event, we reset it
    */
-  if (is_consumed && (xkb_mod_unlatch_occurred))
+  if (is_consumed && xkb_mod_unlatch_occurred)
     spi_dec_set_unlatch_pending (controller, mouse_mask_state);
   
   XAllowEvents (spi_get_display (),
@@ -950,6 +986,7 @@ global_filter_fn (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
                              &= ~(XkbAX_StickyKeysFBMask);
                XkbChangeControls (display, priv->xkb_desc, &changes);
              }
+             /* TODO: account for lock as well as latch */
              XkbLatchModifiers (display,
                                 XkbUseCoreKbd,
                                 priv->pending_xkb_mod_relatch_mask,
@@ -1017,6 +1054,8 @@ spi_controller_register_with_devices (SpiDEController *controller)
       XkbSelectEvents (spi_get_display (),
                       XkbUseCoreKbd,
                       XkbStateNotifyMask, XkbStateNotifyMask);     
+      _numlock_physical_mask = XkbKeysymToModifiers (spi_get_display (), 
+                                                    XK_Num_Lock);
     }  
 
   gdk_window_add_filter (NULL, global_filter_fn, controller);
@@ -1115,7 +1154,7 @@ spi_key_event_matches_listener (const Accessibility_DeviceEvent *key_event,
                                DEControllerKeyListener         *listener,
                                CORBA_boolean                    is_system_global)
 {
-  if ((key_event->modifiers == (CORBA_unsigned_short) (listener->mask & 0xFFFF)) &&
+  if ((key_event->modifiers == (CORBA_unsigned_short) (listener->mask & 0xFF)) &&
        spi_key_set_contains_key (listener->keys, key_event) &&
        spi_eventtype_seq_contains_event (listener->listener.typeseq, key_event) && 
       (is_system_global == listener->mode->global))
@@ -1216,18 +1255,19 @@ 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);
+  char cbuf [cbuf_bytes+1];
+  int nbytes;
+
+  nbytes = XLookupString (x_key_event, cbuf, cbuf_bytes, &keysym, NULL);  
   key_event.id = (CORBA_long)(keysym);
   key_event.hw_code = (CORBA_short) x_key_event->keycode;
   if (((XEvent *) x_key_event)->type == KeyPress)
     {
-      key_event.type = Accessibility_KEY_PRESSED;
+      key_event.type = Accessibility_KEY_PRESSED_EVENT;
     }
   else
     {
-      key_event.type = Accessibility_KEY_RELEASED;
+      key_event.type = Accessibility_KEY_RELEASED_EVENT;
     } 
   key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
   key_event.is_text = CORBA_FALSE;
@@ -1237,9 +1277,6 @@ spi_keystroke_from_x_key_event (XKeyEvent *x_key_event)
         key_event.event_string = CORBA_string_dup ("space");
         break;
       case XK_Tab:
-#ifdef SPI_KEYEVENT_DEBUG
-       fprintf(stderr, "Tab\n");
-#endif
         key_event.event_string = CORBA_string_dup ("Tab");
        break;
       case XK_BackSpace:
@@ -1312,12 +1349,16 @@ spi_keystroke_from_x_key_event (XKeyEvent *x_key_event)
         key_event.event_string = CORBA_string_dup ("Right");
        break;
       default:
-        if (XLookupString (x_key_event, cbuf, cbuf_bytes, &keysym, NULL) > 0)
+        if (nbytes > 0)
           {
+           gunichar c;
+           cbuf[nbytes] = '\0'; /* OK since length is cbuf_bytes+1 */
             key_event.event_string = CORBA_string_dup (cbuf);
-           if (isgraph (keysym))
+           c = g_utf8_get_char_validated (cbuf, nbytes);
+           if ((c > 0) && g_unichar_isprint (c))
              {
-               key_event.is_text = CORBA_TRUE; /* FIXME: incorrect for some composed chars? */
+               key_event.is_text = CORBA_TRUE; 
+               /* incorrect for some composed chars? */
              }
           }
         else
@@ -1329,10 +1370,13 @@ spi_keystroke_from_x_key_event (XKeyEvent *x_key_event)
   key_event.timestamp = (CORBA_unsigned_long) x_key_event->time;
 #ifdef SPI_KEYEVENT_DEBUG
   fprintf (stderr,
-     "Key %lu pressed (%c), modifiers %d\n",
-     (unsigned long) keysym,
-     keysym ? (int) keysym : '*',
-     (int) x_key_event->state);
+          "Key %lu pressed (%c), modifiers %d; string=%s [%x] %s\n",
+          (unsigned long) keysym,
+          keysym ? (int) keysym : '*',
+          (int) x_key_event->state,
+          key_event.event_string,
+          key_event.event_string[0],
+          (key_event.is_text == CORBA_TRUE) ? "(text)" : "(not text)");
 #endif
 #ifdef SPI_DEBUG
   fprintf (stderr, "%s%c",
@@ -1370,7 +1414,6 @@ spi_controller_update_key_grabs (SpiDEController           *controller,
       next = l->next;
 
       re_issue_grab = recv &&
-/*           (recv->type == Accessibility_KEY_RELEASED) && - (?) */
              (recv->modifiers & grab_mask->mod_mask) &&
              (grab_mask->key_val == keycode_for_keysym (recv->id));
 
@@ -1794,6 +1837,7 @@ impl_generate_keyboard_event (PortableServer_Servant           servant,
   SpiDEController *controller =
        SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
   long key_synth_code;
+  KeySym keysym;
 
 #ifdef SPI_DEBUG
        fprintf (stderr, "synthesizing keystroke %ld, type %d\n",
@@ -1836,6 +1880,16 @@ impl_generate_keyboard_event (PortableServer_Servant           servant,
     {
       DBG (-1, g_warning ("Error emitting keystroke"));
     }
+  if (synth_type == Accessibility_KEY_SYM) {
+    keysym = keycode;
+  }
+  else {
+    keysym = XkbKeycodeToKeysym (spi_get_display (), keycode, 0, 0);
+  }
+  if (XkbKeysymToModifiers (spi_get_display (), keysym) == 0) 
+    {
+      spi_dec_clear_unlatch_pending (controller);
+    }
 }
 
 /* Accessibility::DEController::generateMouseEvent */
@@ -2022,4 +2076,4 @@ spi_device_event_controller_new (SpiRegistry *registry)
 BONOBO_TYPE_FUNC_FULL (SpiDEController,
                       Accessibility_DeviceEventController,
                       PARENT_TYPE,
-                      spi_device_event_controller);
+                      spi_device_event_controller)