eleven / messenger Public

mac: only the focused composer claims ⌘B/⌘I (#481)

Key equivalents walk the view hierarchy, not the responder chain — and every
opened space's pane stays mounted (hidden at opacity 0), each with its own
composer. The first composer in the tree swallowed ⌘B/⌘I and formatted a
hidden draft, so the shortcuts only worked on the top space. Guard on being
the window's first responder; everyone else passes the key along.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell e830df52b7ecec38ebbde29f5d67b539ca22b063 parent bf66fde
2 files changed, +15 −0
  • ios/LChatMac/Info.plist +6 −0
  • ios/LChatMac/MacComposerField.swift +9 −0
diff --git a/ios/LChatMac/Info.plist b/ios/LChatMac/Info.plist
index 7ccfc01..ea3fc0c 100644
--- a/ios/LChatMac/Info.plist
+++ b/ios/LChatMac/Info.plist
@@ -38,8 +38,14 @@
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
+ <key>NSUserActivityTypes</key>
+ <array>
+ <string>INSendMessageIntent</string>
+ </array>
<key>SUEnableAutomaticChecks</key>
<true/>
+ <key>SUEnableInstallerLauncherService</key>
+ <true/>
<key>SUFeedURL</key>
<string>https://github.com/elevenmessenger/releases/releases/latest/download/appcast.xml</string>
<key>SUPublicEDKey</key>
diff --git a/ios/LChatMac/MacComposerField.swift b/ios/LChatMac/MacComposerField.swift
index e309ff3..dc52e24 100644
--- a/ios/LChatMac/MacComposerField.swift
+++ b/ios/LChatMac/MacComposerField.swift
@@ -250,6 +250,15 @@ final class ComposerTextView: NSTextView {
// ⌘B/⌘I toggle traits; ⌘U is swallowed (no underline marker — see the
// representable's doc comment). Everything else keeps its meaning.
override func performKeyEquivalent(with event: NSEvent) -> Bool {
+ // Key equivalents walk the VIEW hierarchy, not the responder chain —
+ // and RootView keeps every opened space's pane mounted (hidden at
+ // opacity 0), each with its own composer. Without the focus guard the
+ // FIRST composer in the tree swallows ⌘B/⌘I and formats a hidden
+ // draft, so the shortcut only ever "worked" on the top space. Only the
+ // focused field may claim the key; everyone else passes it along.
+ guard window?.firstResponder === self else {
+ return super.performKeyEquivalent(with: event)
+ }
if event.modifierFlags.intersection(.deviceIndependentFlagsMask) == .command,
let key = event.charactersIgnoringModifiers?.lowercased() {
switch key {