From d5a10c56702b433c30b6aa7694ab4651ed939db7 Mon Sep 17 00:00:00 2001 From: Sinon <34333654+Catta1997@users.noreply.github.com> Date: Sat, 21 Feb 2026 11:55:51 +0100 Subject: [PATCH 1/3] feat: Better Controller Fix on Tahoe --- PlayTools.xcodeproj/project.pbxproj | 6 +++ PlayTools/Utils/BackgroundController.h | 18 ++++++++ PlayTools/Utils/BackgroundController.m | 61 ++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 PlayTools/Utils/BackgroundController.h create mode 100644 PlayTools/Utils/BackgroundController.m diff --git a/PlayTools.xcodeproj/project.pbxproj b/PlayTools.xcodeproj/project.pbxproj index 6c0f2ad5..f75318f8 100644 --- a/PlayTools.xcodeproj/project.pbxproj +++ b/PlayTools.xcodeproj/project.pbxproj @@ -81,6 +81,7 @@ B127172528817C040025112B /* DiscordIPC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B127172428817C040025112B /* DiscordIPC.swift */; }; B1271729288284BE0025112B /* DiscordActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1271728288284BE0025112B /* DiscordActivity.swift */; }; B1E8CF8A28BBE2AB004340D3 /* Keymapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1E8CF8928BBE2AB004340D3 /* Keymapping.swift */; }; + B444BB0D2F49C1D100ADCC5A /* BackgroundController.m in Sources */ = {isa = PBXBuildFile; fileRef = B444BB0B2F49C1D100ADCC5A /* BackgroundController.m */; }; B46C02C72C634AB5007637AB /* BatteryLevel.m in Sources */ = {isa = PBXBuildFile; fileRef = B46C02C62C634AB5007637AB /* BatteryLevel.m */; }; B66E65002C936EA100E48FD0 /* PlayedAppleDBConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66E64FF2C936E9800E48FD0 /* PlayedAppleDBConstants.swift */; }; B6D774FF2ACFC3D900C0D9D8 /* SwordRPC in Frameworks */ = {isa = PBXBuildFile; productRef = B6D774FE2ACFC3D900C0D9D8 /* SwordRPC */; }; @@ -180,6 +181,8 @@ B127172428817C040025112B /* DiscordIPC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscordIPC.swift; sourceTree = ""; }; B1271728288284BE0025112B /* DiscordActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscordActivity.swift; sourceTree = ""; }; B1E8CF8928BBE2AB004340D3 /* Keymapping.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Keymapping.swift; sourceTree = ""; }; + B444BB0B2F49C1D100ADCC5A /* BackgroundController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BackgroundController.m; sourceTree = ""; }; + B444BB0C2F49C1D100ADCC5A /* BackgroundController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BackgroundController.h; sourceTree = ""; }; B46C02C62C634AB5007637AB /* BatteryLevel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BatteryLevel.m; sourceTree = ""; }; B46C02C82C634C60007637AB /* BatteryLevel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BatteryLevel.h; sourceTree = ""; }; B66E64FF2C936E9800E48FD0 /* PlayedAppleDBConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayedAppleDBConstants.swift; sourceTree = ""; }; @@ -480,6 +483,8 @@ 6E7663A428D0FEBE00DE4AF9 /* AKPluginLoader.swift */, B46C02C62C634AB5007637AB /* BatteryLevel.m */, B46C02C82C634C60007637AB /* BatteryLevel.h */, + B444BB0B2F49C1D100ADCC5A /* BackgroundController.m */, + B444BB0C2F49C1D100ADCC5A /* BackgroundController.h */, ); path = Utils; sourceTree = ""; @@ -709,6 +714,7 @@ files = ( 954389CA2B392D7800B063BB /* DraggableButton.swift in Sources */, 9562D16D2AB505D4002C329D /* ControllerEventAdapter.swift in Sources */, + B444BB0D2F49C1D100ADCC5A /* BackgroundController.m in Sources */, AA71975A287A480D00623C15 /* Toucher.swift in Sources */, AA7197A1287A481500623C15 /* CircleMenuLoader.swift in Sources */, 6E76639B28D0FAE700DE4AF9 /* Plugin.swift in Sources */, diff --git a/PlayTools/Utils/BackgroundController.h b/PlayTools/Utils/BackgroundController.h new file mode 100644 index 00000000..c656853b --- /dev/null +++ b/PlayTools/Utils/BackgroundController.h @@ -0,0 +1,18 @@ +// +// BatteryLevel.h +// PlayTools +// +// Created by Edoardo C. on 21/02/26. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSObject (SwizzleBackgroundController) + +- (void)swizzleInstanceMethod:(SEL)origSelector withMethod:(SEL)newSelector; + +@end + +NS_ASSUME_NONNULL_END diff --git a/PlayTools/Utils/BackgroundController.m b/PlayTools/Utils/BackgroundController.m new file mode 100644 index 00000000..1dd74d80 --- /dev/null +++ b/PlayTools/Utils/BackgroundController.m @@ -0,0 +1,61 @@ +// +// BatteryLevel.m +// PlayTools +// +// Created by Edoardo C. on 21/02/26. +// + +#import +#import +#import +#import +#import "BackgroundController.h" + +__attribute__((visibility("hidden"))) +@interface BackgroundControllerLoader : NSObject +@end + +@implementation NSObject (SwizzleBackgroundController) + +- (void) swizzleInstanceMethod:(SEL)origSelector withMethod:(SEL)newSelector +{ + Class cls = [self class]; + // If current class doesn't exist selector, then get super + Method originalMethod = class_getInstanceMethod(cls, origSelector); + Method swizzledMethod = class_getInstanceMethod(cls, newSelector); + + // Add selector if it doesn't exist, implement append with method + if (class_addMethod(cls, + origSelector, + method_getImplementation(swizzledMethod), + method_getTypeEncoding(swizzledMethod)) ) { + // Replace class instance method, added if selector not exist + // For class cluster, it always adds new selector here + class_replaceMethod(cls, + newSelector, + method_getImplementation(originalMethod), + method_getTypeEncoding(originalMethod)); + + } else { + // SwizzleMethod maybe belongs to super + class_replaceMethod(cls, + newSelector, + class_replaceMethod(cls, + origSelector, + method_getImplementation(swizzledMethod), + method_getTypeEncoding(swizzledMethod)), + method_getTypeEncoding(originalMethod)); + } +} + +- (bool) pm_return_true { + return true; +} + +@end + +@implementation BackgroundControllerLoader ++ (void)load { + [objc_getClass("GCController") swizzleInstanceMethod:@selector(shouldMonitorBackgroundEvents) withMethod:@selector(pm_return_true)]; +} +@end From a55a3c82f071a2906cbc5d53d552613f2012bbbd Mon Sep 17 00:00:00 2001 From: Sinon <34333654+Catta1997@users.noreply.github.com> Date: Sat, 21 Feb 2026 11:58:32 +0100 Subject: [PATCH 2/3] Fix file comment --- PlayTools/Utils/BackgroundController.h | 2 +- PlayTools/Utils/BackgroundController.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PlayTools/Utils/BackgroundController.h b/PlayTools/Utils/BackgroundController.h index c656853b..12da7618 100644 --- a/PlayTools/Utils/BackgroundController.h +++ b/PlayTools/Utils/BackgroundController.h @@ -1,5 +1,5 @@ // -// BatteryLevel.h +// BackgroundController.h // PlayTools // // Created by Edoardo C. on 21/02/26. diff --git a/PlayTools/Utils/BackgroundController.m b/PlayTools/Utils/BackgroundController.m index 1dd74d80..2a721526 100644 --- a/PlayTools/Utils/BackgroundController.m +++ b/PlayTools/Utils/BackgroundController.m @@ -1,5 +1,5 @@ // -// BatteryLevel.m +// BackgroundController.m // PlayTools // // Created by Edoardo C. on 21/02/26. From b6464d82d7e1f627b7773d63b921fea5d90366cc Mon Sep 17 00:00:00 2001 From: Sinon <34333654+Catta1997@users.noreply.github.com> Date: Mon, 23 Feb 2026 22:41:30 +0100 Subject: [PATCH 3/3] feat: changed swizzle --- PlayTools.xcodeproj/project.pbxproj | 10 ++--- PlayTools/Utils/BackgroundController.h | 18 -------- PlayTools/Utils/BackgroundController.m | 61 -------------------------- PlayTools/Utils/ControllerFocus.m | 21 +++++++++ 4 files changed, 25 insertions(+), 85 deletions(-) delete mode 100644 PlayTools/Utils/BackgroundController.h delete mode 100644 PlayTools/Utils/BackgroundController.m create mode 100644 PlayTools/Utils/ControllerFocus.m diff --git a/PlayTools.xcodeproj/project.pbxproj b/PlayTools.xcodeproj/project.pbxproj index f75318f8..45bc7204 100644 --- a/PlayTools.xcodeproj/project.pbxproj +++ b/PlayTools.xcodeproj/project.pbxproj @@ -81,7 +81,7 @@ B127172528817C040025112B /* DiscordIPC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B127172428817C040025112B /* DiscordIPC.swift */; }; B1271729288284BE0025112B /* DiscordActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1271728288284BE0025112B /* DiscordActivity.swift */; }; B1E8CF8A28BBE2AB004340D3 /* Keymapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1E8CF8928BBE2AB004340D3 /* Keymapping.swift */; }; - B444BB0D2F49C1D100ADCC5A /* BackgroundController.m in Sources */ = {isa = PBXBuildFile; fileRef = B444BB0B2F49C1D100ADCC5A /* BackgroundController.m */; }; + B444BB0D2F49C1D100ADCC5A /* ControllerFocus.m in Sources */ = {isa = PBXBuildFile; fileRef = B444BB0B2F49C1D100ADCC5A /* ControllerFocus.m */; }; B46C02C72C634AB5007637AB /* BatteryLevel.m in Sources */ = {isa = PBXBuildFile; fileRef = B46C02C62C634AB5007637AB /* BatteryLevel.m */; }; B66E65002C936EA100E48FD0 /* PlayedAppleDBConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66E64FF2C936E9800E48FD0 /* PlayedAppleDBConstants.swift */; }; B6D774FF2ACFC3D900C0D9D8 /* SwordRPC in Frameworks */ = {isa = PBXBuildFile; productRef = B6D774FE2ACFC3D900C0D9D8 /* SwordRPC */; }; @@ -181,8 +181,7 @@ B127172428817C040025112B /* DiscordIPC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscordIPC.swift; sourceTree = ""; }; B1271728288284BE0025112B /* DiscordActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscordActivity.swift; sourceTree = ""; }; B1E8CF8928BBE2AB004340D3 /* Keymapping.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Keymapping.swift; sourceTree = ""; }; - B444BB0B2F49C1D100ADCC5A /* BackgroundController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BackgroundController.m; sourceTree = ""; }; - B444BB0C2F49C1D100ADCC5A /* BackgroundController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BackgroundController.h; sourceTree = ""; }; + B444BB0B2F49C1D100ADCC5A /* ControllerFocus.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ControllerFocus.m; sourceTree = ""; }; B46C02C62C634AB5007637AB /* BatteryLevel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BatteryLevel.m; sourceTree = ""; }; B46C02C82C634C60007637AB /* BatteryLevel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BatteryLevel.h; sourceTree = ""; }; B66E64FF2C936E9800E48FD0 /* PlayedAppleDBConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayedAppleDBConstants.swift; sourceTree = ""; }; @@ -483,8 +482,7 @@ 6E7663A428D0FEBE00DE4AF9 /* AKPluginLoader.swift */, B46C02C62C634AB5007637AB /* BatteryLevel.m */, B46C02C82C634C60007637AB /* BatteryLevel.h */, - B444BB0B2F49C1D100ADCC5A /* BackgroundController.m */, - B444BB0C2F49C1D100ADCC5A /* BackgroundController.h */, + B444BB0B2F49C1D100ADCC5A /* ControllerFocus.m */, ); path = Utils; sourceTree = ""; @@ -714,7 +712,7 @@ files = ( 954389CA2B392D7800B063BB /* DraggableButton.swift in Sources */, 9562D16D2AB505D4002C329D /* ControllerEventAdapter.swift in Sources */, - B444BB0D2F49C1D100ADCC5A /* BackgroundController.m in Sources */, + B444BB0D2F49C1D100ADCC5A /* ControllerFocus.m in Sources */, AA71975A287A480D00623C15 /* Toucher.swift in Sources */, AA7197A1287A481500623C15 /* CircleMenuLoader.swift in Sources */, 6E76639B28D0FAE700DE4AF9 /* Plugin.swift in Sources */, diff --git a/PlayTools/Utils/BackgroundController.h b/PlayTools/Utils/BackgroundController.h deleted file mode 100644 index 12da7618..00000000 --- a/PlayTools/Utils/BackgroundController.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// BackgroundController.h -// PlayTools -// -// Created by Edoardo C. on 21/02/26. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface NSObject (SwizzleBackgroundController) - -- (void)swizzleInstanceMethod:(SEL)origSelector withMethod:(SEL)newSelector; - -@end - -NS_ASSUME_NONNULL_END diff --git a/PlayTools/Utils/BackgroundController.m b/PlayTools/Utils/BackgroundController.m deleted file mode 100644 index 2a721526..00000000 --- a/PlayTools/Utils/BackgroundController.m +++ /dev/null @@ -1,61 +0,0 @@ -// -// BackgroundController.m -// PlayTools -// -// Created by Edoardo C. on 21/02/26. -// - -#import -#import -#import -#import -#import "BackgroundController.h" - -__attribute__((visibility("hidden"))) -@interface BackgroundControllerLoader : NSObject -@end - -@implementation NSObject (SwizzleBackgroundController) - -- (void) swizzleInstanceMethod:(SEL)origSelector withMethod:(SEL)newSelector -{ - Class cls = [self class]; - // If current class doesn't exist selector, then get super - Method originalMethod = class_getInstanceMethod(cls, origSelector); - Method swizzledMethod = class_getInstanceMethod(cls, newSelector); - - // Add selector if it doesn't exist, implement append with method - if (class_addMethod(cls, - origSelector, - method_getImplementation(swizzledMethod), - method_getTypeEncoding(swizzledMethod)) ) { - // Replace class instance method, added if selector not exist - // For class cluster, it always adds new selector here - class_replaceMethod(cls, - newSelector, - method_getImplementation(originalMethod), - method_getTypeEncoding(originalMethod)); - - } else { - // SwizzleMethod maybe belongs to super - class_replaceMethod(cls, - newSelector, - class_replaceMethod(cls, - origSelector, - method_getImplementation(swizzledMethod), - method_getTypeEncoding(swizzledMethod)), - method_getTypeEncoding(originalMethod)); - } -} - -- (bool) pm_return_true { - return true; -} - -@end - -@implementation BackgroundControllerLoader -+ (void)load { - [objc_getClass("GCController") swizzleInstanceMethod:@selector(shouldMonitorBackgroundEvents) withMethod:@selector(pm_return_true)]; -} -@end diff --git a/PlayTools/Utils/ControllerFocus.m b/PlayTools/Utils/ControllerFocus.m new file mode 100644 index 00000000..f9f86b5f --- /dev/null +++ b/PlayTools/Utils/ControllerFocus.m @@ -0,0 +1,21 @@ +// +// ControllerFocus.m +// PlayTools +// +// Created by Edoardo C. on 23/02/26. +// + +#import +#import +#import +#import + +__attribute__((visibility("hidden"))) +@interface BackgroundControllerLoader : NSObject +@end + +@implementation BackgroundControllerLoader ++ (void)load { + [GCController setShouldMonitorBackgroundEvents:YES]; +} +@end