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