mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-04-12 10:48:39 +03:00
macos: left mouse click while not focused doesn't encode to pty (#6998)
Fixes #2595 This fixes an issue where a left mouse click on a terminal while not focused would subsequently be encoded to the pty as a mouse event. This is atypical for macOS applications in general and wasn't something we wanted to do. We do, however, want to ensure our terminal gains focus when clicked without focus. Specifically, a split. This matches iTerm2 behavior and is rather nice. We had this behavior before but our logic to make this work before caused the issue this commit is fixing. I also tested this with command+click which is a common macOS shortcut to emit a mouse event without raising the focus of the target window. In this case, we will properly focus the split but will not encode the mouse event to the pty. I think we actually do a _better job_ here tha iTerm2 (but, subjective) because we do encode the pty event properly if the split is focused whereas iTerm2 never does.
This commit is contained in:
@ -201,7 +201,14 @@ extension Ghostty {
|
||||
self.eventMonitor = NSEvent.addLocalMonitorForEvents(
|
||||
matching: [
|
||||
// We need keyUp because command+key events don't trigger keyUp.
|
||||
.keyUp
|
||||
.keyUp,
|
||||
|
||||
// We need leftMouseDown to determine if we should focus ourselves
|
||||
// when the app/window isn't in focus. We do this instead of
|
||||
// "acceptsFirstMouse" because that forces us to also handle the
|
||||
// event and encode the event to the pty which we want to avoid.
|
||||
// (Issue 2595)
|
||||
.leftMouseDown,
|
||||
]
|
||||
) { [weak self] event in self?.localEventHandler(event) }
|
||||
|
||||
@ -450,11 +457,40 @@ extension Ghostty {
|
||||
case .keyUp:
|
||||
localEventKeyUp(event)
|
||||
|
||||
case .leftMouseDown:
|
||||
localEventLeftMouseDown(event)
|
||||
|
||||
default:
|
||||
event
|
||||
}
|
||||
}
|
||||
|
||||
private func localEventLeftMouseDown(_ event: NSEvent) -> NSEvent? {
|
||||
// We only want to process events that are on this window.
|
||||
guard let window,
|
||||
event.window != nil,
|
||||
window == event.window else { return event }
|
||||
|
||||
// The clicked location in this window should be this view.
|
||||
let location = convert(event.locationInWindow, from: nil)
|
||||
guard hitTest(location) == self else { return event }
|
||||
|
||||
// We only want to grab focus if either our app or window was
|
||||
// not focused.
|
||||
guard !NSApp.isActive || !window.isKeyWindow else { return event }
|
||||
|
||||
// If we're already focused we do nothing
|
||||
guard !focused else { return event }
|
||||
|
||||
// Make ourselves the first responder
|
||||
window.makeFirstResponder(self)
|
||||
|
||||
// We have to keep processing the event so that AppKit can properly
|
||||
// focus the window and dispatch events. If you return nil here then
|
||||
// nobody gets a windowDidBecomeKey event and so on.
|
||||
return event
|
||||
}
|
||||
|
||||
private func localEventKeyUp(_ event: NSEvent) -> NSEvent? {
|
||||
// We only care about events with "command" because all others will
|
||||
// trigger the normal responder chain.
|
||||
@ -620,14 +656,6 @@ extension Ghostty {
|
||||
ghostty_surface_draw(surface);
|
||||
}
|
||||
|
||||
override func acceptsFirstMouse(for event: NSEvent?) -> Bool {
|
||||
// "Override this method in a subclass to allow instances to respond to
|
||||
// click-through. This allows the user to click on a view in an inactive
|
||||
// window, activating the view with one click, instead of clicking first
|
||||
// to make the window active and then clicking the view."
|
||||
return true
|
||||
}
|
||||
|
||||
override func mouseDown(with event: NSEvent) {
|
||||
guard let surface = self.surface else { return }
|
||||
let mods = Ghostty.ghosttyMods(event.modifierFlags)
|
||||
|
Reference in New Issue
Block a user