KeyboardShortcuts: Better organization
This commit is contained in:
@@ -28,113 +28,20 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||||||
return UISceneConfiguration(name: "Browser", sessionRole: connectingSceneSession.role)
|
return UISceneConfiguration(name: "Browser", sessionRole: connectingSceneSession.role)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func appMenuShortcuts() -> [UIKeyCommand] {
|
|
||||||
[
|
|
||||||
// Preferences
|
|
||||||
UIKeyCommand(
|
|
||||||
modifiers: .command,
|
|
||||||
input: ",",
|
|
||||||
title: "Preferences",
|
|
||||||
action: #selector(ShortcutResponder.showPreferences)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
static func fileMenuShortcuts() -> [UIKeyCommand] {
|
|
||||||
[
|
|
||||||
// Open Location...
|
|
||||||
UIKeyCommand(
|
|
||||||
modifiers: .command, input: "L",
|
|
||||||
title: "Open Location",
|
|
||||||
action: #selector(ShortcutResponder.focusURLBar)
|
|
||||||
),
|
|
||||||
|
|
||||||
// Focus Web View
|
|
||||||
UIKeyCommand(
|
|
||||||
modifiers: .command, input: "e",
|
|
||||||
title: "Focus Web View",
|
|
||||||
action: #selector(ShortcutResponder.focusWebView)
|
|
||||||
),
|
|
||||||
|
|
||||||
// Go Back
|
|
||||||
UIKeyCommand(
|
|
||||||
modifiers: .command, input: "[",
|
|
||||||
title: "Go Back",
|
|
||||||
action: #selector(ShortcutResponder.goBack)
|
|
||||||
),
|
|
||||||
|
|
||||||
// Go Forward
|
|
||||||
UIKeyCommand(
|
|
||||||
modifiers: .command, input: "]",
|
|
||||||
title: "Go Forward",
|
|
||||||
action: #selector(ShortcutResponder.goForward)
|
|
||||||
),
|
|
||||||
|
|
||||||
// Create Tab
|
|
||||||
UIKeyCommand(
|
|
||||||
modifiers: .command, input: "T",
|
|
||||||
title: "New Tab",
|
|
||||||
action: #selector(ShortcutResponder.createTab)
|
|
||||||
),
|
|
||||||
|
|
||||||
// Previous Tab
|
|
||||||
UIKeyCommand(
|
|
||||||
modifiers: [.command, .shift], input: "[",
|
|
||||||
title: "Previous Tab",
|
|
||||||
action: #selector(ShortcutResponder.previousTab)
|
|
||||||
),
|
|
||||||
|
|
||||||
// Close tab
|
|
||||||
UIKeyCommand(
|
|
||||||
modifiers: [.command], input: "W",
|
|
||||||
title: "Close Tab",
|
|
||||||
action: #selector(ShortcutResponder.closeTab)
|
|
||||||
),
|
|
||||||
|
|
||||||
// Next Tab
|
|
||||||
UIKeyCommand(
|
|
||||||
modifiers: [.command, .shift], input: "]",
|
|
||||||
title: "Next Tab",
|
|
||||||
action: #selector(ShortcutResponder.nextTab)
|
|
||||||
),
|
|
||||||
|
|
||||||
// Find on page
|
|
||||||
(FindOnPageViewController.isEnabled() ?
|
|
||||||
UIKeyCommand(
|
|
||||||
modifiers: [.command], input: "F",
|
|
||||||
title: "Find on Page",
|
|
||||||
action: #selector(ShortcutResponder.findOnPage)
|
|
||||||
)
|
|
||||||
: UIKeyCommand.null()
|
|
||||||
),
|
|
||||||
|
|
||||||
// Refresh
|
|
||||||
UIKeyCommand(
|
|
||||||
modifiers: [.command], input: "R",
|
|
||||||
title: "Refresh",
|
|
||||||
action: #selector(ShortcutResponder.refresh)
|
|
||||||
),
|
|
||||||
|
|
||||||
// Toggle Dark Mode
|
|
||||||
UIKeyCommand(
|
|
||||||
modifiers: [.command], input: "M",
|
|
||||||
title: "Toggle Dark Mode",
|
|
||||||
action: #selector(ShortcutResponder.toggleDarkMode)
|
|
||||||
),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
override var keyCommands: [UIKeyCommand]? {
|
override var keyCommands: [UIKeyCommand]? {
|
||||||
get { return Self.fileMenuShortcuts() + Self.appMenuShortcuts() }
|
get { KeyboardShortcuts.allKeyCommands() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override func buildMenu(with builder: UIMenuBuilder) {
|
override func buildMenu(with builder: UIMenuBuilder) {
|
||||||
|
// File
|
||||||
builder.replaceChildren(ofMenu: .file) { children in
|
builder.replaceChildren(ofMenu: .file) { children in
|
||||||
return Self.fileMenuShortcuts() + children
|
return KeyboardShortcuts.menu(for: .file) + children
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X Format X
|
||||||
builder.remove(menu: .format)
|
builder.remove(menu: .format)
|
||||||
|
|
||||||
|
// Application
|
||||||
builder.replaceChildren(ofMenu: .application, from: { children in
|
builder.replaceChildren(ofMenu: .application, from: { children in
|
||||||
let index = children.firstIndex(where: { elem in
|
let index = children.firstIndex(where: { elem in
|
||||||
if let elem = elem as? UIMenu {
|
if let elem = elem as? UIMenu {
|
||||||
@@ -144,14 +51,23 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||||||
})
|
})
|
||||||
|
|
||||||
var newChildren = children
|
var newChildren = children
|
||||||
|
let shortcuts = KeyboardShortcuts.menu(for: .application)
|
||||||
if let index = index {
|
if let index = index {
|
||||||
newChildren.insert(contentsOf: Self.appMenuShortcuts(), at: index + 1)
|
newChildren.insert(contentsOf: shortcuts, at: index + 1)
|
||||||
} else {
|
} else {
|
||||||
newChildren.append(contentsOf: Self.appMenuShortcuts())
|
newChildren.append(contentsOf: shortcuts)
|
||||||
}
|
}
|
||||||
|
|
||||||
return newChildren
|
return newChildren
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Go
|
||||||
|
builder.insertSibling(UIMenu(title: "Go", children: KeyboardShortcuts.menu(for: .go)), beforeMenu: .view)
|
||||||
|
|
||||||
|
// View
|
||||||
|
builder.replaceChildren(ofMenu: .view) { children in
|
||||||
|
KeyboardShortcuts.menu(for: .view) + children
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,9 +39,173 @@ protocol ShortcutResponder: AnyObject {
|
|||||||
@objc
|
@objc
|
||||||
optional func refresh(_ sender: Any?)
|
optional func refresh(_ sender: Any?)
|
||||||
|
|
||||||
|
@objc
|
||||||
|
optional func stop(_ sender: Any?)
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
optional func showPreferences(_ sender: Any?)
|
optional func showPreferences(_ sender: Any?)
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
optional func toggleDarkMode(_ sender: Any?)
|
optional func toggleDarkMode(_ sender: Any?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class KeyboardShortcuts {
|
||||||
|
public enum Category: CaseIterable {
|
||||||
|
case application
|
||||||
|
case file
|
||||||
|
case go
|
||||||
|
case view
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func menu(for category: Category) -> [UIMenuElement] {
|
||||||
|
switch category {
|
||||||
|
case .application:
|
||||||
|
return [
|
||||||
|
// Preferences
|
||||||
|
UIKeyCommand(
|
||||||
|
modifiers: .command,
|
||||||
|
input: ",",
|
||||||
|
title: "Preferences",
|
||||||
|
action: #selector(ShortcutResponder.showPreferences)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
case .file:
|
||||||
|
return [
|
||||||
|
// Open Location...
|
||||||
|
UIKeyCommand(
|
||||||
|
modifiers: .command, input: "L",
|
||||||
|
title: "Open Location",
|
||||||
|
action: #selector(ShortcutResponder.focusURLBar)
|
||||||
|
),
|
||||||
|
|
||||||
|
// Tabs
|
||||||
|
UIMenu(options: .displayInline, children: [
|
||||||
|
// Create Tab
|
||||||
|
UIKeyCommand(
|
||||||
|
modifiers: .command, input: "T",
|
||||||
|
title: "New Tab",
|
||||||
|
action: #selector(ShortcutResponder.createTab)
|
||||||
|
),
|
||||||
|
|
||||||
|
// Close tab
|
||||||
|
UIKeyCommand(
|
||||||
|
modifiers: [.command], input: "W",
|
||||||
|
title: "Close Tab",
|
||||||
|
action: #selector(ShortcutResponder.closeTab)
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
|
||||||
|
// Find on page
|
||||||
|
(FindOnPageViewController.isEnabled() ?
|
||||||
|
UIKeyCommand(
|
||||||
|
modifiers: [.command], input: "F",
|
||||||
|
title: "Find on Page",
|
||||||
|
action: #selector(ShortcutResponder.findOnPage)
|
||||||
|
)
|
||||||
|
: UIKeyCommand.null()
|
||||||
|
),
|
||||||
|
|
||||||
|
UIMenu(options: .displayInline, children: [
|
||||||
|
// Refresh
|
||||||
|
UIKeyCommand(
|
||||||
|
modifiers: [.command], input: "R",
|
||||||
|
title: "Refresh",
|
||||||
|
action: #selector(ShortcutResponder.refresh)
|
||||||
|
),
|
||||||
|
|
||||||
|
// Stop
|
||||||
|
UIKeyCommand(
|
||||||
|
modifiers: [.command], input: ".",
|
||||||
|
title: "Stop",
|
||||||
|
action: #selector(ShortcutResponder.stop)
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
]
|
||||||
|
|
||||||
|
case .go:
|
||||||
|
return [
|
||||||
|
// Focus Web View
|
||||||
|
UIKeyCommand(
|
||||||
|
modifiers: .command, input: "e",
|
||||||
|
title: "Focus Web View",
|
||||||
|
action: #selector(ShortcutResponder.focusWebView)
|
||||||
|
),
|
||||||
|
|
||||||
|
// Back/Forward
|
||||||
|
UIMenu(options: .displayInline, children: [
|
||||||
|
// Go Back
|
||||||
|
UIKeyCommand(
|
||||||
|
modifiers: .command, input: "[",
|
||||||
|
title: "Go Back",
|
||||||
|
action: #selector(ShortcutResponder.goBack)
|
||||||
|
),
|
||||||
|
|
||||||
|
// Go Forward
|
||||||
|
UIKeyCommand(
|
||||||
|
modifiers: .command, input: "]",
|
||||||
|
title: "Go Forward",
|
||||||
|
action: #selector(ShortcutResponder.goForward)
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
|
||||||
|
// Tab Navigation
|
||||||
|
UIMenu(options: .displayInline, children: [
|
||||||
|
// Previous Tab
|
||||||
|
UIKeyCommand(
|
||||||
|
modifiers: [.command, .shift], input: "[",
|
||||||
|
title: "Previous Tab",
|
||||||
|
action: #selector(ShortcutResponder.previousTab)
|
||||||
|
),
|
||||||
|
|
||||||
|
// Next Tab
|
||||||
|
UIKeyCommand(
|
||||||
|
modifiers: [.command, .shift], input: "]",
|
||||||
|
title: "Next Tab",
|
||||||
|
action: #selector(ShortcutResponder.nextTab)
|
||||||
|
),
|
||||||
|
])
|
||||||
|
]
|
||||||
|
|
||||||
|
case .view:
|
||||||
|
return [
|
||||||
|
// Toggle Dark Mode
|
||||||
|
UIKeyCommand(
|
||||||
|
modifiers: [.command], input: "M",
|
||||||
|
title: "Toggle Dark Mode",
|
||||||
|
action: #selector(ShortcutResponder.toggleDarkMode)
|
||||||
|
),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func hiddenKeyCommands() -> [UIKeyCommand] {
|
||||||
|
return [
|
||||||
|
// Go Back
|
||||||
|
UIKeyCommand(input: UIKeyCommand.inputLeftArrow,
|
||||||
|
modifierFlags: [.command, .control],
|
||||||
|
action: #selector(ShortcutResponder.goBack)),
|
||||||
|
|
||||||
|
// Go Forward
|
||||||
|
UIKeyCommand(input: UIKeyCommand.inputRightArrow,
|
||||||
|
modifierFlags: [.command, .control],
|
||||||
|
action: #selector(ShortcutResponder.goForward)),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func allKeyCommands() -> [UIKeyCommand] {
|
||||||
|
var commands: [UIKeyCommand] = []
|
||||||
|
for category in Category.allCases {
|
||||||
|
let menuElements = menu(for: category)
|
||||||
|
for element in menuElements {
|
||||||
|
if let command = element as? UIKeyCommand {
|
||||||
|
commands.append(command)
|
||||||
|
} else if let menu = element as? UIMenu {
|
||||||
|
commands.append(contentsOf: menu.children as! [UIKeyCommand])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return commands + Self.hiddenKeyCommands()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user