ctrl+click is handled as right-click (with various details)

If mouse capturing is enabled, we encode ctrl+click as ctrl+left-click
and DO NOT handle it as right click.
This commit is contained in:
Mitchell Hashimoto
2024-06-30 19:44:51 -07:00
parent 1d70e822c5
commit 57d71450ab
4 changed files with 50 additions and 1 deletions

View File

@ -533,6 +533,7 @@ ghostty_input_mods_e ghostty_surface_key_translation_mods(ghostty_surface_t,
ghostty_input_mods_e);
void ghostty_surface_key(ghostty_surface_t, ghostty_input_key_s);
void ghostty_surface_text(ghostty_surface_t, const char*, uintptr_t);
bool ghostty_surface_mouse_captured(ghostty_surface_t);
bool ghostty_surface_mouse_button(ghostty_surface_t,
ghostty_input_mouse_state_e,
ghostty_input_mouse_button_e,

View File

@ -869,7 +869,41 @@ extension Ghostty {
override func menu(for event: NSEvent) -> NSMenu? {
// We only support right-click menus
guard event.type == .rightMouseDown else { return nil }
switch event.type {
case .rightMouseDown:
// Good
break
case .leftMouseDown:
if !event.modifierFlags.contains(.control) {
return nil
}
// In this case, AppKit calls menu BEFORE calling any mouse events.
// If mouse capturing is enabled then we never show the context menu
// so that we can handle ctrl+left-click in the terminal app.
guard let surface = self.surface else { return nil }
if ghostty_surface_mouse_captured(surface) {
return nil
}
// If we return a non-nil menu then mouse events will never be
// processed by the core, so we need to manually send a right
// mouse down event.
//
// Note this never sounds a right mouse up event but that's the
// same as normal right-click with capturing disabled from AppKit.
let mods = Ghostty.ghosttyMods(event.modifierFlags)
ghostty_surface_mouse_button(
surface,
GHOSTTY_MOUSE_PRESS,
GHOSTTY_MOUSE_RIGHT,
mods
)
default:
return nil
}
let menu = NSMenu()

View File

@ -2129,6 +2129,14 @@ fn mouseShiftCapture(self: *const Surface, lock: bool) bool {
};
}
/// Returns true if the mouse is currently captured by the terminal
/// (i.e. reporting events).
pub fn mouseCaptured(self: *Surface) bool {
self.renderer_state.mutex.lock();
defer self.renderer_state.mutex.unlock();
return self.io.terminal.flags.mouse_event != .none;
}
/// Called for mouse button press/release events. This will return true
/// if the mouse event was consumed in some way (i.e. the program is capturing
/// mouse events). If the event was not consumed, then false is returned.

View File

@ -1632,6 +1632,12 @@ pub const CAPI = struct {
surface.textCallback(ptr[0..len]);
}
/// Returns true if the surface currently has mouse capturing
/// enabled.
export fn ghostty_surface_mouse_captured(surface: *Surface) bool {
return surface.core_surface.mouseCaptured();
}
/// Tell the surface that it needs to schedule a render
export fn ghostty_surface_mouse_button(
surface: *Surface,