Index: src/hid/Makefile ================================================================== --- src/hid/Makefile +++ src/hid/Makefile @@ -26,11 +26,13 @@ OHDualShock4Gamepad.m \ OHEmulatedGameControllerAxis.m \ OHEmulatedGameControllerButton.m \ OHEmulatedGameControllerTriggerButton.m \ OHExtendedN64Controller.m \ + OHLeftJoyCon.m \ OHN64Controller.m \ + OHRightJoyCon.m \ OHStadiaGamepad.m \ OHXboxGamepad.m \ ${USE_SRCS_EVDEV} \ ${USE_SRCS_NINTENDO_3DS} \ ${USE_SRCS_NINTENDO_DS} \ Index: src/hid/OHCombinedJoyCons.m ================================================================== --- src/hid/OHCombinedJoyCons.m +++ src/hid/OHCombinedJoyCons.m @@ -49,11 +49,10 @@ @try { void *pool = objc_autoreleasePoolPush(); OFDictionary *leftButtons, *rightButtons; OFMutableDictionary *buttons, *directionalPads; - OHGameControllerDirectionalPad *directionalPad; if (leftJoyCon.vendorID.unsignedShortValue != OHVendorIDNintendo || rightJoyCon.vendorID.unsignedShortValue != OHVendorIDNintendo) @@ -73,47 +72,21 @@ buttons = [OFMutableDictionary dictionaryWithCapacity: leftButtons.count + rightButtons.count]; [buttons addEntriesFromDictionary: leftButtons]; [buttons addEntriesFromDictionary: rightButtons]; - [buttons removeObjectForKey: @"D-Pad Up"]; - [buttons removeObjectForKey: @"D-Pad Down"]; - [buttons removeObjectForKey: @"D-Pad Left"]; - [buttons removeObjectForKey: @"D-Pad Right"]; [buttons removeObjectForKey: @"SL"]; [buttons removeObjectForKey: @"SR"]; [buttons makeImmutable]; _buttons = [buttons retain]; directionalPads = [OFMutableDictionary dictionaryWithCapacity: 3]; - - directionalPad = [[[OHGameControllerDirectionalPad alloc] - initWithName: @"Left Thumbstick" - xAxis: [_leftJoyCon.axes objectForKey: @"X"] - yAxis: [_leftJoyCon.axes objectForKey: @"Y"]] - autorelease]; - [directionalPads setObject: directionalPad - forKey: @"Left Thumbstick"]; - - directionalPad = [[[OHGameControllerDirectionalPad alloc] - initWithName: @"Right Thumbstick" - xAxis: [_rightJoyCon.axes objectForKey: @"RX"] - yAxis: [_rightJoyCon.axes objectForKey: @"RY"]] - autorelease]; - [directionalPads setObject: directionalPad - forKey: @"Right Thumbstick"]; - - directionalPad = [[[OHGameControllerDirectionalPad alloc] - initWithName: @"D-Pad" - up: [leftButtons objectForKey: @"D-Pad Up"] - down: [leftButtons objectForKey: @"D-Pad Down"] - left: [leftButtons objectForKey: @"D-Pad Left"] - right: [leftButtons objectForKey: @"D-Pad Right"]] - autorelease]; - [directionalPads setObject: directionalPad forKey: @"D-Pad"]; - + [directionalPads addEntriesFromDictionary: + _leftJoyCon.directionalPads]; + [directionalPads addEntriesFromDictionary: + _rightJoyCon.directionalPads]; [directionalPads makeImmutable]; _directionalPads = [directionalPads retain]; objc_autoreleasePoolPop(pool); } @catch (id e) { Index: src/hid/OHEvdevGameController.m ================================================================== --- src/hid/OHEvdevGameController.m +++ src/hid/OHEvdevGameController.m @@ -37,10 +37,12 @@ #import "OHExtendedN64Controller.h" #import "OHGameControllerAxis+Private.h" #import "OHGameControllerAxis.h" #import "OHGameControllerButton.h" #import "OHGameControllerProfile.h" +#import "OHLeftJoyCon.h" +#import "OHRightJoyCon.h" #import "OHStadiaGamepad.h" #include #include @@ -205,10 +207,16 @@ _productID == OHProductIDDualShock4) _profile = [[OHDualShock4Gamepad alloc] init]; else if (_vendorID == OHVendorIDNintendo && _productID == OHProductIDN64Controller) _profile = [[OHExtendedN64Controller alloc] init]; + else if (_vendorID == OHVendorIDNintendo && + _productID == OHProductIDLeftJoyCon) + _profile = [[OHLeftJoyCon alloc] init]; + else if (_vendorID == OHVendorIDNintendo && + _productID == OHProductIDRightJoyCon) + _profile = [[OHRightJoyCon 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 @@ -27,56 +27,10 @@ #include static OFString * buttonToName(uint16_t button, uint16_t vendorID, uint16_t productID) { - if (vendorID == OHVendorIDNintendo && - productID == OHProductIDLeftJoyCon) { - switch (button) { - case BTN_TL: - return @"L"; - case BTN_TL2: - return @"ZL"; - case BTN_THUMBL: - return @"Left Thumbstick"; - case BTN_SELECT: - return @"-"; - case BTN_Z: - return @"Capture"; - case BTN_TR: - return @"SL"; - case BTN_TR2: - return @"SR"; - } - } else if (vendorID == OHVendorIDNintendo && - productID == OHProductIDRightJoyCon) { - switch (button) { - case BTN_NORTH: - return @"X"; - case BTN_SOUTH: - return @"B"; - case BTN_WEST: - return @"Y"; - case BTN_EAST: - return @"A"; - case BTN_TR: - return @"R"; - case BTN_TR2: - return @"ZR"; - case BTN_THUMBR: - return @"Right Thumbstick"; - case BTN_START: - return @"+"; - case BTN_MODE: - return @"Home"; - case BTN_TL: - return @"SL"; - case BTN_TL2: - return @"SR"; - } - } - switch (button) { case BTN_A: return @"A"; case BTN_B: return @"B"; ADDED src/hid/OHLeftJoyCon.h Index: src/hid/OHLeftJoyCon.h ================================================================== --- /dev/null +++ src/hid/OHLeftJoyCon.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 OHLeftJoyCon: OFObject +{ + OFDictionary OF_GENERIC(OFString *, OHGameControllerButton *) *_buttons; + OFDictionary OF_GENERIC(OFString *, OHGameControllerDirectionalPad *) + *_directionalPads; +} +@end + +OF_ASSUME_NONNULL_END ADDED src/hid/OHLeftJoyCon.m Index: src/hid/OHLeftJoyCon.m ================================================================== --- /dev/null +++ src/hid/OHLeftJoyCon.m @@ -0,0 +1,162 @@ +/* + * 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 "OHLeftJoyCon.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[] = { + @"L", @"ZL", @"Left Thumbstick", @"-", @"Capture", @"SL", @"SR" +}; +static const size_t numButtons = sizeof(buttonNames) / sizeof(*buttonNames); + +@implementation OHLeftJoyCon +@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: 2]; + + xAxis = [[[OHGameControllerAxis alloc] + initWithName: @"X"] autorelease]; + yAxis = [[[OHGameControllerAxis alloc] + initWithName: @"Y"] autorelease]; + directionalPad = [[[OHGameControllerDirectionalPad alloc] + initWithName: @"Left Thumbstick" + xAxis: xAxis + yAxis: yAxis] autorelease]; + [directionalPads setObject: directionalPad + forKey: @"Left Thumbstick"]; + + up = [[[OHGameControllerButton alloc] + initWithName: @"D-Pad Up"] autorelease]; + down = [[[OHGameControllerButton alloc] + initWithName: @"D-Pad Down"] autorelease]; + left = [[[OHGameControllerButton alloc] + initWithName: @"D-Pad Left"] autorelease]; + right = [[[OHGameControllerButton alloc] + initWithName: @"D-Pad Right"] autorelease]; + directionalPad = [[[OHGameControllerDirectionalPad alloc] + initWithName: @"D-Pad" + up: up + down: down + left: left + right: right] autorelease]; + [directionalPads setObject: directionalPad forKey: @"D-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_DPAD_UP: + return [[_directionalPads objectForKey: @"D-Pad"] up]; + case BTN_DPAD_DOWN: + return [[_directionalPads objectForKey: @"D-Pad"] down]; + case BTN_DPAD_LEFT: + return [[_directionalPads objectForKey: @"D-Pad"] left]; + case BTN_DPAD_RIGHT: + return [[_directionalPads objectForKey: @"D-Pad"] right]; + case BTN_TL: + return [_buttons objectForKey: @"L"]; + case BTN_TL2: + return [_buttons objectForKey: @"ZL"]; + case BTN_THUMBL: + return [_buttons objectForKey: @"Left Thumbstick"]; + case BTN_SELECT: + return [_buttons objectForKey: @"-"]; + case BTN_Z: + return [_buttons objectForKey: @"Capture"]; + case BTN_TR: + return [_buttons objectForKey: @"SL"]; + case BTN_TR2: + return [_buttons objectForKey: @"SR"]; + } + + return nil; +} + +- (OHGameControllerAxis *)oh_axisForEvdevAxis: (uint16_t)axis +{ + switch (axis) { + case ABS_X: + return [[_directionalPads + objectForKey: @"Left Thumbstick"] xAxis]; + case ABS_Y: + return [[_directionalPads + objectForKey: @"Left Thumbstick"] yAxis]; + } + + return nil; +} +#endif +@end ADDED src/hid/OHRightJoyCon.h Index: src/hid/OHRightJoyCon.h ================================================================== --- /dev/null +++ src/hid/OHRightJoyCon.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 OHRightJoyCon: OFObject +{ + OFDictionary OF_GENERIC(OFString *, OHGameControllerButton *) *_buttons; + OFDictionary OF_GENERIC(OFString *, OHGameControllerDirectionalPad *) + *_directionalPads; +} +@end + +OF_ASSUME_NONNULL_END ADDED src/hid/OHRightJoyCon.m Index: src/hid/OHRightJoyCon.m ================================================================== --- /dev/null +++ src/hid/OHRightJoyCon.m @@ -0,0 +1,156 @@ +/* + * 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 "OHRightJoyCon.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[] = { + @"X", @"B", @"A", @"Y", @"R", @"ZR", @"Right Thumbstick", @"+", + @"Home", @"SL", @"SR" +}; +static const size_t numButtons = sizeof(buttonNames) / sizeof(*buttonNames); + +@implementation OHRightJoyCon +@synthesize buttons = _buttons, directionalPads = _directionalPads; + +- (instancetype)init +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + OFMutableDictionary *buttons = + [OFMutableDictionary dictionaryWithCapacity: numButtons]; + OHGameControllerAxis *xAxis, *yAxis; + OHGameControllerDirectionalPad *directionalPad; + + 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]; + + xAxis = [[[OHGameControllerAxis alloc] + initWithName: @"X"] autorelease]; + yAxis = [[[OHGameControllerAxis alloc] + initWithName: @"Y"] autorelease]; + directionalPad = [[[OHGameControllerDirectionalPad alloc] + initWithName: @"Right Thumbstick" + xAxis: xAxis + yAxis: yAxis] autorelease]; + + _directionalPads = [[OFDictionary alloc] + initWithObject: directionalPad + forKey: @"Right Thumbstick"]; + + 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 +{ + OFString *name; + + switch (button) { + case BTN_NORTH: + name = @"X"; + break; + case BTN_SOUTH: + name = @"B"; + break; + case BTN_EAST: + name = @"A"; + break; + case BTN_WEST: + name = @"Y"; + break; + case BTN_TR: + name = @"R"; + break; + case BTN_TR2: + name = @"ZR"; + break; + case BTN_THUMBR: + name = @"Right Thumbstick"; + break; + case BTN_START: + name = @"+"; + break; + case BTN_MODE: + name = @"Home"; + break; + case BTN_TL: + name = @"SL"; + break; + case BTN_TL2: + name = @"SR"; + break; + default: + return nil; + } + + return [_buttons objectForKey: name]; +} + +- (OHGameControllerAxis *)oh_axisForEvdevAxis: (uint16_t)axis +{ + switch (axis) { + case ABS_RX: + return [[_directionalPads + objectForKey: @"Right Thumbstick"] xAxis]; + case ABS_RY: + return [[_directionalPads + objectForKey: @"Right Thumbstick"] yAxis]; + } + + return nil; +} +#endif +@end