mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-19 18:26:13 +03:00
config: add mouse-shift-capture configuration
This commit is contained in:
@ -142,6 +142,7 @@ const DerivedConfig = struct {
|
||||
confirm_close_surface: bool,
|
||||
mouse_interval: u64,
|
||||
mouse_hide_while_typing: bool,
|
||||
mouse_shift_capture: configpkg.MouseShiftCapture,
|
||||
macos_non_native_fullscreen: configpkg.NonNativeFullscreen,
|
||||
macos_option_as_alt: configpkg.OptionAsAlt,
|
||||
window_padding_x: u32,
|
||||
@ -162,6 +163,7 @@ const DerivedConfig = struct {
|
||||
.confirm_close_surface = config.@"confirm-close-surface",
|
||||
.mouse_interval = config.@"click-repeat-interval" * 1_000_000, // 500ms
|
||||
.mouse_hide_while_typing = config.@"mouse-hide-while-typing",
|
||||
.mouse_shift_capture = config.@"mouse-shift-capture",
|
||||
.macos_non_native_fullscreen = config.@"macos-non-native-fullscreen",
|
||||
.macos_option_as_alt = config.@"macos-option-as-alt",
|
||||
.window_padding_x = config.@"window-padding-x",
|
||||
@ -1501,6 +1503,26 @@ fn mouseReport(
|
||||
try self.io_thread.wakeup.notify();
|
||||
}
|
||||
|
||||
/// Returns true if the shift modifier is allowed to be captured by modifier
|
||||
/// events. It is up to the caller to still verify it is a situation in which
|
||||
/// shift capture makes sense (i.e. left button, mouse click, etc.)
|
||||
fn mouseShiftCapture(self: *const Surface, lock: bool) bool {
|
||||
// Handle our never/always case where we don't need a lock.
|
||||
switch (self.config.mouse_shift_capture) {
|
||||
.never => return false,
|
||||
.always => return true,
|
||||
.false, .true => {},
|
||||
}
|
||||
|
||||
if (lock) self.renderer_state.mutex.lock();
|
||||
defer if (lock) self.renderer_state.mutex.unlock();
|
||||
return switch (self.config.mouse_shift_capture) {
|
||||
.false => false,
|
||||
.true => true,
|
||||
.never, .always => unreachable, // handled earlier
|
||||
};
|
||||
}
|
||||
|
||||
pub fn mouseButtonCallback(
|
||||
self: *Surface,
|
||||
action: input.MouseButtonState,
|
||||
@ -1519,11 +1541,20 @@ pub fn mouseButtonCallback(
|
||||
// Always show the mouse again if it is hidden
|
||||
if (self.mouse.hidden) self.showMouse();
|
||||
|
||||
// This is set to true if the terminal is allowed to capture the shift
|
||||
// modifer. Note we can do this more efficiently probably with less
|
||||
// locking/unlocking but clicking isn't that frequent enough to be a
|
||||
// bottleneck.
|
||||
const shift_capture = self.mouseShiftCapture(true);
|
||||
|
||||
// Shift-click continues the previous mouse state if we have a selection.
|
||||
// cursorPosCallback will also do a mouse report so we don't need to do any
|
||||
// of the logic below.
|
||||
if (button == .left and action == .press) {
|
||||
if (mods.shift and self.mouse.left_click_count > 0) {
|
||||
if (mods.shift and
|
||||
self.mouse.left_click_count > 0 and
|
||||
!shift_capture)
|
||||
{
|
||||
// Checking for selection requires the renderer state mutex which
|
||||
// sucks but this should be pretty rare of an event so it won't
|
||||
// cause a ton of contention.
|
||||
@ -1546,8 +1577,9 @@ pub fn mouseButtonCallback(
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
if (self.io.terminal.flags.mouse_event != .none) report: {
|
||||
// Shift overrides mouse "grabbing" in the window, taken from Kitty.
|
||||
if (mods.shift) break :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 button == .left and !shift_capture) break :report;
|
||||
|
||||
// In any other mouse button scenario without shift pressed we
|
||||
// clear the selection since the underlying application can handle
|
||||
@ -1682,7 +1714,9 @@ pub fn cursorPosCallback(
|
||||
// Do a mouse report
|
||||
if (self.io.terminal.flags.mouse_event != .none) report: {
|
||||
// Shift overrides mouse "grabbing" in the window, taken from Kitty.
|
||||
if (self.mouse.mods.shift) break :report;
|
||||
if (self.mouse.mods.shift and
|
||||
self.mouse.click_state[@intFromEnum(input.MouseButton.left)] == .press and
|
||||
!self.mouseShiftCapture(false)) break :report;
|
||||
|
||||
// We use the first mouse button we find pressed in order to report
|
||||
// since the spec (afaict) does not say...
|
||||
|
@ -6,6 +6,7 @@ pub const Config = @import("config/Config.zig");
|
||||
// Field types
|
||||
pub const CopyOnSelect = Config.CopyOnSelect;
|
||||
pub const Keybinds = Config.Keybinds;
|
||||
pub const MouseShiftCapture = Config.MouseShiftCapture;
|
||||
pub const NonNativeFullscreen = Config.NonNativeFullscreen;
|
||||
pub const OptionAsAlt = Config.OptionAsAlt;
|
||||
|
||||
|
@ -197,6 +197,28 @@ palette: Palette = .{},
|
||||
/// cursor is over the active terminal surface.
|
||||
@"mouse-hide-while-typing": bool = false,
|
||||
|
||||
/// Determines whether running programs can detect the shift key pressed
|
||||
/// with a mouse click. Typically, the shift key is used to extend mouse
|
||||
/// selection.
|
||||
///
|
||||
/// The default value of "false" means that the shift key is not sent
|
||||
/// with the mouse protocol and will extend the selection. This value
|
||||
/// can be conditionally overridden by the running program with the
|
||||
/// XTSHIFTESCAPE sequence.
|
||||
///
|
||||
/// The value "true" means that the shift key is sent with the mouse
|
||||
/// protocol but the running program can override this behavior with
|
||||
/// XTSHIFTESCAPE.
|
||||
///
|
||||
/// The value "never" is the same as "false" but the running program
|
||||
/// cannot override this behavior with XTSHIFTESCAPE. The value "always"
|
||||
/// is the same as "true" but the running program cannot override this
|
||||
/// behavior with XTSHIFTESCAPE.
|
||||
///
|
||||
/// If you always want shift to extend mouse selection even if the
|
||||
/// program requests otherwise, set this to "never".
|
||||
@"mouse-shift-capture": MouseShiftCapture = .false,
|
||||
|
||||
/// The opacity level (opposite of transparency) of the background.
|
||||
/// A value of 1 is fully opaque and a value of 0 is fully transparent.
|
||||
/// A value less than 0 or greater than 1 will be clamped to the nearest
|
||||
@ -1930,3 +1952,11 @@ pub const GtkSingleInstance = enum {
|
||||
false,
|
||||
true,
|
||||
};
|
||||
|
||||
/// See mouse-shift-capture
|
||||
pub const MouseShiftCapture = enum {
|
||||
false,
|
||||
true,
|
||||
always,
|
||||
never,
|
||||
};
|
||||
|
Reference in New Issue
Block a user