Index: src/hid/Makefile ================================================================== --- src/hid/Makefile +++ src/hid/Makefile @@ -25,10 +25,12 @@ SRCS += OHDualSenseGamepad.m \ OHDualShock4Gamepad.m \ OHEmulatedGameControllerAxis.m \ OHEmulatedGameControllerButton.m \ OHEmulatedGameControllerTriggerButton.m \ + OHExtendedN64Controller.m \ + OHN64Controller.m \ OHStadiaGamepad.m \ OHXboxGamepad.m \ ${USE_SRCS_EVDEV} \ ${USE_SRCS_NINTENDO_3DS} \ ${USE_SRCS_NINTENDO_DS} \ Index: src/hid/OHEvdevGameController.m ================================================================== --- src/hid/OHEvdevGameController.m +++ src/hid/OHEvdevGameController.m @@ -32,10 +32,11 @@ #import "OFNumber.h" #import "OHDualSenseGamepad.h" #import "OHDualShock4Gamepad.h" #import "OHEvdevExtendedGamepad.h" +#import "OHExtendedN64Controller.h" #import "OHGameControllerAxis+Private.h" #import "OHGameControllerAxis.h" #import "OHGameControllerButton.h" #import "OHGameControllerProfile.h" #import "OHStadiaGamepad.h" @@ -201,10 +202,13 @@ _productID == OHProductIDDualSense) _profile = [[OHDualSenseGamepad alloc] init]; else if (_vendorID == OHVendorIDSony && _productID == OHProductIDDualShock4) _profile = [[OHDualShock4Gamepad alloc] init]; + else if (_vendorID == OHVendorIDNintendo && + _productID == OHProductIDN64Controller) + _profile = [[OHExtendedN64Controller alloc] init]; else if (_vendorID == OHVendorIDGoogle && _productID == OHProductIDStadiaController) _profile = [[OHStadiaGamepad alloc] init]; else _profile = [[OHEvdevExtendedGamepad alloc] Index: src/hid/OHEvdevGameControllerProfile.m ================================================================== --- src/hid/OHEvdevGameControllerProfile.m +++ src/hid/OHEvdevGameControllerProfile.m @@ -71,34 +71,10 @@ case BTN_TL: return @"SL"; case BTN_TL2: return @"SR"; } - } else if (vendorID == OHVendorIDNintendo && - productID == OHProductIDN64Controller) { - switch (button) { - case BTN_SELECT: - return @"C-Pad Up"; - case BTN_X: - return @"C-Pad Down"; - case BTN_Y: - return @"C-Pad Left"; - case BTN_C: - return @"C-Pad Right"; - case BTN_TL: - return @"L"; - case BTN_TR: - return @"R"; - case BTN_TL2: - return @"Z"; - case BTN_TR2: - return @"ZR"; - case BTN_MODE: - return @"Home"; - case BTN_Z: - return @"Capture"; - } } switch (button) { case BTN_A: return @"A"; ADDED src/hid/OHExtendedN64Controller.h Index: src/hid/OHExtendedN64Controller.h ================================================================== --- /dev/null +++ src/hid/OHExtendedN64Controller.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * 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 + * . + */ + +#import "OHN64Controller.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OHExtendedN64Controller: OHN64Controller +@end + +OF_ASSUME_NONNULL_END ADDED src/hid/OHExtendedN64Controller.m Index: src/hid/OHExtendedN64Controller.m ================================================================== --- /dev/null +++ src/hid/OHExtendedN64Controller.m @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * 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 + * . + */ + +#include "config.h" + +#import "OHExtendedN64Controller.h" +#import "OFDictionary.h" +#import "OHGameControllerButton.h" + +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) +# include +#endif + +static OFString *const buttonNames[] = { + @"ZR", @"Home", @"Capture" +}; +static const size_t numButtons = sizeof(buttonNames) / sizeof(*buttonNames); + +@implementation OHExtendedN64Controller +- (instancetype)init +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + OFMutableDictionary *buttons = + [[_buttons mutableCopy] autorelease]; + + for (size_t i = 0; i < numButtons; i++) { + OHGameControllerButton *button = + [[[OHGameControllerButton alloc] + initWithName: buttonNames[i]] autorelease]; + [buttons setObject: button forKey: buttonNames[i]]; + } + [buttons makeImmutable]; + [_buttons release]; + _buttons = [buttons retain]; + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) +- (OHGameControllerButton *)oh_buttonForEvdevButton: (uint16_t)button +{ + switch (button) { + case BTN_TR2: + return [_buttons objectForKey: @"ZR"]; + case BTN_MODE: + return [_buttons objectForKey: @"Home"]; + case BTN_Z: + return [_buttons objectForKey: @"Capture"]; + } + + return [super oh_buttonForEvdevButton: button]; +} +#endif +@end ADDED src/hid/OHN64Controller.h Index: src/hid/OHN64Controller.h ================================================================== --- /dev/null +++ src/hid/OHN64Controller.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * 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 + * . + */ + +#import "OHGameControllerProfile.h" +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) +# import "OHEvdevGameController.h" +#endif + +OF_ASSUME_NONNULL_BEGIN + +@interface OHN64Controller: OFObject +{ + OFDictionary OF_GENERIC(OFString *, OHGameControllerButton *) *_buttons; + OFDictionary OF_GENERIC(OFString *, OHGameControllerDirectionalPad *) + *_directionalPads; +} +@end + +OF_ASSUME_NONNULL_END ADDED src/hid/OHN64Controller.m Index: src/hid/OHN64Controller.m ================================================================== --- /dev/null +++ src/hid/OHN64Controller.m @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * 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 + * . + */ + +#include "config.h" + +#import "OHN64Controller.h" +#import "OFDictionary.h" +#import "OHGameControllerAxis.h" +#import "OHGameControllerButton.h" +#import "OHGameControllerDirectionalPad.h" + +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) +# include +#endif + +static OFString *const buttonNames[] = { + @"A", @"B", @"L", @"R", @"Z", @"Start" +}; +static const size_t numButtons = sizeof(buttonNames) / sizeof(*buttonNames); + +@implementation OHN64Controller +@synthesize buttons = _buttons, directionalPads = _directionalPads; + +- (instancetype)init +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + OFMutableDictionary *buttons = + [OFMutableDictionary dictionaryWithCapacity: numButtons]; + OFMutableDictionary *directionalPads; + OHGameControllerAxis *xAxis, *yAxis; + OHGameControllerDirectionalPad *directionalPad; + OHGameControllerButton *up, *down, *left, *right; + + for (size_t i = 0; i < numButtons; i++) { + OHGameControllerButton *button = + [[[OHGameControllerButton alloc] + initWithName: buttonNames[i]] autorelease]; + [buttons setObject: button forKey: buttonNames[i]]; + } + [buttons makeImmutable]; + _buttons = [buttons retain]; + + directionalPads = + [OFMutableDictionary dictionaryWithCapacity: 3]; + + xAxis = [[[OHGameControllerAxis alloc] + initWithName: @"X"] autorelease]; + yAxis = [[[OHGameControllerAxis alloc] + initWithName: @"Y"] autorelease]; + directionalPad = [[[OHGameControllerDirectionalPad alloc] + initWithName: @"Thumbstick" + xAxis: xAxis + yAxis: yAxis] autorelease]; + [directionalPads setObject: directionalPad + forKey: @"Thumbstick"]; + + xAxis = [[[OHGameControllerAxis alloc] + initWithName: @"D-Pad X"] autorelease]; + yAxis = [[[OHGameControllerAxis alloc] + initWithName: @"D-Pad Y"] autorelease]; + directionalPad = [[[OHGameControllerDirectionalPad alloc] + initWithName: @"D-Pad" + xAxis: xAxis + yAxis: yAxis] autorelease]; + [directionalPads setObject: directionalPad forKey: @"D-Pad"]; + + up = [[[OHGameControllerButton alloc] + initWithName: @"C-Pad Up"] autorelease]; + down = [[[OHGameControllerButton alloc] + initWithName: @"C-Pad Down"] autorelease]; + left = [[[OHGameControllerButton alloc] + initWithName: @"C-Pad Left"] autorelease]; + right = [[[OHGameControllerButton alloc] + initWithName: @"C-Pad Right"] autorelease]; + directionalPad = [[[OHGameControllerDirectionalPad alloc] + initWithName: @"C-Pad" + up: up + down: down + left: left + right: right] autorelease]; + [directionalPads setObject: directionalPad forKey: @"C-Pad"]; + + [directionalPads makeImmutable]; + _directionalPads = [directionalPads retain]; + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_buttons release]; + [_directionalPads release]; + + [super dealloc]; +} + +- (OFDictionary OF_GENERIC(OFString *, OHGameControllerAxis *) *)axes +{ + return [OFDictionary dictionary]; +} + +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) +- (OHGameControllerButton *)oh_buttonForEvdevButton: (uint16_t)button +{ + switch (button) { + case BTN_A: + return [_buttons objectForKey: @"A"]; + case BTN_B: + return [_buttons objectForKey: @"B"]; + case BTN_TL2: + return [_buttons objectForKey: @"Z"]; + case BTN_SELECT: + return [[_directionalPads objectForKey: @"C-Pad"] up]; + case BTN_X: + return [[_directionalPads objectForKey: @"C-Pad"] down]; + case BTN_Y: + return [[_directionalPads objectForKey: @"C-Pad"] left]; + case BTN_C: + return [[_directionalPads objectForKey: @"C-Pad"] right]; + case BTN_TL: + return [_buttons objectForKey: @"L"]; + case BTN_TR: + return [_buttons objectForKey: @"R"]; + case BTN_START: + return [_buttons objectForKey: @"Start"]; + } + + return nil; +} + +- (OHGameControllerAxis *)oh_axisForEvdevAxis: (uint16_t)axis +{ + switch (axis) { + case ABS_X: + return [[_directionalPads objectForKey: @"Thumbstick"] xAxis]; + case ABS_Y: + return [[_directionalPads objectForKey: @"Thumbstick"] yAxis]; + case ABS_HAT0X: + return [[_directionalPads objectForKey: @"D-Pad"] xAxis]; + case ABS_HAT0Y: + return [[_directionalPads objectForKey: @"D-Pad"] yAxis]; + } + + return nil; +} +#endif +@end