From eb7560b32799a0f7872052491f1943856cc0ae1d Mon Sep 17 00:00:00 2001 From: Jordan Baird Date: Mon, 21 Aug 2023 00:27:54 -0600 Subject: [PATCH] Minor code refactoring --- Sources/SwiftKeys/KeyCommand/Key.swift | 550 +++++++----------- .../KeyCommand/KeyCommandProxy.swift | 4 +- Sources/SwiftKeys/KeyCommand/Modifier.swift | 25 +- 3 files changed, 215 insertions(+), 364 deletions(-) diff --git a/Sources/SwiftKeys/KeyCommand/Key.swift b/Sources/SwiftKeys/KeyCommand/Key.swift index 64a4b64..84e668d 100644 --- a/Sources/SwiftKeys/KeyCommand/Key.swift +++ b/Sources/SwiftKeys/KeyCommand/Key.swift @@ -5,8 +5,6 @@ import Carbon.HIToolbox -// MARK: - KeyCommand Key - extension KeyCommand { /// Constants that represent the various keys available on a keyboard. public enum Key { @@ -107,7 +105,7 @@ extension KeyCommand { case period /// The ANSI "/" key. case slash - /// The ANSI "`" key. + /// The ANSI "\`" key. case grave /// The ANSI keypad Decimal key. @@ -157,7 +155,7 @@ extension KeyCommand { case space /// The layout-independent Delete key. case delete - /// The layout-independent Forward Felete key. + /// The layout-independent Forward Delete key. case forwardDelete /// The layout-independent Escape key. case escape @@ -246,230 +244,78 @@ extension KeyCommand { } } -// MARK: Key Properties +// MARK: Custom String Value extension KeyCommand.Key { - /// The key's raw value. - public var rawValue: Int { - switch self { - case .a: - return kVK_ANSI_A - case .b: - return kVK_ANSI_B - case .c: - return kVK_ANSI_C - case .d: - return kVK_ANSI_D - case .e: - return kVK_ANSI_E - case .f: - return kVK_ANSI_F - case .g: - return kVK_ANSI_G - case .h: - return kVK_ANSI_H - case .i: - return kVK_ANSI_I - case .j: - return kVK_ANSI_J - case .k: - return kVK_ANSI_K - case .l: - return kVK_ANSI_L - case .m: - return kVK_ANSI_M - case .n: - return kVK_ANSI_N - case .o: - return kVK_ANSI_O - case .p: - return kVK_ANSI_P - case .q: - return kVK_ANSI_Q - case .r: - return kVK_ANSI_R - case .s: - return kVK_ANSI_S - case .t: - return kVK_ANSI_T - case .u: - return kVK_ANSI_U - case .v: - return kVK_ANSI_V - case .w: - return kVK_ANSI_W - case .x: - return kVK_ANSI_X - case .y: - return kVK_ANSI_Y - case .z: - return kVK_ANSI_Z - case .zero: - return kVK_ANSI_0 - case .one: - return kVK_ANSI_1 - case .two: - return kVK_ANSI_2 - case .three: - return kVK_ANSI_3 - case .four: - return kVK_ANSI_4 - case .five: - return kVK_ANSI_5 - case .six: - return kVK_ANSI_6 - case .seven: - return kVK_ANSI_7 - case .eight: - return kVK_ANSI_8 - case .nine: - return kVK_ANSI_9 - case .minus: - return kVK_ANSI_Minus - case .equals: - return kVK_ANSI_Equal - case .leftBracket: - return kVK_ANSI_LeftBracket - case .rightBracket: - return kVK_ANSI_RightBracket - case .backslash: - return kVK_ANSI_Backslash - case .semicolon: - return kVK_ANSI_Semicolon - case .quote: - return kVK_ANSI_Quote - case .comma: - return kVK_ANSI_Comma - case .period: - return kVK_ANSI_Period - case .slash: - return kVK_ANSI_Slash - case .grave: - return kVK_ANSI_Grave - case .keypadDecimal: - return kVK_ANSI_KeypadDecimal - case .keypadMultiply: - return kVK_ANSI_KeypadMultiply - case .keypadPlus: - return kVK_ANSI_KeypadPlus - case .keypadClear: - return kVK_ANSI_KeypadClear - case .keypadDivide: - return kVK_ANSI_KeypadDivide - case .keypadEnter: - return kVK_ANSI_KeypadEnter - case .keypadMinus: - return kVK_ANSI_KeypadMinus - case .keypadEquals: - return kVK_ANSI_KeypadEquals - case .keypad0: - return kVK_ANSI_Keypad0 - case .keypad1: - return kVK_ANSI_Keypad1 - case .keypad2: - return kVK_ANSI_Keypad2 - case .keypad3: - return kVK_ANSI_Keypad3 - case .keypad4: - return kVK_ANSI_Keypad4 - case .keypad5: - return kVK_ANSI_Keypad5 - case .keypad6: - return kVK_ANSI_Keypad6 - case .keypad7: - return kVK_ANSI_Keypad7 - case .keypad8: - return kVK_ANSI_Keypad8 - case .keypad9: - return kVK_ANSI_Keypad9 - case .return: - return kVK_Return - case .tab: - return kVK_Tab - case .space: - return kVK_Space - case .delete: - return kVK_Delete - case .forwardDelete: - return kVK_ForwardDelete - case .escape: - return kVK_Escape - case .volumeUp: - return kVK_VolumeUp - case .volumeDown: - return kVK_VolumeDown - case .mute: - return kVK_Mute - case .home: - return kVK_Home - case .end: - return kVK_End - case .pageUp: - return kVK_PageUp - case .pageDown: - return kVK_PageDown - case .leftArrow: - return kVK_LeftArrow - case .rightArrow: - return kVK_RightArrow - case .downArrow: - return kVK_DownArrow - case .upArrow: - return kVK_UpArrow - case .f1: - return kVK_F1 - case .f2: - return kVK_F2 - case .f3: - return kVK_F3 - case .f4: - return kVK_F4 - case .f5: - return kVK_F5 - case .f6: - return kVK_F6 - case .f7: - return kVK_F7 - case .f8: - return kVK_F8 - case .f9: - return kVK_F9 - case .f10: - return kVK_F10 - case .f11: - return kVK_F11 - case .f12: - return kVK_F12 - case .f13: - return kVK_F13 - case .f14: - return kVK_F14 - case .f15: - return kVK_F15 - case .f16: - return kVK_F16 - case .f17: - return kVK_F17 - case .f18: - return kVK_F18 - case .f19: - return kVK_F19 - case .f20: - return kVK_F20 - case .isoSection: - return kVK_ISO_Section - case .jisYen: - return kVK_JIS_Yen - case .jisUnderscore: - return kVK_JIS_Underscore - case .jisKeypadComma: - return kVK_JIS_KeypadComma - case .jisEisu: - return kVK_JIS_Eisu - case .jisKana: - return kVK_JIS_Kana - } + /// Maps custom string representations to keys that can't be + /// represented by a key equivalent. + private static let customStringMapping: [KeyCommand.Key: String] = [ + .space: "Space", // matches macOS representation + .tab: "⇥", + .return: "⏎", + .delete: "⌫", + .forwardDelete: "⌦", + .f1: "F1", + .f2: "F2", + .f3: "F3", + .f4: "F4", + .f5: "F5", + .f6: "F6", + .f7: "F7", + .f8: "F8", + .f9: "F9", + .f10: "F10", + .f11: "F11", + .f12: "F12", + .f13: "F13", + .f14: "F14", + .f15: "F15", + .f16: "F16", + .f17: "F17", + .f18: "F18", + .f19: "F19", + .f20: "F20", + .pageUp: "⇞", + .pageDown: "⇟", + .home: "↖", + .end: "↘", + .escape: "⎋", + .leftArrow: "←", + .rightArrow: "→", + .downArrow: "↓", + .upArrow: "↑", + + // represent keypad keys with U+20E3 'COMBINING ENCLOSING KEYCAP' + .keypad0: "0\u{20E3}", + .keypad1: "1\u{20E3}", + .keypad2: "2\u{20E3}", + .keypad3: "3\u{20E3}", + .keypad4: "4\u{20E3}", + .keypad5: "5\u{20E3}", + .keypad6: "6\u{20E3}", + .keypad7: "7\u{20E3}", + .keypad8: "8\u{20E3}", + .keypad9: "9\u{20E3}", + .keypadClear: "⌧\u{20E3}", + .keypadDecimal: ".\u{20E3}", + .keypadDivide: "/\u{20E3}", + /* most keypads just spell out the word "enter"; those that use a symbol most + commonly seem to use "⌤" U+2324 'UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS' */ + .keypadEnter: "⌤\u{20E3}", + .keypadEquals: "=\u{20E3}", + .keypadMinus: "-\u{20E3}", + .keypadMultiply: "*\u{20E3}", + .keypadPlus: "+\u{20E3}", + ] + + /// Returns a custom string representation for keys that don't have + /// a representable key equivalent. + var customStringValue: String? { + Self.customStringMapping[self] } +} +// MARK: Key Equivalent +extension KeyCommand.Key { /// A string representation of the key that can be used as a key /// equivalent in a menu item. public var keyEquivalent: String { @@ -489,7 +335,7 @@ extension KeyCommand.Key { let result = UCKeyTranslate( keyLayoutPtr, - unsigned(), + UInt16(rawValue), UInt16(kUCKeyActionDisplay), 0, UInt32(LMGetKbdType()), @@ -507,83 +353,16 @@ extension KeyCommand.Key { return String(utf16CodeUnits: chars, count: length) } - /// Returns a custom string representation for keys that don't have - /// a representable key equivalent. - var customStringValue: String? { - switch self { - case .return: - return "⏎" - case .tab: - return "⇥" - case .space: - return "␣" - case .delete: - return "⌫" - case .forwardDelete: - return "⌦" - case .escape: - return "⎋" - case .home: - return "⇱" - case .end: - return "⇲" - case .pageUp: - return "⇞" - case .pageDown: - return "⇟" - case .leftArrow: - return "←" - case .rightArrow: - return "→" - case .downArrow: - return "↓" - case .upArrow: - return "↑" - case .f1: - return "F1" - case .f2: - return "F2" - case .f3: - return "F3" - case .f4: - return "F4" - case .f5: - return "F5" - case .f6: - return "F6" - case .f7: - return "F7" - case .f8: - return "F8" - case .f9: - return "F9" - case .f10: - return "F10" - case .f11: - return "F11" - case .f12: - return "F12" - case .f13: - return "F13" - case .f14: - return "F14" - case .f15: - return "F15" - case .f16: - return "F16" - case .f17: - return "F17" - case .f18: - return "F18" - case .f19: - return "F19" - case .f20: - return "F20" - default: + init?(keyEquivalent: String) { + guard let key = Self.allCases.first(where: { $0.keyEquivalent == keyEquivalent }) else { return nil } + self = key } +} +// MARK: String Value +extension KeyCommand.Key { /// A string representation of the key. /// /// - Note: Do not use this property to set the key equivalent of a @@ -591,59 +370,140 @@ extension KeyCommand.Key { /// menu item expects. To get the key's canonical key equivalent /// (i.e. the key equivalent used throughout the rest of macOS), /// use the ``keyEquivalent`` property. - public var stringValue: String { - customStringValue ?? keyEquivalent - } + public var stringValue: String { customStringValue ?? keyEquivalent } } -// MARK: Key Initializers -extension KeyCommand.Key { - /// Runs a check against all possible cases, and if a case is - /// found for which `predicate` evaluates to `true`, creates - /// a value initialized to that case. - init?(matching predicate: (Self) throws -> Bool) rethrows { - guard let key = try Self.allCases.first(where: predicate) else { - return nil - } - self = key - } - - /// Runs a check against all possible cases, and if a case is - /// found whose key equivalent matches the given string, creates - /// a value initialized to that case. - init?(keyEquivalent: String) { - self.init { key in - key.keyEquivalent == keyEquivalent - } - } - - /// Creates a key that matches the specified raw value. - public init?(rawValue: Int) { - self.init { key in - key.rawValue == rawValue - } - } -} - -// MARK: Key Methods -extension KeyCommand.Key { - /// An unsigned version of the key's raw value. - func unsigned(type _: U.Type = U.self) -> U { - U(rawValue) - } -} - -// MARK: Key: CaseIterable +// MARK: CaseIterable extension KeyCommand.Key: CaseIterable { } -// MARK: Key: Codable +// MARK: Codable extension KeyCommand.Key: Codable { } -// MARK: Key: Equatable +// MARK: Equatable extension KeyCommand.Key: Equatable { } -// MARK: Key: Hashable +// MARK: Hashable extension KeyCommand.Key: Hashable { } -// MARK: Key: RawRepresentable -extension KeyCommand.Key: RawRepresentable { } +// MARK: RawRepresentable +extension KeyCommand.Key: RawRepresentable { + public var rawValue: Int { + switch self { + case .a: return kVK_ANSI_A + case .b: return kVK_ANSI_B + case .c: return kVK_ANSI_C + case .d: return kVK_ANSI_D + case .e: return kVK_ANSI_E + case .f: return kVK_ANSI_F + case .g: return kVK_ANSI_G + case .h: return kVK_ANSI_H + case .i: return kVK_ANSI_I + case .j: return kVK_ANSI_J + case .k: return kVK_ANSI_K + case .l: return kVK_ANSI_L + case .m: return kVK_ANSI_M + case .n: return kVK_ANSI_N + case .o: return kVK_ANSI_O + case .p: return kVK_ANSI_P + case .q: return kVK_ANSI_Q + case .r: return kVK_ANSI_R + case .s: return kVK_ANSI_S + case .t: return kVK_ANSI_T + case .u: return kVK_ANSI_U + case .v: return kVK_ANSI_V + case .w: return kVK_ANSI_W + case .x: return kVK_ANSI_X + case .y: return kVK_ANSI_Y + case .z: return kVK_ANSI_Z + case .zero: return kVK_ANSI_0 + case .one: return kVK_ANSI_1 + case .two: return kVK_ANSI_2 + case .three: return kVK_ANSI_3 + case .four: return kVK_ANSI_4 + case .five: return kVK_ANSI_5 + case .six: return kVK_ANSI_6 + case .seven: return kVK_ANSI_7 + case .eight: return kVK_ANSI_8 + case .nine: return kVK_ANSI_9 + case .minus: return kVK_ANSI_Minus + case .equals: return kVK_ANSI_Equal + case .leftBracket: return kVK_ANSI_LeftBracket + case .rightBracket: return kVK_ANSI_RightBracket + case .backslash: return kVK_ANSI_Backslash + case .semicolon: return kVK_ANSI_Semicolon + case .quote: return kVK_ANSI_Quote + case .comma: return kVK_ANSI_Comma + case .period: return kVK_ANSI_Period + case .slash: return kVK_ANSI_Slash + case .grave: return kVK_ANSI_Grave + case .keypadDecimal: return kVK_ANSI_KeypadDecimal + case .keypadMultiply: return kVK_ANSI_KeypadMultiply + case .keypadPlus: return kVK_ANSI_KeypadPlus + case .keypadClear: return kVK_ANSI_KeypadClear + case .keypadDivide: return kVK_ANSI_KeypadDivide + case .keypadEnter: return kVK_ANSI_KeypadEnter + case .keypadMinus: return kVK_ANSI_KeypadMinus + case .keypadEquals: return kVK_ANSI_KeypadEquals + case .keypad0: return kVK_ANSI_Keypad0 + case .keypad1: return kVK_ANSI_Keypad1 + case .keypad2: return kVK_ANSI_Keypad2 + case .keypad3: return kVK_ANSI_Keypad3 + case .keypad4: return kVK_ANSI_Keypad4 + case .keypad5: return kVK_ANSI_Keypad5 + case .keypad6: return kVK_ANSI_Keypad6 + case .keypad7: return kVK_ANSI_Keypad7 + case .keypad8: return kVK_ANSI_Keypad8 + case .keypad9: return kVK_ANSI_Keypad9 + case .return: return kVK_Return + case .tab: return kVK_Tab + case .space: return kVK_Space + case .delete: return kVK_Delete + case .forwardDelete: return kVK_ForwardDelete + case .escape: return kVK_Escape + case .volumeUp: return kVK_VolumeUp + case .volumeDown: return kVK_VolumeDown + case .mute: return kVK_Mute + case .home: return kVK_Home + case .end: return kVK_End + case .pageUp: return kVK_PageUp + case .pageDown: return kVK_PageDown + case .leftArrow: return kVK_LeftArrow + case .rightArrow: return kVK_RightArrow + case .downArrow: return kVK_DownArrow + case .upArrow: return kVK_UpArrow + case .f1: return kVK_F1 + case .f2: return kVK_F2 + case .f3: return kVK_F3 + case .f4: return kVK_F4 + case .f5: return kVK_F5 + case .f6: return kVK_F6 + case .f7: return kVK_F7 + case .f8: return kVK_F8 + case .f9: return kVK_F9 + case .f10: return kVK_F10 + case .f11: return kVK_F11 + case .f12: return kVK_F12 + case .f13: return kVK_F13 + case .f14: return kVK_F14 + case .f15: return kVK_F15 + case .f16: return kVK_F16 + case .f17: return kVK_F17 + case .f18: return kVK_F18 + case .f19: return kVK_F19 + case .f20: return kVK_F20 + case .isoSection: return kVK_ISO_Section + case .jisYen: return kVK_JIS_Yen + case .jisUnderscore: return kVK_JIS_Underscore + case .jisKeypadComma: return kVK_JIS_KeypadComma + case .jisEisu: return kVK_JIS_Eisu + case .jisKana: return kVK_JIS_Kana + } + } + + public init?(rawValue: Int) { + guard let key = Self.allCases.first(where: { $0.rawValue == rawValue }) else { + return nil + } + self = key + } +} diff --git a/Sources/SwiftKeys/KeyCommand/KeyCommandProxy.swift b/Sources/SwiftKeys/KeyCommand/KeyCommandProxy.swift index b256a68..c2a2867 100644 --- a/Sources/SwiftKeys/KeyCommand/KeyCommandProxy.swift +++ b/Sources/SwiftKeys/KeyCommand/KeyCommandProxy.swift @@ -214,8 +214,8 @@ final class KeyCommandProxy { } status = RegisterEventHotKey( - key.unsigned(), - modifiers.unsigned(), + UInt32(key.rawValue), + UInt32(modifiers.carbonFlags), identifier, GetEventDispatcherTarget(), 0, diff --git a/Sources/SwiftKeys/KeyCommand/Modifier.swift b/Sources/SwiftKeys/KeyCommand/Modifier.swift index f3fe86b..2360967 100644 --- a/Sources/SwiftKeys/KeyCommand/Modifier.swift +++ b/Sources/SwiftKeys/KeyCommand/Modifier.swift @@ -6,8 +6,6 @@ import Carbon.HIToolbox import Cocoa -// MARK: - KeyCommand Modifier - extension KeyCommand { /// Constants that represent the modifier keys of a key command. public enum Modifier { @@ -22,7 +20,7 @@ extension KeyCommand { } } -// MARK: Modifier Properties +// MARK: Properties extension KeyCommand.Modifier { /// The modifier key's string representation. public var stringValue: String { @@ -82,20 +80,19 @@ extension KeyCommand.Modifier { } } -// MARK: Modifier: CaseIterable +// MARK: CaseIterable extension KeyCommand.Modifier: CaseIterable { } -// MARK: Modifier: Codable +// MARK: Codable extension KeyCommand.Modifier: Codable { } -// MARK: Modifier: Equatable +// MARK: Equatable extension KeyCommand.Modifier: Equatable { } -// MARK: Modifier: Hashable +// MARK: Hashable extension KeyCommand.Modifier: Hashable { } -// MARK: - [Modifier] - +// MARK: Array extension [KeyCommand.Modifier] { /// The order that macOS represents its modifier keys, according /// to the Apple Style Guide. @@ -139,16 +136,10 @@ extension [KeyCommand.Modifier] { init(carbonModifiers: Int) { self = Self.canonicalOrder.filter(carbonModifiers.bitwiseContains) } - - /// An unsigned version of the modifier keys' `carbonFlags`. - func unsigned(type _: U.Type = U.self) -> U { - U(carbonFlags) - } } -// MARK: - BinaryInteger - -extension BinaryInteger { +// MARK: BinaryInteger +private extension BinaryInteger { /// Returns a Boolean value indicating whether the bits of this /// integer contain the bits of another integer. func bitwiseContains(_ other: Other) -> Bool {