From eb9622fe111aa54a653c6da229582471760e99f3 Mon Sep 17 00:00:00 2001 From: Mateus Sales Bentes Date: Wed, 11 Mar 2026 22:15:14 -0300 Subject: [PATCH 1/5] * (Mac) RTLooneyLadders: replace SDL2 gamepad provider with native GCController (GameController.framework) - fixes Xbox/PS/Switch Pro controllers not being detected in the Cocoa build path --- .../RTLooneyLadders.xcodeproj/project.pbxproj | 16 ++ RTLooneyLadders/source/App.cpp | 8 +- shared/Gamepad/GamepadGCController.h | 29 ++++ shared/Gamepad/GamepadGCController.mm | 151 ++++++++++++++++++ shared/Gamepad/GamepadProviderGCController.h | 25 +++ shared/Gamepad/GamepadProviderGCController.mm | 131 +++++++++++++++ 6 files changed, 357 insertions(+), 3 deletions(-) create mode 100644 shared/Gamepad/GamepadGCController.h create mode 100644 shared/Gamepad/GamepadGCController.mm create mode 100644 shared/Gamepad/GamepadProviderGCController.h create mode 100644 shared/Gamepad/GamepadProviderGCController.mm diff --git a/RTLooneyLadders/OSX/RTLooneyLadders.xcodeproj/project.pbxproj b/RTLooneyLadders/OSX/RTLooneyLadders.xcodeproj/project.pbxproj index 5d25437..715e30b 100644 --- a/RTLooneyLadders/OSX/RTLooneyLadders.xcodeproj/project.pbxproj +++ b/RTLooneyLadders/OSX/RTLooneyLadders.xcodeproj/project.pbxproj @@ -200,6 +200,9 @@ AA000004000000000000AA01 /* AudioManagerSDL.cpp in Sources */ = {isa = PBXBuildF GPLL0000000000000000000003 /* GamepadSDL2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = GPLL0000000000000000000013 /* GamepadSDL2.cpp */; }; GPLL0000000000000000000004 /* GamepadProvider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = GPLL0000000000000000000014 /* GamepadProvider.cpp */; }; GPLL0000000000000000000005 /* Gamepad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = GPLL0000000000000000000015 /* Gamepad.cpp */; }; + GPLL0000000000000000000006 /* GamepadProviderGCController.mm in Sources */ = {isa = PBXBuildFile; fileRef = GPLL0000000000000000000016 /* GamepadProviderGCController.mm */; }; + GPLL0000000000000000000007 /* GamepadGCController.mm in Sources */ = {isa = PBXBuildFile; fileRef = GPLL0000000000000000000017 /* GamepadGCController.mm */; }; + GPLL0000000000000000000008 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = GPLL0000000000000000000018 /* GameController.framework */; }; /* SDL2 embed build files */ SDLLL00000000000000000001 /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = SDLLL00000000000000000011 /* SDL2.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; SDLLL00000000000000000002 /* SDL2_mixer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = SDLLL00000000000000000012 /* SDL2_mixer.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -473,6 +476,11 @@ AA000003000000000000AA02 /* AudioManagerSDL.h */ = {isa = PBXFileReference; file GPLL0000000000000000000024 /* GamepadProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GamepadProvider.h; path = ../../shared/Gamepad/GamepadProvider.h; sourceTree = SOURCE_ROOT; }; GPLL0000000000000000000015 /* Gamepad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Gamepad.cpp; path = ../../shared/Gamepad/Gamepad.cpp; sourceTree = SOURCE_ROOT; }; GPLL0000000000000000000025 /* Gamepad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Gamepad.h; path = ../../shared/Gamepad/Gamepad.h; sourceTree = SOURCE_ROOT; }; + GPLL0000000000000000000016 /* GamepadProviderGCController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = GamepadProviderGCController.mm; path = ../../shared/Gamepad/GamepadProviderGCController.mm; sourceTree = SOURCE_ROOT; }; + GPLL0000000000000000000026 /* GamepadProviderGCController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GamepadProviderGCController.h; path = ../../shared/Gamepad/GamepadProviderGCController.h; sourceTree = SOURCE_ROOT; }; + GPLL0000000000000000000017 /* GamepadGCController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = GamepadGCController.mm; path = ../../shared/Gamepad/GamepadGCController.mm; sourceTree = SOURCE_ROOT; }; + GPLL0000000000000000000027 /* GamepadGCController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GamepadGCController.h; path = ../../shared/Gamepad/GamepadGCController.h; sourceTree = SOURCE_ROOT; }; + GPLL0000000000000000000018 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; }; /* SDL2 framework references */ SDLLL00000000000000000011 /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = "$(HOME)/Library/Frameworks/SDL2.framework"; sourceTree = ""; }; SDLLL00000000000000000012 /* SDL2_mixer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2_mixer.framework; path = "$(HOME)/Library/Frameworks/SDL2_mixer.framework"; sourceTree = ""; }; @@ -521,6 +529,7 @@ AA000003000000000000AA02 /* AudioManagerSDL.h */ = {isa = PBXFileReference; file 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, AFD4D88A113C504F00C2DE76 /* OpenGL.framework in Frameworks */, AF9DBBC6113C611C00D05754 /* QuartzCore.framework in Frameworks */, + GPLL0000000000000000000008 /* GameController.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -558,6 +567,7 @@ AA000003000000000000AA02 /* AudioManagerSDL.h */ = {isa = PBXFileReference; file 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, AFD4D889113C504F00C2DE76 /* OpenGL.framework */, AF9DBBC5113C611C00D05754 /* QuartzCore.framework */, + GPLL0000000000000000000018 /* GameController.framework */, ); name = "Linked Frameworks"; sourceTree = ""; @@ -715,6 +725,10 @@ AA000003000000000000AA02 /* AudioManagerSDL.h */ = {isa = PBXFileReference; file GPLL0000000000000000000022 /* GamepadProviderSDL2.h */, GPLL0000000000000000000013 /* GamepadSDL2.cpp */, GPLL0000000000000000000023 /* GamepadSDL2.h */, + GPLL0000000000000000000016 /* GamepadProviderGCController.mm */, + GPLL0000000000000000000026 /* GamepadProviderGCController.h */, + GPLL0000000000000000000017 /* GamepadGCController.mm */, + GPLL0000000000000000000027 /* GamepadGCController.h */, ); name = Gamepad; sourceTree = ""; @@ -1266,6 +1280,8 @@ AA000003000000000000AA02 /* AudioManagerSDL.h */ = {isa = PBXFileReference; file GPLL0000000000000000000001 /* GamepadManager.cpp in Sources */, GPLL0000000000000000000002 /* GamepadProviderSDL2.cpp in Sources */, GPLL0000000000000000000003 /* GamepadSDL2.cpp in Sources */, + GPLL0000000000000000000006 /* GamepadProviderGCController.mm in Sources */, + GPLL0000000000000000000007 /* GamepadGCController.mm in Sources */, LL000001000000000000000001 /* BuildingComponent.cpp in Sources */, LL000001000000000000000002 /* Character.cpp in Sources */, LL000001000000000000000003 /* CharComponent.cpp in Sources */, diff --git a/RTLooneyLadders/source/App.cpp b/RTLooneyLadders/source/App.cpp index 5882762..14f6b35 100644 --- a/RTLooneyLadders/source/App.cpp +++ b/RTLooneyLadders/source/App.cpp @@ -32,7 +32,7 @@ AudioManagerOS g_audioManager; #else //it's being compiled as a native OSX app - use SDL audio, no FMOD required #include "Audio/AudioManagerSDL.h" -#include "Gamepad/GamepadProviderSDL2.h" +#include "Gamepad/GamepadProviderGCController.h" #include AudioManagerSDL g_audioManager; // Required by MainController.mm and BaseApp.cpp - defined in SDL2Main.cpp for SDL builds @@ -129,8 +129,10 @@ bool App::Init() if (!BaseApp::Init()) return false; #ifdef PLATFORM_OSX - SDL_Init(SDL_INIT_EVENTS | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER); - GetGamepadManager()->AddProvider(new GamepadProviderSDL2()); + SDL_Init(SDL_INIT_EVENTS); + GetGamepadManager()->AddProvider(new GamepadProviderGCController()); + GetGamepadManager()->m_sig_gamepad_connected.connect(1, boost::bind(&App::OnGamepadConnected, this, _1)); + GetGamepadManager()->m_sig_gamepad_disconnected.connect(1, boost::bind(&App::OnGamepadDisconnected, this, _1)); #endif LogMsg("Save path is %s", GetSavePath().c_str()); diff --git a/shared/Gamepad/GamepadGCController.h b/shared/Gamepad/GamepadGCController.h new file mode 100644 index 0000000..56f3abb --- /dev/null +++ b/shared/Gamepad/GamepadGCController.h @@ -0,0 +1,29 @@ +#pragma once + +#ifdef PLATFORM_OSX + +#include "Gamepad.h" + +#ifdef __OBJC__ +#import +#endif + +class GamepadGCController : public Gamepad +{ +public: + GamepadGCController(); + virtual ~GamepadGCController(); + + virtual bool Init(); + virtual void Kill(); + virtual void Update(); + +#ifdef __OBJC__ + void InitWithGCController(GCController* controller); +#endif + +protected: + void* m_pGCController; // GCController* stored as void* for non-ObjC translation units +}; + +#endif // PLATFORM_OSX diff --git a/shared/Gamepad/GamepadGCController.mm b/shared/Gamepad/GamepadGCController.mm new file mode 100644 index 0000000..0d90e7b --- /dev/null +++ b/shared/Gamepad/GamepadGCController.mm @@ -0,0 +1,151 @@ +#include "PlatformPrecomp.h" + +#ifdef PLATFORM_OSX + +#include "GamepadGCController.h" +#include "GamepadManager.h" + +GamepadGCController::GamepadGCController() +{ + m_pGCController = nullptr; +} + +GamepadGCController::~GamepadGCController() +{ + Kill(); +} + +bool GamepadGCController::Init() +{ + m_axisUsedCount = 6; + m_buttonsUsedCount = 16; + m_name = "GCController"; + return true; +} + +void GamepadGCController::Kill() +{ + if (m_pGCController) + { + GCController* controller = (__bridge GCController*)m_pGCController; + (void)controller; + m_pGCController = nullptr; + } +} + +void GamepadGCController::Update() +{ + Gamepad::Update(); +} + +void GamepadGCController::InitWithGCController(GCController* controller) +{ + m_pGCController = (__bridge void*)controller; + + const char* pName = [controller.vendorName UTF8String]; + if (pName) + { + LogMsg("GCController detected: %s", pName); + m_name = pName; + } + + // Same button mapping as GamepadSDL2 Windows path + SetRightStickAxis(2, 3); + + m_buttons[SDL_CONTROLLER_BUTTON_A].m_virtualKey = VIRTUAL_DPAD_BUTTON_DOWN; + m_buttons[SDL_CONTROLLER_BUTTON_B].m_virtualKey = VIRTUAL_DPAD_BUTTON_RIGHT; + m_buttons[SDL_CONTROLLER_BUTTON_X].m_virtualKey = VIRTUAL_DPAD_BUTTON_LEFT; + m_buttons[SDL_CONTROLLER_BUTTON_Y].m_virtualKey = VIRTUAL_DPAD_BUTTON_UP; + m_buttons[SDL_CONTROLLER_BUTTON_LEFTSHOULDER].m_virtualKey = VIRTUAL_DPAD_LBUTTON; + m_buttons[SDL_CONTROLLER_BUTTON_RIGHTSHOULDER].m_virtualKey= VIRTUAL_DPAD_RBUTTON; + m_buttons[SDL_CONTROLLER_BUTTON_BACK].m_virtualKey = VIRTUAL_DPAD_SELECT; + m_buttons[SDL_CONTROLLER_BUTTON_START].m_virtualKey = VIRTUAL_DPAD_START; + m_buttons[SDL_CONTROLLER_BUTTON_GUIDE].m_virtualKey = VIRTUAL_DPAD_MENU; + m_buttons[SDL_CONTROLLER_BUTTON_LEFTSTICK].m_virtualKey = VIRTUAL_JOYSTICK_BUTTON_LEFT; + m_buttons[SDL_CONTROLLER_BUTTON_RIGHTSTICK].m_virtualKey = VIRTUAL_JOYSTICK_BUTTON_RIGHT; + m_buttons[SDL_CONTROLLER_BUTTON_DPAD_UP].m_virtualKey = VIRTUAL_KEY_DIR_UP; + m_buttons[SDL_CONTROLLER_BUTTON_DPAD_DOWN].m_virtualKey = VIRTUAL_KEY_DIR_DOWN; + m_buttons[SDL_CONTROLLER_BUTTON_DPAD_LEFT].m_virtualKey = VIRTUAL_KEY_DIR_LEFT; + m_buttons[SDL_CONTROLLER_BUTTON_DPAD_RIGHT].m_virtualKey = VIRTUAL_KEY_DIR_RIGHT; + + GCExtendedGamepad* pad = controller.extendedGamepad; + if (!pad) + { + LogMsg("GCController has no extendedGamepad profile, ignoring"); + return; + } + + // Capture a weak ref to self for the block + GamepadGCController* self = this; + + pad.buttonA.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { + self->OnButton(pressed, SDL_CONTROLLER_BUTTON_A); + }; + pad.buttonB.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { + self->OnButton(pressed, SDL_CONTROLLER_BUTTON_B); + }; + pad.buttonX.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { + self->OnButton(pressed, SDL_CONTROLLER_BUTTON_X); + }; + pad.buttonY.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { + self->OnButton(pressed, SDL_CONTROLLER_BUTTON_Y); + }; + pad.leftShoulder.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { + self->OnButton(pressed, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); + }; + pad.rightShoulder.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { + self->OnButton(pressed, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); + }; + pad.leftThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { + self->OnButton(pressed, SDL_CONTROLLER_BUTTON_LEFTSTICK); + }; + pad.rightThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { + self->OnButton(pressed, SDL_CONTROLLER_BUTTON_RIGHTSTICK); + }; + pad.buttonOptions.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { + self->OnButton(pressed, SDL_CONTROLLER_BUTTON_BACK); + }; + pad.buttonMenu.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { + self->OnButton(pressed, SDL_CONTROLLER_BUTTON_START); + }; + + // D-pad + pad.dpad.up.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { + self->OnButton(pressed, SDL_CONTROLLER_BUTTON_DPAD_UP); + }; + pad.dpad.down.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { + self->OnButton(pressed, SDL_CONTROLLER_BUTTON_DPAD_DOWN); + }; + pad.dpad.left.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { + self->OnButton(pressed, SDL_CONTROLLER_BUTTON_DPAD_LEFT); + }; + pad.dpad.right.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { + self->OnButton(pressed, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); + }; + + // Left stick + pad.leftThumbstick.xAxis.valueChangedHandler = ^(GCControllerAxisInput*, float value) { + self->SetAxis(0, value); + }; + pad.leftThumbstick.yAxis.valueChangedHandler = ^(GCControllerAxisInput*, float value) { + self->SetAxis(1, -value); // GCController Y is inverted vs SDL convention + }; + + // Right stick + pad.rightThumbstick.xAxis.valueChangedHandler = ^(GCControllerAxisInput*, float value) { + self->SetAxis(2, value); + }; + pad.rightThumbstick.yAxis.valueChangedHandler = ^(GCControllerAxisInput*, float value) { + self->SetAxis(3, -value); + }; + + // Triggers (axes 4 and 5) + pad.leftTrigger.valueChangedHandler = ^(GCControllerButtonInput*, float value, BOOL) { + self->SetAxis(4, value); + }; + pad.rightTrigger.valueChangedHandler = ^(GCControllerButtonInput*, float value, BOOL) { + self->SetAxis(5, value); + }; +} + +#endif // PLATFORM_OSX diff --git a/shared/Gamepad/GamepadProviderGCController.h b/shared/Gamepad/GamepadProviderGCController.h new file mode 100644 index 0000000..745d39b --- /dev/null +++ b/shared/Gamepad/GamepadProviderGCController.h @@ -0,0 +1,25 @@ +#pragma once + +#ifdef PLATFORM_OSX + +#include "GamepadProvider.h" + +class GamepadProviderGCController : public GamepadProvider +{ +public: + GamepadProviderGCController(); + virtual ~GamepadProviderGCController(); + + virtual string GetName() { return "GCController"; } + virtual bool Init(); + virtual void Kill(); + virtual void Update(); + +protected: + void AddControllerByIndex(int index); + + void* m_pConnectObserver; // id stored as void* + void* m_pDisconnectObserver; // id stored as void* +}; + +#endif // PLATFORM_OSX diff --git a/shared/Gamepad/GamepadProviderGCController.mm b/shared/Gamepad/GamepadProviderGCController.mm new file mode 100644 index 0000000..25d7dff --- /dev/null +++ b/shared/Gamepad/GamepadProviderGCController.mm @@ -0,0 +1,131 @@ +#include "PlatformPrecomp.h" + +#ifdef PLATFORM_OSX + +#include "GamepadProviderGCController.h" +#include "GamepadGCController.h" +#include "GamepadManager.h" + +#import + +// Use the GCController pointer address as a stable unique ID +static eGamepadID IDFromController(GCController* c) +{ + return (eGamepadID)(uintptr_t)(__bridge void*)c; +} + +GamepadProviderGCController::GamepadProviderGCController() + : m_pConnectObserver(nullptr) + , m_pDisconnectObserver(nullptr) +{ +} + +GamepadProviderGCController::~GamepadProviderGCController() +{ + Kill(); +} + +void GamepadProviderGCController::AddControllerByIndex(int index) +{ + NSArray* controllers = [GCController controllers]; + if (index < 0 || index >= (int)[controllers count]) + return; + + GCController* controller = controllers[index]; + + if (!controller.extendedGamepad) + { + LogMsg("GCController at index %d has no extendedGamepad, skipping", index); + return; + } + + eGamepadID uid = IDFromController(controller); + + if (GetGamepadManager()->GetGamepadByUniqueID(uid)) + { + LogMsg("GCController already registered, ignoring"); + return; + } + + GamepadGCController* pPad = new GamepadGCController(); + pPad->SetProvider(this); + pPad->Init(); + GetGamepadManager()->AddGamepad(pPad, uid); + pPad->InitWithGCController(controller); +} + +bool GamepadProviderGCController::Init() +{ + LogMsg("Initting GCController gamepad provider"); + + // Enumerate already-connected controllers + NSArray* controllers = [GCController controllers]; + LogMsg("GCController: %d controller(s) already connected", (int)[controllers count]); + for (int i = 0; i < (int)[controllers count]; i++) + { + AddControllerByIndex(i); + } + + // Watch for future connect/disconnect + GamepadProviderGCController* self = this; + + id connectObs = [[NSNotificationCenter defaultCenter] + addObserverForName:GCControllerDidConnectNotification + object:nil + queue:[NSOperationQueue mainQueue] + usingBlock:^(NSNotification* note) { + GCController* controller = note.object; + if (!controller.extendedGamepad) + { + LogMsg("GCController connected but has no extendedGamepad, skipping"); + return; + } + eGamepadID uid = IDFromController(controller); + if (GetGamepadManager()->GetGamepadByUniqueID(uid)) + return; + GamepadGCController* pPad = new GamepadGCController(); + pPad->SetProvider(self); + pPad->Init(); + GetGamepadManager()->AddGamepad(pPad, uid); + pPad->InitWithGCController(controller); + }]; + + id disconnectObs = [[NSNotificationCenter defaultCenter] + addObserverForName:GCControllerDidDisconnectNotification + object:nil + queue:[NSOperationQueue mainQueue] + usingBlock:^(NSNotification* note) { + GCController* controller = note.object; + eGamepadID uid = IDFromController(controller); + LogMsg("GCController disconnected, uid %ld", (long)uid); + GetGamepadManager()->RemoveGamepadByUniqueID(uid); + }]; + + m_pConnectObserver = (__bridge_retained void*)connectObs; + m_pDisconnectObserver = (__bridge_retained void*)disconnectObs; + + return true; +} + +void GamepadProviderGCController::Kill() +{ + if (m_pConnectObserver) + { + id obs = (__bridge_transfer id)m_pConnectObserver; + [[NSNotificationCenter defaultCenter] removeObserver:obs]; + m_pConnectObserver = nullptr; + } + if (m_pDisconnectObserver) + { + id obs = (__bridge_transfer id)m_pDisconnectObserver; + [[NSNotificationCenter defaultCenter] removeObserver:obs]; + m_pDisconnectObserver = nullptr; + } +} + +void GamepadProviderGCController::Update() +{ + // GCController callbacks are delivered on the main queue — nothing to poll +} + +#endif // PLATFORM_OSX From 0dd512839d91a7a84899ad702400796353ed3fe0 Mon Sep 17 00:00:00 2001 From: Mateus Sales Bentes Date: Wed, 11 Mar 2026 22:23:49 -0300 Subject: [PATCH 2/5] * RTLooneyLadders iOS project: fix resource paths bin/ -> media/ (audio, game, interface folders are in media/, not bin/) --- RTLooneyLadders/RTLooneyLadders.xcodeproj/project.pbxproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/RTLooneyLadders/RTLooneyLadders.xcodeproj/project.pbxproj b/RTLooneyLadders/RTLooneyLadders.xcodeproj/project.pbxproj index 38d8109..ec4956d 100644 --- a/RTLooneyLadders/RTLooneyLadders.xcodeproj/project.pbxproj +++ b/RTLooneyLadders/RTLooneyLadders.xcodeproj/project.pbxproj @@ -289,7 +289,7 @@ 5D7BBD0010144FF50015A90E /* ResourceManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResourceManager.h; path = Manager/ResourceManager.h; sourceTree = ""; }; 5D7BBD081014530B0015A90E /* SurfaceAnim.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SurfaceAnim.cpp; path = ../shared/Renderer/SurfaceAnim.cpp; sourceTree = SOURCE_ROOT; }; 5D7BBD091014530B0015A90E /* SurfaceAnim.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SurfaceAnim.h; path = ../shared/Renderer/SurfaceAnim.h; sourceTree = SOURCE_ROOT; }; - 5D7C329E10BBB755009C5324 /* game */ = {isa = PBXFileReference; lastKnownFileType = folder; name = game; path = bin/game; sourceTree = ""; }; + 5D7C329E10BBB755009C5324 /* game */ = {isa = PBXFileReference; lastKnownFileType = folder; name = game; path = media/game; sourceTree = ""; }; 5D7C32C810BBD401009C5324 /* FilterInputComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FilterInputComponent.cpp; path = Entity/FilterInputComponent.cpp; sourceTree = ""; }; 5D7C32C910BBD401009C5324 /* FilterInputComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FilterInputComponent.h; path = Entity/FilterInputComponent.h; sourceTree = ""; }; 5D7C32CA10BBD401009C5324 /* RenderClipComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RenderClipComponent.cpp; path = Entity/RenderClipComponent.cpp; sourceTree = ""; }; @@ -325,7 +325,7 @@ 5D82C88A0FF4BB3F0082EBE7 /* NetUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NetUtils.h; path = Network/NetUtils.h; sourceTree = ""; }; 5D82C8AF0FF4C02B0082EBE7 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; 5D82C8B40FF4C0BF0082EBE7 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; - 5D82C8C20FF4C1500082EBE7 /* audio */ = {isa = PBXFileReference; lastKnownFileType = folder; name = audio; path = bin/audio; sourceTree = ""; }; + 5D82C8C20FF4C1500082EBE7 /* audio */ = {isa = PBXFileReference; lastKnownFileType = folder; name = audio; path = media/audio; sourceTree = ""; }; 5D841435101583BD00366718 /* InputTextRenderComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InputTextRenderComponent.cpp; path = Entity/InputTextRenderComponent.cpp; sourceTree = ""; }; 5D841436101583BD00366718 /* InputTextRenderComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InputTextRenderComponent.h; path = Entity/InputTextRenderComponent.h; sourceTree = ""; }; 5D8483DD0F923D51007338A2 /* Component.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Component.cpp; path = Entity/Component.cpp; sourceTree = ""; }; @@ -360,7 +360,7 @@ 5DB488DA10B1313300B84589 /* RenderBatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RenderBatcher.h; path = ../shared/Renderer/RenderBatcher.h; sourceTree = SOURCE_ROOT; }; 5DC692B00E94852F00E5AC44 /* App.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = App.h; path = source/App.h; sourceTree = ""; }; 5DC692B10E94852F00E5AC44 /* App.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = App.cpp; path = source/App.cpp; sourceTree = ""; }; - 5DC6D63B0EA47C0E001482E0 /* interface */ = {isa = PBXFileReference; lastKnownFileType = folder; name = interface; path = bin/interface; sourceTree = ""; }; + 5DC6D63B0EA47C0E001482E0 /* interface */ = {isa = PBXFileReference; lastKnownFileType = folder; name = interface; path = media/interface; sourceTree = ""; }; 5DC6D77B0EA4B397001482E0 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Default.png; path = media/Default.png; sourceTree = ""; }; 5DC6D77C0EA4B397001482E0 /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon.png; path = media/icon.png; sourceTree = ""; }; 5DD3272012C1CE500009B0F3 /* GameMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GameMenu.h; path = source/GUI/GameMenu.h; sourceTree = ""; }; From 31ce454429402e66bcfae2b385dd2800f4c49fc9 Mon Sep 17 00:00:00 2001 From: Mateus Sales Bentes Date: Wed, 11 Mar 2026 22:26:17 -0300 Subject: [PATCH 3/5] Revert "* RTLooneyLadders iOS project: fix resource paths bin/ -> media/ (audio, game, interface folders are in media/, not bin/)" This reverts commit 0dd512839d91a7a84899ad702400796353ed3fe0. --- RTLooneyLadders/RTLooneyLadders.xcodeproj/project.pbxproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/RTLooneyLadders/RTLooneyLadders.xcodeproj/project.pbxproj b/RTLooneyLadders/RTLooneyLadders.xcodeproj/project.pbxproj index ec4956d..38d8109 100644 --- a/RTLooneyLadders/RTLooneyLadders.xcodeproj/project.pbxproj +++ b/RTLooneyLadders/RTLooneyLadders.xcodeproj/project.pbxproj @@ -289,7 +289,7 @@ 5D7BBD0010144FF50015A90E /* ResourceManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResourceManager.h; path = Manager/ResourceManager.h; sourceTree = ""; }; 5D7BBD081014530B0015A90E /* SurfaceAnim.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SurfaceAnim.cpp; path = ../shared/Renderer/SurfaceAnim.cpp; sourceTree = SOURCE_ROOT; }; 5D7BBD091014530B0015A90E /* SurfaceAnim.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SurfaceAnim.h; path = ../shared/Renderer/SurfaceAnim.h; sourceTree = SOURCE_ROOT; }; - 5D7C329E10BBB755009C5324 /* game */ = {isa = PBXFileReference; lastKnownFileType = folder; name = game; path = media/game; sourceTree = ""; }; + 5D7C329E10BBB755009C5324 /* game */ = {isa = PBXFileReference; lastKnownFileType = folder; name = game; path = bin/game; sourceTree = ""; }; 5D7C32C810BBD401009C5324 /* FilterInputComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FilterInputComponent.cpp; path = Entity/FilterInputComponent.cpp; sourceTree = ""; }; 5D7C32C910BBD401009C5324 /* FilterInputComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FilterInputComponent.h; path = Entity/FilterInputComponent.h; sourceTree = ""; }; 5D7C32CA10BBD401009C5324 /* RenderClipComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RenderClipComponent.cpp; path = Entity/RenderClipComponent.cpp; sourceTree = ""; }; @@ -325,7 +325,7 @@ 5D82C88A0FF4BB3F0082EBE7 /* NetUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NetUtils.h; path = Network/NetUtils.h; sourceTree = ""; }; 5D82C8AF0FF4C02B0082EBE7 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; 5D82C8B40FF4C0BF0082EBE7 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; - 5D82C8C20FF4C1500082EBE7 /* audio */ = {isa = PBXFileReference; lastKnownFileType = folder; name = audio; path = media/audio; sourceTree = ""; }; + 5D82C8C20FF4C1500082EBE7 /* audio */ = {isa = PBXFileReference; lastKnownFileType = folder; name = audio; path = bin/audio; sourceTree = ""; }; 5D841435101583BD00366718 /* InputTextRenderComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InputTextRenderComponent.cpp; path = Entity/InputTextRenderComponent.cpp; sourceTree = ""; }; 5D841436101583BD00366718 /* InputTextRenderComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InputTextRenderComponent.h; path = Entity/InputTextRenderComponent.h; sourceTree = ""; }; 5D8483DD0F923D51007338A2 /* Component.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Component.cpp; path = Entity/Component.cpp; sourceTree = ""; }; @@ -360,7 +360,7 @@ 5DB488DA10B1313300B84589 /* RenderBatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RenderBatcher.h; path = ../shared/Renderer/RenderBatcher.h; sourceTree = SOURCE_ROOT; }; 5DC692B00E94852F00E5AC44 /* App.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = App.h; path = source/App.h; sourceTree = ""; }; 5DC692B10E94852F00E5AC44 /* App.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = App.cpp; path = source/App.cpp; sourceTree = ""; }; - 5DC6D63B0EA47C0E001482E0 /* interface */ = {isa = PBXFileReference; lastKnownFileType = folder; name = interface; path = media/interface; sourceTree = ""; }; + 5DC6D63B0EA47C0E001482E0 /* interface */ = {isa = PBXFileReference; lastKnownFileType = folder; name = interface; path = bin/interface; sourceTree = ""; }; 5DC6D77B0EA4B397001482E0 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Default.png; path = media/Default.png; sourceTree = ""; }; 5DC6D77C0EA4B397001482E0 /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon.png; path = media/icon.png; sourceTree = ""; }; 5DD3272012C1CE500009B0F3 /* GameMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GameMenu.h; path = source/GUI/GameMenu.h; sourceTree = ""; }; From aee64356a220d26b45bdfa4a149b6bc3dcae3c28 Mon Sep 17 00:00:00 2001 From: Mateus Sales Bentes Date: Wed, 11 Mar 2026 22:29:39 -0300 Subject: [PATCH 4/5] * (Mac) GamepadGCController: fix SDL_CONTROLLER_BUTTON_* undeclared errors - use local GCC_BTN_* enum instead; fix ARC bridge warnings by using CFRetain/CFRelease --- shared/Gamepad/GamepadGCController.mm | 82 +++++++++++-------- shared/Gamepad/GamepadProviderGCController.mm | 12 +-- 2 files changed, 57 insertions(+), 37 deletions(-) diff --git a/shared/Gamepad/GamepadGCController.mm b/shared/Gamepad/GamepadGCController.mm index 0d90e7b..3e5603a 100644 --- a/shared/Gamepad/GamepadGCController.mm +++ b/shared/Gamepad/GamepadGCController.mm @@ -5,6 +5,26 @@ #include "GamepadGCController.h" #include "GamepadManager.h" +// Button index constants matching SDL_CONTROLLER_BUTTON_* values, +// used as raw indices into m_buttons[]. No SDL headers needed here. +enum { + GCC_BTN_A = 0, + GCC_BTN_B = 1, + GCC_BTN_X = 2, + GCC_BTN_Y = 3, + GCC_BTN_BACK = 4, + GCC_BTN_GUIDE = 5, + GCC_BTN_START = 6, + GCC_BTN_LEFTSTICK = 7, + GCC_BTN_RIGHTSTICK = 8, + GCC_BTN_LEFTSHOULDER = 9, + GCC_BTN_RIGHTSHOULDER = 10, + GCC_BTN_DPAD_UP = 11, + GCC_BTN_DPAD_DOWN = 12, + GCC_BTN_DPAD_LEFT = 13, + GCC_BTN_DPAD_RIGHT = 14, +}; + GamepadGCController::GamepadGCController() { m_pGCController = nullptr; @@ -27,8 +47,6 @@ { if (m_pGCController) { - GCController* controller = (__bridge GCController*)m_pGCController; - (void)controller; m_pGCController = nullptr; } } @@ -40,7 +58,7 @@ void GamepadGCController::InitWithGCController(GCController* controller) { - m_pGCController = (__bridge void*)controller; + m_pGCController = (void*)controller; const char* pName = [controller.vendorName UTF8String]; if (pName) @@ -52,21 +70,21 @@ // Same button mapping as GamepadSDL2 Windows path SetRightStickAxis(2, 3); - m_buttons[SDL_CONTROLLER_BUTTON_A].m_virtualKey = VIRTUAL_DPAD_BUTTON_DOWN; - m_buttons[SDL_CONTROLLER_BUTTON_B].m_virtualKey = VIRTUAL_DPAD_BUTTON_RIGHT; - m_buttons[SDL_CONTROLLER_BUTTON_X].m_virtualKey = VIRTUAL_DPAD_BUTTON_LEFT; - m_buttons[SDL_CONTROLLER_BUTTON_Y].m_virtualKey = VIRTUAL_DPAD_BUTTON_UP; - m_buttons[SDL_CONTROLLER_BUTTON_LEFTSHOULDER].m_virtualKey = VIRTUAL_DPAD_LBUTTON; - m_buttons[SDL_CONTROLLER_BUTTON_RIGHTSHOULDER].m_virtualKey= VIRTUAL_DPAD_RBUTTON; - m_buttons[SDL_CONTROLLER_BUTTON_BACK].m_virtualKey = VIRTUAL_DPAD_SELECT; - m_buttons[SDL_CONTROLLER_BUTTON_START].m_virtualKey = VIRTUAL_DPAD_START; - m_buttons[SDL_CONTROLLER_BUTTON_GUIDE].m_virtualKey = VIRTUAL_DPAD_MENU; - m_buttons[SDL_CONTROLLER_BUTTON_LEFTSTICK].m_virtualKey = VIRTUAL_JOYSTICK_BUTTON_LEFT; - m_buttons[SDL_CONTROLLER_BUTTON_RIGHTSTICK].m_virtualKey = VIRTUAL_JOYSTICK_BUTTON_RIGHT; - m_buttons[SDL_CONTROLLER_BUTTON_DPAD_UP].m_virtualKey = VIRTUAL_KEY_DIR_UP; - m_buttons[SDL_CONTROLLER_BUTTON_DPAD_DOWN].m_virtualKey = VIRTUAL_KEY_DIR_DOWN; - m_buttons[SDL_CONTROLLER_BUTTON_DPAD_LEFT].m_virtualKey = VIRTUAL_KEY_DIR_LEFT; - m_buttons[SDL_CONTROLLER_BUTTON_DPAD_RIGHT].m_virtualKey = VIRTUAL_KEY_DIR_RIGHT; + m_buttons[GCC_BTN_A].m_virtualKey = VIRTUAL_DPAD_BUTTON_DOWN; + m_buttons[GCC_BTN_B].m_virtualKey = VIRTUAL_DPAD_BUTTON_RIGHT; + m_buttons[GCC_BTN_X].m_virtualKey = VIRTUAL_DPAD_BUTTON_LEFT; + m_buttons[GCC_BTN_Y].m_virtualKey = VIRTUAL_DPAD_BUTTON_UP; + m_buttons[GCC_BTN_LEFTSHOULDER].m_virtualKey = VIRTUAL_DPAD_LBUTTON; + m_buttons[GCC_BTN_RIGHTSHOULDER].m_virtualKey = VIRTUAL_DPAD_RBUTTON; + m_buttons[GCC_BTN_BACK].m_virtualKey = VIRTUAL_DPAD_SELECT; + m_buttons[GCC_BTN_START].m_virtualKey = VIRTUAL_DPAD_START; + m_buttons[GCC_BTN_GUIDE].m_virtualKey = VIRTUAL_DPAD_MENU; + m_buttons[GCC_BTN_LEFTSTICK].m_virtualKey = VIRTUAL_JOYSTICK_BUTTON_LEFT; + m_buttons[GCC_BTN_RIGHTSTICK].m_virtualKey = VIRTUAL_JOYSTICK_BUTTON_RIGHT; + m_buttons[GCC_BTN_DPAD_UP].m_virtualKey = VIRTUAL_KEY_DIR_UP; + m_buttons[GCC_BTN_DPAD_DOWN].m_virtualKey = VIRTUAL_KEY_DIR_DOWN; + m_buttons[GCC_BTN_DPAD_LEFT].m_virtualKey = VIRTUAL_KEY_DIR_LEFT; + m_buttons[GCC_BTN_DPAD_RIGHT].m_virtualKey = VIRTUAL_KEY_DIR_RIGHT; GCExtendedGamepad* pad = controller.extendedGamepad; if (!pad) @@ -79,48 +97,48 @@ GamepadGCController* self = this; pad.buttonA.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { - self->OnButton(pressed, SDL_CONTROLLER_BUTTON_A); + self->OnButton(pressed, GCC_BTN_A); }; pad.buttonB.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { - self->OnButton(pressed, SDL_CONTROLLER_BUTTON_B); + self->OnButton(pressed, GCC_BTN_B); }; pad.buttonX.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { - self->OnButton(pressed, SDL_CONTROLLER_BUTTON_X); + self->OnButton(pressed, GCC_BTN_X); }; pad.buttonY.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { - self->OnButton(pressed, SDL_CONTROLLER_BUTTON_Y); + self->OnButton(pressed, GCC_BTN_Y); }; pad.leftShoulder.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { - self->OnButton(pressed, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); + self->OnButton(pressed, GCC_BTN_LEFTSHOULDER); }; pad.rightShoulder.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { - self->OnButton(pressed, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); + self->OnButton(pressed, GCC_BTN_RIGHTSHOULDER); }; pad.leftThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { - self->OnButton(pressed, SDL_CONTROLLER_BUTTON_LEFTSTICK); + self->OnButton(pressed, GCC_BTN_LEFTSTICK); }; pad.rightThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { - self->OnButton(pressed, SDL_CONTROLLER_BUTTON_RIGHTSTICK); + self->OnButton(pressed, GCC_BTN_RIGHTSTICK); }; pad.buttonOptions.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { - self->OnButton(pressed, SDL_CONTROLLER_BUTTON_BACK); + self->OnButton(pressed, GCC_BTN_BACK); }; pad.buttonMenu.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { - self->OnButton(pressed, SDL_CONTROLLER_BUTTON_START); + self->OnButton(pressed, GCC_BTN_START); }; // D-pad pad.dpad.up.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { - self->OnButton(pressed, SDL_CONTROLLER_BUTTON_DPAD_UP); + self->OnButton(pressed, GCC_BTN_DPAD_UP); }; pad.dpad.down.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { - self->OnButton(pressed, SDL_CONTROLLER_BUTTON_DPAD_DOWN); + self->OnButton(pressed, GCC_BTN_DPAD_DOWN); }; pad.dpad.left.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { - self->OnButton(pressed, SDL_CONTROLLER_BUTTON_DPAD_LEFT); + self->OnButton(pressed, GCC_BTN_DPAD_LEFT); }; pad.dpad.right.valueChangedHandler = ^(GCControllerButtonInput*, float, BOOL pressed) { - self->OnButton(pressed, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); + self->OnButton(pressed, GCC_BTN_DPAD_RIGHT); }; // Left stick diff --git a/shared/Gamepad/GamepadProviderGCController.mm b/shared/Gamepad/GamepadProviderGCController.mm index 25d7dff..eee1b6c 100644 --- a/shared/Gamepad/GamepadProviderGCController.mm +++ b/shared/Gamepad/GamepadProviderGCController.mm @@ -11,7 +11,7 @@ // Use the GCController pointer address as a stable unique ID static eGamepadID IDFromController(GCController* c) { - return (eGamepadID)(uintptr_t)(__bridge void*)c; + return (eGamepadID)(uintptr_t)(void*)c; } GamepadProviderGCController::GamepadProviderGCController() @@ -101,8 +101,8 @@ static eGamepadID IDFromController(GCController* c) GetGamepadManager()->RemoveGamepadByUniqueID(uid); }]; - m_pConnectObserver = (__bridge_retained void*)connectObs; - m_pDisconnectObserver = (__bridge_retained void*)disconnectObs; + m_pConnectObserver = (void*)CFRetain((__bridge CFTypeRef)connectObs); + m_pDisconnectObserver = (void*)CFRetain((__bridge CFTypeRef)disconnectObs); return true; } @@ -111,14 +111,16 @@ static eGamepadID IDFromController(GCController* c) { if (m_pConnectObserver) { - id obs = (__bridge_transfer id)m_pConnectObserver; + id obs = (__bridge id)m_pConnectObserver; [[NSNotificationCenter defaultCenter] removeObserver:obs]; + CFRelease((CFTypeRef)m_pConnectObserver); m_pConnectObserver = nullptr; } if (m_pDisconnectObserver) { - id obs = (__bridge_transfer id)m_pDisconnectObserver; + id obs = (__bridge id)m_pDisconnectObserver; [[NSNotificationCenter defaultCenter] removeObserver:obs]; + CFRelease((CFTypeRef)m_pDisconnectObserver); m_pDisconnectObserver = nullptr; } } From 9882bdaee52228b845840e86e818fbdbb3ddebdd Mon Sep 17 00:00:00 2001 From: Mateus Sales Bentes Date: Wed, 11 Mar 2026 22:38:01 -0300 Subject: [PATCH 5/5] changed readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b55d089..3a5dbfd 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ The following demo apps have Xcode projects under their `OSX/` folder: |-----|--------------|-------|-------| | **RTBareBones** | `RTBareBones/OSX/RTBareBones.xcodeproj` | Dummy (no audio) | Simplest starting point | | **RTSimpleApp** | `RTSimpleApp/OSX/RTSimpleApp.xcodeproj` | SDL2_mixer | Basic app with SDL audio | -| **RTLooneyLadders** | `RTLooneyLadders/OSX/RTLooneyLadders.xcodeproj` | SDL2_mixer | Full game with gamepad support (game controllers not yet working on Mac) | +| **RTLooneyLadders** | `RTLooneyLadders/OSX/RTLooneyLadders.xcodeproj` | SDL2_mixer | Full game with gamepad support | All projects target **macOS 11.0+** and build as **universal binaries** (arm64 + x86_64).