/* * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im> * * All rights reserved. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3.0 only, * as published by the Free Software Foundation. * * This program 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 Lesser General Public License * version 3.0 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3.0 along with this program. If not, see * <https://www.gnu.org/licenses/>. */ #include "config.h" #import "OHNintendoSwitchGameController.h" #import "OFArray.h" #import "OFDictionary.h" #import "OHGameControllerAxis.h" #import "OHGameControllerButton.h" #import "OHGameControllerDirectionalPad.h" #import "OHNintendoSwitchExtendedGamepad.h" #import "OFInitializationFailedException.h" #import "OFReadFailedException.h" #define id nx_id #include <switch.h> #undef id static const size_t maxControllers = 8; @implementation OHNintendoSwitchGameController @synthesize extendedGamepad = _extendedGamepad; + (void)initialize { if (self == [OHNintendoSwitchGameController class]) padConfigureInput(maxControllers, HidNpadStyleSet_NpadFullCtrl); } + (OFArray OF_GENERIC(OHGameController *) *)controllers { OFMutableArray *controllers = [OFMutableArray array]; void *pool = objc_autoreleasePoolPush(); for (size_t i = 0; i < maxControllers; i++) { OHGameController *controller; @try { controller = [[[OHNintendoSwitchGameController alloc] initWithIndex: i] autorelease]; } @catch (OFInitializationFailedException *e) { /* Controller does not exist. */ continue; } [controllers addObject: controller]; } [controllers makeImmutable]; objc_autoreleasePoolPop(pool); return controllers; } - (instancetype)initWithIndex: (size_t)index { self = [super init]; @try { padInitialize(&_padState, HidNpadIdType_No1 + index, (index == 0 ? HidNpadIdType_Handheld : 0)); padUpdate(&_padState); if (!(padGetAttributes(&_padState) & HidNpadAttribute_IsConnected)) @throw [OFInitializationFailedException exceptionWithClass: self.class]; _extendedGamepad = [[OHNintendoSwitchExtendedGamepad alloc] init]; [self retrieveState]; } @catch (id e) { [self release]; @throw e; } return self; } - (void)dealloc { [_extendedGamepad release]; [super dealloc]; } - (void)retrieveState { void *pool = objc_autoreleasePoolPush(); OFDictionary OF_GENERIC(OFString *, OHGameControllerButton *) *buttons = _extendedGamepad.buttons; OFDictionary OF_GENERIC(OFString *, OHGameControllerDirectionalPad *) *directionalPads = _extendedGamepad.directionalPads; u64 keys; HidAnalogStickState stick; OHGameControllerDirectionalPad *directionalPad; padUpdate(&_padState); keys = padGetButtons(&_padState); [[buttons objectForKey: @"A"] setValue: !!(keys & HidNpadButton_A)]; [[buttons objectForKey: @"B"] setValue: !!(keys & HidNpadButton_B)]; [[buttons objectForKey: @"X"] setValue: !!(keys & HidNpadButton_X)]; [[buttons objectForKey: @"Y"] setValue: !!(keys & HidNpadButton_Y)]; [[buttons objectForKey: @"L"] setValue: !!(keys & HidNpadButton_L)]; [[buttons objectForKey: @"R"] setValue: !!(keys & HidNpadButton_R)]; [[buttons objectForKey: @"ZL"] setValue: !!(keys & HidNpadButton_ZL)]; [[buttons objectForKey: @"ZR"] setValue: !!(keys & HidNpadButton_ZR)]; [[buttons objectForKey: @"Left Thumbstick"] setValue: !!(keys & HidNpadButton_StickL)]; [[buttons objectForKey: @"Right Thumbstick"] setValue: !!(keys & HidNpadButton_StickR)]; [[buttons objectForKey: @"+"] setValue: !!(keys & HidNpadButton_Plus)]; [[buttons objectForKey: @"-"] setValue: !!(keys & HidNpadButton_Minus)]; stick = padGetStickPos(&_padState, 0); directionalPad = [directionalPads objectForKey: @"Left Thumbstick"]; [directionalPad.xAxis setValue: (float)stick.x / (stick.x < 0 ? -INT16_MIN : INT16_MAX)]; [directionalPad.yAxis setValue: -(float)stick.y / (stick.y < 0 ? -INT16_MIN : INT16_MAX)]; stick = padGetStickPos(&_padState, 1); directionalPad = [directionalPads objectForKey: @"Right Thumbstick"]; [directionalPad.xAxis setValue: (float)stick.x / (stick.x < 0 ? -INT16_MIN : INT16_MAX)]; [directionalPad.yAxis setValue: -(float)stick.y / (stick.y < 0 ? -INT16_MIN : INT16_MAX)]; directionalPad = [directionalPads objectForKey: @"D-Pad"]; [directionalPad.up setValue: !!(keys & keys & HidNpadButton_Up)]; [directionalPad.down setValue: !!(keys & keys & HidNpadButton_Down)]; [directionalPad.left setValue: !!(keys & keys & HidNpadButton_Left)]; [directionalPad.right setValue: !!(keys & keys & HidNpadButton_Right)]; objc_autoreleasePoolPop(pool); } - (OFString *)name { return @"Nintendo Switch"; } - (id <OHGameControllerProfile>)rawProfile { return _extendedGamepad; } - (id <OHGamepad>)gamepad { return _extendedGamepad; } @end