Subject: Key binding problem, 2.1.6+

From: Lee Skinol <[email-masked]>
Date: 11 Feb 99 18:12:07 EDT

->On Wed, Feb 10, 1999 at 10:36:32PM -0400, [email-masked] wrote:
->> ->On Tue, Feb 09, 1999 at 10:05:40PM -0400, [email-masked] wrote:
->> ->> ->On Sun, Feb 07, 1999 at 02:39:46AM -0400, Lee Skinol wrote:
->> ->> ->> This worked in 2.1.5, but stopped in 2.1.6 and above.  It may
->> ->> ->> be a bug.
->> ->> ->>
->> ->> ->> Key KP_7 A M do-something
->> ->>
->> ->> ->Please try this with 2.1.6 but replace fvwm/bindngs.c with the
->> ->> ->file from 2.1.5. Does this work?
->> ->>
->> ->> Dominik,
->> ->>
->> ->> Yes, with the 2.1.5 bindings.c, it works.
->>
->> ->Huh? Now I'm really confused. Perhaps you could help me here
->> ->(since none of the maintainers sees this problem). What I ask
->> ->you to do is in no way trivial and required some experience
->> ->in C programming and debugging:
->>
->> ->What I need is to know where the differences between the two
->> ->bindings.c versions are (not the diffs of course). The function
->> ->ParseBindEntry has changed. It seems that the 2.1.6 file does
->> ->not bind the same keys as the 2.1.5 file. I don't know why.
->> ->The set of bindings in 2.1.6 should be a super set of 2.1.5.
->>
->> In bindings.c, in the 2.1.6 code, there's the following
->> loop:
->>
->>   for (i=min; i<=max; i++)
->>     if (!fKey || XKeycodeToKeysym(dpy, i, 0) == keysym)
->>     {
->>       /* Code to add binding, I think */
->>     }
->>
->> In my .fvwm2rc, I have:
->>
->>   Key KP_7        A       M       GotoPage 0 0
->>
->> With the new code, fKey is 1, min is 8, max is 134, and
->> (XKeycodeToKeysym(dpy, i, 0) == keysym) is never true, so
->> the key doesn't get added.  In the 2.1.5 code, the add
->> is done (and it *is* done) at the end of the procedure.
->>
->> Anything else I should look at?

->Bummer, I'd never have thought of that. Could you find
->out what value keysym has and what the corresponding
->keycode should be? This looks as if the XDisplayKeycodes
->function is broken on your system. Theoretically you
->should have had the same problem with 2.0.46 (?) as
->it used the same call. And perhaps you could post the
->output of 'xmodmap -pk' and 'xmodmap -pke'.

->What OS/Xserver do you have?

Redhat Linux 5.2, kernel 2.2.1.  XFree 3.3.2.

I think I've found the problem.  In 2.1.5, I bind to KP_7, but
the latest code requires that I bind it as KP_Home.  Not sure
which one is "right."

Here's the xmodmap's:

 xmodmap -pk

 There are 2 KeySyms per KeyCode; KeyCodes range from 8 to 134.

  KeyCode       Keysym (Keysym) ...
  Value         Value   (Name)  ...

    8
    9           0xff1b (Escape)
   10           0x0031 (1)      0x0021 (exclam)
   11           0x0032 (2)      0x0040 (at)
   12           0x0033 (3)      0x0023 (numbersign)
   13           0x0034 (4)      0x0024 (dollar)
   14           0x0035 (5)      0x0025 (percent)
   [snip]
   59           0x002c (comma)  0x003c (less)
   60           0x002e (period) 0x003e (greater)
   61           0x002f (slash)  0x003f (question)
   62           0xffe2 (Shift_R)
   63           0xffaa (KP_Multiply)
   64           0xffe9 (Alt_L)  0xffe7 (Meta_L)
   65           0x0020 (space)
   66           0xffe5 (Caps_Lock)
   67           0xffbe (F1)
   68           0xffbf (F2)
   69           0xffc0 (F3)
   70           0xffc1 (F4)
   71           0xffc2 (F5)
   72           0xffc3 (F6)
   73           0xffc4 (F7)
   74           0xffc5 (F8)
   75           0xffc6 (F9)
   76           0xffc7 (F10)
   77           0xff7f (Num_Lock)       0xfef9 (Pointer_EnableKeys)
   78           0xff14 (Scroll_Lock)
   79           0xff95 (KP_Home)        0xffb7 (KP_7)
   80           0xff97 (KP_Up)  0xffb8 (KP_8)
   81           0xff9a (KP_Prior)       0xffb9 (KP_9)
   82           0xffad (KP_Subtract)
   83           0xff96 (KP_Left)        0xffb4 (KP_4)
   84           0xff9d (KP_Begin)       0xffb5 (KP_5)
   85           0xff98 (KP_Right)       0xffb6 (KP_6)
   86           0xffab (KP_Add)
   87           0xff9c (KP_End) 0xffb1 (KP_1)
   88           0xff99 (KP_Down)        0xffb2 (KP_2)
   89           0xff9b (KP_Next)        0xffb3 (KP_3)
   90           0xff9e (KP_Insert)      0xffb0 (KP_0)
   91           0xff9f (KP_Delete)      0xffae (KP_Decimal)
   92
   93
   94
   95           0xffc8 (F11)
   96           0xffc9 (F12)
   97           0xff50 (Home)
   98           0xff52 (Up)
   99           0xff55 (Prior)
  100           0xff51 (Left)
  101
  102           0xff53 (Right)
  103           0xff57 (End)
  104           0xff54 (Down)
  105           0xff56 (Next)
  106           0xff63 (Insert)
  107           0xffff (Delete)
  108           0xff8d (KP_Enter)
  109           0xffe4 (Control_R)
  110           0xff13 (Pause)  0xff6b (Break)
  111           0xff61 (Print)  0xff62 (Execute)
  112           0xffaf (KP_Divide)
  113           0xffea (Alt_R)  0xffe8 (Meta_R)
  [snip]

  xmodmap -pke
>>> Continued to next message
--
Visit the official FVWM web page at <URL:http://fvwm.math.uh.edu/>.
To unsubscribe from the list, send "unsubscribe fvwm-workers" in the
body of a message to [email-masked].
To report problems, send mail to [email-masked].

---

From: Dominik Vogt <[email-masked]>
Date: Fri, 12 Feb 1999 02:02:18 +0100

> the latest code requires that I bind it as KP_Home.  Not sure
...
>    79           0xff95 (KP_Home)        0xffb7 (KP_7)

Finally I understand what is happening :) The problem is
that:

1) Multiple keycodes can be bound to the same keysym
2) Multiple keysyms can be bound to the same keycode

E.g. you could have this in your xmodmap:

  79           0xff95 (KP_Home)        0xffb7 (KP_7)
  80           0xffb7 (KP_7)           0xff95 (KP_Home)

So if you use XKeysymToKeycode on KP_7 you may either
get 79 or 80 as the return code. On the other hand, if
you only have 

XKeycodeToKeysym will return KP_Home for the keycode
79. This doesn't match what we are comparing it with.
Technically it should be forbidden to bind keysyms that
require a modifier to get them in X. Unfortunately this
is not quite clear to the average user (or even the
expert user).

A way to fix this would be to check the keysym for every
possible combination of keycode and a single modifier
(patch attached, but I don't think the patch is elegant.
It may prove way too slow).

To reproduce this bug anyone can just issue

  # xmodmap -e 'keycode 79 = KP_Home KP_7'

and put these lines in his .fvwm2rc:

  key kp_home a n menu some_menu
  key kp_7    a n menu other_menu

When you press KP_7 you get 'some_menu', not 'other_menu'
as you would expect.

----------- a few minutes later -----------------

No, the patch doesn't slow things down too much. You might
notice if you have tons of key bindings. I'll commit the
patch so that everyone can test it. Please do have a look
at it if it does the right thing.

Lee, does the patch solve your problem?

Bye

Dominik

--
Dominik Vogt, [email-masked]
Reply-To: [email-masked]
--- bindings.c.orig	Fri Feb 12 01:52:19 1999
+++ bindings.c	Fri Feb 12 02:01:33 1999
@@ -11,6 +11,7 @@
 #include "parse.h"
 #include "screen.h"
 #include "module.h"
+#include <X11/keysym.h>
 
 struct charstring
 {
@@ -118,8 +119,11 @@
   int button,i,min,max;
   int n1=0,n2=0,n3=0;
   KeySym keysym;
+  KeySym tkeysym;
   int contexts;
   int mods;
+  int maxmods;
+  int m;
 
   /* tline points after the key word "Mouse" or "Key" */
   ptr = GetNextToken(tline, &token);
@@ -228,32 +232,40 @@
   }
 
   /*
-  ** why wasn't XKeysymToKeycode used instead of this for loop?
-  ** domivogt (18-Dec-1998): because multiple key can be bound to the same
-  ** key symbol?
+  ** Unfortunately a keycode can be bound to multiple keysyms and a keysym can
+  ** be bound to multiple keycodes. Thus we have to check every keycode with
+  ** any single modifier.
   */
   if (fKey)
     {
       XDisplayKeycodes(dpy, &min, &max);
+      maxmods = 8;
     }
   else
     {
       min = button;
       max = button;
+      maxmods = 0;
     }
   for (i=min; i<=max; i++)
-    if (!fKey || XKeycodeToKeysym(dpy, i, 0) == keysym)
-    {
-      temp = Scr.AllBindings;
-      Scr.AllBindings  = (Binding *)safemalloc(sizeof(Binding));
-      Scr.AllBindings->IsMouse = !fKey;
-      Scr.AllBindings->Button_Key = i;
-      Scr.AllBindings->key_name = fKey ? stripcpy(key) : NULL;
-      Scr.AllBindings->Context = contexts;
-      Scr.AllBindings->Modifier = mods;
-      Scr.AllBindings->Action = stripcpy(action);
-      Scr.AllBindings->NextBinding = temp;
-    }
+  {
+    /* If this is a mouse binding we'll fall through the for loop (maxmods is
+     * zero) and the if condition is always true (fKey is zero). Since min ==
+     * max == button there is no loop at all is case of a mouse binding. */
+    for (m = 0, tkeysym = XK_Left; m <= maxmods && tkeysym != NoSymbol; m++)
+      if (!fKey || (tkeysym = XKeycodeToKeysym(dpy, i, m)) == keysym)
+      {
+	temp = Scr.AllBindings;
+	Scr.AllBindings = (Binding *)safemalloc(sizeof(Binding));
+	Scr.AllBindings->IsMouse = !fKey;
+	Scr.AllBindings->Button_Key = i;
+	Scr.AllBindings->key_name = fKey ? stripcpy(key) : NULL;
+	Scr.AllBindings->Context = contexts;
+	Scr.AllBindings->Modifier = mods;
+	Scr.AllBindings->Action = stripcpy(action);
+	Scr.AllBindings->NextBinding = temp;
+      }
+  }
   return;
 }