diff options
| author | robert <robertrussell.72001@gmail.com> | 2022-01-08 11:40:34 -0800 | 
|---|---|---|
| committer | sinanmohd <pcmsinan@gmail.com> | 2023-01-12 08:21:56 +0530 | 
| commit | 3c4c2cffb32782f9b8df961e68c9cadca378f93a (patch) | |
| tree | 34b7f22a63e62fef200f07c9409f832bf7d22b98 | |
| parent | 80d75fa9d416030108ef1b4e6cc07e67d555aeb5 (diff) | |
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
them as presses.
| -rw-r--r-- | x.c | 86 | 
1 files changed, 51 insertions, 35 deletions
| @@ -271,7 +271,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) @@ -384,61 +384,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;  	} @@ -481,9 +488,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; @@ -492,7 +503,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. @@ -706,6 +717,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; @@ -713,7 +729,7 @@ brelease(XEvent *e)  	if (mouseaction(e, 1))  		return; -	if (e->xbutton.button == Button1) +	if (btn == Button1)  		mousesel(e, 1);  } | 
