mirror of
https://github.com/CTCaer/RetroArch.git
synced 2024-12-23 19:24:46 +00:00
(Apple) Split platform specific code out of main.m
This commit is contained in:
parent
7236e51af0
commit
4f70bdeab5
42
apple/OSX/platform.h
Normal file
42
apple/OSX/platform.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2013 - Jason Fetters
|
||||
* Copyright (C) 2011-2013 - Daniel De Matteis
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __RARCH_OSX_PLATFORM_H
|
||||
#define __RARCH_OSX_PLATFORM_H
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
@interface RAGameView : NSOpenGLView
|
||||
|
||||
+ (RAGameView*)get;
|
||||
- (void)display;
|
||||
|
||||
@end
|
||||
|
||||
@interface RetroArch_OSX : NSObject<RetroArch_Platform, NSApplicationDelegate>
|
||||
{
|
||||
@public
|
||||
NSWindow IBOutlet *window;
|
||||
}
|
||||
|
||||
+ (RetroArch_OSX*)get;
|
||||
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
|
||||
- (void)unloadingCore:(RAModuleInfo*)core;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
264
apple/OSX/platform.m
Normal file
264
apple/OSX/platform.m
Normal file
@ -0,0 +1,264 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2013 - Jason Fetters
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
|
||||
#import "RetroArch_Apple.h"
|
||||
#include "rarch_wrapper.h"
|
||||
#include "../RetroArch/apple_input.h"
|
||||
|
||||
// If USE_XATTR is defined any loaded file will get a com.RetroArch.Core extended attribute
|
||||
// specifying which core was used to load.
|
||||
//#define USE_XATTR
|
||||
|
||||
#if defined(USE_XATTR)
|
||||
#include "sys/xattr.h"
|
||||
#endif
|
||||
|
||||
#include "file.h"
|
||||
|
||||
@interface RApplication : NSApplication
|
||||
@end
|
||||
|
||||
@implementation RApplication
|
||||
|
||||
- (void)sendEvent:(NSEvent *)event
|
||||
{
|
||||
[super sendEvent:event];
|
||||
|
||||
if (event.type == GSEVENT_TYPE_KEYDOWN || event.type == GSEVENT_TYPE_KEYUP)
|
||||
apple_input_handle_key_event(event.keyCode, event.type == GSEVENT_TYPE_KEYDOWN);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RetroArch_OSX
|
||||
{
|
||||
NSWindow IBOutlet* _coreSelectSheet;
|
||||
|
||||
bool _isTerminating;
|
||||
bool _loaded;
|
||||
bool _wantReload;
|
||||
NSString* _file;
|
||||
RAModuleInfo* _core;
|
||||
}
|
||||
|
||||
+ (RetroArch_OSX*)get
|
||||
{
|
||||
return (RetroArch_OSX*)[[NSApplication sharedApplication] delegate];
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||
{
|
||||
apple_platform = self;
|
||||
_loaded = true;
|
||||
|
||||
[window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
|
||||
|
||||
RAGameView.get.frame = [window.contentView bounds];
|
||||
[window.contentView setAutoresizesSubviews:YES];
|
||||
[window.contentView addSubview:RAGameView.get];
|
||||
[window makeFirstResponder:RAGameView.get];
|
||||
|
||||
// Create core select list
|
||||
NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1];
|
||||
|
||||
for (RAModuleInfo* i in RAModuleInfo.getModules)
|
||||
[cb addItemWithObjectValue:i];
|
||||
|
||||
if (cb.numberOfItems)
|
||||
[cb selectItemAtIndex:0];
|
||||
else
|
||||
apple_display_alert(@"No libretro cores were found.", @"RetroArch");
|
||||
|
||||
// Run RGUI if needed
|
||||
if (!_wantReload)
|
||||
apple_run_core(nil, 0);
|
||||
else
|
||||
[self chooseCore];
|
||||
|
||||
_wantReload = false;
|
||||
|
||||
extern void osx_pad_init();
|
||||
osx_pad_init();
|
||||
}
|
||||
|
||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||
{
|
||||
_isTerminating = true;
|
||||
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(apple_event_basic_command, (void*)QUIT);
|
||||
|
||||
return apple_is_running ? NSTerminateCancel : NSTerminateNow;
|
||||
}
|
||||
|
||||
|
||||
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
|
||||
{
|
||||
if (filenames.count == 1 && filenames[0])
|
||||
{
|
||||
_file = filenames[0];
|
||||
|
||||
if (!_loaded)
|
||||
_wantReload = true;
|
||||
else
|
||||
[self chooseCore];
|
||||
|
||||
[sender replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
|
||||
}
|
||||
else
|
||||
{
|
||||
apple_display_alert(@"Cannot open multiple files", @"RetroArch");
|
||||
[sender replyToOpenOrPrint:NSApplicationDelegateReplyFailure];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)openDocument:(id)sender
|
||||
{
|
||||
NSOpenPanel* panel = [NSOpenPanel openPanel];
|
||||
[panel beginSheetModalForWindow:window completionHandler:^(NSInteger result)
|
||||
{
|
||||
[NSApplication.sharedApplication stopModal];
|
||||
|
||||
if (result == NSOKButton && panel.URL)
|
||||
{
|
||||
_file = panel.URL.path;
|
||||
[self performSelector:@selector(chooseCore) withObject:nil afterDelay:.5f];
|
||||
}
|
||||
}];
|
||||
[NSApplication.sharedApplication runModalForWindow:panel];
|
||||
}
|
||||
|
||||
// This utility function will queue the _core and _file instance values for running.
|
||||
// If the emulator thread is already running it will tell it to quit.
|
||||
- (void)runCore
|
||||
{
|
||||
_wantReload = apple_is_running;
|
||||
|
||||
if (!apple_is_running)
|
||||
apple_run_core(_core, _file.UTF8String);
|
||||
else
|
||||
apple_frontend_post_event(apple_event_basic_command, (void*)QUIT);
|
||||
}
|
||||
|
||||
- (void)chooseCore
|
||||
{
|
||||
#ifdef USE_XATTR
|
||||
char stored_name[PATH_MAX];
|
||||
if (getxattr(_file.UTF8String, "com.RetroArch.Core", stored_name, PATH_MAX, 0, 0) > 0)
|
||||
{
|
||||
for (RAModuleInfo* i in RAModuleInfo.getModules)
|
||||
{
|
||||
const char* core_name = i.path.lastPathComponent.UTF8String;
|
||||
if (strcmp(core_name, stored_name) == 0)
|
||||
{
|
||||
_core = i;
|
||||
[self runCore];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[NSApplication.sharedApplication beginSheet:_coreSelectSheet modalForWindow:window modalDelegate:nil didEndSelector:nil contextInfo:nil];
|
||||
[NSApplication.sharedApplication runModalForWindow:_coreSelectSheet];
|
||||
}
|
||||
|
||||
- (IBAction)coreWasChosen:(id)sender
|
||||
{
|
||||
[NSApplication.sharedApplication stopModal];
|
||||
[NSApplication.sharedApplication endSheet:_coreSelectSheet returnCode:0];
|
||||
[_coreSelectSheet orderOut:self];
|
||||
|
||||
if (_isTerminating)
|
||||
return;
|
||||
|
||||
NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1];
|
||||
_core = (RAModuleInfo*)cb.objectValueOfSelectedItem;
|
||||
|
||||
[self runCore];
|
||||
}
|
||||
|
||||
#pragma mark RetroArch_Platform
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file
|
||||
{
|
||||
if (file)
|
||||
{
|
||||
[NSDocumentController.sharedDocumentController noteNewRecentDocumentURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:file]]];
|
||||
|
||||
#ifdef USE_XATTR
|
||||
const char* core_name = core.path.lastPathComponent.UTF8String;
|
||||
setxattr(file, "com.RetroArch.Core", core_name, strlen(core_name) + 1, 0, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unloadingCore:(RAModuleInfo*)core
|
||||
{
|
||||
if (_isTerminating)
|
||||
[NSApplication.sharedApplication terminate:nil];
|
||||
|
||||
if (_wantReload)
|
||||
apple_run_core(_core, _file.UTF8String);
|
||||
else if(apple_use_tv_mode)
|
||||
apple_run_core(nil, 0);
|
||||
else
|
||||
[NSApplication.sharedApplication terminate:nil];
|
||||
|
||||
_wantReload = false;
|
||||
}
|
||||
|
||||
- (NSString*)retroarchConfigPath
|
||||
{
|
||||
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||
return [paths[0] stringByAppendingPathComponent:@"RetroArch/retroarch.cfg"];
|
||||
}
|
||||
|
||||
- (NSString*)corePath
|
||||
{
|
||||
return [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"Contents/Resources/modules"];
|
||||
}
|
||||
|
||||
#pragma mark Menus
|
||||
- (IBAction)showPreferences:(id)sender
|
||||
{
|
||||
[[[NSWindowController alloc] initWithWindowNibName:@"Settings"] window];
|
||||
}
|
||||
|
||||
- (IBAction)basicEvent:(id)sender
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(&apple_event_basic_command, (void*)((NSMenuItem*)sender).tag);
|
||||
}
|
||||
|
||||
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
|
||||
{
|
||||
[NSApplication.sharedApplication stopModal];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return NSApplicationMain(argc, (const char **) argv);
|
||||
}
|
||||
|
@ -21,7 +21,8 @@
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
#import "RAModuleInfo.h"
|
||||
|
||||
void apple_run_core(RAModuleInfo* core, const char* file);
|
||||
#define GSEVENT_TYPE_KEYDOWN 10
|
||||
#define GSEVENT_TYPE_KEYUP 11
|
||||
|
||||
@protocol RetroArch_Platform
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
|
||||
@ -30,59 +31,29 @@ void apple_run_core(RAModuleInfo* core, const char* file);
|
||||
- (NSString*)corePath;
|
||||
@end
|
||||
|
||||
#ifdef IOS
|
||||
#import "../iOS/platform.h"
|
||||
#elif defined(OSX)
|
||||
#import "../OSX/platform.h"
|
||||
#endif
|
||||
|
||||
extern bool apple_is_paused;
|
||||
extern bool apple_is_running;
|
||||
extern bool apple_use_tv_mode;
|
||||
extern RAModuleInfo* apple_core;
|
||||
|
||||
extern id<RetroArch_Platform> apple_platform;
|
||||
|
||||
#ifdef IOS
|
||||
// main.m
|
||||
enum basic_event_t { RESET = 1, LOAD_STATE = 2, SAVE_STATE = 3, QUIT = 4 };
|
||||
extern void apple_event_basic_command(void* userdata);
|
||||
extern void apple_event_set_state_slot(void* userdata);
|
||||
extern void apple_event_show_rgui(void* userdata);
|
||||
|
||||
// RAGameView.m
|
||||
@interface RAGameView : UIViewController
|
||||
+ (RAGameView*)get;
|
||||
- (void)openPauseMenu;
|
||||
- (void)closePauseMenu;
|
||||
@end
|
||||
|
||||
@interface RetroArch_iOS : UINavigationController<UIApplicationDelegate, UINavigationControllerDelegate, RetroArch_Platform>
|
||||
|
||||
+ (RetroArch_iOS*)get;
|
||||
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
|
||||
- (void)unloadingCore:(RAModuleInfo*)core;
|
||||
- (NSString*)retroarchConfigPath;
|
||||
|
||||
- (void)refreshConfig;
|
||||
- (void)refreshSystemConfig;
|
||||
|
||||
@property (strong, nonatomic) NSString* documentsDirectory; // e.g. /var/mobile/Documents
|
||||
@property (strong, nonatomic) NSString* systemDirectory; // e.g. /var/mobile/Documents/.RetroArch
|
||||
@property (strong, nonatomic) NSString* systemConfigPath; // e.g. /var/mobile/Documents/.RetroArch/frontend.cfg
|
||||
|
||||
@end
|
||||
|
||||
#elif defined(OSX)
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
@interface RAGameView : NSOpenGLView
|
||||
|
||||
+ (RAGameView*)get;
|
||||
- (void)display;
|
||||
|
||||
@end
|
||||
|
||||
@interface RetroArch_OSX : NSObject<RetroArch_Platform, NSApplicationDelegate>
|
||||
{
|
||||
@public
|
||||
NSWindow IBOutlet *window;
|
||||
}
|
||||
|
||||
+ (RetroArch_OSX*)get;
|
||||
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
|
||||
- (void)unloadingCore:(RAModuleInfo*)core;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
extern void apple_refresh_config();
|
||||
extern void apple_enter_stasis();
|
||||
extern void apple_exit_stasis();
|
||||
extern void apple_run_core(RAModuleInfo* core, const char* file);
|
||||
|
||||
// utility.m
|
||||
extern void apple_display_alert(NSString* message, NSString* title);
|
||||
@ -90,4 +61,7 @@ extern void objc_clear_config_hack();
|
||||
extern bool path_make_and_check_directory(const char* path, mode_t mode, int amode);
|
||||
extern NSString* objc_get_value_from_config(config_file_t* config, NSString* name, NSString* defaultValue);
|
||||
|
||||
// frontend/platform/platform_apple.c
|
||||
extern void apple_frontend_post_event(void (*fn)(void*), void* userdata);
|
||||
|
||||
#endif
|
||||
|
@ -21,36 +21,14 @@
|
||||
|
||||
#include "apple_input.h"
|
||||
|
||||
// If USE_XATTR is defined any loaded file will get a com.RetroArch.Core extended attribute
|
||||
// specifying which core was used to load.
|
||||
//#define USE_XATTR
|
||||
|
||||
#ifdef IOS
|
||||
#import "views.h"
|
||||
#include "../iOS/input/BTStack/btpad.h"
|
||||
#include "../iOS/input/BTStack/btdynamic.h"
|
||||
#include "../iOS/input/BTStack/btpad.h"
|
||||
#elif defined(USE_XATTR)
|
||||
#include "sys/xattr.h"
|
||||
#endif
|
||||
|
||||
#include "file.h"
|
||||
|
||||
#define GSEVENT_TYPE_KEYDOWN 10
|
||||
#define GSEVENT_TYPE_KEYUP 11
|
||||
|
||||
//#define HAVE_DEBUG_FILELOG
|
||||
static bool use_tv_mode;
|
||||
|
||||
id<RetroArch_Platform> apple_platform;
|
||||
|
||||
// From frontend/frontend_ios.c
|
||||
extern void apple_frontend_post_event(void (*fn)(void*), void* userdata);
|
||||
|
||||
|
||||
// These are based on the tag property of the button used to trigger the event
|
||||
enum basic_event_t { RESET = 1, LOAD_STATE = 2, SAVE_STATE = 3, QUIT = 4 };
|
||||
static void event_basic_command(void* userdata)
|
||||
void apple_event_basic_command(void* userdata)
|
||||
{
|
||||
switch ((enum basic_event_t)userdata)
|
||||
{
|
||||
@ -61,12 +39,12 @@ static void event_basic_command(void* userdata)
|
||||
}
|
||||
}
|
||||
|
||||
static void event_set_state_slot(void* userdata)
|
||||
void apple_event_set_state_slot(void* userdata)
|
||||
{
|
||||
g_extern.state_slot = (uint32_t)userdata;
|
||||
}
|
||||
|
||||
static void event_show_rgui(void* userdata)
|
||||
void apple_event_show_rgui(void* userdata)
|
||||
{
|
||||
const bool in_menu = g_extern.lifecycle_mode_state & (1 << MODE_MENU);
|
||||
g_extern.lifecycle_mode_state &= ~(1ULL << (in_menu ? MODE_MENU : MODE_GAME));
|
||||
@ -82,7 +60,15 @@ static void event_reload_config(void* userdata)
|
||||
init_drivers();
|
||||
}
|
||||
|
||||
static pthread_mutex_t stasis_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
void apple_refresh_config()
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(&event_reload_config, 0);
|
||||
else
|
||||
objc_clear_config_hack();
|
||||
}
|
||||
|
||||
pthread_mutex_t stasis_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static void event_stasis(void* userdata)
|
||||
{
|
||||
@ -94,18 +80,34 @@ static void event_stasis(void* userdata)
|
||||
init_drivers();
|
||||
}
|
||||
|
||||
void apple_enter_stasis()
|
||||
{
|
||||
if (apple_is_running)
|
||||
{
|
||||
pthread_mutex_lock(&stasis_mutex);
|
||||
apple_frontend_post_event(event_stasis, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void apple_exit_stasis()
|
||||
{
|
||||
if (apple_is_running)
|
||||
pthread_mutex_unlock(&stasis_mutex);
|
||||
}
|
||||
|
||||
#pragma mark EMULATION
|
||||
static pthread_t apple_retro_thread;
|
||||
static bool apple_is_paused;
|
||||
static bool apple_is_running;
|
||||
static RAModuleInfo* apple_core;
|
||||
bool apple_is_paused;
|
||||
bool apple_is_running;
|
||||
bool apple_use_tv_mode;
|
||||
RAModuleInfo* apple_core;
|
||||
|
||||
void* rarch_main_spring(void* args)
|
||||
{
|
||||
char** argv = args;
|
||||
|
||||
uint32_t argc = 0;
|
||||
while (argv && argv[argc ++]);
|
||||
while (argv && argv[argc]) argc++;
|
||||
|
||||
if (rarch_main(argc, argv))
|
||||
{
|
||||
@ -136,11 +138,15 @@ void apple_run_core(RAModuleInfo* core, const char* file)
|
||||
if (file && core)
|
||||
{
|
||||
argv[3] = "-L";
|
||||
argv[4] = core_path;
|
||||
strlcpy(core_path, apple_core.path.UTF8String, sizeof(core_path));
|
||||
strlcpy(file_path, file, sizeof(file_path));
|
||||
}
|
||||
else
|
||||
argv[3] = 0;
|
||||
{
|
||||
argv[3] = "--menu";
|
||||
argv[4] = 0;
|
||||
}
|
||||
|
||||
if (pthread_create(&apple_retro_thread, 0, rarch_main_spring, argv))
|
||||
{
|
||||
@ -169,578 +175,3 @@ void apple_rarch_exited(void* result)
|
||||
if (use_tv_mode)
|
||||
apple_run_core(nil, 0);
|
||||
}
|
||||
|
||||
//
|
||||
// IOS
|
||||
//
|
||||
#pragma mark IOS
|
||||
#ifdef IOS
|
||||
// Input helpers: This is kept here because it needs objective-c
|
||||
static void handle_touch_event(NSArray* touches)
|
||||
{
|
||||
const int numTouches = [touches count];
|
||||
const float scale = [[UIScreen mainScreen] scale];
|
||||
|
||||
g_current_input_data.touch_count = 0;
|
||||
|
||||
for(int i = 0; i != numTouches && g_current_input_data.touch_count < MAX_TOUCHES; i ++)
|
||||
{
|
||||
UITouch* touch = [touches objectAtIndex:i];
|
||||
const CGPoint coord = [touch locationInView:touch.view];
|
||||
|
||||
if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled)
|
||||
{
|
||||
g_current_input_data.touches[g_current_input_data.touch_count ].screen_x = coord.x * scale;
|
||||
g_current_input_data.touches[g_current_input_data.touch_count ++].screen_y = coord.y * scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@interface RApplication : UIApplication
|
||||
@end
|
||||
|
||||
@implementation RApplication
|
||||
|
||||
- (void)sendEvent:(UIEvent *)event
|
||||
{
|
||||
[super sendEvent:event];
|
||||
|
||||
if ([[event allTouches] count])
|
||||
handle_touch_event(event.allTouches.allObjects);
|
||||
else if ([event respondsToSelector:@selector(_gsEvent)])
|
||||
{
|
||||
// Stolen from: http://nacho4d-nacho4d.blogspot.com/2012/01/catching-keyboard-events-in-ios.html
|
||||
uint8_t* eventMem = (uint8_t*)(void*)CFBridgingRetain([event performSelector:@selector(_gsEvent)]);
|
||||
int eventType = eventMem ? *(int*)&eventMem[8] : 0;
|
||||
|
||||
if (eventType == GSEVENT_TYPE_KEYDOWN || eventType == GSEVENT_TYPE_KEYUP)
|
||||
apple_input_handle_key_event(*(uint16_t*)&eventMem[0x3C], eventType == GSEVENT_TYPE_KEYDOWN);
|
||||
|
||||
CFBridgingRelease(eventMem);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@autoreleasepool {
|
||||
#if defined(HAVE_DEBUG_FILELOG) && (TARGET_IPHONE_SIMULATOR == 0)
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
NSString *documentsDirectory = [paths objectAtIndex:0];
|
||||
NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console_stdout.log"];
|
||||
freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stdout);
|
||||
freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stderr);
|
||||
#endif
|
||||
return UIApplicationMain(argc, argv, NSStringFromClass([RApplication class]), NSStringFromClass([RetroArch_iOS class]));
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RetroArch_iOS
|
||||
{
|
||||
UIWindow* _window;
|
||||
|
||||
bool _isGameTop, _isRomList;
|
||||
uint32_t _settingMenusInBackStack;
|
||||
uint32_t _enabledOrientations;
|
||||
|
||||
RAModuleInfo* _module;
|
||||
}
|
||||
|
||||
+ (RetroArch_iOS*)get
|
||||
{
|
||||
return (RetroArch_iOS*)[[UIApplication sharedApplication] delegate];
|
||||
}
|
||||
|
||||
// UIApplicationDelegate
|
||||
- (void)applicationDidFinishLaunching:(UIApplication *)application
|
||||
{
|
||||
apple_platform = self;
|
||||
self.delegate = self;
|
||||
|
||||
// Setup window
|
||||
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
_window.rootViewController = self;
|
||||
[_window makeKeyAndVisible];
|
||||
|
||||
// Build system paths and test permissions
|
||||
self.documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
|
||||
self.systemDirectory = [self.documentsDirectory stringByAppendingPathComponent:@".RetroArch"];
|
||||
self.systemConfigPath = [self.systemDirectory stringByAppendingPathComponent:@"frontend.cfg"];
|
||||
|
||||
if (!path_make_and_check_directory(self.documentsDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
|
||||
apple_display_alert([NSString stringWithFormat:@"Failed to create or access base directory: %@", self.documentsDirectory], 0);
|
||||
else if (!path_make_and_check_directory(self.systemDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
|
||||
apple_display_alert([NSString stringWithFormat:@"Failed to create or access system directory: %@", self.systemDirectory], 0);
|
||||
else
|
||||
{
|
||||
[self pushViewController:[RADirectoryList directoryListAtBrowseRoot] animated:YES];
|
||||
[self refreshSystemConfig];
|
||||
|
||||
if (use_tv_mode)
|
||||
apple_run_core(nil, 0);
|
||||
}
|
||||
|
||||
// Warn if there are no cores present
|
||||
if ([RAModuleInfo getModules].count == 0)
|
||||
apple_display_alert(@"No libretro cores were found. You will not be able to play any games.", 0);
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application
|
||||
{
|
||||
if (apple_is_running)
|
||||
pthread_mutex_unlock(&stasis_mutex);
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication *)application
|
||||
{
|
||||
if (apple_is_running)
|
||||
{
|
||||
pthread_mutex_lock(&stasis_mutex);
|
||||
apple_frontend_post_event(event_stasis, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// UINavigationControllerDelegate
|
||||
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
|
||||
{
|
||||
_isGameTop = [viewController isKindOfClass:[RAGameView class]];
|
||||
_isRomList = [viewController isKindOfClass:[RADirectoryList class]];
|
||||
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:_isGameTop withAnimation:UIStatusBarAnimationNone];
|
||||
[[UIApplication sharedApplication] setIdleTimerDisabled:_isGameTop];
|
||||
|
||||
self.navigationBarHidden = _isGameTop;
|
||||
[self setToolbarHidden:!_isRomList animated:YES];
|
||||
self.topViewController.navigationItem.rightBarButtonItem = [self createSettingsButton];
|
||||
}
|
||||
|
||||
// UINavigationController: Never animate when pushing onto, or popping, an RAGameView
|
||||
- (void)pushViewController:(UIViewController*)theView animated:(BOOL)animated
|
||||
{
|
||||
if ([theView respondsToSelector:@selector(isSettingsView)] && [(id)theView isSettingsView])
|
||||
_settingMenusInBackStack ++;
|
||||
|
||||
[super pushViewController:theView animated:animated && !_isGameTop];
|
||||
}
|
||||
|
||||
- (UIViewController*)popViewControllerAnimated:(BOOL)animated
|
||||
{
|
||||
if ([self.topViewController respondsToSelector:@selector(isSettingsView)] && [(id)self.topViewController isSettingsView])
|
||||
_settingMenusInBackStack --;
|
||||
|
||||
return [super popViewControllerAnimated:animated && !_isGameTop];
|
||||
}
|
||||
|
||||
// NOTE: This version only runs on iOS6
|
||||
- (NSUInteger)supportedInterfaceOrientations
|
||||
{
|
||||
return _isGameTop ? _enabledOrientations
|
||||
: UIInterfaceOrientationMaskAll;
|
||||
}
|
||||
|
||||
// NOTE: This version runs on iOS2-iOS5, but not iOS6
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
if (_isGameTop)
|
||||
switch (interfaceOrientation)
|
||||
{
|
||||
case UIInterfaceOrientationPortrait:
|
||||
return (_enabledOrientations & UIInterfaceOrientationMaskPortrait);
|
||||
case UIInterfaceOrientationPortraitUpsideDown:
|
||||
return (_enabledOrientations & UIInterfaceOrientationMaskPortraitUpsideDown);
|
||||
case UIInterfaceOrientationLandscapeLeft:
|
||||
return (_enabledOrientations & UIInterfaceOrientationMaskLandscapeLeft);
|
||||
case UIInterfaceOrientationLandscapeRight:
|
||||
return (_enabledOrientations & UIInterfaceOrientationMaskLandscapeRight);
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark RetroArch_Platform
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file
|
||||
{
|
||||
[self pushViewController:RAGameView.get animated:NO];
|
||||
[RASettingsList refreshModuleConfig:core];
|
||||
|
||||
btpad_set_inquiry_state(false);
|
||||
|
||||
[self refreshSystemConfig];
|
||||
}
|
||||
|
||||
- (void)unloadingCore:(RAModuleInfo*)core
|
||||
{
|
||||
[self popToViewController:[RAGameView get] animated:NO];
|
||||
[self popViewControllerAnimated:NO];
|
||||
|
||||
btpad_set_inquiry_state(true);
|
||||
}
|
||||
|
||||
- (NSString*)retroarchConfigPath
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@/retroarch.cfg", self.systemDirectory];
|
||||
}
|
||||
|
||||
- (NSString*)corePath
|
||||
{
|
||||
return [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"modules"];
|
||||
}
|
||||
|
||||
- (void)refreshConfig
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(&event_reload_config, 0);
|
||||
else
|
||||
objc_clear_config_hack();
|
||||
}
|
||||
|
||||
- (void)refreshSystemConfig
|
||||
{
|
||||
// Read load time settings
|
||||
config_file_t* conf = config_file_new([self.systemConfigPath UTF8String]);
|
||||
|
||||
if (conf)
|
||||
{
|
||||
// Get enabled orientations
|
||||
static const struct { const char* setting; uint32_t orientation; } orientationSettings[4] =
|
||||
{
|
||||
{ "ios_allow_portrait", UIInterfaceOrientationMaskPortrait },
|
||||
{ "ios_allow_portrait_upside_down", UIInterfaceOrientationMaskPortraitUpsideDown },
|
||||
{ "ios_allow_landscape_left", UIInterfaceOrientationMaskLandscapeLeft },
|
||||
{ "ios_allow_landscape_right", UIInterfaceOrientationMaskLandscapeRight }
|
||||
};
|
||||
|
||||
_enabledOrientations = 0;
|
||||
|
||||
for (int i = 0; i < 4; i ++)
|
||||
{
|
||||
bool enabled = false;
|
||||
bool found = config_get_bool(conf, orientationSettings[i].setting, &enabled);
|
||||
|
||||
if (!found || enabled)
|
||||
_enabledOrientations |= orientationSettings[i].orientation;
|
||||
}
|
||||
|
||||
// Setup bluetooth mode
|
||||
NSString* btmode = objc_get_value_from_config(conf, @"ios_btmode", @"keyboard");
|
||||
apple_input_enable_icade([btmode isEqualToString:@"icade"]);
|
||||
btstack_set_poweron([btmode isEqualToString:@"btstack"]);
|
||||
|
||||
bool val;
|
||||
use_tv_mode = config_get_bool(conf, "ios_tv_mode", & val) && val;
|
||||
|
||||
config_file_free(conf);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark PAUSE MENU
|
||||
- (UIBarButtonItem*)createSettingsButton
|
||||
{
|
||||
if (_settingMenusInBackStack == 0)
|
||||
return [[UIBarButtonItem alloc]
|
||||
initWithTitle:@"Settings"
|
||||
style:UIBarButtonItemStyleBordered
|
||||
target:[RetroArch_iOS get]
|
||||
action:@selector(showSystemSettings)];
|
||||
|
||||
else
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (IBAction)showPauseMenu:(id)sender
|
||||
{
|
||||
if (apple_is_running && !apple_is_paused && _isGameTop)
|
||||
{
|
||||
apple_is_paused = true;
|
||||
[[RAGameView get] openPauseMenu];
|
||||
|
||||
btpad_set_inquiry_state(true);
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)basicEvent:(id)sender
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(&event_basic_command, ((UIView*)sender).tag);
|
||||
|
||||
[self closePauseMenu:sender];
|
||||
}
|
||||
|
||||
- (IBAction)chooseState:(id)sender
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(event_set_state_slot, (void*)((UISegmentedControl*)sender).selectedSegmentIndex);
|
||||
}
|
||||
|
||||
- (IBAction)showRGUI:(id)sender
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(event_show_rgui, 0);
|
||||
|
||||
[self closePauseMenu:sender];
|
||||
}
|
||||
|
||||
- (IBAction)closePauseMenu:(id)sender
|
||||
{
|
||||
[[RAGameView get] closePauseMenu];
|
||||
apple_is_paused = false;
|
||||
|
||||
btpad_set_inquiry_state(false);
|
||||
}
|
||||
|
||||
- (IBAction)showSettings
|
||||
{
|
||||
[self pushViewController:[[RASettingsList alloc] initWithModule:_module] animated:YES];
|
||||
}
|
||||
|
||||
- (IBAction)showSystemSettings
|
||||
{
|
||||
[self pushViewController:[RASystemSettingsList new] animated:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// OSX
|
||||
//
|
||||
#pragma mark OSX
|
||||
#ifdef OSX
|
||||
|
||||
@interface RApplication : NSApplication
|
||||
@end
|
||||
|
||||
@implementation RApplication
|
||||
|
||||
- (void)sendEvent:(NSEvent *)event
|
||||
{
|
||||
[super sendEvent:event];
|
||||
|
||||
if (event.type == GSEVENT_TYPE_KEYDOWN || event.type == GSEVENT_TYPE_KEYUP)
|
||||
apple_input_handle_key_event(event.keyCode, event.type == GSEVENT_TYPE_KEYDOWN);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RetroArch_OSX
|
||||
{
|
||||
NSWindow IBOutlet* _coreSelectSheet;
|
||||
|
||||
bool _isTerminating;
|
||||
bool _loaded;
|
||||
bool _wantReload;
|
||||
NSString* _file;
|
||||
RAModuleInfo* _core;
|
||||
}
|
||||
|
||||
+ (RetroArch_OSX*)get
|
||||
{
|
||||
return (RetroArch_OSX*)[[NSApplication sharedApplication] delegate];
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||
{
|
||||
apple_platform = self;
|
||||
_loaded = true;
|
||||
|
||||
[window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
|
||||
|
||||
RAGameView.get.frame = [window.contentView bounds];
|
||||
[window.contentView setAutoresizesSubviews:YES];
|
||||
[window.contentView addSubview:RAGameView.get];
|
||||
[window makeFirstResponder:RAGameView.get];
|
||||
|
||||
// Create core select list
|
||||
NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1];
|
||||
|
||||
for (RAModuleInfo* i in RAModuleInfo.getModules)
|
||||
[cb addItemWithObjectValue:i];
|
||||
|
||||
if (cb.numberOfItems)
|
||||
[cb selectItemAtIndex:0];
|
||||
else
|
||||
apple_display_alert(@"No libretro cores were found.", @"RetroArch");
|
||||
|
||||
// Run RGUI if needed
|
||||
if (!_wantReload)
|
||||
apple_run_core(nil, 0);
|
||||
else
|
||||
[self chooseCore];
|
||||
|
||||
_wantReload = false;
|
||||
|
||||
extern void osx_pad_init();
|
||||
osx_pad_init();
|
||||
}
|
||||
|
||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||
{
|
||||
_isTerminating = true;
|
||||
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(event_basic_command, (void*)QUIT);
|
||||
|
||||
return apple_is_running ? NSTerminateCancel : NSTerminateNow;
|
||||
}
|
||||
|
||||
|
||||
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
|
||||
{
|
||||
if (filenames.count == 1 && filenames[0])
|
||||
{
|
||||
_file = filenames[0];
|
||||
|
||||
if (!_loaded)
|
||||
_wantReload = true;
|
||||
else
|
||||
[self chooseCore];
|
||||
|
||||
[sender replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
|
||||
}
|
||||
else
|
||||
{
|
||||
apple_display_alert(@"Cannot open multiple files", @"RetroArch");
|
||||
[sender replyToOpenOrPrint:NSApplicationDelegateReplyFailure];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)openDocument:(id)sender
|
||||
{
|
||||
NSOpenPanel* panel = [NSOpenPanel openPanel];
|
||||
[panel beginSheetModalForWindow:window completionHandler:^(NSInteger result)
|
||||
{
|
||||
[NSApplication.sharedApplication stopModal];
|
||||
|
||||
if (result == NSOKButton && panel.URL)
|
||||
{
|
||||
_file = panel.URL.path;
|
||||
[self performSelector:@selector(chooseCore) withObject:nil afterDelay:.5f];
|
||||
}
|
||||
}];
|
||||
[NSApplication.sharedApplication runModalForWindow:panel];
|
||||
}
|
||||
|
||||
// This utility function will queue the _core and _file instance values for running.
|
||||
// If the emulator thread is already running it will tell it to quit.
|
||||
- (void)runCore
|
||||
{
|
||||
_wantReload = apple_is_running;
|
||||
|
||||
if (!apple_is_running)
|
||||
apple_run_core(_core, _file.UTF8String);
|
||||
else
|
||||
apple_frontend_post_event(event_basic_command, (void*)QUIT);
|
||||
}
|
||||
|
||||
- (void)chooseCore
|
||||
{
|
||||
#ifdef USE_XATTR
|
||||
char stored_name[PATH_MAX];
|
||||
if (getxattr(_file.UTF8String, "com.RetroArch.Core", stored_name, PATH_MAX, 0, 0) > 0)
|
||||
{
|
||||
for (RAModuleInfo* i in RAModuleInfo.getModules)
|
||||
{
|
||||
const char* core_name = i.path.lastPathComponent.UTF8String;
|
||||
if (strcmp(core_name, stored_name) == 0)
|
||||
{
|
||||
_core = i;
|
||||
[self runCore];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[NSApplication.sharedApplication beginSheet:_coreSelectSheet modalForWindow:window modalDelegate:nil didEndSelector:nil contextInfo:nil];
|
||||
[NSApplication.sharedApplication runModalForWindow:_coreSelectSheet];
|
||||
}
|
||||
|
||||
- (IBAction)coreWasChosen:(id)sender
|
||||
{
|
||||
[NSApplication.sharedApplication stopModal];
|
||||
[NSApplication.sharedApplication endSheet:_coreSelectSheet returnCode:0];
|
||||
[_coreSelectSheet orderOut:self];
|
||||
|
||||
if (_isTerminating)
|
||||
return;
|
||||
|
||||
NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1];
|
||||
_core = (RAModuleInfo*)cb.objectValueOfSelectedItem;
|
||||
|
||||
[self runCore];
|
||||
}
|
||||
|
||||
#pragma mark RetroArch_Platform
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file
|
||||
{
|
||||
if (file)
|
||||
{
|
||||
[NSDocumentController.sharedDocumentController noteNewRecentDocumentURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:file]]];
|
||||
|
||||
#ifdef USE_XATTR
|
||||
const char* core_name = core.path.lastPathComponent.UTF8String;
|
||||
setxattr(file, "com.RetroArch.Core", core_name, strlen(core_name) + 1, 0, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unloadingCore:(RAModuleInfo*)core
|
||||
{
|
||||
if (_isTerminating)
|
||||
[NSApplication.sharedApplication terminate:nil];
|
||||
|
||||
if (_wantReload)
|
||||
apple_run_core(_core, _file.UTF8String);
|
||||
else if(use_tv_mode)
|
||||
apple_run_core(nil, 0);
|
||||
else
|
||||
[NSApplication.sharedApplication terminate:nil];
|
||||
|
||||
_wantReload = false;
|
||||
}
|
||||
|
||||
- (NSString*)retroarchConfigPath
|
||||
{
|
||||
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||
return [paths[0] stringByAppendingPathComponent:@"RetroArch/retroarch.cfg"];
|
||||
}
|
||||
|
||||
- (NSString*)corePath
|
||||
{
|
||||
return [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"Contents/Resources/modules"];
|
||||
}
|
||||
|
||||
#pragma mark Menus
|
||||
- (IBAction)showPreferences:(id)sender
|
||||
{
|
||||
[[[NSWindowController alloc] initWithWindowNibName:@"Settings"] window];
|
||||
}
|
||||
|
||||
- (IBAction)basicEvent:(id)sender
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(&event_basic_command, (void*)((NSMenuItem*)sender).tag);
|
||||
}
|
||||
|
||||
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
|
||||
{
|
||||
[NSApplication.sharedApplication stopModal];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return NSApplicationMain(argc, (const char **) argv);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -11,6 +11,7 @@
|
||||
9620F6651790004F001B3B81 /* Settings.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9620F6641790004F001B3B81 /* Settings.xib */; };
|
||||
962EE0E2178B3DF6004224FF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 962EE0E1178B3DF6004224FF /* IOKit.framework */; };
|
||||
96355CE31788E72A0010DBFA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96355CE21788E72A0010DBFA /* Cocoa.framework */; };
|
||||
9646869817BBC14E00C5EA69 /* platform.m in Sources */ = {isa = PBXBuildFile; fileRef = 9646869617BBC14E00C5EA69 /* platform.m */; };
|
||||
967894931788ECDB00D6CA69 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9678948F1788ECDB00D6CA69 /* InfoPlist.strings */; };
|
||||
967894941788ECDB00D6CA69 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 967894911788ECDB00D6CA69 /* MainMenu.xib */; };
|
||||
967894961788ED1100D6CA69 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 967894951788ED1100D6CA69 /* main.m */; };
|
||||
@ -35,6 +36,8 @@
|
||||
96355CE51788E72A0010DBFA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
|
||||
96355CE61788E72A0010DBFA /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
|
||||
96355CE71788E72A0010DBFA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
9646869617BBC14E00C5EA69 /* platform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = platform.m; path = OSX/platform.m; sourceTree = SOURCE_ROOT; };
|
||||
9646869717BBC14E00C5EA69 /* platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = platform.h; path = OSX/platform.h; sourceTree = SOURCE_ROOT; };
|
||||
9678948D1788ECCA00D6CA69 /* RetroArch-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "RetroArch-Info.plist"; path = "OSX/RetroArch-Info.plist"; sourceTree = SOURCE_ROOT; };
|
||||
967894901788ECDB00D6CA69 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = OSX/en.lproj/InfoPlist.strings; sourceTree = SOURCE_ROOT; };
|
||||
967894921788ECDB00D6CA69 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = OSX/en.lproj/MainMenu.xib; sourceTree = SOURCE_ROOT; };
|
||||
@ -109,6 +112,8 @@
|
||||
96355CE81788E72A0010DBFA /* RetroArch */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9646869617BBC14E00C5EA69 /* platform.m */,
|
||||
9646869717BBC14E00C5EA69 /* platform.h */,
|
||||
9620F662178FD4D3001B3B81 /* settings.m */,
|
||||
967894A01788F07D00D6CA69 /* griffin.c */,
|
||||
967894971788F02600D6CA69 /* RAGameView.m */,
|
||||
@ -214,6 +219,7 @@
|
||||
9678949F1788F02600D6CA69 /* utility.m in Sources */,
|
||||
967894A11788F07D00D6CA69 /* griffin.c in Sources */,
|
||||
9620F663178FD4D3001B3B81 /* settings.m in Sources */,
|
||||
9646869817BBC14E00C5EA69 /* platform.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -16,6 +16,7 @@
|
||||
96366C5516C9AC3300D64A22 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96366C5416C9AC3300D64A22 /* CoreAudio.framework */; };
|
||||
96366C5916C9ACF500D64A22 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96366C5816C9ACF500D64A22 /* AudioToolbox.framework */; };
|
||||
963F5AC816CC523B009BBD19 /* RAGameView.m in Sources */ = {isa = PBXBuildFile; fileRef = 963F5AC516CC523B009BBD19 /* RAGameView.m */; };
|
||||
9646869517BBBEAE00C5EA69 /* platform.m in Sources */ = {isa = PBXBuildFile; fileRef = 9646869417BBBEAE00C5EA69 /* platform.m */; };
|
||||
966B9CBD16E41E7A005B61E1 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 966B9CB816E41E7A005B61E1 /* Default-568h@2x.png */; };
|
||||
966B9CBF16E41E7A005B61E1 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 966B9CB916E41E7A005B61E1 /* Default.png */; };
|
||||
966B9CC116E41E7A005B61E1 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 966B9CBA16E41E7A005B61E1 /* Default@2x.png */; };
|
||||
@ -49,6 +50,7 @@
|
||||
96366C5416C9AC3300D64A22 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; };
|
||||
96366C5816C9ACF500D64A22 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
|
||||
963F5AC516CC523B009BBD19 /* RAGameView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RAGameView.m; sourceTree = "<group>"; };
|
||||
9646869417BBBEAE00C5EA69 /* platform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = platform.m; path = iOS/platform.m; sourceTree = SOURCE_ROOT; };
|
||||
966B9CB816E41E7A005B61E1 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
|
||||
966B9CB916E41E7A005B61E1 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = "<group>"; };
|
||||
966B9CBA16E41E7A005B61E1 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = "<group>"; };
|
||||
@ -152,6 +154,7 @@
|
||||
96AFAE3316C1D4EA009DE44C /* RetroArch */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9646869417BBBEAE00C5EA69 /* platform.m */,
|
||||
967894571788EAAE00D6CA69 /* browser.m */,
|
||||
967894581788EAAE00D6CA69 /* RALogView.m */,
|
||||
967894591788EAAE00D6CA69 /* settings.m */,
|
||||
@ -305,6 +308,7 @@
|
||||
9678945B1788EAAE00D6CA69 /* browser.m in Sources */,
|
||||
9678945C1788EAAE00D6CA69 /* RALogView.m in Sources */,
|
||||
9678945D1788EAAE00D6CA69 /* settings.m in Sources */,
|
||||
9646869517BBBEAE00C5EA69 /* platform.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
42
apple/iOS/platform.h
Normal file
42
apple/iOS/platform.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2013 - Jason Fetters
|
||||
* Copyright (C) 2011-2013 - Daniel De Matteis
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __RARCH_IOS_PLATFORM_H
|
||||
#define __RARCH_IOS_PLATFORM_H
|
||||
|
||||
@interface RAGameView : UIViewController
|
||||
+ (RAGameView*)get;
|
||||
- (void)openPauseMenu;
|
||||
- (void)closePauseMenu;
|
||||
@end
|
||||
|
||||
@interface RetroArch_iOS : UINavigationController<UIApplicationDelegate, UINavigationControllerDelegate, RetroArch_Platform>
|
||||
|
||||
+ (RetroArch_iOS*)get;
|
||||
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
|
||||
- (void)unloadingCore:(RAModuleInfo*)core;
|
||||
- (NSString*)retroarchConfigPath;
|
||||
|
||||
- (void)refreshSystemConfig;
|
||||
|
||||
@property (strong, nonatomic) NSString* documentsDirectory; // e.g. /var/mobile/Documents
|
||||
@property (strong, nonatomic) NSString* systemDirectory; // e.g. /var/mobile/Documents/.RetroArch
|
||||
@property (strong, nonatomic) NSString* systemConfigPath; // e.g. /var/mobile/Documents/.RetroArch/frontend.cfg
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
346
apple/iOS/platform.m
Normal file
346
apple/iOS/platform.m
Normal file
@ -0,0 +1,346 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2013 - Jason Fetters
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
|
||||
#import "RetroArch_Apple.h"
|
||||
#include "rarch_wrapper.h"
|
||||
|
||||
#include "../RetroArch/apple_input.h"
|
||||
|
||||
#import "views.h"
|
||||
#include "input/BTStack/btpad.h"
|
||||
#include "input/BTStack/btdynamic.h"
|
||||
#include "input/BTStack/btpad.h"
|
||||
|
||||
#include "file.h"
|
||||
|
||||
//#define HAVE_DEBUG_FILELOG
|
||||
|
||||
// Input helpers: This is kept here because it needs objective-c
|
||||
static void handle_touch_event(NSArray* touches)
|
||||
{
|
||||
const int numTouches = [touches count];
|
||||
const float scale = [[UIScreen mainScreen] scale];
|
||||
|
||||
g_current_input_data.touch_count = 0;
|
||||
|
||||
for(int i = 0; i != numTouches && g_current_input_data.touch_count < MAX_TOUCHES; i ++)
|
||||
{
|
||||
UITouch* touch = [touches objectAtIndex:i];
|
||||
const CGPoint coord = [touch locationInView:touch.view];
|
||||
|
||||
if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled)
|
||||
{
|
||||
g_current_input_data.touches[g_current_input_data.touch_count ].screen_x = coord.x * scale;
|
||||
g_current_input_data.touches[g_current_input_data.touch_count ++].screen_y = coord.y * scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@interface RApplication : UIApplication
|
||||
@end
|
||||
|
||||
@implementation RApplication
|
||||
|
||||
- (void)sendEvent:(UIEvent *)event
|
||||
{
|
||||
[super sendEvent:event];
|
||||
|
||||
if ([[event allTouches] count])
|
||||
handle_touch_event(event.allTouches.allObjects);
|
||||
else if ([event respondsToSelector:@selector(_gsEvent)])
|
||||
{
|
||||
// Stolen from: http://nacho4d-nacho4d.blogspot.com/2012/01/catching-keyboard-events-in-ios.html
|
||||
uint8_t* eventMem = (uint8_t*)(void*)CFBridgingRetain([event performSelector:@selector(_gsEvent)]);
|
||||
int eventType = eventMem ? *(int*)&eventMem[8] : 0;
|
||||
|
||||
if (eventType == GSEVENT_TYPE_KEYDOWN || eventType == GSEVENT_TYPE_KEYUP)
|
||||
apple_input_handle_key_event(*(uint16_t*)&eventMem[0x3C], eventType == GSEVENT_TYPE_KEYDOWN);
|
||||
|
||||
CFBridgingRelease(eventMem);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RetroArch_iOS
|
||||
{
|
||||
UIWindow* _window;
|
||||
|
||||
bool _isGameTop, _isRomList;
|
||||
uint32_t _settingMenusInBackStack;
|
||||
uint32_t _enabledOrientations;
|
||||
|
||||
RAModuleInfo* _module;
|
||||
}
|
||||
|
||||
+ (RetroArch_iOS*)get
|
||||
{
|
||||
return (RetroArch_iOS*)[[UIApplication sharedApplication] delegate];
|
||||
}
|
||||
|
||||
#pragma mark LIFECYCLE (UIApplicationDelegate)
|
||||
- (void)applicationDidFinishLaunching:(UIApplication *)application
|
||||
{
|
||||
apple_platform = self;
|
||||
self.delegate = self;
|
||||
|
||||
// Setup window
|
||||
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
_window.rootViewController = self;
|
||||
[_window makeKeyAndVisible];
|
||||
|
||||
// Build system paths and test permissions
|
||||
self.documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
|
||||
self.systemDirectory = [self.documentsDirectory stringByAppendingPathComponent:@".RetroArch"];
|
||||
self.systemConfigPath = [self.systemDirectory stringByAppendingPathComponent:@"frontend.cfg"];
|
||||
|
||||
if (!path_make_and_check_directory(self.documentsDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
|
||||
apple_display_alert([NSString stringWithFormat:@"Failed to create or access base directory: %@", self.documentsDirectory], 0);
|
||||
else if (!path_make_and_check_directory(self.systemDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
|
||||
apple_display_alert([NSString stringWithFormat:@"Failed to create or access system directory: %@", self.systemDirectory], 0);
|
||||
else
|
||||
{
|
||||
[self pushViewController:[RADirectoryList directoryListAtBrowseRoot] animated:YES];
|
||||
[self refreshSystemConfig];
|
||||
|
||||
if (apple_use_tv_mode)
|
||||
apple_run_core(nil, 0);
|
||||
}
|
||||
|
||||
// Warn if there are no cores present
|
||||
if ([RAModuleInfo getModules].count == 0)
|
||||
apple_display_alert(@"No libretro cores were found. You will not be able to play any games.", 0);
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application
|
||||
{
|
||||
apple_enter_stasis();
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication *)application
|
||||
{
|
||||
apple_exit_stasis();
|
||||
}
|
||||
|
||||
// UINavigationControllerDelegate
|
||||
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
|
||||
{
|
||||
_isGameTop = [viewController isKindOfClass:[RAGameView class]];
|
||||
_isRomList = [viewController isKindOfClass:[RADirectoryList class]];
|
||||
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:_isGameTop withAnimation:UIStatusBarAnimationNone];
|
||||
[[UIApplication sharedApplication] setIdleTimerDisabled:_isGameTop];
|
||||
|
||||
self.navigationBarHidden = _isGameTop;
|
||||
[self setToolbarHidden:!_isRomList animated:YES];
|
||||
self.topViewController.navigationItem.rightBarButtonItem = [self createSettingsButton];
|
||||
}
|
||||
|
||||
// UINavigationController: Never animate when pushing onto, or popping, an RAGameView
|
||||
- (void)pushViewController:(UIViewController*)theView animated:(BOOL)animated
|
||||
{
|
||||
if ([theView respondsToSelector:@selector(isSettingsView)] && [(id)theView isSettingsView])
|
||||
_settingMenusInBackStack ++;
|
||||
|
||||
[super pushViewController:theView animated:animated && !_isGameTop];
|
||||
}
|
||||
|
||||
- (UIViewController*)popViewControllerAnimated:(BOOL)animated
|
||||
{
|
||||
if ([self.topViewController respondsToSelector:@selector(isSettingsView)] && [(id)self.topViewController isSettingsView])
|
||||
_settingMenusInBackStack --;
|
||||
|
||||
return [super popViewControllerAnimated:animated && !_isGameTop];
|
||||
}
|
||||
|
||||
// NOTE: This version only runs on iOS6
|
||||
- (NSUInteger)supportedInterfaceOrientations
|
||||
{
|
||||
return _isGameTop ? _enabledOrientations
|
||||
: UIInterfaceOrientationMaskAll;
|
||||
}
|
||||
|
||||
// NOTE: This version runs on iOS2-iOS5, but not iOS6
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
if (_isGameTop)
|
||||
switch (interfaceOrientation)
|
||||
{
|
||||
case UIInterfaceOrientationPortrait:
|
||||
return (_enabledOrientations & UIInterfaceOrientationMaskPortrait);
|
||||
case UIInterfaceOrientationPortraitUpsideDown:
|
||||
return (_enabledOrientations & UIInterfaceOrientationMaskPortraitUpsideDown);
|
||||
case UIInterfaceOrientationLandscapeLeft:
|
||||
return (_enabledOrientations & UIInterfaceOrientationMaskLandscapeLeft);
|
||||
case UIInterfaceOrientationLandscapeRight:
|
||||
return (_enabledOrientations & UIInterfaceOrientationMaskLandscapeRight);
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark RetroArch_Platform
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file
|
||||
{
|
||||
[self pushViewController:RAGameView.get animated:NO];
|
||||
[RASettingsList refreshModuleConfig:core];
|
||||
|
||||
btpad_set_inquiry_state(false);
|
||||
|
||||
[self refreshSystemConfig];
|
||||
}
|
||||
|
||||
- (void)unloadingCore:(RAModuleInfo*)core
|
||||
{
|
||||
[self popToViewController:[RAGameView get] animated:NO];
|
||||
[self popViewControllerAnimated:NO];
|
||||
|
||||
btpad_set_inquiry_state(true);
|
||||
}
|
||||
|
||||
- (NSString*)retroarchConfigPath
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@/retroarch.cfg", self.systemDirectory];
|
||||
}
|
||||
|
||||
- (NSString*)corePath
|
||||
{
|
||||
return [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"modules"];
|
||||
}
|
||||
|
||||
#pragma mark FRONTEND CONFIG
|
||||
- (void)refreshSystemConfig
|
||||
{
|
||||
// Read load time settings
|
||||
config_file_t* conf = config_file_new([self.systemConfigPath UTF8String]);
|
||||
|
||||
if (conf)
|
||||
{
|
||||
// Get enabled orientations
|
||||
static const struct { const char* setting; uint32_t orientation; } orientationSettings[4] =
|
||||
{
|
||||
{ "ios_allow_portrait", UIInterfaceOrientationMaskPortrait },
|
||||
{ "ios_allow_portrait_upside_down", UIInterfaceOrientationMaskPortraitUpsideDown },
|
||||
{ "ios_allow_landscape_left", UIInterfaceOrientationMaskLandscapeLeft },
|
||||
{ "ios_allow_landscape_right", UIInterfaceOrientationMaskLandscapeRight }
|
||||
};
|
||||
|
||||
_enabledOrientations = 0;
|
||||
|
||||
for (int i = 0; i < 4; i ++)
|
||||
{
|
||||
bool enabled = false;
|
||||
bool found = config_get_bool(conf, orientationSettings[i].setting, &enabled);
|
||||
|
||||
if (!found || enabled)
|
||||
_enabledOrientations |= orientationSettings[i].orientation;
|
||||
}
|
||||
|
||||
// Setup bluetooth mode
|
||||
NSString* btmode = objc_get_value_from_config(conf, @"ios_btmode", @"keyboard");
|
||||
apple_input_enable_icade([btmode isEqualToString:@"icade"]);
|
||||
btstack_set_poweron([btmode isEqualToString:@"btstack"]);
|
||||
|
||||
bool val;
|
||||
apple_use_tv_mode = config_get_bool(conf, "ios_tv_mode", & val) && val;
|
||||
|
||||
config_file_free(conf);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark PAUSE MENU
|
||||
- (UIBarButtonItem*)createSettingsButton
|
||||
{
|
||||
if (_settingMenusInBackStack == 0)
|
||||
return [[UIBarButtonItem alloc]
|
||||
initWithTitle:@"Settings"
|
||||
style:UIBarButtonItemStyleBordered
|
||||
target:[RetroArch_iOS get]
|
||||
action:@selector(showSystemSettings)];
|
||||
|
||||
else
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (IBAction)showPauseMenu:(id)sender
|
||||
{
|
||||
if (apple_is_running && !apple_is_paused && _isGameTop)
|
||||
{
|
||||
apple_is_paused = true;
|
||||
[[RAGameView get] openPauseMenu];
|
||||
|
||||
btpad_set_inquiry_state(true);
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)basicEvent:(id)sender
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(&apple_event_basic_command, ((UIView*)sender).tag);
|
||||
|
||||
[self closePauseMenu:sender];
|
||||
}
|
||||
|
||||
- (IBAction)chooseState:(id)sender
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(apple_event_set_state_slot, (void*)((UISegmentedControl*)sender).selectedSegmentIndex);
|
||||
}
|
||||
|
||||
- (IBAction)showRGUI:(id)sender
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(apple_event_show_rgui, 0);
|
||||
|
||||
[self closePauseMenu:sender];
|
||||
}
|
||||
|
||||
- (IBAction)closePauseMenu:(id)sender
|
||||
{
|
||||
[[RAGameView get] closePauseMenu];
|
||||
apple_is_paused = false;
|
||||
|
||||
btpad_set_inquiry_state(false);
|
||||
}
|
||||
|
||||
- (IBAction)showSettings
|
||||
{
|
||||
[self pushViewController:[[RASettingsList alloc] initWithModule:_module] animated:YES];
|
||||
}
|
||||
|
||||
- (IBAction)showSystemSettings
|
||||
{
|
||||
[self pushViewController:[RASystemSettingsList new] animated:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@autoreleasepool {
|
||||
#if defined(HAVE_DEBUG_FILELOG) && (TARGET_IPHONE_SIMULATOR == 0)
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
NSString *documentsDirectory = [paths objectAtIndex:0];
|
||||
NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console_stdout.log"];
|
||||
freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stdout);
|
||||
freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stderr);
|
||||
#endif
|
||||
return UIApplicationMain(argc, argv, NSStringFromClass([RApplication class]), NSStringFromClass([RetroArch_iOS class]));
|
||||
}
|
||||
}
|
@ -345,7 +345,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
||||
config_file_free(config);
|
||||
}
|
||||
|
||||
[[RetroArch_iOS get] refreshConfig];
|
||||
apple_refresh_config();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user