From f8a8ab866e369812cb4da0a8ec914452a2a57be7 Mon Sep 17 00:00:00 2001 From: viatearz Date: Wed, 24 Sep 2025 22:04:23 +0800 Subject: [PATCH] fix: disable built-in mouse support to avoid click conflicts --- .../Controls/PTFakeTouch/NSObject+Swizzle.m | 38 +++++++++++++++++++ PlayTools/Controls/PlayInput.swift | 32 ++++++++++++++++ PlayTools/PlaySettings.swift | 3 ++ 3 files changed, 73 insertions(+) diff --git a/PlayTools/Controls/PTFakeTouch/NSObject+Swizzle.m b/PlayTools/Controls/PTFakeTouch/NSObject+Swizzle.m index d3f68bf3..aace284a 100644 --- a/PlayTools/Controls/PTFakeTouch/NSObject+Swizzle.m +++ b/PlayTools/Controls/PTFakeTouch/NSObject+Swizzle.m @@ -14,6 +14,7 @@ #import #import #import +#import __attribute__((visibility("hidden"))) @interface PTSwizzleLoader : NSObject @@ -62,6 +63,30 @@ - (void) swizzleExchangeMethod:(SEL)origSelector withMethod:(SEL)newSelector method_exchangeImplementations(originalMethod, swizzledMethod); } ++ (void) swizzleClassMethod:(SEL)origSelector withMethod:(SEL)newSelector { + Class cls = object_getClass((id)self); + Method originalMethod = class_getClassMethod(cls, origSelector); + Method swizzledMethod = class_getClassMethod(cls, newSelector); + + if (class_addMethod(cls, + origSelector, + method_getImplementation(swizzledMethod), + method_getTypeEncoding(swizzledMethod))) { + class_replaceMethod(cls, + newSelector, + method_getImplementation(originalMethod), + method_getTypeEncoding(originalMethod)); + } else { + class_replaceMethod(cls, + newSelector, + class_replaceMethod(cls, + origSelector, + method_getImplementation(swizzledMethod), + method_getTypeEncoding(swizzledMethod)), + method_getTypeEncoding(originalMethod)); + } +} + - (BOOL) hook_prefersPointerLocked { return false; } @@ -160,6 +185,14 @@ - (instancetype)hook_CMMotionManager_init { return motionManager; } ++ (GCMouse *)hook_GCMouse_current { + return nil; +} + ++ (NSArray *)hook_GCMouse_mice { + return @[]; +} + // Hook for UIUserInterfaceIdiom // - (long long) hook_userInterfaceIdiom { @@ -301,6 +334,11 @@ + (void)load { if ([[PlaySettings shared] limitMotionUpdateFrequency]) { [objc_getClass("CMMotionManager") swizzleInstanceMethod:@selector(init) withMethod:@selector(hook_CMMotionManager_init)]; } + + if (([[PlaySettings shared] disableBuiltinMouse])) { + [objc_getClass("GCMouse") swizzleClassMethod:@selector(current) withMethod:@selector(hook_GCMouse_current)]; + [objc_getClass("GCMouse") swizzleClassMethod:@selector(mice) withMethod:@selector(hook_GCMouse_mice)]; + } } @end diff --git a/PlayTools/Controls/PlayInput.swift b/PlayTools/Controls/PlayInput.swift index 45c3dfb7..6aa3cc0b 100644 --- a/PlayTools/Controls/PlayInput.swift +++ b/PlayTools/Controls/PlayInput.swift @@ -1,5 +1,6 @@ import Foundation import UIKit +import GameController // This class is a coordinator (and module entrance), coordinating other concrete classes @@ -19,6 +20,10 @@ class PlayInput { let displaylink = CADisplayLink(target: self, selector: #selector(drainMainDispatchQueue)) displaylink.add(to: .main, forMode: .common) + if PlaySettings.shared.disableBuiltinMouse { + simulateGCMouseDisconnect() + } + if !PlaySettings.shared.keymapping { return } @@ -41,4 +46,31 @@ class PlayInput { } mode.initialize() } + + private func simulateGCMouseDisconnect() { + NotificationCenter.default.addObserver( + forName: .GCMouseDidConnect, + object: nil, + queue: .main + ) { nofitication in + guard let mouse = nofitication.object as? GCMouse else { + return + } + DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1)) { + NotificationCenter.default.post(name: .GCMouseDidDisconnect, object: mouse) + mouse.mouseInput?.leftButton.pressedChangedHandler = nil + mouse.mouseInput?.leftButton.valueChangedHandler = nil + mouse.mouseInput?.rightButton?.pressedChangedHandler = nil + mouse.mouseInput?.rightButton?.valueChangedHandler = nil + mouse.mouseInput?.middleButton?.pressedChangedHandler = nil + mouse.mouseInput?.middleButton?.valueChangedHandler = nil + mouse.mouseInput?.auxiliaryButtons?.forEach { button in + button.pressedChangedHandler = nil + button.valueChangedHandler = nil + } + mouse.mouseInput?.scroll.valueChangedHandler = nil + mouse.mouseInput?.mouseMovedHandler = nil + } + } + } } diff --git a/PlayTools/PlaySettings.swift b/PlayTools/PlaySettings.swift index 5bf1a265..5c2cb5a8 100644 --- a/PlayTools/PlaySettings.swift +++ b/PlayTools/PlaySettings.swift @@ -87,6 +87,8 @@ let settings = PlaySettings.shared @objc lazy var checkMicPermissionSync = settingsData.checkMicPermissionSync @objc lazy var limitMotionUpdateFrequency = settingsData.limitMotionUpdateFrequency + + @objc lazy var disableBuiltinMouse = settingsData.disableBuiltinMouse } struct AppSettingsData: Codable { @@ -114,4 +116,5 @@ struct AppSettingsData: Codable { var hideTitleBar = false var checkMicPermissionSync = false var limitMotionUpdateFrequency = false + var disableBuiltinMouse = false }