From 31d1b02dc08db9ede4daf15a90b847df16d390da Mon Sep 17 00:00:00 2001 From: Xyct <87l46110@gmail.com> Date: Mon, 1 Jul 2024 06:00:55 +0800 Subject: [PATCH] support Control key modifier combination mapping (#152) --- AKPlugin.swift | 14 ++++++--- PlayTools/Controls/Frontend/ControlMode.swift | 5 +-- .../EditorKeyboardEventAdapter.swift | 15 +++++++-- .../TouchscreenKeyboardEventAdapter.swift | 31 +++++++++++++++++-- .../TransparentKeyboardEventAdapter.swift | 2 +- .../Keyboard/KeyboardEventAdapter.swift | 2 +- Plugin.swift | 2 +- 7 files changed, 57 insertions(+), 14 deletions(-) diff --git a/AKPlugin.swift b/AKPlugin.swift index 7a6a1341..37a45331 100644 --- a/AKPlugin.swift +++ b/AKPlugin.swift @@ -66,7 +66,7 @@ class AKPlugin: NSObject, Plugin { } private var modifierFlag: UInt = 0 - func setupKeyboard(keyboard: @escaping(UInt16, Bool, Bool) -> Bool, + func setupKeyboard(keyboard: @escaping(UInt16, Bool, Bool, Bool) -> Bool, swapMode: @escaping() -> Bool) { func checkCmd(modifier: NSEvent.ModifierFlags) -> Bool { if modifier.contains(.command) { @@ -81,7 +81,8 @@ class AKPlugin: NSObject, Plugin { if checkCmd(modifier: event.modifierFlags) { return event } - let consumed = keyboard(event.keyCode, true, event.isARepeat) + let consumed = keyboard(event.keyCode, true, event.isARepeat, + event.modifierFlags.contains(.control)) if consumed { return nil } @@ -91,7 +92,8 @@ class AKPlugin: NSObject, Plugin { if checkCmd(modifier: event.modifierFlags) { return event } - let consumed = keyboard(event.keyCode, false, false) + let consumed = keyboard(event.keyCode, false, false, + event.modifierFlags.contains(.control)) if consumed { return nil } @@ -104,13 +106,15 @@ class AKPlugin: NSObject, Plugin { let pressed = self.modifierFlag < event.modifierFlags.rawValue let changed = self.modifierFlag ^ event.modifierFlags.rawValue self.modifierFlag = event.modifierFlags.rawValue - if pressed && NSEvent.ModifierFlags(rawValue: changed).contains(.option) { + let changedFlags = NSEvent.ModifierFlags(rawValue: changed) + if pressed && changedFlags.contains(.option) { if swapMode() { return nil } return event } - let consumed = keyboard(event.keyCode, pressed, false) + let consumed = keyboard(event.keyCode, pressed, false, + event.modifierFlags.contains(.control)) if consumed { return nil } diff --git a/PlayTools/Controls/Frontend/ControlMode.swift b/PlayTools/Controls/Frontend/ControlMode.swift index d5a753bb..509135d5 100644 --- a/PlayTools/Controls/Frontend/ControlMode.swift +++ b/PlayTools/Controls/Frontend/ControlMode.swift @@ -61,8 +61,9 @@ public class ControlMode: Equatable { } } - AKInterface.shared!.setupKeyboard(keyboard: { keycode, pressed, isRepeat in - self.keyboardAdapter.handleKey(keycode: keycode, pressed: pressed, isRepeat: isRepeat)}, + AKInterface.shared!.setupKeyboard(keyboard: { keycode, pressed, isRepeat, ctrlModified in + self.keyboardAdapter.handleKey(keycode: keycode, pressed: pressed, + isRepeat: isRepeat, ctrlModified: ctrlModified)}, swapMode: ModeAutomaton.onOption) if PlaySettings.shared.enableScrollWheel { diff --git a/PlayTools/Controls/Frontend/EventAdapter/Keyboard/Instances/EditorKeyboardEventAdapter.swift b/PlayTools/Controls/Frontend/EventAdapter/Keyboard/Instances/EditorKeyboardEventAdapter.swift index 796c553b..7077b665 100644 --- a/PlayTools/Controls/Frontend/EventAdapter/Keyboard/Instances/EditorKeyboardEventAdapter.swift +++ b/PlayTools/Controls/Frontend/EventAdapter/Keyboard/Instances/EditorKeyboardEventAdapter.swift @@ -16,10 +16,12 @@ public class EditorKeyboardEventAdapter: KeyboardEventAdapter { .rightGUI, .leftAlt, .rightAlt, + .leftControl, + .rightControl, .printScreen ] - public func handleKey(keycode: UInt16, pressed: Bool, isRepeat: Bool) -> Bool { + public func handleKey(keycode: UInt16, pressed: Bool, isRepeat: Bool, ctrlModified: Bool) -> Bool { if AKInterface.shared!.cmdPressed || !pressed || isRepeat { return false } @@ -31,7 +33,16 @@ public class EditorKeyboardEventAdapter: KeyboardEventAdapter { // Toast.showHint(title: "Invalid Key", text: ["This key is intentionally forbidden. Keyname: \(name)"]) return false } - EditorController.shared.setKey(rawValue) + + if ctrlModified { + if let name = KeyCodeNames.virtualCodes[keycode] { + // Setkey by name does not work with all kinds of mapping + EditorController.shared.setKey("⌃" + name) + } + } else { + EditorController.shared.setKey(rawValue) + } + return true } diff --git a/PlayTools/Controls/Frontend/EventAdapter/Keyboard/Instances/TouchscreenKeyboardEventAdapter.swift b/PlayTools/Controls/Frontend/EventAdapter/Keyboard/Instances/TouchscreenKeyboardEventAdapter.swift index 18d3251d..f9604f09 100644 --- a/PlayTools/Controls/Frontend/EventAdapter/Keyboard/Instances/TouchscreenKeyboardEventAdapter.swift +++ b/PlayTools/Controls/Frontend/EventAdapter/Keyboard/Instances/TouchscreenKeyboardEventAdapter.swift @@ -10,14 +10,41 @@ import Foundation // Keyboard events handler when keyboard mapping is on public class TouchscreenKeyboardEventAdapter: KeyboardEventAdapter { - public func handleKey(keycode: UInt16, pressed: Bool, isRepeat: Bool) -> Bool { + private var modifiedKeys: [UInt16] = [] + public func handleKey(keycode: UInt16, pressed: Bool, isRepeat: Bool, ctrlModified: Bool) -> Bool { if isRepeat { // eat, eat, eat! return true } - let name = KeyCodeNames.virtualCodes[keycode] ?? "Btn" + var name = KeyCodeNames.virtualCodes[keycode] ?? "Btn" + + if keycode == 59 || keycode == 62 { + // if this is Control + if !pressed { + // just in case followed by + // release modified keys when ctrl release + while let key = modifiedKeys.first { + _ = handleKey( + keycode: key, + pressed: false, isRepeat: false, + ctrlModified: true) + } + } + } else if ctrlModified && pressed { + name = "⌃" + name // "⌃" is not "^" + // Record pressed key + modifiedKeys.append(keycode) + + } else if !pressed && modifiedKeys.contains(keycode) { + // just in case followed by + // does not modify on release if not recorded + name = "⌃" + name // "⌃" is not "^" + // unrecord released key + modifiedKeys.removeAll(where: {code in code == keycode}) + } + return ActionDispatcher.dispatch(key: name, pressed: pressed) } diff --git a/PlayTools/Controls/Frontend/EventAdapter/Keyboard/Instances/TransparentKeyboardEventAdapter.swift b/PlayTools/Controls/Frontend/EventAdapter/Keyboard/Instances/TransparentKeyboardEventAdapter.swift index 03c181b2..e08e54f7 100644 --- a/PlayTools/Controls/Frontend/EventAdapter/Keyboard/Instances/TransparentKeyboardEventAdapter.swift +++ b/PlayTools/Controls/Frontend/EventAdapter/Keyboard/Instances/TransparentKeyboardEventAdapter.swift @@ -10,7 +10,7 @@ import Foundation // Keyboard events handler when keyboard mapping is off public class TransparentKeyboardEventAdapter: KeyboardEventAdapter { - public func handleKey(keycode: UInt16, pressed: Bool, isRepeat: Bool) -> Bool { + public func handleKey(keycode: UInt16, pressed: Bool, isRepeat: Bool, ctrlModified: Bool) -> Bool { // explicitly eat repeated Enter key isRepeat && keycode == 36 } diff --git a/PlayTools/Controls/Frontend/EventAdapter/Keyboard/KeyboardEventAdapter.swift b/PlayTools/Controls/Frontend/EventAdapter/Keyboard/KeyboardEventAdapter.swift index ca742a8c..3c46a463 100644 --- a/PlayTools/Controls/Frontend/EventAdapter/Keyboard/KeyboardEventAdapter.swift +++ b/PlayTools/Controls/Frontend/EventAdapter/Keyboard/KeyboardEventAdapter.swift @@ -10,5 +10,5 @@ import Foundation // All keyboard events under any mode public protocol KeyboardEventAdapter: EventAdapter { - func handleKey(keycode: UInt16, pressed: Bool, isRepeat: Bool) -> Bool + func handleKey(keycode: UInt16, pressed: Bool, isRepeat: Bool, ctrlModified: Bool) -> Bool } diff --git a/Plugin.swift b/Plugin.swift index f10429c1..e7f0552b 100644 --- a/Plugin.swift +++ b/Plugin.swift @@ -23,7 +23,7 @@ public protocol Plugin: NSObjectProtocol { func warpCursor() func unhideCursor() func terminateApplication() - func setupKeyboard(keyboard: @escaping(UInt16, Bool, Bool) -> Bool, + func setupKeyboard(keyboard: @escaping(UInt16, Bool, Bool, Bool) -> Bool, swapMode: @escaping() -> Bool) func setupMouseMoved(_ mouseMoved: @escaping(CGFloat, CGFloat) -> Bool) func setupMouseButton(left: Bool, right: Bool, _ consumed: @escaping(Int, Bool) -> Bool)