parent
4dac019386
commit
8e7291f441
|
@ -14,12 +14,14 @@ struct ContentView: View {
|
|||
VStack {
|
||||
HStack {
|
||||
KeyboardShortcuts.Recorder(for: .testShortcut1)
|
||||
Text("Is pressed? \(isPressed1 ? "Yes" : "No")")
|
||||
.padding(.trailing, 10)
|
||||
Text("Pressed? \(isPressed1 ? "👍" : "👎")")
|
||||
.frame(width: 100, alignment: .leading)
|
||||
}
|
||||
HStack {
|
||||
KeyboardShortcuts.Recorder(for: .testShortcut2)
|
||||
Text("Is pressed? \(isPressed2 ? "Yes" : "No")")
|
||||
.padding(.trailing, 10)
|
||||
Text("Pressed? \(isPressed2 ? "👍" : "👎")")
|
||||
.frame(width: 100, alignment: .leading)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,12 +40,21 @@ extension KeyboardShortcuts {
|
|||
return size
|
||||
}
|
||||
|
||||
private var cancelButton: NSButtonCell?
|
||||
|
||||
private var showsCancelButton: Bool {
|
||||
get { (cell as? NSSearchFieldCell)?.cancelButtonCell != nil }
|
||||
set {
|
||||
(cell as? NSSearchFieldCell)?.cancelButtonCell = newValue ? cancelButton : nil
|
||||
}
|
||||
}
|
||||
|
||||
public required init(for name: Name) {
|
||||
self.shortcutName = name
|
||||
|
||||
super.init(frame: .zero)
|
||||
self.delegate = self
|
||||
self.placeholderString = "Click to Record"
|
||||
self.placeholderString = "Record Shortcut"
|
||||
self.centersPlaceholder = true
|
||||
self.alignment = .center
|
||||
(self.cell as? NSSearchFieldCell)?.searchButtonCell = nil
|
||||
|
@ -59,6 +68,10 @@ extension KeyboardShortcuts {
|
|||
self.setContentHuggingPriority(.defaultHigh, for: .vertical)
|
||||
self.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
||||
self.widthAnchor.constraint(greaterThanOrEqualToConstant: CGFloat(minimumWidth)).isActive = true
|
||||
|
||||
// Hide the cancel button when not showing the shortcut so the placeholder text is properly centered. Must be last.
|
||||
self.cancelButton = (self.cell as? NSSearchFieldCell)?.cancelButtonCell
|
||||
self.showsCancelButton = !stringValue.isEmpty
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
|
@ -71,12 +84,20 @@ extension KeyboardShortcuts {
|
|||
if stringValue.isEmpty {
|
||||
userDefaultsRemove(name: shortcutName)
|
||||
}
|
||||
|
||||
showsCancelButton = !stringValue.isEmpty
|
||||
|
||||
if stringValue.isEmpty {
|
||||
// Hack to ensure that the placeholder centers after the above `showsCancelButton` setter.
|
||||
focus()
|
||||
}
|
||||
}
|
||||
|
||||
/// :nodoc:
|
||||
public func controlTextDidEndEditing(_ object: Notification) {
|
||||
eventMonitor = nil
|
||||
placeholderString = "Click to Record"
|
||||
placeholderString = "Record Shortcut"
|
||||
showsCancelButton = !stringValue.isEmpty
|
||||
}
|
||||
|
||||
/// :nodoc:
|
||||
|
@ -88,17 +109,36 @@ extension KeyboardShortcuts {
|
|||
}
|
||||
|
||||
placeholderString = "Press Shortcut"
|
||||
showsCancelButton = !stringValue.isEmpty
|
||||
hideCaret()
|
||||
|
||||
eventMonitor = LocalEventMonitor(events: [.keyDown]) { [weak self] event in
|
||||
eventMonitor = LocalEventMonitor(events: [.keyDown, .leftMouseUp, .rightMouseUp]) { [weak self] event in
|
||||
guard let self = self else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let clickPoint = self.convert(event.locationInWindow, from: nil)
|
||||
let clickMargin: CGFloat = 3
|
||||
|
||||
if
|
||||
(event.type == .leftMouseUp || event.type == .rightMouseUp),
|
||||
!self.frame.insetBy(dx: -clickMargin, dy: -clickMargin).contains(clickPoint)
|
||||
{
|
||||
self.blur()
|
||||
return nil
|
||||
}
|
||||
|
||||
guard event.isKeyEvent else {
|
||||
return nil
|
||||
}
|
||||
|
||||
if
|
||||
event.modifiers.isEmpty,
|
||||
event.specialKey == .tab
|
||||
{
|
||||
self.blur()
|
||||
|
||||
// We intentionally bubble up the event so it can focus the next responder.
|
||||
return event
|
||||
}
|
||||
|
||||
|
@ -134,24 +174,37 @@ extension KeyboardShortcuts {
|
|||
}
|
||||
|
||||
if let menuItem = shortcut.takenByMainMenu {
|
||||
// TODO: Find a better way to make it possible to dismiss the alert by pressing "Enter". How can we make the input automatically temporarily lose focus while the alert is open?
|
||||
self.blur()
|
||||
|
||||
NSAlert.showModal(
|
||||
for: self.window,
|
||||
message: "This keyboard shortcut cannot be used as it's already used by the “\(menuItem.title)” menu item."
|
||||
)
|
||||
|
||||
self.focus()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
guard !shortcut.isTakenBySystem else {
|
||||
self.blur()
|
||||
|
||||
NSAlert.showModal(
|
||||
for: self.window,
|
||||
message: "This keyboard shortcut cannot be used as it's already a system-wide keyboard shortcut.",
|
||||
// TODO: Add button to offer to open the relevant system preference pane for the user.
|
||||
informativeText: "Most system-wide keyboard shortcuts can be changed in “System Preferences › Keyboard › Shortcuts“."
|
||||
)
|
||||
|
||||
self.focus()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
self.stringValue = "\(shortcut)"
|
||||
self.showsCancelButton = true
|
||||
|
||||
userDefaultsSet(name: self.shortcutName, shortcut: shortcut)
|
||||
self.blur()
|
||||
|
||||
|
@ -161,6 +214,10 @@ extension KeyboardShortcuts {
|
|||
return shouldBecomeFirstResponder
|
||||
}
|
||||
|
||||
private func focus() {
|
||||
window?.makeFirstResponder(self)
|
||||
}
|
||||
|
||||
private func blur() {
|
||||
window?.makeFirstResponder(nil)
|
||||
}
|
||||
|
|
BIN
screenshot.png
BIN
screenshot.png
Binary file not shown.
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 82 KiB |
Loading…
Reference in New Issue