Skip to content

Commit

Permalink
Fix a bug which meta keys don't work in some apps
Browse files Browse the repository at this point in the history
  • Loading branch information
magicien committed Jun 16, 2020
1 parent 19af5c8 commit 81a78ce
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 42 deletions.
4 changes: 4 additions & 0 deletions JoyKeyMapper.xcodeproj/project.pbxproj
Expand Up @@ -8,6 +8,7 @@

/* Begin PBXBuildFile section */
93256183A11EAD19ADC85FF9 /* Pods_JoyKeyMapper.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 480DB1F0DAF805C943A9656A /* Pods_JoyKeyMapper.framework */; };
DD0389E82497D911009090BE /* MetaKeyState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD0389E72497D911009090BE /* MetaKeyState.swift */; };
DD05303224272D7A0091B3C6 /* DataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD05302D24272D7A0091B3C6 /* DataManager.swift */; };
DD05303324272D7A0091B3C6 /* GameController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD05302E24272D7A0091B3C6 /* GameController.swift */; };
DD05303424272D7A0091B3C6 /* JoyKeyMapper.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DD05302F24272D7A0091B3C6 /* JoyKeyMapper.xcdatamodeld */; };
Expand Down Expand Up @@ -57,6 +58,7 @@
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>"; };
480DB1F0DAF805C943A9656A /* Pods_JoyKeyMapper.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_JoyKeyMapper.framework; sourceTree = BUILT_PRODUCTS_DIR; };
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>"; };
DD0389E72497D911009090BE /* MetaKeyState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetaKeyState.swift; sourceTree = "<group>"; };
DD05302D24272D7A0091B3C6 /* DataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataManager.swift; sourceTree = "<group>"; };
DD05302E24272D7A0091B3C6 /* GameController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameController.swift; sourceTree = "<group>"; };
DD05303024272D7A0091B3C6 /* JoyKeyMapper.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = JoyKeyMapper.xcdatamodel; sourceTree = "<group>"; };
Expand Down Expand Up @@ -140,6 +142,7 @@
DD05302D24272D7A0091B3C6 /* DataManager.swift */,
DD05302E24272D7A0091B3C6 /* GameController.swift */,
DD05303124272D7A0091B3C6 /* GameControllerIcon.swift */,
DD0389E72497D911009090BE /* MetaKeyState.swift */,
);
path = DataModels;
sourceTree = "<group>";
Expand Down Expand Up @@ -453,6 +456,7 @@
DD05305624272DAA0091B3C6 /* SpecialKeyName.swift in Sources */,
DD05305524272DAA0091B3C6 /* StickConfigCellView.swift in Sources */,
DDAC3B4024151C350022FF32 /* AppNotifications.swift in Sources */,
DD0389E82497D911009090BE /* MetaKeyState.swift in Sources */,
DD05305424272DAA0091B3C6 /* AppSettingsViewController.swift in Sources */,
DD05305224272DAA0091B3C6 /* KeyConfigComboBox.swift in Sources */,
DD05305E24272DAA0091B3C6 /* ControllerView.swift in Sources */,
Expand Down
2 changes: 2 additions & 0 deletions JoyKeyMapper/AppDelegate.swift
Expand Up @@ -289,6 +289,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, UNUserNoti
guard let app = notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication,
let bundleID = app.bundleIdentifier else { return }

resetMetaKeyState()

self.controllers.forEach { controller in
controller.switchApp(bundleID: bundleID)
}
Expand Down
90 changes: 48 additions & 42 deletions JoyKeyMapper/DataModels/GameController.swift
Expand Up @@ -193,32 +193,37 @@ class GameController {
}

func buttonPressHandler(config: KeyMap) {
let source = CGEventSource(stateID: .hidSystemState)
DispatchQueue.main.async {
let source = CGEventSource(stateID: .hidSystemState)

if config.keyCode >= 0 {
DispatchQueue.main.async {
if config.keyCode >= 0 {
metaKeyEvent(config: config, keyDown: true)

let event = CGEvent(keyboardEventSource: source, virtualKey: CGKeyCode(config.keyCode), keyDown: true)
event?.flags = CGEventFlags(rawValue: CGEventFlags.RawValue(config.modifiers))
event?.post(tap: .cghidEventTap)
}
}

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

var event: CGEvent?
if config.mouseButton == 0 {
event = CGEvent(mouseEventSource: source, mouseType: .leftMouseDown, mouseCursorPosition: cursorPos, mouseButton: .left)
self.isLeftDragging = true
} else if config.mouseButton == 1 {
event = CGEvent(mouseEventSource: source, mouseType: .rightMouseDown, mouseCursorPosition: cursorPos, mouseButton: .right)
self.isRightDragging = true
} else if config.mouseButton == 2 {
event = CGEvent(mouseEventSource: source, mouseType: .otherMouseDown, mouseCursorPosition: cursorPos, mouseButton: .center)
self.isCenterDragging = true
metaKeyEvent(config: config, keyDown: true)

var event: CGEvent?
if config.mouseButton == 0 {
event = CGEvent(mouseEventSource: source, mouseType: .leftMouseDown, mouseCursorPosition: cursorPos, mouseButton: .left)
self.isLeftDragging = true
} else if config.mouseButton == 1 {
event = CGEvent(mouseEventSource: source, mouseType: .rightMouseDown, mouseCursorPosition: cursorPos, mouseButton: .right)
self.isRightDragging = true
} else if config.mouseButton == 2 {
event = CGEvent(mouseEventSource: source, mouseType: .otherMouseDown, mouseCursorPosition: cursorPos, mouseButton: .center)
self.isCenterDragging = true
}
event?.flags = CGEventFlags(rawValue: CGEventFlags.RawValue(config.modifiers))
event?.post(tap: .cghidEventTap)
}
event?.post(tap: .cghidEventTap)
}
}

Expand All @@ -228,32 +233,34 @@ class GameController {
}

func buttonReleaseHandler(config: KeyMap) {
let source = CGEventSource(stateID: .hidSystemState)

if config.keyCode >= 0 {
DispatchQueue.main.async {
let event = CGEvent(keyboardEventSource: source, virtualKey: CGKeyCode(config.keyCode), keyDown: false)
event?.flags = CGEventFlags(rawValue: CGEventFlags.RawValue(config.modifiers))
event?.post(tap: .cghidEventTap)
DispatchQueue.main.async {
let source = CGEventSource(stateID: .hidSystemState)

if config.keyCode >= 0 {
let event = CGEvent(keyboardEventSource: source, virtualKey: CGKeyCode(config.keyCode), keyDown: false)
event?.flags = CGEventFlags(rawValue: CGEventFlags.RawValue(config.modifiers))
event?.post(tap: .cghidEventTap)

metaKeyEvent(config: config, keyDown: false)
}
}

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

var event: CGEvent?
if config.mouseButton == 0 {
event = CGEvent(mouseEventSource: source, mouseType: .leftMouseUp, mouseCursorPosition: cursorPos, mouseButton: .left)
self.isLeftDragging = false
} else if config.mouseButton == 1 {
event = CGEvent(mouseEventSource: source, mouseType: .rightMouseUp, mouseCursorPosition: cursorPos, mouseButton: .right)
self.isRightDragging = false
} else if config.mouseButton == 2 {
event = CGEvent(mouseEventSource: source, mouseType: .otherMouseUp, mouseCursorPosition: cursorPos, mouseButton: .center)
self.isCenterDragging = false
if config.mouseButton >= 0 {
let mousePos = NSEvent.mouseLocation
let cursorPos = CGPoint(x: mousePos.x, y: NSScreen.main!.frame.maxY - mousePos.y)

var event: CGEvent?
if config.mouseButton == 0 {
event = CGEvent(mouseEventSource: source, mouseType: .leftMouseUp, mouseCursorPosition: cursorPos, mouseButton: .left)
self.isLeftDragging = false
} else if config.mouseButton == 1 {
event = CGEvent(mouseEventSource: source, mouseType: .rightMouseUp, mouseCursorPosition: cursorPos, mouseButton: .right)
self.isRightDragging = false
} else if config.mouseButton == 2 {
event = CGEvent(mouseEventSource: source, mouseType: .otherMouseUp, mouseCursorPosition: cursorPos, mouseButton: .center)
self.isCenterDragging = false
}
event?.post(tap: .cghidEventTap)
}
event?.post(tap: .cghidEventTap)
}
}

Expand Down Expand Up @@ -337,7 +344,6 @@ class GameController {
func batteryChangeHandler(newState: JoyCon.BatteryStatus, oldState: JoyCon.BatteryStatus) {
self.updateControllerIcon()

Swift.print("*** battery change: \(oldState.rawValue) -> \(newState.rawValue)")
if newState == .full && oldState != .unknown {
AppNotifications.notifyBatteryFullCharge(self)
}
Expand Down
88 changes: 88 additions & 0 deletions JoyKeyMapper/DataModels/MetaKeyState.swift
@@ -0,0 +1,88 @@
//
// MetaKeyState.swift
// JoyKeyMapper
//
// Created by magicien on 2020/06/16.
// Copyright © 2020 DarkHorse. All rights reserved.
//

import InputMethodKit

private let shiftKey = Int32(kVK_Shift)
private let optionKey = Int32(kVK_Option)
private let controlKey = Int32(kVK_Control)
private let commandKey = Int32(kVK_Command)
private let metaKeys = [kVK_Shift, kVK_Option, kVK_Control, kVK_Command]
private var pushedKeyConfigs = Set<KeyMap>()

func resetMetaKeyState() {
let source = CGEventSource(stateID: .hidSystemState)
pushedKeyConfigs.removeAll()

DispatchQueue.main.async {
// Release all meta keys
metaKeys.forEach {
let ev = CGEvent(keyboardEventSource: source, virtualKey: CGKeyCode($0), keyDown: false)
ev?.post(tap: .cghidEventTap)
}
}
}

func getMetaKeyState() -> (shift: Bool, option: Bool, control: Bool, command: Bool) {
var shift: Bool = false
var option: Bool = false
var control: Bool = false
var command: Bool = false

pushedKeyConfigs.forEach {
let modifiers = NSEvent.ModifierFlags(rawValue: UInt($0.modifiers))
shift = shift || modifiers.contains(.shift)
option = option || modifiers.contains(.option)
control = control || modifiers.contains(.control)
command = command || modifiers.contains(.command)
}

return (shift, option, control, command)
}

/**
* This command must be called in the main thread
*/
func metaKeyEvent(config: KeyMap, keyDown: Bool) {
var shift: Bool
var option: Bool
var control: Bool
var command: Bool

if keyDown {
// Check if meta keys are not pressed before pressing keys
(shift, option, control, command) = getMetaKeyState()
pushedKeyConfigs.insert(config)
} else {
pushedKeyConfigs.remove(config)
// Check if meta keys are not pressed after releasing keys
(shift, option, control, command) = getMetaKeyState()
}

let source = CGEventSource(stateID: .hidSystemState)
let modifiers = NSEvent.ModifierFlags(rawValue: UInt(config.modifiers))
if !shift && modifiers.contains(.shift) {
let ev = CGEvent(keyboardEventSource: source, virtualKey: CGKeyCode(kVK_Shift), keyDown: keyDown)
ev?.post(tap: .cghidEventTap)
}

if !option && modifiers.contains(.option) {
let ev = CGEvent(keyboardEventSource: source, virtualKey: CGKeyCode(kVK_Option), keyDown: keyDown)
ev?.post(tap: .cghidEventTap)
}

if !control && modifiers.contains(.control) {
let ev = CGEvent(keyboardEventSource: source, virtualKey: CGKeyCode(kVK_Control), keyDown: keyDown)
ev?.post(tap: .cghidEventTap)
}

if !command && modifiers.contains(.command) {
let ev = CGEvent(keyboardEventSource: source, virtualKey: CGKeyCode(kVK_Command), keyDown: keyDown)
ev?.post(tap: .cghidEventTap)
}
}

0 comments on commit 81a78ce

Please sign in to comment.