diff --git a/Frameworks/RSCore/RSCore/Keyboard.swift b/Frameworks/RSCore/RSCore/Keyboard.swift index 0334ac69c..ead55948d 100644 --- a/Frameworks/RSCore/RSCore/Keyboard.swift +++ b/Frameworks/RSCore/RSCore/Keyboard.swift @@ -6,7 +6,7 @@ // Copyright © 2017 Ranchero Software, LLC. All rights reserved. // -import Foundation +import Cocoa // To get, for instance, the keyboard integer value for "\r": "\r".keyboardIntegerValue (returns 13) @@ -14,6 +14,7 @@ public struct KeyboardConstant { public static let lineFeedKey = "\n".keyboardIntegerValue public static let returnKey = "\r".keyboardIntegerValue + public static let spaceKey = " ".keyboardIntegerValue } public extension String { @@ -22,3 +23,130 @@ public extension String { return Int(utf8[utf8.startIndex]) } } + +public struct KeyboardShortcut: Hashable { + + public let key: KeyboardKey + public let actionString: String + public let hashValue: Int + + public init?(dictionary: [String: Any]) { + + guard let key = KeyboardKey(dictionary: dictionary) else { + return nil + } + guard let actionString = dictionary["action"] as? String else { + return nil + } + + self.key = key + self.actionString = actionString + self.hashValue = key.hashValue + self.actionString.hashValue + } + + public func perform(with view: NSView) { + + let action = NSSelectorFromString(actionString) + NSApplication.shared.sendAction(action, to: nil, from: view) + } + + public static func findMatchingShortcut(in shortcuts: Set, key: KeyboardKey) -> KeyboardShortcut? { + + for shortcut in shortcuts { + if shortcut.key == key { + return shortcut + } + } + return nil + } + + public static func ==(lhs: KeyboardShortcut, rhs: KeyboardShortcut) -> Bool { + + return lhs.hashValue == rhs.hashValue && lhs.key == rhs.key && lhs.actionString == rhs.actionString + } +} + +public struct KeyboardKey: Hashable { + + public let shiftKeyDown: Bool + public let optionKeyDown: Bool + public let commandKeyDown: Bool + public let controlKeyDown: Bool + public let integerValue: Int // unmodified character as Int + + public var isModified: Bool { + return !shiftKeyDown && !optionKeyDown && !commandKeyDown && !controlKeyDown + } + + public var hashValue: Int { + return integerValue + } + + init(integerValue: Int, shiftKeyDown: Bool, optionKeyDown: Bool, commandKeyDown: Bool, controlKeyDown: Bool) { + + self.integerValue = integerValue + + self.shiftKeyDown = shiftKeyDown + self.optionKeyDown = optionKeyDown + self.commandKeyDown = commandKeyDown + self.controlKeyDown = controlKeyDown + } + + public init(with event: NSEvent) { + + let flags = event.modifierFlags + let shiftKeyDown = flags.contains(.shift) + let optionKeyDown = flags.contains(.option) + let commandKeyDown = flags.contains(.command) + let controlKeyDown = flags.contains(.control) + + let integerValue = event.charactersIgnoringModifiers?.keyboardIntegerValue ?? 0 + + self.init(integerValue: integerValue, shiftKeyDown: shiftKeyDown, optionKeyDown: optionKeyDown, commandKeyDown: commandKeyDown, controlKeyDown: controlKeyDown) + } + + + public init?(dictionary: [String: Any]) { + + guard let s = dictionary["key"] as? String else { + return nil + } + + var integerValue = 0 + + switch(s) { + case "[space]": + integerValue = " ".keyboardIntegerValue + case "[uparrow]": + integerValue = NSUpArrowFunctionKey + case "[downarrow]": + integerValue = NSDownArrowFunctionKey + case "[leftarrow]": + integerValue = NSLeftArrowFunctionKey + case "[rightarrow]": + integerValue = NSRightArrowFunctionKey + case "[return]": + integerValue = NSCarriageReturnCharacter + case "[enter]": + integerValue = NSEnterCharacter + case "[delete]": + integerValue = Int(kDeleteKeyCode) + case "[deletefunction]": + integerValue = NSDeleteFunctionKey + default: + integerValue = s.keyboardIntegerValue + } + + let shiftKeyDown = dictionary["shiftModifier"] as? Bool ?? false + let optionKeyDown = dictionary["optionModifier"] as? Bool ?? false + let commandKeyDown = dictionary["commandModifier"] as? Bool ?? false + let controlKeyDown = dictionary["controlModifier"] as? Bool ?? false + + self.init(integerValue: integerValue, shiftKeyDown: shiftKeyDown, optionKeyDown: optionKeyDown, commandKeyDown: commandKeyDown, controlKeyDown: controlKeyDown) + } + + public static func ==(lhs: KeyboardKey, rhs: KeyboardKey) -> Bool { + + return lhs.integerValue == rhs.integerValue && lhs.shiftKeyDown == rhs.shiftKeyDown && lhs.optionKeyDown == rhs.optionKeyDown && lhs.commandKeyDown == rhs.commandKeyDown && lhs.controlKeyDown == rhs.controlKeyDown + } +}