Fixes for #92143 and #109776; we now support string keysynthesis
authorbillh <billh@e2bd861d-eb25-0410-b326-f6ed22b6b98c>
Tue, 10 Jun 2003 20:40:32 +0000 (20:40 +0000)
committerbillh <billh@e2bd861d-eb25-0410-b326-f6ed22b6b98c>
Tue, 10 Jun 2003 20:40:32 +0000 (20:40 +0000)
for most Latin locales, and correctly set modifiers when synthesizing
keysyms.

git-svn-id: http://svn.gnome.org/svn/at-spi/trunk@439 e2bd861d-eb25-0410-b326-f6ed22b6b98c

ChangeLog
configure.in
cspi/spi_registry.c
registryd/deviceeventcontroller.c
test/Makefile.am

index ed3ba08..f85cfbb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,39 @@
+2003-06-10  Bill Haneman <bill.haneman@sun.com>
+
+
+       * configure.in: Version revved to 1.3.2, lt 0.9.2
+       Incremented ATK required version to 1.3.4.
+
+       * cspi/spi_registry.c:
+       (SPI_generateKeyEvent):
+       We now pass the keystring along if it's non-null.
+       
+       * registryd/deviceeventcontroller.c:
+       (keysym_mod_mask): New method, returns modifier mask 
+       required to generate a keysym from a given keycode.
+       (dec_synth_keysym): New method.
+       (dec_synth_keystring): New method.
+       (dec_get_modifier_state): New method.
+       (dec_lock_modifiers): New
+       (dec_unlock_modifiers): New.
+       (dec_keysym_for_unichar): New, rather brute-force
+       conversion from UCS-4 to X KeySyms.  Only works for
+       Latin at the moment, with partial implementations for
+       Greek, Hebrew, and (incomplete) Katakana.
+       (impl_generate_keyboard_event): Now implement 
+       "KEYSTRING" synthesis and implement "KEYSYM"
+       synthesis properly.
+       (keycode_from_keysym): Improved, passes a returned
+       modmask value now if the corresponding param is non-NULL.
+       
+       Fixes bugs #92143  and #109776.
+
+       * test/Makefile.am:
+       * test/keysynth-test.c:
+       New test program for key synthesis, to confirm fixes for
+       above bugs.
+
+
 2003-06-10  Padraig O'Briain <padraig.obriain@sun.com>
 
        * cspi/spi.h: Add relation SPI_RELATION_POPUP_FOR
index 3f21245..74bc7df 100644 (file)
@@ -2,9 +2,9 @@ AC_INIT(idl/Accessibility.idl)
 
 AT_SPI_MAJOR_VERSION=1
 AT_SPI_MINOR_VERSION=3
-AT_SPI_MICRO_VERSION=1
-AT_SPI_INTERFACE_AGE=1
-AT_SPI_BINARY_AGE=0
+AT_SPI_MICRO_VERSION=2
+AT_SPI_INTERFACE_AGE=2
+AT_SPI_BINARY_AGE=2
 AT_SPI_VERSION="$AT_SPI_MAJOR_VERSION.$AT_SPI_MINOR_VERSION.$AT_SPI_MICRO_VERSION"
 AM_INIT_AUTOMAKE(at-spi, $AT_SPI_VERSION)
 AC_SUBST(AT_SPI_MAJOR_VERSION)
@@ -16,7 +16,7 @@ AC_SUBST(AT_SPI_BINARY_AGE)
 # libtool versioning
 LT_RELEASE=$AT_SPI_MAJOR_VERSION.$AT_SPI_MINOR_VERSION
 LT_CURRENT=9
-LT_REVISION=1
+LT_REVISION=2
 LT_AGE=9
 LT_VERSION_INFO='-version-info ${LT_CURRENT}:${LT_REVISION}:${LT_AGE}'
 AC_SUBST(LT_VERSION_INFO)
@@ -125,7 +125,7 @@ AC_SUBST(REGISTRYD_CFLAGS)
 
 PKG_CHECK_MODULES(TESTS, \
        libbonobo-2.0 >= 1.107.0 \
-       atk >= 1.3.0 \
+       atk >= 1.3.4 \
        gtk+-2.0 > 2.0.0 \
        gail >= 1.3.0)
 AC_SUBST(TESTS_LIBS)
index 610d0f9..feb3bac 100644 (file)
@@ -601,11 +601,6 @@ SPI_generateKeyboardEvent (long int keyval,
                           char *keystring,
                           AccessibleKeySynthType synth_type)
 {
-/* TODO: check current modifier status and
- *  send keycode to alter, if necessary
- */
-       
-  /* TODO: implement keystring use case */
   Accessibility_KeySynthType keysynth_type;
   Accessibility_DeviceEventController device_event_controller = 
          Accessibility_Registry_getDeviceEventController (cspi_registry (), cspi_ev ());
@@ -635,7 +630,7 @@ SPI_generateKeyboardEvent (long int keyval,
 
   Accessibility_DeviceEventController_generateKeyboardEvent (device_event_controller,
                                                             keyval,
-                                                            "",
+                                                            keystring ? keystring : "",
                                                             keysynth_type,
                                                             cspi_ev ());
 
index 609deea..6edf938 100644 (file)
@@ -139,10 +139,60 @@ static gboolean spi_dec_poll_mouse_idle (gpointer data);
 
 /* Private methods */
 
+static unsigned int
+keysym_mod_mask (KeySym keysym, KeyCode keycode)
+{
+       /* we really should use XKB and look directly at the keymap */
+       /* this is very inelegant */
+       Display *display = spi_get_display ();
+       unsigned int mods_rtn = 0;
+       unsigned int retval = 0;
+       KeySym sym_rtn;
+
+       if (XkbLookupKeySym (display, keycode, 0, &mods_rtn, &sym_rtn) &&
+           (sym_rtn == keysym)) {
+               retval = 0;
+       }
+       else if (XkbLookupKeySym (display, keycode, ShiftMask, &mods_rtn, &sym_rtn) &&
+                (sym_rtn == keysym)) {
+               retval = ShiftMask;
+       }
+       else if (XkbLookupKeySym (display, keycode, Mod2Mask, &mods_rtn, &sym_rtn) &&
+                (sym_rtn == keysym)) {
+               retval = Mod2Mask;
+       }
+       else if (XkbLookupKeySym (display, keycode, Mod3Mask, &mods_rtn, &sym_rtn) &&
+                (sym_rtn == keysym)) {
+               retval = Mod3Mask;
+       }
+       else if (XkbLookupKeySym (display, keycode, 
+                                 ShiftMask | Mod2Mask, &mods_rtn, &sym_rtn) &&
+                (sym_rtn == keysym)) {
+               retval = (Mod2Mask | ShiftMask);
+       }
+       else if (XkbLookupKeySym (display, keycode, 
+                                 ShiftMask | Mod3Mask, &mods_rtn, &sym_rtn) &&
+                (sym_rtn == keysym)) {
+               retval = (Mod3Mask | ShiftMask);
+       }
+       else if (XkbLookupKeySym (display, keycode, 
+                                 ShiftMask | Mod4Mask, &mods_rtn, &sym_rtn) &&
+                (sym_rtn == keysym)) {
+               retval = (Mod4Mask | ShiftMask);
+       }
+       else
+               retval = 0xFFFF;
+       return retval;
+}
+
 static KeyCode
-keycode_for_keysym (long keysym)
+keycode_for_keysym (long keysym, unsigned int *modmask)
 {
-  return XKeysymToKeycode (spi_get_display (), (KeySym) keysym);
+       KeyCode keycode = 0;
+       keycode = XKeysymToKeycode (spi_get_display (), (KeySym) keysym);
+       if (modmask) 
+               *modmask = keysym_mod_mask (keysym, keycode);
+       return keycode;
 }
 
 static DEControllerGrabMask *
@@ -1415,7 +1465,7 @@ spi_controller_update_key_grabs (SpiDEController           *controller,
 
       re_issue_grab = recv &&
              (recv->modifiers & grab_mask->mod_mask) &&
-             (grab_mask->key_val == keycode_for_keysym (recv->id));
+             (grab_mask->key_val == keycode_for_keysym (recv->id, NULL));
 
 #ifdef SPI_DEBUG
       fprintf (stderr, "mask=%lx %lx (%c%c) %s\n",
@@ -1823,6 +1873,157 @@ dec_synth_keycode_release (SpiDEController *controller,
        return TRUE;
 }
 
+static unsigned
+dec_get_modifier_state (SpiDEController *controller)
+{
+       return mouse_mask_state;
+}
+
+static gboolean
+dec_lock_modifiers (SpiDEController *controller, unsigned modifiers)
+{
+       return XkbLockModifiers (spi_get_display (), XkbUseCoreKbd, 
+                         modifiers, modifiers);
+}
+
+static gboolean
+dec_unlock_modifiers (SpiDEController *controller, unsigned modifiers)
+{
+       return XkbLockModifiers (spi_get_display (), XkbUseCoreKbd, 
+                         modifiers, 0);
+}
+
+dec_keysym_for_unichar (SpiDEController *controller, gunichar unichar)
+{
+       /* TODO: table lookups within a range, for various code pages! */
+       KeySym keysym = NoSymbol;
+
+       if (unichar >= 0x20 && unichar < 0x7f) { /* Basic Latin/ASCII */
+               keysym = (KeySym) unichar;
+       }
+       else if (unichar >= 0xa0 && unichar <= 0xff) { /* Latin 1 extensions */
+               keysym = (KeySym) unichar;
+       }
+       else if (unichar >= 0x100 && unichar <= 0x233) { /* unfortunately the mapping gets nasty for Latin-2 and 3... help! */
+               keysym = NoSymbol;
+       }
+       else if (unichar >= 0x7c1 && unichar <= 0x3a1) { /* let's try Greek anyway... */
+               keysym = (KeySym) (0x391 + (unichar - 0x7c1));
+       }
+       else if (unichar >= 0x3a3 && unichar <= 0x3a9) { /* let's try Greek anyway... */
+               keysym = (KeySym) (0x7d2 + (unichar - 0x3a3));
+       }
+       else if (unichar >= 0x3b1 && unichar <= 0x3c1) { /* let's try Greek anyway... */
+               keysym = (KeySym) (0x7e1 + (unichar - 0x3b1));
+       }
+       else if (unichar == 0x3c2) {
+               keysym = (KeySym) 0x7f3; /* XK_Greek_finalsmallsigma; */
+       }
+       else if (unichar >= 0x3c3 && unichar <= 0x3c9) { /* let's try Greek anyway... */
+               keysym = (KeySym) (0x7f2 + (unichar - 0x3c2));
+       }       
+       else if (unichar >= 0x5d0 && unichar <= 0x5ea) { /* Hebrew basics */
+               /* probably broken :-) */
+               keysym = (KeySym) (0xce0 + (unichar - 0x5d0));
+       }       
+       else if (unichar >= 0x30a1 && unichar <= 0x30ab) { /* partial katakana support */
+               /* TODO: complete! */
+               keysym = (KeySym) (0x4b1 + (unichar - 0x30a1)/2);
+       }
+       else if (unichar >= 0x20a0 && unichar <= 0x20ac) { /* currency */
+               keysym = (KeySym) unichar; /* how convenient ;-) */
+       }
+       return keysym;
+}
+
+static gboolean
+dec_synth_keysym (SpiDEController *controller, KeySym keysym)
+{
+       KeyCode key_synth_code;
+       unsigned int modifiers, synth_mods, lock_mods;
+
+       key_synth_code = keycode_for_keysym (keysym, &synth_mods);
+
+       if ((key_synth_code == 0) || (synth_mods == 0xFF)) return FALSE;
+
+       /* TODO: set the modifiers accordingly! */
+       modifiers = dec_get_modifier_state (controller);
+       /* side-effect; we may unset mousebutton modifiers here! */
+
+       if (synth_mods != modifiers) {
+               lock_mods = synth_mods & ~modifiers;
+               dec_lock_modifiers (controller, lock_mods);
+       }
+       dec_synth_keycode_press (controller, key_synth_code);
+       dec_synth_keycode_release (controller, key_synth_code);
+       if (synth_mods != modifiers) 
+               dec_unlock_modifiers (controller, lock_mods);
+       return TRUE;
+}
+
+
+static gboolean
+dec_synth_keystring (SpiDEController *controller, const CORBA_char *keystring)
+{
+       /* probably we need to create and inject an XIM handler eventually. */
+       /* for now, try to match the string to existing 
+        * keycode+modifier states. 
+         */
+       KeySym *keysyms;
+       gint maxlen = 0;
+       gunichar unichar = 0;
+       gint i = 0;
+       gboolean retval = TRUE;
+       const gchar *c;
+
+       maxlen = strlen (keystring);
+       keysyms = g_new0 (KeySym, maxlen);
+       if (!(keystring && *keystring && g_utf8_validate (keystring, -1, &c))) { 
+               retval = FALSE;
+       } 
+       else {
+#ifdef SPI_DEBUG
+               fprintf (stderr, "[keystring synthesis attempted on %s]\n", keystring);
+#endif
+               while (keystring && (unichar = g_utf8_get_char (keystring))) {
+                       KeySym keysym;
+                       char bytes[6];
+                       gint mbytes;
+                       
+                       mbytes = g_unichar_to_utf8 (unichar, bytes);
+                       bytes[mbytes] = '\0';
+#ifdef SPI_DEBUG
+                       fprintf (stderr, "[unichar %s]", bytes);
+#endif
+                       keysym = dec_keysym_for_unichar (controller, unichar);
+                       if (keysym == NoSymbol) {
+#ifdef SPI_DEBUG
+                               fprintf (stderr, "no keysym for %s", bytes);
+#endif
+                               retval = FALSE;
+                               break;
+                       }
+                       keysyms[i++] = keysym;
+                       keystring = g_utf8_next_char (keystring); 
+               }
+               keysyms[i++] = 0;
+               for (i = 0; keysyms[i]; ++i) {
+                       if (!dec_synth_keysym (controller, keysyms[i])) {
+#ifdef SPI_DEBUG
+                               fprintf (stderr, "could not synthesize %c\n",
+                                        (int) keysyms[i]);
+#endif
+                               retval = FALSE;
+                               break;
+                       }
+               }
+       }
+       g_free (keysyms);
+
+       return retval;
+}
+
+
 /*
  * CORBA Accessibility::DEController::registerKeystrokeListener
  *     method implementation
@@ -1868,12 +2069,17 @@ impl_generate_keyboard_event (PortableServer_Servant           servant,
 #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);
+             /* 
+              * note: we are using long for 'keycode'
+              * in our arg list; it can contain either
+              * a keycode or a keysym.
+              */
+             dec_synth_keysym (controller, (KeySym) keycode);
              break;
       case Accessibility_KEY_STRING:
-             fprintf (stderr, "Not yet implemented\n");
+             if (!dec_synth_keystring (controller, keystring))
+                     fprintf (stderr, "Keystring synthesis failure, string=%s\n",
+                              keystring);
              break;
     }
   if (gdk_error_trap_pop ())
index 4d18d5a..31078d0 100644 (file)
@@ -1,6 +1,8 @@
 NULL=
 
-noinst_PROGRAMS = test-simple at app simple-at stress-test keysynth-demo key-listener-test event-listener-test window-listener-test screen-review-test visual-bell keypad-test
+noinst_PROGRAMS = test-simple at app simple-at stress-test keysynth-demo key-listener-test event-listener-test window-listener-test screen-review-test keypad-test keysynth-test
+
+keysynth_test_SOURCES = keysynth-test.c
 
 stress_test_SOURCES = stress-test.c
 
@@ -10,8 +12,6 @@ keypad_test_SOURCES = keypad-test.c
 
 key_listener_test_SOURCES = key-listener-test.c
 
-visual_bell_SOURCES = visual-bell.c
-
 event_listener_test_SOURCES = event-listener-test.c
 
 screen_review_test_SOURCES = screen-review-test.c