[comp.windows.x] Solutions and Insights to the translation problem

paul@tredysvr.Tredydev.Unisys.COM (Paul Siu) (01/11/91)

I have discovered the cause and a partial solution to the translation problem.
The problem is related to the virtual binding as some usenet user suggested.
I would like to go over the translation problem once again, this post will be
a bit long, but people who are having problems with translation may want to
read it.

The translation manager allows user to modify behavior add new functionality
to a widget.  A typical translation entry looks something like this:
     <Key>q:     quit()
When the user press 'q' key, the action function quit() is called.  The
left side of the is the event that you want to trigger the action function.
This event can be a button, a key, or other types of event.  For this post, we
will deal only with key events.

The X-Window system represent the code generated by the keyboard as keycode,
and represent the symbols on the keys as keysym.  The association between
keysym and keycode are store in the files "keysym.h", and "keysymdef.h".
Both file can be found in the "/usr/include/X11" directory.  A entry in the
file looks something like this:
     #define XK_Return     0xFF0D
Which basically means the keysym Return is defined as keycode 0xFF0D.  When
you press return, the keycode 0xFF0D is generated.

Motif adds another layer of Keysym abstraction.  Attempting to maintain some
sort of programming consistancy among different keyboards, a number of virtual
keysyms are define.  The virtual keysym "osfHelp" for example is binded to the
actual keysym "F1".  The programmer use the virtual keysym in his or her
program.  When the program is run on a machine with no "F1", the user simply
bind "osfHelp" to another key, running the program on the machine without any
code changes.  The binding entries can be store in a special file call
".motifbind", or it can be set in a resource "defaultVirtualBindings".
There is also a default set of virtual bindings in case you do you want to
change anything.  You can find out more about this in P. I-89 of the Motif
reference manual.  A typical binding entry in ".motifbind" will look like this:
     osfHelp:     <Key>F1
Note that virtually all the virtual binding keysym has the prefix "osf".

What does this have to do with translation?  When you specify a key event a
translation entry, you will use the virtual keysym if they are available
rather than using the actual keysym.  Instead of specifying in your table:
     <Key>Delete:     delete()
You must instead specify:
     <Key>osfDelete:  delete()
This is because osfDelete is bind to the Delete key, and when you bind a
virtual keysym to an actual keysym, the actual keysym disappear and can no
longer be reference by the translation manager.  I have no idea why this is so,
and if it is a bug or not, but I find this very annoying.

Additional problem develops when you attempt to rebind some of the keys.
Assuming that your keyboard does not have a "F1" key, so you rebind "osfHelp"
to "Escape".  In the process of doing so, all of the default binding will
become unbinded.  Your "osfDelete" for example will no longer be bind to
your "Delete" automatically.  You must add entries to rebind every virtual
keysym to an actual keysym.  Virtual keysyms that are not rebind cannot be
used.  If rebinding "osfHelp" breaks the bind on "osfDelete", pressing the
"osfDelete" key will not work until it is rebinded.

It boils down to a few simple rules:
1. Motif binds virtual keysym to an actual keysym.  After the binding, you can
   no longer reference the actual keysym directly in a translation entry,
   but you can reference the it indirectly through the virtual keysym.  In any
   case, I think you are supposed to use the virtual keysym in place of the
   actual keysym

2. There exist a set of default virtual keysym which will become unbind if one
   or more virtual keysym are rebinded.  When you rebind one keysym, you must
   rebind all.

3. There seems to be a problem with override.  There are currently 3 methods
   to override the translation table.  You can do this in the resource file,
   you can use XtSetArg(), and you can use XtOverrideTranslations().
   According to definitioin, override is supposed to merge your tranlation
   table into the widget's translation table, overriding any overlaps.
   Unfortunately, the order after the merge seems a little rearranged.

   Let's look at an example of an override that failed.  One of the text
   widget's translation entry is "KAny" (see XmText in Motif Ref), which
   basically stands for "<Key>" (see VirtualBindings in Motif Ref).  Currently,
   "KAny" activates the action procedure self-insert(), it is placed as the
   last entry of the translation table, so it will not conflict with the other
   translation entries (It is a rule that you should always specify the more
   specific translation entry before the less specific.).  Let say I override
   the "KAny" of the text widget by setting it to activate the function
   self-insert(), the text widget's behavior should remain unchanged because I
   simply override it with the same function.  This does not happen, the text
   widget now self-inserts any key, as if it "KAny" had become the first
   entry in the text widget's translation table.  This problem occur no matter
   which override method you choose.  I have no idea of how to get around this
   short of using replacing the entire translation table.
   
In any case, I said my 2 cents worth.  All comments, and corrections  will be
welcome.

Paul Siu
paul@tredysvr.tredydev.unisys.com

ben@hpcvlx.cv.hp.com (Benjamin Ellsworth) (01/11/91)

> ... the text widget now self-inserts any key, as if it "KAny" had
> become the first entry in the text widget's translation table.

Because that is exactly what happened.

> This problem occur no matter which override method you choose.  I
> have no idea of how to get around this short of using replacing the
> entire translation table.

Me neither.