mirror of
https://github.com/CTCaer/RetroArch.git
synced 2024-12-14 06:18:34 +00:00
commit
7985de4eb8
@ -92,10 +92,9 @@ void* rarch_main_ios(void* args)
|
||||
|
||||
#ifdef HAVE_RGUI
|
||||
char* system_directory = ios_get_rarch_system_directory();
|
||||
strlcpy(g_extern.savestate_dir, system_directory,
|
||||
sizeof(g_extern.savestate_dir));
|
||||
strlcpy(g_extern.savefile_dir, system_directory,
|
||||
sizeof(g_extern.savefile_dir));
|
||||
strlcpy(g_extern.savestate_dir, system_directory, sizeof(g_extern.savestate_dir));
|
||||
strlcpy(g_extern.savefile_dir, system_directory, sizeof(g_extern.savefile_dir));
|
||||
free(system_directory);
|
||||
|
||||
menu_init();
|
||||
g_extern.lifecycle_mode_state |= 1ULL << MODE_GAME;
|
||||
@ -168,8 +167,6 @@ void* rarch_main_ios(void* args)
|
||||
|
||||
if (g_extern.main_is_init)
|
||||
rarch_main_deinit();
|
||||
|
||||
free(system_directory);
|
||||
#else
|
||||
while ((g_extern.is_paused && !g_extern.is_oneshot) ? rarch_main_idle_iterate() : rarch_main_iterate());
|
||||
rarch_main_deinit();
|
||||
|
@ -260,6 +260,7 @@ INPUT
|
||||
#include "../ios/RetroArch/input/BTStack/btpad.c"
|
||||
#include "../ios/RetroArch/input/BTStack/btpad_ps3.c"
|
||||
#include "../ios/RetroArch/input/BTStack/btpad_wii.c"
|
||||
#include "../ios/RetroArch/input/BTStack/btpad_queue.c"
|
||||
#elif defined(__BLACKBERRY_QNX__)
|
||||
#include "../blackberry-qnx/qnx_input.c"
|
||||
#endif
|
||||
|
@ -41,8 +41,11 @@
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{160, 237}, {120, 44}}</string>
|
||||
<reference key="NSSuperview" ref="191373211"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<int key="IBUITag">4</int>
|
||||
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
|
||||
<int key="IBUIContentHorizontalAlignment">0</int>
|
||||
<int key="IBUIContentVerticalAlignment">0</int>
|
||||
@ -75,6 +78,7 @@
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{20, 20}, {120, 44}}</string>
|
||||
<reference key="NSSuperview" ref="191373211"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="344367644"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
@ -97,6 +101,7 @@
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{160, 20}, {120, 44}}</string>
|
||||
<reference key="NSSuperview" ref="191373211"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="1033465661"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
@ -119,9 +124,11 @@
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{20, 237}, {120, 44}}</string>
|
||||
<reference key="NSSuperview" ref="191373211"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="61755535"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<int key="IBUITag">1</int>
|
||||
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
|
||||
<int key="IBUIContentHorizontalAlignment">0</int>
|
||||
<int key="IBUIContentVerticalAlignment">0</int>
|
||||
@ -141,9 +148,11 @@
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{20, 186}, {120, 44}}</string>
|
||||
<reference key="NSSuperview" ref="191373211"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="58186559"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<int key="IBUITag">3</int>
|
||||
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
|
||||
<int key="IBUIContentHorizontalAlignment">0</int>
|
||||
<int key="IBUIContentVerticalAlignment">0</int>
|
||||
@ -163,9 +172,11 @@
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{160, 186}, {120, 44}}</string>
|
||||
<reference key="NSSuperview" ref="191373211"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="721040644"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<int key="IBUITag">2</int>
|
||||
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
|
||||
<int key="IBUIContentHorizontalAlignment">0</int>
|
||||
<int key="IBUIContentVerticalAlignment">0</int>
|
||||
@ -185,14 +196,16 @@
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{20, 135}, {260, 44}}</string>
|
||||
<reference key="NSSuperview" ref="191373211"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="694263183"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<int key="IBUITag">1</int>
|
||||
<int key="IBUITag">10</int>
|
||||
<string key="targetRuntimeIdentifier">IBIPadFramework</string>
|
||||
<int key="IBNumberOfSegments">10</int>
|
||||
<int key="IBSelectedSegmentIndex">0</int>
|
||||
<array key="IBSegmentTitles">
|
||||
<string>0</string>
|
||||
<string>1</string>
|
||||
<string>2</string>
|
||||
<string>3</string>
|
||||
@ -202,7 +215,6 @@
|
||||
<string>7</string>
|
||||
<string>8</string>
|
||||
<string>9</string>
|
||||
<string>10</string>
|
||||
</array>
|
||||
<array class="NSMutableArray" key="IBSegmentWidths">
|
||||
<real value="0.0"/>
|
||||
@ -258,6 +270,7 @@
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{20, 71}, {120, 44}}</string>
|
||||
<reference key="NSSuperview" ref="191373211"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="374409903"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
@ -280,6 +293,7 @@
|
||||
<int key="NSvFlags">292</int>
|
||||
<string key="NSFrame">{{160, 71}, {120, 44}}</string>
|
||||
<reference key="NSSuperview" ref="191373211"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="562513162"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
@ -300,6 +314,7 @@
|
||||
</array>
|
||||
<string key="NSFrame">{{0, 20}, {300, 300}}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
<reference key="NSWindow"/>
|
||||
<reference key="NSNextKeyView" ref="38801877"/>
|
||||
<object class="NSColor" key="IBUIBackgroundColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
@ -324,12 +339,12 @@
|
||||
<array class="NSMutableArray" key="connectionRecords">
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchEventConnection" key="connection">
|
||||
<string key="label">closeGamePressed:</string>
|
||||
<string key="label">basicEvent:</string>
|
||||
<reference key="source" ref="61755535"/>
|
||||
<reference key="destination" ref="372490531"/>
|
||||
<int key="IBEventType">7</int>
|
||||
</object>
|
||||
<int key="connectionID">23</int>
|
||||
<int key="connectionID">215</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchEventConnection" key="connection">
|
||||
@ -342,30 +357,30 @@
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchEventConnection" key="connection">
|
||||
<string key="label">resetGame:</string>
|
||||
<string key="label">basicEvent:</string>
|
||||
<reference key="source" ref="721040644"/>
|
||||
<reference key="destination" ref="372490531"/>
|
||||
<int key="IBEventType">7</int>
|
||||
</object>
|
||||
<int key="connectionID">138</int>
|
||||
<int key="connectionID">214</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchEventConnection" key="connection">
|
||||
<string key="label">saveState:</string>
|
||||
<string key="label">basicEvent:</string>
|
||||
<reference key="source" ref="694263183"/>
|
||||
<reference key="destination" ref="372490531"/>
|
||||
<int key="IBEventType">7</int>
|
||||
</object>
|
||||
<int key="connectionID">137</int>
|
||||
<int key="connectionID">212</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchEventConnection" key="connection">
|
||||
<string key="label">loadState:</string>
|
||||
<string key="label">basicEvent:</string>
|
||||
<reference key="source" ref="58186559"/>
|
||||
<reference key="destination" ref="372490531"/>
|
||||
<int key="IBEventType">7</int>
|
||||
</object>
|
||||
<int key="connectionID">136</int>
|
||||
<int key="connectionID">213</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchEventConnection" key="connection">
|
||||
@ -418,13 +433,13 @@
|
||||
<array class="NSMutableArray" key="children">
|
||||
<reference ref="694263183"/>
|
||||
<reference ref="38801877"/>
|
||||
<reference ref="721040644"/>
|
||||
<reference ref="58186559"/>
|
||||
<reference ref="562513162"/>
|
||||
<reference ref="61755535"/>
|
||||
<reference ref="374409903"/>
|
||||
<reference ref="1033465661"/>
|
||||
<reference ref="344367644"/>
|
||||
<reference ref="721040644"/>
|
||||
</array>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
@ -515,9 +530,20 @@
|
||||
<nil key="activeLocalization"/>
|
||||
<dictionary class="NSMutableDictionary" key="localizations"/>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">210</int>
|
||||
<int key="maxID">215</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<array class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">RetroArch_iOS</string>
|
||||
<string key="superclassName">UINavigationController</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/RetroArch_iOS.h</string>
|
||||
</object>
|
||||
</object>
|
||||
</array>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes"/>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBIPadFramework</string>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
|
@ -81,21 +81,21 @@ static UIView* g_pause_indicator_view;
|
||||
- (void)openPauseMenu
|
||||
{
|
||||
// Setup save state selector
|
||||
UISegmentedControl* stateSelect = (UISegmentedControl*)[g_pause_view viewWithTag:1];
|
||||
UISegmentedControl* stateSelect = (UISegmentedControl*)[g_pause_view viewWithTag:10];
|
||||
stateSelect.selectedSegmentIndex = (g_extern.state_slot < 10) ? g_extern.state_slot : -1;
|
||||
|
||||
g_extern.is_paused = true;
|
||||
|
||||
//
|
||||
[UIView animateWithDuration:0.2
|
||||
animations:^ { g_pause_view.alpha = 1.0f; }
|
||||
completion:^(BOOL finished){}];
|
||||
animations:^{ g_pause_view.alpha = 1.0f; }
|
||||
completion:^(BOOL finished) { }];
|
||||
}
|
||||
|
||||
- (void)closePauseMenu
|
||||
{
|
||||
[UIView animateWithDuration:0.2
|
||||
animations:^ { g_pause_view.alpha = 0.0f; }
|
||||
animations:^{ g_pause_view.alpha = 0.0f; }
|
||||
completion:^(BOOL finished) { }
|
||||
];
|
||||
|
||||
@ -105,9 +105,9 @@ static UIView* g_pause_indicator_view;
|
||||
- (void)hidePauseButton
|
||||
{
|
||||
[UIView animateWithDuration:0.2
|
||||
animations:^ { g_pause_indicator_view.alpha = ALMOST_INVISIBLE; }
|
||||
completion:^(BOOL finished) { }
|
||||
];
|
||||
animations:^{ g_pause_indicator_view.alpha = ALMOST_INVISIBLE; }
|
||||
completion:^(BOOL finished) { }
|
||||
];
|
||||
}
|
||||
|
||||
- (void)suspend
|
||||
@ -170,9 +170,6 @@ void ios_flip_game_view()
|
||||
{
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
[g_view display];
|
||||
|
||||
// HACK: While here, copy input structures
|
||||
ios_copy_input(&g_ios_input_data);
|
||||
});
|
||||
g_fast_forward_skips = g_is_syncing ? 0 : 3;
|
||||
}
|
||||
|
@ -22,7 +22,6 @@
|
||||
static NSMutableArray* g_messages;
|
||||
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
#ifndef HAVE_DEBUG_DIAGLOG
|
||||
void ios_add_log_message(const char* format, ...)
|
||||
{
|
||||
pthread_mutex_lock(&g_lock);
|
||||
@ -39,54 +38,6 @@ void ios_add_log_message(const char* format, ...)
|
||||
|
||||
pthread_mutex_unlock(&g_lock);
|
||||
}
|
||||
#else
|
||||
static FILE* old_stdout;
|
||||
static FILE* old_stderr;
|
||||
static FILE* log_stream;
|
||||
|
||||
static int stdout_write(void* mem_buffer, const char* data, int len)
|
||||
{
|
||||
pthread_mutex_lock(&g_lock);
|
||||
|
||||
g_messages = g_messages ? g_messages : [NSMutableArray array];
|
||||
|
||||
char buffer[len + 10];
|
||||
strncpy(buffer, data, len);
|
||||
buffer[len] = 0;
|
||||
|
||||
[g_messages addObject:[NSString stringWithFormat:@"%s", buffer]];
|
||||
|
||||
pthread_mutex_unlock(&g_lock);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void ios_log_init()
|
||||
{
|
||||
if (!log_stream)
|
||||
{
|
||||
old_stdout = stdout;
|
||||
old_stderr = stderr;
|
||||
|
||||
log_stream = fwopen(0, stdout_write);
|
||||
setvbuf(log_stream, 0, _IOLBF, 0);
|
||||
|
||||
stdout = log_stream;
|
||||
stderr = log_stream;
|
||||
}
|
||||
}
|
||||
|
||||
void ios_log_quit()
|
||||
{
|
||||
if (log_stream)
|
||||
{
|
||||
stdout = old_stdout;
|
||||
stderr = old_stderr;
|
||||
fclose(log_stream);
|
||||
log_stream = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@implementation RALogView
|
||||
|
||||
|
@ -165,7 +165,7 @@ static NSString* build_string_pair(NSString* stringA, NSString* stringB)
|
||||
if (indexPath.section == _firmwareSectionIndex)
|
||||
{
|
||||
NSString* item = (NSString*)[self itemForIndexPath:indexPath];
|
||||
[RetroArch_iOS displayErrorMessage:objc_getAssociatedObject(item, "OTHER") withTitle:item];
|
||||
ios_display_alert(objc_getAssociatedObject(item, "OTHER"), item);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,18 +17,12 @@
|
||||
|
||||
@interface RetroArch_iOS : UINavigationController<UIApplicationDelegate, UINavigationControllerDelegate>
|
||||
|
||||
+ (void)displayErrorMessage:(NSString*)message;
|
||||
+ (void)displayErrorMessage:(NSString*)message withTitle:(NSString*)title;
|
||||
|
||||
+ (RetroArch_iOS*)get;
|
||||
|
||||
- (void)runGame:(NSString*)path withModule:(RAModuleInfo*)module;
|
||||
- (void)refreshConfig;
|
||||
- (void)refreshSystemConfig;
|
||||
|
||||
- (IBAction)startBluetooth;
|
||||
- (IBAction)stopBluetooth;
|
||||
|
||||
@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
|
||||
@ -36,4 +30,7 @@
|
||||
@end
|
||||
|
||||
// utility.m
|
||||
extern void ios_display_alert(NSString* message, NSString* title);
|
||||
extern void ios_clear_config_hack();
|
||||
extern bool path_make_and_check_directory(const char* path, mode_t mode, int amode);
|
||||
extern NSString* ios_get_value_from_config(config_file_t* config, NSString* name, NSString* defaultValue);
|
||||
|
@ -115,7 +115,7 @@
|
||||
}
|
||||
}
|
||||
else
|
||||
[RetroArch_iOS displayErrorMessage:[NSString stringWithFormat:@"Browsed path is not a directory: %@", _path]];
|
||||
ios_display_alert([NSString stringWithFormat:@"Browsed path is not a directory: %@", _path], 0);
|
||||
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
@ -129,8 +129,8 @@
|
||||
else
|
||||
{
|
||||
if (access(_path.UTF8String, R_OK | W_OK | X_OK))
|
||||
[RetroArch_iOS displayErrorMessage:@"The directory containing the selected file has limited permissions. This may "
|
||||
"prevent zipped games from loading, and will cause some cores to not function."];
|
||||
ios_display_alert(@"The directory containing the selected file has limited permissions. This may "
|
||||
"prevent zipped games from loading, and will cause some cores to not function.", 0);
|
||||
|
||||
[[RetroArch_iOS get] pushViewController:[[RAModuleList alloc] initWithGame:path.path] animated:YES];
|
||||
}
|
||||
@ -199,7 +199,7 @@
|
||||
if (info && info.data)
|
||||
[RetroArch_iOS.get pushViewController:[[RAModuleInfoList alloc] initWithModuleInfo:info] animated:YES];
|
||||
else
|
||||
[RetroArch_iOS displayErrorMessage:@"No information available."];
|
||||
ios_display_alert(@"No information available.", 0);
|
||||
}
|
||||
|
||||
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
|
@ -37,9 +37,8 @@ static struct
|
||||
GRAB(bt_send_l2cap),
|
||||
GRAB(run_loop_init),
|
||||
GRAB(run_loop_execute),
|
||||
GRAB(btstack_get_system_bluetooth_enabled),
|
||||
|
||||
GRAB(btstack_set_power_mode),
|
||||
GRAB(btstack_set_system_bluetooth_enabled),
|
||||
GRAB(hci_delete_stored_link_key),
|
||||
GRAB(hci_disconnect),
|
||||
GRAB(hci_read_bd_addr),
|
||||
@ -65,7 +64,7 @@ static bool btstack_loaded;
|
||||
static bool btstack_open;
|
||||
static bool btstack_poweron;
|
||||
|
||||
bool btstack_load()
|
||||
bool btstack_try_load()
|
||||
{
|
||||
assert(sizeof(void**) == sizeof(void(*)()));
|
||||
|
||||
@ -109,47 +108,28 @@ bool btstack_load()
|
||||
return true;
|
||||
}
|
||||
|
||||
void btstack_start()
|
||||
void btstack_set_poweron(bool on)
|
||||
{
|
||||
if (!btstack_load())
|
||||
if (!btstack_try_load())
|
||||
return;
|
||||
|
||||
if (!btstack_open)
|
||||
|
||||
if (!btstack_open && bt_open_ptr())
|
||||
{
|
||||
if (bt_open_ptr())
|
||||
{
|
||||
ios_add_log_message("BTstack: bt_open failed");
|
||||
btstack_loaded = false;
|
||||
return;
|
||||
}
|
||||
ios_add_log_message("BTstack: bt_open failed");
|
||||
btstack_loaded = false;
|
||||
return;
|
||||
}
|
||||
|
||||
btstack_open = true;
|
||||
if (!btstack_poweron)
|
||||
if (on != btstack_poweron)
|
||||
{
|
||||
ios_add_log_message("BTstack: Turning on");
|
||||
bt_send_cmd_ptr(btstack_set_power_mode_ptr, HCI_POWER_ON);
|
||||
btstack_poweron = true;
|
||||
}
|
||||
}
|
||||
|
||||
void btstack_stop()
|
||||
{
|
||||
if (btstack_load() && btstack_open && btstack_poweron)
|
||||
{
|
||||
ios_add_log_message("BTstack: Turning off");
|
||||
bt_send_cmd_ptr(btstack_set_power_mode_ptr, HCI_POWER_OFF);
|
||||
btstack_poweron = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool btstack_is_loaded()
|
||||
{
|
||||
return btstack_load();
|
||||
btstack_poweron = on;
|
||||
ios_add_log_message("BTstack: Turning %s", on ? "on" : "off");
|
||||
bt_send_cmd_ptr(btstack_set_power_mode_ptr, on ? HCI_POWER_ON : HCI_POWER_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
bool btstack_is_running()
|
||||
{
|
||||
return btstack_poweron;
|
||||
}
|
||||
|
||||
|
@ -20,10 +20,8 @@
|
||||
#include "btstack/utils.h"
|
||||
#include "btstack/btstack.h"
|
||||
|
||||
bool btstack_load();
|
||||
void btstack_start();
|
||||
void btstack_stop();
|
||||
bool btstack_is_loaded();
|
||||
bool btstack_try_load();
|
||||
void btstack_set_poweron(bool on);
|
||||
bool btstack_is_running();
|
||||
|
||||
#ifndef BUILDING_BTDYNAMIC
|
||||
@ -41,9 +39,7 @@ BTDIMPORT void (*bt_send_l2cap_ptr)(uint16_t local_cid, uint8_t *data, uint16_t
|
||||
BTDIMPORT void (*run_loop_init_ptr)(RUN_LOOP_TYPE type);
|
||||
BTDIMPORT void (*run_loop_execute_ptr)();
|
||||
|
||||
BTDIMPORT const hci_cmd_t* btstack_get_system_bluetooth_enabled_ptr;
|
||||
BTDIMPORT const hci_cmd_t* btstack_set_power_mode_ptr;
|
||||
BTDIMPORT const hci_cmd_t* btstack_set_system_bluetooth_enabled_ptr;
|
||||
BTDIMPORT const hci_cmd_t* hci_delete_stored_link_key_ptr;
|
||||
BTDIMPORT const hci_cmd_t* hci_disconnect_ptr;
|
||||
BTDIMPORT const hci_cmd_t* hci_read_bd_addr_ptr;
|
||||
|
@ -23,67 +23,94 @@
|
||||
#include "../../rarch_wrapper.h"
|
||||
#include "btdynamic.h"
|
||||
#include "btpad.h"
|
||||
#include "btpad_queue.h"
|
||||
#include "wiimote.h"
|
||||
|
||||
static btpad_connection_t btpad_connection;
|
||||
static btpad_connection_t btpad_connection[MAX_PADS];
|
||||
static struct btpad_interface* btpad_iface[MAX_PADS];
|
||||
static void* btpad_device[MAX_PADS];
|
||||
static bool inquiry_off;
|
||||
static bool inquiry_running;
|
||||
|
||||
static bool btpad_connection_test(uint16_t handle, bd_addr_t address)
|
||||
// External interface (MAIN THREAD ONLY)
|
||||
void btpad_set_inquiry_state(bool on)
|
||||
{
|
||||
if (handle && btpad_connection.handle && handle != btpad_connection.handle)
|
||||
return false;
|
||||
btpad_connection.handle = handle ? handle : btpad_connection.handle;
|
||||
inquiry_off = !on;
|
||||
|
||||
if (address && btpad_connection.has_address && (BD_ADDR_CMP(address, btpad_connection.address)))
|
||||
return false;
|
||||
|
||||
if (address)
|
||||
{
|
||||
btpad_connection.has_address = true;
|
||||
memcpy(btpad_connection.address, address, sizeof(bd_addr_t));
|
||||
}
|
||||
|
||||
return true;
|
||||
if (!inquiry_off && !inquiry_running)
|
||||
btpad_queue_hci_inquiry(HCI_INQUIRY_LAP, 3, 1);
|
||||
}
|
||||
|
||||
static struct btpad_interface* btpad_iface;
|
||||
static void* btpad_device;
|
||||
|
||||
// MAIN THREAD ONLY
|
||||
uint32_t btpad_get_buttons()
|
||||
uint32_t btpad_get_buttons(uint32_t slot)
|
||||
{
|
||||
return (btpad_device && btpad_iface) ? btpad_iface->get_buttons(btpad_device) : 0;
|
||||
if (slot < MAX_PADS && btpad_device[slot] && btpad_iface[slot])
|
||||
return btpad_iface[slot]->get_buttons(btpad_device[slot]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16_t btpad_get_axis(unsigned axis)
|
||||
int16_t btpad_get_axis(uint32_t slot, unsigned axis)
|
||||
{
|
||||
return (btpad_device && btpad_iface) ? btpad_iface->get_axis(btpad_device, axis) : 0;
|
||||
if (slot < MAX_PADS && btpad_device[slot] && btpad_iface[slot])
|
||||
return btpad_iface[slot]->get_axis(btpad_device[slot], axis);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void btpad_disconnect_pad()
|
||||
// Internal interface:
|
||||
static int32_t btpad_find_slot_for(uint16_t handle, bd_addr_t address)
|
||||
{
|
||||
if (btpad_iface && btpad_device)
|
||||
for (int i = 0; i < MAX_PADS; i ++)
|
||||
{
|
||||
ios_add_log_message("BTpad: Disconnecting");
|
||||
|
||||
btpad_iface->disconnect(btpad_device);
|
||||
btpad_device = 0;
|
||||
btpad_iface = 0;
|
||||
if (!btpad_connection[i].handle && !btpad_connection[i].has_address)
|
||||
continue;
|
||||
|
||||
if (handle && btpad_connection[i].handle && handle != btpad_connection[i].handle)
|
||||
continue;
|
||||
|
||||
if (address && btpad_connection[i].has_address && (BD_ADDR_CMP(address, btpad_connection[i].address)))
|
||||
continue;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
if (btpad_connection.handle)
|
||||
bt_send_cmd_ptr(hci_disconnect_ptr, btpad_connection.handle, 0x15);
|
||||
|
||||
memset(&btpad_connection, 0, sizeof(btpad_connection_t));
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void btpad_connect_pad()
|
||||
static int32_t btpad_find_slot_with_state(enum btpad_state state)
|
||||
{
|
||||
if (btpad_connection.state == BTPAD_CONNECTED)
|
||||
btpad_disconnect_pad();
|
||||
memset(&btpad_connection, 0, sizeof(btpad_connection_t));
|
||||
for (int i = 0; i < MAX_PADS; i ++)
|
||||
if (btpad_connection[i].state == state)
|
||||
return i;
|
||||
|
||||
ios_add_log_message("BTpad: Requesting local address");
|
||||
bt_send_cmd_ptr(hci_read_bd_addr_ptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void btpad_disconnect_pad(uint32_t slot)
|
||||
{
|
||||
if (slot > MAX_PADS)
|
||||
return;
|
||||
|
||||
if (btpad_iface[slot] && btpad_device[slot])
|
||||
{
|
||||
ios_add_log_message("BTpad: Disconnecting slot %d", slot);
|
||||
|
||||
btpad_iface[slot]->disconnect(btpad_device[slot]);
|
||||
btpad_device[slot] = 0;
|
||||
btpad_iface[slot] = 0;
|
||||
}
|
||||
|
||||
if (btpad_connection[slot].handle)
|
||||
btpad_queue_hci_disconnect(btpad_connection[slot].handle, 0x15);
|
||||
|
||||
memset(&btpad_connection[slot], 0, sizeof(btpad_connection_t));
|
||||
}
|
||||
|
||||
static void btpad_disconnect_all_pads()
|
||||
{
|
||||
for (int i = 0; i < MAX_PADS; i ++)
|
||||
btpad_disconnect_pad(i);
|
||||
}
|
||||
|
||||
void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
|
||||
@ -94,45 +121,41 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
|
||||
{
|
||||
switch (packet[0])
|
||||
{
|
||||
case BTSTACK_EVENT_STATE:
|
||||
case BTSTACK_EVENT_STATE:
|
||||
{
|
||||
if (packet[2] == HCI_STATE_WORKING)
|
||||
btpad_connect_pad();
|
||||
{
|
||||
btpad_queue_reset();
|
||||
|
||||
btpad_queue_hci_read_bd_addr();
|
||||
bt_send_cmd_ptr(l2cap_register_service_ptr, PSM_HID_CONTROL, 672); // TODO: Where did I get 672 for mtu?
|
||||
bt_send_cmd_ptr(l2cap_register_service_ptr, PSM_HID_INTERRUPT, 672);
|
||||
btpad_queue_hci_inquiry(HCI_INQUIRY_LAP, 3, 1);
|
||||
|
||||
btpad_queue_run(1);
|
||||
}
|
||||
else if(packet[2] > HCI_STATE_WORKING && btpad_iface && btpad_device)
|
||||
btpad_disconnect_pad();
|
||||
break;
|
||||
{
|
||||
btpad_disconnect_all_pads();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_EVENT_COMMAND_STATUS:
|
||||
{
|
||||
btpad_queue_run(packet[3]);
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_EVENT_COMMAND_COMPLETE:
|
||||
{
|
||||
btpad_queue_run(packet[2]);
|
||||
|
||||
if (COMMAND_COMPLETE_EVENT(packet, (*hci_read_bd_addr_ptr)))
|
||||
{
|
||||
if (packet[5])
|
||||
ios_add_log_message("BTpad: Failed to get local address (E: %02X)", packet[5]);
|
||||
else
|
||||
{
|
||||
bt_flip_addr_ptr(event_addr, &packet[6]);
|
||||
ios_add_log_message("BTpad: Local address is %s", bd_addr_to_str_ptr(event_addr));
|
||||
}
|
||||
|
||||
ios_add_log_message("BTpad: Registering HID INTERRUPT service");
|
||||
bt_send_cmd_ptr(l2cap_register_service_ptr, PSM_HID_INTERRUPT, 672);
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_SERVICE_REGISTERED:
|
||||
{
|
||||
uint32_t psm = READ_BT_16(packet, 3);
|
||||
if (packet[2])
|
||||
ios_add_log_message("BTpad: Failed to register HID service (PSM: %02X, E: %02X)", psm, packet[2]);
|
||||
else if (psm == PSM_HID_INTERRUPT)
|
||||
{
|
||||
ios_add_log_message("BTpad: HID INTERRUPT service registered");
|
||||
ios_add_log_message("BTpad: Registering HID CONTROL service");
|
||||
bt_send_cmd_ptr(l2cap_register_service_ptr, PSM_HID_CONTROL, 672);
|
||||
}
|
||||
else if(psm == PSM_HID_CONTROL)
|
||||
{
|
||||
ios_add_log_message("BTpad: HID CONTROL service registered");
|
||||
ios_add_log_message("BTpad: Starting inquiry");
|
||||
bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, 3, 1);
|
||||
bt_flip_addr_ptr(event_addr, &packet[6]);
|
||||
if (!packet[5]) ios_add_log_message("BTpad: Local address is %s", bd_addr_to_str_ptr(event_addr));
|
||||
else ios_add_log_message("BTpad: Failed to get local address (Status: %02X)", packet[5]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -142,15 +165,20 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
|
||||
if (packet[2])
|
||||
{
|
||||
bt_flip_addr_ptr(event_addr, &packet[3]);
|
||||
if (btpad_connection_test(0, event_addr))
|
||||
|
||||
const int32_t slot = btpad_find_slot_with_state(BTPAD_EMPTY);
|
||||
if (slot >= 0)
|
||||
{
|
||||
btpad_connection.state = BTPAD_WANT_INQ_COMPLETE;
|
||||
ios_add_log_message("BTpad: Inquiry found device (Slot %d)", slot);
|
||||
|
||||
btpad_connection.page_scan_repetition_mode = packet [3 + packet[2] * (6)];
|
||||
btpad_connection.class = READ_BT_24(packet, 3 + packet[2] * (6+1+1+1));
|
||||
btpad_connection.clock_offset = READ_BT_16(packet, 3 + packet[2] * (6+1+1+1+3)) & 0x7fff;
|
||||
memcpy(btpad_connection[slot].address, event_addr, sizeof(bd_addr_t));
|
||||
|
||||
ios_add_log_message("BTpad: Inquiry found device");
|
||||
btpad_connection[slot].has_address = true;
|
||||
btpad_connection[slot].state = BTPAD_CONNECTING;
|
||||
btpad_connection[slot].slot = slot;
|
||||
|
||||
bt_send_cmd_ptr(l2cap_create_channel_ptr, btpad_connection[slot].address, PSM_HID_CONTROL);
|
||||
bt_send_cmd_ptr(l2cap_create_channel_ptr, btpad_connection[slot].address, PSM_HID_INTERRUPT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -158,62 +186,50 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
|
||||
|
||||
case HCI_EVENT_INQUIRY_COMPLETE:
|
||||
{
|
||||
if (btpad_connection.state == BTPAD_WANT_INQ_COMPLETE)
|
||||
{
|
||||
ios_add_log_message("BTpad: Got inquiry complete; connecting\n");
|
||||
bt_send_cmd_ptr(l2cap_create_channel_ptr, btpad_connection.address, PSM_HID_CONTROL);
|
||||
}
|
||||
else if(btpad_connection.state == BTPAD_EMPTY)
|
||||
{
|
||||
if (btpad_connection.laps < 40)
|
||||
{
|
||||
btpad_connection.laps ++;
|
||||
bt_send_cmd_ptr(hci_inquiry_ptr, HCI_INQUIRY_LAP, 3, 1);
|
||||
}
|
||||
else
|
||||
ios_add_log_message("BTpad: Did not find wiimote, will stop searching");
|
||||
}
|
||||
// TODO: Check performance and battery effect of this
|
||||
|
||||
inquiry_running = !inquiry_off;
|
||||
|
||||
if (inquiry_running)
|
||||
btpad_queue_hci_inquiry(HCI_INQUIRY_LAP, 3, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_CHANNEL_OPENED:
|
||||
{
|
||||
const uint8_t status = packet[2];
|
||||
bt_flip_addr_ptr(event_addr, &packet[3]);
|
||||
const uint16_t handle = READ_BT_16(packet, 9);
|
||||
const uint16_t psm = READ_BT_16(packet, 11);
|
||||
const uint16_t channel_id = READ_BT_16(packet, 13);
|
||||
|
||||
if (!btpad_connection_test(handle, event_addr))
|
||||
{
|
||||
ios_add_log_message("BTpad: Incoming L2CAP connection not recognized; ignoring");
|
||||
break;
|
||||
}
|
||||
const int32_t slot = btpad_find_slot_for(handle, event_addr);
|
||||
|
||||
if (status == 0)
|
||||
if (!packet[2])
|
||||
{
|
||||
ios_add_log_message("BTpad: L2CAP channel opened for psm: %02X", psm);
|
||||
if (slot < 0)
|
||||
{
|
||||
ios_add_log_message("BTpad: Got L2CAP 'Channel Opened' event for unrecognized device");
|
||||
break;
|
||||
}
|
||||
|
||||
ios_add_log_message("BTpad: L2CAP channel opened: (Slot: %d, PSM: %02X)", slot, psm);
|
||||
btpad_connection[slot].handle = handle;
|
||||
|
||||
if (psm == PSM_HID_CONTROL)
|
||||
{
|
||||
btpad_connection.channels[0] = channel_id;
|
||||
|
||||
ios_add_log_message("BTpad: Got HID CONTROL channel; Opening INTERRUPT");
|
||||
bt_send_cmd_ptr(l2cap_create_channel_ptr, btpad_connection.address, PSM_HID_INTERRUPT);
|
||||
}
|
||||
btpad_connection[slot].channels[0] = channel_id;
|
||||
else if (psm == PSM_HID_INTERRUPT)
|
||||
{
|
||||
btpad_connection.channels[1] = channel_id;
|
||||
|
||||
ios_add_log_message("BTpad: Got HID INTERRUPT channel; Requesting name");
|
||||
bt_send_cmd_ptr(hci_remote_name_request_ptr, btpad_connection.address, btpad_connection.page_scan_repetition_mode,
|
||||
0, btpad_connection.clock_offset | 0x8000);
|
||||
}
|
||||
btpad_connection[slot].channels[1] = channel_id;
|
||||
else
|
||||
ios_add_log_message("BTpad: Got unknown L2CAP channel, ignoring");
|
||||
ios_add_log_message("BTpad: Got unknown L2CAP PSM, ignoring (Slot: %d, PSM: %02X)", slot, psm);
|
||||
|
||||
if (btpad_connection[slot].channels[0] && btpad_connection[slot].channels[1])
|
||||
{
|
||||
ios_add_log_message("BTpad: Got both L2CAP channels, requesting name (Slot: %d)", slot);
|
||||
btpad_queue_hci_remote_name_request(btpad_connection[slot].address, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
ios_add_log_message("BTpad: Failed to open WiiMote L2CAP channel (PSM: %02X, E: %02X)", psm, status);
|
||||
ios_add_log_message("BTpad: Got failed L2CAP 'Channel Opened' event (Slot %d, PSM: %02X, Status: %02X)", -1, psm, packet[2]);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -223,31 +239,28 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
|
||||
const uint16_t handle = READ_BT_16(packet, 8);
|
||||
const uint32_t psm = READ_BT_16(packet, 10);
|
||||
const uint32_t channel_id = READ_BT_16(packet, 12);
|
||||
|
||||
const unsigned interrupt = (psm == PSM_HID_INTERRUPT) ? 1 : 0;
|
||||
|
||||
ios_add_log_message("BTpad: Incoming L2CAP connection for PSM: %02X", psm);
|
||||
|
||||
if (!btpad_connection_test(handle, event_addr))
|
||||
int32_t slot = btpad_find_slot_for(handle, event_addr);
|
||||
if (slot < 0)
|
||||
{
|
||||
ios_add_log_message("BTpad: Connection is for unregnized handle or address, denying");
|
||||
slot = btpad_find_slot_with_state(BTPAD_EMPTY);
|
||||
|
||||
// TODO: Check error code
|
||||
bt_send_cmd_ptr(l2cap_decline_connection_ptr, 0x15);
|
||||
if (slot >= 0)
|
||||
{
|
||||
ios_add_log_message("BTpad: Got new incoming connection (Slot: %d)", slot);
|
||||
|
||||
break;
|
||||
memcpy(btpad_connection[slot].address, event_addr, sizeof(bd_addr_t));
|
||||
|
||||
btpad_connection[slot].has_address = true;
|
||||
btpad_connection[slot].handle = handle;
|
||||
btpad_connection[slot].state = BTPAD_CONNECTING;
|
||||
btpad_connection[slot].slot = slot;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
btpad_connection.channels[interrupt] = channel_id;
|
||||
|
||||
bt_send_cmd_ptr(l2cap_accept_connection_ptr, btpad_connection.channels[interrupt]);
|
||||
ios_add_log_message("BTpad: L2CAP Connection accepted");
|
||||
|
||||
if (btpad_connection.channels[0] && btpad_connection.channels[1])
|
||||
{
|
||||
ios_add_log_message("BTpad: Got both L2CAP channels, requesting name");
|
||||
bt_send_cmd_ptr(hci_remote_name_request_ptr, btpad_connection.address, 0, 0, 0);
|
||||
}
|
||||
ios_add_log_message("BTpad: Incoming L2CAP connection (Slot: %d, PSM: %02X)", slot, psm);
|
||||
bt_send_cmd_ptr(l2cap_accept_connection_ptr, channel_id);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -255,38 +268,66 @@ void btpad_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
|
||||
{
|
||||
bt_flip_addr_ptr(event_addr, &packet[3]);
|
||||
|
||||
if (!btpad_connection_test(0, event_addr))
|
||||
const int32_t slot = btpad_find_slot_for(0, event_addr);
|
||||
if (slot < 0)
|
||||
{
|
||||
ios_add_log_message("BTpad: Got unexpected remote name, ignoring");
|
||||
break;
|
||||
}
|
||||
|
||||
ios_add_log_message("BTpad: Got %200s", (char*)&packet[9]);
|
||||
ios_add_log_message("BTpad: Got %.200s (Slot: %d)", (char*)&packet[9], slot);
|
||||
if (strncmp((char*)&packet[9], "PLAYSTATION(R)3 Controller", 26) == 0)
|
||||
btpad_iface = &btpad_ps3;
|
||||
btpad_iface[slot] = &btpad_ps3;
|
||||
else if (strncmp((char*)&packet[9], "Nintendo RVL-CNT-01", 19) == 0)
|
||||
btpad_iface = &btpad_wii;
|
||||
btpad_iface[slot] = &btpad_wii;
|
||||
|
||||
if (btpad_iface)
|
||||
if (btpad_iface[slot])
|
||||
{
|
||||
btpad_device = btpad_iface->connect(&btpad_connection);
|
||||
btpad_connection.state = BTPAD_CONNECTED;
|
||||
btpad_device[slot] = btpad_iface[slot]->connect(&btpad_connection[slot]);
|
||||
btpad_connection[slot].state = BTPAD_CONNECTED;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_EVENT_PIN_CODE_REQUEST:
|
||||
{
|
||||
ios_add_log_message("BTpad: Sending PIN");
|
||||
ios_add_log_message("BTpad: Sending WiiMote PIN");
|
||||
|
||||
bt_flip_addr_ptr(event_addr, &packet[2]);
|
||||
bt_send_cmd_ptr(hci_pin_code_request_reply_ptr, event_addr, 6, &packet[2]);
|
||||
btpad_queue_hci_pin_code_request_reply(event_addr, &packet[2]);
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_EVENT_DISCONNECTION_COMPLETE:
|
||||
{
|
||||
const uint32_t handle = READ_BT_16(packet, 3);
|
||||
|
||||
if (!packet[2])
|
||||
{
|
||||
const int32_t slot = btpad_find_slot_for(handle, 0);
|
||||
if (slot >= 0)
|
||||
{
|
||||
btpad_connection[slot].handle = 0;
|
||||
btpad_disconnect_pad(slot);
|
||||
|
||||
ios_add_log_message("BTpad: Device disconnected (Slot: %d)", slot);
|
||||
}
|
||||
}
|
||||
else
|
||||
ios_add_log_message("BTpad: Got failed 'Disconnection Complete' event (Status: %02X)", packet[2]);
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_SERVICE_REGISTERED:
|
||||
{
|
||||
if (!packet[2])
|
||||
ios_add_log_message("BTpad: Got failed 'Service Registered' event (PSM: %02X, Status: %02X)", READ_BT_16(packet, 3), packet[2]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (btpad_device && btpad_iface)
|
||||
btpad_iface->packet_handler(btpad_device, packet_type, channel, packet, size);
|
||||
for (int i = 0; i < MAX_PADS; i ++)
|
||||
if (btpad_device[i] && btpad_iface[i] && (btpad_connection[i].channels[0] == channel || btpad_connection[i].channels[1] == channel))
|
||||
btpad_iface[i]->packet_handler(btpad_device[i], packet_type, channel, packet, size);
|
||||
}
|
||||
|
@ -18,26 +18,24 @@
|
||||
|
||||
#include "btstack/btstack.h"
|
||||
|
||||
uint32_t btpad_get_buttons();
|
||||
int16_t btpad_get_axis(unsigned axis);
|
||||
void btpad_set_inquiry_state(bool on);
|
||||
|
||||
uint32_t btpad_get_buttons(uint32_t slot);
|
||||
int16_t btpad_get_axis(uint32_t slot, unsigned axis);
|
||||
|
||||
// Private interface
|
||||
enum btpad_state { BTPAD_EMPTY, BTPAD_WANT_INQ_COMPLETE, BTPAD_CONNECTED };
|
||||
enum btpad_state { BTPAD_EMPTY, BTPAD_CONNECTING, BTPAD_CONNECTED };
|
||||
|
||||
typedef struct
|
||||
{
|
||||
enum btpad_state state;
|
||||
|
||||
uint32_t slot;
|
||||
uint16_t handle;
|
||||
|
||||
bool has_address;
|
||||
bd_addr_t address;
|
||||
|
||||
uint32_t laps;
|
||||
uint32_t page_scan_repetition_mode;
|
||||
uint32_t class;
|
||||
uint32_t clock_offset;
|
||||
|
||||
uint16_t channels[2]; //0: Control, 1: Interrupt
|
||||
|
||||
bool connected;
|
||||
@ -47,7 +45,6 @@ struct btpad_interface
|
||||
{
|
||||
void* (*connect)(const btpad_connection_t* connection);
|
||||
void (*disconnect)(void* device);
|
||||
void (*set_leds)(void* device, unsigned leds);
|
||||
|
||||
uint32_t (*get_buttons)(void* device);
|
||||
int16_t (*get_axis)(void* device, unsigned axis);
|
||||
|
@ -31,39 +31,16 @@ struct btpad_ps3_data
|
||||
uint32_t handle;
|
||||
uint32_t channels[2];
|
||||
|
||||
uint32_t slot;
|
||||
bool have_led;
|
||||
};
|
||||
|
||||
static void btpad_ps3_setleds(struct btpad_ps3_data* device, unsigned leds);
|
||||
static void* btpad_ps3_connect(const btpad_connection_t* connection)
|
||||
{
|
||||
struct btpad_ps3_data* device = malloc(sizeof(struct btpad_ps3_data));
|
||||
memset(device, 0, sizeof(*device));
|
||||
|
||||
memcpy(device->address, connection->address, BD_ADDR_LEN);
|
||||
device->handle = connection->handle;
|
||||
device->channels[0] = connection->channels[0];
|
||||
device->channels[1] = connection->channels[1];
|
||||
|
||||
// Magic packet to start reports
|
||||
static uint8_t data[] = {0x53, 0xF4, 0x42, 0x03, 0x00, 0x00};
|
||||
bt_send_l2cap_ptr(device->channels[0], data, 6);
|
||||
|
||||
// Without this the digital buttons won't be reported
|
||||
btpad_ps3_setleds(device, 1);
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
static void btpad_ps3_disconnect(struct btpad_ps3_data* device)
|
||||
{
|
||||
}
|
||||
|
||||
static void btpad_ps3_setleds(struct btpad_ps3_data* device, unsigned leds)
|
||||
static void btpad_ps3_send_control(struct btpad_ps3_data* device)
|
||||
{
|
||||
// TODO: Can this be modified to turn of motion tracking?
|
||||
static uint8_t report_buffer[] = {
|
||||
0x52, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x52, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0x27, 0x10, 0x00, 0x32,
|
||||
0xff, 0x27, 0x10, 0x00, 0x32,
|
||||
@ -74,13 +51,55 @@ static void btpad_ps3_setleds(struct btpad_ps3_data* device, unsigned leds)
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
report_buffer[11] = (leds & 0xF) << 1;
|
||||
report_buffer[11] = 1 << ((device->slot % 4) + 1);
|
||||
bt_send_l2cap_ptr(device->channels[0], report_buffer, sizeof(report_buffer));
|
||||
}
|
||||
|
||||
static void* btpad_ps3_connect(const btpad_connection_t* connection)
|
||||
{
|
||||
struct btpad_ps3_data* device = malloc(sizeof(struct btpad_ps3_data));
|
||||
memset(device, 0, sizeof(*device));
|
||||
|
||||
memcpy(device->address, connection->address, BD_ADDR_LEN);
|
||||
device->handle = connection->handle;
|
||||
device->channels[0] = connection->channels[0];
|
||||
device->channels[1] = connection->channels[1];
|
||||
device->slot = connection->slot;
|
||||
|
||||
// Magic packet to start reports
|
||||
static uint8_t data[] = {0x53, 0xF4, 0x42, 0x03, 0x00, 0x00};
|
||||
bt_send_l2cap_ptr(device->channels[0], data, 6);
|
||||
|
||||
// Without this the digital buttons won't be reported
|
||||
btpad_ps3_send_control(device);
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
static void btpad_ps3_disconnect(struct btpad_ps3_data* device)
|
||||
{
|
||||
}
|
||||
|
||||
static uint32_t btpad_ps3_get_buttons(struct btpad_ps3_data* device)
|
||||
{
|
||||
return device->data[3] | (device->data[4] << 8) | ((device->data[5] & 1) << 16);
|
||||
#define KEY(X) RETRO_DEVICE_ID_JOYPAD_##X
|
||||
static const uint32_t button_mapping[17] =
|
||||
{
|
||||
KEY(SELECT), KEY(L3), KEY(R3), KEY(START),
|
||||
KEY(UP), KEY(RIGHT), KEY(DOWN), KEY(LEFT),
|
||||
KEY(L2), KEY(R2), KEY(L), KEY(R),
|
||||
KEY(X), KEY(A), KEY(B), KEY(Y),
|
||||
16 //< PS Button
|
||||
};
|
||||
#undef KEY
|
||||
|
||||
const uint32_t pressed_keys = device->data[3] | (device->data[4] << 8) | ((device->data[5] & 1) << 16);
|
||||
uint32_t result = 0;
|
||||
|
||||
for (int i = 0; i < 17; i ++)
|
||||
result |= (pressed_keys & (1 << i)) ? (1 << button_mapping[i]) : 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int16_t btpad_ps3_get_axis(struct btpad_ps3_data* device, unsigned axis)
|
||||
@ -101,11 +120,14 @@ static void btpad_ps3_packet_handler(struct btpad_ps3_data* device, uint8_t pack
|
||||
{
|
||||
if (!device->have_led)
|
||||
{
|
||||
btpad_ps3_setleds(device, 1);
|
||||
btpad_ps3_send_control(device);
|
||||
device->have_led = true;
|
||||
}
|
||||
|
||||
memcpy(device->data, packet, size);
|
||||
g_current_input_data.pad_buttons[device->slot] = btpad_ps3_get_buttons(device);
|
||||
for (int i = 0; i < 4; i ++)
|
||||
g_current_input_data.pad_axis[device->slot][i] = btpad_ps3_get_axis(device, i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,7 +135,6 @@ struct btpad_interface btpad_ps3 =
|
||||
{
|
||||
(void*)&btpad_ps3_connect,
|
||||
(void*)&btpad_ps3_disconnect,
|
||||
(void*)&btpad_ps3_setleds,
|
||||
(void*)&btpad_ps3_get_buttons,
|
||||
(void*)&btpad_ps3_get_axis,
|
||||
(void*)&btpad_ps3_packet_handler
|
||||
|
176
ios/RetroArch/input/BTStack/btpad_queue.c
Normal file
176
ios/RetroArch/input/BTStack/btpad_queue.c
Normal file
@ -0,0 +1,176 @@
|
||||
/* 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 "btdynamic.h"
|
||||
#include "btpad.h"
|
||||
#include "btpad_queue.h"
|
||||
|
||||
struct btpad_queue_command
|
||||
{
|
||||
const hci_cmd_t* command;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t on;
|
||||
} btstack_set_power_mode;
|
||||
|
||||
struct
|
||||
{
|
||||
uint16_t handle;
|
||||
uint8_t reason;
|
||||
} hci_disconnect;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32_t lap;
|
||||
uint8_t length;
|
||||
uint8_t num_responses;
|
||||
} hci_inquiry;
|
||||
|
||||
struct
|
||||
{
|
||||
bd_addr_t bd_addr;
|
||||
uint8_t page_scan_repetition_mode;
|
||||
uint8_t reserved;
|
||||
uint16_t clock_offset;
|
||||
} hci_remote_name_request;
|
||||
|
||||
struct // For wiimote only
|
||||
{
|
||||
bd_addr_t bd_addr;
|
||||
bd_addr_t pin;
|
||||
} hci_pin_code_request_reply;
|
||||
};
|
||||
};
|
||||
|
||||
struct btpad_queue_command commands[64];
|
||||
static uint32_t insert_position;
|
||||
static uint32_t read_position;
|
||||
static uint32_t can_run;
|
||||
|
||||
#define INCPOS(POS) { POS##_position = (POS##_position + 1) % 64; }
|
||||
|
||||
void btpad_queue_reset()
|
||||
{
|
||||
insert_position = 0;
|
||||
read_position = 0;
|
||||
can_run = 1;
|
||||
}
|
||||
|
||||
void btpad_queue_run(uint32_t count)
|
||||
{
|
||||
can_run = count;
|
||||
|
||||
btpad_queue_process();
|
||||
}
|
||||
|
||||
void btpad_queue_process()
|
||||
{
|
||||
for (; can_run && (insert_position != read_position); can_run --)
|
||||
{
|
||||
struct btpad_queue_command* cmd = &commands[read_position];
|
||||
|
||||
if (cmd->command == btstack_set_power_mode_ptr)
|
||||
bt_send_cmd_ptr(cmd->command, cmd->btstack_set_power_mode.on);
|
||||
else if (cmd->command == hci_read_bd_addr_ptr)
|
||||
bt_send_cmd_ptr(cmd->command);
|
||||
else if (cmd->command == hci_disconnect_ptr)
|
||||
bt_send_cmd_ptr(cmd->command, cmd->hci_disconnect.handle, cmd->hci_disconnect.reason);
|
||||
else if (cmd->command == hci_inquiry_ptr)
|
||||
bt_send_cmd_ptr(cmd->command, cmd->hci_inquiry.lap, cmd->hci_inquiry.length, cmd->hci_inquiry.num_responses);
|
||||
else if (cmd->command == hci_remote_name_request_ptr)
|
||||
bt_send_cmd_ptr(cmd->command, cmd->hci_remote_name_request.bd_addr, cmd->hci_remote_name_request.page_scan_repetition_mode,
|
||||
cmd->hci_remote_name_request.reserved, cmd->hci_remote_name_request.clock_offset);
|
||||
else if (cmd->command == hci_pin_code_request_reply_ptr)
|
||||
bt_send_cmd_ptr(cmd->command, cmd->hci_pin_code_request_reply.bd_addr, 6, cmd->hci_pin_code_request_reply.pin);
|
||||
|
||||
INCPOS(read);
|
||||
}
|
||||
}
|
||||
|
||||
void btpad_queue_btstack_set_power_mode(uint8_t on)
|
||||
{
|
||||
struct btpad_queue_command* cmd = &commands[insert_position];
|
||||
|
||||
cmd->command = btstack_set_power_mode_ptr;
|
||||
cmd->btstack_set_power_mode.on = on;
|
||||
|
||||
INCPOS(insert);
|
||||
btpad_queue_process();
|
||||
}
|
||||
|
||||
void btpad_queue_hci_read_bd_addr()
|
||||
{
|
||||
struct btpad_queue_command* cmd = &commands[insert_position];
|
||||
|
||||
cmd->command = hci_read_bd_addr_ptr;
|
||||
|
||||
INCPOS(insert);
|
||||
btpad_queue_process();
|
||||
}
|
||||
|
||||
void btpad_queue_hci_disconnect(uint16_t handle, uint8_t reason)
|
||||
{
|
||||
struct btpad_queue_command* cmd = &commands[insert_position];
|
||||
|
||||
cmd->command = hci_disconnect_ptr;
|
||||
cmd->hci_disconnect.handle = handle;
|
||||
cmd->hci_disconnect.reason = reason;
|
||||
|
||||
INCPOS(insert);
|
||||
btpad_queue_process();
|
||||
}
|
||||
|
||||
void btpad_queue_hci_inquiry(uint32_t lap, uint8_t length, uint8_t num_responses)
|
||||
{
|
||||
struct btpad_queue_command* cmd = &commands[insert_position];
|
||||
|
||||
cmd->command = hci_inquiry_ptr;
|
||||
cmd->hci_inquiry.lap = lap;
|
||||
cmd->hci_inquiry.length = length;
|
||||
cmd->hci_inquiry.num_responses = num_responses;
|
||||
|
||||
INCPOS(insert);
|
||||
btpad_queue_process();
|
||||
}
|
||||
|
||||
void btpad_queue_hci_remote_name_request(bd_addr_t bd_addr, uint8_t page_scan_repetition_mode, uint8_t reserved, uint16_t clock_offset)
|
||||
{
|
||||
struct btpad_queue_command* cmd = &commands[insert_position];
|
||||
|
||||
cmd->command = hci_remote_name_request_ptr;
|
||||
memcpy(cmd->hci_remote_name_request.bd_addr, bd_addr, sizeof(bd_addr_t));
|
||||
cmd->hci_remote_name_request.page_scan_repetition_mode = page_scan_repetition_mode;
|
||||
cmd->hci_remote_name_request.reserved = reserved;
|
||||
cmd->hci_remote_name_request.clock_offset = clock_offset;
|
||||
|
||||
INCPOS(insert);
|
||||
btpad_queue_process();
|
||||
}
|
||||
|
||||
void btpad_queue_hci_pin_code_request_reply(bd_addr_t bd_addr, bd_addr_t pin)
|
||||
{
|
||||
struct btpad_queue_command* cmd = &commands[insert_position];
|
||||
|
||||
cmd->command = hci_pin_code_request_reply_ptr;
|
||||
memcpy(cmd->hci_pin_code_request_reply.bd_addr, bd_addr, sizeof(bd_addr_t));
|
||||
memcpy(cmd->hci_pin_code_request_reply.pin, pin, sizeof(bd_addr_t));
|
||||
|
||||
INCPOS(insert);
|
||||
btpad_queue_process();
|
||||
}
|
||||
|
30
ios/RetroArch/input/BTStack/btpad_queue.h
Normal file
30
ios/RetroArch/input/BTStack/btpad_queue.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __IOS_RARCH_BTPAD_QUEUE_H__
|
||||
#define __IOS_RARCH_BTPAD_QUEUE_H__
|
||||
|
||||
void btpad_queue_reset();
|
||||
void btpad_queue_run(uint32_t count);
|
||||
void btpad_queue_process();
|
||||
|
||||
void btpad_queue_btstack_set_power_mode(uint8_t on);
|
||||
void btpad_queue_hci_read_bd_addr();
|
||||
void btpad_queue_hci_disconnect(uint16_t handle, uint8_t reason);
|
||||
void btpad_queue_hci_inquiry(uint32_t lap, uint8_t length, uint8_t num_responses);
|
||||
void btpad_queue_hci_remote_name_request(bd_addr_t bd_addr, uint8_t page_scan_repetition_mode, uint8_t reserved, uint16_t clock_offset);
|
||||
void btpad_queue_hci_pin_code_request_reply(bd_addr_t bd_addr, bd_addr_t pin);
|
||||
|
||||
#endif
|
@ -31,6 +31,7 @@ static void* btpad_wii_connect(const btpad_connection_t* connection)
|
||||
|
||||
memcpy(device->addr, connection->address, BD_ADDR_LEN);
|
||||
|
||||
device->unid = connection->slot;
|
||||
device->wiiMoteConHandle = connection->handle;
|
||||
device->c_source_cid = connection->channels[0];
|
||||
device->i_source_cid = connection->channels[1];
|
||||
@ -46,11 +47,6 @@ static void btpad_wii_disconnect(struct wiimote_t* device)
|
||||
{
|
||||
}
|
||||
|
||||
static void btpad_wii_setleds(struct wiimote_t* device, unsigned leds)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static uint32_t btpad_wii_get_buttons(struct wiimote_t* device)
|
||||
{
|
||||
return device->btns | (device->exp.classic.btns << 16);
|
||||
@ -86,30 +82,34 @@ static void btpad_wii_packet_handler(struct wiimote_t* device, uint8_t packet_ty
|
||||
case WM_RPT_BTN:
|
||||
{
|
||||
wiimote_pressed_buttons(device, msg);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_RPT_READ:
|
||||
{
|
||||
wiimote_pressed_buttons(device, msg);
|
||||
wiimote_handshake(device, WM_RPT_READ, msg + 5, ((msg[2] & 0xF0) >> 4) + 1);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_RPT_CTRL_STATUS:
|
||||
{
|
||||
wiimote_pressed_buttons(device, msg);
|
||||
wiimote_handshake(device,WM_RPT_CTRL_STATUS,msg,-1);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_RPT_BTN_EXP:
|
||||
{
|
||||
wiimote_pressed_buttons(device, msg);
|
||||
wiimote_handle_expansion(device, msg+2);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_current_input_data.pad_buttons[device->unid] = btpad_wii_get_buttons(device);
|
||||
for (int i = 0; i < 4; i ++)
|
||||
g_current_input_data.pad_axis[device->unid][i] = btpad_wii_get_axis(device, i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,7 +117,6 @@ struct btpad_interface btpad_wii =
|
||||
{
|
||||
(void*)&btpad_wii_connect,
|
||||
(void*)&btpad_wii_disconnect,
|
||||
(void*)&btpad_wii_setleds,
|
||||
(void*)&btpad_wii_get_buttons,
|
||||
(void*)&btpad_wii_get_axis,
|
||||
(void*)&btpad_wii_packet_handler
|
||||
|
@ -13,7 +13,10 @@
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <unistd.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
#include "input/input_common.h"
|
||||
#include "ios_input.h"
|
||||
#include "general.h"
|
||||
@ -22,6 +25,215 @@
|
||||
extern const rarch_joypad_driver_t ios_joypad;
|
||||
static const rarch_joypad_driver_t* const g_joydriver = &ios_joypad;
|
||||
|
||||
ios_input_data_t g_current_input_data;
|
||||
ios_input_data_t g_polled_input_data;
|
||||
|
||||
static const struct rarch_key_map rarch_key_map_hidusage[];
|
||||
|
||||
// Main thread interface
|
||||
static bool icade_enabled;
|
||||
static uint32_t icade_buttons;
|
||||
|
||||
static void handle_icade_event(unsigned keycode)
|
||||
{
|
||||
static const struct
|
||||
{
|
||||
bool up;
|
||||
int button;
|
||||
} icade_map[0x20] =
|
||||
{
|
||||
{ false, -1 }, { false, -1 }, { false, -1 }, { false, -1 }, // 0
|
||||
{ false, 2 }, { false, -1 }, { true , 3 }, { false, 3 }, // 4
|
||||
{ true , 0 }, { true, 5 }, { true , 7 }, { false, 8 }, // 8
|
||||
{ false, 6 }, { false, 9 }, { false, 10 }, { false, 11 }, // C
|
||||
{ true , 6 }, { true , 9 }, { false, 7 }, { true, 10 }, // 0
|
||||
{ true , 2 }, { true , 8 }, { false, -1 }, { true , 4 }, // 4
|
||||
{ false, 5 }, { true , 11 }, { false, 0 }, { false, 1 }, // 8
|
||||
{ false, 4 }, { true , 1 }, { false, -1 }, { false, -1 } // C
|
||||
};
|
||||
|
||||
if (icade_enabled && (keycode < 0x20) && (icade_map[keycode].button >= 0))
|
||||
{
|
||||
const int button = icade_map[keycode].button;
|
||||
|
||||
if (icade_map[keycode].up)
|
||||
icade_buttons &= ~(1 << button);
|
||||
else
|
||||
icade_buttons |= (1 << button);
|
||||
}
|
||||
}
|
||||
|
||||
void ios_input_enable_icade(bool on)
|
||||
{
|
||||
icade_enabled = on;
|
||||
icade_buttons = 0;
|
||||
}
|
||||
|
||||
void ios_input_handle_key_event(unsigned keycode, bool down)
|
||||
{
|
||||
if (icade_enabled)
|
||||
handle_icade_event(keycode);
|
||||
else if (keycode < MAX_KEYS)
|
||||
g_current_input_data.keys[keycode] = down;
|
||||
}
|
||||
|
||||
// Game thread interface
|
||||
static bool ios_key_pressed(enum retro_key key)
|
||||
{
|
||||
if ((int)key >= 0 && key < RETROK_LAST)
|
||||
return g_polled_input_data.keys[input_translate_rk_to_keysym(key)];
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ios_is_pressed(unsigned port_num, const struct retro_keybind *binds, unsigned key)
|
||||
{
|
||||
return ios_key_pressed(binds[key].key) || input_joypad_pressed(g_joydriver, port_num, binds, key);
|
||||
}
|
||||
|
||||
// Exported input driver
|
||||
static void *ios_input_init(void)
|
||||
{
|
||||
input_init_keyboard_lut(rarch_key_map_hidusage);
|
||||
memset(&g_polled_input_data, 0, sizeof(g_polled_input_data));
|
||||
return (void*)-1;
|
||||
}
|
||||
|
||||
static void ios_input_poll(void *data)
|
||||
{
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
memcpy(&g_polled_input_data, &g_current_input_data, sizeof(ios_input_data_t));
|
||||
|
||||
for (int i = 0; i != g_polled_input_data.touch_count; i ++)
|
||||
{
|
||||
input_translate_coord_viewport(g_polled_input_data.touches[i].screen_x, g_polled_input_data.touches[i].screen_y,
|
||||
&g_polled_input_data.touches[i].fixed_x, &g_polled_input_data.touches[i].fixed_y,
|
||||
&g_polled_input_data.touches[i].full_x, &g_polled_input_data.touches[i].full_y);
|
||||
}
|
||||
|
||||
input_joypad_poll(g_joydriver);
|
||||
});
|
||||
}
|
||||
|
||||
static int16_t ios_input_state(void *data, const struct retro_keybind **binds, unsigned port, unsigned device, unsigned index, unsigned id)
|
||||
{
|
||||
switch (device)
|
||||
{
|
||||
case RETRO_DEVICE_JOYPAD:
|
||||
return (id < RARCH_BIND_LIST_END) ? ios_is_pressed(port, binds[port], id) : false;
|
||||
|
||||
case RETRO_DEVICE_ANALOG:
|
||||
return input_joypad_analog(g_joydriver, port, index, id, binds[port]);
|
||||
|
||||
case RETRO_DEVICE_KEYBOARD:
|
||||
return ios_key_pressed(id);
|
||||
|
||||
case RETRO_DEVICE_POINTER:
|
||||
case RARCH_DEVICE_POINTER_SCREEN:
|
||||
{
|
||||
const bool want_full = device == RARCH_DEVICE_POINTER_SCREEN;
|
||||
|
||||
if (index < g_polled_input_data.touch_count && index < MAX_TOUCHES)
|
||||
{
|
||||
const ios_touch_data_t* touch = &g_polled_input_data.touches[index];
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_POINTER_PRESSED: return 1;
|
||||
case RETRO_DEVICE_ID_POINTER_X: return want_full ? touch->full_x : touch->fixed_x;
|
||||
case RETRO_DEVICE_ID_POINTER_Y: return want_full ? touch->full_y : touch->fixed_y;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ios_bind_button_pressed(void *data, int key)
|
||||
{
|
||||
const struct retro_keybind *binds = g_settings.input.binds[0];
|
||||
return (key >= 0 && key < RARCH_BIND_LIST_END) ? ios_is_pressed(0, binds, key) : false;
|
||||
}
|
||||
|
||||
static void ios_input_free_input(void *data)
|
||||
{
|
||||
(void)data;
|
||||
}
|
||||
|
||||
static void ios_input_set_keybinds(void *data, unsigned device, unsigned port,
|
||||
unsigned id, unsigned keybind_action)
|
||||
{
|
||||
(void)device;
|
||||
|
||||
if (keybind_action & (1ULL << KEYBINDS_ACTION_SET_DEFAULT_BINDS))
|
||||
{
|
||||
switch (device)
|
||||
{
|
||||
case DEVICE_NONE:
|
||||
break;
|
||||
case DEVICE_WIIMOTE:
|
||||
strlcpy(g_settings.input.device_names[port], "Wiimote + Classic",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
g_settings.input.device[port] = device;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_B].joykey = 22;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_Y].joykey = 21;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_SELECT].joykey = 28;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_START].joykey = 26;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_UP].joykey = 16;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_DOWN].joykey = 30;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_LEFT].joykey = 17;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_RIGHT].joykey = 31;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_A].joykey = 20;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_X].joykey = 19;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L].joykey = 29;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R].joykey = 25;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].joykey = 23;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].joykey = 18;
|
||||
g_settings.input.binds[port][RARCH_MENU_TOGGLE].joykey = 27;
|
||||
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
|
||||
break;
|
||||
case DEVICE_SIXAXIS:
|
||||
strlcpy(g_settings.input.device_names[port], "SixAxis/DualShock3",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
g_settings.input.device[port] = device;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_B].joykey = 14;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_Y].joykey = 15;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_SELECT].joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_START].joykey = 3;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_UP].joykey = 4;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_DOWN].joykey = 6;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_LEFT].joykey = 7;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_RIGHT].joykey = 5;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_A].joykey = 13;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_X].joykey = 12;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L].joykey = 10;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R].joykey = 11;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].joykey = 8;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].joykey = 9;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].joykey = 1;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].joykey = 2;
|
||||
g_settings.input.binds[port][RARCH_MENU_TOGGLE].joykey = 16;
|
||||
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const input_driver_t input_ios = {
|
||||
ios_input_init,
|
||||
ios_input_poll,
|
||||
ios_input_state,
|
||||
ios_bind_button_pressed,
|
||||
ios_input_free_input,
|
||||
ios_input_set_keybinds,
|
||||
"ios_input",
|
||||
};
|
||||
|
||||
|
||||
// Key table
|
||||
#include "keycode.h"
|
||||
static const struct rarch_key_map rarch_key_map_hidusage[] = {
|
||||
@ -166,158 +378,4 @@ static const struct rarch_key_map rarch_key_map_hidusage[] = {
|
||||
// RETROK_EURO },
|
||||
// RETROK_UNDO },
|
||||
{ 0, RETROK_UNKNOWN }
|
||||
};
|
||||
|
||||
ios_input_data_t g_ios_input_data;
|
||||
|
||||
// Non-exported helpers
|
||||
static bool ios_key_pressed(enum retro_key key)
|
||||
{
|
||||
if ((int)key >= 0 && key < RETROK_LAST)
|
||||
return g_ios_input_data.keys[input_translate_rk_to_keysym(key)];
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ios_is_pressed(unsigned port_num, const struct retro_keybind *binds, unsigned key)
|
||||
{
|
||||
return ios_key_pressed(binds[key].key) || input_joypad_pressed(g_joydriver, port_num, binds, key);
|
||||
}
|
||||
|
||||
// Exported input driver
|
||||
static void *ios_input_init(void)
|
||||
{
|
||||
input_init_keyboard_lut(rarch_key_map_hidusage);
|
||||
memset(&g_ios_input_data, 0, sizeof(g_ios_input_data));
|
||||
return (void*)-1;
|
||||
}
|
||||
|
||||
static void ios_input_poll(void *data)
|
||||
{
|
||||
for (int i = 0; i != g_ios_input_data.touch_count; i ++)
|
||||
{
|
||||
input_translate_coord_viewport(g_ios_input_data.touches[i].screen_x, g_ios_input_data.touches[i].screen_y,
|
||||
&g_ios_input_data.touches[i].fixed_x, &g_ios_input_data.touches[i].fixed_y,
|
||||
&g_ios_input_data.touches[i].full_x, &g_ios_input_data.touches[i].full_y);
|
||||
}
|
||||
|
||||
input_joypad_poll(g_joydriver);
|
||||
}
|
||||
|
||||
static int16_t ios_input_state(void *data, const struct retro_keybind **binds, unsigned port, unsigned device, unsigned index, unsigned id)
|
||||
{
|
||||
switch (device)
|
||||
{
|
||||
case RETRO_DEVICE_JOYPAD:
|
||||
return (id < RARCH_BIND_LIST_END) ? ios_is_pressed(port, binds[port], id) : false;
|
||||
|
||||
case RETRO_DEVICE_ANALOG:
|
||||
return input_joypad_analog(g_joydriver, port, index, id, binds[port]);
|
||||
|
||||
case RETRO_DEVICE_KEYBOARD:
|
||||
return ios_key_pressed(id);
|
||||
|
||||
case RETRO_DEVICE_POINTER:
|
||||
case RARCH_DEVICE_POINTER_SCREEN:
|
||||
{
|
||||
const bool want_full = device == RARCH_DEVICE_POINTER_SCREEN;
|
||||
|
||||
if (index < g_ios_input_data.touch_count && index < MAX_TOUCHES)
|
||||
{
|
||||
const ios_touch_data_t* touch = &g_ios_input_data.touches[index];
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_POINTER_PRESSED: return 1;
|
||||
case RETRO_DEVICE_ID_POINTER_X: return want_full ? touch->full_x : touch->fixed_x;
|
||||
case RETRO_DEVICE_ID_POINTER_Y: return want_full ? touch->full_y : touch->fixed_y;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ios_bind_button_pressed(void *data, int key)
|
||||
{
|
||||
const struct retro_keybind *binds = g_settings.input.binds[0];
|
||||
return (key >= 0 && key < RARCH_BIND_LIST_END) ? ios_is_pressed(0, binds, key) : false;
|
||||
}
|
||||
|
||||
static void ios_input_free_input(void *data)
|
||||
{
|
||||
(void)data;
|
||||
}
|
||||
|
||||
static void ios_input_set_keybinds(void *data, unsigned device, unsigned port,
|
||||
unsigned id, unsigned keybind_action)
|
||||
{
|
||||
(void)device;
|
||||
|
||||
if (keybind_action & (1ULL << KEYBINDS_ACTION_SET_DEFAULT_BINDS))
|
||||
{
|
||||
switch (device)
|
||||
{
|
||||
case DEVICE_NONE:
|
||||
break;
|
||||
case DEVICE_WIIMOTE:
|
||||
strlcpy(g_settings.input.device_names[port], "Wiimote + Classic",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
g_settings.input.device[port] = device;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_B].joykey = 22;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_Y].joykey = 21;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_SELECT].joykey = 28;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_START].joykey = 26;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_UP].joykey = 16;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_DOWN].joykey = 30;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_LEFT].joykey = 17;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_RIGHT].joykey = 31;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_A].joykey = 20;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_X].joykey = 19;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L].joykey = 29;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R].joykey = 25;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].joykey = 23;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].joykey = 18;
|
||||
g_settings.input.binds[port][RARCH_MENU_TOGGLE].joykey = 27;
|
||||
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
|
||||
break;
|
||||
case DEVICE_SIXAXIS:
|
||||
strlcpy(g_settings.input.device_names[port], "SixAxis/DualShock3",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
g_settings.input.device[port] = device;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_B].joykey = 14;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_Y].joykey = 15;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_SELECT].joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_START].joykey = 3;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_UP].joykey = 4;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_DOWN].joykey = 6;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_LEFT].joykey = 7;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_RIGHT].joykey = 5;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_A].joykey = 13;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_X].joykey = 12;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L].joykey = 10;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R].joykey = 11;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].joykey = 8;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].joykey = 9;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].joykey = 1;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].joykey = 2;
|
||||
g_settings.input.binds[port][RARCH_MENU_TOGGLE].joykey = 16;
|
||||
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const input_driver_t input_ios = {
|
||||
ios_input_init,
|
||||
ios_input_poll,
|
||||
ios_input_state,
|
||||
ios_bind_button_pressed,
|
||||
ios_input_free_input,
|
||||
ios_input_set_keybinds,
|
||||
"ios_input",
|
||||
};
|
||||
};
|
@ -19,6 +19,7 @@
|
||||
// Input responder
|
||||
#define MAX_TOUCHES 16
|
||||
#define MAX_KEYS 256
|
||||
#define MAX_PADS 4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -34,16 +35,15 @@ typedef struct
|
||||
|
||||
uint32_t keys[MAX_KEYS];
|
||||
|
||||
uint32_t pad_buttons;
|
||||
int16_t pad_axis[4];
|
||||
uint32_t pad_buttons[MAX_PADS];
|
||||
int16_t pad_axis[MAX_PADS][4];
|
||||
} ios_input_data_t;
|
||||
|
||||
extern ios_input_data_t g_ios_input_data;
|
||||
extern ios_input_data_t g_current_input_data; //< Main thread data
|
||||
extern ios_input_data_t g_polled_input_data; //< Game thread data
|
||||
|
||||
// Defined in main.m, must be called on the emu thread in a dispatch_sync block
|
||||
void ios_copy_input(ios_input_data_t* data);
|
||||
|
||||
// Called from main.m, defined in ios_input.c
|
||||
void ios_add_key_event(bool down, unsigned keycode, uint32_t character, uint16_t keyModifiers);
|
||||
// Main thread only
|
||||
void ios_input_enable_icade(bool on);
|
||||
void ios_input_handle_key_event(unsigned keycode, bool down);
|
||||
|
||||
#endif
|
||||
|
@ -41,7 +41,7 @@ static bool ios_joypad_button(unsigned port, uint16_t joykey)
|
||||
if (GET_HAT_DIR(joykey))
|
||||
return false;
|
||||
else // Check the button
|
||||
return (port == 0 && joykey < 32) ? (g_ios_input_data.pad_buttons & (1 << joykey)) != 0 : false;
|
||||
return (port < MAX_PADS && joykey < 32) ? (g_polled_input_data.pad_buttons[port] & (1 << joykey)) != 0 : false;
|
||||
}
|
||||
|
||||
static int16_t ios_joypad_axis(unsigned port, uint32_t joyaxis)
|
||||
@ -52,12 +52,12 @@ static int16_t ios_joypad_axis(unsigned port, uint32_t joyaxis)
|
||||
int16_t val = 0;
|
||||
if (AXIS_NEG_GET(joyaxis) < 4)
|
||||
{
|
||||
val = g_ios_input_data.pad_axis[AXIS_NEG_GET(joyaxis)];
|
||||
val = g_polled_input_data.pad_axis[AXIS_NEG_GET(joyaxis)];
|
||||
val = (val < 0) ? val : 0;
|
||||
}
|
||||
else if(AXIS_POS_GET(joyaxis) < 4)
|
||||
{
|
||||
val = g_ios_input_data.pad_axis[AXIS_POS_GET(joyaxis)];
|
||||
val = g_polled_input_data.pad_axis[AXIS_POS_GET(joyaxis)];
|
||||
val = (val > 0) ? val : 0;
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -30,82 +29,29 @@
|
||||
#include "file.h"
|
||||
|
||||
//#define HAVE_DEBUG_FILELOG
|
||||
static bool use_tv_mode;
|
||||
|
||||
static ios_input_data_t g_input_data;
|
||||
|
||||
static bool enable_btstack;
|
||||
static bool use_icade;
|
||||
static uint32_t icade_buttons;
|
||||
|
||||
bool path_make_and_check_directory(const char* path, mode_t mode, int amode)
|
||||
{
|
||||
if (!path_is_directory(path) && mkdir(path, mode) != 0)
|
||||
return false;
|
||||
|
||||
return access(path, amode) == 0;
|
||||
}
|
||||
|
||||
// Input helpers
|
||||
void ios_copy_input(ios_input_data_t* data)
|
||||
{
|
||||
// Call only from main thread
|
||||
|
||||
memcpy(data, &g_input_data, sizeof(g_input_data));
|
||||
data->pad_buttons = btpad_get_buttons() | (use_icade ? icade_buttons : 0);
|
||||
|
||||
for (int i = 0; i < 4; i ++)
|
||||
data->pad_axis[i] = btpad_get_axis(i);
|
||||
}
|
||||
|
||||
// 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_input_data.touch_count = 0;
|
||||
g_current_input_data.touch_count = 0;
|
||||
|
||||
for(int i = 0; i != numTouches && g_input_data.touch_count < MAX_TOUCHES; i ++)
|
||||
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_input_data.touches[g_input_data.touch_count ].screen_x = coord.x * scale;
|
||||
g_input_data.touches[g_input_data.touch_count ++].screen_y = coord.y * scale;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_icade_event(unsigned keycode)
|
||||
{
|
||||
static const struct
|
||||
{
|
||||
bool up;
|
||||
int button;
|
||||
} icade_map[0x20] =
|
||||
{
|
||||
{ false, -1 }, { false, -1 }, { false, -1 }, { false, -1 }, // 0
|
||||
{ false, 2 }, { false, -1 }, { true , 3 }, { false, 3 }, // 4
|
||||
{ true , 0 }, { true, 5 }, { true , 7 }, { false, 8 }, // 8
|
||||
{ false, 6 }, { false, 9 }, { false, 10 }, { false, 11 }, // C
|
||||
{ true , 6 }, { true , 9 }, { false, 7 }, { true, 10 }, // 0
|
||||
{ true , 2 }, { true , 8 }, { false, -1 }, { true , 4 }, // 4
|
||||
{ false, 5 }, { true , 11 }, { false, 0 }, { false, 1 }, // 8
|
||||
{ false, 4 }, { true , 1 }, { false, -1 }, { false, -1 } // C
|
||||
};
|
||||
|
||||
if ((keycode < 0x20) && (icade_map[keycode].button >= 0))
|
||||
{
|
||||
const int button = icade_map[keycode].button;
|
||||
|
||||
if (icade_map[keycode].up)
|
||||
icade_buttons &= ~(1 << button);
|
||||
else
|
||||
icade_buttons |= (1 << button);
|
||||
}
|
||||
}
|
||||
|
||||
@interface RApplication : UIApplication
|
||||
@end
|
||||
|
||||
@ -127,14 +73,7 @@ static void handle_icade_event(unsigned keycode)
|
||||
int eventType = eventMem ? *(int*)&eventMem[8] : 0;
|
||||
|
||||
if (eventType == GSEVENT_TYPE_KEYDOWN || eventType == GSEVENT_TYPE_KEYUP)
|
||||
{
|
||||
uint16_t key = *(uint16_t*)&eventMem[0x3C];
|
||||
|
||||
if (!use_icade && key < MAX_KEYS)
|
||||
g_input_data.keys[key] = (eventType == GSEVENT_TYPE_KEYDOWN);
|
||||
else if (eventType == GSEVENT_TYPE_KEYDOWN)
|
||||
handle_icade_event(key);
|
||||
}
|
||||
ios_input_handle_key_event(*(uint16_t*)&eventMem[0x3C], eventType == GSEVENT_TYPE_KEYDOWN);
|
||||
|
||||
CFBridgingRelease(eventMem);
|
||||
}
|
||||
@ -160,19 +99,18 @@ int main(int argc, char *argv[])
|
||||
extern void* rarch_main_ios(void* args);
|
||||
extern void ios_frontend_post_event(void (*fn)(void*), void* userdata);
|
||||
|
||||
static void event_game_reset(void* userdata)
|
||||
{
|
||||
rarch_game_reset();
|
||||
}
|
||||
|
||||
static void event_load_state(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)
|
||||
{
|
||||
rarch_load_state();
|
||||
}
|
||||
|
||||
static void event_save_state(void* userdata)
|
||||
{
|
||||
rarch_save_state();
|
||||
switch ((enum basic_event_t)userdata)
|
||||
{
|
||||
case RESET: rarch_game_reset(); return;
|
||||
case LOAD_STATE: rarch_load_state(); return;
|
||||
case SAVE_STATE: rarch_save_state(); return;
|
||||
case QUIT: g_extern.system.shutdown = true; return;
|
||||
}
|
||||
}
|
||||
|
||||
static void event_set_state_slot(void* userdata)
|
||||
@ -182,31 +120,16 @@ static void event_set_state_slot(void* userdata)
|
||||
|
||||
static void event_show_rgui(void* userdata)
|
||||
{
|
||||
if (g_extern.lifecycle_mode_state & (1ULL << MODE_MENU))
|
||||
{
|
||||
g_extern.lifecycle_mode_state &= ~(1ULL << MODE_MENU);
|
||||
g_extern.lifecycle_mode_state |= (1ULL << MODE_GAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_extern.lifecycle_mode_state &= ~(1ULL << MODE_GAME);
|
||||
g_extern.lifecycle_mode_state |= (1ULL << MODE_MENU);
|
||||
}
|
||||
}
|
||||
|
||||
static void event_quit(void* userdata)
|
||||
{
|
||||
g_extern.system.shutdown = true;
|
||||
const bool in_menu = g_extern.lifecycle_mode_state & (1 << MODE_MENU);
|
||||
g_extern.lifecycle_mode_state &= ~(1ULL << (in_menu ? MODE_MENU : MODE_GAME));
|
||||
g_extern.lifecycle_mode_state |= (1ULL << (in_menu ? MODE_GAME : MODE_MENU));
|
||||
}
|
||||
|
||||
static void event_reload_config(void* userdata)
|
||||
{
|
||||
// Need to clear these otherwise stale versions may be used!
|
||||
memset(g_settings.input.overlay, 0, sizeof(g_settings.input.overlay));
|
||||
memset(g_settings.video.shader_path, 0, sizeof(g_settings.video.shader_path));
|
||||
ios_clear_config_hack();
|
||||
|
||||
uninit_drivers();
|
||||
g_extern.block_config_read = false;
|
||||
config_load();
|
||||
init_drivers();
|
||||
}
|
||||
@ -226,21 +149,6 @@ static void event_reload_config(void* userdata)
|
||||
RAModuleInfo* _module;
|
||||
}
|
||||
|
||||
+ (void)displayErrorMessage:(NSString*)message
|
||||
{
|
||||
[RetroArch_iOS displayErrorMessage:message withTitle:@"RetroArch"];
|
||||
}
|
||||
|
||||
+ (void)displayErrorMessage:(NSString*)message withTitle:(NSString*)title
|
||||
{
|
||||
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:title
|
||||
message:message
|
||||
delegate:nil
|
||||
cancelButtonTitle:@"OK"
|
||||
otherButtonTitles:nil];
|
||||
[alert show];
|
||||
}
|
||||
|
||||
+ (RetroArch_iOS*)get
|
||||
{
|
||||
return (RetroArch_iOS*)[[UIApplication sharedApplication] delegate];
|
||||
@ -249,10 +157,6 @@ static void event_reload_config(void* userdata)
|
||||
// UIApplicationDelegate
|
||||
- (void)applicationDidFinishLaunching:(UIApplication *)application
|
||||
{
|
||||
#ifdef HAVE_DEBUG_DIAGLOG
|
||||
ios_log_init();
|
||||
#endif
|
||||
|
||||
self.delegate = self;
|
||||
|
||||
// Setup window
|
||||
@ -266,18 +170,21 @@ static void event_reload_config(void* userdata)
|
||||
self.systemConfigPath = [self.systemDirectory stringByAppendingPathComponent:@"frontend.cfg"];
|
||||
|
||||
if (!path_make_and_check_directory(self.documentsDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
|
||||
[RetroArch_iOS displayErrorMessage:[NSString stringWithFormat:@"Failed to create or access base directory: %@", self.documentsDirectory]];
|
||||
ios_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))
|
||||
[RetroArch_iOS displayErrorMessage:[NSString stringWithFormat:@"Failed to create or access system directory: %@", self.systemDirectory]];
|
||||
ios_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)
|
||||
[self runGame:nil withModule:nil];
|
||||
}
|
||||
|
||||
// Warn if there are no cores present
|
||||
if ([RAModuleInfo getModules].count == 0)
|
||||
[RetroArch_iOS displayErrorMessage:@"No libretro cores were found. You will not be able to play any games."];
|
||||
ios_display_alert(@"No libretro cores were found. You will not be able to play any games.", 0);
|
||||
}
|
||||
|
||||
- (void)applicationWillEnterForeground:(UIApplication *)application
|
||||
@ -351,29 +258,36 @@ static void event_reload_config(void* userdata)
|
||||
{
|
||||
if (!_isRunning)
|
||||
{
|
||||
_module = module;
|
||||
|
||||
[RASettingsList refreshModuleConfig:_module];
|
||||
|
||||
[self pushViewController:RAGameView.get animated:NO];
|
||||
_isRunning = true;
|
||||
|
||||
_module = module;
|
||||
[RASettingsList refreshModuleConfig:_module];
|
||||
|
||||
btpad_set_inquiry_state(false);
|
||||
|
||||
struct rarch_main_wrap* load_data = malloc(sizeof(struct rarch_main_wrap));
|
||||
memset(load_data, 0, sizeof(struct rarch_main_wrap));
|
||||
load_data->libretro_path = strdup(_module.path.UTF8String);
|
||||
load_data->rom_path = strdup(path.UTF8String);
|
||||
|
||||
load_data->sram_path = strdup(self.systemDirectory.UTF8String);
|
||||
load_data->state_path = strdup(self.systemDirectory.UTF8String);
|
||||
load_data->config_path = strdup(_module.configPath.UTF8String);
|
||||
load_data->verbose = false;
|
||||
|
||||
if (path && module)
|
||||
{
|
||||
load_data->libretro_path = strdup(_module.path.UTF8String);
|
||||
load_data->rom_path = strdup(path.UTF8String);
|
||||
load_data->config_path = strdup(_module.configPath.UTF8String);
|
||||
}
|
||||
else
|
||||
load_data->config_path = strdup(RAModuleInfo.globalConfigPath.UTF8String);
|
||||
|
||||
if (pthread_create(&_retroThread, 0, rarch_main_ios, load_data))
|
||||
{
|
||||
[self rarchExited:NO];
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_detach(_retroThread);
|
||||
|
||||
[self refreshSystemConfig];
|
||||
}
|
||||
}
|
||||
@ -381,7 +295,7 @@ static void event_reload_config(void* userdata)
|
||||
- (void)rarchExited:(BOOL)successful
|
||||
{
|
||||
if (!successful)
|
||||
[RetroArch_iOS displayErrorMessage:@"Failed to load game."];
|
||||
ios_display_alert(@"Failed to load game.", 0);
|
||||
|
||||
if (_isRunning)
|
||||
{
|
||||
@ -390,7 +304,12 @@ static void event_reload_config(void* userdata)
|
||||
//
|
||||
[self popToViewController:[RAGameView get] animated:NO];
|
||||
[self popViewControllerAnimated:NO];
|
||||
|
||||
btpad_set_inquiry_state(true);
|
||||
}
|
||||
|
||||
if (use_tv_mode)
|
||||
[self runGame:nil withModule:nil];
|
||||
|
||||
_module = nil;
|
||||
}
|
||||
@ -400,11 +319,7 @@ static void event_reload_config(void* userdata)
|
||||
if (_isRunning)
|
||||
ios_frontend_post_event(&event_reload_config, 0);
|
||||
else
|
||||
{
|
||||
// Need to clear these otherwise stale versions may be used!
|
||||
memset(g_settings.input.overlay, 0, sizeof(g_settings.input.overlay));
|
||||
memset(g_settings.video.shader_path, 0, sizeof(g_settings.video.shader_path));
|
||||
}
|
||||
ios_clear_config_hack();
|
||||
}
|
||||
|
||||
- (void)refreshSystemConfig
|
||||
@ -435,13 +350,10 @@ static void event_reload_config(void* userdata)
|
||||
}
|
||||
|
||||
//
|
||||
config_get_bool(conf, "ios_use_icade", &use_icade);
|
||||
config_get_bool(conf, "ios_use_btstack", &enable_btstack);
|
||||
|
||||
if (enable_btstack)
|
||||
[self startBluetooth];
|
||||
else
|
||||
[self stopBluetooth];
|
||||
bool val;
|
||||
ios_input_enable_icade(config_get_bool(conf, "ios_use_icade", &val) && val);
|
||||
btstack_set_poweron(config_get_bool(conf, "ios_use_btstack", &val) && val);
|
||||
use_tv_mode = config_get_bool(conf, "ios_tv_mode", & val) && val;
|
||||
|
||||
config_file_free(conf);
|
||||
}
|
||||
@ -467,33 +379,19 @@ static void event_reload_config(void* userdata)
|
||||
{
|
||||
_isPaused = true;
|
||||
[[RAGameView get] openPauseMenu];
|
||||
|
||||
btpad_set_inquiry_state(true);
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)resetGame:(id)sender
|
||||
- (IBAction)basicEvent:(id)sender
|
||||
{
|
||||
if (_isRunning)
|
||||
ios_frontend_post_event(&event_game_reset, 0);
|
||||
ios_frontend_post_event(&event_basic_command, ((UIView*)sender).tag);
|
||||
|
||||
[self closePauseMenu:sender];
|
||||
}
|
||||
|
||||
- (IBAction)loadState:(id)sender
|
||||
{
|
||||
if (_isRunning)
|
||||
ios_frontend_post_event(&event_load_state, 0);
|
||||
|
||||
[self closePauseMenu:sender];
|
||||
}
|
||||
|
||||
- (IBAction)saveState:(id)sender
|
||||
{
|
||||
if (_isRunning)
|
||||
ios_frontend_post_event(&event_save_state, 0);
|
||||
|
||||
[self closePauseMenu:sender];
|
||||
}
|
||||
|
||||
- (IBAction)chooseState:(id)sender
|
||||
{
|
||||
if (_isRunning)
|
||||
@ -512,18 +410,13 @@ static void event_reload_config(void* userdata)
|
||||
{
|
||||
[[RAGameView get] closePauseMenu];
|
||||
_isPaused = false;
|
||||
}
|
||||
|
||||
- (IBAction)closeGamePressed:(id)sender
|
||||
{
|
||||
[self closePauseMenu:sender];
|
||||
ios_frontend_post_event(event_quit, 0);
|
||||
|
||||
btpad_set_inquiry_state(false);
|
||||
}
|
||||
|
||||
- (IBAction)showSettings
|
||||
{
|
||||
if (_module)
|
||||
[self pushViewController:[[RASettingsList alloc] initWithModule:_module] animated:YES];
|
||||
[self pushViewController:[[RASettingsList alloc] initWithModule:_module] animated:YES];
|
||||
}
|
||||
|
||||
- (IBAction)showSystemSettings
|
||||
@ -531,19 +424,6 @@ static void event_reload_config(void* userdata)
|
||||
[self pushViewController:[RASystemSettingsList new] animated:YES];
|
||||
}
|
||||
|
||||
#pragma mark Bluetooth Helpers
|
||||
- (IBAction)startBluetooth
|
||||
{
|
||||
if (btstack_is_loaded() && !btstack_is_running())
|
||||
btstack_start();
|
||||
}
|
||||
|
||||
- (IBAction)stopBluetooth
|
||||
{
|
||||
if (btstack_is_loaded())
|
||||
btstack_stop();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
void ios_rarch_exited(void* result)
|
||||
|
@ -30,13 +30,6 @@ void ios_set_game_view_sync(unsigned interval);
|
||||
void ios_get_game_view_size(unsigned *width, unsigned *height);
|
||||
void ios_bind_game_view_fbo();
|
||||
|
||||
#ifndef HAVE_DEBUG_DIAGLOG
|
||||
void ios_add_log_message(const char* format, ...);
|
||||
#else
|
||||
void ios_log_init();
|
||||
void ios_log_quit();
|
||||
// Thread safe
|
||||
#define ios_add_log_message(...) do { printf(__VA_ARGS__); printf("\n"); } while(0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -41,6 +41,8 @@ enum SettingTypes
|
||||
@property double rangeMin;
|
||||
@property double rangeMax;
|
||||
|
||||
@property uint32_t player;
|
||||
|
||||
@property bool haveNoneOption;
|
||||
|
||||
- (id)initWithType:(enum SettingTypes)aType label:(NSString*)aLabel name:(NSString*)aName;
|
||||
@ -73,14 +75,17 @@ static RASettingData* boolean_setting(config_file_t* config, NSString* name, NSS
|
||||
return result;
|
||||
}
|
||||
|
||||
static RASettingData* button_setting(config_file_t* config, NSString* name, NSString* label, NSString* defaultValue)
|
||||
static RASettingData* button_setting(config_file_t* config, uint32_t player, NSString* name, NSString* label, NSString* defaultValue)
|
||||
{
|
||||
RASettingData* result = [[RASettingData alloc] initWithType:ButtonSetting label:label name:name];
|
||||
NSString* realname = player ? [NSString stringWithFormat:@"input_player%d_%@", player, name] : name;
|
||||
|
||||
RASettingData* result = [[RASettingData alloc] initWithType:ButtonSetting label:label name:realname];
|
||||
result.msubValues = [NSMutableArray arrayWithObjects:
|
||||
ios_get_value_from_config(config, name, defaultValue),
|
||||
ios_get_value_from_config(config, [name stringByAppendingString:@"_btn"], @"nul"),
|
||||
ios_get_value_from_config(config, [name stringByAppendingString:@"_axis"], @"nul"),
|
||||
ios_get_value_from_config(config, realname, defaultValue),
|
||||
ios_get_value_from_config(config, [realname stringByAppendingString:@"_btn"], @"nul"),
|
||||
ios_get_value_from_config(config, [realname stringByAppendingString:@"_axis"], @"nul"),
|
||||
nil];
|
||||
result.player = player ? player - 1 : 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -163,6 +168,42 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
|
||||
return result;
|
||||
}
|
||||
|
||||
static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
||||
{
|
||||
return [NSArray arrayWithObjects:
|
||||
[NSArray arrayWithObjects:[NSString stringWithFormat:@"Player %d", player],
|
||||
button_setting(config, player, @"up", @"Up", @"up"),
|
||||
button_setting(config, player, @"down", @"Down", @"down"),
|
||||
button_setting(config, player, @"left", @"Left", @"left"),
|
||||
button_setting(config, player, @"right", @"Right", @"right"),
|
||||
|
||||
button_setting(config, player, @"start", @"Start", @"enter"),
|
||||
button_setting(config, player, @"select", @"Select", @"rshift"),
|
||||
|
||||
button_setting(config, player, @"b", @"B", @"z"),
|
||||
button_setting(config, player, @"a", @"A", @"x"),
|
||||
button_setting(config, player, @"x", @"X", @"s"),
|
||||
button_setting(config, player, @"y", @"Y", @"a"),
|
||||
|
||||
button_setting(config, player, @"l", @"L", @"q"),
|
||||
button_setting(config, player, @"r", @"R", @"w"),
|
||||
button_setting(config, player, @"l2", @"L2", @"nul"),
|
||||
button_setting(config, player, @"r2", @"R2", @"nul"),
|
||||
button_setting(config, player, @"l3", @"L3", @"nul"),
|
||||
button_setting(config, player, @"r3", @"R3", @"nul"),
|
||||
|
||||
button_setting(config, player, @"l_y_minus", @"Left Stick Up", @"nul"),
|
||||
button_setting(config, player, @"l_y_plus", @"Left Stick Down", @"nul"),
|
||||
button_setting(config, player, @"l_x_minus", @"Left Stick Left", @"nul"),
|
||||
button_setting(config, player, @"l_x_plus", @"Left Stick Right", @"nul"),
|
||||
button_setting(config, player, @"r_y_minus", @"Right Stick Up", @"nul"),
|
||||
button_setting(config, player, @"r_y_plus", @"Right Stick Down", @"nul"),
|
||||
button_setting(config, player, @"r_x_minus", @"Right Stick Left", @"nul"),
|
||||
button_setting(config, player, @"r_x_plus", @"Right Stick Right", @"nul"),
|
||||
nil],
|
||||
nil];
|
||||
}
|
||||
|
||||
@implementation RASettingsList
|
||||
{
|
||||
RAModuleInfo* _module;
|
||||
@ -212,57 +253,29 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
|
||||
[NSArray arrayWithObjects:@"Input",
|
||||
subpath_setting(config, @"input_overlay", @"Input Overlay", @"", overlay_path, @"cfg"),
|
||||
range_setting(config, @"input_overlay_opacity", @"Overlay Opacity", @"1.0", 0.0, 1.0),
|
||||
group_setting(@"Player 1 Keys", [NSArray arrayWithObjects:
|
||||
[NSArray arrayWithObjects:@"Player 1",
|
||||
button_setting(config, @"input_player1_up", @"Up", @"up"),
|
||||
button_setting(config, @"input_player1_down", @"Down", @"down"),
|
||||
button_setting(config, @"input_player1_left", @"Left", @"left"),
|
||||
button_setting(config, @"input_player1_right", @"Right", @"right"),
|
||||
|
||||
button_setting(config, @"input_player1_start", @"Start", @"enter"),
|
||||
button_setting(config, @"input_player1_select", @"Select", @"rshift"),
|
||||
|
||||
button_setting(config, @"input_player1_b", @"B", @"z"),
|
||||
button_setting(config, @"input_player1_a", @"A", @"x"),
|
||||
button_setting(config, @"input_player1_x", @"X", @"s"),
|
||||
button_setting(config, @"input_player1_y", @"Y", @"a"),
|
||||
|
||||
button_setting(config, @"input_player1_l", @"L", @"q"),
|
||||
button_setting(config, @"input_player1_r", @"R", @"w"),
|
||||
button_setting(config, @"input_player1_l2", @"L2", @"nul"),
|
||||
button_setting(config, @"input_player1_r2", @"R2", @"nul"),
|
||||
button_setting(config, @"input_player1_l3", @"L3", @"nul"),
|
||||
button_setting(config, @"input_player1_r3", @"R3", @"nul"),
|
||||
|
||||
button_setting(config, @"input_player1_l_y_minus", @"Left Stick Up", @"nul"),
|
||||
button_setting(config, @"input_player1_l_y_plus", @"Left Stick Down", @"nul"),
|
||||
button_setting(config, @"input_player1_l_x_minus", @"Left Stick Left", @"nul"),
|
||||
button_setting(config, @"input_player1_l_x_plus", @"Left Stick Right", @"nul"),
|
||||
button_setting(config, @"input_player1_r_y_minus", @"Right Stick Up", @"nul"),
|
||||
button_setting(config, @"input_player1_r_y_plus", @"Right Stick Down", @"nul"),
|
||||
button_setting(config, @"input_player1_r_x_minus", @"Right Stick Left", @"nul"),
|
||||
button_setting(config, @"input_player1_r_x_plus", @"Right Stick Right", @"nul"),
|
||||
nil],
|
||||
nil]),
|
||||
group_setting(@"System Keys", [NSArray arrayWithObjects:
|
||||
// TODO: Many of these strings will be cut off on an iPhone
|
||||
[NSArray arrayWithObjects:@"System Keys",
|
||||
button_setting(config, @"input_menu_toggle", @"Show RGUI", @"f1"),
|
||||
button_setting(config, @"input_disk_eject_toggle", @"Insert/Eject Disk", @"nul"),
|
||||
button_setting(config, @"input_disk_next", @"Cycle Disks", @"nul"),
|
||||
button_setting(config, @"input_save_state", @"Save State", @"f2"),
|
||||
button_setting(config, @"input_load_state", @"Load State", @"f4"),
|
||||
button_setting(config, @"input_state_slot_increase", @"Next State Slot", @"f7"),
|
||||
button_setting(config, @"input_state_slot_decrease", @"Previous State Slot", @"f6"),
|
||||
button_setting(config, @"input_toggle_fast_forward", @"Toggle Fast Forward", @"space"),
|
||||
button_setting(config, @"input_hold_fast_forward", @"Hold Fast Forward", @"l"),
|
||||
button_setting(config, @"input_rewind", @"Rewind", @"r"),
|
||||
button_setting(config, @"input_slowmotion", @"Slow Motion", @"e"),
|
||||
button_setting(config, @"input_reset", @"Reset", @"h"),
|
||||
button_setting(config, @"input_exit_emulator", @"Close Game", @"escape"),
|
||||
button_setting(config, @"input_enable_hotkey", @"Hotkey Enable (Always on if not set)", @"nul"),
|
||||
button_setting(config, 0, @"input_menu_toggle", @"Show RGUI", @"f1"),
|
||||
button_setting(config, 0, @"input_disk_eject_toggle", @"Insert/Eject Disk", @"nul"),
|
||||
button_setting(config, 0, @"input_disk_next", @"Cycle Disks", @"nul"),
|
||||
button_setting(config, 0, @"input_save_state", @"Save State", @"f2"),
|
||||
button_setting(config, 0, @"input_load_state", @"Load State", @"f4"),
|
||||
button_setting(config, 0, @"input_state_slot_increase", @"Next State Slot", @"f7"),
|
||||
button_setting(config, 0, @"input_state_slot_decrease", @"Previous State Slot", @"f6"),
|
||||
button_setting(config, 0, @"input_toggle_fast_forward", @"Toggle Fast Forward", @"space"),
|
||||
button_setting(config, 0, @"input_hold_fast_forward", @"Hold Fast Forward", @"l"),
|
||||
button_setting(config, 0, @"input_rewind", @"Rewind", @"r"),
|
||||
button_setting(config, 0, @"input_slowmotion", @"Slow Motion", @"e"),
|
||||
button_setting(config, 0, @"input_reset", @"Reset", @"h"),
|
||||
button_setting(config, 0, @"input_exit_emulator", @"Close Game", @"escape"),
|
||||
button_setting(config, 0, @"input_enable_hotkey", @"Hotkey Enable (Always on if not set)", @"nul"),
|
||||
nil],
|
||||
nil]),
|
||||
group_setting(@"Player 1 Keys", build_input_port_group(config, 1)),
|
||||
group_setting(@"Player 2 Keys", build_input_port_group(config, 2)),
|
||||
group_setting(@"Player 3 Keys", build_input_port_group(config, 3)),
|
||||
group_setting(@"Player 4 Keys", build_input_port_group(config, 4)),
|
||||
nil],
|
||||
|
||||
[NSArray arrayWithObjects:@"Save States",
|
||||
@ -334,11 +347,12 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
|
||||
NSArray* settings = [NSArray arrayWithObjects:
|
||||
[NSArray arrayWithObjects:@"Frontend",
|
||||
custom_action(@"Diagnostic Log", nil, nil),
|
||||
boolean_setting(config, @"ios_tv_mode", @"TV Mode", @"false"),
|
||||
nil],
|
||||
[NSArray arrayWithObjects:@"Bluetooth",
|
||||
// TODO: Note that with this turned off the native bluetooth is expected to be a real keyboard
|
||||
boolean_setting(config, @"ios_use_icade", @"Native BT is iCade", @"false"),
|
||||
btstack_is_loaded() ? boolean_setting(config, @"ios_use_btstack", @"Enable BTstack", @"false") : nil,
|
||||
btstack_try_load() ? boolean_setting(config, @"ios_use_btstack", @"Enable BTstack", @"false") : nil,
|
||||
nil],
|
||||
[NSArray arrayWithObjects:@"Orientations",
|
||||
boolean_setting(config, @"ios_allow_portrait", @"Portrait", @"true"),
|
||||
@ -379,16 +393,9 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
|
||||
if ([@"Diagnostic Log" isEqualToString:setting.label])
|
||||
[[RetroArch_iOS get] pushViewController:[RALogView new] animated:YES];
|
||||
else if ([@"Enable BTstack" isEqualToString:setting.label])
|
||||
{
|
||||
if ([@"true" isEqualToString:setting.value])
|
||||
[RetroArch_iOS.get startBluetooth];
|
||||
else
|
||||
[RetroArch_iOS.get stopBluetooth];
|
||||
}
|
||||
btstack_set_poweron([setting.value isEqualToString:@"true"]);
|
||||
else if([@"Global Core Config" isEqualToString:setting.label])
|
||||
{
|
||||
[RetroArch_iOS.get pushViewController:[[RASettingsList alloc] initWithModule:nil] animated:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
RAModuleInfo* data = (RAModuleInfo*)objc_getAssociatedObject(setting, "USERDATA");
|
||||
@ -741,9 +748,6 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
|
||||
|
||||
- (void)checkInput
|
||||
{
|
||||
ios_input_data_t data;
|
||||
ios_copy_input(&data);
|
||||
|
||||
// Keyboard
|
||||
static const struct
|
||||
{
|
||||
@ -802,7 +806,7 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
|
||||
|
||||
for (int i = 0; ios_key_name_map[i].hid_id; i++)
|
||||
{
|
||||
if (data.keys[ios_key_name_map[i].hid_id])
|
||||
if (g_current_input_data.keys[ios_key_name_map[i].hid_id])
|
||||
{
|
||||
_value.msubValues[0] = [NSString stringWithUTF8String:ios_key_name_map[i].keyname];
|
||||
[self finish];
|
||||
@ -811,9 +815,9 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
|
||||
}
|
||||
|
||||
// Pad Buttons
|
||||
for (int i = 0; data.pad_buttons && i < sizeof(data.pad_buttons) * 8; i++)
|
||||
for (int i = 0; g_current_input_data.pad_buttons[_value.player] && i < sizeof(g_current_input_data.pad_buttons[_value.player]) * 8; i++)
|
||||
{
|
||||
if (data.pad_buttons & (1 << i))
|
||||
if (g_current_input_data.pad_buttons[_value.player] & (1 << i))
|
||||
{
|
||||
_value.msubValues[1] = [NSString stringWithFormat:@"%d", i];
|
||||
[self finish];
|
||||
@ -824,7 +828,7 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
|
||||
// Pad Axis
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int16_t value = data.pad_axis[i];
|
||||
int16_t value = g_current_input_data.pad_axis[_value.player][i];
|
||||
|
||||
if (abs(value) > 0x1000)
|
||||
{
|
||||
|
@ -13,8 +13,30 @@
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "general.h"
|
||||
#include "file.h"
|
||||
#import "views.h"
|
||||
|
||||
void ios_display_alert(NSString* message, NSString* title)
|
||||
{
|
||||
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:title ? title : @"RetroArch"
|
||||
message:message
|
||||
delegate:nil
|
||||
cancelButtonTitle:@"OK"
|
||||
otherButtonTitles:nil];
|
||||
[alert show];
|
||||
}
|
||||
|
||||
// Little nudge to prevent stale values when reloading the confg file
|
||||
void ios_clear_config_hack()
|
||||
{
|
||||
g_extern.block_config_read = false;
|
||||
memset(g_settings.input.overlay, 0, sizeof(g_settings.input.overlay));
|
||||
memset(g_settings.video.shader_path, 0, sizeof(g_settings.video.shader_path));
|
||||
}
|
||||
|
||||
// Fetch a value from a config file, returning defaultValue if the value is not present
|
||||
NSString* ios_get_value_from_config(config_file_t* config, NSString* name, NSString* defaultValue)
|
||||
{
|
||||
@ -27,6 +49,15 @@ NSString* ios_get_value_from_config(config_file_t* config, NSString* name, NSStr
|
||||
return result;
|
||||
}
|
||||
|
||||
// Ensures a directory exists and has correct permissions
|
||||
bool path_make_and_check_directory(const char* path, mode_t mode, int amode)
|
||||
{
|
||||
if (!path_is_directory(path) && mkdir(path, mode) != 0)
|
||||
return false;
|
||||
|
||||
return access(path, amode) == 0;
|
||||
}
|
||||
|
||||
// Simple class to reduce code duplication for fixed table views
|
||||
@implementation RATableViewController
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user