From e934a4d3f53cac734086ae8a8357e1683ce73f9c Mon Sep 17 00:00:00 2001 From: James Magahern Date: Mon, 21 Sep 2020 18:35:39 -0700 Subject: [PATCH] Keyboard shortcuts --- App/AppDelegate.swift | 50 ++++++++++++++++++++ App/Browser View/BrowserViewController.swift | 37 ++++++++++++++- App/KeyboardShortcuts.swift | 29 ++++++++++++ App/Utilities/UIKeyCommand+ConvInit.swift | 15 ++++++ SBrowser.xcodeproj/project.pbxproj | 8 ++++ 5 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 App/KeyboardShortcuts.swift create mode 100644 App/Utilities/UIKeyCommand+ConvInit.swift diff --git a/App/AppDelegate.swift b/App/AppDelegate.swift index 679a446..6971543 100644 --- a/App/AppDelegate.swift +++ b/App/AppDelegate.swift @@ -21,5 +21,55 @@ class AppDelegate: UIResponder, UIApplicationDelegate { { return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } + + override func buildMenu(with builder: UIMenuBuilder) { + let fileCommands = [ + // Open Location... + UIKeyCommand( + modifiers: .command, input: "L", + title: "Open Location", + action: #selector(ShortcutResponder.focusURLBar) + ), + + // 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) + ), + + // Next Tab + UIKeyCommand( + modifiers: [.command, .shift], input: "]", + title: "Next Tab", + action: #selector(ShortcutResponder.nextTab) + ), + ] + + builder.replaceChildren(ofMenu: .file) { children in + return fileCommands + children + } + } } diff --git a/App/Browser View/BrowserViewController.swift b/App/Browser View/BrowserViewController.swift index f72378e..d8e5b3a 100644 --- a/App/Browser View/BrowserViewController.swift +++ b/App/Browser View/BrowserViewController.swift @@ -11,7 +11,7 @@ import UniformTypeIdentifiers class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegate, UITextFieldDelegate, ScriptPolicyViewControllerDelegate, UIPopoverPresentationControllerDelegate, TabDelegate, TabPickerViewControllerDelegate, - AutocompleteViewControllerDelegate + AutocompleteViewControllerDelegate, ShortcutResponder { let browserView = BrowserView() var tab: Tab { didSet { didChangeTab(tab) } } @@ -428,4 +428,39 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat tab.beginLoadingURL(item.url) autocompleteViewController.view.isHidden = true } + + // MARK: Keyboard shortcuts + + func focusURLBar(_ sender: Any?) { + toolbarController.urlBar.textField.becomeFirstResponder() + } + + func goBack(_ sender: Any?) { + tab.webView.goBack() + } + + func goForward(_ sender: Any?) { + tab.webView.goForward() + } + + func createTab(_ sender: Any?) { + let newTab = tabController.createNewTab(url: nil) + self.tab = newTab + } + + func previousTab(_ sender: Any?) { + if let tabIndex = tabController.tabs.firstIndex(of: self.tab) { + if tabIndex - 1 >= 0 { + self.tab = tabController.tabs[tabIndex - 1] + } + } + } + + func nextTab(_ sender: Any?) { + if let tabIndex = tabController.tabs.firstIndex(of: self.tab) { + if tabIndex + 1 < tabController.tabs.count { + self.tab = tabController.tabs[tabIndex + 1] + } + } + } } diff --git a/App/KeyboardShortcuts.swift b/App/KeyboardShortcuts.swift new file mode 100644 index 0000000..8d3c4ef --- /dev/null +++ b/App/KeyboardShortcuts.swift @@ -0,0 +1,29 @@ +// +// KeyboardShortcuts.swift +// App +// +// Created by James Magahern on 9/21/20. +// + +import UIKit + +@objc +protocol ShortcutResponder: class { + @objc + optional func focusURLBar(_ sender: Any?) + + @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?) +} diff --git a/App/Utilities/UIKeyCommand+ConvInit.swift b/App/Utilities/UIKeyCommand+ConvInit.swift new file mode 100644 index 0000000..77cf58f --- /dev/null +++ b/App/Utilities/UIKeyCommand+ConvInit.swift @@ -0,0 +1,15 @@ +// +// UIKeyCommand+ConvInit.swift +// App +// +// Created by James Magahern on 9/21/20. +// + +import UIKit + +extension UIKeyCommand { + convenience init(modifiers: UIKeyModifierFlags, input: String, title: String, action: Selector) { + self.init(input: input, modifierFlags: modifiers, action: action) + self.title = title + } +} diff --git a/SBrowser.xcodeproj/project.pbxproj b/SBrowser.xcodeproj/project.pbxproj index 87f2ea6..ee6d955 100644 --- a/SBrowser.xcodeproj/project.pbxproj +++ b/SBrowser.xcodeproj/project.pbxproj @@ -37,6 +37,8 @@ 1ADFF4CD24CBB0C8006DC7AE /* ScriptPolicyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ADFF4CC24CBB0C8006DC7AE /* ScriptPolicyViewController.swift */; }; 1ADFF4D024CBBCD1006DC7AE /* ScriptPolicyControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ADFF4CF24CBBCD1006DC7AE /* ScriptPolicyControl.swift */; }; CD7A8915251975B70075991E /* AutocompleteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7A8914251975B70075991E /* AutocompleteViewController.swift */; }; + CD7A89172519872D0075991E /* KeyboardShortcuts.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7A89162519872D0075991E /* KeyboardShortcuts.swift */; }; + CD7A8919251989C90075991E /* UIKeyCommand+ConvInit.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7A8918251989C90075991E /* UIKeyCommand+ConvInit.swift */; }; CD853BCE24E7763900D2BDCC /* BrowserHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD853BCD24E7763900D2BDCC /* BrowserHistory.swift */; }; CD853BD124E778B800D2BDCC /* History.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = CD853BCF24E778B800D2BDCC /* History.xcdatamodeld */; }; CD853BD424E77BF900D2BDCC /* HistoryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD853BD324E77BF900D2BDCC /* HistoryItem.swift */; }; @@ -106,6 +108,8 @@ 1ADFF4CC24CBB0C8006DC7AE /* ScriptPolicyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptPolicyViewController.swift; sourceTree = ""; }; 1ADFF4CF24CBBCD1006DC7AE /* ScriptPolicyControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptPolicyControl.swift; sourceTree = ""; }; CD7A8914251975B70075991E /* AutocompleteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteViewController.swift; sourceTree = ""; }; + CD7A89162519872D0075991E /* KeyboardShortcuts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardShortcuts.swift; sourceTree = ""; }; + CD7A8918251989C90075991E /* UIKeyCommand+ConvInit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIKeyCommand+ConvInit.swift"; sourceTree = ""; }; CD853BCD24E7763900D2BDCC /* BrowserHistory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserHistory.swift; sourceTree = ""; }; CD853BD024E778B800D2BDCC /* History.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = History.xcdatamodel; sourceTree = ""; }; CD853BD324E77BF900D2BDCC /* HistoryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryItem.swift; sourceTree = ""; }; @@ -194,6 +198,7 @@ children = ( 1ADFF45F24C7DE53006DC7AE /* AppDelegate.swift */, 1ADFF46124C7DE53006DC7AE /* SceneDelegate.swift */, + CD7A89162519872D0075991E /* KeyboardShortcuts.swift */, CD7A89132519759D0075991E /* Autocomplete */, 1ADFF47A24C7E176006DC7AE /* Backend */, 1ADFF47724C7DFE8006DC7AE /* Browser View */, @@ -272,6 +277,7 @@ isa = PBXGroup; children = ( 1ADFF4C224CA6AF6006DC7AE /* Geometry.swift */, + CD7A8918251989C90075991E /* UIKeyCommand+ConvInit.swift */, 1ADFF4C624CA6DEB006DC7AE /* UIEdgeInsets+Layout.swift */, 1AB88F0524D4D3A90006F850 /* UIGestureRecognizer+Actions.swift */, ); @@ -413,6 +419,7 @@ 1A03811224E71EAA00826501 /* GradientView.swift in Sources */, 1ADFF4C024CA6964006DC7AE /* URLBar.swift in Sources */, CD853BD124E778B800D2BDCC /* History.xcdatamodeld in Sources */, + CD7A8919251989C90075991E /* UIKeyCommand+ConvInit.swift in Sources */, 1ADFF4C724CA6DEB006DC7AE /* UIEdgeInsets+Layout.swift in Sources */, 1ADFF4AE24C8ED32006DC7AE /* ResourcePolicyManager.swift in Sources */, 1ADFF47424C7DE9C006DC7AE /* BrowserViewController.swift in Sources */, @@ -429,6 +436,7 @@ 1AB88EFD24D3BA560006F850 /* TabController.swift in Sources */, 1ADFF4C324CA6AF6006DC7AE /* Geometry.swift in Sources */, 1ADFF4C924CA793E006DC7AE /* ToolbarViewController.swift in Sources */, + CD7A89172519872D0075991E /* KeyboardShortcuts.swift in Sources */, 1ADFF4CD24CBB0C8006DC7AE /* ScriptPolicyViewController.swift in Sources */, 1A14FC2824D26749009B3F83 /* Tab.swift in Sources */, 1ADFF47924C7DFF8006DC7AE /* BrowserView.swift in Sources */,