2020-09-21 18:35:39 -07:00
|
|
|
//
|
|
|
|
|
// KeyboardShortcuts.swift
|
|
|
|
|
// App
|
|
|
|
|
//
|
|
|
|
|
// Created by James Magahern on 9/21/20.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import UIKit
|
|
|
|
|
|
|
|
|
|
@objc
|
2021-02-15 22:47:02 -08:00
|
|
|
protocol ShortcutResponder: AnyObject {
|
2020-09-21 18:35:39 -07:00
|
|
|
@objc
|
|
|
|
|
optional func focusURLBar(_ sender: Any?)
|
|
|
|
|
|
2021-03-04 16:07:30 -08:00
|
|
|
@objc
|
|
|
|
|
optional func focusWebView(_ sender: Any?)
|
|
|
|
|
|
2020-09-21 18:35:39 -07:00
|
|
|
@objc
|
|
|
|
|
optional func goBack(_ sender: Any?)
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
optional func goForward(_ sender: Any?)
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
optional func createTab(_ sender: Any?)
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
optional func previousTab(_ sender: Any?)
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
optional func nextTab(_ sender: Any?)
|
2020-09-30 18:06:47 -07:00
|
|
|
|
2020-11-10 11:57:40 -06:00
|
|
|
@objc
|
|
|
|
|
optional func closeTab(_ sender: Any?)
|
|
|
|
|
|
2020-09-30 18:06:47 -07:00
|
|
|
@objc
|
|
|
|
|
optional func findOnPage(_ sender: Any?)
|
2020-11-10 16:41:19 -06:00
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
optional func refresh(_ sender: Any?)
|
2021-03-03 16:17:54 -08:00
|
|
|
|
2022-05-09 14:37:41 -07:00
|
|
|
@objc
|
|
|
|
|
optional func stop(_ sender: Any?)
|
|
|
|
|
|
2021-03-03 16:17:54 -08:00
|
|
|
@objc
|
|
|
|
|
optional func showPreferences(_ sender: Any?)
|
2021-03-08 23:38:01 -08:00
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
optional func toggleDarkMode(_ sender: Any?)
|
2022-08-22 17:18:50 -07:00
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
optional func openInReaderMode(_ sender: Any?)
|
2023-01-20 17:28:15 -08:00
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
optional func showHistory(_ sender: Any?)
|
|
|
|
|
|
|
|
|
|
@objc
|
2023-01-27 13:46:23 -08:00
|
|
|
optional func handleOpenURL(_ sender: Any?, forEvent event: OpenURLEvent?)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class OpenURLEvent: UIEvent {
|
|
|
|
|
let url: URL
|
|
|
|
|
public init(url: URL) {
|
|
|
|
|
self.url = url
|
|
|
|
|
}
|
2020-09-21 18:35:39 -07:00
|
|
|
}
|
2022-05-09 14:37:41 -07:00
|
|
|
|
2022-08-03 19:04:40 -07:00
|
|
|
fileprivate extension Array {
|
|
|
|
|
func removeNulls() -> Array {
|
|
|
|
|
self.filter { element in
|
|
|
|
|
guard let keyCommand = element as? UIKeyCommand else { return true }
|
|
|
|
|
return !keyCommand.isNull()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-09 14:37:41 -07:00
|
|
|
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)
|
|
|
|
|
),
|
|
|
|
|
|
2022-08-22 17:18:50 -07:00
|
|
|
// Open in Reader
|
|
|
|
|
UIKeyCommand(
|
|
|
|
|
modifiers: [ .command, .shift ], input: "R",
|
|
|
|
|
title: "Open in Reader Mode…",
|
|
|
|
|
action: #selector(ShortcutResponder.openInReaderMode)
|
|
|
|
|
),
|
|
|
|
|
|
2022-05-09 14:37:41 -07:00
|
|
|
// 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)
|
|
|
|
|
)
|
|
|
|
|
]),
|
2022-08-03 19:04:40 -07:00
|
|
|
].removeNulls()
|
2022-05-09 14:37:41 -07:00
|
|
|
|
|
|
|
|
case .go:
|
|
|
|
|
return [
|
|
|
|
|
// Focus Web View
|
|
|
|
|
UIKeyCommand(
|
2022-06-28 16:59:47 -07:00
|
|
|
modifiers: [ .command, .shift ], input: "w",
|
2022-05-09 14:37:41 -07:00
|
|
|
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()
|
|
|
|
|
}
|
|
|
|
|
}
|