@@ -24,25 +24,12 @@ class KeyboardEvents {
24
24
static var hotKeyReleasedEventHandler : EventHandlerRef ?
25
25
static var localMonitor : Any !
26
26
27
- static func addGlobalShortcut( _ controlId: String , _ shortcut: Shortcut ) {
28
- addGlobalHandlerIfNeeded ( shortcut)
29
- registerHotKeyIfNeeded ( controlId, shortcut)
30
- }
31
-
32
- static func removeGlobalShortcut( _ controlId: String , _ shortcut: Shortcut ) {
33
- unregisterHotKeyIfNeeded ( controlId, shortcut)
34
- removeHandlerIfNeeded ( )
35
- }
36
-
37
- private static func unregisterHotKeyIfNeeded( _ controlId: String , _ shortcut: Shortcut ) {
38
- if shortcut. keyCode != . none {
39
- UnregisterEventHotKey ( eventHotKeyRefs [ controlId] !)
40
- eventHotKeyRefs [ controlId] = nil
41
- }
42
- }
43
-
44
- static func registerHotKeyIfNeeded( _ controlId: String , _ shortcut: Shortcut ) {
45
- if shortcut. keyCode != . none {
27
+ static func addGlobalShortcutIfNeeded( _ controlId: String , _ shortcut: Shortcut , checkEnabled: Bool = true , checkAnyModifierSide: Bool = true ) {
28
+ if
29
+ shortcut. keyCode != . none, eventHotKeyRefs [ controlId] == nil ,
30
+ !checkEnabled || !App. app. globalShortcutsAreDisabled,
31
+ !checkAnyModifierSide || Preferences . shortcutModifierSide [ Preferences . nameToIndex ( controlId) ] == . any
32
+ {
46
33
let id = globalShortcutsIds [ controlId] !
47
34
let hotkeyId = EventHotKeyID ( signature: signature, id: UInt32 ( id) )
48
35
let key = shortcut. carbonKeyCode
@@ -54,12 +41,22 @@ class KeyboardEvents {
54
41
}
55
42
}
56
43
44
+ static func removeGlobalShortcutIfNeeded( _ controlId: String , _ shortcut: Shortcut ) {
45
+ if shortcut. keyCode != . none, eventHotKeyRefs [ controlId] != nil {
46
+ UnregisterEventHotKey ( eventHotKeyRefs [ controlId] !)
47
+ eventHotKeyRefs [ controlId] = nil
48
+ }
49
+ }
50
+
57
51
static func toggleGlobalShortcuts( _ shouldDisable: Bool ) {
58
52
if shouldDisable != App . app. globalShortcutsAreDisabled {
59
- let fn = shouldDisable ? unregisterHotKeyIfNeeded : registerHotKeyIfNeeded
60
53
for shortcutId in globalShortcutsIds. keys {
61
54
if let shortcut = ControlsTab . shortcuts [ shortcutId] ? . shortcut {
62
- fn ( shortcutId, shortcut)
55
+ if shouldDisable {
56
+ removeGlobalShortcutIfNeeded ( shortcutId, shortcut)
57
+ } else {
58
+ addGlobalShortcutIfNeeded ( shortcutId, shortcut, checkEnabled: false )
59
+ }
63
60
}
64
61
}
65
62
debugPrint ( " toggleGlobalShortcuts " , shouldDisable)
@@ -69,15 +66,33 @@ class KeyboardEvents {
69
66
70
67
static func addEventHandlers( ) {
71
68
addLocalMonitorForKeyDownAndKeyUp ( )
69
+ addGlobalHandler ( )
72
70
addCgEventTapForModifierFlags ( )
73
71
}
74
72
75
73
private static func addLocalMonitorForKeyDownAndKeyUp( ) {
76
74
localMonitor = NSEvent . addLocalMonitorForEvents ( matching: [ . keyDown, . keyUp] ) { ( event: NSEvent ) in
77
- let someShortcutTriggered = handleEvent ( nil , nil , event. type == . keyDown ? UInt32 ( event. keyCode) : nil , cocoaToCarbonFlags ( event. modifierFlags) , event. type == . keyDown ? event. isARepeat : false )
75
+ let someShortcutTriggered = handleEvent ( nil , nil , event. type == . keyDown ? UInt32 ( event. keyCode) : nil , cocoaToCarbonFlags ( event. modifierFlags) , event. type == . keyDown ? event. isARepeat : false , . local )
78
76
return someShortcutTriggered ? nil : event
79
77
}
80
78
}
79
+
80
+ private static func addGlobalHandler( ) {
81
+ var hotKeyPressedEventTypes = [ EventTypeSpec ( eventClass: OSType ( kEventClassKeyboard) , eventKind: OSType ( kEventHotKeyPressed) ) ]
82
+ InstallEventHandler ( shortcutEventTarget, { ( _: EventHandlerCallRef ? , event: EventRef ? , _: UnsafeMutableRawPointer ? ) -> OSStatus in
83
+ var id = EventHotKeyID ( )
84
+ GetEventParameter ( event, EventParamName ( kEventParamDirectObject) , EventParamType ( typeEventHotKeyID) , nil , MemoryLayout< EventHotKeyID> . size, nil , & id)
85
+ handleEvent ( id, . down, nil , nil , false , . global)
86
+ return noErr
87
+ } , hotKeyPressedEventTypes. count, & hotKeyPressedEventTypes, nil , & hotKeyPressedEventHandler)
88
+ var hotKeyReleasedEventTypes = [ EventTypeSpec ( eventClass: OSType ( kEventClassKeyboard) , eventKind: OSType ( kEventHotKeyReleased) ) ]
89
+ InstallEventHandler ( shortcutEventTarget, { ( _: EventHandlerCallRef ? , event: EventRef ? , _: UnsafeMutableRawPointer ? ) -> OSStatus in
90
+ var id = EventHotKeyID ( )
91
+ GetEventParameter ( event, EventParamName ( kEventParamDirectObject) , EventParamType ( typeEventHotKeyID) , nil , MemoryLayout< EventHotKeyID> . size, nil , & id)
92
+ handleEvent ( id, . up, nil , nil , false , . global)
93
+ return noErr
94
+ } , hotKeyReleasedEventTypes. count, & hotKeyReleasedEventTypes, nil , & hotKeyReleasedEventHandler)
95
+ }
81
96
82
97
private static func addCgEventTapForModifierFlags( ) {
83
98
let eventMask = [ CGEventType . flagsChanged ] . reduce ( CGEventMask ( 0 ) , { $0 | ( 1 << $1. rawValue) } )
@@ -97,45 +112,59 @@ class KeyboardEvents {
97
112
App . app. restart ( )
98
113
}
99
114
}
115
+ }
100
116
101
- private static func addGlobalHandlerIfNeeded( _ shortcut: Shortcut ) {
102
- if shortcut. keyCode != . none && hotKeyPressedEventHandler == nil {
103
- var eventTypes = [ EventTypeSpec ( eventClass: OSType ( kEventClassKeyboard) , eventKind: OSType ( kEventHotKeyPressed) ) ]
104
- InstallEventHandler ( shortcutEventTarget, { ( _: EventHandlerCallRef ? , event: EventRef ? , _: UnsafeMutableRawPointer ? ) -> OSStatus in
105
- var id = EventHotKeyID ( )
106
- GetEventParameter ( event, EventParamName ( kEventParamDirectObject) , EventParamType ( typeEventHotKeyID) , nil , MemoryLayout< EventHotKeyID> . size, nil , & id)
107
- handleEvent ( id, . down, nil , nil , false )
108
- return noErr
109
- } , eventTypes. count, & eventTypes, nil , & hotKeyPressedEventHandler)
117
+ fileprivate func handleShortcutModifierSide( _ modifiers: NSEvent . ModifierFlags ) {
118
+ let sideModifiers : [ ( any: NSEvent . ModifierFlags , left : NSEvent . ModifierFlags , right : NSEvent . ModifierFlags ) ] = [
119
+ ( . shift, . leftShift, . rightShift) ,
120
+ ( . control, . leftControl, . rightControl) ,
121
+ ( . option, . leftOption, . rightOption) ,
122
+ ( . command, . leftCommand, . rightCommand)
123
+ ]
124
+ var removeShortcuts = [ ( id: String, shortcut: Shortcut) ] ( )
125
+ var addShortcuts = [ ( id: String, shortcut: Shortcut) ] ( )
126
+ for shortcutIndex in 0 ... 4 {
127
+ let shortcutModifierSide = Preferences . shortcutModifierSide [ shortcutIndex]
128
+ guard shortcutModifierSide != . any else {
129
+ continue
110
130
}
111
- if shortcut. keyCode != . none && hotKeyReleasedEventHandler == nil {
112
- var eventTypes = [ EventTypeSpec ( eventClass: OSType ( kEventClassKeyboard) , eventKind: OSType ( kEventHotKeyReleased) ) ]
113
- InstallEventHandler ( shortcutEventTarget, { ( _: EventHandlerCallRef ? , event: EventRef ? , _: UnsafeMutableRawPointer ? ) -> OSStatus in
114
- var id = EventHotKeyID ( )
115
- GetEventParameter ( event, EventParamName ( kEventParamDirectObject) , EventParamType ( typeEventHotKeyID) , nil , MemoryLayout< EventHotKeyID> . size, nil , & id)
116
- handleEvent ( id, . up, nil , nil , false )
117
- return noErr
118
- } , eventTypes. count, & eventTypes, nil , & hotKeyReleasedEventHandler)
131
+ let holdShortcutId = Preferences . indexToName ( " holdShortcut " , shortcutIndex)
132
+ let nextWindowShortcutId = Preferences . indexToName ( " nextWindowShortcut " , shortcutIndex)
133
+ guard
134
+ let holdShortcut = ControlsTab . shortcuts [ holdShortcutId] ? . shortcut,
135
+ let nextWindowShortcut = ControlsTab . shortcuts [ nextWindowShortcutId] ? . shortcut
136
+ else {
137
+ continue
119
138
}
120
- }
121
-
122
- private static func removeHandlerIfNeeded( ) {
123
- let globalShortcuts = ControlsTab . shortcuts. values. filter { $0. scope == . global }
124
- if let hotKeyPressedEventHandler_ = hotKeyPressedEventHandler, let hotKeyReleasedEventHandler_ = hotKeyReleasedEventHandler,
125
- ( globalShortcuts. allSatisfy { $0. shortcut. keyCode == . none } ) {
126
- RemoveEventHandler ( hotKeyPressedEventHandler_)
127
- hotKeyPressedEventHandler = nil
128
- RemoveEventHandler ( hotKeyReleasedEventHandler_)
129
- hotKeyReleasedEventHandler = nil
139
+ if
140
+ ( sideModifiers. filter {
141
+ holdShortcut. modifierFlags. contains ( $0. any)
142
+ } . allSatisfy {
143
+ modifiers. contains ( shortcutModifierSide == . left ? $0. left : $0. right) &&
144
+ !modifiers. contains ( shortcutModifierSide == . left ? $0. right : $0. left)
145
+ } )
146
+ {
147
+ addShortcuts. append ( ( nextWindowShortcutId, nextWindowShortcut) )
148
+ } else {
149
+ if App . app. shortcutIndex == shortcutIndex && App . app. appIsBeingUsed {
150
+ App . app. hideUi ( )
151
+ }
152
+ removeShortcuts. append ( ( nextWindowShortcutId, nextWindowShortcut) )
130
153
}
131
154
}
155
+ removeShortcuts. forEach {
156
+ KeyboardEvents . removeGlobalShortcutIfNeeded ( $0. id, $0. shortcut)
157
+ }
158
+ addShortcuts. forEach {
159
+ KeyboardEvents . addGlobalShortcutIfNeeded ( $0. id, $0. shortcut, checkAnyModifierSide: false )
160
+ }
132
161
}
133
162
134
163
@discardableResult
135
- fileprivate func handleEvent( _ id: EventHotKeyID ? , _ shortcutState: ShortcutState ? , _ keyCode: UInt32 ? , _ modifiers: UInt32 ? , _ isARepeat: Bool ) -> Bool {
164
+ fileprivate func handleEvent( _ id: EventHotKeyID ? , _ shortcutState: ShortcutState ? , _ keyCode: UInt32 ? , _ modifiers: UInt32 ? , _ isARepeat: Bool , _ shortcutScope : ShortcutScope ) -> Bool {
136
165
var someShortcutTriggered = false
137
166
for shortcut in ControlsTab . shortcuts. values {
138
- if shortcut. matches ( id, shortcutState, keyCode, modifiers, isARepeat) && shortcut. shouldTrigger ( ) {
167
+ if shortcut. matches ( id, shortcutState, keyCode, modifiers, isARepeat, shortcutScope ) && shortcut. shouldTrigger ( ) {
139
168
shortcut. executeAction ( isARepeat)
140
169
someShortcutTriggered = true
141
170
}
@@ -145,8 +174,9 @@ fileprivate func handleEvent(_ id: EventHotKeyID?, _ shortcutState: ShortcutStat
145
174
146
175
fileprivate func cgEventFlagsChangedHandler( proxy: CGEventTapProxy , type: CGEventType , cgEvent: CGEvent , userInfo: UnsafeMutableRawPointer ? ) -> Unmanaged < CGEvent > ? {
147
176
if type == . flagsChanged {
148
- let modifiers = cocoaToCarbonFlags ( NSEvent . ModifierFlags ( rawValue: UInt ( cgEvent. flags. rawValue) ) )
149
- handleEvent ( nil , nil , nil , modifiers, false )
177
+ let modifiers = NSEvent . ModifierFlags ( rawValue: UInt ( cgEvent. flags. rawValue) )
178
+ handleShortcutModifierSide ( modifiers)
179
+ handleEvent ( nil , nil , nil , cocoaToCarbonFlags ( modifiers) , false , . global)
150
180
} else if ( type == . tapDisabledByUserInput || type == . tapDisabledByTimeout) {
151
181
CGEvent . tapEnable ( tap: eventTap!, enable: true )
152
182
}
0 commit comments