Fix horizontal wheel events not being reported to client programs when they grab the mouse

Fixes #2819
This commit is contained in:
Kovid Goyal 2022-06-18 06:47:42 +05:30
parent 3a9c6088b2
commit a89e1b5573
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 78 additions and 54 deletions

View File

@ -45,6 +45,8 @@ Detailed list of changes
- Allow resizing windows created in session files (:pull:`5196`) - Allow resizing windows created in session files (:pull:`5196`)
- Fix horizontal wheel events not being reported to client programs when they grab the mouse (:iss:`2819`)
0.25.2 [2022-06-07] 0.25.2 [2022-06-07]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -109,17 +109,17 @@ class TermManager:
class MouseButton(IntFlag): class MouseButton(IntFlag):
NONE, LEFT, MIDDLE, RIGHT, FOURTH, FIFTH = 0, 1, 2, 4, 8, 16 NONE, LEFT, MIDDLE, RIGHT, FOURTH, FIFTH, SIXTH, SEVENTH = 0, 1, 2, 4, 8, 16, 32, 64
WHEEL_UP, WHEEL_DOWN = -1, -2 WHEEL_UP, WHEEL_DOWN, WHEEL_LEFT, WHEEL_RIGHT = -1, -2, -4, -8
bmap = {0: MouseButton.LEFT, 1: MouseButton.MIDDLE, 2: MouseButton.RIGHT} bmap = MouseButton.LEFT, MouseButton.MIDDLE, MouseButton.RIGHT
ebmap = MouseButton.FOURTH, MouseButton.FIFTH, MouseButton.SIXTH, MouseButton.SEVENTH
wbmap = MouseButton.WHEEL_UP, MouseButton.WHEEL_DOWN, MouseButton.WHEEL_LEFT, MouseButton.WHEEL_RIGHT
SHIFT_INDICATOR = 1 << 2 SHIFT_INDICATOR = 1 << 2
ALT_INDICATOR = 1 << 3 ALT_INDICATOR = 1 << 3
CTRL_INDICATOR = 1 << 4 CTRL_INDICATOR = 1 << 4
MOTION_INDICATOR = 1 << 5 MOTION_INDICATOR = 1 << 5
SCROLL_BUTTON_INDICATOR = 1 << 6
EXTRA_BUTTON_INDICATOR = 1 << 7
class EventType(Enum): class EventType(Enum):
@ -150,13 +150,12 @@ def decode_sgr_mouse(text: str, screen_size: ScreenSize) -> MouseEvent:
typ = EventType.RELEASE if m == 'm' else (EventType.MOVE if cb & MOTION_INDICATOR else EventType.PRESS) typ = EventType.RELEASE if m == 'm' else (EventType.MOVE if cb & MOTION_INDICATOR else EventType.PRESS)
buttons: MouseButton = MouseButton.NONE buttons: MouseButton = MouseButton.NONE
cb3 = cb & 3 cb3 = cb & 3
if cb3 != 3: if cb >= 128:
if cb & SCROLL_BUTTON_INDICATOR: buttons |= ebmap[cb3]
buttons = MouseButton.WHEEL_DOWN if cb3 & 1 else MouseButton.WHEEL_UP elif cb >= 64:
elif cb & EXTRA_BUTTON_INDICATOR: buttons |= wbmap[cb3]
buttons |= MouseButton.FIFTH if cb3 & 1 else MouseButton.FOURTH elif cb3 < 3:
else: buttons |= bmap[cb3]
buttons |= bmap[cb3]
mods = 0 mods = 0
if cb & SHIFT_INDICATOR: if cb & SHIFT_INDICATOR:
mods |= SHIFT mods |= SHIFT

View File

@ -135,8 +135,8 @@ encode_mouse_button(Window *w, int button, MouseAction action, int mods) {
} }
static int static int
encode_mouse_scroll(Window *w, bool upwards, int mods) { encode_mouse_scroll(Window *w, int button, int mods) {
return encode_mouse_event(w, upwards ? 4 : 5, PRESS, mods); return encode_mouse_event(w, button, PRESS, mods);
} }
// }}} // }}}
@ -815,6 +815,38 @@ mouse_event(const int button, int modifiers, int action) {
if (mouse_cursor_shape != old_cursor) set_mouse_cursor(mouse_cursor_shape); if (mouse_cursor_shape != old_cursor) set_mouse_cursor(mouse_cursor_shape);
} }
static int
scale_scroll(Screen *screen, double offset, bool is_high_resolution, double *pending_scroll_pixels, int cell_size) {
// scale the scroll by the multiplier unless the mouse is grabbed. If the mouse is grabbed only change direction.
#define SCALE_SCROLL(which) { double scale = OPT(which); if (screen->modes.mouse_tracking_mode) scale /= fabs(scale); offset *= scale; }
int s = 0;
if (is_high_resolution) {
SCALE_SCROLL(touch_scroll_multiplier);
double pixels = *pending_scroll_pixels + offset;
if (fabs(pixels) < cell_size) {
*pending_scroll_pixels = pixels;
return 0;
}
s = (int)round(pixels) / cell_size;
*pending_scroll_pixels = pixels - s * cell_size;
} else {
SCALE_SCROLL(wheel_scroll_multiplier);
s = (int) round(offset);
if (offset != 0) {
const int min_lines = screen->modes.mouse_tracking_mode ? 1 : OPT(wheel_scroll_min_lines);
if (min_lines > 0 && abs(s) < min_lines) s = offset > 0 ? min_lines : -min_lines;
// Always add the minimum number of lines when it is negative
else if (min_lines < 0) s = offset > 0 ? s - min_lines : s + min_lines;
// apparently on cocoa some mice generate really small yoffset values
// when scrolling slowly https://github.com/kovidgoyal/kitty/issues/1238
if (s == 0) s = offset > 0 ? 1 : -1;
}
*pending_scroll_pixels = 0;
}
return s;
#undef SCALE_SCROLL
}
void void
scroll_event(double xoffset, double yoffset, int flags, int modifiers) { scroll_event(double xoffset, double yoffset, int flags, int modifiers) {
debug("\x1b[36mScroll\x1b[m xoffset: %f yoffset: %f flags: %x modifiers: %s\n", xoffset, yoffset, flags, format_mods(modifiers)); debug("\x1b[36mScroll\x1b[m xoffset: %f yoffset: %f flags: %x modifiers: %s\n", xoffset, yoffset, flags, format_mods(modifiers));
@ -874,51 +906,42 @@ scroll_event(double xoffset, double yoffset, int flags, int modifiers) {
default: default:
break; break;
} }
if (yoffset == 0.0) return;
int s; int s;
bool is_high_resolution = flags & 1; bool is_high_resolution = flags & 1;
// scale the scroll by the multiplier unless the mouse is grabbed. If the mouse is grabbed only change direction. if (yoffset != 0.0) {
#define SCALE_SCROLL(which) { double scale = OPT(which); if (screen->modes.mouse_tracking_mode) scale /= fabs(scale); yoffset *= scale; } s = scale_scroll(screen, yoffset, is_high_resolution, &screen->pending_scroll_pixels_y, global_state.callback_os_window->fonts_data->cell_height);
if (is_high_resolution) { if (s) {
SCALE_SCROLL(touch_scroll_multiplier); bool upwards = s > 0;
double pixels = screen->pending_scroll_pixels + yoffset; if (screen->modes.mouse_tracking_mode) {
if (fabs(pixels) < global_state.callback_os_window->fonts_data->cell_height) { int sz = encode_mouse_scroll(w, upwards ? 4 : 5, modifiers);
screen->pending_scroll_pixels = pixels; if (sz > 0) {
return; mouse_event_buf[sz] = 0;
} for (s = abs(s); s > 0; s--) {
s = (int)round(pixels) / (int)global_state.callback_os_window->fonts_data->cell_height; write_escape_code_to_child(screen, CSI, mouse_event_buf);
screen->pending_scroll_pixels = pixels - s * (int) global_state.callback_os_window->fonts_data->cell_height; }
} else { }
SCALE_SCROLL(wheel_scroll_multiplier); } else {
s = (int) round(yoffset); if (screen->linebuf == screen->main_linebuf) screen_history_scroll(screen, abs(s), upwards);
if (yoffset != 0) { else fake_scroll(w, abs(s), upwards);
const int min_lines = screen->modes.mouse_tracking_mode ? 1 : OPT(wheel_scroll_min_lines);
if (min_lines > 0 && abs(s) < min_lines) s = yoffset > 0 ? min_lines : -min_lines;
// Always add the minimum number of lines when it is negative
else if (min_lines < 0) s = yoffset > 0 ? s - min_lines : s + min_lines;
// apparently on cocoa some mice generate really small yoffset values
// when scrolling slowly https://github.com/kovidgoyal/kitty/issues/1238
if (s == 0) s = yoffset > 0 ? 1 : -1;
}
screen->pending_scroll_pixels = 0;
}
#undef SCALE_SCROLL
if (s == 0) return;
bool upwards = s > 0;
if (screen->modes.mouse_tracking_mode) {
int sz = encode_mouse_scroll(w, upwards, modifiers);
if (sz > 0) {
mouse_event_buf[sz] = 0;
for (s = abs(s); s > 0; s--) {
write_escape_code_to_child(screen, CSI, mouse_event_buf);
} }
} }
} else {
if (screen->linebuf == screen->main_linebuf) screen_history_scroll(screen, abs(s), upwards);
else fake_scroll(w, abs(s), upwards);
} }
if (xoffset != 0.0) {
s = scale_scroll(screen, xoffset, is_high_resolution, &screen->pending_scroll_pixels_x, global_state.callback_os_window->fonts_data->cell_width);
if (s) {
if (screen->modes.mouse_tracking_mode) {
int sz = encode_mouse_scroll(w, s > 0 ? 6 : 7, modifiers);
if (sz > 0) {
mouse_event_buf[sz] = 0;
for (s = abs(s); s > 0; s--) {
write_escape_code_to_child(screen, CSI, mouse_event_buf);
}
}
}
}
}
} }
static PyObject* static PyObject*

View File

@ -78,7 +78,7 @@ typedef struct {
PyObject_HEAD PyObject_HEAD
unsigned int columns, lines, margin_top, margin_bottom, charset, scrolled_by; unsigned int columns, lines, margin_top, margin_bottom, charset, scrolled_by;
double pending_scroll_pixels; double pending_scroll_pixels_x, pending_scroll_pixels_y;
CellPixelSize cell_size; CellPixelSize cell_size;
OverlayLine overlay_line; OverlayLine overlay_line;
id_type window_id; id_type window_id;