[g-a-devel]at-spi patch for bug #95828



Attached is a patch for bug #95828.

It adds some private data to SpiDEController via g_object_add_qdata, and
calls XKB (if available) to determine the current SlowKeys and
BounceKeys settings before synthesizing events, and sets the 'time'
parameter for event synthesis accordingly.  This means that event
synthesis will meet the current filter requirements for AccessX,
otherwise many synthesized events would be rejected.

If I hear no issues I plan to commit this fix within the next 24 hours.

regards,

Bill


Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/at-spi/ChangeLog,v
retrieving revision 1.252
diff -u -r1.252 ChangeLog
--- ChangeLog	16 Oct 2002 14:27:05 -0000	1.252
+++ ChangeLog	18 Oct 2002 16:19:53 -0000
@@ -1,3 +1,37 @@
+2002-10-18  Bill Haneman  <bill haneman sun com>
+
+	BUGFIX for #95828.
+
+	* acconfig.h:
+	Added template for HAVE_XKB.
+	
+	* configure.in:
+	Changes to check for XKB, and to set the HAVE_XKB #define if it 
+	is available.
+	
+	* libspi/listener.c:
+	()impl_notify_event): Make failure to get event source name
+	nonfatal.
+
+	* registryd/deviceeventcontroller.c:
+	(#include): include X11/XKBlib.h.
+	(DEControllerPrivateData) : New struct.
+	(dec_xkb_get_slowkeys_delay) (dec_xkb_get_boucekeys_delay) : 
+	New methods.
+	(dec_synth_keycode_press) (dec_synth_keycode_release):
+	New methods; split the key synthesis code into these methods.
+	They check XKB settings before determining the "time" values to
+	pass to Xtest; this fixes bug #95828.
+	(impl_generate_keyboard_event): Changed to use methods above,
+	instead of callng Xtest directly.
+	(spi_device_event_controller_init): Initialize new privae struct s
+	above.
+	(spi_device_event_controllr_object_finalize):
+	Free the (new) private data.
+
+	* registryd/deviceeventcontroller.h:
+	Add new gpointer to end of struct data.
+
 2002-10-16  Bill Haneman  <bill haneman sun com>
 
 	* configure.in:
Index: acconfig.h
===================================================================
RCS file: /cvs/gnome/at-spi/acconfig.h,v
retrieving revision 1.2
diff -u -r1.2 acconfig.h
--- acconfig.h	13 Nov 2001 00:54:01 -0000	1.2
+++ acconfig.h	18 Oct 2002 16:19:53 -0000
@@ -5,3 +5,4 @@
 #undef HAVE_GET_TEXT
 #undef HAVE_LC_MESSAGES
 #undef HAVE_STPCPY
+#undef HAVE_XKB
Index: configure.in
===================================================================
RCS file: /cvs/gnome/at-spi/configure.in,v
retrieving revision 1.51
diff -u -r1.51 configure.in
--- configure.in	16 Oct 2002 14:27:05 -0000	1.51
+++ configure.in	18 Oct 2002 16:19:53 -0000
@@ -160,6 +160,16 @@
 fi
 AC_SUBST(XTST_LIBS)
 
+have_xkb=
+AC_CHECK_LIB(X11, XkbQueryExtension, have_xkb="maybe",,$X_LIBS)
+if test "x$have_xkb" = "xmaybe"; then 
+  AC_CHECK_HEADER(X11/XKBlib.h, have_xkb=yes)
+fi
+if test "x$have_xkb" = "xyes"; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(HAVE_XKB)
+fi
+
 AC_SUBST(CFLAGS)
 AC_SUBST(CPPFLAGS)
 AC_SUBST(LDFLAGS)
Index: libspi/listener.c
===================================================================
RCS file: /cvs/gnome/at-spi/libspi/listener.c,v
retrieving revision 1.18
diff -u -r1.18 listener.c
--- libspi/listener.c	13 Sep 2002 13:09:01 -0000	1.18
+++ libspi/listener.c	18 Oct 2002 16:19:53 -0000
@@ -67,7 +67,6 @@
     fprintf(stderr,
             ("Accessibility app error: exception during event notification: %s\n"),
             CORBA_exception_id(ev));
-    exit(-1);
   }
   /*
   fprintf (stderr, "source is component ? : %s\n",
Index: registryd/deviceeventcontroller.c
===================================================================
RCS file: /cvs/gnome/at-spi/registryd/deviceeventcontroller.c,v
retrieving revision 1.48
diff -u -r1.48 deviceeventcontroller.c
--- registryd/deviceeventcontroller.c	16 Oct 2002 14:27:05 -0000	1.48
+++ registryd/deviceeventcontroller.c	18 Oct 2002 16:19:53 -0000
@@ -25,6 +25,7 @@
 
 #include <config.h>
 
+#undef  SPI_XKB_DEBUG
 #undef  SPI_DEBUG
 #undef  SPI_KEYEVENT_DEBUG
 
@@ -35,6 +36,7 @@
 
 #include <X11/Xlib.h>
 #include <X11/extensions/XTest.h>
+#include <X11/XKBlib.h>
 #define XK_MISCELLANY
 #include <X11/keysymdef.h>
 #include <gdk/gdk.h>
@@ -58,6 +60,8 @@
 static unsigned int key_modifier_mask =
   Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask | LockMask | ControlMask;
 
+static GQuark spi_dec_private_quark = 0;
+
 int (*x_default_error_handler) (Display *display, XErrorEvent *error_event);
 
 typedef enum {
@@ -89,6 +93,13 @@
   Accessibility_EventListenerMode  *mode;	
 } DEControllerKeyListener;
 
+typedef struct {
+	unsigned int last_press_keycode;
+	unsigned int last_release_keycode;
+	struct timeval last_press_time;
+	struct timeval last_release_time;
+} DEControllerPrivateData;
+
 static void     spi_controller_register_with_devices          (SpiDEController           *controller);
 static gboolean spi_controller_update_key_grabs               (SpiDEController           *controller,
 							       Accessibility_DeviceEvent *recv);
@@ -212,7 +223,9 @@
 	  }
 	  if ((mask_return & key_modifier_mask) !=
 	      (mouse_mask_state & key_modifier_mask)) {
-		  fprintf (stderr, "MODIFIER CHANGE EVENT!\n");  
+#ifdef SPI_DEBUG
+		  fprintf (stderr, "MODIFIER CHANGE EVENT!\n");
+#endif
 		  e.type = "keyboard:modifiers";  
 		  e.source = BONOBO_OBJREF (registry->desktop);
 		  e.detail1 = mouse_mask_state;
@@ -307,7 +320,9 @@
 		   True, ButtonPressMask | ButtonReleaseMask,
 		   GrabModeSync, GrabModeAsync, None, None);
       XSync (display, False);
+#ifdef SPI_DEBUG
       fprintf (stderr, "mouse buttons grabbed\n");
+#endif
     }
 }
 
@@ -1051,7 +1066,8 @@
 #endif
   /* disconnect any special listeners, get rid of outstanding keygrabs */
   XUngrabKey (spi_get_display (), AnyKey, AnyModifier, DefaultRootWindow (spi_get_display ()));
-	
+
+  g_free (g_object_get_data (G_OBJECT (controller), "spi-dec-private"));
   spi_device_event_controller_parent_class->finalize (object);
 }
 
@@ -1175,6 +1191,149 @@
   spi_dec_key_listener_free (key_listener, ev);
 }
 
+static unsigned int dec_xkb_get_slowkeys_delay (SpiDEController *controller)
+{
+	unsigned int retval = 0;
+#ifdef HAVE_XKB
+#ifdef XKB_HAS_GET_SLOW_KEYS_DELAY	
+	retval = XkbGetSlowKeysDelay (spi_get_display (),
+				      XkbUseCoreKbd, &bounce_delay);
+#else
+	XkbDescPtr xkb = XkbGetMap (spi_get_display (), 0, XkbUseCoreKbd);
+	if (!(xkb == (XkbDescPtr) BadAlloc || xkb == NULL))
+	{
+		Status s = XkbGetControls (spi_get_display (),
+					   XkbAllControlsMask, xkb);
+		if (s == Success)
+		{
+			if (xkb->ctrls->enabled_ctrls & XkbSlowKeysMask)
+				retval = xkb->ctrls->slow_keys_delay;
+		}
+		XkbFreeKeyboard (xkb, XkbAllControlsMask, True);
+	}
+#endif
+#endif
+#ifdef SPI_XKB_DEBUG
+	fprintf (stderr, "SlowKeys delay: %d\n", (int) retval);
+#endif
+        return retval;
+}
+
+static unsigned int dec_xkb_get_bouncekeys_delay (SpiDEController *controller)
+{
+	unsigned int retval = 0;
+#ifdef HAVE_XKB
+#ifdef XKB_HAS_GET_BOUNCE_KEYS_DELAY	
+	retval = XkbGetBounceKeysDelay (spi_get_display (),
+					XkbUseCoreKbd, &bounce_delay);
+#else
+	XkbDescPtr xkb = XkbGetMap (spi_get_display (), 0, XkbUseCoreKbd);
+	if (!(xkb == (XkbDescPtr) BadAlloc || xkb == NULL))
+	{
+		Status s = XkbGetControls (spi_get_display (),
+					   XkbAllControlsMask, xkb);
+		if (s == Success)
+		{
+			if (xkb->ctrls->enabled_ctrls & XkbBounceKeysMask)
+				retval = xkb->ctrls->debounce_delay;
+		}
+		XkbFreeKeyboard (xkb, XkbAllControlsMask, True);
+	}
+#endif
+#endif
+#ifdef SPI_XKB_DEBUG
+	fprintf (stderr, "BounceKeys delay: %d\n", (int) retval);
+#endif
+	return retval;
+}
+
+static gboolean
+dec_synth_keycode_press (SpiDEController *controller,
+			 unsigned int keycode)
+{
+	unsigned int time = CurrentTime;
+	unsigned int bounce_delay;
+	unsigned int elapsed_msec;
+	struct timeval tv;
+	DEControllerPrivateData *priv =
+		(DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
+								spi_dec_private_quark);
+	if (keycode == priv->last_release_keycode)
+	{
+		bounce_delay = dec_xkb_get_bouncekeys_delay (controller); 
+                if (bounce_delay)
+		{
+			gettimeofday (&tv);
+			XFlush (spi_get_display ());
+			elapsed_msec =
+				(tv.tv_sec - priv->last_release_time.tv_sec) * 1000
+				+ (tv.tv_usec - priv->last_release_time.tv_usec) / 1000;
+#ifdef SPI_XKB_DEBUG			
+			fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
+				 (long) (tv.tv_usec - priv->last_release_time.tv_usec));
+#endif
+#ifdef THIS_IS_BROKEN
+			if (elapsed_msec < bounce_delay)
+				time = bounce_delay - elapsed_msec + 1;
+#else
+			time = bounce_delay + 1;
+#endif
+#ifdef SPI_XKB_DEBUG			
+			fprintf (stderr, "waiting %d ms\n", time);
+#endif
+		}
+	}
+	fprintf (stderr, "press %d\n", (int) keycode);
+        XTestFakeKeyEvent (spi_get_display (), keycode, True, time);
+	priv->last_press_keycode = keycode;
+	XFlush (spi_get_display ());
+	gettimeofday (&priv->last_press_time, NULL);
+	return TRUE;
+}
+
+static gboolean
+dec_synth_keycode_release (SpiDEController *controller,
+			   unsigned int keycode)
+{
+	unsigned int time = CurrentTime;
+	unsigned int slow_delay;
+	unsigned int elapsed_msec;
+	struct timeval tv;
+	DEControllerPrivateData *priv =
+		(DEControllerPrivateData *) g_object_get_qdata (G_OBJECT (controller),
+								spi_dec_private_quark);
+	if (keycode == priv->last_press_keycode)
+	{
+		slow_delay = dec_xkb_get_slowkeys_delay (controller);
+		if (slow_delay)
+		{
+			gettimeofday (&tv);
+			elapsed_msec =
+				(tv.tv_sec - priv->last_press_time.tv_sec) * 1000
+				+ (tv.tv_usec - priv->last_press_time.tv_usec) / 1000;
+#ifdef SPI_XKB_DEBUG			
+			fprintf (stderr, "%d ms elapsed (%ld usec)\n", elapsed_msec,
+				 (long) (tv.tv_usec - priv->last_press_time.tv_usec));
+#endif
+#ifdef THIS_IS_BROKEN_DUNNO_WHY
+			if (elapsed_msec < slow_delay)
+				time = slow_delay - elapsed_msec + 1;
+#else
+			time = slow_delay + 1;
+#endif
+#ifdef SPI_XKB_DEBUG			
+			fprintf (stderr, "waiting %d ms\n", time);
+#endif
+		}
+	}
+	fprintf (stderr, "release %d\n", (int) keycode);
+        XTestFakeKeyEvent (spi_get_display (), keycode, False, time);
+	priv->last_release_keycode = keycode;
+	XFlush (spi_get_display ());
+	gettimeofday (&priv->last_release_time, NULL);
+	return TRUE;
+}
+
 /*
  * CORBA Accessibility::DEController::registerKeystrokeListener
  *     method implementation
@@ -1186,16 +1345,19 @@
 			      const Accessibility_KeySynthType synth_type,
 			      CORBA_Environment               *ev)
 {
+  SpiDEController *controller =
+	SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
   long key_synth_code;
+  unsigned int slow_keys_delay;
+  unsigned int press_time;
+  unsigned int release_time;
 
 #ifdef SPI_DEBUG
-  fprintf (stderr, "synthesizing keystroke %ld, type %d\n",
-	   (long) keycode, (int) synth_type);
+	fprintf (stderr, "synthesizing keystroke %ld, type %d\n",
+		 (long) keycode, (int) synth_type);
 #endif
   /* TODO: hide/wrap/remove X dependency */
 
-  /* 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.
@@ -1203,25 +1365,28 @@
   
   /* TODO: implement keystring mode also */
   gdk_error_trap_push ();
-
+  
   switch (synth_type)
     {
       case Accessibility_KEY_PRESS:
-        XTestFakeKeyEvent (spi_get_display (), (unsigned int) keycode, True, CurrentTime);
-	break;
+	      dec_synth_keycode_press (controller, keycode);
+	      break;
       case Accessibility_KEY_PRESSRELEASE:
-	XTestFakeKeyEvent (spi_get_display (), (unsigned int) keycode, True, CurrentTime);
+	      dec_synth_keycode_press (controller, keycode);
       case Accessibility_KEY_RELEASE:
-	XTestFakeKeyEvent (spi_get_display (), (unsigned int) keycode, False, CurrentTime);
-	break;
+	      dec_synth_keycode_release (controller, keycode);
+	      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;
+#ifdef SPI_XKB_DEBUG	      
+	      fprintf (stderr, "KeySym synthesis\n");
+#endif
+	      key_synth_code = keycode_for_keysym (keycode);
+	      dec_synth_keycode_press (controller, key_synth_code);
+	      dec_synth_keycode_release (controller, key_synth_code);
+	      break;
       case Accessibility_KEY_STRING:
-	fprintf (stderr, "Not yet implemented\n");
-	break;
+	      fprintf (stderr, "Not yet implemented\n");
+	      break;
     }
   if (gdk_error_trap_pop ())
     {
@@ -1393,13 +1558,21 @@
 {
   SpiDEController *retval = g_object_new (
     SPI_DEVICE_EVENT_CONTROLLER_TYPE, NULL);
-
+  DEControllerPrivateData *private;
+  
   retval->registry = SPI_REGISTRY (bonobo_object_ref (
 	  BONOBO_OBJECT (registry)));
 
+  private = g_new0 (DEControllerPrivateData, 1);
+  gettimeofday (&private->last_press_time, NULL);
+  gettimeofday (&private->last_release_time, NULL);
+  if (!spi_dec_private_quark)
+	  spi_dec_private_quark = g_quark_from_static_string ("spi-dec-private");
+  g_object_set_qdata (G_OBJECT (retval),
+		      spi_dec_private_quark,
+		      private);
   spi_dec_init_mouse_listener (registry);
-  /* TODO: kill mouse listener on finalize */
-  
+  /* TODO: kill mouse listener on finalize */  
   return retval;
 }
 
Index: registryd/deviceeventcontroller.h
===================================================================
RCS file: /cvs/gnome/at-spi/registryd/deviceeventcontroller.h,v
retrieving revision 1.12
diff -u -r1.12 deviceeventcontroller.h
--- registryd/deviceeventcontroller.h	13 Sep 2002 13:09:02 -0000	1.12
+++ registryd/deviceeventcontroller.h	18 Oct 2002 16:19:53 -0000
@@ -42,12 +42,12 @@
 #define SPI_DEVICE_EVENT_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SPI_DEVICE_EVENT_CONTROLLER_TYPE, SpiDEControllerClass))
 
 struct _SpiDEController {
-  BonoboObject parent;
-
-  SpiRegistry *registry;
-  GList       *key_listeners;
-  GList       *mouse_listeners;
-  GList       *keygrabs_list;
+	BonoboObject parent;
+	
+	SpiRegistry *registry;
+	GList       *key_listeners;
+	GList       *mouse_listeners;
+	GList       *keygrabs_list;
 };
 
 typedef struct {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]