Re: support for accelerators and bindings independant of currentXKB keyboard language
- From: Vlad Harchev <hvv hippo ru>
- To: gtk-devel-list gnome org
- Subject: Re: support for accelerators and bindings independant of currentXKB keyboard language
- Date: Mon, 21 Aug 2000 21:45:55 +0500 (SAMST)
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]