Index: src/hid/Makefile ================================================================== --- src/hid/Makefile +++ src/hid/Makefile @@ -12,23 +12,34 @@ SRCS = OHCombinedJoyCons.m \ OHGameController.m \ OHGameControllerAxis.m \ OHGameControllerButton.m \ OHGameControllerDirectionalPad.m \ - OHGameControllerElement.m \ - ${USE_SRCS_EVDEV} \ - ${USE_SRCS_NINTENDO_3DS} \ - ${USE_SRCS_NINTENDO_DS} \ - ${USE_SRCS_NINTENDO_SWITCH} \ - ${USE_SRCS_WII} \ - ${USE_SRCS_XINPUT} -SRCS_EVDEV = OHEvdevDualSense.m \ - OHEvdevDualShock4.m \ - OHEvdevExtendedGamepad.m \ + OHGameControllerElement.m + +INCLUDES := ${SRCS:.m=.h} \ + OHExtendedGamepad.h \ + OHGameControllerProfile.h \ + OHGamepad.h \ + ObjFWHID.h + +SRCS += OHDualSenseGamepad.m \ + OHDualShock4Gamepad.m \ + OHGameControllerEmulatedAxis.m \ + OHGameControllerEmulatedButton.m \ + OHGameControllerEmulatedTriggerButton.m \ + OHStadiaGamepad.m \ + OHXboxGamepad.m \ + ${USE_SRCS_EVDEV} \ + ${USE_SRCS_NINTENDO_3DS} \ + ${USE_SRCS_NINTENDO_DS} \ + ${USE_SRCS_NINTENDO_SWITCH} \ + ${USE_SRCS_WII} \ + ${USE_SRCS_XINPUT} +SRCS_EVDEV = OHEvdevExtendedGamepad.m \ OHEvdevGameController.m \ - OHEvdevPlayStationExtendedGamepad.m \ - OHEvdevStadiaExtendedGamepad.m + OHEvdevGameControllerProfile.m SRCS_NINTENDO_3DS = OHNintendo3DSExtendedGamepad.m \ OHNintendo3DSGameController.m SRCS_NINTENDO_DS = OHNintendoDSGamepad.m \ OHNintendoDSGameController.m SRCS_NINTENDO_SWITCH = OHNintendoSwitchExtendedGamepad.m \ @@ -35,22 +46,11 @@ OHNintendoSwitchGameController.m SRCS_WII = OHWiiClassicController.m \ OHWiiGameController.m \ OHWiimote.m \ OHWiimoteWithNunchuk.m -SRCS_XINPUT = OHXbox360Gamepad.m \ - OHXInputGameController.m - -INCLUDES := ${SRCS:.m=.h} \ - OHExtendedGamepad.h \ - OHGameControllerProfile.h \ - OHGamepad.h \ - ObjFWHID.h - -SRCS += OHGameControllerEmulatedAxis.m \ - OHGameControllerEmulatedButton.m \ - OHGameControllerEmulatedTriggerButton.m +SRCS_XINPUT = OHXInputGameController.m includesubdir = ObjFWHID include ../../buildsys.mk Index: src/hid/OHCombinedJoyCons.m ================================================================== --- src/hid/OHCombinedJoyCons.m +++ src/hid/OHCombinedJoyCons.m @@ -63,12 +63,12 @@ OHProductIDLeftJoyCon || rightJoyCon.productID.unsignedShortValue != OHProductIDRightJoyCon) @throw [OFInvalidArgumentException exception]; - _leftJoyCon = [leftJoyCon.rawProfile retain]; - _rightJoyCon = [rightJoyCon.rawProfile retain]; + _leftJoyCon = [leftJoyCon.profile retain]; + _rightJoyCon = [rightJoyCon.profile retain]; leftButtons = _leftJoyCon.buttons; rightButtons = _rightJoyCon.buttons; buttons = [OFMutableDictionary dictionaryWithCapacity: ADDED src/hid/OHDualSenseGamepad.h Index: src/hid/OHDualSenseGamepad.h ================================================================== --- /dev/null +++ src/hid/OHDualSenseGamepad.h @@ -0,0 +1,34 @@ +/* + * 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 "OHExtendedGamepad.h" +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) +# import "OHEvdevGameController.h" +#endif + +OF_ASSUME_NONNULL_BEGIN + +@interface OHDualSenseGamepad: OFObject +@end + +OF_ASSUME_NONNULL_END ADDED src/hid/OHDualSenseGamepad.m Index: src/hid/OHDualSenseGamepad.m ================================================================== --- /dev/null +++ src/hid/OHDualSenseGamepad.m @@ -0,0 +1,290 @@ +/* + * 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 "OHDualSenseGamepad.h" +#import "OFDictionary.h" +#import "OHGameControllerAxis.h" +#import "OHGameControllerButton.h" +#import "OHGameControllerDirectionalPad.h" +#import "OHGameControllerEmulatedTriggerButton.h" + +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) +# include +#endif + +static OFString *const buttonNames[] = { + @"Triangle", @"Cross", @"Square", @"Circle", @"L1", @"R1", @"L3", @"R3", + @"Options", @"Create", @"PS" +}; +static const size_t numButtons = sizeof(buttonNames) / sizeof(*buttonNames); + +@implementation OHDualSenseGamepad +@synthesize buttons = _buttons, directionalPads = _directionalPads; + +- (instancetype)init +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + OFMutableDictionary *buttons = + [OFMutableDictionary dictionaryWithCapacity: numButtons]; + OHGameControllerButton *button; + OFMutableDictionary *directionalPads; + OHGameControllerAxis *axis, *xAxis, *yAxis; + OHGameControllerDirectionalPad *directionalPad; + + for (size_t i = 0; i < numButtons; i++) { + button = [[[OHGameControllerButton alloc] + initWithName: buttonNames[i]] autorelease]; + [buttons setObject: button forKey: buttonNames[i]]; + } + + axis = [[[OHGameControllerAxis alloc] + initWithName: @"L2"] autorelease]; + button = [[[OHGameControllerEmulatedTriggerButton alloc] + initWithName: @"L2" + axis: axis] autorelease]; + [buttons setObject: button forKey: @"L2"]; + + axis = [[[OHGameControllerAxis alloc] + initWithName: @"R2"] autorelease]; + button = [[[OHGameControllerEmulatedTriggerButton alloc] + initWithName: @"R2" + axis: axis] autorelease]; + [buttons setObject: button forKey: @"R2"]; + + [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: @"Left Stick" + xAxis: xAxis + yAxis: yAxis] autorelease]; + [directionalPads setObject: directionalPad + forKey: @"Left Stick"]; + + xAxis = [[[OHGameControllerAxis alloc] + initWithName: @"RX"] autorelease]; + yAxis = [[[OHGameControllerAxis alloc] + initWithName: @"RY"] autorelease]; + directionalPad = [[[OHGameControllerDirectionalPad alloc] + initWithName: @"Right Stick" + xAxis: xAxis + yAxis: yAxis] autorelease]; + [directionalPads setObject: directionalPad + forKey: @"Right Stick"]; + + 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"]; + + [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]; +} + +- (OHGameControllerButton *)northButton +{ + return [_buttons objectForKey: @"Triangle"]; +} + +- (OHGameControllerButton *)southButton +{ + return [_buttons objectForKey: @"Cross"]; +} + +- (OHGameControllerButton *)westButton +{ + return [_buttons objectForKey: @"Square"]; +} + +- (OHGameControllerButton *)eastButton +{ + return [_buttons objectForKey: @"Circle"]; +} + +- (OHGameControllerButton *)leftShoulderButton +{ + return [_buttons objectForKey: @"L1"]; +} + +- (OHGameControllerButton *)rightShoulderButton +{ + return [_buttons objectForKey: @"R1"]; +} + +- (OHGameControllerButton *)leftTriggerButton +{ + return [_buttons objectForKey: @"L2"]; +} + +- (OHGameControllerButton *)rightTriggerButton +{ + return [_buttons objectForKey: @"R2"]; +} + +- (OHGameControllerButton *)leftThumbstickButton +{ + return [_buttons objectForKey: @"L3"]; +} + +- (OHGameControllerButton *)rightThumbstickButton +{ + return [_buttons objectForKey: @"R3"]; +} + +- (OHGameControllerButton *)menuButton +{ + return [_buttons objectForKey: @"Options"]; +} + +- (OHGameControllerButton *)optionsButton +{ + return [_buttons objectForKey: @"Create"]; +} + +- (OHGameControllerButton *)homeButton +{ + return [_buttons objectForKey: @"PS"]; +} + +- (OHGameControllerDirectionalPad *)leftThumbstick +{ + return [_directionalPads objectForKey: @"Left Stick"]; +} + +- (OHGameControllerDirectionalPad *)rightThumbstick +{ + return [_directionalPads objectForKey: @"Right Stick"]; +} + +- (OHGameControllerDirectionalPad *)dPad +{ + return [_directionalPads objectForKey: @"D-Pad"]; +} + +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) +- (OHGameControllerButton *)oh_buttonForEvdevButton: (uint16_t)button +{ + OFString *name; + + switch (button) { + case BTN_NORTH: + name = @"Triangle"; + break; + case BTN_SOUTH: + name = @"Cross"; + break; + case BTN_WEST: + name = @"Square"; + break; + case BTN_EAST: + name = @"Circle"; + break; + case BTN_TL: + name = @"L1"; + break; + case BTN_TR: + name = @"R1"; + break; + case BTN_THUMBL: + name = @"L3"; + break; + case BTN_THUMBR: + name = @"R3"; + break; + case BTN_START: + name = @"Options"; + break; + case BTN_SELECT: + name = @"Create"; + break; + case BTN_MODE: + name = @"PS"; + break; + default: + return nil; + } + + return [_buttons objectForKey: name]; +} + +- (OHGameControllerAxis *)oh_axisForEvdevAxis: (uint16_t)axis +{ + switch (axis) { + case ABS_X: + return [[_directionalPads objectForKey: @"Left Stick"] xAxis]; + case ABS_Y: + return [[_directionalPads objectForKey: @"Left Stick"] yAxis]; + case ABS_RX: + return [[_directionalPads objectForKey: @"Right Stick"] xAxis]; + case ABS_RY: + return [[_directionalPads objectForKey: @"Right Stick"] yAxis]; + case ABS_HAT0X: + return [[_directionalPads objectForKey: @"D-Pad"] xAxis]; + case ABS_HAT0Y: + return [[_directionalPads objectForKey: @"D-Pad"] yAxis]; + case ABS_Z: + return ((OHGameControllerEmulatedTriggerButton *) + [_buttons objectForKey: @"L2"]).axis; + case ABS_RZ: + return ((OHGameControllerEmulatedTriggerButton *) + [_buttons objectForKey: @"R2"]).axis; + default: + return nil; + } +} +#endif +@end ADDED src/hid/OHDualShock4Gamepad.h Index: src/hid/OHDualShock4Gamepad.h ================================================================== --- /dev/null +++ src/hid/OHDualShock4Gamepad.h @@ -0,0 +1,34 @@ +/* + * 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 "OHExtendedGamepad.h" +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) +# import "OHEvdevGameController.h" +#endif + +OF_ASSUME_NONNULL_BEGIN + +@interface OHDualShock4Gamepad: OFObject +@end + +OF_ASSUME_NONNULL_END ADDED src/hid/OHDualShock4Gamepad.m Index: src/hid/OHDualShock4Gamepad.m ================================================================== --- /dev/null +++ src/hid/OHDualShock4Gamepad.m @@ -0,0 +1,290 @@ +/* + * 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 "OHDualShock4Gamepad.h" +#import "OFDictionary.h" +#import "OHGameControllerAxis.h" +#import "OHGameControllerButton.h" +#import "OHGameControllerDirectionalPad.h" +#import "OHGameControllerEmulatedTriggerButton.h" + +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) +# include +#endif + +static OFString *const buttonNames[] = { + @"Triangle", @"Cross", @"Square", @"Circle", @"L1", @"R1", @"L3", @"R3", + @"Options", @"Share", @"PS" +}; +static const size_t numButtons = sizeof(buttonNames) / sizeof(*buttonNames); + +@implementation OHDualShock4Gamepad +@synthesize buttons = _buttons, directionalPads = _directionalPads; + +- (instancetype)init +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + OFMutableDictionary *buttons = + [OFMutableDictionary dictionaryWithCapacity: numButtons]; + OHGameControllerButton *button; + OFMutableDictionary *directionalPads; + OHGameControllerAxis *axis, *xAxis, *yAxis; + OHGameControllerDirectionalPad *directionalPad; + + for (size_t i = 0; i < numButtons; i++) { + button = [[[OHGameControllerButton alloc] + initWithName: buttonNames[i]] autorelease]; + [buttons setObject: button forKey: buttonNames[i]]; + } + + axis = [[[OHGameControllerAxis alloc] + initWithName: @"L2"] autorelease]; + button = [[[OHGameControllerEmulatedTriggerButton alloc] + initWithName: @"L2" + axis: axis] autorelease]; + [buttons setObject: button forKey: @"L2"]; + + axis = [[[OHGameControllerAxis alloc] + initWithName: @"R2"] autorelease]; + button = [[[OHGameControllerEmulatedTriggerButton alloc] + initWithName: @"R2" + axis: axis] autorelease]; + [buttons setObject: button forKey: @"R2"]; + + [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: @"Left Stick" + xAxis: xAxis + yAxis: yAxis] autorelease]; + [directionalPads setObject: directionalPad + forKey: @"Left Stick"]; + + xAxis = [[[OHGameControllerAxis alloc] + initWithName: @"RX"] autorelease]; + yAxis = [[[OHGameControllerAxis alloc] + initWithName: @"RY"] autorelease]; + directionalPad = [[[OHGameControllerDirectionalPad alloc] + initWithName: @"Right Stick" + xAxis: xAxis + yAxis: yAxis] autorelease]; + [directionalPads setObject: directionalPad + forKey: @"Right Stick"]; + + 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"]; + + [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]; +} + +- (OHGameControllerButton *)northButton +{ + return [_buttons objectForKey: @"Triangle"]; +} + +- (OHGameControllerButton *)southButton +{ + return [_buttons objectForKey: @"Cross"]; +} + +- (OHGameControllerButton *)westButton +{ + return [_buttons objectForKey: @"Square"]; +} + +- (OHGameControllerButton *)eastButton +{ + return [_buttons objectForKey: @"Circle"]; +} + +- (OHGameControllerButton *)leftShoulderButton +{ + return [_buttons objectForKey: @"L1"]; +} + +- (OHGameControllerButton *)rightShoulderButton +{ + return [_buttons objectForKey: @"R1"]; +} + +- (OHGameControllerButton *)leftTriggerButton +{ + return [_buttons objectForKey: @"L2"]; +} + +- (OHGameControllerButton *)rightTriggerButton +{ + return [_buttons objectForKey: @"R2"]; +} + +- (OHGameControllerButton *)leftThumbstickButton +{ + return [_buttons objectForKey: @"L3"]; +} + +- (OHGameControllerButton *)rightThumbstickButton +{ + return [_buttons objectForKey: @"R3"]; +} + +- (OHGameControllerButton *)menuButton +{ + return [_buttons objectForKey: @"Options"]; +} + +- (OHGameControllerButton *)optionsButton +{ + return [_buttons objectForKey: @"Share"]; +} + +- (OHGameControllerButton *)homeButton +{ + return [_buttons objectForKey: @"PS"]; +} + +- (OHGameControllerDirectionalPad *)leftThumbstick +{ + return [_directionalPads objectForKey: @"Left Stick"]; +} + +- (OHGameControllerDirectionalPad *)rightThumbstick +{ + return [_directionalPads objectForKey: @"Right Stick"]; +} + +- (OHGameControllerDirectionalPad *)dPad +{ + return [_directionalPads objectForKey: @"D-Pad"]; +} + +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) +- (OHGameControllerButton *)oh_buttonForEvdevButton: (uint16_t)button +{ + OFString *name; + + switch (button) { + case BTN_NORTH: + name = @"Triangle"; + break; + case BTN_SOUTH: + name = @"Cross"; + break; + case BTN_WEST: + name = @"Square"; + break; + case BTN_EAST: + name = @"Circle"; + break; + case BTN_TL: + name = @"L1"; + break; + case BTN_TR: + name = @"R1"; + break; + case BTN_THUMBL: + name = @"L3"; + break; + case BTN_THUMBR: + name = @"R3"; + break; + case BTN_START: + name = @"Options"; + break; + case BTN_SELECT: + name = @"Share"; + break; + case BTN_MODE: + name = @"PS"; + break; + default: + return nil; + } + + return [_buttons objectForKey: name]; +} + +- (OHGameControllerAxis *)oh_axisForEvdevAxis: (uint16_t)axis +{ + switch (axis) { + case ABS_X: + return [[_directionalPads objectForKey: @"Left Stick"] xAxis]; + case ABS_Y: + return [[_directionalPads objectForKey: @"Left Stick"] yAxis]; + case ABS_RX: + return [[_directionalPads objectForKey: @"Right Stick"] xAxis]; + case ABS_RY: + return [[_directionalPads objectForKey: @"Right Stick"] yAxis]; + case ABS_HAT0X: + return [[_directionalPads objectForKey: @"D-Pad"] xAxis]; + case ABS_HAT0Y: + return [[_directionalPads objectForKey: @"D-Pad"] yAxis]; + case ABS_Z: + return ((OHGameControllerEmulatedTriggerButton *) + [_buttons objectForKey: @"L2"]).axis; + case ABS_RZ: + return ((OHGameControllerEmulatedTriggerButton *) + [_buttons objectForKey: @"R2"]).axis; + default: + return nil; + } +} +#endif +@end DELETED src/hid/OHEvdevDualSense.h Index: src/hid/OHEvdevDualSense.h ================================================================== --- src/hid/OHEvdevDualSense.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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 "OHEvdevPlayStationExtendedGamepad.h" - -OF_ASSUME_NONNULL_BEGIN - -@interface OHEvdevDualSense: OHEvdevPlayStationExtendedGamepad -@end - -OF_ASSUME_NONNULL_END DELETED src/hid/OHEvdevDualSense.m Index: src/hid/OHEvdevDualSense.m ================================================================== --- src/hid/OHEvdevDualSense.m +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 "OHEvdevDualSense.h" -#import "OFDictionary.h" - -@implementation OHEvdevDualSense -- (OHGameControllerButton *)optionsButton -{ - return [_rawProfile.buttons objectForKey: @"Create"]; -} -@end DELETED src/hid/OHEvdevDualShock4.h Index: src/hid/OHEvdevDualShock4.h ================================================================== --- src/hid/OHEvdevDualShock4.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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 "OHEvdevPlayStationExtendedGamepad.h" - -OF_ASSUME_NONNULL_BEGIN - -@interface OHEvdevDualShock4: OHEvdevPlayStationExtendedGamepad -@end - -OF_ASSUME_NONNULL_END DELETED src/hid/OHEvdevDualShock4.m Index: src/hid/OHEvdevDualShock4.m ================================================================== --- src/hid/OHEvdevDualShock4.m +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 "OHEvdevDualShock4.h" -#import "OFDictionary.h" - -@implementation OHEvdevDualShock4 -- (OHGameControllerButton *)optionsButton -{ - return [_rawProfile.buttons objectForKey: @"Share"]; -} -@end Index: src/hid/OHEvdevExtendedGamepad.h ================================================================== --- src/hid/OHEvdevExtendedGamepad.h +++ src/hid/OHEvdevExtendedGamepad.h @@ -15,20 +15,14 @@ * You should have received a copy of the GNU Lesser General Public License * version 3.0 along with this program. If not, see * . */ -#import "OHExtendedGamepad.h" +#import "OHEvdevGameControllerProfile.h" OF_ASSUME_NONNULL_BEGIN -@class OHEvdevGameController; - -@interface OHEvdevExtendedGamepad: OFObject -{ - id _rawProfile; -} - -- (instancetype)initWithController: (OHEvdevGameController *)controller; +@interface OHEvdevExtendedGamepad: OHEvdevGameControllerProfile + @end OF_ASSUME_NONNULL_END Index: src/hid/OHEvdevExtendedGamepad.m ================================================================== --- src/hid/OHEvdevExtendedGamepad.m +++ src/hid/OHEvdevExtendedGamepad.m @@ -26,28 +26,35 @@ #import "OHGameControllerEmulatedTriggerButton.h" #import "OFInvalidArgumentException.h" @implementation OHEvdevExtendedGamepad -- (instancetype)initWithController: (OHEvdevGameController *)controller +- (instancetype)initWithKeyBits: (unsigned long *)keyBits + evBits: (unsigned long *)evBits + absBits: (unsigned long *)absBits + vendorID: (uint16_t)vendorID + productID: (uint16_t)productID { - self = [super init]; + self = [super initWithKeyBits: keyBits + evBits: evBits + absBits: absBits + vendorID: vendorID + productID: productID]; @try { void *pool = objc_autoreleasePoolPush(); - _rawProfile = [controller.rawProfile retain]; - if (self.northButton == nil || self.southButton == nil || self.westButton == nil || self.eastButton == nil || self.leftShoulderButton == nil || self.rightShoulderButton == nil || self.leftTriggerButton == nil || self.rightTriggerButton == nil || self.menuButton == nil || self.optionsButton == nil || self.leftThumbstick == nil || self.rightThumbstick == nil || self.dPad == nil) - @throw [OFInvalidArgumentException exception]; + object_setClass(self, + [OHEvdevGameControllerProfile class]); objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @throw e; @@ -54,42 +61,33 @@ } return self; } -- (void)dealloc -{ - [_rawProfile release]; - - [super dealloc]; -} - - (OFDictionary OF_GENERIC(OFString *, OHGameControllerButton *) *)buttons { - OFMutableDictionary *buttons = - [[_rawProfile.buttons mutableCopy] autorelease]; + OFMutableDictionary *buttons = [[_buttons mutableCopy] autorelease]; [buttons removeObjectForKey: @"D-Pad Up"]; [buttons removeObjectForKey: @"D-Pad Down"]; [buttons removeObjectForKey: @"D-Pad Left"]; [buttons removeObjectForKey: @"D-Pad Right"]; - if ([_rawProfile.axes objectForKey: @"Z"] != nil) + if ([_axes objectForKey: @"Z"] != nil) [buttons setObject: self.leftTriggerButton forKey: @"LT"]; - if ([_rawProfile.axes objectForKey: @"RZ"] != nil) + if ([_axes objectForKey: @"RZ"] != nil) [buttons setObject: self.rightTriggerButton forKey: @"RT"]; [buttons makeImmutable]; return buttons; } - (OFDictionary OF_GENERIC(OFString *, OHGameControllerAxis *) *)axes { - OFMutableDictionary *axes = - [[_rawProfile.axes mutableCopy] autorelease]; + OFMutableDictionary *axes = [[_axes mutableCopy] autorelease]; [axes removeObjectForKey: @"X"]; [axes removeObjectForKey: @"Y"]; [axes removeObjectForKey: @"RX"]; [axes removeObjectForKey: @"RY"]; @@ -112,91 +110,91 @@ @"D-Pad", self.dPad, nil]; } - (OHGameControllerButton *)northButton { - return [_rawProfile.buttons objectForKey: @"Y"]; + return [_buttons objectForKey: @"Y"]; } - (OHGameControllerButton *)southButton { - return [_rawProfile.buttons objectForKey: @"A"]; + return [_buttons objectForKey: @"A"]; } - (OHGameControllerButton *)westButton { - return [_rawProfile.buttons objectForKey: @"X"]; + return [_buttons objectForKey: @"X"]; } - (OHGameControllerButton *)eastButton { - return [_rawProfile.buttons objectForKey: @"B"]; + return [_buttons objectForKey: @"B"]; } - (OHGameControllerButton *)leftShoulderButton { - return [_rawProfile.buttons objectForKey: @"LB"]; + return [_buttons objectForKey: @"LB"]; } - (OHGameControllerButton *)rightShoulderButton { - return [_rawProfile.buttons objectForKey: @"RB"]; + return [_buttons objectForKey: @"RB"]; } - (OHGameControllerButton *)leftTriggerButton { - OHGameControllerAxis *axis = [_rawProfile.axes objectForKey: @"Z"]; + OHGameControllerAxis *axis = [_axes objectForKey: @"Z"]; if (axis != nil) return [[[OHGameControllerEmulatedTriggerButton alloc] initWithName: @"LT" axis: axis] autorelease]; - return [_rawProfile.buttons objectForKey: @"LT"]; + return [_buttons objectForKey: @"LT"]; } - (OHGameControllerButton *)rightTriggerButton { - OHGameControllerAxis *axis = [_rawProfile.axes objectForKey: @"RZ"]; + OHGameControllerAxis *axis = [_axes objectForKey: @"RZ"]; if (axis != nil) return [[[OHGameControllerEmulatedTriggerButton alloc] initWithName: @"RT" axis: axis] autorelease]; - return [_rawProfile.buttons objectForKey: @"RT"]; + return [_buttons objectForKey: @"RT"]; } - (OHGameControllerButton *)leftThumbstickButton { - return [_rawProfile.buttons objectForKey: @"LSB"]; + return [_buttons objectForKey: @"LSB"]; } - (OHGameControllerButton *)rightThumbstickButton { - return [_rawProfile.buttons objectForKey: @"RSB"]; + return [_buttons objectForKey: @"RSB"]; } - (OHGameControllerButton *)menuButton { - return [_rawProfile.buttons objectForKey: @"Start"]; + return [_buttons objectForKey: @"Start"]; } - (OHGameControllerButton *)optionsButton { - return [_rawProfile.buttons objectForKey: @"Back"]; + return [_buttons objectForKey: @"Back"]; } - (OHGameControllerButton *)homeButton { - return [_rawProfile.buttons objectForKey: @"Guide"]; + return [_buttons objectForKey: @"Guide"]; } - (OHGameControllerDirectionalPad *)leftThumbstick { - OHGameControllerAxis *xAxis = [_rawProfile.axes objectForKey: @"X"]; - OHGameControllerAxis *yAxis = [_rawProfile.axes objectForKey: @"Y"]; + OHGameControllerAxis *xAxis = [_axes objectForKey: @"X"]; + OHGameControllerAxis *yAxis = [_axes objectForKey: @"Y"]; if (xAxis == nil || yAxis == nil) return nil; return [[[OHGameControllerDirectionalPad alloc] @@ -205,12 +203,12 @@ yAxis: yAxis] autorelease]; } - (OHGameControllerDirectionalPad *)rightThumbstick { - OHGameControllerAxis *xAxis = [_rawProfile.axes objectForKey: @"RX"]; - OHGameControllerAxis *yAxis = [_rawProfile.axes objectForKey: @"RY"]; + OHGameControllerAxis *xAxis = [_axes objectForKey: @"RX"]; + OHGameControllerAxis *yAxis = [_axes objectForKey: @"RY"]; if (xAxis == nil || yAxis == nil) return nil; return [[[OHGameControllerDirectionalPad alloc] @@ -219,24 +217,24 @@ yAxis: yAxis] autorelease]; } - (OHGameControllerDirectionalPad *)dPad { - OHGameControllerAxis *xAxis = [_rawProfile.axes objectForKey: @"HAT0X"]; - OHGameControllerAxis *yAxis = [_rawProfile.axes objectForKey: @"HAT0Y"]; + OHGameControllerAxis *xAxis = [_axes objectForKey: @"HAT0X"]; + OHGameControllerAxis *yAxis = [_axes objectForKey: @"HAT0Y"]; OHGameControllerButton *up, *down, *left, *right; if (xAxis != nil && yAxis != nil) return [[[OHGameControllerDirectionalPad alloc] initWithName: @"D-Pad" xAxis: xAxis yAxis: yAxis] autorelease]; - up = [_rawProfile.buttons objectForKey: @"D-Pad Up"]; - down = [_rawProfile.buttons objectForKey: @"D-Pad Down"]; - left = [_rawProfile.buttons objectForKey: @"D-Pad Left"]; - right = [_rawProfile.buttons objectForKey: @"D-Pad Right"]; + up = [_buttons objectForKey: @"D-Pad Up"]; + down = [_buttons objectForKey: @"D-Pad Down"]; + left = [_buttons objectForKey: @"D-Pad Left"]; + right = [_buttons objectForKey: @"D-Pad Right"]; if (up != nil && down != nil && left != nil && right != nil) return [[[OHGameControllerDirectionalPad alloc] initWithName: @"D-Pad" up: up Index: src/hid/OHEvdevGameController.h ================================================================== --- src/hid/OHEvdevGameController.h +++ src/hid/OHEvdevGameController.h @@ -19,22 +19,32 @@ #import "OHGameController.h" #import "OHGameControllerProfile.h" OF_ASSUME_NONNULL_BEGIN + +@protocol OHEvdevMapping +- (OHGameControllerButton *)oh_buttonForEvdevButton: (uint16_t)button; +- (OHGameControllerAxis *)oh_axisForEvdevAxis: (uint16_t)axis; +@end @interface OHEvdevGameController: OHGameController { OFString *_path; int _fd; bool _discardUntilReport; unsigned long *_evBits, *_keyBits, *_absBits; uint16_t _vendorID, _productID; OFString *_name; - id _rawProfile; + id _profile; } - (instancetype)initWithPath: (OFString *)path; - (void)oh_pollState; @end + +extern const uint16_t OHEvdevButtonIDs[]; +extern const size_t OHNumEvdevButtonIDs; +extern const uint16_t OHEvdevAxisIDs[]; +extern const size_t OHNumEvdevAxisIDs; OF_ASSUME_NONNULL_END Index: src/hid/OHEvdevGameController.m ================================================================== --- src/hid/OHEvdevGameController.m +++ src/hid/OHEvdevGameController.m @@ -29,17 +29,18 @@ #import "OFDictionary.h" #import "OFFileManager.h" #import "OFLocale.h" #import "OFNumber.h" -#import "OHEvdevDualSense.h" -#import "OHEvdevDualShock4.h" +#import "OHDualSenseGamepad.h" +#import "OHDualShock4Gamepad.h" #import "OHEvdevExtendedGamepad.h" -#import "OHEvdevStadiaExtendedGamepad.h" +#import "OHGameControllerAxis+Private.h" #import "OHGameControllerAxis.h" #import "OHGameControllerButton.h" #import "OHGameControllerProfile.h" +#import "OHStadiaGamepad.h" #include #include #import "OFInitializationFailedException.h" @@ -46,28 +47,11 @@ #import "OFInvalidArgumentException.h" #import "OFOpenItemFailedException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" -@interface OHEvdevGameControllerAxis: OHGameControllerAxis -{ -@public - int32_t _minValue, _maxValue; -} -@end - -@interface OHEvdevGameControllerProfile: OFObject -{ - OFDictionary OF_GENERIC(OFString *, OHGameControllerButton *) *_buttons; - OFDictionary OF_GENERIC(OFString *, OHGameControllerAxis *) *_axes; -} - -- (instancetype)initWithButtons: (OFDictionary *)buttons - axes: (OFDictionary *)axes; -@end - -static const uint16_t buttonIDs[] = { +const uint16_t OHEvdevButtonIDs[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_SELECT, BTN_START, BTN_MODE, BTN_THUMBL, BTN_THUMBR, BTN_DPAD_UP, BTN_DPAD_DOWN, BTN_DPAD_LEFT, BTN_DPAD_RIGHT, BTN_TRIGGER_HAPPY1, BTN_TRIGGER_HAPPY2, BTN_TRIGGER_HAPPY3, BTN_TRIGGER_HAPPY4, BTN_TRIGGER_HAPPY5, BTN_TRIGGER_HAPPY6, @@ -82,318 +66,19 @@ BTN_TRIGGER_HAPPY31, BTN_TRIGGER_HAPPY32, BTN_TRIGGER_HAPPY33, BTN_TRIGGER_HAPPY34, BTN_TRIGGER_HAPPY35, BTN_TRIGGER_HAPPY36, BTN_TRIGGER_HAPPY37, BTN_TRIGGER_HAPPY38, BTN_TRIGGER_HAPPY39, BTN_TRIGGER_HAPPY40 }; -static const uint16_t axisIDs[] = { +const size_t OHNumEvdevButtonIDs = + sizeof(OHEvdevButtonIDs) / sizeof(*OHEvdevButtonIDs); +const uint16_t OHEvdevAxisIDs[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ, ABS_THROTTLE, ABS_RUDDER, ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y, ABS_HAT3X, ABS_HAT3Y }; - -static OFString * -buttonToName(uint16_t button, uint16_t vendorID, uint16_t productID) -{ - if (vendorID == OHVendorIDSony && (productID == OHProductIDDualSense || - productID == OHProductIDDualShock4)) { - switch (button) { - case BTN_NORTH: - return @"Triangle"; - case BTN_SOUTH: - return @"Cross"; - case BTN_WEST: - return @"Square"; - case BTN_EAST: - return @"Circle"; - case BTN_TL: - return @"L1"; - case BTN_TR: - return @"R1"; - case BTN_TL2: - return @"L2"; - case BTN_TR2: - return @"R2"; - case BTN_THUMBL: - return @"L3"; - case BTN_THUMBR: - return @"R3"; - case BTN_START: - return @"Options"; - case BTN_SELECT: - if (productID == OHProductIDDualSense) - return @"Create"; - else - return @"Share"; - case BTN_MODE: - return @"PS"; - } - } else 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"; - } - } 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"; - } - } else if (vendorID == OHVendorIDGoogle && - productID == OHProductIDStadiaController) { - switch (button) { - case BTN_TL: - return @"L1"; - case BTN_TR: - return @"R1"; - case BTN_TRIGGER_HAPPY4: - return @"L2"; - case BTN_TRIGGER_HAPPY3: - return @"R2"; - case BTN_THUMBL: - return @"L3"; - case BTN_THUMBR: - return @"R3"; - case BTN_START: - return @"Menu"; - case BTN_SELECT: - return @"Options"; - case BTN_MODE: - return @"Stadia"; - case BTN_TRIGGER_HAPPY1: - return @"Assistant"; - case BTN_TRIGGER_HAPPY2: - return @"Capture"; - } - } - - switch (button) { - case BTN_A: - return @"A"; - case BTN_B: - return @"B"; - case BTN_C: - return @"C"; - case BTN_X: - return @"X"; - case BTN_Y: - return @"Y"; - case BTN_Z: - return @"Z"; - case BTN_TL: - return @"LB"; - case BTN_TR: - return @"RB"; - case BTN_TL2: - return @"LT"; - case BTN_TR2: - return @"RT"; - case BTN_SELECT: - return @"Back"; - case BTN_START: - return @"Start"; - case BTN_MODE: - return @"Guide"; - case BTN_THUMBL: - return @"LSB"; - case BTN_THUMBR: - return @"RSB"; - case BTN_DPAD_UP: - return @"D-Pad Up"; - case BTN_DPAD_DOWN: - return @"D-Pad Down"; - case BTN_DPAD_LEFT: - return @"D-Pad Left"; - case BTN_DPAD_RIGHT: - return @"D-Pad Right"; - case BTN_TRIGGER_HAPPY1: - return @"Trigger Happy 1"; - case BTN_TRIGGER_HAPPY2: - return @"Trigger Happy 2"; - case BTN_TRIGGER_HAPPY3: - return @"Trigger Happy 3"; - case BTN_TRIGGER_HAPPY4: - return @"Trigger Happy 4"; - case BTN_TRIGGER_HAPPY5: - return @"Trigger Happy 5"; - case BTN_TRIGGER_HAPPY6: - return @"Trigger Happy 6"; - case BTN_TRIGGER_HAPPY7: - return @"Trigger Happy 7"; - case BTN_TRIGGER_HAPPY8: - return @"Trigger Happy 8"; - case BTN_TRIGGER_HAPPY9: - return @"Trigger Happy 9"; - case BTN_TRIGGER_HAPPY10: - return @"Trigger Happy 10"; - case BTN_TRIGGER_HAPPY11: - return @"Trigger Happy 11"; - case BTN_TRIGGER_HAPPY12: - return @"Trigger Happy 12"; - case BTN_TRIGGER_HAPPY13: - return @"Trigger Happy 13"; - case BTN_TRIGGER_HAPPY14: - return @"Trigger Happy 14"; - case BTN_TRIGGER_HAPPY15: - return @"Trigger Happy 15"; - case BTN_TRIGGER_HAPPY16: - return @"Trigger Happy 16"; - case BTN_TRIGGER_HAPPY17: - return @"Trigger Happy 17"; - case BTN_TRIGGER_HAPPY18: - return @"Trigger Happy 18"; - case BTN_TRIGGER_HAPPY19: - return @"Trigger Happy 19"; - case BTN_TRIGGER_HAPPY20: - return @"Trigger Happy 20"; - case BTN_TRIGGER_HAPPY21: - return @"Trigger Happy 21"; - case BTN_TRIGGER_HAPPY22: - return @"Trigger Happy 22"; - case BTN_TRIGGER_HAPPY23: - return @"Trigger Happy 23"; - case BTN_TRIGGER_HAPPY24: - return @"Trigger Happy 24"; - case BTN_TRIGGER_HAPPY25: - return @"Trigger Happy 25"; - case BTN_TRIGGER_HAPPY26: - return @"Trigger Happy 26"; - case BTN_TRIGGER_HAPPY27: - return @"Trigger Happy 27"; - case BTN_TRIGGER_HAPPY28: - return @"Trigger Happy 28"; - case BTN_TRIGGER_HAPPY29: - return @"Trigger Happy 29"; - case BTN_TRIGGER_HAPPY30: - return @"Trigger Happy 30"; - case BTN_TRIGGER_HAPPY31: - return @"Trigger Happy 31"; - case BTN_TRIGGER_HAPPY32: - return @"Trigger Happy 32"; - case BTN_TRIGGER_HAPPY33: - return @"Trigger Happy 33"; - case BTN_TRIGGER_HAPPY34: - return @"Trigger Happy 34"; - case BTN_TRIGGER_HAPPY35: - return @"Trigger Happy 35"; - case BTN_TRIGGER_HAPPY36: - return @"Trigger Happy 36"; - case BTN_TRIGGER_HAPPY37: - return @"Trigger Happy 37"; - case BTN_TRIGGER_HAPPY38: - return @"Trigger Happy 38"; - case BTN_TRIGGER_HAPPY39: - return @"Trigger Happy 39"; - case BTN_TRIGGER_HAPPY40: - return @"Trigger Happy 40"; - default: - return nil; - } -} - -static OFString * -axisToName(uint16_t axis) -{ - switch (axis) { - case ABS_X: - return @"X"; - case ABS_Y: - return @"Y"; - case ABS_Z: - return @"Z"; - case ABS_RX: - return @"RX"; - case ABS_RY: - return @"RY"; - case ABS_RZ: - return @"RZ"; - case ABS_THROTTLE: - return @"Throttle"; - case ABS_RUDDER: - return @"Rudder"; - case ABS_WHEEL: - return @"Wheel"; - case ABS_GAS: - return @"Gas"; - case ABS_BRAKE: - return @"Brake"; - case ABS_HAT0X: - return @"HAT0X"; - case ABS_HAT0Y: - return @"HAT0Y"; - case ABS_HAT1X: - return @"HAT1X"; - case ABS_HAT1Y: - return @"HAT1Y"; - case ABS_HAT2X: - return @"HAT2X"; - case ABS_HAT2Y: - return @"HAT2Y"; - case ABS_HAT3X: - return @"HAT3X"; - case ABS_HAT3Y: - return @"HAT3Y"; - default: - return nil; - } -} +const size_t OHNumEvdevAxisIDs = + sizeof(OHEvdevAxisIDs) / sizeof(*OHEvdevAxisIDs); static float scale(float value, float min, float max) { if (value < min) @@ -403,11 +88,11 @@ return ((value - min) / (max - min) * 2) - 1; } @implementation OHEvdevGameController -@synthesize name = _name, rawProfile = _rawProfile; +@synthesize name = _name, profile = _profile; + (OFArray OF_GENERIC(OHGameController *) *)controllers { OFMutableArray *controllers = [OFMutableArray array]; void *pool = objc_autoreleasePoolPush(); @@ -453,11 +138,10 @@ @try { void *pool = objc_autoreleasePoolPush(); OFStringEncoding encoding = [OFLocale encoding]; struct input_id inputID; char name[128]; - OFMutableDictionary *buttons, *axes; _path = [path copy]; if ((_fd = open([_path cStringWithEncoding: encoding], O_RDONLY | O_NONBLOCK)) == -1) @@ -499,31 +183,10 @@ @throw [OFInitializationFailedException exception]; _name = [[OFString alloc] initWithCString: name encoding: encoding]; - buttons = [OFMutableDictionary dictionary]; - for (size_t i = 0; i < sizeof(buttonIDs) / sizeof(*buttonIDs); - i++) { - if (OFBitSetIsSet(_keyBits, buttonIDs[i])) { - OFString *buttonName; - OHGameControllerButton *button; - - buttonName = buttonToName(buttonIDs[i], - _vendorID, _productID); - if (buttonName == nil) - continue; - - button = [[[OHGameControllerButton alloc] - initWithName: buttonName] autorelease]; - - [buttons setObject: button forKey: buttonName]; - } - } - [buttons makeImmutable]; - - axes = [OFMutableDictionary dictionary]; if (OFBitSetIsSet(_evBits, EV_ABS)) { _absBits = OFAllocZeroedMemory(OFRoundUpToPowerOf2( OF_ULONG_BIT, ABS_MAX) / OF_ULONG_BIT, sizeof(unsigned long)); @@ -530,34 +193,28 @@ if (ioctl(_fd, EVIOCGBIT(EV_ABS, OFRoundUpToPowerOf2( OF_ULONG_BIT, ABS_MAX) / OF_ULONG_BIT * sizeof(unsigned long)), _absBits) == -1) @throw [OFInitializationFailedException exception]; - - for (size_t i = 0; - i < sizeof(axisIDs) / sizeof(*axisIDs); i++) { - if (OFBitSetIsSet(_absBits, axisIDs[i])) { - OFString *axisName; - OHEvdevGameControllerAxis *axis; - - axisName = axisToName(axisIDs[i]); - if (axisName == nil) - continue; - - axis = [[[OHEvdevGameControllerAxis - alloc] initWithName: axisName] - autorelease]; - - [axes setObject: axis forKey: axisName]; - } - } - } - [axes makeImmutable]; - - _rawProfile = [[OHEvdevGameControllerProfile alloc] - initWithButtons: buttons - axes: axes]; + } + + if (_vendorID == OHVendorIDSony && + _productID == OHProductIDDualSense) + _profile = [[OHDualSenseGamepad alloc] init]; + else if (_vendorID == OHVendorIDSony && + _productID == OHProductIDDualShock4) + _profile = [[OHDualShock4Gamepad alloc] init]; + else if (_vendorID == OHVendorIDGoogle && + _productID == OHProductIDStadiaController) + _profile = [[OHStadiaGamepad alloc] init]; + else + _profile = [[OHEvdevExtendedGamepad alloc] + initWithKeyBits: _keyBits + evBits: _evBits + absBits: _absBits + vendorID: _vendorID + productID: _productID]; [self oh_pollState]; objc_autoreleasePoolPop(pool); } @catch (id e) { @@ -578,11 +235,11 @@ OFFreeMemory(_evBits); OFFreeMemory(_keyBits); OFFreeMemory(_absBits); [_name release]; - [_rawProfile release]; + [_profile release]; [super dealloc]; } - (OFNumber *)vendorID @@ -604,59 +261,49 @@ @throw [OFReadFailedException exceptionWithObject: self requestedLength: sizeof(keyState) errNo: errno]; - for (size_t i = 0; i < sizeof(buttonIDs) / sizeof(*buttonIDs); - i++) { - OFString *name; + for (size_t i = 0; i < OHNumEvdevButtonIDs; i++) { OHGameControllerButton *button; - if (!OFBitSetIsSet(_keyBits, buttonIDs[i])) + if (!OFBitSetIsSet(_keyBits, OHEvdevButtonIDs[i])) continue; - name = buttonToName(buttonIDs[i], _vendorID, _productID); - if (name == nil) - continue; - - button = [_rawProfile.buttons objectForKey: name]; + button = [_profile + oh_buttonForEvdevButton: OHEvdevButtonIDs[i]]; if (button == nil) continue; - if (OFBitSetIsSet(keyState, buttonIDs[i])) + if (OFBitSetIsSet(keyState, OHEvdevButtonIDs[i])) button.value = 1.f; else button.value = 0.f; } if (OFBitSetIsSet(_evBits, EV_ABS)) { - for (size_t i = 0; i < sizeof(axisIDs) / sizeof(*axisIDs); - i++) { - struct input_absinfo info; - OFString *name; - OHEvdevGameControllerAxis *axis; - - if (!OFBitSetIsSet(_absBits, axisIDs[i])) - continue; - - name = axisToName(axisIDs[i]); - if (name == nil) - continue; - - axis = (OHEvdevGameControllerAxis *) - [_rawProfile.axes objectForKey: name]; + for (size_t i = 0; i < OHNumEvdevAxisIDs; i++) { + struct input_absinfo info; + OHGameControllerAxis *axis; + + if (!OFBitSetIsSet(_absBits, OHEvdevAxisIDs[i])) + continue; + + axis = [_profile + oh_axisForEvdevAxis: OHEvdevAxisIDs[i]]; if (axis == nil) continue; - if (ioctl(_fd, EVIOCGABS(axisIDs[i]), &info) == -1) + if (ioctl(_fd, EVIOCGABS(OHEvdevAxisIDs[i]), + &info) == -1) @throw [OFReadFailedException exceptionWithObject: self requestedLength: sizeof(info) errNo: errno]; - axis->_minValue = info.minimum; - axis->_maxValue = info.maximum; + axis.oh_minRawValue = info.minimum; + axis.oh_maxRawValue = info.maximum; axis.value = scale(info.value, info.minimum, info.maximum); } } } @@ -665,13 +312,12 @@ { void *pool = objc_autoreleasePoolPush(); struct input_event event; for (;;) { - OFString *name; OHGameControllerButton *button; - OHEvdevGameControllerAxis *axis; + OHGameControllerAxis *axis; errno = 0; if (read(_fd, &event, sizeof(event)) < (int)sizeof(event)) { if (errno == EWOULDBLOCK) { @@ -700,15 +346,11 @@ _discardUntilReport = true; continue; } break; case EV_KEY: - name = buttonToName(event.code, _vendorID, _productID); - if (name == nil) - continue; - - button = [_rawProfile.buttons objectForKey: name]; + button = [_profile oh_buttonForEvdevButton: event.code]; if (button == nil) continue; if (event.value) button.value = 1.f; @@ -715,53 +357,36 @@ else button.value = 0.f; break; case EV_ABS: - name = axisToName(event.code); - if (name == nil) - continue; - - axis = (OHEvdevGameControllerAxis *) - [_rawProfile.axes objectForKey: name]; + axis = [_profile oh_axisForEvdevAxis: event.code]; if (axis == nil) continue; axis.value = scale(event.value, - axis->_minValue, axis->_maxValue); + axis.oh_minRawValue, axis.oh_maxRawValue); break; } } } - (id )gamepad { - return self.extendedGamepad; + if ([_profile conformsToProtocol: @protocol(OHGamepad)]) + return (id )_profile; + + return nil; } - (id )extendedGamepad { - @try { - if (_vendorID == OHVendorIDSony && - _productID == OHProductIDDualSense) - return [[[OHEvdevDualSense alloc] - initWithController: self] autorelease]; - else if (_vendorID == OHVendorIDSony && - _productID == OHProductIDDualShock4) - return [[[OHEvdevDualShock4 alloc] - initWithController: self] autorelease]; - else if (_vendorID == OHVendorIDGoogle && - _productID == OHProductIDStadiaController) - return [[[OHEvdevStadiaExtendedGamepad alloc] - initWithController: self] autorelease]; - else - return [[[OHEvdevExtendedGamepad alloc] - initWithController: self] autorelease]; - } @catch (OFInvalidArgumentException *e) { - return nil; - } + if ([_profile conformsToProtocol: @protocol(OHExtendedGamepad)]) + return (id )_profile; + + return nil; } - (OFComparisonResult)compare: (OHEvdevGameController *)otherController { unsigned long long selfIndex, otherIndex; @@ -778,43 +403,6 @@ if (selfIndex < otherIndex) return OFOrderedAscending; return OFOrderedSame; } -@end - -@implementation OHEvdevGameControllerAxis -@end - -@implementation OHEvdevGameControllerProfile -@synthesize buttons = _buttons, axes = _axes; - -- (instancetype)initWithButtons: (OFDictionary *)buttons - axes: (OFDictionary *)axes -{ - self = [super init]; - - @try { - _buttons = [buttons retain]; - _axes = [axes retain]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_buttons release]; - [_axes release]; - - [super dealloc]; -} - -- (OFDictionary OF_GENERIC(OFString *, OHGameControllerDirectionalPad *) *) - directionalPads -{ - return [OFDictionary dictionary]; -} @end ADDED src/hid/OHEvdevGameControllerProfile.h Index: src/hid/OHEvdevGameControllerProfile.h ================================================================== --- /dev/null +++ src/hid/OHEvdevGameControllerProfile.h @@ -0,0 +1,40 @@ +/* + * 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 "OHEvdevGameController.h" +#import "OHGameControllerProfile.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OHEvdevGameControllerProfile: OFObject +{ + OFDictionary OF_GENERIC(OFString *, OHGameControllerButton *) *_buttons; + OFDictionary OF_GENERIC(OFString *, OHGameControllerAxis *) *_axes; + uint16_t _vendorID, _productID; +} + +- (instancetype)initWithKeyBits: (unsigned long *)keyBits + evBits: (unsigned long *)evBits + absBits: (unsigned long *)absBits + vendorID: (uint16_t)vendorID + productID: (uint16_t)productID; +@end + +OF_ASSUME_NONNULL_END ADDED src/hid/OHEvdevGameControllerProfile.m Index: src/hid/OHEvdevGameControllerProfile.m ================================================================== --- /dev/null +++ src/hid/OHEvdevGameControllerProfile.m @@ -0,0 +1,376 @@ +/* + * 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 "OHEvdevGameControllerProfile.h" +#import "OFDictionary.h" +#import "OHGameControllerAxis.h" +#import "OHGameControllerButton.h" + +#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"; + } + } 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"; + case BTN_B: + return @"B"; + case BTN_C: + return @"C"; + case BTN_X: + return @"X"; + case BTN_Y: + return @"Y"; + case BTN_Z: + return @"Z"; + case BTN_TL: + return @"LB"; + case BTN_TR: + return @"RB"; + case BTN_TL2: + return @"LT"; + case BTN_TR2: + return @"RT"; + case BTN_SELECT: + return @"Back"; + case BTN_START: + return @"Start"; + case BTN_MODE: + return @"Guide"; + case BTN_THUMBL: + return @"LSB"; + case BTN_THUMBR: + return @"RSB"; + case BTN_DPAD_UP: + return @"D-Pad Up"; + case BTN_DPAD_DOWN: + return @"D-Pad Down"; + case BTN_DPAD_LEFT: + return @"D-Pad Left"; + case BTN_DPAD_RIGHT: + return @"D-Pad Right"; + case BTN_TRIGGER_HAPPY1: + return @"Trigger Happy 1"; + case BTN_TRIGGER_HAPPY2: + return @"Trigger Happy 2"; + case BTN_TRIGGER_HAPPY3: + return @"Trigger Happy 3"; + case BTN_TRIGGER_HAPPY4: + return @"Trigger Happy 4"; + case BTN_TRIGGER_HAPPY5: + return @"Trigger Happy 5"; + case BTN_TRIGGER_HAPPY6: + return @"Trigger Happy 6"; + case BTN_TRIGGER_HAPPY7: + return @"Trigger Happy 7"; + case BTN_TRIGGER_HAPPY8: + return @"Trigger Happy 8"; + case BTN_TRIGGER_HAPPY9: + return @"Trigger Happy 9"; + case BTN_TRIGGER_HAPPY10: + return @"Trigger Happy 10"; + case BTN_TRIGGER_HAPPY11: + return @"Trigger Happy 11"; + case BTN_TRIGGER_HAPPY12: + return @"Trigger Happy 12"; + case BTN_TRIGGER_HAPPY13: + return @"Trigger Happy 13"; + case BTN_TRIGGER_HAPPY14: + return @"Trigger Happy 14"; + case BTN_TRIGGER_HAPPY15: + return @"Trigger Happy 15"; + case BTN_TRIGGER_HAPPY16: + return @"Trigger Happy 16"; + case BTN_TRIGGER_HAPPY17: + return @"Trigger Happy 17"; + case BTN_TRIGGER_HAPPY18: + return @"Trigger Happy 18"; + case BTN_TRIGGER_HAPPY19: + return @"Trigger Happy 19"; + case BTN_TRIGGER_HAPPY20: + return @"Trigger Happy 20"; + case BTN_TRIGGER_HAPPY21: + return @"Trigger Happy 21"; + case BTN_TRIGGER_HAPPY22: + return @"Trigger Happy 22"; + case BTN_TRIGGER_HAPPY23: + return @"Trigger Happy 23"; + case BTN_TRIGGER_HAPPY24: + return @"Trigger Happy 24"; + case BTN_TRIGGER_HAPPY25: + return @"Trigger Happy 25"; + case BTN_TRIGGER_HAPPY26: + return @"Trigger Happy 26"; + case BTN_TRIGGER_HAPPY27: + return @"Trigger Happy 27"; + case BTN_TRIGGER_HAPPY28: + return @"Trigger Happy 28"; + case BTN_TRIGGER_HAPPY29: + return @"Trigger Happy 29"; + case BTN_TRIGGER_HAPPY30: + return @"Trigger Happy 30"; + case BTN_TRIGGER_HAPPY31: + return @"Trigger Happy 31"; + case BTN_TRIGGER_HAPPY32: + return @"Trigger Happy 32"; + case BTN_TRIGGER_HAPPY33: + return @"Trigger Happy 33"; + case BTN_TRIGGER_HAPPY34: + return @"Trigger Happy 34"; + case BTN_TRIGGER_HAPPY35: + return @"Trigger Happy 35"; + case BTN_TRIGGER_HAPPY36: + return @"Trigger Happy 36"; + case BTN_TRIGGER_HAPPY37: + return @"Trigger Happy 37"; + case BTN_TRIGGER_HAPPY38: + return @"Trigger Happy 38"; + case BTN_TRIGGER_HAPPY39: + return @"Trigger Happy 39"; + case BTN_TRIGGER_HAPPY40: + return @"Trigger Happy 40"; + default: + return nil; + } +} + +static OFString * +axisToName(uint16_t axis) +{ + switch (axis) { + case ABS_X: + return @"X"; + case ABS_Y: + return @"Y"; + case ABS_Z: + return @"Z"; + case ABS_RX: + return @"RX"; + case ABS_RY: + return @"RY"; + case ABS_RZ: + return @"RZ"; + case ABS_THROTTLE: + return @"Throttle"; + case ABS_RUDDER: + return @"Rudder"; + case ABS_WHEEL: + return @"Wheel"; + case ABS_GAS: + return @"Gas"; + case ABS_BRAKE: + return @"Brake"; + case ABS_HAT0X: + return @"HAT0X"; + case ABS_HAT0Y: + return @"HAT0Y"; + case ABS_HAT1X: + return @"HAT1X"; + case ABS_HAT1Y: + return @"HAT1Y"; + case ABS_HAT2X: + return @"HAT2X"; + case ABS_HAT2Y: + return @"HAT2Y"; + case ABS_HAT3X: + return @"HAT3X"; + case ABS_HAT3Y: + return @"HAT3Y"; + default: + return nil; + } +} + +@implementation OHEvdevGameControllerProfile +@synthesize buttons = _buttons, axes = _axes; + +- (instancetype)initWithKeyBits: (unsigned long *)keyBits + evBits: (unsigned long *)evBits + absBits: (unsigned long *)absBits + vendorID: (uint16_t)vendorID + productID: (uint16_t)productID +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + OFMutableDictionary *buttons, *axes; + + buttons = [OFMutableDictionary dictionary]; + for (size_t i = 0; i < OHNumEvdevButtonIDs; i++) { + if (OFBitSetIsSet(keyBits, OHEvdevButtonIDs[i])) { + OFString *buttonName; + OHGameControllerButton *button; + + buttonName = buttonToName(OHEvdevButtonIDs[i], + vendorID, productID); + if (buttonName == nil) + continue; + + button = [[[OHGameControllerButton alloc] + initWithName: buttonName] autorelease]; + + [buttons setObject: button forKey: buttonName]; + } + } + [buttons makeImmutable]; + + axes = [OFMutableDictionary dictionary]; + if (OFBitSetIsSet(evBits, EV_ABS)) { + for (size_t i = 0; i < OHNumEvdevAxisIDs; i++) { + if (OFBitSetIsSet(absBits, OHEvdevAxisIDs[i])) { + OFString *axisName; + OHGameControllerAxis *axis; + + axisName = + axisToName(OHEvdevAxisIDs[i]); + if (axisName == nil) + continue; + + axis = [[[OHGameControllerAxis + alloc] initWithName: axisName] + autorelease]; + + [axes setObject: axis forKey: axisName]; + } + } + } + [axes makeImmutable]; + + _buttons = [buttons retain]; + _axes = [axes retain]; + _vendorID = vendorID; + _productID = productID; + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_buttons release]; + [_axes release]; + + [super dealloc]; +} + +- (OFDictionary OF_GENERIC(OFString *, OHGameControllerDirectionalPad *) *) + directionalPads +{ + return [OFDictionary dictionary]; +} + +- (OHGameControllerButton *)oh_buttonForEvdevButton: (uint16_t)button +{ + OFString *name; + + if ((name = buttonToName(button, _vendorID, _productID)) == nil) + return nil; + + return [_buttons objectForKey: name]; +} + +- (OHGameControllerAxis *)oh_axisForEvdevAxis: (uint16_t)axis +{ + OFString *name; + + if ((name = axisToName(axis)) == nil) + return nil; + + return [_axes objectForKey: name]; +} +@end DELETED src/hid/OHEvdevPlayStationExtendedGamepad.h Index: src/hid/OHEvdevPlayStationExtendedGamepad.h ================================================================== --- src/hid/OHEvdevPlayStationExtendedGamepad.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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 "OHEvdevExtendedGamepad.h" - -OF_ASSUME_NONNULL_BEGIN - -@interface OHEvdevPlayStationExtendedGamepad: OHEvdevExtendedGamepad -@end - -OF_ASSUME_NONNULL_END DELETED src/hid/OHEvdevPlayStationExtendedGamepad.m Index: src/hid/OHEvdevPlayStationExtendedGamepad.m ================================================================== --- src/hid/OHEvdevPlayStationExtendedGamepad.m +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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 "OHEvdevPlayStationExtendedGamepad.h" -#import "OFDictionary.h" -#import "OHGameControllerEmulatedTriggerButton.h" - -@implementation OHEvdevPlayStationExtendedGamepad -- (OFDictionary OF_GENERIC(OFString *, OHGameControllerButton *) *)buttons -{ - OFMutableDictionary *buttons = - [[_rawProfile.buttons mutableCopy] autorelease]; - - [buttons setObject: self.leftTriggerButton forKey: @"L2"]; - [buttons setObject: self.rightTriggerButton forKey: @"R2"]; - - [buttons makeImmutable]; - - return buttons; -} - -- (OHGameControllerButton *)northButton -{ - return [_rawProfile.buttons objectForKey: @"Triangle"]; -} - -- (OHGameControllerButton *)southButton -{ - return [_rawProfile.buttons objectForKey: @"Cross"]; -} - -- (OHGameControllerButton *)westButton -{ - return [_rawProfile.buttons objectForKey: @"Square"]; -} - -- (OHGameControllerButton *)eastButton -{ - return [_rawProfile.buttons objectForKey: @"Circle"]; -} - -- (OHGameControllerButton *)leftShoulderButton -{ - return [_rawProfile.buttons objectForKey: @"L1"]; -} - -- (OHGameControllerButton *)rightShoulderButton -{ - return [_rawProfile.buttons objectForKey: @"R1"]; -} - -- (OHGameControllerButton *)leftTriggerButton -{ - return [[[OHGameControllerEmulatedTriggerButton alloc] - initWithName: @"L2" - axis: [_rawProfile.axes objectForKey: @"Z"]] autorelease]; -} - -- (OHGameControllerButton *)rightTriggerButton -{ - return [[[OHGameControllerEmulatedTriggerButton alloc] - initWithName: @"R2" - axis: [_rawProfile.axes objectForKey: @"RZ"]] autorelease]; -} - -- (OHGameControllerButton *)leftThumbstickButton -{ - return [_rawProfile.buttons objectForKey: @"L3"]; -} - -- (OHGameControllerButton *)rightThumbstickButton -{ - return [_rawProfile.buttons objectForKey: @"R3"]; -} - -- (OHGameControllerButton *)menuButton -{ - return [_rawProfile.buttons objectForKey: @"Options"]; -} - -- (OHGameControllerButton *)homeButton -{ - return [_rawProfile.buttons objectForKey: @"PS"]; -} -@end DELETED src/hid/OHEvdevStadiaExtendedGamepad.h Index: src/hid/OHEvdevStadiaExtendedGamepad.h ================================================================== --- src/hid/OHEvdevStadiaExtendedGamepad.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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 "OHEvdevExtendedGamepad.h" - -OF_ASSUME_NONNULL_BEGIN - -@interface OHEvdevStadiaExtendedGamepad: OHEvdevExtendedGamepad -@end - -OF_ASSUME_NONNULL_END DELETED src/hid/OHEvdevStadiaExtendedGamepad.m Index: src/hid/OHEvdevStadiaExtendedGamepad.m ================================================================== --- src/hid/OHEvdevStadiaExtendedGamepad.m +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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 "OHEvdevStadiaExtendedGamepad.h" -#import "OFDictionary.h" -#import "OHGameControllerAxis.h" -#import "OHGameControllerDirectionalPad.h" -#import "OHGameControllerEmulatedTriggerButton.h" - -@implementation OHEvdevStadiaExtendedGamepad -- (OFDictionary OF_GENERIC(OFString *, OHGameControllerButton *) *)buttons -{ - OFMutableDictionary *buttons = - [[_rawProfile.buttons mutableCopy] autorelease]; - - [buttons setObject: self.leftTriggerButton forKey: @"L2"]; - [buttons setObject: self.rightTriggerButton forKey: @"R2"]; - - [buttons makeImmutable]; - - return buttons; -} - -- (OFDictionary OF_GENERIC(OFString *, OHGameControllerAxis *) *)axes -{ - OFMutableDictionary *axes = - [[_rawProfile.axes mutableCopy] autorelease]; - - [axes removeObjectForKey: @"X"]; - [axes removeObjectForKey: @"Y"]; - [axes removeObjectForKey: @"Z"]; - [axes removeObjectForKey: @"RZ"]; - [axes removeObjectForKey: @"Gas"]; - [axes removeObjectForKey: @"Brake"]; - [axes removeObjectForKey: @"HAT0X"]; - [axes removeObjectForKey: @"HAT0Y"]; - - [axes makeImmutable]; - - return axes; -} - -- (OHGameControllerButton *)leftShoulderButton -{ - return [_rawProfile.buttons objectForKey: @"L1"]; -} - -- (OHGameControllerButton *)rightShoulderButton -{ - return [_rawProfile.buttons objectForKey: @"R1"]; -} - -- (OHGameControllerButton *)leftTriggerButton -{ - OHGameControllerAxis *axis = [_rawProfile.axes objectForKey: @"Brake"]; - - return [[[OHGameControllerEmulatedTriggerButton alloc] - initWithName: @"L2" - axis: axis] autorelease]; -} - -- (OHGameControllerButton *)rightTriggerButton -{ - return [[[OHGameControllerEmulatedTriggerButton alloc] - initWithName: @"R2" - axis: [_rawProfile.axes objectForKey: @"Gas"]] autorelease]; -} - -- (OHGameControllerButton *)leftThumbstickButton -{ - return [_rawProfile.buttons objectForKey: @"L3"]; -} - -- (OHGameControllerButton *)rightThumbstickButton -{ - return [_rawProfile.buttons objectForKey: @"R3"]; -} - -- (OHGameControllerButton *)menuButton -{ - return [_rawProfile.buttons objectForKey: @"Menu"]; -} - -- (OHGameControllerButton *)optionsButton -{ - return [_rawProfile.buttons objectForKey: @"Options"]; -} - -- (OHGameControllerButton *)homeButton -{ - return [_rawProfile.buttons objectForKey: @"Stadia"]; -} - -- (OHGameControllerDirectionalPad *)rightThumbstick -{ - OHGameControllerAxis *xAxis = [_rawProfile.axes objectForKey: @"Z"]; - OHGameControllerAxis *yAxis = [_rawProfile.axes objectForKey: @"RZ"]; - - return [[[OHGameControllerDirectionalPad alloc] - initWithName: @"Right Thumbstick" - xAxis: xAxis - yAxis: yAxis] autorelease]; -} -@end Index: src/hid/OHGameController.h ================================================================== --- src/hid/OHGameController.h +++ src/hid/OHGameController.h @@ -67,14 +67,13 @@ * @brief The product ID of the controller or `nil` if unavailable. */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFNumber *productID; /** - * @brief The raw profile for the game controller, meaning no remapping is - * being performed. + * @brief The profile for the game controller. */ -@property (readonly, nonatomic) id rawProfile; +@property (readonly, nonatomic) id profile; /** * @brief The gamepad profile for the game controller, or `nil` if not * supported. */ Index: src/hid/OHGameController.m ================================================================== --- src/hid/OHGameController.m +++ src/hid/OHGameController.m @@ -52,11 +52,11 @@ const uint16_t OHProductIDRightJoyCon = 0x2007; const uint16_t OHProductIDN64Controller = 0x2019; const uint16_t OHProductIDStadiaController = 0x9400; @implementation OHGameController -@dynamic name, rawProfile; +@dynamic name, profile; + (OFArray OF_GENERIC(OHGameController *) *)controllers { #if defined(OF_LINUX) && defined(OF_HAVE_FILES) return [OHEvdevGameController controllers]; ADDED src/hid/OHGameControllerAxis+Private.h Index: src/hid/OHGameControllerAxis+Private.h ================================================================== --- /dev/null +++ src/hid/OHGameControllerAxis+Private.h @@ -0,0 +1,31 @@ +/* + * 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 "OHGameControllerAxis.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OHGameControllerAxis () +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) +@property (nonatomic, setter=oh_setMinRawValue:) int32_t oh_minRawValue; +@property (nonatomic, setter=oh_setMaxRawValue:) int32_t oh_maxRawValue; +#endif +@end + +OF_ASSUME_NONNULL_END Index: src/hid/OHGameControllerAxis.h ================================================================== --- src/hid/OHGameControllerAxis.h +++ src/hid/OHGameControllerAxis.h @@ -28,10 +28,13 @@ * @brief An axis of a game controller. */ @interface OHGameControllerAxis: OHGameControllerElement { float _value; +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) + int32_t _minRawValue, _maxRawValue; +#endif OF_RESERVE_IVARS(OHGameControllerButton, 4) } /** * @brief The value of the axis. Index: src/hid/OHGameControllerAxis.m ================================================================== --- src/hid/OHGameControllerAxis.m +++ src/hid/OHGameControllerAxis.m @@ -18,13 +18,17 @@ */ #include "config.h" #import "OHGameControllerAxis.h" +#import "OHGameControllerAxis+Private.h" @implementation OHGameControllerAxis @synthesize value = _value; +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) +@synthesize oh_minRawValue = _minRawValue, oh_maxRawValue = _maxRawValue; +#endif - (OFString *)description { return [OFString stringWithFormat: @"<%@: %@>", self.class, self.name]; } Index: src/hid/OHGameControllerEmulatedTriggerButton.h ================================================================== --- src/hid/OHGameControllerEmulatedTriggerButton.h +++ src/hid/OHGameControllerEmulatedTriggerButton.h @@ -26,10 +26,12 @@ OF_SUBCLASSING_RESTRICTED @interface OHGameControllerEmulatedTriggerButton: OHGameControllerButton { OHGameControllerAxis *_axis; } + +@property (readonly, nonatomic) OHGameControllerAxis *axis; - (instancetype)initWithName: (OFString *)name OF_UNAVAILABLE; - (instancetype)initWithName: (OFString *)name axis: (OHGameControllerAxis *)axis; @end Index: src/hid/OHGameControllerEmulatedTriggerButton.m ================================================================== --- src/hid/OHGameControllerEmulatedTriggerButton.m +++ src/hid/OHGameControllerEmulatedTriggerButton.m @@ -21,10 +21,12 @@ #import "OHGameControllerEmulatedTriggerButton.h" #import "OHGameControllerAxis.h" @implementation OHGameControllerEmulatedTriggerButton +@synthesize axis = _axis; + - (instancetype)initWithName: (OFString *)name { OF_INVALID_INIT_METHOD } Index: src/hid/OHNintendo3DSGameController.m ================================================================== --- src/hid/OHNintendo3DSGameController.m +++ src/hid/OHNintendo3DSGameController.m @@ -146,11 +146,11 @@ - (OFString *)name { return @"Nintendo 3DS"; } -- (id )rawProfile +- (id )profile { return _extendedGamepad; } - (id )gamepad Index: src/hid/OHNintendoDSGameController.m ================================================================== --- src/hid/OHNintendoDSGameController.m +++ src/hid/OHNintendoDSGameController.m @@ -107,10 +107,10 @@ - (OFString *)name { return @"Nintendo DS"; } -- (id )rawProfile +- (id )profile { return _gamepad; } @end Index: src/hid/OHNintendoSwitchGameController.m ================================================================== --- src/hid/OHNintendoSwitchGameController.m +++ src/hid/OHNintendoSwitchGameController.m @@ -158,11 +158,11 @@ - (OFString *)name { return @"Nintendo Switch"; } -- (id )rawProfile +- (id )profile { return _extendedGamepad; } - (id )gamepad ADDED src/hid/OHStadiaGamepad.h Index: src/hid/OHStadiaGamepad.h ================================================================== --- /dev/null +++ src/hid/OHStadiaGamepad.h @@ -0,0 +1,34 @@ +/* + * 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 "OHExtendedGamepad.h" +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) +# import "OHEvdevGameController.h" +#endif + +OF_ASSUME_NONNULL_BEGIN + +@interface OHStadiaGamepad: OFObject +@end + +OF_ASSUME_NONNULL_END ADDED src/hid/OHStadiaGamepad.m Index: src/hid/OHStadiaGamepad.m ================================================================== --- /dev/null +++ src/hid/OHStadiaGamepad.m @@ -0,0 +1,296 @@ +/* + * 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 "OHStadiaGamepad.h" +#import "OFDictionary.h" +#import "OHGameControllerAxis.h" +#import "OHGameControllerButton.h" +#import "OHGameControllerDirectionalPad.h" +#import "OHGameControllerEmulatedTriggerButton.h" + +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) +# include +#endif + +static OFString *const buttonNames[] = { + @"A", @"B", @"X", @"Y", @"L1", @"R1", @"L3", @"R3", @"Menu", @"Options", + @"Capture", @"Stadia", @"Assistant" +}; +static const size_t numButtons = sizeof(buttonNames) / sizeof(*buttonNames); + +@implementation OHStadiaGamepad +@synthesize buttons = _buttons, directionalPads = _directionalPads; + +- (instancetype)init +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + OFMutableDictionary *buttons = + [OFMutableDictionary dictionaryWithCapacity: numButtons]; + OHGameControllerButton *button; + OFMutableDictionary *directionalPads; + OHGameControllerAxis *axis, *xAxis, *yAxis; + OHGameControllerDirectionalPad *directionalPad; + + for (size_t i = 0; i < numButtons; i++) { + button = [[[OHGameControllerButton alloc] + initWithName: buttonNames[i]] autorelease]; + [buttons setObject: button forKey: buttonNames[i]]; + } + + axis = [[[OHGameControllerAxis alloc] + initWithName: @"L2"] autorelease]; + button = [[[OHGameControllerEmulatedTriggerButton alloc] + initWithName: @"L2" + axis: axis] autorelease]; + [buttons setObject: button forKey: @"L2"]; + + axis = [[[OHGameControllerAxis alloc] + initWithName: @"R2"] autorelease]; + button = [[[OHGameControllerEmulatedTriggerButton alloc] + initWithName: @"R2" + axis: axis] autorelease]; + [buttons setObject: button forKey: @"R2"]; + + [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: @"Left Stick" + xAxis: xAxis + yAxis: yAxis] autorelease]; + [directionalPads setObject: directionalPad + forKey: @"Left Stick"]; + + xAxis = [[[OHGameControllerAxis alloc] + initWithName: @"RX"] autorelease]; + yAxis = [[[OHGameControllerAxis alloc] + initWithName: @"RY"] autorelease]; + directionalPad = [[[OHGameControllerDirectionalPad alloc] + initWithName: @"Right Stick" + xAxis: xAxis + yAxis: yAxis] autorelease]; + [directionalPads setObject: directionalPad + forKey: @"Right Stick"]; + + 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"]; + + [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]; +} + +- (OHGameControllerButton *)northButton +{ + return [_buttons objectForKey: @"Y"]; +} + +- (OHGameControllerButton *)southButton +{ + return [_buttons objectForKey: @"A"]; +} + +- (OHGameControllerButton *)westButton +{ + return [_buttons objectForKey: @"X"]; +} + +- (OHGameControllerButton *)eastButton +{ + return [_buttons objectForKey: @"B"]; +} + +- (OHGameControllerButton *)leftShoulderButton +{ + return [_buttons objectForKey: @"L1"]; +} + +- (OHGameControllerButton *)rightShoulderButton +{ + return [_buttons objectForKey: @"R1"]; +} + +- (OHGameControllerButton *)leftTriggerButton +{ + return [_buttons objectForKey: @"L2"]; +} + +- (OHGameControllerButton *)rightTriggerButton +{ + return [_buttons objectForKey: @"R2"]; +} + +- (OHGameControllerButton *)leftThumbstickButton +{ + return [_buttons objectForKey: @"L3"]; +} + +- (OHGameControllerButton *)rightThumbstickButton +{ + return [_buttons objectForKey: @"R3"]; +} + +- (OHGameControllerButton *)menuButton +{ + return [_buttons objectForKey: @"Menu"]; +} + +- (OHGameControllerButton *)optionsButton +{ + return [_buttons objectForKey: @"Options"]; +} + +- (OHGameControllerButton *)homeButton +{ + return [_buttons objectForKey: @"Stadia"]; +} + +- (OHGameControllerDirectionalPad *)leftThumbstick +{ + return [_directionalPads objectForKey: @"Left Stick"]; +} + +- (OHGameControllerDirectionalPad *)rightThumbstick +{ + return [_directionalPads objectForKey: @"Right Stick"]; +} + +- (OHGameControllerDirectionalPad *)dPad +{ + return [_directionalPads objectForKey: @"D-Pad"]; +} + +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) +- (OHGameControllerButton *)oh_buttonForEvdevButton: (uint16_t)button +{ + OFString *name; + + switch (button) { + case BTN_A: + name = @"A"; + break; + case BTN_B: + name = @"B"; + break; + case BTN_X: + name = @"X"; + break; + case BTN_Y: + name = @"Y"; + break; + case BTN_TL: + name = @"L1"; + break; + case BTN_TR: + name = @"R1"; + break; + case BTN_THUMBL: + name = @"L3"; + break; + case BTN_THUMBR: + name = @"R3"; + break; + case BTN_START: + name = @"Menu"; + break; + case BTN_SELECT: + name = @"Options"; + break; + case BTN_MODE: + name = @"Stadia"; + break; + case BTN_TRIGGER_HAPPY1: + name = @"Assistant"; + break; + case BTN_TRIGGER_HAPPY2: + name = @"Capture"; + break; + default: + return nil; + } + + return [_buttons objectForKey: name]; +} + +- (OHGameControllerAxis *)oh_axisForEvdevAxis: (uint16_t)axis +{ + switch (axis) { + case ABS_X: + return [[_directionalPads objectForKey: @"Left Stick"] xAxis]; + case ABS_Y: + return [[_directionalPads objectForKey: @"Left Stick"] yAxis]; + case ABS_Z: + return [[_directionalPads objectForKey: @"Right Stick"] xAxis]; + case ABS_RZ: + return [[_directionalPads objectForKey: @"Right Stick"] yAxis]; + case ABS_HAT0X: + return [[_directionalPads objectForKey: @"D-Pad"] xAxis]; + case ABS_HAT0Y: + return [[_directionalPads objectForKey: @"D-Pad"] yAxis]; + case ABS_BRAKE: + return ((OHGameControllerEmulatedTriggerButton *) + [_buttons objectForKey: @"L2"]).axis; + case ABS_GAS: + return ((OHGameControllerEmulatedTriggerButton *) + [_buttons objectForKey: @"R2"]).axis; + default: + return nil; + } +} +#endif +@end Index: src/hid/OHWiiGameController.h ================================================================== --- src/hid/OHWiiGameController.h +++ src/hid/OHWiiGameController.h @@ -23,11 +23,11 @@ @interface OHWiiGameController: OHGameController { int32_t _index; uint32_t _type; - id _rawProfile; + id _profile; } - (instancetype)initWithIndex: (int32_t)index type: (uint32_t)type; @end Index: src/hid/OHWiiGameController.m ================================================================== --- src/hid/OHWiiGameController.m +++ src/hid/OHWiiGameController.m @@ -49,11 +49,11 @@ else return (value - center) / (center - min); } @implementation OHWiiGameController -@synthesize rawProfile = _rawProfile; +@synthesize profile = _profile; + (void)initialize { if (self != [OHWiiGameController class]) return; @@ -93,15 +93,15 @@ @try { _index = index; _type = type; if (type == WPAD_EXP_CLASSIC) - _rawProfile = [[OHWiiClassicController alloc] init]; + _profile = [[OHWiiClassicController alloc] init]; else if (type == WPAD_EXP_NUNCHUK) - _rawProfile = [[OHWiimoteWithNunchuk alloc] init]; + _profile = [[OHWiimoteWithNunchuk alloc] init]; else - _rawProfile = [[OHWiimote alloc] init]; + _profile = [[OHWiimote alloc] init]; [self retrieveState]; } @catch (id e) { [self release]; @throw e; @@ -110,19 +110,19 @@ return self; } - (void)dealloc { - [_rawProfile release]; + [_profile release]; [super dealloc]; } - (void)retrieveState { - OFDictionary *buttons = _rawProfile.buttons; - OFDictionary *directionalPads = _rawProfile.directionalPads; + OFDictionary *buttons = _profile.buttons; + OFDictionary *directionalPads = _profile.directionalPads; WPADData *data; if (WPAD_ReadPending(_index, NULL) < WPAD_ERR_NONE) @throw [OFReadFailedException exceptionWithObject: self @@ -239,18 +239,18 @@ } - (id )gamepad { if (_type == WPAD_EXP_CLASSIC) - return (id )_rawProfile; + return (id )_profile; return nil; } - (id )extendedGamepad { if (_type == WPAD_EXP_CLASSIC) - return (id )_rawProfile; + return (id )_profile; return nil; } @end Index: src/hid/OHXInputGameController.m ================================================================== --- src/hid/OHXInputGameController.m +++ src/hid/OHXInputGameController.m @@ -24,11 +24,11 @@ #import "OFDictionary.h" #import "OFNumber.h" #import "OHGameControllerAxis.h" #import "OHGameControllerButton.h" #import "OHGameControllerDirectionalPad.h" -#import "OHXbox360Gamepad.h" +#import "OHXboxGamepad.h" #import "OFInitializationFailedException.h" #import "OFReadFailedException.h" #include @@ -139,11 +139,11 @@ initWithUnsignedShort: capabilities.productID]; } } - _extendedGamepad = [[OHXbox360Gamepad alloc] + _extendedGamepad = [[OHXboxGamepad alloc] initWithHasGuideButton: (XInputVersion != 910)]; [self retrieveState]; } @catch (id e) { [self release]; @@ -235,15 +235,15 @@ } return nil; } -- (id )rawProfile +- (id )profile { return _extendedGamepad; } - (id )gamepad { return _extendedGamepad; } @end DELETED src/hid/OHXbox360Gamepad.h Index: src/hid/OHXbox360Gamepad.h ================================================================== --- src/hid/OHXbox360Gamepad.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 "OHExtendedGamepad.h" - -OF_ASSUME_NONNULL_BEGIN - -@interface OHXbox360Gamepad: OFObject -{ - OFDictionary OF_GENERIC(OFString *, OHGameControllerButton *) *_buttons; - OFDictionary OF_GENERIC(OFString *, OHGameControllerDirectionalPad *) - *_directionalPads; -} - -- (instancetype)initWithHasGuideButton: (bool)hasGuideButton; -@end - -OF_ASSUME_NONNULL_END DELETED src/hid/OHXbox360Gamepad.m Index: src/hid/OHXbox360Gamepad.m ================================================================== --- src/hid/OHXbox360Gamepad.m +++ /dev/null @@ -1,214 +0,0 @@ -/* - * 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 "OHXbox360Gamepad.h" -#import "OFDictionary.h" -#import "OHGameControllerAxis.h" -#import "OHGameControllerButton.h" -#import "OHGameControllerDirectionalPad.h" - -static OFString *const buttonNames[] = { - @"A", @"B", @"X", @"Y", @"LB", @"RB", @"LT", @"RT", @"LSB", @"RSB", - @"Start", @"Back", @"Guide" -}; -static const size_t numButtons = sizeof(buttonNames) / sizeof(*buttonNames); - -@implementation OHXbox360Gamepad -@synthesize buttons = _buttons, directionalPads = _directionalPads; - -- (instancetype)init -{ - return [self initWithHasGuideButton: true]; -} - -- (instancetype)initWithHasGuideButton: (bool)hasGuideButton -{ - 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; - - if ([buttonNames[i] isEqual: @"Guide"] && - !hasGuideButton) - continue; - - button = [[OHGameControllerButton alloc] - initWithName: buttonNames[i]]; - [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: @"Left Thumbstick" - xAxis: xAxis - yAxis: yAxis] autorelease]; - [directionalPads setObject: directionalPad - forKey: @"Left Thumbstick"]; - - xAxis = [[[OHGameControllerAxis alloc] - initWithName: @"RX"] autorelease]; - yAxis = [[[OHGameControllerAxis alloc] - initWithName: @"RY"] autorelease]; - directionalPad = [[[OHGameControllerDirectionalPad alloc] - initWithName: @"Right Thumbstick" - xAxis: xAxis - yAxis: yAxis] autorelease]; - [directionalPads setObject: directionalPad - forKey: @"Right 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]; -} - -- (OHGameControllerButton *)northButton -{ - return [_buttons objectForKey: @"Y"]; -} - -- (OHGameControllerButton *)southButton -{ - return [_buttons objectForKey: @"A"]; -} - -- (OHGameControllerButton *)westButton -{ - return [_buttons objectForKey: @"X"]; -} - -- (OHGameControllerButton *)eastButton -{ - return [_buttons objectForKey: @"B"]; -} - -- (OHGameControllerButton *)leftShoulderButton -{ - return [_buttons objectForKey: @"LB"]; -} - -- (OHGameControllerButton *)rightShoulderButton -{ - return [_buttons objectForKey: @"RB"]; -} - -- (OHGameControllerButton *)leftTriggerButton -{ - return [_buttons objectForKey: @"LT"]; -} - -- (OHGameControllerButton *)rightTriggerButton -{ - return [_buttons objectForKey: @"RT"]; -} - -- (OHGameControllerButton *)leftThumbstickButton -{ - return [_buttons objectForKey: @"LSB"]; -} - -- (OHGameControllerButton *)rightThumbstickButton -{ - return [_buttons objectForKey: @"RSB"]; -} - -- (OHGameControllerButton *)menuButton -{ - return [_buttons objectForKey: @"Start"]; -} - -- (OHGameControllerButton *)optionsButton -{ - return [_buttons objectForKey: @"Back"]; -} - -- (OHGameControllerButton *)homeButton -{ - return [_buttons objectForKey: @"Guide"]; -} - -- (OHGameControllerDirectionalPad *)leftThumbstick -{ - return [_directionalPads objectForKey: @"Left Thumbstick"]; -} - -- (OHGameControllerDirectionalPad *)rightThumbstick -{ - return [_directionalPads objectForKey: @"Right Thumbstick"]; -} - -- (OHGameControllerDirectionalPad *)dPad -{ - return [_directionalPads objectForKey: @"D-Pad"]; -} -@end ADDED src/hid/OHXboxGamepad.h Index: src/hid/OHXboxGamepad.h ================================================================== --- /dev/null +++ src/hid/OHXboxGamepad.h @@ -0,0 +1,34 @@ +/* + * 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 "OHExtendedGamepad.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OHXboxGamepad: OFObject +{ + OFDictionary OF_GENERIC(OFString *, OHGameControllerButton *) *_buttons; + OFDictionary OF_GENERIC(OFString *, OHGameControllerDirectionalPad *) + *_directionalPads; +} + +- (instancetype)initWithHasGuideButton: (bool)hasGuideButton; +@end + +OF_ASSUME_NONNULL_END ADDED src/hid/OHXboxGamepad.m Index: src/hid/OHXboxGamepad.m ================================================================== --- /dev/null +++ src/hid/OHXboxGamepad.m @@ -0,0 +1,214 @@ +/* + * 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 "OHXboxGamepad.h" +#import "OFDictionary.h" +#import "OHGameControllerAxis.h" +#import "OHGameControllerButton.h" +#import "OHGameControllerDirectionalPad.h" + +static OFString *const buttonNames[] = { + @"A", @"B", @"X", @"Y", @"LB", @"RB", @"LT", @"RT", @"LSB", @"RSB", + @"Start", @"Back", @"Guide" +}; +static const size_t numButtons = sizeof(buttonNames) / sizeof(*buttonNames); + +@implementation OHXboxGamepad +@synthesize buttons = _buttons, directionalPads = _directionalPads; + +- (instancetype)init +{ + return [self initWithHasGuideButton: true]; +} + +- (instancetype)initWithHasGuideButton: (bool)hasGuideButton +{ + 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; + + if ([buttonNames[i] isEqual: @"Guide"] && + !hasGuideButton) + continue; + + 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: @"Left Thumbstick" + xAxis: xAxis + yAxis: yAxis] autorelease]; + [directionalPads setObject: directionalPad + forKey: @"Left Thumbstick"]; + + xAxis = [[[OHGameControllerAxis alloc] + initWithName: @"RX"] autorelease]; + yAxis = [[[OHGameControllerAxis alloc] + initWithName: @"RY"] autorelease]; + directionalPad = [[[OHGameControllerDirectionalPad alloc] + initWithName: @"Right Thumbstick" + xAxis: xAxis + yAxis: yAxis] autorelease]; + [directionalPads setObject: directionalPad + forKey: @"Right 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]; +} + +- (OHGameControllerButton *)northButton +{ + return [_buttons objectForKey: @"Y"]; +} + +- (OHGameControllerButton *)southButton +{ + return [_buttons objectForKey: @"A"]; +} + +- (OHGameControllerButton *)westButton +{ + return [_buttons objectForKey: @"X"]; +} + +- (OHGameControllerButton *)eastButton +{ + return [_buttons objectForKey: @"B"]; +} + +- (OHGameControllerButton *)leftShoulderButton +{ + return [_buttons objectForKey: @"LB"]; +} + +- (OHGameControllerButton *)rightShoulderButton +{ + return [_buttons objectForKey: @"RB"]; +} + +- (OHGameControllerButton *)leftTriggerButton +{ + return [_buttons objectForKey: @"LT"]; +} + +- (OHGameControllerButton *)rightTriggerButton +{ + return [_buttons objectForKey: @"RT"]; +} + +- (OHGameControllerButton *)leftThumbstickButton +{ + return [_buttons objectForKey: @"LSB"]; +} + +- (OHGameControllerButton *)rightThumbstickButton +{ + return [_buttons objectForKey: @"RSB"]; +} + +- (OHGameControllerButton *)menuButton +{ + return [_buttons objectForKey: @"Start"]; +} + +- (OHGameControllerButton *)optionsButton +{ + return [_buttons objectForKey: @"Back"]; +} + +- (OHGameControllerButton *)homeButton +{ + return [_buttons objectForKey: @"Guide"]; +} + +- (OHGameControllerDirectionalPad *)leftThumbstick +{ + return [_directionalPads objectForKey: @"Left Thumbstick"]; +} + +- (OHGameControllerDirectionalPad *)rightThumbstick +{ + return [_directionalPads objectForKey: @"Right Thumbstick"]; +} + +- (OHGameControllerDirectionalPad *)dPad +{ + return [_directionalPads objectForKey: @"D-Pad"]; +} +@end Index: tests/gamecontroller/GameControllerTests.m ================================================================== --- tests/gamecontroller/GameControllerTests.m +++ tests/gamecontroller/GameControllerTests.m @@ -209,17 +209,12 @@ } [OFStdOut setCursorPosition: OFMakePoint(0, 0)]; for (OHGameController *controller in _controllers) { - id profile; - - profile = controller.extendedGamepad; - if (profile == nil) - profile = controller.gamepad; - if (profile == nil) - profile = controller.rawProfile; + id profile = + controller.profile; [OFStdOut setForegroundColor: [OFColor green]]; [OFStdOut writeLine: controller.description]; @try {