feat: added mouse-reporting / toggle-mouse-reporting (#9282)

Closes #8430

A few questions:
* Should I set a default keybind for `toggle-mouse-reporting`? The issue
mentioned one, it's currently unset.
* Am I handling the `toggle-mouse-reporting` action properly in
`performAction` (gtk) / `action` (macos)?

Copilot was used to understand the codebase, but code was authored
manually.
pull/9288/head
Matthew Hrehirchuk 2025-10-19 21:45:37 -06:00 committed by GitHub
parent 1b86691896
commit 2696d50ca4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 53 additions and 5 deletions

View File

@ -268,6 +268,7 @@ const DerivedConfig = struct {
font: font.SharedGridSet.DerivedConfig,
mouse_interval: u64,
mouse_hide_while_typing: bool,
mouse_reporting: bool,
mouse_scroll_multiplier: configpkg.MouseScrollMultiplier,
mouse_shift_capture: configpkg.MouseShiftCapture,
macos_non_native_fullscreen: configpkg.NonNativeFullscreen,
@ -341,6 +342,7 @@ const DerivedConfig = struct {
.font = try font.SharedGridSet.DerivedConfig.init(alloc, config),
.mouse_interval = config.@"click-repeat-interval" * 1_000_000, // 500ms
.mouse_hide_while_typing = config.@"mouse-hide-while-typing",
.mouse_reporting = config.@"mouse-reporting",
.mouse_scroll_multiplier = config.@"mouse-scroll-multiplier",
.mouse_shift_capture = config.@"mouse-shift-capture",
.macos_non_native_fullscreen = config.@"macos-non-native-fullscreen",
@ -2984,7 +2986,7 @@ pub fn scrollCallback(
// If we have an active mouse reporting mode, clear the selection.
// The selection can occur if the user uses the shift mod key to
// override mouse grabbing from the window.
if (self.io.terminal.flags.mouse_event != .none) {
if (self.isMouseReporting()) {
try self.setSelection(null);
}
@ -3027,7 +3029,7 @@ pub fn scrollCallback(
// the normal logic.
// If we're scrolling up or down, then send a mouse event.
if (self.io.terminal.flags.mouse_event != .none) {
if (self.isMouseReporting()) {
for (0..@abs(y.delta)) |_| {
const pos = try self.rt_surface.getCursorPos();
try self.mouseReport(switch (y.direction()) {
@ -3100,6 +3102,13 @@ pub fn contentScaleCallback(self: *Surface, content_scale: apprt.ContentScale) !
/// The type of action to report for a mouse event.
const MouseReportAction = enum { press, release, motion };
/// Returns true if mouse reporting is enabled both in the config and
/// the terminal state.
fn isMouseReporting(self: *const Surface) bool {
return self.config.mouse_reporting and
self.io.terminal.flags.mouse_event != .none;
}
fn mouseReport(
self: *Surface,
button: ?input.MouseButton,
@ -3107,9 +3116,13 @@ fn mouseReport(
mods: input.Mods,
pos: apprt.CursorPos,
) !void {
// Mouse reporting must be enabled by both config and terminal state
assert(self.config.mouse_reporting);
assert(self.io.terminal.flags.mouse_event != .none);
// Depending on the event, we may do nothing at all.
switch (self.io.terminal.flags.mouse_event) {
.none => return,
.none => unreachable, // checked by assert above
// X10 only reports clicks with mouse button 1, 2, 3. We verify
// the button later.
@ -3504,7 +3517,7 @@ pub fn mouseButtonCallback(
{
self.renderer_state.mutex.lock();
defer self.renderer_state.mutex.unlock();
if (self.io.terminal.flags.mouse_event != .none) report: {
if (self.isMouseReporting()) report: {
// If we have shift-pressed and we aren't allowed to capture it,
// then we do not do a mouse report.
if (mods.shift and !shift_capture) break :report;
@ -4142,7 +4155,7 @@ pub fn cursorPosCallback(
}
// Do a mouse report
if (self.io.terminal.flags.mouse_event != .none) report: {
if (self.isMouseReporting()) report: {
// Shift overrides mouse "grabbing" in the window, taken from Kitty.
// This only applies if there is a mouse button pressed so that
// movement reports are not affected.
@ -5035,6 +5048,11 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
.toggle,
),
.toggle_mouse_reporting => {
self.config.mouse_reporting = !self.config.mouse_reporting;
log.debug("mouse reporting toggled: {}", .{self.config.mouse_reporting});
},
.toggle_command_palette => return try self.rt_app.performAction(
.{ .surface = self },
.toggle_command_palette,

View File

@ -839,6 +839,18 @@ palette: Palette = .{},
/// * `never`
@"mouse-shift-capture": MouseShiftCapture = .false,
/// Enable or disable mouse reporting. When set to `false`, mouse events will
/// not be reported to terminal applications even if they request it. This
/// allows you to always use the mouse for selection and other terminal UI
/// interactions without applications capturing mouse input.
///
/// When set to `true` (the default), terminal applications can request mouse
/// reporting and will receive mouse events according to their requested mode.
///
/// This can be toggled at runtime using the `toggle_mouse_reporting` keybind
/// action.
@"mouse-reporting": bool = true,
/// Multiplier for scrolling distance with the mouse wheel.
///
/// A prefix of `precision:` or `discrete:` can be used to set the multiplier

View File

@ -637,6 +637,17 @@ pub const Action = union(enum) {
/// Only implemented on macOS, as this uses a built-in system API.
toggle_secure_input,
/// Toggle mouse reporting on or off.
///
/// When mouse reporting is disabled, mouse events will not be reported to
/// terminal applications even if they request it. This allows you to always
/// use the mouse for selection and other terminal UI interactions without
/// applications capturing mouse input.
///
/// This can also be controlled via the `mouse-reporting` configuration
/// option.
toggle_mouse_reporting,
/// Toggle the command palette.
///
/// The command palette is a popup that lets you see what actions
@ -1099,6 +1110,7 @@ pub const Action = union(enum) {
.toggle_window_decorations,
.toggle_window_float_on_top,
.toggle_secure_input,
.toggle_mouse_reporting,
.toggle_command_palette,
.show_on_screen_keyboard,
.reset_window_size,

View File

@ -449,6 +449,12 @@ fn actionCommands(action: Action.Key) []const Command {
.description = "Toggle secure input mode.",
}},
.toggle_mouse_reporting => comptime &.{.{
.action = .toggle_mouse_reporting,
.title = "Toggle Mouse Reporting",
.description = "Toggle whether mouse events are reported to terminal applications.",
}},
.check_for_updates => comptime &.{.{
.action = .check_for_updates,
.title = "Check for Updates",