1
0
mirror of https://github.com/Toxblh/MTMR.git synced 2026-01-09 16:48:38 +00:00

Fix HapticFeedback; Add MBP 13, M1 2020 (#408)

* Fix HapticFeedback; Add MBP 13, M1 2020

* Fix warnings

Co-authored-by: Sergey Ryazanov <sergey.ryazanov@rightperception.company>
This commit is contained in:
Sergey Ryazanov 2021-06-23 13:58:18 +04:00 committed by GitHub
parent 44732e8ad6
commit d270a7bbcd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 64 additions and 62 deletions

View File

@ -25,7 +25,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
AXIsProcessTrustedWithOptions([kAXTrustedCheckOptionPrompt.takeRetainedValue() as NSString: true] as NSDictionary)
TouchBarController.shared.setupControlStripPresence()
HapticFeedbackUpdate()
if let button = statusItem.button {
button.image = #imageLiteral(resourceName: "StatusImage")
@ -41,10 +40,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
func applicationWillTerminate(_: Notification) {}
func HapticFeedbackUpdate() {
HapticFeedback.shared = AppSettings.hapticFeedbackState ? HapticFeedback() : nil
}
@objc func updateIsBlockedApp() {
if let frontmostAppId = TouchBarController.shared.frontmostApplicationIdentifier {
isBlockedApp = AppSettings.blacklistedAppIds.firstIndex(of: frontmostAppId) != nil
@ -86,7 +81,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
@objc func toggleHapticFeedback(_ item: NSMenuItem) {
item.state = item.state == .on ? .off : .on
AppSettings.hapticFeedbackState = item.state == .on
HapticFeedbackUpdate()
}
@objc func toggleMultitouch(_ item: NSMenuItem) {

View File

@ -240,12 +240,12 @@ final class MultiClickGestureRecognizer: NSClickGestureRecognizer {
}
override func touchesBegan(with event: NSEvent) {
HapticFeedback.shared?.tap(strong: 2)
HapticFeedback.instance.tap(type: .click)
super.touchesBegan(with: event)
}
override func touchesEnded(with event: NSEvent) {
HapticFeedback.shared?.tap(strong: 1)
HapticFeedback.instance.tap(type: .back)
super.touchesEnded(with: event)
_clickCount += 1
@ -322,7 +322,7 @@ class LongPressGestureRecognizer: NSPressGestureRecognizer {
@objc private func onTimer() {
if let target = self.target, let action = self.action {
target.performSelector(onMainThread: action, with: self, waitUntilDone: false)
HapticFeedback.shared?.tap(strong: 6)
HapticFeedback.instance.tap(type: .strong)
}
}

View File

@ -9,81 +9,89 @@
import IOKit
class HapticFeedback {
static var shared: HapticFeedback?
// Here we have list of possible IDs for Haptic Generator Device. They are not constant
// To find deviceID, you will need IORegistryExplorer app from Additional Tools for Xcode dmg
// which you can download from https://developer.apple.com/download/more/?=Additional%20Tools
// Open IORegistryExplorer app, search for AppleMultitouchDevice and get "Multitouch ID"
// There should be programmatic way to get it but I can't find, no docs for macOS :(
private let possibleDeviceIDs: [UInt64] = [
0x200_0000_0100_0000, // MacBook Pro 2016/2017
0x300000080500000 // MacBook Pro 2019 (possibly 2018 as well)
0x200_0000_0100_0000, // MacBook Pro 2016/2017
0x300_0000_8050_0000, // MacBook Pro 2019/2018
0x200_0000_0000_0024, // MacBook Pro (13-inch, M1, 2020)
]
private var correctDeviceID: UInt64?
private var actuatorRef: CFTypeRef?
init() {
recreateDevice()
// you can get a plist `otool -s __TEXT __tpad_act_plist /System/Library/PrivateFrameworks/MultitouchSupport.framework/Versions/Current/MultitouchSupport|tail -n +3|awk -F'\t' '{print $2}'|xxd -r -p`
enum HapticType: Int32, CaseIterable {
case back = 1
case click = 2
case weak = 3
case medium = 4
case weakMedium = 5
case strong = 6
case reserved1 = 15
case reserved2 = 16
}
// Don't know how to do strong is enum one of
// 1 like back Click
// 2 like Click
// 3 week
// 4 medium
// 5 week medium
// 6 strong
// 15 nothing
// 16 nothing
// you can get a plist `otool -s __TEXT __tpad_act_plist /System/Library/PrivateFrameworks/MultitouchSupport.framework/Versions/Current/MultitouchSupport|tail -n +3|awk -F'\t' '{print $2}'|xxd -r -p`
private var actuatorRef: CFTypeRef?
func tap(strong: Int32) {
guard correctDeviceID != nil, actuatorRef != nil else {
static var instance = HapticFeedback()
// MARK: - Init
private init() {
self.recreateDevice()
}
private func recreateDevice() {
if let actuatorRef = self.actuatorRef {
MTActuatorClose(actuatorRef)
self.actuatorRef = nil // just in case %)
}
guard self.actuatorRef == nil else {
return
}
// Let's find our Haptic device
self.possibleDeviceIDs.forEach {(deviceID) in
let actuatorRef = MTActuatorCreateFromDeviceID(deviceID).takeRetainedValue()
if actuatorRef != nil {
self.actuatorRef = actuatorRef
}
}
}
// MARK: - Tap action
private func getActuatorIfPosible() -> CFTypeRef? {
guard AppSettings.hapticFeedbackState else { return nil }
guard let actuatorRef = self.actuatorRef else {
print("guard actuatorRef == nil (no haptic device found?)")
return
return nil
}
var result: IOReturn
result = MTActuatorOpen(actuatorRef!)
guard result == kIOReturnSuccess else {
guard MTActuatorOpen(actuatorRef) == kIOReturnSuccess else {
print("guard MTActuatorOpen")
recreateDevice()
return
self.recreateDevice()
return nil
}
result = MTActuatorActuate(actuatorRef!, strong, 0, 0, 0)
guard result == kIOReturnSuccess else {
return actuatorRef
}
func tap(type: HapticType) {
guard let actuator = getActuatorIfPosible() else { return }
guard MTActuatorActuate(actuator, type.rawValue, 0, 0, 0) == kIOReturnSuccess else {
print("guard MTActuatorActuate")
return
}
result = MTActuatorClose(actuatorRef!)
guard result == kIOReturnSuccess else {
guard MTActuatorClose(actuator) == kIOReturnSuccess else {
print("guard MTActuatorClose")
return
}
}
private func recreateDevice() {
if let actuatorRef = actuatorRef {
MTActuatorClose(actuatorRef)
self.actuatorRef = nil // just in case %)
}
if let correctDeviceID = correctDeviceID {
actuatorRef = MTActuatorCreateFromDeviceID(correctDeviceID).takeRetainedValue()
} else {
// Let's find our Haptic device
possibleDeviceIDs.forEach {(deviceID) in
guard correctDeviceID == nil else {return}
actuatorRef = MTActuatorCreateFromDeviceID(deviceID).takeRetainedValue()
if actuatorRef != nil {
correctDeviceID = deviceID
}
}
}
}
}