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:
		
							parent
							
								
									7fb0c0cc68
								
							
						
					
					
						commit
						ea7cd7b62f
					
				
					 1 changed files with 51 additions and 35 deletions
				
			
		
							
								
								
									
										86
									
								
								x.c
									
										
									
									
									
								
							
							
						
						
									
										86
									
								
								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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue