]> Sergey Matveev's repositories - st.git/commitdiff
Fix mousereport
authorrobert <robertrussell.72001@gmail.com>
Sat, 8 Jan 2022 19:40:34 +0000 (11:40 -0800)
committerHiltjo Posthuma <hiltjo@codemadness.org>
Mon, 10 Jan 2022 16:04:01 +0000 (17:04 +0100)
This patch replaces the previous one I sent.

The following changes are made in this patch:
 - Fix tracking of pressed buttons. Previously, pressing two buttons and
   then releasing one would make st think no buttons are pressed, which
   in particular broke MODE_MOUSEMOTION.
 - Always send the lowest-numbered pressed button on motion events; when
   no button is pressed for a motion event in MODE_MOUSEMANY, then send
   a release. This matches the behaviour of xterm. (Previously, st sent
   the most recently pressed button in the motion report.)
 - Remove UB (?) access to potentially inactive struct member
   e->xbutton.button of XEvent union.
 - Fix (unlikely) possibility of overflow for large button numbers.

The one discrepancy I found between st and xterm is that xterm sometimes
encodes buttons with large numbers (>5) strangely. E.g., xterm reports
presses of buttons 8 and 9 as releases, whereas st properly (?) encodes
them as presses.

x.c

diff --git a/x.c b/x.c
index 8a16faaad0f09a0ceae0faa436fc08593e8df2a4..5f4ea734b60e44845a5ac559cc7611cd8058765e 100644 (file)
--- a/x.c
+++ b/x.c
@@ -252,7 +252,7 @@ static char *opt_line  = NULL;
 static char *opt_name  = NULL;
 static char *opt_title = NULL;
 
-static int oldbutton = 3; /* button event on startup: 3 = release */
+static uint buttons; /* bit field of pressed buttons */
 
 void
 clipcopy(const Arg *dummy)
@@ -364,61 +364,68 @@ mousesel(XEvent *e, int done)
 void
 mousereport(XEvent *e)
 {
-       int len, x = evcol(e), y = evrow(e),
-           button = e->xbutton.button, state = e->xbutton.state;
+       int len, btn, code;
+       int x = evcol(e), y = evrow(e);
+       int state = e->xbutton.state;
        char buf[40];
        static int ox, oy;
 
-       /* from urxvt */
-       if (e->xbutton.type == MotionNotify) {
+       if (e->type == MotionNotify) {
                if (x == ox && y == oy)
                        return;
                if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY))
                        return;
-               /* MOUSE_MOTION: no reporting if no button is pressed */
-               if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3)
+               /* MODE_MOUSEMOTION: no reporting if no button is pressed */
+               if (IS_SET(MODE_MOUSEMOTION) && buttons == 0)
                        return;
-
-               button = oldbutton + 32;
-               ox = x;
-               oy = y;
+               /* Set btn to lowest-numbered pressed button, or 12 if no
+                * buttons are pressed. */
+               for (btn = 1; btn <= 11 && !(buttons & (1<<(btn-1))); btn++)
+                       ;
+               code = 32;
        } else {
-               if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) {
-                       button = 3;
-               } else {
-                       button -= Button1;
-                       if (button >= 7)
-                               button += 128 - 7;
-                       else if (button >= 3)
-                               button += 64 - 3;
-               }
-               if (e->xbutton.type == ButtonPress) {
-                       oldbutton = button;
-                       ox = x;
-                       oy = y;
-               } else if (e->xbutton.type == ButtonRelease) {
-                       oldbutton = 3;
+               btn = e->xbutton.button;
+               /* Only buttons 1 through 11 can be encoded */
+               if (btn < 1 || btn > 11)
+                       return;
+               if (e->type == ButtonRelease) {
                        /* MODE_MOUSEX10: no button release reporting */
                        if (IS_SET(MODE_MOUSEX10))
                                return;
-                       if (button == 64 || button == 65)
+                       /* Don't send release events for the scroll wheel */
+                       if (btn == 4 || btn == 5)
                                return;
                }
+               code = 0;
        }
 
+       ox = x;
+       oy = y;
+
+       /* Encode btn into code. If no button is pressed for a motion event in
+        * MODE_MOUSEMANY, then encode it as a release. */
+       if ((!IS_SET(MODE_MOUSESGR) && e->type == ButtonRelease) || btn == 12)
+               code += 3;
+       else if (btn >= 8)
+               code += 128 + btn - 8;
+       else if (btn >= 4)
+               code += 64 + btn - 4;
+       else
+               code += btn - 1;
+
        if (!IS_SET(MODE_MOUSEX10)) {
-               button += ((state & ShiftMask  ) ? 4  : 0)
-                       + ((state & Mod4Mask   ) ? 8  : 0)
-                       + ((state & ControlMask) ? 16 : 0);
+               code += ((state & ShiftMask  ) ?  4 : 0)
+                     + ((state & Mod4Mask   ) ?  8 : 0)
+                     + ((state & ControlMask) ? 16 : 0);
        }
 
        if (IS_SET(MODE_MOUSESGR)) {
                len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
-                               button, x+1, y+1,
-                               e->xbutton.type == ButtonRelease ? 'm' : 'M');
+                               code, x+1, y+1,
+                               e->type == ButtonRelease ? 'm' : 'M');
        } else if (x < 223 && y < 223) {
                len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
-                               32+button, 32+x+1, 32+y+1);
+                               32+code, 32+x+1, 32+y+1);
        } else {
                return;
        }
@@ -461,9 +468,13 @@ mouseaction(XEvent *e, uint release)
 void
 bpress(XEvent *e)
 {
+       int btn = e->xbutton.button;
        struct timespec now;
        int snap;
 
+       if (1 <= btn && btn <= 11)
+               buttons |= 1 << (btn-1);
+
        if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
                mousereport(e);
                return;
@@ -472,7 +483,7 @@ bpress(XEvent *e)
        if (mouseaction(e, 0))
                return;
 
-       if (e->xbutton.button == Button1) {
+       if (btn == Button1) {
                /*
                 * If the user clicks below predefined timeouts specific
                 * snapping behaviour is exposed.
@@ -686,6 +697,11 @@ xsetsel(char *str)
 void
 brelease(XEvent *e)
 {
+       int btn = e->xbutton.button;
+
+       if (1 <= btn && btn <= 11)
+               buttons &= ~(1 << (btn-1));
+
        if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
                mousereport(e);
                return;
@@ -693,7 +709,7 @@ brelease(XEvent *e)
 
        if (mouseaction(e, 1))
                return;
-       if (e->xbutton.button == Button1)
+       if (btn == Button1)
                mousesel(e, 1);
 }