Re: support for accelerators and bindings independant of currentXKB keyboard language



On Mon, 21 Aug 2000, Vlad Harchev wrote:

> On Sun, 20 Aug 2000, Vlad Harchev wrote:
> 
>  Just to describe the idea in more detail:
> 
> > On 19 Aug 2000, Owen Taylor wrote:
> > 
> > > 
> > > Vlad Harchev <hvv@hippo.ru> writes:
> > > 
> > > >  Hi,
> > > > 
> > > >  I didn't try gtk-1.3.1 (but seems things didn't change in that respect), but
> > > > there is a localization problem for all gtk-based applications, if they are
> > > > used in environments that require support for several XKB keyboard languages
> > > > (sorry, I don't know how to better name that thing) with respect to
> > > > accelerators.
> > > > 
> > > >  Example: There is an accelerator Ctrl-F for some widget. It works fine if the
> > > > current XKB keyboard language is "english". When user switches to some other
> > > > keyboard language (say Russian, using Ctrl-Shift), pressing Ctrl-F doesn't
> > > > work at all in the way it should be. The reason for that is that gtk uses
> > > > keysym (that describes some string or character produced when pressing the
> > > > letter in the given XKB keyboard language), rather than keycode (that
> > > > identifies the key on keyboard, independant of current XKB language). As for
> > > > other widget sets - QT apps use keycode (so accelerators work independant of
> > > > the current XKB language), Win32's "widgetset" also uses "keycode", not a
> > > > "keysym". Also, in gtk all keybinding for standard widgets (like Ctrl-A for
> > > > "move to begining of line in GtkEntry") doesn't work after switching to 
> > > > non-english XKB language. So, it's a big pain to use gtk-based apps, and this 
> > > > should be fixed ASAP.
> > > > 
> > > >  So,  are gtk+ developers aware of this problem? (When) Are they going to fix
> > > > it?
> > > 
> > > I'm not really sure what you are proposing.
> > 
> >  In fact, I didn't propose how to solve that problem :)
> >  
> > > An application that actually specified keycodes for accelerators would
> > > be entirely incorrect. Keycodes are keyboard dependent, opaque
> > > values. The application needs to specify Ctrl-F. It can't specify
> > > Ctrl-41 because F will not have the value 41 on my system.
> > > 
> > > And, it would also be wrong to assume that Ctrl-F always maps to the
> > > same keycode, even on the same machine. If I remap my keyboard so that
> > > F is at a different place, then the accelerator should follow.
> > 
> >  Of course programmer shouldn't have to deal with keycodes directly. 
> >  
> > > What perhaps _should_ be the case is that if you have a key where in
> > > one keyboard group it maps to F, and in another keyboard group, it
> > > maps to Cyrillic_a, then we should treat the accelerator C-F as
> > > referring to both. Using keycodes internally to do the matching may be
> > > part of the solution but there are additional things to worry about.
> > > 
> > > The problem that is actually harder to solve (and it is a problem that
> > > GTK+ has now), is that you need to know that accelerators for 'a' and
> > > 'Shift-A' are distinct, but accelerators for 'plus' and 'Shift-plus'
> > > are identical. (Note that '+' is unshifted on some keyboards, and
> > > shifted on others.) 
> > > 
> > > Any use of keycodes certainly needs to be internal magic. I don't
> > > think it makes any sense to expose keycodes to GTK+ applications.
> > > 
> > > So, I guess what I can say is:
> > > 
> > >  * Yes, we are aware of the problem and some other ones
> > >  * If you have a proposal for a good solution, or a patch
> > >    we'd most likely be willing to accept/apply it.
> > >  * The constraints on the solution are:
> > >    - It shouldn't expose keycodes to the app developer
> > >    - It needs to handle existing sets of accelerators like
> > >      the ones the GIMP has.
> > 
> > 
> >   The problem can't be solved if gtk won't deal with keycodes internally, of
> > course. I propose addition of the following functions to gdk:
> > 	/*this calls XKeysymToKeycode*/
> > 	guint gdk_keycode_from_keyval(guint keyval);
> > 	/*this uses XKeycodeToKeysym*/
> > 	guint gdk_keyval_from_keycode(guint keycode,guint index);
> > 
> >  Also, the field 'guint keycode' should be added to the following structs:
> >  GdkEventKey, _GtkBindingEntry, _GtkAccelEntry.
> >  
> >  Prototype of no function needs to be changed - all functions that deal
> > with the modified structures should get the value of keycode theirself (e.g. 
> > gboolean    gtk_bindings_activate           (GtkObject *object,
> >                                              guint keyval,
> >                                              guint modifiers);
> >   - this function will get the keycode value itself using, so there is no need
> > to change its prototype).
> >  I think this change won't break binary compatibility (since very few programs
> > manipulate with _GtkBindingEntry and _GtkAccelEntry directly).
> > 
> >  As for exposing keycodes to applications - I think this exposure is
> > necessary, at gdk level using 2 functions I described. Keycodes could be
> > useful for app writers too, I think (but for very specific purposes).
> > 
> >  What do you think about this proposal? Does it satisfy constraints listed?
> > 
> >  Another variant would be the following:
> >  No new members or functions are added, but 'keyval' in GtkEventKey is always
> >  set to the keysym corresponding to the keycode of the real X event in the 
> >  latin-1 keyboard group (while 'string' containing the real string). I.e., 
> >  when the real keysym should be, say, Cyrillic_a (as Returned by XLookupString)
> >  , the keyevent->string is set to the string returned by XLookupString,
> >  but the keyval is set to 'f' (latin set), not the Cyrillic_a. This won't break
> >  any existing apps at all (since gtk's keyvals are not defined to mean something 
> >  particular, so they don't use it). The only use of keyval different from 
> >  comparing to some  hardcoded value (like GDK_Up) is in gtkinputdialog.c for 
> >  producing visual string for state+key combination - but its behaviour with 
> >  this hack is more desireble than without!. Probably review of gtk code would
> >  be necessary (just a 'grep keyval' :) to check that this hacklish solution 
> >  won't hurt anything.
> 
>   I meant this conversion to be performed in gdk_event_translate() of course.
> 
>   As for apps that really demand real keyval, I think the field 'guint
> realkeyval' could be added to GdkEventKey that will contain the real keysym.
> 
>   I don't know whether the similar tricks possible for other ports of gdk.
> 
>   It may be still useful to introduce the gdk_keycode_from_keyval() and
> gdk_keyval_from_keycode() too.
> 

 I composed a patch against gtk-1.2.5 and tested it with stock gnome from
RH6.2. It works fine - accelerators like Ctrl-A work in GtkEntry independant
of keyboard group and accelerators can be bound interactively to menu items
correctly. Also, everything worked fine with gedit (^V as paste works
independant of keyboard group and capslock's state).

 The only sideffect (probably, positive) for other apps is the following:
 the 'keyval' in GdkEventKey is always lowercased version of keysym (so a lot
of lame apps that don't do some sort of tolower() of it in
handler for "key-press-event" become fixed).

 I attached the patch. 
 The hunks' roadmap is:
2nd hunk is gdk_events_init() - the index of "canonical" keyboard group is
	determined

3rd hunk is the very function that does canonanization of keysyms
4th and 5th hunks are for gdk_event_translate, for KeyPress and KeyRelease
cases.

 No additions of gdk_keycode_from_keyval() and  gdk_keyval_from_keycode() as
you see.
 Probably it would be fair to add 'guint real_keyval' field to GdkEventKey.
 If new behaviour is considered inapropriate for all cases, I think it would
be nice to still add the code but enable it if some env var is set (say
GTK_SPOOF_KEYVALS) or so (since it's hard to provide the same functionality
from gmodules).
 
 Best regards,
  -Vlad

--- gdkevents.c-was	Mon Aug 21 13:23:53 2000
+++ gdkevents.c	Mon Aug 21 16:09:41 2000
@@ -129,6 +129,8 @@
 
 static GList *client_filters;	            /* Filters for client messages */
 
+static int gdk_canonical_group_index = 0; /*index used for XKeysymToKeycode*/
+
 /* FIFO's for event queue, and for events put back using
  * gdk_event_put().
  */
@@ -240,6 +242,24 @@
 
   gdk_add_client_message_filter (gdk_wm_protocols, 
 				 gdk_wm_protocols_filter, NULL);
+  {
+    /*now determine the keyboard group that contais latin letters*/	
+    int g,k;
+    for(g=0;g<12;++g) 
+      {
+        for(k=0;k<1500;++k)
+          {
+            guint keysym = XKeycodeToKeysym(gdk_display,k,g);
+            if (keysym=='a')
+              {
+                gdk_canonical_group_index =g;
+                goto done;
+              };              
+          }
+      };
+      gdk_canonical_group_index = -2;/*failed to - won't translate*/
+     done:
+  }
 }
 
 /*
@@ -969,6 +989,49 @@
   client_filters = g_list_prepend (client_filters, filter);
 }
 
+/*
+Vlad Harchev <hvv@hippo.ru>:
+    keycode_orig will be used if real_keysym is 0 (yes, XLookupString returns it
+    on my Xfree96-3.3.3 from RH6.2, when the auxilary keyboard group is active
+    (russian) and when capslock is on (the XLookupString functions returns 0 as 
+    keysym but returns correct string).
+	My xkb is configured as follows: 
+    XkbModel    "pc104"
+    XkbLayout   "ru"
+    XkbOptions "grp:ctrl_shift_toggle"	        
+*/
+static int canonalize_keysym(int real_keysym,int keycode_orig,int canonical_group)
+{
+  Display* disp;
+  guint keycode;
+  guint ret;
+  int group_index;
+    
+  disp = GDK_DISPLAY();
+  group_index = canonical_group == -1 ? gdk_canonical_group_index : canonical_group;
+
+  if (gdk_canonical_group_index==-2)
+    return real_keysym;
+  keycode = real_keysym ? XKeysymToKeycode(disp,real_keysym) : keycode_orig;
+
+  if (!keycode) /*shouldn't happen for real X Events*/
+    ret = real_keysym;    
+  else 
+    {
+      ret = XKeycodeToKeysym(disp,keycode,group_index);
+      if (ret==NoSymbol)
+        ret = real_keysym;
+    };
+#ifdef G_ENABLE_DEBUG
+  if (gdk_debug_flags & GDK_DEBUG_EVENTS)
+    {
+      g_message ("canon_keysym: from %#lx to %#lx via keycode %d",real_keysym,
+        ret,keycode);
+    }
+#endif
+  return ret;
+};
+
 static gint
 gdk_event_translate (GdkEvent *event,
 		     XEvent   *xevent)
@@ -1148,6 +1211,7 @@
 		       charcount, buf);
 	}
 #endif /* G_ENABLE_DEBUG */
+      event->key.keyval = canonalize_keysym(event->key.keyval,xevent->xkey.keycode,-1);
       
       event->key.type = GDK_KEY_PRESS;
       event->key.window = window;
@@ -1180,7 +1244,8 @@
 			   xevent->xkey.window,
 			   XKeysymToString (event->key.keyval),
 			   event->key.keyval));
-      
+			   
+      event->key.keyval = canonalize_keysym(keysym,xevent->xkey.keycode,-1);      
       event->key.type = GDK_KEY_RELEASE;
       event->key.window = window;
       event->key.time = xevent->xkey.time;






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