mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
Key events return boolean if handled
This commit is contained in:
@ -713,7 +713,7 @@ void ghostty_surface_set_color_scheme(ghostty_surface_t,
|
|||||||
ghostty_color_scheme_e);
|
ghostty_color_scheme_e);
|
||||||
ghostty_input_mods_e ghostty_surface_key_translation_mods(ghostty_surface_t,
|
ghostty_input_mods_e ghostty_surface_key_translation_mods(ghostty_surface_t,
|
||||||
ghostty_input_mods_e);
|
ghostty_input_mods_e);
|
||||||
void ghostty_surface_key(ghostty_surface_t, ghostty_input_key_s);
|
bool ghostty_surface_key(ghostty_surface_t, ghostty_input_key_s);
|
||||||
bool ghostty_surface_key_is_binding(ghostty_surface_t, ghostty_input_key_s);
|
bool ghostty_surface_key_is_binding(ghostty_surface_t, ghostty_input_key_s);
|
||||||
void ghostty_surface_text(ghostty_surface_t, const char*, uintptr_t);
|
void ghostty_surface_text(ghostty_surface_t, const char*, uintptr_t);
|
||||||
bool ghostty_surface_mouse_captured(ghostty_surface_t);
|
bool ghostty_surface_mouse_captured(ghostty_surface_t);
|
||||||
|
@ -88,6 +88,7 @@
|
|||||||
A5CEAFDE29B8058B00646FDA /* SplitView.Divider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CEAFDD29B8058B00646FDA /* SplitView.Divider.swift */; };
|
A5CEAFDE29B8058B00646FDA /* SplitView.Divider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CEAFDD29B8058B00646FDA /* SplitView.Divider.swift */; };
|
||||||
A5CEAFFF29C2410700646FDA /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CEAFFE29C2410700646FDA /* Backport.swift */; };
|
A5CEAFFF29C2410700646FDA /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CEAFFE29C2410700646FDA /* Backport.swift */; };
|
||||||
A5CF66D42D289CEE00139794 /* NSEvent+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CF66D32D289CEA00139794 /* NSEvent+Extension.swift */; };
|
A5CF66D42D289CEE00139794 /* NSEvent+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CF66D32D289CEA00139794 /* NSEvent+Extension.swift */; };
|
||||||
|
A5CF66D72D29DDB500139794 /* Ghostty.Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CF66D62D29DDB100139794 /* Ghostty.Event.swift */; };
|
||||||
A5D0AF3B2B36A1DE00D21823 /* TerminalRestorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5D0AF3A2B36A1DE00D21823 /* TerminalRestorable.swift */; };
|
A5D0AF3B2B36A1DE00D21823 /* TerminalRestorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5D0AF3A2B36A1DE00D21823 /* TerminalRestorable.swift */; };
|
||||||
A5D0AF3D2B37804400D21823 /* CodableBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5D0AF3C2B37804400D21823 /* CodableBridge.swift */; };
|
A5D0AF3D2B37804400D21823 /* CodableBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5D0AF3C2B37804400D21823 /* CodableBridge.swift */; };
|
||||||
A5E112932AF73E6E00C6E0C2 /* ClipboardConfirmation.xib in Resources */ = {isa = PBXBuildFile; fileRef = A5E112922AF73E6E00C6E0C2 /* ClipboardConfirmation.xib */; };
|
A5E112932AF73E6E00C6E0C2 /* ClipboardConfirmation.xib in Resources */ = {isa = PBXBuildFile; fileRef = A5E112922AF73E6E00C6E0C2 /* ClipboardConfirmation.xib */; };
|
||||||
@ -179,6 +180,7 @@
|
|||||||
A5CEAFDD29B8058B00646FDA /* SplitView.Divider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplitView.Divider.swift; sourceTree = "<group>"; };
|
A5CEAFDD29B8058B00646FDA /* SplitView.Divider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplitView.Divider.swift; sourceTree = "<group>"; };
|
||||||
A5CEAFFE29C2410700646FDA /* Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Backport.swift; sourceTree = "<group>"; };
|
A5CEAFFE29C2410700646FDA /* Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Backport.swift; sourceTree = "<group>"; };
|
||||||
A5CF66D32D289CEA00139794 /* NSEvent+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSEvent+Extension.swift"; sourceTree = "<group>"; };
|
A5CF66D32D289CEA00139794 /* NSEvent+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSEvent+Extension.swift"; sourceTree = "<group>"; };
|
||||||
|
A5CF66D62D29DDB100139794 /* Ghostty.Event.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Event.swift; sourceTree = "<group>"; };
|
||||||
A5D0AF3A2B36A1DE00D21823 /* TerminalRestorable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalRestorable.swift; sourceTree = "<group>"; };
|
A5D0AF3A2B36A1DE00D21823 /* TerminalRestorable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalRestorable.swift; sourceTree = "<group>"; };
|
||||||
A5D0AF3C2B37804400D21823 /* CodableBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableBridge.swift; sourceTree = "<group>"; };
|
A5D0AF3C2B37804400D21823 /* CodableBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableBridge.swift; sourceTree = "<group>"; };
|
||||||
A5D4499D2B53AE7B000F5B83 /* Ghostty-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Ghostty-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
A5D4499D2B53AE7B000F5B83 /* Ghostty-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Ghostty-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
@ -353,6 +355,7 @@
|
|||||||
A53D0C992B543F3B00305CE6 /* Ghostty.App.swift */,
|
A53D0C992B543F3B00305CE6 /* Ghostty.App.swift */,
|
||||||
A514C8D52B54A16400493A16 /* Ghostty.Config.swift */,
|
A514C8D52B54A16400493A16 /* Ghostty.Config.swift */,
|
||||||
A53A6C022CCC1B7D00943E98 /* Ghostty.Action.swift */,
|
A53A6C022CCC1B7D00943E98 /* Ghostty.Action.swift */,
|
||||||
|
A5CF66D62D29DDB100139794 /* Ghostty.Event.swift */,
|
||||||
A5278A9A2AA05B2600CD3039 /* Ghostty.Input.swift */,
|
A5278A9A2AA05B2600CD3039 /* Ghostty.Input.swift */,
|
||||||
A56D58852ACDDB4100508D2C /* Ghostty.Shell.swift */,
|
A56D58852ACDDB4100508D2C /* Ghostty.Shell.swift */,
|
||||||
A59630A32AF059BB00D64628 /* Ghostty.SplitNode.swift */,
|
A59630A32AF059BB00D64628 /* Ghostty.SplitNode.swift */,
|
||||||
@ -621,6 +624,7 @@
|
|||||||
A56D58892ACDE6CA00508D2C /* ServiceProvider.swift in Sources */,
|
A56D58892ACDE6CA00508D2C /* ServiceProvider.swift in Sources */,
|
||||||
A5CBD0602CA0C90A0017A1AE /* QuickTerminalWindow.swift in Sources */,
|
A5CBD0602CA0C90A0017A1AE /* QuickTerminalWindow.swift in Sources */,
|
||||||
A5CBD05E2CA0C5EC0017A1AE /* QuickTerminalController.swift in Sources */,
|
A5CBD05E2CA0C5EC0017A1AE /* QuickTerminalController.swift in Sources */,
|
||||||
|
A5CF66D72D29DDB500139794 /* Ghostty.Event.swift in Sources */,
|
||||||
A51BFC222B2FB6B400E92F16 /* AboutView.swift in Sources */,
|
A51BFC222B2FB6B400E92F16 /* AboutView.swift in Sources */,
|
||||||
A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */,
|
A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */,
|
||||||
A5CBD0562C9E65B80017A1AE /* DraggableWindowView.swift in Sources */,
|
A5CBD0562C9E65B80017A1AE /* DraggableWindowView.swift in Sources */,
|
||||||
|
15
macos/Sources/Ghostty/Ghostty.Event.swift
Normal file
15
macos/Sources/Ghostty/Ghostty.Event.swift
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import Cocoa
|
||||||
|
import GhosttyKit
|
||||||
|
|
||||||
|
extension Ghostty {
|
||||||
|
/// A comparable event.
|
||||||
|
struct ComparableKeyEvent: Equatable {
|
||||||
|
let keyCode: UInt16
|
||||||
|
let flags: NSEvent.ModifierFlags
|
||||||
|
|
||||||
|
init(event: NSEvent) {
|
||||||
|
self.keyCode = event.keyCode
|
||||||
|
self.flags = event.modifierFlags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -773,7 +773,7 @@ extension Ghostty {
|
|||||||
if let list = keyTextAccumulator, list.count > 0 {
|
if let list = keyTextAccumulator, list.count > 0 {
|
||||||
handled = true
|
handled = true
|
||||||
for text in list {
|
for text in list {
|
||||||
keyAction(action, event: event, text: text)
|
_ = keyAction(action, event: event, text: text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -783,29 +783,38 @@ extension Ghostty {
|
|||||||
// the preedit.
|
// the preedit.
|
||||||
if (markedText.length > 0 || markedTextBefore) {
|
if (markedText.length > 0 || markedTextBefore) {
|
||||||
handled = true
|
handled = true
|
||||||
keyAction(action, event: event, preedit: markedText.string)
|
_ = keyAction(action, event: event, preedit: markedText.string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!handled) {
|
if (!handled) {
|
||||||
// No text or anything, we want to handle this manually.
|
// No text or anything, we want to handle this manually.
|
||||||
keyAction(action, event: event)
|
_ = keyAction(action, event: event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func keyUp(with event: NSEvent) {
|
override func keyUp(with event: NSEvent) {
|
||||||
keyAction(GHOSTTY_ACTION_RELEASE, event: event)
|
_ = keyAction(GHOSTTY_ACTION_RELEASE, event: event)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Special case handling for some control keys
|
/// Special case handling for some control keys
|
||||||
override func performKeyEquivalent(with event: NSEvent) -> Bool {
|
override func performKeyEquivalent(with event: NSEvent) -> Bool {
|
||||||
// Only process key down events
|
switch (event.type) {
|
||||||
if (event.type != .keyDown) {
|
case .keyDown:
|
||||||
|
// Continue, we care about key down events
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Any other key event we don't care about. I don't think its even
|
||||||
|
// possible to receive any other event type.
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only process events if we're focused. Some key events like C-/ macOS
|
// Only process events if we're focused. Some key events like C-/ macOS
|
||||||
// appears to send to the first view in the hierarchy rather than the
|
// appears to send to the first view in the hierarchy rather than the
|
||||||
// the first responder (I don't know why). This prevents us from handling it.
|
// the first responder (I don't know why). This prevents us from handling it.
|
||||||
|
// Besides C-/, its important we don't process key equivalents if unfocused
|
||||||
|
// because there are other event listeners for that (i.e. AppDelegate's
|
||||||
|
// local event handler).
|
||||||
if (!focused) {
|
if (!focused) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -819,13 +828,6 @@ extension Ghostty {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only process keys when Control is active. All known issues we're
|
|
||||||
// resolving happen only in this scenario. This probably isn't fully robust
|
|
||||||
// but we can broaden the scope as we find more cases.
|
|
||||||
if (!event.modifierFlags.contains(.control)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
let equivalent: String
|
let equivalent: String
|
||||||
switch (event.charactersIgnoringModifiers) {
|
switch (event.charactersIgnoringModifiers) {
|
||||||
case "/":
|
case "/":
|
||||||
@ -841,14 +843,25 @@ extension Ghostty {
|
|||||||
case "\r":
|
case "\r":
|
||||||
// Pass C-<return> through verbatim
|
// Pass C-<return> through verbatim
|
||||||
// (prevent the default context menu equivalent)
|
// (prevent the default context menu equivalent)
|
||||||
|
if (!event.modifierFlags.contains(.control)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
equivalent = "\r"
|
equivalent = "\r"
|
||||||
|
|
||||||
|
case ".":
|
||||||
|
if (!event.modifierFlags.contains(.command)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
equivalent = "."
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Ignore other events
|
// Ignore other events
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
let newEvent = NSEvent.keyEvent(
|
let finalEvent = NSEvent.keyEvent(
|
||||||
with: .keyDown,
|
with: .keyDown,
|
||||||
location: event.locationInWindow,
|
location: event.locationInWindow,
|
||||||
modifierFlags: event.modifierFlags,
|
modifierFlags: event.modifierFlags,
|
||||||
@ -861,7 +874,7 @@ extension Ghostty {
|
|||||||
keyCode: event.keyCode
|
keyCode: event.keyCode
|
||||||
)
|
)
|
||||||
|
|
||||||
self.keyDown(with: newEvent!)
|
self.keyDown(with: finalEvent!)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -906,33 +919,38 @@ extension Ghostty {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keyAction(action, event: event)
|
_ = keyAction(action, event: event)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func keyAction(_ action: ghostty_input_action_e, event: NSEvent) {
|
private func keyAction(_ action: ghostty_input_action_e, event: NSEvent) -> Bool {
|
||||||
guard let surface = self.surface else { return }
|
guard let surface = self.surface else { return false }
|
||||||
|
return ghostty_surface_key(surface, event.ghosttyKeyEvent(action))
|
||||||
ghostty_surface_key(surface, event.ghosttyKeyEvent(action))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func keyAction(_ action: ghostty_input_action_e, event: NSEvent, preedit: String) {
|
private func keyAction(
|
||||||
guard let surface = self.surface else { return }
|
_ action: ghostty_input_action_e,
|
||||||
|
event: NSEvent, preedit: String
|
||||||
|
) -> Bool {
|
||||||
|
guard let surface = self.surface else { return false }
|
||||||
|
|
||||||
preedit.withCString { ptr in
|
return preedit.withCString { ptr in
|
||||||
var key_ev = event.ghosttyKeyEvent(action)
|
var key_ev = event.ghosttyKeyEvent(action)
|
||||||
key_ev.text = ptr
|
key_ev.text = ptr
|
||||||
key_ev.composing = true
|
key_ev.composing = true
|
||||||
ghostty_surface_key(surface, key_ev)
|
return ghostty_surface_key(surface, key_ev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func keyAction(_ action: ghostty_input_action_e, event: NSEvent, text: String) {
|
private func keyAction(
|
||||||
guard let surface = self.surface else { return }
|
_ action: ghostty_input_action_e,
|
||||||
|
event: NSEvent, text: String
|
||||||
|
) -> Bool {
|
||||||
|
guard let surface = self.surface else { return false }
|
||||||
|
|
||||||
text.withCString { ptr in
|
return text.withCString { ptr in
|
||||||
var key_ev = event.ghosttyKeyEvent(action)
|
var key_ev = event.ghosttyKeyEvent(action)
|
||||||
key_ev.text = ptr
|
key_ev.text = ptr
|
||||||
ghostty_surface_key(surface, key_ev)
|
return ghostty_surface_key(surface, key_ev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1606,13 +1606,13 @@ pub const CAPI = struct {
|
|||||||
export fn ghostty_surface_key(
|
export fn ghostty_surface_key(
|
||||||
surface: *Surface,
|
surface: *Surface,
|
||||||
event: KeyEvent,
|
event: KeyEvent,
|
||||||
) void {
|
) bool {
|
||||||
_ = surface.app.keyEvent(
|
return surface.app.keyEvent(
|
||||||
.{ .surface = surface },
|
.{ .surface = surface },
|
||||||
event.keyEvent(),
|
event.keyEvent(),
|
||||||
) catch |err| {
|
) catch |err| {
|
||||||
log.warn("error processing key event err={}", .{err});
|
log.warn("error processing key event err={}", .{err});
|
||||||
return;
|
return false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user