From 8ad15cd770c2f15ffbdda722b72ef023db2b469b Mon Sep 17 00:00:00 2001 From: Yuki Iwanaga Date: Tue, 2 Jun 2020 14:05:40 +0900 Subject: [PATCH 1/2] Organize --- keyboard/AppComponent.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/keyboard/AppComponent.swift b/keyboard/AppComponent.swift index fca86b8..961a81b 100644 --- a/keyboard/AppComponent.swift +++ b/keyboard/AppComponent.swift @@ -74,12 +74,12 @@ final class AppComponent { func eventManager() -> EventManagerType { let eventManager: EventManagerType = EventManager(emitter: emitter) - eventManager.register(handler: navigationHandler()) eventManager.register(handler: emacsHandler()) - eventManager.register(handler: wordMotionHandler()) eventManager.register(handler: escapeHandler()) - eventManager.register(handler: windowResizeHandler()) + eventManager.register(handler: navigationHandler()) eventManager.register(handler: mouseHandler()) + eventManager.register(handler: wordMotionHandler()) + eventManager.register(handler: windowResizeHandler()) eventManager.register(handler: appSwitchHandler()) eventManager.register(handler: inputMethodHandler()) eventManager.register(handler: appQuithHandler()) From 2901f55a4946a669a7515efa579b8c1281b56e18 Mon Sep 17 00:00:00 2001 From: Yuki Iwanaga Date: Tue, 2 Jun 2020 16:03:23 +0900 Subject: [PATCH 2/2] Improve SuperKey --- keyboard/Core/EventManager.swift | 93 ++++++++++++++++---------------- keyboard/Core/SuperKey.swift | 28 ++++------ 2 files changed, 56 insertions(+), 65 deletions(-) diff --git a/keyboard/Core/EventManager.swift b/keyboard/Core/EventManager.swift index 427833e..57d851f 100644 --- a/keyboard/Core/EventManager.swift +++ b/keyboard/Core/EventManager.swift @@ -8,8 +8,9 @@ protocol EventManagerType { final class EventManager: EventManagerType { private let emitter: EmitterType - private var handlers: [Handler] = [] - private var superKeys: [KeyCode: SuperKey] = [:] + private var handlers = [Handler]() + private let superKey = SuperKey() + private var superKeyPrefixes = Set() init(emitter: EmitterType) { self.emitter = emitter @@ -19,9 +20,7 @@ final class EventManager: EventManagerType { handlers.append(handler) handler.activateSuperKeys().forEach { - if superKeys[$0] == nil { - superKeys[$0] = SuperKey(prefix: $0) - } + superKeyPrefixes.insert($0) } } @@ -35,7 +34,10 @@ final class EventManager: EventManagerType { return Unmanaged.passRetained(cgEvent) } - let action = handle(keyEvent: keyEvent) ?? .passThrough + let action = updateSuperKey(keyEvent: keyEvent) + ?? handleSuperKey(keyEvent: keyEvent) + ?? handle(keyEvent: keyEvent) + ?? .passThrough switch action { case .prevent: @@ -48,21 +50,11 @@ final class EventManager: EventManagerType { extension EventManager: Handler { func handle(keyEvent: KeyEvent) -> HandlerAction? { - for (_, superKey) in superKeys { - if let action = updateState(superKey: superKey, keyEvent: keyEvent) { - return action - } - if let action = execute(superKey: superKey, keyEvent: keyEvent) { - return action - } - } - for handler in handlers { if let action = handler.handle(keyEvent: keyEvent) { return action } } - return nil } @@ -73,53 +65,58 @@ extension EventManager: Handler { return true } } - return false } } extension EventManager { - private func updateState(superKey: SuperKey, keyEvent: KeyEvent) -> HandlerAction? { + private func updateSuperKey(keyEvent: KeyEvent) -> HandlerAction? { guard keyEvent.match() else { superKey.state = .inactive return nil } - if keyEvent.code == superKey.prefix { - guard !keyEvent.isARepeat else { - return .prevent - } - guard !keyEvent.isDown else { + if superKeyPrefixes.contains(keyEvent.code) { + // Activte the mode + if keyEvent.isDown, superKey.state == .inactive { + superKey.prefixKey = keyEvent.code superKey.state = .activated return .prevent } - switch superKey.state { - case .activated: - emitter.emit(keyCode: superKey.prefix, flags: [], action: .both) - case .used, .enabled: - if let key = superKey.cancel() { - emitter.emit(keyCode: superKey.prefix, flags: [], action: .both) - emitter.emit(keyCode: key, flags: [], action: .both) - } else { - emitter.emit(keyCode: .command, flags: [], action: .both) + if let prefixKey = superKey.prefixKey, prefixKey == keyEvent.code { + // Cancel on the final keyup + if !keyEvent.isDown && !keyEvent.isARepeat { + switch superKey.state { + case .activated: + emitter.emit(keyCode: prefixKey, flags: [], action: .both) + case .used, .enabled: + // Abort a pending operation, if any + if let pendingKey = superKey.cancel() { + emitter.emit(keyCode: prefixKey, flags: [], action: .both) + emitter.emit(keyCode: pendingKey, flags: [], action: .both) + } else { + // Trigger any key events to clean up + emitter.emit(keyCode: .command, flags: [], action: .both) + } + default: break + } + + // Restore the state + superKey.state = .inactive } - default: break - } - - superKey.state = .inactive - return .prevent - } - guard keyEvent.isDown else { - return nil + // Always ignore the prefix key + return .prevent + } } - guard superKey.enable() else { - superKey.state = .disabled - - emitter.emit(keyCode: superKey.prefix, flags: [], action: .both) - emitter.emit(keyCode: keyEvent.code, flags: [], action: (keyEvent.isDown ? .down : .up)) + // Disable when another key was pressed immediately after the activation + if keyEvent.isDown, !superKey.enable() { + if let prefixKey = superKey.prefixKey { + emitter.emit(keyCode: prefixKey, flags: [], action: .both) + } + emitter.emit(keyCode: keyEvent.code, flags: [], action: .down) return .prevent } @@ -127,8 +124,8 @@ extension EventManager { return nil } - private func execute(superKey: SuperKey, keyEvent: KeyEvent) -> HandlerAction? { - guard superKey.isEnabled else { + private func handleSuperKey(keyEvent: KeyEvent) -> HandlerAction? { + guard superKey.isEnabled, let prefixKey = superKey.prefixKey else { return nil } guard keyEvent.match() else { @@ -136,7 +133,7 @@ extension EventManager { } superKey.perform(key: keyEvent.code, isKeyDown: keyEvent.isDown) { [weak self] (keys) in - self?.handleSuperKey(prefix: superKey.prefix, keys: keys) + self?.handleSuperKey(prefix: prefixKey, keys: keys) } return .prevent diff --git a/keyboard/Core/SuperKey.swift b/keyboard/Core/SuperKey.swift index 8cb12cb..2cb12ee 100644 --- a/keyboard/Core/SuperKey.swift +++ b/keyboard/Core/SuperKey.swift @@ -1,7 +1,10 @@ import Foundation final class SuperKey { - let prefix: KeyCode + struct Const { + static let downThresholdMs: Double = 50 + static let dispatchDelayMs: Int = 150 + } enum State { case inactive @@ -11,12 +14,10 @@ final class SuperKey { case disabled } - private let downThreshold: Double = 50 // ms - private let dispatchDelay: Int = 150 // ms - private var activatedAt: Double = 0 private var current: (key: KeyCode, time: DispatchTime, work: DispatchWorkItem?)? + var prefixKey: KeyCode? private var pressedKeys: Set = [] var state: State = .inactive { @@ -35,15 +36,12 @@ final class SuperKey { return [.enabled, .used].contains(state) } - init(prefix: KeyCode) { - self.prefix = prefix - } - func enable() -> Bool { guard state == .activated else { return true } - guard DispatchTime.uptimeNanoseconds() - activatedAt > downThreshold * 1e6 else { + guard DispatchTime.uptimeNanoseconds() - activatedAt > Const.downThresholdMs * 1e6 else { + state = .disabled return false } state = .enabled @@ -68,23 +66,19 @@ final class SuperKey { let work = DispatchWorkItem() { block(keys) } - let dispatchTime = DispatchTime.now() + DispatchTimeInterval.milliseconds(dispatchDelay) + let dispatchTime = DispatchTime.now() + DispatchTimeInterval.milliseconds(Const.dispatchDelayMs) current = (key: key, time: dispatchTime, work: work) DispatchQueue.main.asyncAfter(deadline: dispatchTime, execute: work) } func cancel() -> KeyCode? { - guard let current = current else { - return nil - } + guard let current = current else { return nil } self.current = nil + prefixKey = nil pressedKeys = [] - guard current.time > DispatchTime.now() else { - return nil - } - + guard current.time > DispatchTime.now() else { return nil } current.work?.cancel() return current.key