From 3a2078c59929127ed8d0a3b15544b0af77cf81dc Mon Sep 17 00:00:00 2001 From: Akshay Kolli Date: Tue, 30 Jun 2026 01:38:00 -0700 Subject: [PATCH] WIP: add panel command shortcuts --- .../views/ClipboardPanelController.swift | 37 +++++++++++++++++++ .../ClipboardPanelControllerTests.swift | 12 ++++++ 2 files changed, 49 insertions(+) diff --git a/sources/clipbored/views/ClipboardPanelController.swift b/sources/clipbored/views/ClipboardPanelController.swift index f46c0f9..1721cd7 100644 --- a/sources/clipbored/views/ClipboardPanelController.swift +++ b/sources/clipbored/views/ClipboardPanelController.swift @@ -12,6 +12,12 @@ struct ClipboardPanelReflowPlan { let bottomSafeInset: CGFloat } +enum ClipboardPanelShortcutAction: Equatable { + case copy + case open + case reveal +} + final class ClipboardPanelController: NSObject, NSWindowDelegate { private enum Animation { static let showDuration: TimeInterval = 0.16 @@ -317,6 +323,11 @@ final class ClipboardPanelController: NSObject, NSWindowDelegate { self.viewModel.sortMode = mode return nil } + if self.shouldHandlePanelKeyEvent(event, allowSearchFieldEditing: true), + let action = Self.commandShortcutAction(forKeyCode: event.keyCode, modifiers: event.modifierFlags) { + self.performShortcutAction(action) + return nil + } guard self.shouldHandlePanelKeyEvent(event) else { return event } switch event.keyCode { case 53: @@ -343,6 +354,17 @@ final class ClipboardPanelController: NSObject, NSWindowDelegate { } } + private func performShortcutAction(_ action: ClipboardPanelShortcutAction) { + switch action { + case .copy: + viewModel.copySelected() + case .open: + viewModel.openSelected() + case .reveal: + viewModel.revealSelected() + } + } + private func shouldHandlePanelKeyEvent(_ event: NSEvent) -> Bool { shouldHandlePanelKeyEvent(event, allowSearchFieldEditing: false) } @@ -369,6 +391,21 @@ final class ClipboardPanelController: NSObject, NSWindowDelegate { return collectionShortcuts[keyCode] } + static func commandShortcutAction(forKeyCode keyCode: UInt16, modifiers: NSEvent.ModifierFlags) -> ClipboardPanelShortcutAction? { + let relevantModifiers = modifiers.intersection(.deviceIndependentFlagsMask) + guard relevantModifiers == .command else { return nil } + switch keyCode { + case 8: + return .copy + case 31: + return .open + case 15: + return .reveal + default: + return nil + } + } + #if DEBUG var debugPanelFrame: NSRect { panel.frame diff --git a/tests/clipboredtests/ClipboardPanelControllerTests.swift b/tests/clipboredtests/ClipboardPanelControllerTests.swift index bd0c1a2..635c0c5 100644 --- a/tests/clipboredtests/ClipboardPanelControllerTests.swift +++ b/tests/clipboredtests/ClipboardPanelControllerTests.swift @@ -144,4 +144,16 @@ final class ClipboardPanelControllerTests: XCTestCase { XCTAssertNil(ClipboardPanelController.collectionShortcutMode(forKeyCode: 18, modifiers: [.command, .shift])) XCTAssertNil(ClipboardPanelController.collectionShortcutMode(forKeyCode: 29, modifiers: .command)) } + + func testCommandActionShortcutsMapToSelectedClipActions() { + XCTAssertEqual(ClipboardPanelController.commandShortcutAction(forKeyCode: 8, modifiers: .command), .copy) + XCTAssertEqual(ClipboardPanelController.commandShortcutAction(forKeyCode: 31, modifiers: .command), .open) + XCTAssertEqual(ClipboardPanelController.commandShortcutAction(forKeyCode: 15, modifiers: .command), .reveal) + } + + func testCommandActionShortcutsRequireCommandOnlySoSearchTypingIsUntouched() { + XCTAssertNil(ClipboardPanelController.commandShortcutAction(forKeyCode: 8, modifiers: [])) + XCTAssertNil(ClipboardPanelController.commandShortcutAction(forKeyCode: 8, modifiers: [.command, .shift])) + XCTAssertNil(ClipboardPanelController.commandShortcutAction(forKeyCode: 9, modifiers: .command)) + } }