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,
|
confirm_close_surface: bool,
|
||||||
mouse_interval: u64,
|
mouse_interval: u64,
|
||||||
mouse_hide_while_typing: bool,
|
mouse_hide_while_typing: bool,
|
||||||
|
mouse_shift_capture: configpkg.MouseShiftCapture,
|
||||||
macos_non_native_fullscreen: configpkg.NonNativeFullscreen,
|
macos_non_native_fullscreen: configpkg.NonNativeFullscreen,
|
||||||
macos_option_as_alt: configpkg.OptionAsAlt,
|
macos_option_as_alt: configpkg.OptionAsAlt,
|
||||||
window_padding_x: u32,
|
window_padding_x: u32,
|
||||||
@ -162,6 +163,7 @@ const DerivedConfig = struct {
|
|||||||
.confirm_close_surface = config.@"confirm-close-surface",
|
.confirm_close_surface = config.@"confirm-close-surface",
|
||||||
.mouse_interval = config.@"click-repeat-interval" * 1_000_000, // 500ms
|
.mouse_interval = config.@"click-repeat-interval" * 1_000_000, // 500ms
|
||||||
.mouse_hide_while_typing = config.@"mouse-hide-while-typing",
|
.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_non_native_fullscreen = config.@"macos-non-native-fullscreen",
|
||||||
.macos_option_as_alt = config.@"macos-option-as-alt",
|
.macos_option_as_alt = config.@"macos-option-as-alt",
|
||||||
.window_padding_x = config.@"window-padding-x",
|
.window_padding_x = config.@"window-padding-x",
|
||||||
@ -1501,6 +1503,26 @@ fn mouseReport(
|
|||||||
try self.io_thread.wakeup.notify();
|
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(
|
pub fn mouseButtonCallback(
|
||||||
self: *Surface,
|
self: *Surface,
|
||||||
action: input.MouseButtonState,
|
action: input.MouseButtonState,
|
||||||
@ -1519,11 +1541,20 @@ pub fn mouseButtonCallback(
|
|||||||
// Always show the mouse again if it is hidden
|
// Always show the mouse again if it is hidden
|
||||||
if (self.mouse.hidden) self.showMouse();
|
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.
|
// 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
|
// cursorPosCallback will also do a mouse report so we don't need to do any
|
||||||
// of the logic below.
|
// of the logic below.
|
||||||
if (button == .left and action == .press) {
|
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
|
// Checking for selection requires the renderer state mutex which
|
||||||
// sucks but this should be pretty rare of an event so it won't
|
// sucks but this should be pretty rare of an event so it won't
|
||||||
// cause a ton of contention.
|
// cause a ton of contention.
|
||||||
@ -1546,8 +1577,9 @@ pub fn mouseButtonCallback(
|
|||||||
self.renderer_state.mutex.lock();
|
self.renderer_state.mutex.lock();
|
||||||
defer self.renderer_state.mutex.unlock();
|
defer self.renderer_state.mutex.unlock();
|
||||||
if (self.io.terminal.flags.mouse_event != .none) report: {
|
if (self.io.terminal.flags.mouse_event != .none) report: {
|
||||||
// Shift overrides mouse "grabbing" in the window, taken from Kitty.
|
// If we have shift-pressed and we aren't allowed to capture it,
|
||||||
if (mods.shift) break :report;
|
// 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
|
// In any other mouse button scenario without shift pressed we
|
||||||
// clear the selection since the underlying application can handle
|
// clear the selection since the underlying application can handle
|
||||||
@ -1682,7 +1714,9 @@ pub fn cursorPosCallback(
|
|||||||
// Do a mouse report
|
// Do a mouse report
|
||||||
if (self.io.terminal.flags.mouse_event != .none) report: {
|
if (self.io.terminal.flags.mouse_event != .none) report: {
|
||||||
// Shift overrides mouse "grabbing" in the window, taken from Kitty.
|
// 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
|
// We use the first mouse button we find pressed in order to report
|
||||||
// since the spec (afaict) does not say...
|
// since the spec (afaict) does not say...
|
||||||
|
@ -6,6 +6,7 @@ pub const Config = @import("config/Config.zig");
|
|||||||
// Field types
|
// Field types
|
||||||
pub const CopyOnSelect = Config.CopyOnSelect;
|
pub const CopyOnSelect = Config.CopyOnSelect;
|
||||||
pub const Keybinds = Config.Keybinds;
|
pub const Keybinds = Config.Keybinds;
|
||||||
|
pub const MouseShiftCapture = Config.MouseShiftCapture;
|
||||||
pub const NonNativeFullscreen = Config.NonNativeFullscreen;
|
pub const NonNativeFullscreen = Config.NonNativeFullscreen;
|
||||||
pub const OptionAsAlt = Config.OptionAsAlt;
|
pub const OptionAsAlt = Config.OptionAsAlt;
|
||||||
|
|
||||||
|
@ -197,6 +197,28 @@ palette: Palette = .{},
|
|||||||
/// cursor is over the active terminal surface.
|
/// cursor is over the active terminal surface.
|
||||||
@"mouse-hide-while-typing": bool = false,
|
@"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.
|
/// 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 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
|
/// A value less than 0 or greater than 1 will be clamped to the nearest
|
||||||
@ -1930,3 +1952,11 @@ pub const GtkSingleInstance = enum {
|
|||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// See mouse-shift-capture
|
||||||
|
pub const MouseShiftCapture = enum {
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
always,
|
||||||
|
never,
|
||||||
|
};
|
||||||
|
Reference in New Issue
Block a user