tFix mousereport - st - [fork] customized build of st, the simple terminal | |
git clone git://src.adamsgaard.dk/st | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit ea7cd7b62fdfa6a1fbd882d1565d557577f2cf32 | |
parent 7fb0c0cc681f36be2ad12091ef93a41671f32738 | |
Author: robert <[email protected]> | |
Date: Sat, 8 Jan 2022 11:40:34 -0800 | |
Fix mousereport | |
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 | |
tthem as presses. | |
Diffstat: | |
M x.c | 86 ++++++++++++++++++-----------… | |
1 file changed, 51 insertions(+), 35 deletions(-) | |
--- | |
diff --git a/x.c b/x.c | |
t@@ -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) | |
t@@ -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; | |
} | |
t@@ -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; | |
t@@ -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. | |
t@@ -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; | |
t@@ -693,7 +709,7 @@ brelease(XEvent *e) | |
if (mouseaction(e, 1)) | |
return; | |
- if (e->xbutton.button == Button1) | |
+ if (btn == Button1) | |
mousesel(e, 1); | |
} | |