From 4f2379a2d30eda0b4352a28f6dd17f07e8bfc2ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 May 2024 00:24:36 +0200 Subject: [PATCH 01/10] Remove obsolete code path --- ios/ViewController.mm | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 10dd5bf70d..6a0232b62d 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -325,12 +325,6 @@ extern float g_safeInsetBottom; [self shutdown]; } -// For iOS before 6.0 -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation -{ - return UIInterfaceOrientationIsLandscape(toInterfaceOrientation); -} - // For iOS 6.0 and up - (NSUInteger)supportedInterfaceOrientations { @@ -346,7 +340,6 @@ extern float g_safeInsetBottom; - (void)touchX:(float)x y:(float)y code:(int)code pointerId:(int)pointerId { float scale = [UIScreen mainScreen].scale; - if ([[UIScreen mainScreen] respondsToSelector:@selector(nativeScale)]) { scale = [UIScreen mainScreen].nativeScale; } From 09e89e9d7903a83b6e5a087f1e54fb1e155e71a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 May 2024 10:38:40 +0200 Subject: [PATCH 02/10] Minor cleanup --- CMakeLists.txt | 2 + ios/Controls.h | 3 + ios/Controls.mm | 3 + ios/ViewController.h | 2 - ios/ViewController.mm | 11 --- ios/iOSCoreAudio.mm | 157 +++++++++++++++++++++--------------------- 6 files changed, 87 insertions(+), 91 deletions(-) create mode 100644 ios/Controls.h create mode 100644 ios/Controls.mm diff --git a/CMakeLists.txt b/CMakeLists.txt index 749f788478..e0d117728b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1290,6 +1290,8 @@ elseif(IOS AND NOT LIBRETRO) ios/AppDelegate.h ios/DisplayManager.h ios/DisplayManager.mm + ios/Controls.h + ios/Controls.mm ios/ViewController.mm ios/ViewController.h ios/iOSCoreAudio.mm diff --git a/ios/Controls.h b/ios/Controls.h new file mode 100644 index 0000000000..2f5ed182a1 --- /dev/null +++ b/ios/Controls.h @@ -0,0 +1,3 @@ +// Code extracted from ViewController.mm, in order to modularize +// and share it between multiple view controllers. + diff --git a/ios/Controls.mm b/ios/Controls.mm new file mode 100644 index 0000000000..0ddf13417b --- /dev/null +++ b/ios/Controls.mm @@ -0,0 +1,3 @@ +#include "Controls.h" + +#include "Common/Log.h" diff --git a/ios/ViewController.h b/ios/ViewController.h index 0e91161453..1e1678685d 100644 --- a/ios/ViewController.h +++ b/ios/ViewController.h @@ -2,9 +2,7 @@ #import #import -#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1 #import -#endif #import "iCade/iCadeReaderView.h" #import "CameraHelper.h" #import "LocationHelper.h" diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 6a0232b62d..cb7547efcf 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -110,9 +110,7 @@ static LocationHelper *locationHelper; @property (nonatomic, strong) EAGLContext* context; //@property (nonatomic) iCadeReaderView* iCadeView; -#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1 @property (nonatomic) GCController *gameController __attribute__((weak_import)); -#endif @end @@ -139,13 +137,11 @@ static LocationHelper *locationHelper; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillTerminate:) name:UIApplicationWillTerminateNotification object:nil]; -#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1 if ([GCController class]) // Checking the availability of a GameController framework { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidConnect:) name:GCControllerDidConnectNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidDisconnect:) name:GCControllerDidDisconnectNotification object:nil]; } -#endif } return self; } @@ -170,7 +166,6 @@ extern float g_safeInsetBottom; - (void)viewSafeAreaInsetsDidChange { if (@available(iOS 11.0, *)) { [super viewSafeAreaInsetsDidChange]; - char safeArea[100]; // we use 0.0f instead of safeAreaInsets.bottom because the bottom overlay isn't disturbing (for now) g_safeInsetLeft = self.view.safeAreaInsets.left; g_safeInsetRight = self.view.safeAreaInsets.right; @@ -225,13 +220,11 @@ extern float g_safeInsetBottom; self.iCadeView.delegate = self; self.iCadeView.active = YES;*/ -#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1 if ([GCController class]) { if ([[GCController controllers] count] > 0) { [self setupController:[[GCController controllers] firstObject]]; } } -#endif cameraHelper = [[CameraHelper alloc] init]; [cameraHelper setDelegate:self]; @@ -305,11 +298,9 @@ extern float g_safeInsetBottom; [[NSNotificationCenter defaultCenter] removeObserver:self]; -#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1 if ([GCController class]) { self.gameController = nil; } -#endif if (graphicsContext) { graphicsContext->Shutdown(); @@ -553,10 +544,8 @@ int ToTouchID(UITouch *uiTouch, bool allowAllocate) { key.deviceId = DEVICE_ID_PAD_0; NativeKey(key); } - } -#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1 - (void)controllerDidConnect:(NSNotification *)note { if (![[GCController controllers] containsObject:self.gameController]) self.gameController = nil; diff --git a/ios/iOSCoreAudio.mm b/ios/iOSCoreAudio.mm index 8743ab7953..8129cc9afc 100644 --- a/ios/iOSCoreAudio.mm +++ b/ios/iOSCoreAudio.mm @@ -25,10 +25,9 @@ #include #import - #define SAMPLE_RATE 44100 -AudioComponentInstance audioInstance = nil; +static AudioComponentInstance audioInstance = nil; int NativeMix(short *audio, int numSamples, int sampleRate); @@ -77,83 +76,85 @@ void iOSCoreAudioInit() } } - if (!audioInstance) { - OSErr err; - - // first, grab the default output - AudioComponentDescription defaultOutputDescription; - defaultOutputDescription.componentType = kAudioUnitType_Output; - defaultOutputDescription.componentSubType = kAudioUnitSubType_RemoteIO; - defaultOutputDescription.componentManufacturer = kAudioUnitManufacturer_Apple; - defaultOutputDescription.componentFlags = 0; - defaultOutputDescription.componentFlagsMask = 0; - AudioComponent defaultOutput = AudioComponentFindNext(NULL, &defaultOutputDescription); - - // create our instance - err = AudioComponentInstanceNew(defaultOutput, &audioInstance); - if (err != noErr) { - audioInstance = nil; - return; - } - - // create our callback so we can give it the audio data - AURenderCallbackStruct input; - input.inputProc = iOSCoreAudioCallback; - input.inputProcRefCon = NULL; - err = AudioUnitSetProperty(audioInstance, - kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, - 0, - &input, - sizeof(input)); - if (err != noErr) { - AudioComponentInstanceDispose(audioInstance); - audioInstance = nil; - return; - } - - // setup the audio format we'll be using (stereo pcm) - AudioStreamBasicDescription streamFormat; - memset(&streamFormat, 0, sizeof(streamFormat)); - streamFormat.mSampleRate = SAMPLE_RATE; - streamFormat.mFormatID = kAudioFormatLinearPCM; - streamFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; - streamFormat.mBitsPerChannel = sizeof(short) * 8; - streamFormat.mChannelsPerFrame = 2; - streamFormat.mFramesPerPacket = 1; - streamFormat.mBytesPerFrame = (streamFormat.mBitsPerChannel / 8) * streamFormat.mChannelsPerFrame; - streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame * streamFormat.mFramesPerPacket; - err = AudioUnitSetProperty(audioInstance, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, - 0, - &streamFormat, - sizeof(AudioStreamBasicDescription)); - if (err != noErr) { - AudioComponentInstanceDispose(audioInstance); - audioInstance = nil; - return; - } - - // k, all setup, so init - err = AudioUnitInitialize(audioInstance); - if (err != noErr) { - AudioComponentInstanceDispose(audioInstance); - audioInstance = nil; - return; - } - - // finally start playback - err = AudioOutputUnitStart(audioInstance); - if (err != noErr) { - AudioUnitUninitialize(audioInstance); - AudioComponentInstanceDispose(audioInstance); - audioInstance = nil; - return; - } - - // we're good to go + if (audioInstance) { + // Already running + return; } + OSErr err; + + // first, grab the default output + AudioComponentDescription defaultOutputDescription; + defaultOutputDescription.componentType = kAudioUnitType_Output; + defaultOutputDescription.componentSubType = kAudioUnitSubType_RemoteIO; + defaultOutputDescription.componentManufacturer = kAudioUnitManufacturer_Apple; + defaultOutputDescription.componentFlags = 0; + defaultOutputDescription.componentFlagsMask = 0; + AudioComponent defaultOutput = AudioComponentFindNext(NULL, &defaultOutputDescription); + + // create our instance + err = AudioComponentInstanceNew(defaultOutput, &audioInstance); + if (err != noErr) { + audioInstance = nil; + return; + } + + // create our callback so we can give it the audio data + AURenderCallbackStruct input; + input.inputProc = iOSCoreAudioCallback; + input.inputProcRefCon = NULL; + err = AudioUnitSetProperty(audioInstance, + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, + 0, + &input, + sizeof(input)); + if (err != noErr) { + AudioComponentInstanceDispose(audioInstance); + audioInstance = nil; + return; + } + + // setup the audio format we'll be using (stereo pcm) + AudioStreamBasicDescription streamFormat; + memset(&streamFormat, 0, sizeof(streamFormat)); + streamFormat.mSampleRate = SAMPLE_RATE; + streamFormat.mFormatID = kAudioFormatLinearPCM; + streamFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; + streamFormat.mBitsPerChannel = sizeof(short) * 8; + streamFormat.mChannelsPerFrame = 2; + streamFormat.mFramesPerPacket = 1; + streamFormat.mBytesPerFrame = (streamFormat.mBitsPerChannel / 8) * streamFormat.mChannelsPerFrame; + streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame * streamFormat.mFramesPerPacket; + err = AudioUnitSetProperty(audioInstance, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + &streamFormat, + sizeof(AudioStreamBasicDescription)); + if (err != noErr) { + AudioComponentInstanceDispose(audioInstance); + audioInstance = nil; + return; + } + + // k, all setup, so init + err = AudioUnitInitialize(audioInstance); + if (err != noErr) { + AudioComponentInstanceDispose(audioInstance); + audioInstance = nil; + return; + } + + // finally start playback + err = AudioOutputUnitStart(audioInstance); + if (err != noErr) { + AudioUnitUninitialize(audioInstance); + AudioComponentInstanceDispose(audioInstance); + audioInstance = nil; + return; + } + + // we're good to go } void iOSCoreAudioShutdown() From c34079a9081c619d8c8c023cc00690a579b6f642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 May 2024 11:17:01 +0200 Subject: [PATCH 03/10] Hide keyboard on app display --- ios/ViewController.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/ios/ViewController.mm b/ios/ViewController.mm index cb7547efcf..d48a63371f 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -176,6 +176,7 @@ extern float g_safeInsetBottom; - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; + [self hideKeyboard]; } - (void)viewDidLoad { From 04a260bded12e22d85a05431b46004404a612b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 May 2024 11:17:38 +0200 Subject: [PATCH 04/10] Move System_LaunchUri to a more appropriate place --- ios/ViewController.mm | 8 -------- ios/main.mm | 12 +++++++++++- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/ios/ViewController.mm b/ios/ViewController.mm index d48a63371f..b35399416c 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -807,14 +807,6 @@ void stopLocation() { @end -void System_LaunchUrl(LaunchUrlType urlType, char const* url) -{ - NSURL *nsUrl = [NSURL URLWithString:[NSString stringWithCString:url encoding:NSStringEncodingConversionAllowLossy]]; - dispatch_async(dispatch_get_main_queue(), ^{ - [[UIApplication sharedApplication] openURL:nsUrl options:@{} completionHandler:nil]; - }); -} - void bindDefaultFBO() { [sharedViewController bindDefaultFBO]; diff --git a/ios/main.mm b/ios/main.mm index ae369324df..0466c67000 100644 --- a/ios/main.mm +++ b/ios/main.mm @@ -489,7 +489,17 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string void System_Toast(std::string_view text) {} void System_AskForPermission(SystemPermission permission) {} -PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; } +void System_LaunchUrl(LaunchUrlType urlType, const char *url) +{ + NSURL *nsUrl = [NSURL URLWithString:[NSString stringWithCString:url encoding:NSStringEncodingConversionAllowLossy]]; + dispatch_async(dispatch_get_main_queue(), ^{ + [[UIApplication sharedApplication] openURL:nsUrl options:@{} completionHandler:nil]; + }); +} + +PermissionStatus System_GetPermissionStatus(SystemPermission permission) { + return PERMISSION_STATUS_GRANTED; +} #if !PPSSPP_PLATFORM(IOS_APP_STORE) FOUNDATION_EXTERN void AudioServicesPlaySystemSoundWithVibration(unsigned long, objc_object*, NSDictionary*); From 82573b4f8256d7e8c27cfe42317265f9b67dd722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 May 2024 11:18:03 +0200 Subject: [PATCH 05/10] Move controller setup to Controls.mm --- ios/Controls.h | 5 ++ ios/Controls.mm | 145 ++++++++++++++++++++++++++++++++++++++++++ ios/DisplayManager.mm | 4 +- ios/ViewController.mm | 141 +--------------------------------------- 4 files changed, 154 insertions(+), 141 deletions(-) diff --git a/ios/Controls.h b/ios/Controls.h index 2f5ed182a1..ce89fae303 100644 --- a/ios/Controls.h +++ b/ios/Controls.h @@ -1,3 +1,8 @@ +#pragma once + +#import + // Code extracted from ViewController.mm, in order to modularize // and share it between multiple view controllers. +bool SetupController(GCController *controller); \ No newline at end of file diff --git a/ios/Controls.mm b/ios/Controls.mm index 0ddf13417b..346c18e9e9 100644 --- a/ios/Controls.mm +++ b/ios/Controls.mm @@ -1,3 +1,148 @@ #include "Controls.h" #include "Common/Log.h" +#include "Common/Input/InputState.h" +#include "Common/System/NativeApp.h" + +static void controllerButtonPressed(BOOL pressed, InputKeyCode keyCode) { + KeyInput key; + key.deviceId = DEVICE_ID_PAD_0; + key.flags = pressed ? KEY_DOWN : KEY_UP; + key.keyCode = keyCode; + NativeKey(key); +} + +bool SetupController(GCController *controller) { + GCGamepad *baseProfile = controller.gamepad; + if (baseProfile == nil) { + return false; + } + + controller.controllerPausedHandler = ^(GCController *controller) { + KeyInput key; + key.flags = KEY_DOWN; + key.keyCode = NKCODE_ESCAPE; + key.deviceId = DEVICE_ID_KEYBOARD; + NativeKey(key); + }; + + baseProfile.buttonA.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_2); // Cross + }; + + baseProfile.buttonB.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_3); // Circle + }; + + baseProfile.buttonX.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_4); // Square + }; + + baseProfile.buttonY.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_1); // Triangle + }; + + baseProfile.leftShoulder.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_7); // LTrigger + }; + + baseProfile.rightShoulder.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_8); // RTrigger + }; + + baseProfile.dpad.up.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_DPAD_UP); + }; + + baseProfile.dpad.down.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_DPAD_DOWN); + }; + + baseProfile.dpad.left.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_DPAD_LEFT); + }; + + baseProfile.dpad.right.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_DPAD_RIGHT); + }; + + GCExtendedGamepad *extendedProfile = controller.extendedGamepad; + if (extendedProfile == nil) + return; // controller doesn't support extendedGamepad profile + + extendedProfile.leftTrigger.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_9); // Select + }; + + extendedProfile.rightTrigger.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_10); // Start + }; + +#if defined(__IPHONE_12_1) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_12_1 + if ([extendedProfile respondsToSelector:@selector(leftThumbstickButton)] && extendedProfile.leftThumbstickButton != nil) { + extendedProfile.leftThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_11); + }; + } + if ([extendedProfile respondsToSelector:@selector(rightThumbstickButton)] && extendedProfile.rightThumbstickButton != nil) { + extendedProfile.rightThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_12); + }; + } +#endif +#if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0 + if ([extendedProfile respondsToSelector:@selector(buttonOptions)] && extendedProfile.buttonOptions != nil) { + extendedProfile.buttonOptions.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_13); + }; + } + if ([extendedProfile respondsToSelector:@selector(buttonMenu)] && extendedProfile.buttonMenu != nil) { + extendedProfile.buttonMenu.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_14); + }; + } +#endif +#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0 + if ([extendedProfile respondsToSelector:@selector(buttonHome)] && extendedProfile.buttonHome != nil) { + extendedProfile.buttonHome.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + controllerButtonPressed(pressed, NKCODE_BUTTON_15); + }; + } +#endif + + extendedProfile.leftThumbstick.xAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) { + AxisInput axisInput; + axisInput.deviceId = DEVICE_ID_PAD_0; + axisInput.axisId = JOYSTICK_AXIS_X; + axisInput.value = value; + NativeAxis(&axisInput, 1); + }; + + extendedProfile.leftThumbstick.yAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) { + AxisInput axisInput; + axisInput.deviceId = DEVICE_ID_PAD_0; + axisInput.axisId = JOYSTICK_AXIS_Y; + axisInput.value = -value; + NativeAxis(&axisInput, 1); + }; + + // Map right thumbstick as another analog stick, particularly useful for controllers + // like the DualShock 3/4 when connected to an iOS device + extendedProfile.rightThumbstick.xAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) { + AxisInput axisInput; + axisInput.deviceId = DEVICE_ID_PAD_0; + axisInput.axisId = JOYSTICK_AXIS_Z; + axisInput.value = value; + NativeAxis(&axisInput, 1); + }; + + extendedProfile.rightThumbstick.yAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) { + AxisInput axisInput; + axisInput.deviceId = DEVICE_ID_PAD_0; + axisInput.axisId = JOYSTICK_AXIS_RZ; + axisInput.value = -value; + NativeAxis(&axisInput, 1); + }; + + return true; +} diff --git a/ios/DisplayManager.mm b/ios/DisplayManager.mm index ce669d5dbd..02c795de9f 100644 --- a/ios/DisplayManager.mm +++ b/ios/DisplayManager.mm @@ -139,14 +139,14 @@ scale = screen.nativeScale; } - CGSize size = screen.applicationFrame.size; + CGSize size = screen.bounds.size; if (size.height > size.width) { float h = size.height; size.height = size.width; size.width = h; } - + if (screen == [UIScreen mainScreen]) { g_display.dpi = (IS_IPAD() ? 200.0f : 150.0f) * scale; } else { diff --git a/ios/ViewController.mm b/ios/ViewController.mm index b35399416c..bbf072100e 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -8,6 +8,7 @@ #import "AppDelegate.h" #import "ViewController.h" #import "DisplayManager.h" +#include "Controls.h" #import "iOSCoreAudio.h" #import @@ -567,15 +568,6 @@ int ToTouchID(UITouch *uiTouch, bool allowAllocate) { } } -- (void)controllerButtonPressed:(BOOL)pressed keyCode:(InputKeyCode)keyCode -{ - KeyInput key; - key.deviceId = DEVICE_ID_PAD_0; - key.flags = pressed ? KEY_DOWN : KEY_UP; - key.keyCode = keyCode; - NativeKey(key); -} - // Enables tapping for edge area. -(UIRectEdge)preferredScreenEdgesDeferringSystemGestures { @@ -589,139 +581,10 @@ int ToTouchID(UITouch *uiTouch, bool allowAllocate) { - (void)setupController:(GCController *)controller { self.gameController = controller; - - GCGamepad *baseProfile = self.gameController.gamepad; - if (baseProfile == nil) { + if (!SetupController(controller)) { self.gameController = nil; - return; } - - self.gameController.controllerPausedHandler = ^(GCController *controller) { - KeyInput key; - key.flags = KEY_DOWN; - key.keyCode = NKCODE_ESCAPE; - key.deviceId = DEVICE_ID_KEYBOARD; - NativeKey(key); - }; - - baseProfile.buttonA.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_2]; // Cross - }; - - baseProfile.buttonB.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_3]; // Circle - }; - - baseProfile.buttonX.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_4]; // Square - }; - - baseProfile.buttonY.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_1]; // Triangle - }; - - baseProfile.leftShoulder.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_7]; // LTrigger - }; - - baseProfile.rightShoulder.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_8]; // RTrigger - }; - - baseProfile.dpad.up.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_DPAD_UP]; - }; - - baseProfile.dpad.down.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_DPAD_DOWN]; - }; - - baseProfile.dpad.left.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_DPAD_LEFT]; - }; - - baseProfile.dpad.right.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_DPAD_RIGHT]; - }; - - GCExtendedGamepad *extendedProfile = self.gameController.extendedGamepad; - if (extendedProfile == nil) - return; // controller doesn't support extendedGamepad profile - - extendedProfile.leftTrigger.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_9]; // Select - }; - - extendedProfile.rightTrigger.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_10]; // Start - }; - -#if defined(__IPHONE_12_1) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_12_1 - if ([extendedProfile respondsToSelector:@selector(leftThumbstickButton)] && extendedProfile.leftThumbstickButton != nil) { - extendedProfile.leftThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_11]; - }; - } - if ([extendedProfile respondsToSelector:@selector(rightThumbstickButton)] && extendedProfile.rightThumbstickButton != nil) { - extendedProfile.rightThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_12]; - }; - } -#endif -#if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0 - if ([extendedProfile respondsToSelector:@selector(buttonOptions)] && extendedProfile.buttonOptions != nil) { - extendedProfile.buttonOptions.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_13]; - }; - } - if ([extendedProfile respondsToSelector:@selector(buttonMenu)] && extendedProfile.buttonMenu != nil) { - extendedProfile.buttonMenu.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_14]; - }; - } -#endif -#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0 - if ([extendedProfile respondsToSelector:@selector(buttonHome)] && extendedProfile.buttonHome != nil) { - extendedProfile.buttonHome.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { - [self controllerButtonPressed:pressed keyCode:NKCODE_BUTTON_15]; - }; - } -#endif - - extendedProfile.leftThumbstick.xAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) { - AxisInput axisInput; - axisInput.deviceId = DEVICE_ID_PAD_0; - axisInput.axisId = JOYSTICK_AXIS_X; - axisInput.value = value; - NativeAxis(&axisInput, 1); - }; - - extendedProfile.leftThumbstick.yAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) { - AxisInput axisInput; - axisInput.deviceId = DEVICE_ID_PAD_0; - axisInput.axisId = JOYSTICK_AXIS_Y; - axisInput.value = -value; - NativeAxis(&axisInput, 1); - }; - - // Map right thumbstick as another analog stick, particularly useful for controllers like the DualShock 3/4 when connected to an iOS device - extendedProfile.rightThumbstick.xAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) { - AxisInput axisInput; - axisInput.deviceId = DEVICE_ID_PAD_0; - axisInput.axisId = JOYSTICK_AXIS_Z; - axisInput.value = value; - NativeAxis(&axisInput, 1); - }; - - extendedProfile.rightThumbstick.yAxis.valueChangedHandler = ^(GCControllerAxisInput *axis, float value) { - AxisInput axisInput; - axisInput.deviceId = DEVICE_ID_PAD_0; - axisInput.axisId = JOYSTICK_AXIS_RZ; - axisInput.value = -value; - NativeAxis(&axisInput, 1); - }; } -#endif void setCameraSize(int width, int height) { [cameraHelper setCameraSize: width h:height]; From 75af8c670419d6e10adfda6b20dee98d769aa32a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 May 2024 11:24:00 +0200 Subject: [PATCH 06/10] Some C++-ification --- ios/ViewController.mm | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/ios/ViewController.mm b/ios/ViewController.mm index bbf072100e..6caa2832e6 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -330,8 +330,7 @@ extern float g_safeInsetBottom; graphicsContext->ThreadFrame(); } -- (void)touchX:(float)x y:(float)y code:(int)code pointerId:(int)pointerId -{ +static void SendTouchEvent(float x, float y, int code, int pointerId) { float scale = [UIScreen mainScreen].scale; if ([[UIScreen mainScreen] respondsToSelector:@selector(nativeScale)]) { scale = [UIScreen mainScreen].nativeScale; @@ -344,17 +343,9 @@ extern float g_safeInsetBottom; input.x = scaledX; input.y = scaledY; switch (code) { - case 1 : - input.flags = TOUCH_DOWN; - break; - - case 2 : - input.flags = TOUCH_UP; - break; - - default : - input.flags = TOUCH_MOVE; - break; + case 1: input.flags = TOUCH_DOWN; break; + case 2: input.flags = TOUCH_UP; break; + default: input.flags = TOUCH_MOVE; break; } input.id = pointerId; NativeTouch(input); @@ -384,35 +375,31 @@ int ToTouchID(UITouch *uiTouch, bool allowAllocate) { return -1; } - - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - for(UITouch* touch in touches) - { + for (UITouch* touch in touches) { CGPoint point = [touch locationInView:self.view]; int touchId = ToTouchID(touch, true); - [self touchX:point.x y:point.y code:1 pointerId:touchId]; + SendTouchEvent(point.x, point.y, 1, touchId); } } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - for(UITouch* touch in touches) - { + for (UITouch* touch in touches) { CGPoint point = [touch locationInView:self.view]; int touchId = ToTouchID(touch, true); - [self touchX:point.x y:point.y code:0 pointerId: touchId]; + SendTouchEvent(point.x, point.y, 0, touchId); } } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - for(UITouch* touch in touches) - { + for (UITouch* touch in touches) { CGPoint point = [touch locationInView:self.view]; int touchId = ToTouchID(touch, false); if (touchId >= 0) { - [self touchX:point.x y:point.y code:2 pointerId: touchId]; + SendTouchEvent(point.x, point.y, 2, touchId); g_touches[touchId] = nullptr; } } @@ -420,12 +407,11 @@ int ToTouchID(UITouch *uiTouch, bool allowAllocate) { - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { - for(UITouch* touch in touches) - { + for (UITouch* touch in touches) { CGPoint point = [touch locationInView:self.view]; int touchId = ToTouchID(touch, false); if (touchId >= 0) { - [self touchX:point.x y:point.y code:2 pointerId: touchId]; + SendTouchEvent(point.x, point.y, 2, touchId); g_touches[touchId] = nullptr; } } From 1db11599b4339725a9d921618425dd0c0f50d86c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 May 2024 11:36:52 +0200 Subject: [PATCH 07/10] Move some more code --- ios/Controls.h | 3 ++- ios/Controls.mm | 26 ++++++++++++++++++++++++++ ios/ViewController.mm | 40 ++++++++-------------------------------- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/ios/Controls.h b/ios/Controls.h index ce89fae303..ac641a7ad3 100644 --- a/ios/Controls.h +++ b/ios/Controls.h @@ -5,4 +5,5 @@ // Code extracted from ViewController.mm, in order to modularize // and share it between multiple view controllers. -bool SetupController(GCController *controller); \ No newline at end of file +bool SetupController(GCController *controller); +void SendTouchEvent(float x, float y, int code, int pointerId); \ No newline at end of file diff --git a/ios/Controls.mm b/ios/Controls.mm index 346c18e9e9..388564cf4c 100644 --- a/ios/Controls.mm +++ b/ios/Controls.mm @@ -3,6 +3,7 @@ #include "Common/Log.h" #include "Common/Input/InputState.h" #include "Common/System/NativeApp.h" +#include "Common/System/Display.h" static void controllerButtonPressed(BOOL pressed, InputKeyCode keyCode) { KeyInput key; @@ -146,3 +147,28 @@ bool SetupController(GCController *controller) { return true; } + +void SendTouchEvent(float x, float y, int code, int pointerId) { + float scale = [UIScreen mainScreen].scale; + if ([[UIScreen mainScreen] respondsToSelector:@selector(nativeScale)]) { + scale = [UIScreen mainScreen].nativeScale; + } + + float dp_xscale = (float)g_display.dp_xres / (float)g_display.pixel_xres; + float dp_yscale = (float)g_display.dp_yres / (float)g_display.pixel_yres; + + float scaledX = (int)(x * dp_xscale) * scale; + float scaledY = (int)(y * dp_yscale) * scale; + + TouchInput input; + input.x = scaledX; + input.y = scaledY; + switch (code) { + case 1: input.flags = TOUCH_DOWN; break; + case 2: input.flags = TOUCH_UP; break; + default: input.flags = TOUCH_MOVE; break; + } + input.id = pointerId; + NativeTouch(input); +} + diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 6caa2832e6..907576070f 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -88,9 +88,6 @@ private: GLRenderManager *renderManager_; }; -static float dp_xscale = 1.0f; -static float dp_yscale = 1.0f; - static double lastSelectPress = 0.0f; static double lastStartPress = 0.0f; static bool simulateAnalog = false; @@ -214,9 +211,6 @@ extern float g_safeInsetBottom; graphicsContext->ThreadStart(); - dp_xscale = (float)g_display.dp_xres / (float)g_display.pixel_xres; - dp_yscale = (float)g_display.dp_yres / (float)g_display.pixel_yres; - /*self.iCadeView = [[iCadeReaderView alloc] init]; [self.view addSubview:self.iCadeView]; self.iCadeView.delegate = self; @@ -318,7 +312,6 @@ extern float g_safeInsetBottom; [self shutdown]; } -// For iOS 6.0 and up - (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskLandscape; @@ -330,27 +323,6 @@ extern float g_safeInsetBottom; graphicsContext->ThreadFrame(); } -static void SendTouchEvent(float x, float y, int code, int pointerId) { - float scale = [UIScreen mainScreen].scale; - if ([[UIScreen mainScreen] respondsToSelector:@selector(nativeScale)]) { - scale = [UIScreen mainScreen].nativeScale; - } - - float scaledX = (int)(x * dp_xscale) * scale; - float scaledY = (int)(y * dp_yscale) * scale; - - TouchInput input; - input.x = scaledX; - input.y = scaledY; - switch (code) { - case 1: input.flags = TOUCH_DOWN; break; - case 2: input.flags = TOUCH_UP; break; - default: input.flags = TOUCH_MOVE; break; - } - input.id = pointerId; - NativeTouch(input); -} - int ToTouchID(UITouch *uiTouch, bool allowAllocate) { // Find the id for the touch. for (int localId = 0; localId < (int)ARRAY_SIZE(g_touches); ++localId) { @@ -377,8 +349,9 @@ int ToTouchID(UITouch *uiTouch, bool allowAllocate) { - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + UIView *view = self.view; for (UITouch* touch in touches) { - CGPoint point = [touch locationInView:self.view]; + CGPoint point = [touch locationInView:view]; int touchId = ToTouchID(touch, true); SendTouchEvent(point.x, point.y, 1, touchId); } @@ -386,8 +359,9 @@ int ToTouchID(UITouch *uiTouch, bool allowAllocate) { - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + UIView *view = self.view; for (UITouch* touch in touches) { - CGPoint point = [touch locationInView:self.view]; + CGPoint point = [touch locationInView:view]; int touchId = ToTouchID(touch, true); SendTouchEvent(point.x, point.y, 0, touchId); } @@ -395,8 +369,9 @@ int ToTouchID(UITouch *uiTouch, bool allowAllocate) { - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + UIView *view = self.view; for (UITouch* touch in touches) { - CGPoint point = [touch locationInView:self.view]; + CGPoint point = [touch locationInView:view]; int touchId = ToTouchID(touch, false); if (touchId >= 0) { SendTouchEvent(point.x, point.y, 2, touchId); @@ -407,8 +382,9 @@ int ToTouchID(UITouch *uiTouch, bool allowAllocate) { - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + UIView *view = self.view; for (UITouch* touch in touches) { - CGPoint point = [touch locationInView:self.view]; + CGPoint point = [touch locationInView:view]; int touchId = ToTouchID(touch, false); if (touchId >= 0) { SendTouchEvent(point.x, point.y, 2, touchId); From bf8d55c97004acc84f427b99c118a0d9c7f6f58f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 May 2024 11:59:26 +0200 Subject: [PATCH 08/10] Finish extracting the touch tracker from the ViewController --- ios/Controls.h | 12 ++++++++- ios/Controls.mm | 63 ++++++++++++++++++++++++++++++++++++++++++- ios/ViewController.mm | 62 ++++-------------------------------------- 3 files changed, 78 insertions(+), 59 deletions(-) diff --git a/ios/Controls.h b/ios/Controls.h index ac641a7ad3..7b7b4ee67a 100644 --- a/ios/Controls.h +++ b/ios/Controls.h @@ -6,4 +6,14 @@ // and share it between multiple view controllers. bool SetupController(GCController *controller); -void SendTouchEvent(float x, float y, int code, int pointerId); \ No newline at end of file + +struct TouchTracker { + void Began(NSSet *touches, UIView *view); + void Moved(NSSet *touches, UIView *view); + void Ended(NSSet *touches, UIView *view); + void Cancelled(NSSet *touches, UIView *view); +private: + void SendTouchEvent(float x, float y, int code, int pointerId); + int ToTouchID(UITouch *uiTouch, bool allowAllocate); + UITouch *touches_[10]{}; +}; \ No newline at end of file diff --git a/ios/Controls.mm b/ios/Controls.mm index 388564cf4c..bca399c1eb 100644 --- a/ios/Controls.mm +++ b/ios/Controls.mm @@ -148,7 +148,7 @@ bool SetupController(GCController *controller) { return true; } -void SendTouchEvent(float x, float y, int code, int pointerId) { +void TouchTracker::SendTouchEvent(float x, float y, int code, int pointerId) { float scale = [UIScreen mainScreen].scale; if ([[UIScreen mainScreen] respondsToSelector:@selector(nativeScale)]) { scale = [UIScreen mainScreen].nativeScale; @@ -172,3 +172,64 @@ void SendTouchEvent(float x, float y, int code, int pointerId) { NativeTouch(input); } +int TouchTracker::ToTouchID(UITouch *uiTouch, bool allowAllocate) { + // Find the id for the touch. + for (int localId = 0; localId < (int)ARRAY_SIZE(touches_); ++localId) { + if (touches_[localId] == uiTouch) { + return localId; + } + } + + // Allocate a new one, perhaps? + if (allowAllocate) { + for (int localId = 0; localId < (int)ARRAY_SIZE(touches_); ++localId) { + if (touches_[localId] == 0) { + touches_[localId] = uiTouch; + return localId; + } + } + + // None were free. Ignore? + return 0; + } + + return -1; +} + +void TouchTracker::Began(NSSet *touches, UIView *view) { + for (UITouch* touch in touches) { + CGPoint point = [touch locationInView:view]; + int touchId = ToTouchID(touch, true); + SendTouchEvent(point.x, point.y, 1, touchId); + } +} + +void TouchTracker::Moved(NSSet *touches, UIView *view) { + for (UITouch* touch in touches) { + CGPoint point = [touch locationInView:view]; + int touchId = ToTouchID(touch, true); + SendTouchEvent(point.x, point.y, 0, touchId); + } +} + +void TouchTracker::Ended(NSSet *touches, UIView *view) { + for (UITouch* touch in touches) { + CGPoint point = [touch locationInView:view]; + int touchId = ToTouchID(touch, false); + if (touchId >= 0) { + SendTouchEvent(point.x, point.y, 2, touchId); + touches_[touchId] = nullptr; + } + } +} + +void TouchTracker::Cancelled(NSSet *touches, UIView *view) { + for (UITouch* touch in touches) { + CGPoint point = [touch locationInView:view]; + int touchId = ToTouchID(touch, false); + if (touchId >= 0) { + SendTouchEvent(point.x, point.y, 2, touchId); + touches_[touchId] = nullptr; + } + } +} diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 907576070f..900046f9d1 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -94,7 +94,7 @@ static bool simulateAnalog = false; static bool iCadeConnectNotified = false; static bool threadEnabled = true; static bool threadStopped = false; -static UITouch *g_touches[10]; +static TouchTracker g_touchTracker; id sharedViewController; static GraphicsContext *graphicsContext; @@ -118,8 +118,6 @@ static LocationHelper *locationHelper; self = [super init]; if (self) { sharedViewController = self; - memset(g_touches, 0, sizeof(g_touches)); - iCadeToKeyMap[iCadeJoystickUp] = NKCODE_DPAD_UP; iCadeToKeyMap[iCadeJoystickRight] = NKCODE_DPAD_RIGHT; iCadeToKeyMap[iCadeJoystickDown] = NKCODE_DPAD_DOWN; @@ -323,74 +321,24 @@ extern float g_safeInsetBottom; graphicsContext->ThreadFrame(); } -int ToTouchID(UITouch *uiTouch, bool allowAllocate) { - // Find the id for the touch. - for (int localId = 0; localId < (int)ARRAY_SIZE(g_touches); ++localId) { - if (g_touches[localId] == uiTouch) { - return localId; - } - } - - // Allocate a new one, perhaps? - if (allowAllocate) { - for (int localId = 0; localId < (int)ARRAY_SIZE(g_touches); ++localId) { - if (g_touches[localId] == 0) { - g_touches[localId] = uiTouch; - return localId; - } - } - - // None were free. Ignore? - return 0; - } - - return -1; -} - - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - UIView *view = self.view; - for (UITouch* touch in touches) { - CGPoint point = [touch locationInView:view]; - int touchId = ToTouchID(touch, true); - SendTouchEvent(point.x, point.y, 1, touchId); - } + g_touchTracker.Began(touches, self.view); } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - UIView *view = self.view; - for (UITouch* touch in touches) { - CGPoint point = [touch locationInView:view]; - int touchId = ToTouchID(touch, true); - SendTouchEvent(point.x, point.y, 0, touchId); - } + g_touchTracker.Moved(touches, self.view); } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - UIView *view = self.view; - for (UITouch* touch in touches) { - CGPoint point = [touch locationInView:view]; - int touchId = ToTouchID(touch, false); - if (touchId >= 0) { - SendTouchEvent(point.x, point.y, 2, touchId); - g_touches[touchId] = nullptr; - } - } + g_touchTracker.Ended(touches, self.view); } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { - UIView *view = self.view; - for (UITouch* touch in touches) { - CGPoint point = [touch locationInView:view]; - int touchId = ToTouchID(touch, false); - if (touchId >= 0) { - SendTouchEvent(point.x, point.y, 2, touchId); - g_touches[touchId] = nullptr; - } - } + g_touchTracker.Cancelled(touches, self.view); } - (void)bindDefaultFBO From 98e87a78d8e8cd3757a3a6f3a3510331cf7189bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 May 2024 12:11:51 +0200 Subject: [PATCH 09/10] Extract the iCade code to Controls.mm --- ios/Controls.h | 23 +++++++- ios/Controls.mm | 127 ++++++++++++++++++++++++++++++++++++++++++ ios/ViewController.mm | 127 ++---------------------------------------- 3 files changed, 154 insertions(+), 123 deletions(-) diff --git a/ios/Controls.h b/ios/Controls.h index 7b7b4ee67a..cf4112f9d2 100644 --- a/ios/Controls.h +++ b/ios/Controls.h @@ -1,6 +1,10 @@ #pragma once +#include + #import +#include "iCade/iCadeState.h" +#include "Common/Input/InputState.h" // Code extracted from ViewController.mm, in order to modularize // and share it between multiple view controllers. @@ -8,6 +12,7 @@ bool SetupController(GCController *controller); struct TouchTracker { +public: void Began(NSSet *touches, UIView *view); void Moved(NSSet *touches, UIView *view); void Ended(NSSet *touches, UIView *view); @@ -16,4 +21,20 @@ private: void SendTouchEvent(float x, float y, int code, int pointerId); int ToTouchID(UITouch *uiTouch, bool allowAllocate); UITouch *touches_[10]{}; -}; \ No newline at end of file +}; + +// Can probably get rid of this, but let's keep it for now. +struct ICadeTracker { +public: + void ButtonDown(iCadeState button); + void ButtonUp(iCadeState button); + void InitKeyMap(); +private: + bool simulateAnalog = false; + bool iCadeConnectNotified = false; + + std::map iCadeToKeyMap; + + double lastSelectPress = 0.0f; + double lastStartPress = 0.0f; +}; diff --git a/ios/Controls.mm b/ios/Controls.mm index bca399c1eb..28ff43bf86 100644 --- a/ios/Controls.mm +++ b/ios/Controls.mm @@ -1,9 +1,11 @@ #include "Controls.h" #include "Common/Log.h" +#include "Common/TimeUtil.h" #include "Common/Input/InputState.h" #include "Common/System/NativeApp.h" #include "Common/System/Display.h" +#include "Core/KeyMap.h" static void controllerButtonPressed(BOOL pressed, InputKeyCode keyCode) { KeyInput key; @@ -233,3 +235,128 @@ void TouchTracker::Cancelled(NSSet *touches, UIView *view) { } } } + +void ICadeTracker::InitKeyMap() { + iCadeToKeyMap[iCadeJoystickUp] = NKCODE_DPAD_UP; + iCadeToKeyMap[iCadeJoystickRight] = NKCODE_DPAD_RIGHT; + iCadeToKeyMap[iCadeJoystickDown] = NKCODE_DPAD_DOWN; + iCadeToKeyMap[iCadeJoystickLeft] = NKCODE_DPAD_LEFT; + iCadeToKeyMap[iCadeButtonA] = NKCODE_BUTTON_9; // Select + iCadeToKeyMap[iCadeButtonB] = NKCODE_BUTTON_7; // LTrigger + iCadeToKeyMap[iCadeButtonC] = NKCODE_BUTTON_10; // Start + iCadeToKeyMap[iCadeButtonD] = NKCODE_BUTTON_8; // RTrigger + iCadeToKeyMap[iCadeButtonE] = NKCODE_BUTTON_4; // Square + iCadeToKeyMap[iCadeButtonF] = NKCODE_BUTTON_2; // Cross + iCadeToKeyMap[iCadeButtonG] = NKCODE_BUTTON_1; // Triangle + iCadeToKeyMap[iCadeButtonH] = NKCODE_BUTTON_3; // Circle +} + +void ICadeTracker::ButtonDown(iCadeState button) { + if (simulateAnalog && + ((button == iCadeJoystickUp) || + (button == iCadeJoystickDown) || + (button == iCadeJoystickLeft) || + (button == iCadeJoystickRight))) { + AxisInput axis; + switch (button) { + case iCadeJoystickUp : + axis.axisId = JOYSTICK_AXIS_Y; + axis.value = -1.0f; + break; + + case iCadeJoystickDown : + axis.axisId = JOYSTICK_AXIS_Y; + axis.value = 1.0f; + break; + + case iCadeJoystickLeft : + axis.axisId = JOYSTICK_AXIS_X; + axis.value = -1.0f; + break; + + case iCadeJoystickRight : + axis.axisId = JOYSTICK_AXIS_X; + axis.value = 1.0f; + break; + + default: + break; + } + axis.deviceId = DEVICE_ID_PAD_0; + NativeAxis(&axis, 1); + } else { + KeyInput key; + key.flags = KEY_DOWN; + key.keyCode = iCadeToKeyMap[button]; + key.deviceId = DEVICE_ID_PAD_0; + NativeKey(key); + } +} + +void ICadeTracker::ButtonUp(iCadeState button) { + if (!iCadeConnectNotified) { + iCadeConnectNotified = true; + KeyMap::NotifyPadConnected(DEVICE_ID_PAD_0, "iCade"); + } + + if (button == iCadeButtonA) { + // Pressing Select twice within 1 second toggles the DPad between + // normal operation and simulating the Analog stick. + if ((lastSelectPress + 1.0f) > time_now_d()) + simulateAnalog = !simulateAnalog; + lastSelectPress = time_now_d(); + } + + if (button == iCadeButtonC) { + // Pressing Start twice within 1 second will take to the Emu menu + if ((lastStartPress + 1.0f) > time_now_d()) { + KeyInput key; + key.flags = KEY_DOWN; + key.keyCode = NKCODE_ESCAPE; + key.deviceId = DEVICE_ID_KEYBOARD; + NativeKey(key); + return; + } + lastStartPress = time_now_d(); + } + + if (simulateAnalog && + ((button == iCadeJoystickUp) || + (button == iCadeJoystickDown) || + (button == iCadeJoystickLeft) || + (button == iCadeJoystickRight))) { + AxisInput axis; + switch (button) { + case iCadeJoystickUp : + axis.axisId = JOYSTICK_AXIS_Y; + axis.value = 0.0f; + break; + + case iCadeJoystickDown : + axis.axisId = JOYSTICK_AXIS_Y; + axis.value = 0.0f; + break; + + case iCadeJoystickLeft : + axis.axisId = JOYSTICK_AXIS_X; + axis.value = 0.0f; + break; + + case iCadeJoystickRight : + axis.axisId = JOYSTICK_AXIS_X; + axis.value = 0.0f; + break; + + default: + break; + } + axis.deviceId = DEVICE_ID_PAD_0; + NativeAxis(&axis, 1); + } else { + KeyInput key; + key.flags = KEY_UP; + key.keyCode = iCadeToKeyMap[button]; + key.deviceId = DEVICE_ID_PAD_0; + NativeKey(key); + } +} \ No newline at end of file diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 900046f9d1..5d66732ddd 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -88,13 +88,8 @@ private: GLRenderManager *renderManager_; }; -static double lastSelectPress = 0.0f; -static double lastStartPress = 0.0f; -static bool simulateAnalog = false; -static bool iCadeConnectNotified = false; static bool threadEnabled = true; static bool threadStopped = false; -static TouchTracker g_touchTracker; id sharedViewController; static GraphicsContext *graphicsContext; @@ -102,7 +97,8 @@ static CameraHelper *cameraHelper; static LocationHelper *locationHelper; @interface PPSSPPViewControllerGL () { - std::map iCadeToKeyMap; + ICadeTracker g_iCadeTracker; + TouchTracker g_touchTracker; } @property (nonatomic, strong) EAGLContext* context; @@ -118,18 +114,7 @@ static LocationHelper *locationHelper; self = [super init]; if (self) { sharedViewController = self; - iCadeToKeyMap[iCadeJoystickUp] = NKCODE_DPAD_UP; - iCadeToKeyMap[iCadeJoystickRight] = NKCODE_DPAD_RIGHT; - iCadeToKeyMap[iCadeJoystickDown] = NKCODE_DPAD_DOWN; - iCadeToKeyMap[iCadeJoystickLeft] = NKCODE_DPAD_LEFT; - iCadeToKeyMap[iCadeButtonA] = NKCODE_BUTTON_9; // Select - iCadeToKeyMap[iCadeButtonB] = NKCODE_BUTTON_7; // LTrigger - iCadeToKeyMap[iCadeButtonC] = NKCODE_BUTTON_10; // Start - iCadeToKeyMap[iCadeButtonD] = NKCODE_BUTTON_8; // RTrigger - iCadeToKeyMap[iCadeButtonE] = NKCODE_BUTTON_4; // Square - iCadeToKeyMap[iCadeButtonF] = NKCODE_BUTTON_2; // Cross - iCadeToKeyMap[iCadeButtonG] = NKCODE_BUTTON_1; // Triangle - iCadeToKeyMap[iCadeButtonH] = NKCODE_BUTTON_3; // Circle + g_iCadeTracker.InitKeyMap(); [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillTerminate:) name:UIApplicationWillTerminateNotification object:nil]; @@ -348,114 +333,12 @@ extern float g_safeInsetBottom; - (void)buttonDown:(iCadeState)button { - if (simulateAnalog && - ((button == iCadeJoystickUp) || - (button == iCadeJoystickDown) || - (button == iCadeJoystickLeft) || - (button == iCadeJoystickRight))) { - AxisInput axis; - switch (button) { - case iCadeJoystickUp : - axis.axisId = JOYSTICK_AXIS_Y; - axis.value = -1.0f; - break; - - case iCadeJoystickDown : - axis.axisId = JOYSTICK_AXIS_Y; - axis.value = 1.0f; - break; - - case iCadeJoystickLeft : - axis.axisId = JOYSTICK_AXIS_X; - axis.value = -1.0f; - break; - - case iCadeJoystickRight : - axis.axisId = JOYSTICK_AXIS_X; - axis.value = 1.0f; - break; - - default: - break; - } - axis.deviceId = DEVICE_ID_PAD_0; - NativeAxis(&axis, 1); - } else { - KeyInput key; - key.flags = KEY_DOWN; - key.keyCode = iCadeToKeyMap[button]; - key.deviceId = DEVICE_ID_PAD_0; - NativeKey(key); - } + g_iCadeTracker.ButtonDown(button); } - (void)buttonUp:(iCadeState)button { - if (!iCadeConnectNotified) { - iCadeConnectNotified = true; - KeyMap::NotifyPadConnected(DEVICE_ID_PAD_0, "iCade"); - } - - if (button == iCadeButtonA) { - // Pressing Select twice within 1 second toggles the DPad between - // normal operation and simulating the Analog stick. - if ((lastSelectPress + 1.0f) > time_now_d()) - simulateAnalog = !simulateAnalog; - lastSelectPress = time_now_d(); - } - - if (button == iCadeButtonC) { - // Pressing Start twice within 1 second will take to the Emu menu - if ((lastStartPress + 1.0f) > time_now_d()) { - KeyInput key; - key.flags = KEY_DOWN; - key.keyCode = NKCODE_ESCAPE; - key.deviceId = DEVICE_ID_KEYBOARD; - NativeKey(key); - return; - } - lastStartPress = time_now_d(); - } - - if (simulateAnalog && - ((button == iCadeJoystickUp) || - (button == iCadeJoystickDown) || - (button == iCadeJoystickLeft) || - (button == iCadeJoystickRight))) { - AxisInput axis; - switch (button) { - case iCadeJoystickUp : - axis.axisId = JOYSTICK_AXIS_Y; - axis.value = 0.0f; - break; - - case iCadeJoystickDown : - axis.axisId = JOYSTICK_AXIS_Y; - axis.value = 0.0f; - break; - - case iCadeJoystickLeft : - axis.axisId = JOYSTICK_AXIS_X; - axis.value = 0.0f; - break; - - case iCadeJoystickRight : - axis.axisId = JOYSTICK_AXIS_X; - axis.value = 0.0f; - break; - - default: - break; - } - axis.deviceId = DEVICE_ID_PAD_0; - NativeAxis(&axis, 1); - } else { - KeyInput key; - key.flags = KEY_UP; - key.keyCode = iCadeToKeyMap[button]; - key.deviceId = DEVICE_ID_PAD_0; - NativeKey(key); - } + g_iCadeTracker.ButtonUp(button); } - (void)controllerDidConnect:(NSNotification *)note From 016e90f7a4bfbf3a8ee2671e70b70b49737c59b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 May 2024 13:34:17 +0200 Subject: [PATCH 10/10] Buildfix, cleanup use of long-deprecated stuff. --- ios/Controls.mm | 30 +++++++++++++----------------- ios/ViewController.mm | 5 ++++- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/ios/Controls.mm b/ios/Controls.mm index 28ff43bf86..2807d9ea31 100644 --- a/ios/Controls.mm +++ b/ios/Controls.mm @@ -16,8 +16,8 @@ static void controllerButtonPressed(BOOL pressed, InputKeyCode keyCode) { } bool SetupController(GCController *controller) { - GCGamepad *baseProfile = controller.gamepad; - if (baseProfile == nil) { + GCExtendedGamepad *extendedProfile = controller.extendedGamepad; + if (extendedProfile == nil) { return false; } @@ -29,50 +29,46 @@ bool SetupController(GCController *controller) { NativeKey(key); }; - baseProfile.buttonA.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + extendedProfile.buttonA.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { controllerButtonPressed(pressed, NKCODE_BUTTON_2); // Cross }; - baseProfile.buttonB.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + extendedProfile.buttonB.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { controllerButtonPressed(pressed, NKCODE_BUTTON_3); // Circle }; - baseProfile.buttonX.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + extendedProfile.buttonX.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { controllerButtonPressed(pressed, NKCODE_BUTTON_4); // Square }; - baseProfile.buttonY.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + extendedProfile.buttonY.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { controllerButtonPressed(pressed, NKCODE_BUTTON_1); // Triangle }; - baseProfile.leftShoulder.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + extendedProfile.leftShoulder.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { controllerButtonPressed(pressed, NKCODE_BUTTON_7); // LTrigger }; - baseProfile.rightShoulder.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + extendedProfile.rightShoulder.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { controllerButtonPressed(pressed, NKCODE_BUTTON_8); // RTrigger }; - baseProfile.dpad.up.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + extendedProfile.dpad.up.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { controllerButtonPressed(pressed, NKCODE_DPAD_UP); }; - baseProfile.dpad.down.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + extendedProfile.dpad.down.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { controllerButtonPressed(pressed, NKCODE_DPAD_DOWN); }; - baseProfile.dpad.left.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + extendedProfile.dpad.left.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { controllerButtonPressed(pressed, NKCODE_DPAD_LEFT); }; - baseProfile.dpad.right.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + extendedProfile.dpad.right.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { controllerButtonPressed(pressed, NKCODE_DPAD_RIGHT); }; - GCExtendedGamepad *extendedProfile = controller.extendedGamepad; - if (extendedProfile == nil) - return; // controller doesn't support extendedGamepad profile - extendedProfile.leftTrigger.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { controllerButtonPressed(pressed, NKCODE_BUTTON_9); // Select }; @@ -359,4 +355,4 @@ void ICadeTracker::ButtonUp(iCadeState button) { key.deviceId = DEVICE_ID_PAD_0; NativeKey(key); } -} \ No newline at end of file +} diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 5d66732ddd..169cc32de9 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -92,13 +92,16 @@ static bool threadEnabled = true; static bool threadStopped = false; id sharedViewController; -static GraphicsContext *graphicsContext; + +// TODO: Reach these through sharedViewController static CameraHelper *cameraHelper; static LocationHelper *locationHelper; @interface PPSSPPViewControllerGL () { ICadeTracker g_iCadeTracker; TouchTracker g_touchTracker; + + GraphicsContext *graphicsContext; } @property (nonatomic, strong) EAGLContext* context;