Skip to content

Commit 3b8d208

Browse files
committed
feat(find-bar): close inline find bar on Escape even without focus
Previously, pressing Escape only closed the find bar when a text field inside it had keyboard focus (handled via NSControlTextEditingDelegate). If focus had moved back to the editor, Escape had no effect on the bar. Install a local NSEvent monitor (NSEventMaskKeyDown) when the bar is shown, and remove it when the bar closes or is deallocated. The monitor intercepts keyCode 53 (Escape) app-wide and closes the bar regardless of which view holds focus. The existing focused-field path is unchanged; the hidden-guard in the monitor block prevents a double-close if both paths fire for the same event.
1 parent 1551d33 commit 3b8d208

1 file changed

Lines changed: 36 additions & 0 deletions

File tree

src/MacVim/MMFindBarView.m

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ @implementation MMFindBarView {
5353
NSButton *_nextButton;
5454
NSButton *_closeButton; // MMHoverButton
5555
NSPoint _dragOffset; // mouse-down offset for dragging
56+
id _escMonitor; // local event monitor for Escape key
5657
}
5758

5859
- (instancetype)init {
@@ -183,6 +184,9 @@ - (void)showWithText:(NSString *)text flags:(int)flags {
183184

184185
self.hidden = NO;
185186
[[self window] makeFirstResponder:_findBox];
187+
188+
// Install local event monitor to catch Escape even when find bar has no focus
189+
[self _installEscapeMonitor];
186190
}
187191

188192
- (NSString *)findString { return _findBox.stringValue; }
@@ -192,6 +196,11 @@ - (BOOL)matchWord { return _matchWordButton.state == NSControlStateVa
192196

193197
// ── Background ───────────────────────────────────────────────────────────────
194198

199+
- (void)dealloc {
200+
[self _removeEscapeMonitor];
201+
[super dealloc];
202+
}
203+
195204
- (void)drawRect:(NSRect)dirtyRect {
196205
[[NSColor windowBackgroundColor] setFill];
197206
NSRectFill(dirtyRect);
@@ -222,9 +231,36 @@ - (void)_replaceAll:(id)sender {
222231

223232
- (void)_close:(id)sender {
224233
self.hidden = YES;
234+
[self _removeEscapeMonitor];
225235
[_delegate findBarViewDidClose:self];
226236
}
227237

238+
// ── Escape key monitor ───────────────────────────────────────────────────────
239+
240+
- (void)_installEscapeMonitor {
241+
if (_escMonitor) return;
242+
// Use __block + unsafe_unretained to avoid ARC-only __weak in MRR context.
243+
// The monitor is always removed before self is deallocated (_close or dealloc).
244+
MMFindBarView * __unsafe_unretained unsafeSelf = self;
245+
_escMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown
246+
handler:^NSEvent *(NSEvent *event) {
247+
if (unsafeSelf.hidden) return event;
248+
// keyCode 53 = Escape
249+
if (event.keyCode == 53) {
250+
[unsafeSelf _close:nil];
251+
return nil; // consume the event
252+
}
253+
return event;
254+
}];
255+
}
256+
257+
- (void)_removeEscapeMonitor {
258+
if (_escMonitor) {
259+
[NSEvent removeMonitor:_escMonitor];
260+
_escMonitor = nil;
261+
}
262+
}
263+
228264
// ── Dragging ──────────────────────────────────────────────────────────────────
229265
// Allow the bar to be dragged anywhere within the text-editing area.
230266
// The delegate supplies the allowed rect; if unavailable we fall back to the

0 commit comments

Comments
 (0)