Skip to content

Commit 81a78ce

Browse files
committed
Fix a bug which meta keys don't work in some apps
1 parent 19af5c8 commit 81a78ce

File tree

4 files changed

+142
-42
lines changed

4 files changed

+142
-42
lines changed

JoyKeyMapper.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
/* Begin PBXBuildFile section */
1010
93256183A11EAD19ADC85FF9 /* Pods_JoyKeyMapper.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 480DB1F0DAF805C943A9656A /* Pods_JoyKeyMapper.framework */; };
11+
DD0389E82497D911009090BE /* MetaKeyState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD0389E72497D911009090BE /* MetaKeyState.swift */; };
1112
DD05303224272D7A0091B3C6 /* DataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD05302D24272D7A0091B3C6 /* DataManager.swift */; };
1213
DD05303324272D7A0091B3C6 /* GameController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD05302E24272D7A0091B3C6 /* GameController.swift */; };
1314
DD05303424272D7A0091B3C6 /* JoyKeyMapper.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DD05302F24272D7A0091B3C6 /* JoyKeyMapper.xcdatamodeld */; };
@@ -57,6 +58,7 @@
5758
475E07CC10AB2EDFD3A1DE83 /* Pods-JoyKeyMapper.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JoyKeyMapper.release.xcconfig"; path = "Target Support Files/Pods-JoyKeyMapper/Pods-JoyKeyMapper.release.xcconfig"; sourceTree = "<group>"; };
5859
480DB1F0DAF805C943A9656A /* Pods_JoyKeyMapper.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_JoyKeyMapper.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5960
AE0B679D3FC9AD29E57D0287 /* Pods-JoyKeyMapper.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JoyKeyMapper.debug.xcconfig"; path = "Target Support Files/Pods-JoyKeyMapper/Pods-JoyKeyMapper.debug.xcconfig"; sourceTree = "<group>"; };
61+
DD0389E72497D911009090BE /* MetaKeyState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetaKeyState.swift; sourceTree = "<group>"; };
6062
DD05302D24272D7A0091B3C6 /* DataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataManager.swift; sourceTree = "<group>"; };
6163
DD05302E24272D7A0091B3C6 /* GameController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameController.swift; sourceTree = "<group>"; };
6264
DD05303024272D7A0091B3C6 /* JoyKeyMapper.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = JoyKeyMapper.xcdatamodel; sourceTree = "<group>"; };
@@ -140,6 +142,7 @@
140142
DD05302D24272D7A0091B3C6 /* DataManager.swift */,
141143
DD05302E24272D7A0091B3C6 /* GameController.swift */,
142144
DD05303124272D7A0091B3C6 /* GameControllerIcon.swift */,
145+
DD0389E72497D911009090BE /* MetaKeyState.swift */,
143146
);
144147
path = DataModels;
145148
sourceTree = "<group>";
@@ -453,6 +456,7 @@
453456
DD05305624272DAA0091B3C6 /* SpecialKeyName.swift in Sources */,
454457
DD05305524272DAA0091B3C6 /* StickConfigCellView.swift in Sources */,
455458
DDAC3B4024151C350022FF32 /* AppNotifications.swift in Sources */,
459+
DD0389E82497D911009090BE /* MetaKeyState.swift in Sources */,
456460
DD05305424272DAA0091B3C6 /* AppSettingsViewController.swift in Sources */,
457461
DD05305224272DAA0091B3C6 /* KeyConfigComboBox.swift in Sources */,
458462
DD05305E24272DAA0091B3C6 /* ControllerView.swift in Sources */,

JoyKeyMapper/AppDelegate.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, UNUserNoti
289289
guard let app = notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication,
290290
let bundleID = app.bundleIdentifier else { return }
291291

292+
resetMetaKeyState()
293+
292294
self.controllers.forEach { controller in
293295
controller.switchApp(bundleID: bundleID)
294296
}

JoyKeyMapper/DataModels/GameController.swift

Lines changed: 48 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -193,32 +193,37 @@ class GameController {
193193
}
194194

195195
func buttonPressHandler(config: KeyMap) {
196-
let source = CGEventSource(stateID: .hidSystemState)
196+
DispatchQueue.main.async {
197+
let source = CGEventSource(stateID: .hidSystemState)
197198

198-
if config.keyCode >= 0 {
199-
DispatchQueue.main.async {
199+
if config.keyCode >= 0 {
200+
metaKeyEvent(config: config, keyDown: true)
201+
200202
let event = CGEvent(keyboardEventSource: source, virtualKey: CGKeyCode(config.keyCode), keyDown: true)
201203
event?.flags = CGEventFlags(rawValue: CGEventFlags.RawValue(config.modifiers))
202204
event?.post(tap: .cghidEventTap)
203205
}
204-
}
205206

206-
if config.mouseButton >= 0 {
207-
let mousePos = NSEvent.mouseLocation
208-
let cursorPos = CGPoint(x: mousePos.x, y: NSScreen.main!.frame.maxY - mousePos.y)
207+
if config.mouseButton >= 0 {
208+
let mousePos = NSEvent.mouseLocation
209+
let cursorPos = CGPoint(x: mousePos.x, y: NSScreen.main!.frame.maxY - mousePos.y)
209210

210-
var event: CGEvent?
211-
if config.mouseButton == 0 {
212-
event = CGEvent(mouseEventSource: source, mouseType: .leftMouseDown, mouseCursorPosition: cursorPos, mouseButton: .left)
213-
self.isLeftDragging = true
214-
} else if config.mouseButton == 1 {
215-
event = CGEvent(mouseEventSource: source, mouseType: .rightMouseDown, mouseCursorPosition: cursorPos, mouseButton: .right)
216-
self.isRightDragging = true
217-
} else if config.mouseButton == 2 {
218-
event = CGEvent(mouseEventSource: source, mouseType: .otherMouseDown, mouseCursorPosition: cursorPos, mouseButton: .center)
219-
self.isCenterDragging = true
211+
metaKeyEvent(config: config, keyDown: true)
212+
213+
var event: CGEvent?
214+
if config.mouseButton == 0 {
215+
event = CGEvent(mouseEventSource: source, mouseType: .leftMouseDown, mouseCursorPosition: cursorPos, mouseButton: .left)
216+
self.isLeftDragging = true
217+
} else if config.mouseButton == 1 {
218+
event = CGEvent(mouseEventSource: source, mouseType: .rightMouseDown, mouseCursorPosition: cursorPos, mouseButton: .right)
219+
self.isRightDragging = true
220+
} else if config.mouseButton == 2 {
221+
event = CGEvent(mouseEventSource: source, mouseType: .otherMouseDown, mouseCursorPosition: cursorPos, mouseButton: .center)
222+
self.isCenterDragging = true
223+
}
224+
event?.flags = CGEventFlags(rawValue: CGEventFlags.RawValue(config.modifiers))
225+
event?.post(tap: .cghidEventTap)
220226
}
221-
event?.post(tap: .cghidEventTap)
222227
}
223228
}
224229

@@ -228,32 +233,34 @@ class GameController {
228233
}
229234

230235
func buttonReleaseHandler(config: KeyMap) {
231-
let source = CGEventSource(stateID: .hidSystemState)
232-
233-
if config.keyCode >= 0 {
234-
DispatchQueue.main.async {
235-
let event = CGEvent(keyboardEventSource: source, virtualKey: CGKeyCode(config.keyCode), keyDown: false)
236-
event?.flags = CGEventFlags(rawValue: CGEventFlags.RawValue(config.modifiers))
237-
event?.post(tap: .cghidEventTap)
236+
DispatchQueue.main.async {
237+
let source = CGEventSource(stateID: .hidSystemState)
238+
239+
if config.keyCode >= 0 {
240+
let event = CGEvent(keyboardEventSource: source, virtualKey: CGKeyCode(config.keyCode), keyDown: false)
241+
event?.flags = CGEventFlags(rawValue: CGEventFlags.RawValue(config.modifiers))
242+
event?.post(tap: .cghidEventTap)
243+
244+
metaKeyEvent(config: config, keyDown: false)
238245
}
239-
}
240246

241-
if config.mouseButton >= 0 {
242-
let mousePos = NSEvent.mouseLocation
243-
let cursorPos = CGPoint(x: mousePos.x, y: NSScreen.main!.frame.maxY - mousePos.y)
244-
245-
var event: CGEvent?
246-
if config.mouseButton == 0 {
247-
event = CGEvent(mouseEventSource: source, mouseType: .leftMouseUp, mouseCursorPosition: cursorPos, mouseButton: .left)
248-
self.isLeftDragging = false
249-
} else if config.mouseButton == 1 {
250-
event = CGEvent(mouseEventSource: source, mouseType: .rightMouseUp, mouseCursorPosition: cursorPos, mouseButton: .right)
251-
self.isRightDragging = false
252-
} else if config.mouseButton == 2 {
253-
event = CGEvent(mouseEventSource: source, mouseType: .otherMouseUp, mouseCursorPosition: cursorPos, mouseButton: .center)
254-
self.isCenterDragging = false
247+
if config.mouseButton >= 0 {
248+
let mousePos = NSEvent.mouseLocation
249+
let cursorPos = CGPoint(x: mousePos.x, y: NSScreen.main!.frame.maxY - mousePos.y)
250+
251+
var event: CGEvent?
252+
if config.mouseButton == 0 {
253+
event = CGEvent(mouseEventSource: source, mouseType: .leftMouseUp, mouseCursorPosition: cursorPos, mouseButton: .left)
254+
self.isLeftDragging = false
255+
} else if config.mouseButton == 1 {
256+
event = CGEvent(mouseEventSource: source, mouseType: .rightMouseUp, mouseCursorPosition: cursorPos, mouseButton: .right)
257+
self.isRightDragging = false
258+
} else if config.mouseButton == 2 {
259+
event = CGEvent(mouseEventSource: source, mouseType: .otherMouseUp, mouseCursorPosition: cursorPos, mouseButton: .center)
260+
self.isCenterDragging = false
261+
}
262+
event?.post(tap: .cghidEventTap)
255263
}
256-
event?.post(tap: .cghidEventTap)
257264
}
258265
}
259266

@@ -337,7 +344,6 @@ class GameController {
337344
func batteryChangeHandler(newState: JoyCon.BatteryStatus, oldState: JoyCon.BatteryStatus) {
338345
self.updateControllerIcon()
339346

340-
Swift.print("*** battery change: \(oldState.rawValue) -> \(newState.rawValue)")
341347
if newState == .full && oldState != .unknown {
342348
AppNotifications.notifyBatteryFullCharge(self)
343349
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//
2+
// MetaKeyState.swift
3+
// JoyKeyMapper
4+
//
5+
// Created by magicien on 2020/06/16.
6+
// Copyright © 2020 DarkHorse. All rights reserved.
7+
//
8+
9+
import InputMethodKit
10+
11+
private let shiftKey = Int32(kVK_Shift)
12+
private let optionKey = Int32(kVK_Option)
13+
private let controlKey = Int32(kVK_Control)
14+
private let commandKey = Int32(kVK_Command)
15+
private let metaKeys = [kVK_Shift, kVK_Option, kVK_Control, kVK_Command]
16+
private var pushedKeyConfigs = Set<KeyMap>()
17+
18+
func resetMetaKeyState() {
19+
let source = CGEventSource(stateID: .hidSystemState)
20+
pushedKeyConfigs.removeAll()
21+
22+
DispatchQueue.main.async {
23+
// Release all meta keys
24+
metaKeys.forEach {
25+
let ev = CGEvent(keyboardEventSource: source, virtualKey: CGKeyCode($0), keyDown: false)
26+
ev?.post(tap: .cghidEventTap)
27+
}
28+
}
29+
}
30+
31+
func getMetaKeyState() -> (shift: Bool, option: Bool, control: Bool, command: Bool) {
32+
var shift: Bool = false
33+
var option: Bool = false
34+
var control: Bool = false
35+
var command: Bool = false
36+
37+
pushedKeyConfigs.forEach {
38+
let modifiers = NSEvent.ModifierFlags(rawValue: UInt($0.modifiers))
39+
shift = shift || modifiers.contains(.shift)
40+
option = option || modifiers.contains(.option)
41+
control = control || modifiers.contains(.control)
42+
command = command || modifiers.contains(.command)
43+
}
44+
45+
return (shift, option, control, command)
46+
}
47+
48+
/**
49+
* This command must be called in the main thread
50+
*/
51+
func metaKeyEvent(config: KeyMap, keyDown: Bool) {
52+
var shift: Bool
53+
var option: Bool
54+
var control: Bool
55+
var command: Bool
56+
57+
if keyDown {
58+
// Check if meta keys are not pressed before pressing keys
59+
(shift, option, control, command) = getMetaKeyState()
60+
pushedKeyConfigs.insert(config)
61+
} else {
62+
pushedKeyConfigs.remove(config)
63+
// Check if meta keys are not pressed after releasing keys
64+
(shift, option, control, command) = getMetaKeyState()
65+
}
66+
67+
let source = CGEventSource(stateID: .hidSystemState)
68+
let modifiers = NSEvent.ModifierFlags(rawValue: UInt(config.modifiers))
69+
if !shift && modifiers.contains(.shift) {
70+
let ev = CGEvent(keyboardEventSource: source, virtualKey: CGKeyCode(kVK_Shift), keyDown: keyDown)
71+
ev?.post(tap: .cghidEventTap)
72+
}
73+
74+
if !option && modifiers.contains(.option) {
75+
let ev = CGEvent(keyboardEventSource: source, virtualKey: CGKeyCode(kVK_Option), keyDown: keyDown)
76+
ev?.post(tap: .cghidEventTap)
77+
}
78+
79+
if !control && modifiers.contains(.control) {
80+
let ev = CGEvent(keyboardEventSource: source, virtualKey: CGKeyCode(kVK_Control), keyDown: keyDown)
81+
ev?.post(tap: .cghidEventTap)
82+
}
83+
84+
if !command && modifiers.contains(.command) {
85+
let ev = CGEvent(keyboardEventSource: source, virtualKey: CGKeyCode(kVK_Command), keyDown: keyDown)
86+
ev?.post(tap: .cghidEventTap)
87+
}
88+
}

0 commit comments

Comments
 (0)