diff --git a/docs/changelog.rst b/docs/changelog.rst index ac0af4400..15c2742c3 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -45,6 +45,8 @@ Detailed list of changes - 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] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/kittens/tui/loop.py b/kittens/tui/loop.py index dd723890a..218cd9b9b 100644 --- a/kittens/tui/loop.py +++ b/kittens/tui/loop.py @@ -109,17 +109,17 @@ class TermManager: class MouseButton(IntFlag): - NONE, LEFT, MIDDLE, RIGHT, FOURTH, FIFTH = 0, 1, 2, 4, 8, 16 - WHEEL_UP, WHEEL_DOWN = -1, -2 + NONE, LEFT, MIDDLE, RIGHT, FOURTH, FIFTH, SIXTH, SEVENTH = 0, 1, 2, 4, 8, 16, 32, 64 + 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 ALT_INDICATOR = 1 << 3 CTRL_INDICATOR = 1 << 4 MOTION_INDICATOR = 1 << 5 -SCROLL_BUTTON_INDICATOR = 1 << 6 -EXTRA_BUTTON_INDICATOR = 1 << 7 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) buttons: MouseButton = MouseButton.NONE cb3 = cb & 3 - if cb3 != 3: - if cb & SCROLL_BUTTON_INDICATOR: - buttons = MouseButton.WHEEL_DOWN if cb3 & 1 else MouseButton.WHEEL_UP - elif cb & EXTRA_BUTTON_INDICATOR: - buttons |= MouseButton.FIFTH if cb3 & 1 else MouseButton.FOURTH - else: - buttons |= bmap[cb3] + if cb >= 128: + buttons |= ebmap[cb3] + elif cb >= 64: + buttons |= wbmap[cb3] + elif cb3 < 3: + buttons |= bmap[cb3] mods = 0 if cb & SHIFT_INDICATOR: mods |= SHIFT diff --git a/kitty/mouse.c b/kitty/mouse.c index 8844c000d..b0c159630 100644 --- a/kitty/mouse.c +++ b/kitty/mouse.c @@ -135,8 +135,8 @@ encode_mouse_button(Window *w, int button, MouseAction action, int mods) { } static int -encode_mouse_scroll(Window *w, bool upwards, int mods) { - return encode_mouse_event(w, upwards ? 4 : 5, PRESS, mods); +encode_mouse_scroll(Window *w, int button, int 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); } +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 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)); @@ -874,51 +906,42 @@ scroll_event(double xoffset, double yoffset, int flags, int modifiers) { default: break; } - if (yoffset == 0.0) return; - int s; 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. -#define SCALE_SCROLL(which) { double scale = OPT(which); if (screen->modes.mouse_tracking_mode) scale /= fabs(scale); yoffset *= scale; } - if (is_high_resolution) { - SCALE_SCROLL(touch_scroll_multiplier); - double pixels = screen->pending_scroll_pixels + yoffset; - if (fabs(pixels) < global_state.callback_os_window->fonts_data->cell_height) { - screen->pending_scroll_pixels = pixels; - return; - } - s = (int)round(pixels) / (int)global_state.callback_os_window->fonts_data->cell_height; - screen->pending_scroll_pixels = pixels - s * (int) global_state.callback_os_window->fonts_data->cell_height; - } else { - SCALE_SCROLL(wheel_scroll_multiplier); - s = (int) round(yoffset); - if (yoffset != 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 = 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); + if (yoffset != 0.0) { + s = scale_scroll(screen, yoffset, is_high_resolution, &screen->pending_scroll_pixels_y, global_state.callback_os_window->fonts_data->cell_height); + if (s) { + bool upwards = s > 0; + if (screen->modes.mouse_tracking_mode) { + int sz = encode_mouse_scroll(w, upwards ? 4 : 5, 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); } } - } 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* diff --git a/kitty/screen.h b/kitty/screen.h index ad3779733..10ea23562 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -78,7 +78,7 @@ typedef struct { PyObject_HEAD 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; OverlayLine overlay_line; id_type window_id;