diff options
author | robert <robertrussell.72001@gmail.com> | 2022-01-08 11:40:34 -0800 |
---|---|---|
committer | Hiltjo Posthuma <hiltjo@codemadness.org> | 2022-01-10 17:04:01 +0100 |
commit | ea7cd7b62fdfa6a1fbd882d1565d557577f2cf32 (patch) | |
tree | 5eafff9b5a615369874408a9820471982ac727b3 | |
parent | 7fb0c0cc681f36be2ad12091ef93a41671f32738 (diff) | |
download | st-patched-ea7cd7b62fdfa6a1fbd882d1565d557577f2cf32.tar.bz2 st-patched-ea7cd7b62fdfa6a1fbd882d1565d557577f2cf32.tar.xz st-patched-ea7cd7b62fdfa6a1fbd882d1565d557577f2cf32.zip |
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
@@ -252,7 +252,7 @@ static char *opt_line = NULL; | |||
252 | static char *opt_name = NULL; | 252 | static char *opt_name = NULL; |
253 | static char *opt_title = NULL; | 253 | static char *opt_title = NULL; |
254 | 254 | ||
255 | static int oldbutton = 3; /* button event on startup: 3 = release */ | 255 | static uint buttons; /* bit field of pressed buttons */ |
256 | 256 | ||
257 | void | 257 | void |
258 | clipcopy(const Arg *dummy) | 258 | clipcopy(const Arg *dummy) |
@@ -364,61 +364,68 @@ mousesel(XEvent *e, int done) | |||
364 | void | 364 | void |
365 | mousereport(XEvent *e) | 365 | mousereport(XEvent *e) |
366 | { | 366 | { |
367 | int len, x = evcol(e), y = evrow(e), | 367 | int len, btn, code; |
368 | button = e->xbutton.button, state = e->xbutton.state; | 368 | int x = evcol(e), y = evrow(e); |
369 | int state = e->xbutton.state; | ||
369 | char buf[40]; | 370 | char buf[40]; |
370 | static int ox, oy; | 371 | static int ox, oy; |
371 | 372 | ||
372 | /* from urxvt */ | 373 | if (e->type == MotionNotify) { |
373 | if (e->xbutton.type == MotionNotify) { | ||
374 | if (x == ox && y == oy) | 374 | if (x == ox && y == oy) |
375 | return; | 375 | return; |
376 | if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY)) | 376 | if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY)) |
377 | return; | 377 | return; |
378 | /* MOUSE_MOTION: no reporting if no button is pressed */ | 378 | /* MODE_MOUSEMOTION: no reporting if no button is pressed */ |
379 | if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3) | 379 | if (IS_SET(MODE_MOUSEMOTION) && buttons == 0) |
380 | return; | 380 | return; |
381 | 381 | /* Set btn to lowest-numbered pressed button, or 12 if no | |
382 | button = oldbutton + 32; | 382 | * buttons are pressed. */ |
383 | ox = x; | 383 | for (btn = 1; btn <= 11 && !(buttons & (1<<(btn-1))); btn++) |
384 | oy = y; | 384 | ; |
385 | code = 32; | ||
385 | } else { | 386 | } else { |
386 | if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) { | 387 | btn = e->xbutton.button; |
387 | button = 3; | 388 | /* Only buttons 1 through 11 can be encoded */ |
388 | } else { | 389 | if (btn < 1 || btn > 11) |
389 | button -= Button1; | 390 | return; |
390 | if (button >= 7) | 391 | if (e->type == ButtonRelease) { |
391 | button += 128 - 7; | ||
392 | else if (button >= 3) | ||
393 | button += 64 - 3; | ||
394 | } | ||
395 | if (e->xbutton.type == ButtonPress) { | ||
396 | oldbutton = button; | ||
397 | ox = x; | ||
398 | oy = y; | ||
399 | } else if (e->xbutton.type == ButtonRelease) { | ||
400 | oldbutton = 3; | ||
401 | /* MODE_MOUSEX10: no button release reporting */ | 392 | /* MODE_MOUSEX10: no button release reporting */ |
402 | if (IS_SET(MODE_MOUSEX10)) | 393 | if (IS_SET(MODE_MOUSEX10)) |
403 | return; | 394 | return; |
404 | if (button == 64 || button == 65) | 395 | /* Don't send release events for the scroll wheel */ |
396 | if (btn == 4 || btn == 5) | ||
405 | return; | 397 | return; |
406 | } | 398 | } |
399 | code = 0; | ||
407 | } | 400 | } |
408 | 401 | ||
402 | ox = x; | ||
403 | oy = y; | ||
404 | |||
405 | /* Encode btn into code. If no button is pressed for a motion event in | ||
406 | * MODE_MOUSEMANY, then encode it as a release. */ | ||
407 | if ((!IS_SET(MODE_MOUSESGR) && e->type == ButtonRelease) || btn == 12) | ||
408 | code += 3; | ||
409 | else if (btn >= 8) | ||
410 | code += 128 + btn - 8; | ||
411 | else if (btn >= 4) | ||
412 | code += 64 + btn - 4; | ||
413 | else | ||
414 | code += btn - 1; | ||
415 | |||
409 | if (!IS_SET(MODE_MOUSEX10)) { | 416 | if (!IS_SET(MODE_MOUSEX10)) { |
410 | button += ((state & ShiftMask ) ? 4 : 0) | 417 | code += ((state & ShiftMask ) ? 4 : 0) |
411 | + ((state & Mod4Mask ) ? 8 : 0) | 418 | + ((state & Mod4Mask ) ? 8 : 0) |
412 | + ((state & ControlMask) ? 16 : 0); | 419 | + ((state & ControlMask) ? 16 : 0); |
413 | } | 420 | } |
414 | 421 | ||
415 | if (IS_SET(MODE_MOUSESGR)) { | 422 | if (IS_SET(MODE_MOUSESGR)) { |
416 | len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", | 423 | len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", |
417 | button, x+1, y+1, | 424 | code, x+1, y+1, |
418 | e->xbutton.type == ButtonRelease ? 'm' : 'M'); | 425 | e->type == ButtonRelease ? 'm' : 'M'); |
419 | } else if (x < 223 && y < 223) { | 426 | } else if (x < 223 && y < 223) { |
420 | len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", | 427 | len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", |
421 | 32+button, 32+x+1, 32+y+1); | 428 | 32+code, 32+x+1, 32+y+1); |
422 | } else { | 429 | } else { |
423 | return; | 430 | return; |
424 | } | 431 | } |
@@ -461,9 +468,13 @@ mouseaction(XEvent *e, uint release) | |||
461 | void | 468 | void |
462 | bpress(XEvent *e) | 469 | bpress(XEvent *e) |
463 | { | 470 | { |
471 | int btn = e->xbutton.button; | ||
464 | struct timespec now; | 472 | struct timespec now; |
465 | int snap; | 473 | int snap; |
466 | 474 | ||
475 | if (1 <= btn && btn <= 11) | ||
476 | buttons |= 1 << (btn-1); | ||
477 | |||
467 | if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { | 478 | if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { |
468 | mousereport(e); | 479 | mousereport(e); |
469 | return; | 480 | return; |
@@ -472,7 +483,7 @@ bpress(XEvent *e) | |||
472 | if (mouseaction(e, 0)) | 483 | if (mouseaction(e, 0)) |
473 | return; | 484 | return; |
474 | 485 | ||
475 | if (e->xbutton.button == Button1) { | 486 | if (btn == Button1) { |
476 | /* | 487 | /* |
477 | * If the user clicks below predefined timeouts specific | 488 | * If the user clicks below predefined timeouts specific |
478 | * snapping behaviour is exposed. | 489 | * snapping behaviour is exposed. |
@@ -686,6 +697,11 @@ xsetsel(char *str) | |||
686 | void | 697 | void |
687 | brelease(XEvent *e) | 698 | brelease(XEvent *e) |
688 | { | 699 | { |
700 | int btn = e->xbutton.button; | ||
701 | |||
702 | if (1 <= btn && btn <= 11) | ||
703 | buttons &= ~(1 << (btn-1)); | ||
704 | |||
689 | if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { | 705 | if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { |
690 | mousereport(e); | 706 | mousereport(e); |
691 | return; | 707 | return; |
@@ -693,7 +709,7 @@ brelease(XEvent *e) | |||
693 | 709 | ||
694 | if (mouseaction(e, 1)) | 710 | if (mouseaction(e, 1)) |
695 | return; | 711 | return; |
696 | if (e->xbutton.button == Button1) | 712 | if (btn == Button1) |
697 | mousesel(e, 1); | 713 | mousesel(e, 1); |
698 | } | 714 | } |
699 | 715 | ||