mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-14 23:10:33 +02:00
Merge pull request #22493 from hrydgard/ios-share-file
iOS: Add support for the internal "Share file" API just like Android
This commit is contained in:
17 files changed
+76
-505
No files matched your search
@@ -955,9 +955,6 @@ elseif(IOS AND NOT LIBRETRO)
|
||||
ios/CameraHelper.h
|
||||
ios/LocationHelper.mm
|
||||
ios/LocationHelper.h
|
||||
ios/iCade/iCadeReaderView.h
|
||||
ios/iCade/iCadeReaderView.m
|
||||
ios/iCade/iCadeState.h
|
||||
Common/Battery/AppleBatteryClient.m
|
||||
)
|
||||
|
||||
@@ -987,7 +984,6 @@ elseif(IOS AND NOT LIBRETRO)
|
||||
ios/ViewControllerMetal.mm
|
||||
ios/iOSCoreAudio.mm
|
||||
ios/IAPManager.mm
|
||||
ios/iCade/iCadeReaderView.m
|
||||
ios/main.mm
|
||||
ios/CameraHelper.mm
|
||||
ios/LocationHelper.mm
|
||||
|
||||
@@ -731,22 +731,6 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ios\iCade\iCadeReaderView.h">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ios\iCade\iCadeState.h">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ios\iOSCoreAudio.h">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
@@ -1143,14 +1127,6 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</None>
|
||||
<None Include="..\ios\iCade\iCadeReaderView.m">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</None>
|
||||
<None Include="..\ios\iOSCoreAudio.mm">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
|
||||
@@ -50,9 +50,6 @@
|
||||
<Filter Include="Build\Actions">
|
||||
<UniqueIdentifier>{14abd855-ec8b-47a5-8b4c-eadcff122dc8}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Other Platforms\iOS\iCade">
|
||||
<UniqueIdentifier>{ce617e38-1bc8-4eab-a3cb-d3d664116c91}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Build\CMake">
|
||||
<UniqueIdentifier>{8f39c005-9738-41c5-a8d8-cfc05bf178e8}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@@ -487,12 +484,6 @@
|
||||
<ClInclude Include="..\libretro\retro_inline.h">
|
||||
<Filter>Other Platforms\libretro</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ios\iCade\iCadeState.h">
|
||||
<Filter>Other Platforms\iOS\iCade</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ios\iCade\iCadeReaderView.h">
|
||||
<Filter>Other Platforms\iOS\iCade</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="W32Util\DarkMode.h">
|
||||
<Filter>Windows\W32Util</Filter>
|
||||
</ClInclude>
|
||||
@@ -698,9 +689,6 @@
|
||||
<None Include="..\ios\README.md">
|
||||
<Filter>Other Platforms\iOS</Filter>
|
||||
</None>
|
||||
<None Include="..\ios\iCade\iCadeReaderView.m">
|
||||
<Filter>Other Platforms\iOS\iCade</Filter>
|
||||
</None>
|
||||
<None Include="..\cmake\Modules\FindMINIUPNPC.cmake">
|
||||
<Filter>Build\CMake</Filter>
|
||||
</None>
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string_view>
|
||||
|
||||
#import <GameController/GameController.h>
|
||||
#import <CoreMotion/CoreMotion.h>
|
||||
|
||||
#include "iCade/iCadeState.h"
|
||||
#include "Common/Input/InputState.h"
|
||||
|
||||
// Code extracted from ViewController.mm, in order to modularize
|
||||
@@ -27,22 +25,6 @@ private:
|
||||
UITouch *touches_[10]{};
|
||||
};
|
||||
|
||||
// Can probably get rid of this, but let's keep it for now.
|
||||
struct ICadeTracker {
|
||||
public:
|
||||
void ButtonDown(iCadeState button);
|
||||
void ButtonUp(iCadeState button);
|
||||
void InitKeyMap();
|
||||
private:
|
||||
bool simulateAnalog = false;
|
||||
bool iCadeConnectNotified = false;
|
||||
|
||||
std::map<uint16_t, InputKeyCode> iCadeToKeyMap;
|
||||
|
||||
double lastSelectPress = 0.0f;
|
||||
double lastStartPress = 0.0f;
|
||||
};
|
||||
|
||||
void ProcessAccelerometerData(CMAccelerometerData *accData);
|
||||
InputKeyCode HIDUsageToInputKeyCode(UIKeyboardHIDUsage usage);
|
||||
|
||||
|
||||
-125
@@ -287,131 +287,6 @@ void TouchTracker::Cancelled(NSSet *touches, UIView *view) {
|
||||
}
|
||||
}
|
||||
|
||||
void ICadeTracker::InitKeyMap() {
|
||||
iCadeToKeyMap[iCadeJoystickUp] = NKCODE_DPAD_UP;
|
||||
iCadeToKeyMap[iCadeJoystickRight] = NKCODE_DPAD_RIGHT;
|
||||
iCadeToKeyMap[iCadeJoystickDown] = NKCODE_DPAD_DOWN;
|
||||
iCadeToKeyMap[iCadeJoystickLeft] = NKCODE_DPAD_LEFT;
|
||||
iCadeToKeyMap[iCadeButtonA] = NKCODE_BUTTON_9; // Select
|
||||
iCadeToKeyMap[iCadeButtonB] = NKCODE_BUTTON_7; // LTrigger
|
||||
iCadeToKeyMap[iCadeButtonC] = NKCODE_BUTTON_10; // Start
|
||||
iCadeToKeyMap[iCadeButtonD] = NKCODE_BUTTON_8; // RTrigger
|
||||
iCadeToKeyMap[iCadeButtonE] = NKCODE_BUTTON_4; // Square
|
||||
iCadeToKeyMap[iCadeButtonF] = NKCODE_BUTTON_2; // Cross
|
||||
iCadeToKeyMap[iCadeButtonG] = NKCODE_BUTTON_1; // Triangle
|
||||
iCadeToKeyMap[iCadeButtonH] = NKCODE_BUTTON_3; // Circle
|
||||
}
|
||||
|
||||
void ICadeTracker::ButtonDown(iCadeState button) {
|
||||
if (simulateAnalog &&
|
||||
((button == iCadeJoystickUp) ||
|
||||
(button == iCadeJoystickDown) ||
|
||||
(button == iCadeJoystickLeft) ||
|
||||
(button == iCadeJoystickRight))) {
|
||||
AxisInput axis;
|
||||
switch (button) {
|
||||
case iCadeJoystickUp :
|
||||
axis.axisId = JOYSTICK_AXIS_Y;
|
||||
axis.value = -1.0f;
|
||||
break;
|
||||
|
||||
case iCadeJoystickDown :
|
||||
axis.axisId = JOYSTICK_AXIS_Y;
|
||||
axis.value = 1.0f;
|
||||
break;
|
||||
|
||||
case iCadeJoystickLeft :
|
||||
axis.axisId = JOYSTICK_AXIS_X;
|
||||
axis.value = -1.0f;
|
||||
break;
|
||||
|
||||
case iCadeJoystickRight :
|
||||
axis.axisId = JOYSTICK_AXIS_X;
|
||||
axis.value = 1.0f;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
axis.deviceId = DEVICE_ID_PAD_0;
|
||||
NativeAxis(&axis, 1);
|
||||
} else {
|
||||
KeyInput key;
|
||||
key.flags = KeyInputFlags::DOWN;
|
||||
key.keyCode = iCadeToKeyMap[button];
|
||||
key.deviceId = DEVICE_ID_PAD_0;
|
||||
NativeKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
void ICadeTracker::ButtonUp(iCadeState button) {
|
||||
if (!iCadeConnectNotified) {
|
||||
iCadeConnectNotified = true;
|
||||
KeyMap::NotifyPadConnected(DEVICE_ID_PAD_0, "iCade");
|
||||
}
|
||||
|
||||
if (button == iCadeButtonA) {
|
||||
// Pressing Select twice within 1 second toggles the DPad between
|
||||
// normal operation and simulating the Analog stick.
|
||||
if ((lastSelectPress + 1.0f) > time_now_d())
|
||||
simulateAnalog = !simulateAnalog;
|
||||
lastSelectPress = time_now_d();
|
||||
}
|
||||
|
||||
if (button == iCadeButtonC) {
|
||||
// Pressing Start twice within 1 second will take to the Emu menu
|
||||
if ((lastStartPress + 1.0f) > time_now_d()) {
|
||||
KeyInput key;
|
||||
key.flags = KeyInputFlags::DOWN;
|
||||
key.keyCode = NKCODE_ESCAPE;
|
||||
key.deviceId = DEVICE_ID_KEYBOARD;
|
||||
NativeKey(key);
|
||||
return;
|
||||
}
|
||||
lastStartPress = time_now_d();
|
||||
}
|
||||
|
||||
if (simulateAnalog &&
|
||||
((button == iCadeJoystickUp) ||
|
||||
(button == iCadeJoystickDown) ||
|
||||
(button == iCadeJoystickLeft) ||
|
||||
(button == iCadeJoystickRight))) {
|
||||
AxisInput axis;
|
||||
switch (button) {
|
||||
case iCadeJoystickUp :
|
||||
axis.axisId = JOYSTICK_AXIS_Y;
|
||||
axis.value = 0.0f;
|
||||
break;
|
||||
|
||||
case iCadeJoystickDown :
|
||||
axis.axisId = JOYSTICK_AXIS_Y;
|
||||
axis.value = 0.0f;
|
||||
break;
|
||||
|
||||
case iCadeJoystickLeft :
|
||||
axis.axisId = JOYSTICK_AXIS_X;
|
||||
axis.value = 0.0f;
|
||||
break;
|
||||
|
||||
case iCadeJoystickRight :
|
||||
axis.axisId = JOYSTICK_AXIS_X;
|
||||
axis.value = 0.0f;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
axis.deviceId = DEVICE_ID_PAD_0;
|
||||
NativeAxis(&axis, 1);
|
||||
} else {
|
||||
KeyInput key;
|
||||
key.flags = KeyInputFlags::UP;
|
||||
key.keyCode = iCadeToKeyMap[button];
|
||||
key.deviceId = DEVICE_ID_PAD_0;
|
||||
NativeKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessAccelerometerData(CMAccelerometerData *accData) {
|
||||
CMAcceleration acc = accData.acceleration;
|
||||
// INFO_LOG(SYSTEM, "%f %f %f", acc.x, acc.y, acc.z);
|
||||
|
||||
@@ -199,12 +199,9 @@ static bool SafeStringEqual(NSString *a, NSString *b) {
|
||||
completionHandler:^(NSError * _Nullable error) {
|
||||
if (error) {
|
||||
NSLog(@"[IAPManager] Failed to set Gold icon to %@: %@", desiredIcon, error.localizedDescription);
|
||||
[sharedViewController hideKeyboard];
|
||||
} else {
|
||||
NSLog(@"Icon update succeeded.");
|
||||
NSLog(@"Current icon name: %@", [[UIApplication sharedApplication] alternateIconName]);
|
||||
// Here we need to call hideKeyboard.
|
||||
[sharedViewController hideKeyboard];
|
||||
}
|
||||
}];
|
||||
NSLog(@"Icon update to %@ dispatched, waiting for response.", desiredIcon);
|
||||
|
||||
@@ -171,7 +171,9 @@ static NSString *ExtractGameInfoScheme(NSURL *url) {
|
||||
|
||||
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
|
||||
NSString *bundlePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/assets/"];
|
||||
NativeInit(argc, argv.data(), cmdLineOptions, documentsPath.UTF8String, bundlePath.UTF8String, NULL);
|
||||
// Caches the system may clear when space runs low, and the zips ShareFilesAsZip hands to other apps.
|
||||
NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
|
||||
NativeInit(argc, argv.data(), cmdLineOptions, documentsPath.UTF8String, bundlePath.UTF8String, cachesPath.UTF8String);
|
||||
|
||||
// If we were cold-started by a library export request, serve it now that
|
||||
// the config (and recent games list) has been loaded by NativeInit.
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <GLKit/GLKit.h>
|
||||
|
||||
#import "iCade/iCadeReaderView.h"
|
||||
#import "LocationHelper.h"
|
||||
|
||||
#import "ViewControllerCommon.h"
|
||||
|
||||
@@ -138,17 +138,10 @@ PPSSPPBaseViewController *sharedViewController;
|
||||
ERROR_LOG(Log::G3D, "InitSurface failed: %s", errorMessage.c_str());
|
||||
}
|
||||
|
||||
/*self.iCadeView = [[iCadeReaderView alloc] init];
|
||||
[self.view addSubview:self.iCadeView];
|
||||
self.iCadeView.delegate = self;
|
||||
self.iCadeView.active = YES;*/
|
||||
|
||||
if ([[GCController controllers] count] > 0) {
|
||||
[self setupController:[[GCController controllers] firstObject]];
|
||||
}
|
||||
|
||||
[self hideKeyboard];
|
||||
|
||||
INFO_LOG(Log::G3D, "Done with viewDidLoad.");
|
||||
}
|
||||
|
||||
|
||||
@@ -7,17 +7,17 @@
|
||||
|
||||
#import "CameraHelper.h"
|
||||
#import "LocationHelper.h"
|
||||
#import "iCade/iCadeReaderView.h"
|
||||
|
||||
@interface PPSSPPBaseViewController : UIViewController<
|
||||
UIImagePickerControllerDelegate, UINavigationControllerDelegate,
|
||||
PHPickerViewControllerDelegate,
|
||||
CameraFrameDelegate, LocationHandlerDelegate, UIKeyInput,
|
||||
UIGestureRecognizerDelegate, iCadeEventDelegate>
|
||||
CameraFrameDelegate, LocationHandlerDelegate,
|
||||
UIGestureRecognizerDelegate>
|
||||
|
||||
- (void)hideKeyboard;
|
||||
- (void)showKeyboard;
|
||||
- (void)shareText:(NSString *)text;
|
||||
- (void)shareFile:(NSURL *)url;
|
||||
- (void)shutdown;
|
||||
- (void)bindDefaultFBO;
|
||||
- (void)startLocation;
|
||||
|
||||
+55
-55
@@ -14,10 +14,40 @@
|
||||
#include "Core/System.h"
|
||||
#include "Core/Config.h"
|
||||
|
||||
// The target of the soft keyboard. It's a view of its own so the keyboard only comes up when we ask
|
||||
// for it: UIKit hands first responder back to the view controller whenever something it presented
|
||||
// (a share sheet, a picker, an alert) goes away, and if that were the text input, up it would come.
|
||||
@interface KeyboardInputView : UIView <UIKeyInput>
|
||||
@end
|
||||
|
||||
@implementation KeyboardInputView
|
||||
|
||||
- (BOOL)canBecomeFirstResponder {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)hasText {
|
||||
// Otherwise the keyboard wouldn't send backspaces.
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)insertText:(NSString *)text {
|
||||
SendKeyboardChars([text UTF8String]);
|
||||
}
|
||||
|
||||
- (void)deleteBackward {
|
||||
KeyInput input{};
|
||||
input.deviceId = DEVICE_ID_KEYBOARD;
|
||||
input.flags = KeyInputFlags::DOWN | KeyInputFlags::UP;
|
||||
input.keyCode = NKCODE_DEL;
|
||||
NativeKey(input);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface PPSSPPBaseViewController () {
|
||||
CameraHelper *cameraHelper;
|
||||
LocationHelper *locationHelper;
|
||||
ICadeTracker g_iCadeTracker;
|
||||
TouchTracker g_touchTracker;
|
||||
}
|
||||
|
||||
@@ -30,6 +60,7 @@
|
||||
@implementation PPSSPPBaseViewController {
|
||||
UIScreenEdgePanGestureRecognizer *mBackGestureRecognizer;
|
||||
CGSize lastLayoutSize_;
|
||||
KeyboardInputView *keyboardInputView_;
|
||||
}
|
||||
|
||||
// Strange idiom for generating unique IDs (within the process, at least).
|
||||
@@ -66,8 +97,6 @@ static int GetPickerRequestId(id picker) {
|
||||
if (self) {
|
||||
sharedViewController = self;
|
||||
|
||||
g_iCadeTracker.InitKeyMap();
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillTerminate:) name:UIApplicationWillTerminateNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidConnect:) name:GCControllerDidConnectNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidDisconnect:) name:GCControllerDidDisconnectNotification object:nil];
|
||||
@@ -137,7 +166,8 @@ static int GetPickerRequestId(id picker) {
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
INFO_LOG(Log::G3D, "viewDidAppear");
|
||||
[self hideKeyboard];
|
||||
// For hardware keyboard presses.
|
||||
[self becomeFirstResponder];
|
||||
[self updateGesture];
|
||||
|
||||
// This needs to be called really late during startup, unfortunately.
|
||||
@@ -146,7 +176,6 @@ static int GetPickerRequestId(id picker) {
|
||||
NSLog(@"viewDidAppear. updating icon");
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[[IAPManager sharedIAPManager] updateIcon:false];
|
||||
[self hideKeyboard];
|
||||
});
|
||||
#endif // IOS_APP_STORE
|
||||
}
|
||||
@@ -248,7 +277,6 @@ static int GetPickerRequestId(id picker) {
|
||||
if (results.count == 0) {
|
||||
NSLog(@"User cancelled photo picker");
|
||||
g_requestManager.PostSystemFailure(requestId);
|
||||
[self hideKeyboard];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -256,7 +284,6 @@ static int GetPickerRequestId(id picker) {
|
||||
if (![itemProvider canLoadObjectOfClass:[UIImage class]]) {
|
||||
NSLog(@"Photo picker result does not provide UIImage");
|
||||
g_requestManager.PostSystemFailure(requestId);
|
||||
[self hideKeyboard];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -268,7 +295,6 @@ static int GetPickerRequestId(id picker) {
|
||||
} else {
|
||||
[self savePickedImage:image toFilename:targetFilename requestId:requestId];
|
||||
}
|
||||
[self hideKeyboard];
|
||||
});
|
||||
}];
|
||||
}
|
||||
@@ -282,8 +308,6 @@ static int GetPickerRequestId(id picker) {
|
||||
[self savePickedImage:image toFilename:targetFilename requestId:requestId];
|
||||
|
||||
[picker dismissViewControllerAnimated:YES completion:nil];
|
||||
|
||||
[self hideKeyboard];
|
||||
}
|
||||
|
||||
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
|
||||
@@ -292,9 +316,7 @@ static int GetPickerRequestId(id picker) {
|
||||
|
||||
[picker dismissViewControllerAnimated:YES completion:nil];
|
||||
|
||||
// You can also call your custom callback or use the requestId here
|
||||
g_requestManager.PostSystemFailure(requestId);
|
||||
[self hideKeyboard];
|
||||
}
|
||||
|
||||
- (void)handleSwipeFrom:(UIScreenEdgePanGestureRecognizer *)recognizer {
|
||||
@@ -370,6 +392,9 @@ static int GetPickerRequestId(id picker) {
|
||||
[locationHelper setDelegate:self];
|
||||
|
||||
self.motionManager = [[CMMotionManager alloc] init];
|
||||
|
||||
keyboardInputView_ = [[KeyboardInputView alloc] initWithFrame:CGRectZero];
|
||||
[self.view addSubview:keyboardInputView_];
|
||||
}
|
||||
|
||||
extern float g_safeInsetLeft;
|
||||
@@ -406,7 +431,15 @@ extern float g_safeInsetBottom;
|
||||
}
|
||||
|
||||
- (void)shareText:(NSString *)text {
|
||||
NSArray *items = @[text];
|
||||
[self shareItems:@[text]];
|
||||
}
|
||||
|
||||
- (void)shareFile:(NSURL *)url {
|
||||
// The share sheet works out the type from the extension.
|
||||
[self shareItems:@[url]];
|
||||
}
|
||||
|
||||
- (void)shareItems:(NSArray *)items {
|
||||
UIActivityViewController *viewController = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil];
|
||||
// On iPad, the share sheet is a popover and needs an anchor.
|
||||
viewController.popoverPresentationController.sourceView = self.view;
|
||||
@@ -419,56 +452,25 @@ extern float g_safeInsetBottom;
|
||||
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
|
||||
}
|
||||
|
||||
// The below is inspired by https://stackoverflow.com/questions/7253477/how-to-display-the-iphone-ipad-keyboard-over-a-full-screen-opengl-es-app
|
||||
// It's a bit limited but good enough.
|
||||
|
||||
- (void)deleteBackward {
|
||||
KeyInput input{};
|
||||
input.deviceId = DEVICE_ID_KEYBOARD;
|
||||
input.flags = KeyInputFlags::DOWN | KeyInputFlags::UP;
|
||||
input.keyCode = NKCODE_DEL;
|
||||
NativeKey(input);
|
||||
INFO_LOG(Log::System, "Backspace");
|
||||
}
|
||||
|
||||
- (void)insertText:(NSString *)text {
|
||||
std::string str([text UTF8String]);
|
||||
INFO_LOG(Log::System, "Chars: %s", str.c_str());
|
||||
SendKeyboardChars(str);
|
||||
}
|
||||
|
||||
- (BOOL)hasText {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Main thread, like the rest of these.
|
||||
- (void)showKeyboard {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
INFO_LOG(Log::System, "becomeFirstResponder");
|
||||
[self becomeFirstResponder];
|
||||
});
|
||||
INFO_LOG(Log::System, "showKeyboard");
|
||||
[keyboardInputView_ becomeFirstResponder];
|
||||
}
|
||||
|
||||
- (void)hideKeyboard {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
INFO_LOG(Log::System, "resignFirstResponder");
|
||||
[self resignFirstResponder];
|
||||
});
|
||||
if (keyboardInputView_.isFirstResponder) {
|
||||
INFO_LOG(Log::System, "hideKeyboard");
|
||||
[keyboardInputView_ resignFirstResponder];
|
||||
// Back to us, for hardware keyboard presses. We don't take text, so no keyboard comes with it.
|
||||
[self becomeFirstResponder];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeFirstResponder {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)buttonDown:(iCadeState)button
|
||||
{
|
||||
g_iCadeTracker.ButtonDown(button);
|
||||
}
|
||||
|
||||
- (void)buttonUp:(iCadeState)button
|
||||
{
|
||||
g_iCadeTracker.ButtonUp(button);
|
||||
}
|
||||
|
||||
- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
|
||||
KeyboardPressesBegan(presses, event);
|
||||
}
|
||||
@@ -520,8 +522,6 @@ extern float g_safeInsetBottom;
|
||||
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
// The immersive mode setting is per-orientation, so the status bar may need to change along with the rotation.
|
||||
[self setNeedsStatusBarAppearanceUpdate];
|
||||
|
||||
[self.view endEditing:YES]; // clears any input focus
|
||||
}
|
||||
|
||||
// Rotations and window resizes land here. UIKit lays out at the final size at the start of a
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#pragma once
|
||||
|
||||
#import "ViewControllerCommon.h"
|
||||
#import "iCade/iCadeReaderView.h"
|
||||
|
||||
@interface PPSSPPViewControllerMetal : PPSSPPBaseViewController
|
||||
@end
|
||||
|
||||
@@ -168,7 +168,6 @@ static void VulkanRenderLoop(GraphicsContext *graphicsContext, CAMetalLayer *met
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
[self hideKeyboard];
|
||||
|
||||
INFO_LOG(Log::System, "Metal viewDidLoad");
|
||||
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2011 by Stuart Carnie
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "iCadeState.h"
|
||||
|
||||
/*
|
||||
UP ON,OFF = w,e
|
||||
RT ON,OFF = d,c
|
||||
DN ON,OFF = x,z
|
||||
LT ON,OFF = a,q
|
||||
A ON,OFF = y,t
|
||||
B ON,OFF = h,r
|
||||
C ON,OFF = u,f
|
||||
D ON,OFF = j,n
|
||||
E ON,OFF = i,m
|
||||
F ON,OFF = k,p
|
||||
G ON,OFF = o,g
|
||||
H ON,OFF = l,v
|
||||
*/
|
||||
|
||||
@protocol iCadeEventDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
- (void)stateChanged:(iCadeState)state;
|
||||
- (void)buttonDown:(iCadeState)button;
|
||||
- (void)buttonUp:(iCadeState)button;
|
||||
|
||||
@end
|
||||
|
||||
@interface iCadeReaderView : UIView<UIKeyInput> {
|
||||
UIView *inputView;
|
||||
iCadeState _iCadeState;
|
||||
id<iCadeEventDelegate> __weak _delegate;
|
||||
|
||||
struct {
|
||||
bool stateChanged:1;
|
||||
bool buttonDown:1;
|
||||
bool buttonUp:1;
|
||||
} _delegateFlags;
|
||||
}
|
||||
|
||||
@property (nonatomic, assign) iCadeState iCadeState;
|
||||
@property (nonatomic, weak) id<iCadeEventDelegate> delegate;
|
||||
@property (nonatomic, assign) BOOL active;
|
||||
|
||||
@end
|
||||
@@ -1,140 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2011 by Stuart Carnie
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#import "iCadeReaderView.h"
|
||||
|
||||
static const char * const ON_STATES = "wdxayhujikol";
|
||||
static const char * const OFF_STATES = "eczqtrfnmpgv";
|
||||
|
||||
@interface iCadeReaderView()
|
||||
|
||||
- (void)didEnterBackground;
|
||||
- (void)didBecomeActive;
|
||||
|
||||
@end
|
||||
|
||||
@implementation iCadeReaderView
|
||||
|
||||
@synthesize iCadeState=_iCadeState, delegate=_delegate, active;
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
inputView = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)didEnterBackground {
|
||||
if (self.active)
|
||||
[self resignFirstResponder];
|
||||
}
|
||||
|
||||
- (void)didBecomeActive {
|
||||
if (self.active)
|
||||
[self becomeFirstResponder];
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeFirstResponder {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)setActive:(BOOL)value {
|
||||
if (active == value) return;
|
||||
|
||||
active = value;
|
||||
if (active) {
|
||||
[self becomeFirstResponder];
|
||||
} else {
|
||||
[self resignFirstResponder];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIView*) inputView {
|
||||
return inputView;
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id<iCadeEventDelegate>)delegate {
|
||||
_delegate = delegate;
|
||||
if (!_delegate) return;
|
||||
|
||||
/*_delegateFlags.stateChanged = [_delegate respondsToSelector:@selector(stateChanged:)];
|
||||
_delegateFlags.buttonDown = [_delegate respondsToSelector:@selector(buttonDown:)];
|
||||
_delegateFlags.buttonUp = [_delegate respondsToSelector:@selector(buttonUp:)];*/
|
||||
}
|
||||
|
||||
/*#pragma mark -
|
||||
#pragma mark UIKeyInput Protocol Methods
|
||||
|
||||
- (BOOL)hasText {
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)insertText:(NSString *)text {
|
||||
|
||||
char ch = [text characterAtIndex:0];
|
||||
char *p = strchr(ON_STATES, ch);
|
||||
bool stateChanged = false;
|
||||
if (p) {
|
||||
int index = p-ON_STATES;
|
||||
_iCadeState |= (1 << index);
|
||||
stateChanged = true;
|
||||
if (_delegateFlags.buttonDown) {
|
||||
[_delegate buttonDown:(1 << index)];
|
||||
}
|
||||
} else {
|
||||
p = strchr(OFF_STATES, ch);
|
||||
if (p) {
|
||||
int index = p-OFF_STATES;
|
||||
_iCadeState &= ~(1 << index);
|
||||
stateChanged = true;
|
||||
if (_delegateFlags.buttonUp) {
|
||||
[_delegate buttonUp:(1 << index)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stateChanged && _delegateFlags.stateChanged) {
|
||||
[_delegate stateChanged:_iCadeState];
|
||||
}
|
||||
|
||||
static int cycleResponder = 0;
|
||||
if (++cycleResponder > 20) {
|
||||
// necessary to clear a buffer that accumulates internally
|
||||
cycleResponder = 0;
|
||||
[self resignFirstResponder];
|
||||
[self becomeFirstResponder];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)deleteBackward {
|
||||
// This space intentionally left blank to complete protocol
|
||||
}*/
|
||||
|
||||
@end
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2011 by Stuart Carnie
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
typedef enum iCadeState {
|
||||
iCadeJoystickNone = 0x000,
|
||||
iCadeJoystickUp = 0x001,
|
||||
iCadeJoystickRight = 0x002,
|
||||
iCadeJoystickDown = 0x004,
|
||||
iCadeJoystickLeft = 0x008,
|
||||
|
||||
iCadeJoystickUpRight = iCadeJoystickUp | iCadeJoystickRight,
|
||||
iCadeJoystickDownRight = iCadeJoystickDown | iCadeJoystickRight,
|
||||
iCadeJoystickUpLeft = iCadeJoystickUp | iCadeJoystickLeft,
|
||||
iCadeJoystickDownLeft = iCadeJoystickDown | iCadeJoystickLeft,
|
||||
|
||||
iCadeButtonA = 0x010,
|
||||
iCadeButtonB = 0x020,
|
||||
iCadeButtonC = 0x040,
|
||||
iCadeButtonD = 0x080,
|
||||
iCadeButtonE = 0x100,
|
||||
iCadeButtonF = 0x200,
|
||||
iCadeButtonG = 0x400,
|
||||
iCadeButtonH = 0x800,
|
||||
|
||||
} iCadeState;
|
||||
+15
@@ -377,6 +377,7 @@ bool System_GetPropertyBool(SystemProperty prop) {
|
||||
case SYSPROP_HAS_KEYBOARD:
|
||||
return true;
|
||||
case SYSPROP_SUPPORTS_SHARE_TEXT:
|
||||
case SYSPROP_SUPPORTS_SHARE_FILE:
|
||||
return true;
|
||||
case SYSPROP_KEYBOARD_IS_SOFT:
|
||||
// If a hardware keyboard is connected, and we add support, we could return false here.
|
||||
@@ -586,6 +587,20 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
|
||||
});
|
||||
return true;
|
||||
}
|
||||
case SystemRequestType::SHARE_FILE:
|
||||
{
|
||||
// param2, the MIME type, isn't needed. The share sheet goes by the extension.
|
||||
NSString *path = [NSString stringWithUTF8String:param1.c_str()];
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
|
||||
ERROR_LOG(Log::System, "SHARE_FILE: '%s' doesn't exist", param1.c_str());
|
||||
return false;
|
||||
}
|
||||
NSURL *url = [NSURL fileURLWithPath:path];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[sharedViewController shareFile:url];
|
||||
});
|
||||
return true;
|
||||
}
|
||||
case SystemRequestType::NOTIFY_UI_EVENT:
|
||||
{
|
||||
const UIEventNotification event = (UIEventNotification)param3;
|
||||
|
||||
Reference in new issue
Block a user