mirror of
https://github.com/libretro/RetroArch
synced 2025-03-28 19:20:35 +00:00
tvOS Siri remote handling
It's not really usable as a game controller, but it is good for going through the menu as a simple LRUD. This also adds better support for names of mFI controllers, as well as being able to do the expected tvOS behavior of "backing out" of the app.
This commit is contained in:
parent
0674613d28
commit
dda7776252
@ -873,7 +873,7 @@
|
||||
#define DEFAULT_OVERLAY_DPAD_DIAGONAL_SENSITIVITY 80
|
||||
#define DEFAULT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY 50
|
||||
|
||||
#if defined(ANDROID) || defined(_WIN32) || defined(HAVE_STEAM)
|
||||
#if defined(ANDROID) || defined(_WIN32) || defined(HAVE_STEAM) || TARGET_OS_TV
|
||||
#define DEFAULT_MENU_SWAP_OK_CANCEL_BUTTONS true
|
||||
#else
|
||||
#define DEFAULT_MENU_SWAP_OK_CANCEL_BUTTONS false
|
||||
|
@ -137,6 +137,9 @@ static void apple_gamecontroller_joypad_poll_internal(GCController *controller,
|
||||
mfi_axes[slot][3] = gp.rightThumbstick.yAxis.value * 32767.0f;
|
||||
|
||||
}
|
||||
else if (controller.microGamepad)
|
||||
{
|
||||
}
|
||||
|
||||
/* GCGamepad is deprecated */
|
||||
#pragma clang diagnostic push
|
||||
@ -255,9 +258,9 @@ static void apple_gamecontroller_joypad_register(GCController *controller)
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
static void mfi_joypad_autodetect_add(unsigned autoconf_pad)
|
||||
static void mfi_joypad_autodetect_add(unsigned autoconf_pad, const char *display_name)
|
||||
{
|
||||
input_autoconfigure_connect("mFi Controller", NULL, mfi_joypad.ident, autoconf_pad, 0, 0);
|
||||
input_autoconfigure_connect("mFi Controller", display_name, mfi_joypad.ident, autoconf_pad, 0, 0);
|
||||
}
|
||||
|
||||
#define MFI_RUMBLE_AVAIL API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0))
|
||||
@ -455,9 +458,12 @@ static void apple_gamecontroller_joypad_connect(GCController *controller)
|
||||
gc.playerIndex = newPlayerIndex++;
|
||||
}
|
||||
|
||||
if (controller.microGamepad && !controller.extendedGamepad)
|
||||
return;
|
||||
|
||||
apple_gamecontroller_joypad_register(controller);
|
||||
apple_gamecontroller_joypad_setup_haptics(controller);
|
||||
mfi_joypad_autodetect_add((unsigned)controller.playerIndex);
|
||||
mfi_joypad_autodetect_add((unsigned)controller.playerIndex, [controller.vendorName cStringUsingEncoding:NSUTF8StringEncoding]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,9 +97,167 @@ void *glkitview_init(void);
|
||||
video_driver_display_userdata_set((uintptr_t)self);
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_TV
|
||||
/* This causes all inputs to be handled by both mfi and uikit.
|
||||
*
|
||||
* For "extended gamepads" the only button we want to handle is 'cancel'
|
||||
* (buttonB), and only when the cancel button wouldn't do anything.
|
||||
*/
|
||||
self.controllerUserInteractionEnabled = YES;
|
||||
#endif
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#if TARGET_OS_TV
|
||||
- (bool)menuIsAtTop
|
||||
{
|
||||
struct menu_state *menu_st = menu_state_get_ptr();
|
||||
if (!(menu_st->flags & MENU_ST_FLAG_ALIVE)) // content
|
||||
return false;
|
||||
if (menu_st->flags & MENU_ST_FLAG_INP_DLG_KB_DISPLAY) // search
|
||||
return false;
|
||||
if (menu_st->selection_ptr != 0) // not the first item
|
||||
return false;
|
||||
if (menu_st->entries.list->menu_stack[0]->size != 1) // submenu
|
||||
return false;
|
||||
if (!string_is_equal(menu_st->entries.list->menu_stack[0]->list->label, // not on the main menu
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
- (bool)didMicroGamepadPress:(UIPressType)type
|
||||
{
|
||||
if (type != UIPressTypeMenu &&
|
||||
type != UIPressTypeSelect &&
|
||||
type != UIPressTypePlayPause)
|
||||
return false;
|
||||
|
||||
NSArray<GCController*>* controllers = [GCController controllers];
|
||||
if ([controllers count] == 1)
|
||||
return !controllers[0].extendedGamepad;
|
||||
|
||||
bool microPress = false;
|
||||
bool extendedPress = false;
|
||||
for (GCController *controller in [GCController controllers]) {
|
||||
// the microGamepad does not always know if Menu has been pressed,
|
||||
// so we have to check all the extended gamepads as well
|
||||
if (controller.extendedGamepad)
|
||||
{
|
||||
if (type == UIPressTypeMenu)
|
||||
extendedPress |= controller.extendedGamepad.buttonB.pressed;
|
||||
else if (type == UIPressTypeSelect)
|
||||
extendedPress |= controller.extendedGamepad.buttonA.pressed;
|
||||
else if (type == UIPressTypePlayPause)
|
||||
extendedPress |= controller.extendedGamepad.buttonX.pressed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type == UIPressTypeSelect)
|
||||
extendedPress |= controller.extendedGamepad.buttonA.pressed;
|
||||
else if (type == UIPressTypePlayPause)
|
||||
extendedPress |= controller.extendedGamepad.buttonX.pressed;
|
||||
else if (@available(tvOS 13, *)) {
|
||||
if (type == UIPressTypeMenu)
|
||||
extendedPress |= controller.microGamepad.buttonMenu.pressed ||
|
||||
controller.microGamepad.buttonMenu.isPressed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return microPress || !extendedPress;
|
||||
}
|
||||
|
||||
- (void)pressesBegan:(NSSet<UIPress *> *)presses
|
||||
withEvent:(UIPressesEvent *)event
|
||||
{
|
||||
for (UIPress *press in presses) {
|
||||
switch (press.type)
|
||||
{
|
||||
case UIPressTypePlayPause:
|
||||
if ([self didMicroGamepadPress:press.type])
|
||||
apple_direct_input_keyboard_event(true, RETROK_s, 's', 0, RETRO_DEVICE_KEYBOARD);
|
||||
break;
|
||||
case UIPressTypeSelect:
|
||||
if ([self didMicroGamepadPress:press.type])
|
||||
apple_direct_input_keyboard_event(true, RETROK_z, 'z', 0, RETRO_DEVICE_KEYBOARD);
|
||||
break;
|
||||
case UIPressTypeMenu:
|
||||
if ([self menuIsAtTop])
|
||||
{
|
||||
// if we're at the top it doesn't matter who pressed it, we want to leave
|
||||
[super pressesBegan:presses withEvent:event];
|
||||
}
|
||||
else if ([self didMicroGamepadPress:press.type])
|
||||
apple_direct_input_keyboard_event(true, RETROK_x, 0, 0, RETRO_DEVICE_KEYBOARD);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
|
||||
{
|
||||
for (UIPress *press in presses) {
|
||||
switch (press.type)
|
||||
{
|
||||
case UIPressTypePlayPause:
|
||||
apple_direct_input_keyboard_event(false, RETROK_s, 's', 0, RETRO_DEVICE_KEYBOARD);
|
||||
break;
|
||||
case UIPressTypeSelect:
|
||||
apple_direct_input_keyboard_event(false, RETROK_z, 'z', 0, RETRO_DEVICE_KEYBOARD);
|
||||
break;
|
||||
case UIPressTypeMenu:
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
|
||||
apple_direct_input_keyboard_event(false, RETROK_x, 0, 0, RETRO_DEVICE_KEYBOARD);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
}
|
||||
|
||||
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
}
|
||||
|
||||
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
}
|
||||
|
||||
-(void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch *> *)touches
|
||||
{
|
||||
}
|
||||
|
||||
-(void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
}
|
||||
|
||||
-(void)handleSiriSwipe:(id)sender
|
||||
{
|
||||
UISwipeGestureRecognizer *gestureRecognizer = (UISwipeGestureRecognizer*)sender;
|
||||
unsigned code;
|
||||
switch (gestureRecognizer.direction)
|
||||
{
|
||||
case UISwipeGestureRecognizerDirectionUp: code = RETROK_UP; break;
|
||||
case UISwipeGestureRecognizerDirectionDown: code = RETROK_DOWN; break;
|
||||
case UISwipeGestureRecognizerDirectionLeft: code = RETROK_LEFT; break;
|
||||
case UISwipeGestureRecognizerDirectionRight: code = RETROK_RIGHT; break;
|
||||
}
|
||||
apple_direct_input_keyboard_event(true, code, 0, 0, RETRO_DEVICE_KEYBOARD);
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
|
||||
apple_direct_input_keyboard_event(false, code, 0, 0, RETRO_DEVICE_KEYBOARD);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(OSX)
|
||||
- (void)setFrame:(NSRect)frameRect
|
||||
{
|
||||
@ -314,6 +472,23 @@ void *glkitview_init(void);
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 130000
|
||||
[self setupHelperBar];
|
||||
#endif
|
||||
#elif TARGET_OS_TV
|
||||
UISwipeGestureRecognizer *siriSwipeUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSiriSwipe:)];
|
||||
siriSwipeUp.direction = UISwipeGestureRecognizerDirectionUp;
|
||||
siriSwipeUp.delegate = self;
|
||||
[self.view addGestureRecognizer:siriSwipeUp];
|
||||
UISwipeGestureRecognizer *siriSwipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSiriSwipe:)];
|
||||
siriSwipeDown.direction = UISwipeGestureRecognizerDirectionDown;
|
||||
siriSwipeDown.delegate = self;
|
||||
[self.view addGestureRecognizer:siriSwipeDown];
|
||||
UISwipeGestureRecognizer *siriSwipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSiriSwipe:)];
|
||||
siriSwipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
|
||||
siriSwipeLeft.delegate = self;
|
||||
[self.view addGestureRecognizer:siriSwipeLeft];
|
||||
UISwipeGestureRecognizer *siriSwipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSiriSwipe:)];
|
||||
siriSwipeRight.direction = UISwipeGestureRecognizerDirectionRight;
|
||||
siriSwipeRight.delegate = self;
|
||||
[self.view addGestureRecognizer:siriSwipeRight];
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -109,6 +109,7 @@ void get_ios_version(int *major, int *minor)
|
||||
/* Input helpers: This is kept here because it needs ObjC */
|
||||
static void handle_touch_event(NSArray* touches)
|
||||
{
|
||||
#if !TARGET_OS_TV
|
||||
unsigned i;
|
||||
cocoa_input_data_t *apple = (cocoa_input_data_t*)
|
||||
input_state_get_ptr()->current_data;
|
||||
@ -129,6 +130,7 @@ static void handle_touch_event(NSArray* touches)
|
||||
apple->touches[apple->touch_count ++].screen_y = coord.y * scale;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef HAVE_APPLE_STORE
|
||||
|
Loading…
x
Reference in New Issue
Block a user