mirror of
https://github.com/encounter/SDL.git
synced 2025-12-09 13:37:56 +00:00
Initial Apple TV / tvOS support.
The Apple TV remote is currently exposed as a joystick with its touch surface treated as two axes. Key presses are also generated when its buttons and touch surface are used. A new hint has been added to help deal with deciding whether to background the app when the remote's menu button is pressed: SDL_HINT_APPLE_TV_CONTROLLER_UI_EVENTS.
This commit is contained in:
@@ -443,6 +443,8 @@ SDL_GetPlatform()
|
||||
return "Windows";
|
||||
#elif __WINRT__
|
||||
return "WinRT";
|
||||
#elif __TVOS__
|
||||
return "tvOS";
|
||||
#elif __IPHONEOS__
|
||||
return "iOS";
|
||||
#elif __PSP__
|
||||
|
||||
@@ -274,7 +274,7 @@ static int open_capture_devices = 0;
|
||||
|
||||
static void update_audio_session()
|
||||
{
|
||||
#if !MACOSX_COREAUDIO
|
||||
#if !MACOSX_COREAUDIO && !TARGET_OS_TV
|
||||
/* !!! FIXME: move this to AVAudioSession. This is deprecated, and the new version is available as of (ancient!) iOS 3.0 */
|
||||
UInt32 category;
|
||||
if (open_playback_devices && open_capture_devices) {
|
||||
@@ -569,8 +569,8 @@ prepare_audioqueue(_THIS)
|
||||
/* We're running! */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
audioqueue_thread(void *arg)
|
||||
{
|
||||
SDL_AudioDevice *this = (SDL_AudioDevice *) arg;
|
||||
@@ -725,9 +725,11 @@ COREAUDIO_Init(SDL_AudioDriverImpl * impl)
|
||||
!!! FIXME: do this when a device is opened, and deinitialize when all devices close.
|
||||
*/
|
||||
/* !!! FIXME: move this to AVAudioSession. This is deprecated, and the new version is available as of (ancient!) iOS 3.0 */
|
||||
#if !TARGET_OS_TV
|
||||
AudioSessionInitialize(NULL, NULL, NULL, nil);
|
||||
UInt32 category = kAudioSessionCategory_AmbientSound;
|
||||
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(UInt32), &category);
|
||||
#endif /* !TARGET_OS_TV */
|
||||
#endif
|
||||
|
||||
impl->ProvidesOwnCallbackThread = 1;
|
||||
|
||||
@@ -33,7 +33,13 @@
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "../SDL_joystick_c.h"
|
||||
|
||||
#if !SDL_EVENTS_DISABLED
|
||||
#include "../../events/SDL_events_c.h"
|
||||
#endif
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
#import <CoreMotion/CoreMotion.h>
|
||||
#endif
|
||||
|
||||
#ifdef SDL_JOYSTICK_MFI
|
||||
#import <GameController/GameController.h>
|
||||
@@ -42,8 +48,10 @@ static id connectObserver = nil;
|
||||
static id disconnectObserver = nil;
|
||||
#endif /* SDL_JOYSTICK_MFI */
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
static const char *accelerometerName = "iOS Accelerometer";
|
||||
static CMMotionManager *motionManager = nil;
|
||||
#endif /* !TARGET_OS_TV */
|
||||
|
||||
static SDL_JoystickDeviceItem *deviceList = NULL;
|
||||
|
||||
@@ -102,6 +110,11 @@ SDL_SYS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *contr
|
||||
} else if (controller.gamepad) {
|
||||
device->guid.data[10] = 2;
|
||||
}
|
||||
#if TARGET_OS_TV
|
||||
else if (controller.microGamepad) {
|
||||
device->guid.data[10] = 3;
|
||||
}
|
||||
#endif /* TARGET_OS_TV */
|
||||
|
||||
if (controller.extendedGamepad) {
|
||||
device->naxes = 6; /* 2 thumbsticks and 2 triggers */
|
||||
@@ -112,12 +125,19 @@ SDL_SYS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *contr
|
||||
device->nhats = 1; /* d-pad */
|
||||
device->nbuttons = 7; /* ABXY, shoulder buttons, pause button */
|
||||
}
|
||||
/* TODO: Handle micro profiles on tvOS. */
|
||||
#if TARGET_OS_TV
|
||||
else if (controller.microGamepad) {
|
||||
device->naxes = 2; /* treat the touch surface as two axes */
|
||||
device->nhats = 0; /* apparently the touch surface-as-dpad is buggy */
|
||||
device->nbuttons = 3; /* AX, pause button */
|
||||
}
|
||||
#endif /* TARGET_OS_TV */
|
||||
|
||||
/* This will be set when the first button press of the controller is
|
||||
* detected. */
|
||||
controller.playerIndex = -1;
|
||||
#endif
|
||||
|
||||
#endif /* SDL_JOYSTICK_MFI */
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -143,6 +163,10 @@ SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer)
|
||||
device->instance_id = instancecounter++;
|
||||
|
||||
if (accelerometer) {
|
||||
#if TARGET_OS_TV
|
||||
SDL_free(device);
|
||||
return;
|
||||
#else
|
||||
device->name = SDL_strdup(accelerometerName);
|
||||
device->naxes = 3; /* Device acceleration in the x, y, and z axes. */
|
||||
device->nhats = 0;
|
||||
@@ -150,6 +174,7 @@ SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer)
|
||||
|
||||
/* Use the accelerometer name as a GUID. */
|
||||
SDL_memcpy(&device->guid.data, device->name, SDL_min(sizeof(SDL_JoystickGUID), SDL_strlen(device->name)));
|
||||
#endif /* TARGET_OS_TV */
|
||||
} else if (controller) {
|
||||
SDL_SYS_AddMFIJoystickDevice(device, controller);
|
||||
}
|
||||
@@ -232,12 +257,14 @@ SDL_SYS_JoystickInit(void)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
const char *hint = SDL_GetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK);
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
const char *hint = SDL_GetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK);
|
||||
if (!hint || SDL_atoi(hint)) {
|
||||
/* Default behavior, accelerometer as joystick */
|
||||
SDL_SYS_AddJoystickDevice(nil, SDL_TRUE);
|
||||
}
|
||||
#endif /* !TARGET_OS_TV */
|
||||
|
||||
#ifdef SDL_JOYSTICK_MFI
|
||||
/* GameController.framework was added in iOS 7. */
|
||||
@@ -326,6 +353,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
|
||||
@autoreleasepool {
|
||||
if (device->accelerometer) {
|
||||
#if !TARGET_OS_TV
|
||||
if (motionManager == nil) {
|
||||
motionManager = [[CMMotionManager alloc] init];
|
||||
}
|
||||
@@ -333,6 +361,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
/* Shorter times between updates can significantly increase CPU usage. */
|
||||
motionManager.accelerometerUpdateInterval = 0.1;
|
||||
[motionManager startAccelerometerUpdates];
|
||||
#endif /* !TARGET_OS_TV */
|
||||
} else {
|
||||
#ifdef SDL_JOYSTICK_MFI
|
||||
GCController *controller = device->controller;
|
||||
@@ -358,6 +387,7 @@ SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
|
||||
static void
|
||||
SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
#if !TARGET_OS_TV
|
||||
const float maxgforce = SDL_IPHONE_MAX_GFORCE;
|
||||
const SInt16 maxsint16 = 0x7FFF;
|
||||
CMAcceleration accel;
|
||||
@@ -395,6 +425,7 @@ SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick)
|
||||
SDL_PrivateJoystickAxis(joystick, 0, (accel.x / maxgforce) * maxsint16);
|
||||
SDL_PrivateJoystickAxis(joystick, 1, -(accel.y / maxgforce) * maxsint16);
|
||||
SDL_PrivateJoystickAxis(joystick, 2, (accel.z / maxgforce) * maxsint16);
|
||||
#endif /* !TARGET_OS_TV */
|
||||
}
|
||||
|
||||
#ifdef SDL_JOYSTICK_MFI
|
||||
@@ -426,7 +457,7 @@ SDL_SYS_MFIJoystickHatStateForDPad(GCControllerDirectionPad *dpad)
|
||||
static void
|
||||
SDL_SYS_MFIJoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
#ifdef SDL_JOYSTICK_MFI
|
||||
#if SDL_JOYSTICK_MFI
|
||||
@autoreleasepool {
|
||||
GCController *controller = joystick->hwdata->controller;
|
||||
Uint8 hatstate = SDL_HAT_CENTERED;
|
||||
@@ -482,13 +513,43 @@ SDL_SYS_MFIJoystickUpdate(SDL_Joystick * joystick)
|
||||
};
|
||||
|
||||
hatstate = SDL_SYS_MFIJoystickHatStateForDPad(gamepad.dpad);
|
||||
SDL_PrivateJoystickHat(joystick, 0, hatstate);
|
||||
|
||||
for (i = 0; i < SDL_arraysize(buttons); i++) {
|
||||
updateplayerindex |= (joystick->buttons[i] != buttons[i]);
|
||||
SDL_PrivateJoystickButton(joystick, i, buttons[i]);
|
||||
}
|
||||
}
|
||||
/* TODO: Handle micro profiles on tvOS. */
|
||||
#if TARGET_OS_TV
|
||||
else if (controller.microGamepad) {
|
||||
GCMicroGamepad *gamepad = controller.microGamepad;
|
||||
|
||||
Sint16 axes[] = {
|
||||
(Sint16) (gamepad.dpad.xAxis.value * 32767),
|
||||
(Sint16) (gamepad.dpad.yAxis.value * -32767),
|
||||
};
|
||||
|
||||
for (i = 0; i < SDL_arraysize(axes); i++) {
|
||||
updateplayerindex |= (joystick->axes[i] != axes[i]);
|
||||
SDL_PrivateJoystickAxis(joystick, i, axes[i]);
|
||||
}
|
||||
|
||||
/* Apparently the dpad values are not accurate enough to be useful. */
|
||||
/* hatstate = SDL_SYS_MFIJoystickHatStateForDPad(gamepad.dpad); */
|
||||
|
||||
Uint8 buttons[] = {
|
||||
gamepad.buttonA.isPressed,
|
||||
gamepad.buttonX.isPressed,
|
||||
};
|
||||
|
||||
for (i = 0; i < SDL_arraysize(buttons); i++) {
|
||||
updateplayerindex |= (joystick->buttons[i] != buttons[i]);
|
||||
SDL_PrivateJoystickButton(joystick, i, buttons[i]);
|
||||
}
|
||||
|
||||
/* TODO: Figure out what to do with reportsAbsoluteDpadValues */
|
||||
}
|
||||
#endif /* TARGET_OS_TV */
|
||||
|
||||
if (joystick->nhats > 0) {
|
||||
updateplayerindex |= (joystick->hats[0] != hatstate);
|
||||
@@ -528,7 +589,7 @@ SDL_SYS_MFIJoystickUpdate(SDL_Joystick * joystick)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* SDL_JOYSTICK_MFI */
|
||||
}
|
||||
|
||||
/* Function to update the state of a joystick - called as a device poll.
|
||||
@@ -566,7 +627,9 @@ SDL_SYS_JoystickClose(SDL_Joystick * joystick)
|
||||
|
||||
@autoreleasepool {
|
||||
if (device->accelerometer) {
|
||||
#if !TARGET_OS_TV
|
||||
[motionManager stopAccelerometerUpdates];
|
||||
#endif /* !TARGET_OS_TV */
|
||||
} else if (device->controller) {
|
||||
#ifdef SDL_JOYSTICK_MFI
|
||||
GCController *controller = device->controller;
|
||||
@@ -600,7 +663,9 @@ SDL_SYS_JoystickQuit(void)
|
||||
SDL_SYS_RemoveJoystickDevice(deviceList);
|
||||
}
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
motionManager = nil;
|
||||
#endif /* !TARGET_OS_TV */
|
||||
}
|
||||
|
||||
numjoysticks = 0;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_syspower.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
/* turn off the battery monitor if it's been more than X ms since last check. */
|
||||
static const int BATTERY_MONITORING_TIMEOUT = 3000;
|
||||
static Uint32 SDL_UIKitLastPowerInfoQuery = 0;
|
||||
@@ -46,10 +47,22 @@ SDL_UIKit_UpdateBatteryMonitoring(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void
|
||||
SDL_UIKit_UpdateBatteryMonitoring(void)
|
||||
{
|
||||
/* Do nothing. */
|
||||
}
|
||||
#endif /* !TARGET_OS_TV */
|
||||
|
||||
SDL_bool
|
||||
SDL_GetPowerInfo_UIKit(SDL_PowerState * state, int *seconds, int *percent)
|
||||
{
|
||||
#if TARGET_OS_TV
|
||||
*state = SDL_POWERSTATE_NO_BATTERY;
|
||||
*seconds = -1;
|
||||
*percent = -1;
|
||||
#else /* TARGET_OS_TV */
|
||||
@autoreleasepool {
|
||||
UIDevice *uidev = [UIDevice currentDevice];
|
||||
|
||||
@@ -88,8 +101,10 @@ SDL_GetPowerInfo_UIKit(SDL_PowerState * state, int *seconds, int *percent)
|
||||
|
||||
const float level = uidev.batteryLevel;
|
||||
*percent = ( (level < 0.0f) ? -1 : ((int) ((level * 100) + 0.5f)) );
|
||||
return SDL_TRUE; /* always the definitive answer on iOS. */
|
||||
}
|
||||
#endif /* TARGET_OS_TV */
|
||||
|
||||
return SDL_TRUE; /* always the definitive answer on iOS. */
|
||||
}
|
||||
|
||||
#endif /* SDL_POWER_UIKIT */
|
||||
|
||||
@@ -343,7 +343,7 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery,
|
||||
SDL_Surface *rz_dst;
|
||||
int is32bit;
|
||||
int i;
|
||||
Uint8 r,g,b;
|
||||
Uint8 r = 0,g = 0,b = 0;
|
||||
Uint32 colorkey = 0;
|
||||
int colorKeyAvailable = 0;
|
||||
double sangleinv, cangleinv;
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
- (instancetype)init;
|
||||
- (void)loadView;
|
||||
- (NSUInteger)supportedInterfaceOrientations;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ SDL_IdleTimerDisabledChanged(void *userdata, const char *name, const char *oldVa
|
||||
[UIApplication sharedApplication].idleTimerDisabled = disable;
|
||||
}
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
/* Load a launch image using the old UILaunchImageFile-era naming rules. */
|
||||
static UIImage *
|
||||
SDL_LoadLaunchImageNamed(NSString *name, int screenh)
|
||||
@@ -114,6 +115,15 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh)
|
||||
|
||||
return image;
|
||||
}
|
||||
#endif /* !TARGET_OS_TV */
|
||||
|
||||
@interface SDLLaunchScreenController ()
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
- (NSUInteger)supportedInterfaceOrientations;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDLLaunchScreenController
|
||||
|
||||
@@ -140,6 +150,7 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh)
|
||||
}
|
||||
|
||||
if (!self.view) {
|
||||
#if !TARGET_OS_TV
|
||||
NSArray *launchimages = [bundle objectForInfoDictionaryKey:@"UILaunchImages"];
|
||||
UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation;
|
||||
NSString *imagename = nil;
|
||||
@@ -244,6 +255,9 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh)
|
||||
|
||||
self.view = view;
|
||||
}
|
||||
#else /* !TARGET_OS_TV */
|
||||
return nil;
|
||||
#endif
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -254,6 +268,7 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh)
|
||||
/* Do nothing. */
|
||||
}
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
- (BOOL)shouldAutorotate
|
||||
{
|
||||
/* If YES, the launch image will be incorrectly rotated in some cases. */
|
||||
@@ -267,6 +282,7 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh)
|
||||
* the ones set here (it will cause an exception in that case.) */
|
||||
return UIInterfaceOrientationMaskAll;
|
||||
}
|
||||
#endif /* !TARGET_OS_TV */
|
||||
|
||||
@end
|
||||
|
||||
@@ -381,6 +397,7 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh)
|
||||
SDL_SendAppEvent(SDL_APP_LOWMEMORY);
|
||||
}
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
- (void)application:(UIApplication *)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation
|
||||
{
|
||||
BOOL isLandscape = UIInterfaceOrientationIsLandscape(application.statusBarOrientation);
|
||||
@@ -408,6 +425,7 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication*)application
|
||||
{
|
||||
|
||||
@@ -30,15 +30,22 @@
|
||||
int
|
||||
UIKit_SetClipboardText(_THIS, const char *text)
|
||||
{
|
||||
#if TARGET_OS_TV
|
||||
return SDL_SetError("The clipboard is not available on tvOS");
|
||||
#else
|
||||
@autoreleasepool {
|
||||
[UIPasteboard generalPasteboard].string = @(text);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
char *
|
||||
UIKit_GetClipboardText(_THIS)
|
||||
{
|
||||
#if TARGET_OS_TV
|
||||
return SDL_strdup(""); // Unsupported.
|
||||
#else
|
||||
@autoreleasepool {
|
||||
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
|
||||
NSString *string = pasteboard.string;
|
||||
@@ -49,15 +56,18 @@ UIKit_GetClipboardText(_THIS)
|
||||
return SDL_strdup("");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
UIKit_HasClipboardText(_THIS)
|
||||
{
|
||||
@autoreleasepool {
|
||||
#if !TARGET_OS_TV
|
||||
if ([UIPasteboard generalPasteboard].string != nil) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
#endif
|
||||
return SDL_FALSE;
|
||||
}
|
||||
}
|
||||
@@ -65,6 +75,7 @@ UIKit_HasClipboardText(_THIS)
|
||||
void
|
||||
UIKit_InitClipboard(_THIS)
|
||||
{
|
||||
#if !TARGET_OS_TV
|
||||
@autoreleasepool {
|
||||
SDL_VideoData *data = (__bridge SDL_VideoData *) _this->driverdata;
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
@@ -78,6 +89,7 @@ UIKit_InitClipboard(_THIS)
|
||||
|
||||
data.pasteboardObserver = observer;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -156,9 +156,12 @@ UIKit_AddDisplay(UIScreen *uiscreen)
|
||||
SDL_bool
|
||||
UIKit_IsDisplayLandscape(UIScreen *uiscreen)
|
||||
{
|
||||
#if !TARGET_OS_TV
|
||||
if (uiscreen == [UIScreen mainScreen]) {
|
||||
return UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation);
|
||||
} else {
|
||||
} else
|
||||
#endif /* !TARGET_OS_TV */
|
||||
{
|
||||
CGSize size = uiscreen.bounds.size;
|
||||
return (size.width > size.height);
|
||||
}
|
||||
@@ -187,6 +190,14 @@ UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
|
||||
SDL_bool isLandscape = UIKit_IsDisplayLandscape(data.uiscreen);
|
||||
SDL_bool addRotation = (data.uiscreen == [UIScreen mainScreen]);
|
||||
CGFloat scale = data.uiscreen.scale;
|
||||
NSArray *availableModes = nil;
|
||||
|
||||
#if TARGET_OS_TV
|
||||
addRotation = SDL_FALSE;
|
||||
availableModes = @[data.uiscreen.currentMode];
|
||||
#else
|
||||
availableModes = data.uiscreen.availableModes;
|
||||
#endif
|
||||
|
||||
#ifdef __IPHONE_8_0
|
||||
/* The UIScreenMode of an iPhone 6 Plus should be 1080x1920 rather than
|
||||
@@ -196,7 +207,7 @@ UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
|
||||
}
|
||||
#endif
|
||||
|
||||
for (UIScreenMode *uimode in data.uiscreen.availableModes) {
|
||||
for (UIScreenMode *uimode in availableModes) {
|
||||
/* The size of a UIScreenMode is in pixels, but we deal exclusively
|
||||
* in points (except in SDL_GL_GetDrawableSize.) */
|
||||
int w = (int)(uimode.size.width / scale);
|
||||
@@ -219,9 +230,11 @@ UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
|
||||
SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)mode->driverdata;
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)mode->driverdata;
|
||||
[data.uiscreen setCurrentMode:modedata.uiscreenmode];
|
||||
#endif
|
||||
|
||||
if (data.uiscreen == [UIScreen mainScreen]) {
|
||||
/* [UIApplication setStatusBarOrientation:] no longer works reliably
|
||||
@@ -245,20 +258,30 @@ UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
|
||||
int
|
||||
UIKit_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
|
||||
{
|
||||
/* the default function iterates displays to make a fake offset,
|
||||
as if all the displays were side-by-side, which is fine for iOS. */
|
||||
const int displayIndex = (int) (display - _this->displays);
|
||||
if (SDL_GetDisplayBounds(displayIndex, rect) < 0) {
|
||||
return -1;
|
||||
@autoreleasepool {
|
||||
int displayIndex = (int) (display - _this->displays);
|
||||
SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
|
||||
|
||||
/* the default function iterates displays to make a fake offset,
|
||||
as if all the displays were side-by-side, which is fine for iOS. */
|
||||
if (SDL_GetDisplayBounds(displayIndex, rect) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
CGRect frame = data.uiscreen.bounds;
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
if (!UIKit_IsSystemVersionAtLeast(7.0)) {
|
||||
frame = [data.uiscreen applicationFrame];
|
||||
}
|
||||
#endif
|
||||
|
||||
rect->x += frame.origin.x;
|
||||
rect->y += frame.origin.y;
|
||||
rect->w = frame.size.width;
|
||||
rect->h = frame.size.height;
|
||||
}
|
||||
|
||||
SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
|
||||
const CGRect frame = [data.uiscreen applicationFrame];
|
||||
const float scale = (float) data.uiscreen.scale;
|
||||
rect->x += (int) (frame.origin.x * scale);
|
||||
rect->y += (int) (frame.origin.y * scale);
|
||||
rect->w = (int) (frame.size.width * scale);
|
||||
rect->h = (int) (frame.size.height * scale);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -176,6 +176,7 @@ UIKit_IsSystemVersionAtLeast(double version)
|
||||
CGRect
|
||||
UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen)
|
||||
{
|
||||
#if !TARGET_OS_TV && (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0)
|
||||
BOOL hasiOS7 = UIKit_IsSystemVersionAtLeast(7.0);
|
||||
|
||||
if (hasiOS7 || (window->flags & (SDL_WINDOW_BORDERLESS|SDL_WINDOW_FULLSCREEN))) {
|
||||
@@ -184,6 +185,9 @@ UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen)
|
||||
} else {
|
||||
return screen.applicationFrame;
|
||||
}
|
||||
#else
|
||||
return screen.bounds;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -45,7 +45,9 @@
|
||||
self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
self.autoresizesSubviews = YES;
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
self.multipleTouchEnabled = YES;
|
||||
#endif
|
||||
|
||||
touchId = 1;
|
||||
SDL_AddTouch(touchId, "");
|
||||
@@ -197,6 +199,69 @@
|
||||
}
|
||||
}
|
||||
|
||||
#if TARGET_OS_TV || defined(__IPHONE_9_1)
|
||||
- (SDL_Scancode)scancodeFromPressType:(UIPressType)presstype
|
||||
{
|
||||
switch (presstype) {
|
||||
case UIPressTypeUpArrow:
|
||||
return SDL_SCANCODE_UP;
|
||||
case UIPressTypeDownArrow:
|
||||
return SDL_SCANCODE_DOWN;
|
||||
case UIPressTypeLeftArrow:
|
||||
return SDL_SCANCODE_LEFT;
|
||||
case UIPressTypeRightArrow:
|
||||
return SDL_SCANCODE_RIGHT;
|
||||
case UIPressTypeSelect:
|
||||
/* HIG says: "primary button behavior" */
|
||||
return SDL_SCANCODE_SELECT;
|
||||
case UIPressTypeMenu:
|
||||
/* HIG says: "returns to previous screen" */
|
||||
return SDL_SCANCODE_MENU;
|
||||
case UIPressTypePlayPause:
|
||||
/* HIG says: "secondary button behavior" */
|
||||
return SDL_SCANCODE_PAUSE;
|
||||
default:
|
||||
return SDL_SCANCODE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
|
||||
{
|
||||
for (UIPress *press in presses) {
|
||||
SDL_Scancode scancode = [self scancodeFromPressType:press.type];
|
||||
SDL_SendKeyboardKey(SDL_PRESSED, scancode);
|
||||
}
|
||||
|
||||
[super pressesBegan:presses withEvent:event];
|
||||
}
|
||||
|
||||
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
|
||||
{
|
||||
for (UIPress *press in presses) {
|
||||
SDL_Scancode scancode = [self scancodeFromPressType:press.type];
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, scancode);
|
||||
}
|
||||
|
||||
[super pressesEnded:presses withEvent:event];
|
||||
}
|
||||
|
||||
- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
|
||||
{
|
||||
for (UIPress *press in presses) {
|
||||
SDL_Scancode scancode = [self scancodeFromPressType:press.type];
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, scancode);
|
||||
}
|
||||
|
||||
[super pressesCancelled:presses withEvent:event];
|
||||
}
|
||||
|
||||
- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
|
||||
{
|
||||
/* This is only called when the force of a press changes. */
|
||||
[super pressesChanged:presses withEvent:event];
|
||||
}
|
||||
#endif /* TARGET_OS_TV || defined(__IPHONE_9_1) */
|
||||
|
||||
@end
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_UIKIT */
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@@ -25,10 +26,17 @@
|
||||
|
||||
#include "SDL_touch.h"
|
||||
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
@interface SDL_uikitviewcontroller : UIViewController <UITextFieldDelegate>
|
||||
#if TARGET_OS_TV
|
||||
#import <GameController/GameController.h>
|
||||
#define SDLRootViewController GCEventViewController
|
||||
#else
|
||||
@interface SDL_uikitviewcontroller : UIViewController
|
||||
#define SDLRootViewController UIViewController
|
||||
#endif
|
||||
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
@interface SDL_uikitviewcontroller : SDLRootViewController <UITextFieldDelegate>
|
||||
#else
|
||||
@interface SDL_uikitviewcontroller : SDLRootViewController
|
||||
#endif
|
||||
|
||||
@property (nonatomic, assign) SDL_Window *window;
|
||||
@@ -46,8 +54,11 @@
|
||||
|
||||
- (void)loadView;
|
||||
- (void)viewDidLayoutSubviews;
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
- (NSUInteger)supportedInterfaceOrientations;
|
||||
- (BOOL)prefersStatusBarHidden;
|
||||
#endif
|
||||
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
- (void)showKeyboard;
|
||||
|
||||
@@ -39,6 +39,17 @@
|
||||
#include "keyinfotable.h"
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_TV
|
||||
static void
|
||||
SDL_AppleTVControllerUIHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_uikitviewcontroller *viewcontroller = (__bridge SDL_uikitviewcontroller *) userdata;
|
||||
viewcontroller.controllerUserInteractionEnabled = hint && (*hint != '0');
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@implementation SDL_uikitviewcontroller {
|
||||
CADisplayLink *displayLink;
|
||||
int animationInterval;
|
||||
@@ -60,6 +71,12 @@
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
[self initKeyboard];
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_TV
|
||||
SDL_AddHintCallback(SDL_HINT_APPLE_TV_CONTROLLER_UI_EVENTS,
|
||||
SDL_AppleTVControllerUIHintChanged,
|
||||
(__bridge void *) self);
|
||||
#endif
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -69,6 +86,12 @@
|
||||
#if SDL_IPHONE_KEYBOARD
|
||||
[self deinitKeyboard];
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_TV
|
||||
SDL_DelHintCallback(SDL_HINT_APPLE_TV_CONTROLLER_UI_EVENTS,
|
||||
SDL_AppleTVControllerUIHintChanged,
|
||||
(__bridge void *) self);
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)setAnimationCallback:(int)interval
|
||||
@@ -124,6 +147,7 @@
|
||||
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, w, h);
|
||||
}
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
- (NSUInteger)supportedInterfaceOrientations
|
||||
{
|
||||
return UIKit_GetSupportedOrientations(window);
|
||||
@@ -138,6 +162,7 @@
|
||||
{
|
||||
return (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) != 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
---- Keyboard related functionality below this line ----
|
||||
@@ -168,9 +193,11 @@
|
||||
textField.hidden = YES;
|
||||
keyboardVisible = NO;
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
[center addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
|
||||
[center addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)setView:(UIView *)view
|
||||
@@ -186,9 +213,11 @@
|
||||
|
||||
- (void)deinitKeyboard
|
||||
{
|
||||
#if !TARGET_OS_TV
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
[center removeObserver:self name:UIKeyboardWillShowNotification object:nil];
|
||||
[center removeObserver:self name:UIKeyboardWillHideNotification object:nil];
|
||||
#endif
|
||||
}
|
||||
|
||||
/* reveal onscreen virtual keyboard */
|
||||
@@ -209,6 +238,7 @@
|
||||
|
||||
- (void)keyboardWillShow:(NSNotification *)notification
|
||||
{
|
||||
#if !TARGET_OS_TV
|
||||
CGRect kbrect = [[notification userInfo][UIKeyboardFrameBeginUserInfoKey] CGRectValue];
|
||||
|
||||
/* The keyboard rect is in the coordinate space of the screen/window, but we
|
||||
@@ -216,6 +246,7 @@
|
||||
kbrect = [self.view convertRect:kbrect fromView:nil];
|
||||
|
||||
[self setKeyboardHeight:(int)kbrect.size.height];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)keyboardWillHide:(NSNotification *)notification
|
||||
|
||||
@@ -107,6 +107,7 @@ static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bo
|
||||
window->flags |= SDL_WINDOW_BORDERLESS; /* never has a status bar. */
|
||||
}
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
if (displaydata.uiscreen == [UIScreen mainScreen]) {
|
||||
NSUInteger orients = UIKit_GetSupportedOrientations(window);
|
||||
BOOL supportsLandscape = (orients & UIInterfaceOrientationMaskLandscape) != 0;
|
||||
@@ -119,6 +120,7 @@ static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bo
|
||||
height = temp;
|
||||
}
|
||||
}
|
||||
#endif /* !TARGET_OS_TV */
|
||||
|
||||
window->x = 0;
|
||||
window->y = 0;
|
||||
@@ -152,7 +154,6 @@ UIKit_CreateWindow(_THIS, SDL_Window *window)
|
||||
@autoreleasepool {
|
||||
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
|
||||
SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata;
|
||||
const CGSize origsize = data.uiscreen.currentMode.size;
|
||||
|
||||
/* SDL currently puts this window at the start of display's linked list. We rely on this. */
|
||||
SDL_assert(_this->windows == window);
|
||||
@@ -165,6 +166,8 @@ UIKit_CreateWindow(_THIS, SDL_Window *window)
|
||||
/* If monitor has a resolution of 0x0 (hasn't been explicitly set by the
|
||||
* user, so it's in standby), try to force the display to a resolution
|
||||
* that most closely matches the desired window size. */
|
||||
#if !TARGET_OS_TV
|
||||
const CGSize origsize = data.uiscreen.currentMode.size;
|
||||
if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
|
||||
if (display->num_display_modes == 0) {
|
||||
_this->GetDisplayModes(_this, display);
|
||||
@@ -197,6 +200,7 @@ UIKit_CreateWindow(_THIS, SDL_Window *window)
|
||||
[UIApplication sharedApplication].statusBarHidden = NO;
|
||||
}
|
||||
}
|
||||
#endif /* !TARGET_OS_TV */
|
||||
|
||||
/* ignore the size user requested, and make a fullscreen window */
|
||||
/* !!! FIXME: can we have a smaller view? */
|
||||
@@ -258,6 +262,7 @@ UIKit_UpdateWindowBorder(_THIS, SDL_Window * window)
|
||||
SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
|
||||
SDL_uikitviewcontroller *viewcontroller = data.viewcontroller;
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
if (data.uiwindow.screen == [UIScreen mainScreen]) {
|
||||
if (window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS)) {
|
||||
[UIApplication sharedApplication].statusBarHidden = YES;
|
||||
@@ -273,6 +278,7 @@ UIKit_UpdateWindowBorder(_THIS, SDL_Window * window)
|
||||
|
||||
/* Update the view's frame to account for the status bar change. */
|
||||
viewcontroller.view.frame = UIKit_ComputeViewFrame(window, data.uiwindow.screen);
|
||||
#endif /* !TARGET_OS_TV */
|
||||
|
||||
#ifdef SDL_IPHONE_KEYBOARD
|
||||
/* Make sure the view is offset correctly when the keyboard is visible. */
|
||||
@@ -363,6 +369,7 @@ UIKit_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
|
||||
}
|
||||
}
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
NSUInteger
|
||||
UIKit_GetSupportedOrientations(SDL_Window * window)
|
||||
{
|
||||
@@ -428,6 +435,7 @@ UIKit_GetSupportedOrientations(SDL_Window * window)
|
||||
|
||||
return orientationMask;
|
||||
}
|
||||
#endif /* !TARGET_OS_TV */
|
||||
|
||||
int
|
||||
SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam)
|
||||
|
||||
Reference in New Issue
Block a user