Index: src/hid/Makefile ================================================================== --- src/hid/Makefile +++ src/hid/Makefile @@ -18,11 +18,12 @@ OHGamepad.m \ ${USE_SRCS_EVDEV} \ ${USE_SRCS_NINTENDO_3DS} \ ${USE_SRCS_NINTENDO_DS} \ ${USE_SRCS_XINPUT} -SRCS_EVDEV = OHEvdevGameController.m \ +SRCS_EVDEV = OHEvdevDualSense.m \ + OHEvdevGameController.m \ OHEvdevGamepad.m SRCS_NINTENDO_3DS = OHNintendo3DSGameController.m \ OHNintendo3DSGamepad.m SRCS_NINTENDO_DS = OHNintendoDSGameController.m SRCS_XINPUT = OHXInputGameController.m \ ADDED src/hid/OHEvdevDualSense.h Index: src/hid/OHEvdevDualSense.h ================================================================== --- /dev/null +++ src/hid/OHEvdevDualSense.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 3.0 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * version 3.0 for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3.0 along with this program. If not, see + * . + */ + +#import "OHEvdevGamepad.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OHEvdevDualSense: OHEvdevGamepad +@end + +OF_ASSUME_NONNULL_END ADDED src/hid/OHEvdevDualSense.m Index: src/hid/OHEvdevDualSense.m ================================================================== --- /dev/null +++ src/hid/OHEvdevDualSense.m @@ -0,0 +1,104 @@ +/* + * 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" +#import "OFNumber.h" +#import "OHEvdevGameController.h" +#import "OHGameControllerDirectionalPad.h" +#import "OHGameControllerEmulatedTriggerButton.h" + +#import "OFInvalidArgumentException.h" + +@implementation OHEvdevDualSense +- (OFDictionary OF_GENERIC(OFString *, OHGameControllerButton *) *)buttons +{ + OFMutableDictionary *buttons = + [[_rawProfile.buttons mutableCopy] autorelease]; + + [buttons removeObjectForKey: @"D-Pad Up"]; + [buttons removeObjectForKey: @"D-Pad Down"]; + [buttons removeObjectForKey: @"D-Pad Left"]; + [buttons removeObjectForKey: @"D-Pad Right"]; + + [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 *)leftThumbstickButton +{ + return [_rawProfile.buttons objectForKey: @"L3"]; +} + +- (OHGameControllerButton *)rightThumbstickButton +{ + return [_rawProfile.buttons objectForKey: @"R3"]; +} + +- (OHGameControllerButton *)menuButton +{ + return [_rawProfile.buttons objectForKey: @"Options"]; +} + +- (OHGameControllerButton *)optionsButton +{ + return [_rawProfile.buttons objectForKey: @"Create"]; +} + +- (OHGameControllerButton *)homeButton +{ + return [_rawProfile.buttons objectForKey: @"PS"]; +} +@end Index: src/hid/OHEvdevGameController.m ================================================================== --- src/hid/OHEvdevGameController.m +++ src/hid/OHEvdevGameController.m @@ -29,10 +29,11 @@ #import "OFDictionary.h" #import "OFFileManager.h" #import "OFLocale.h" #import "OFNumber.h" +#import "OHEvdevDualSense.h" #import "OHEvdevGamepad.h" #import "OHGameControllerAxis.h" #import "OHGameControllerButton.h" #import "OHGameControllerProfile.h" @@ -81,12 +82,43 @@ 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) +buttonToName(uint16_t button, uint16_t vendorID, uint16_t productID) { + if (vendorID == OHVendorIDSony && productID == OHProductIDDualSense) { + 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: + return @"Create"; + case BTN_MODE: + return @"PS"; + } + } + switch (button) { case BTN_A: return @"A"; case BTN_B: return @"B"; @@ -369,11 +401,12 @@ i++) { if (OFBitSetIsSet(_keyBits, buttonIDs[i])) { OFString *buttonName; OHGameControllerButton *button; - buttonName = buttonToName(buttonIDs[i]); + buttonName = buttonToName(buttonIDs[i], + _vendorID, _productID); if (buttonName == nil) continue; button = [[[OHGameControllerButton alloc] initWithName: buttonName] autorelease]; @@ -474,11 +507,11 @@ OHGameControllerButton *button; if (!OFBitSetIsSet(_keyBits, buttonIDs[i])) continue; - name = buttonToName(buttonIDs[i]); + name = buttonToName(buttonIDs[i], _vendorID, _productID); if (name == nil) continue; button = [_rawProfile.buttons objectForKey: name]; if (button == nil) @@ -562,11 +595,11 @@ _discardUntilReport = true; continue; } break; case EV_KEY: - name = buttonToName(event.code); + name = buttonToName(event.code, _vendorID, _productID); if (name == nil) continue; button = [_rawProfile.buttons objectForKey: name]; if (button == nil) @@ -597,12 +630,17 @@ } - (OHGamepad *)gamepad { @try { - return [[[OHEvdevGamepad alloc] - initWithController: self] autorelease]; + if (_vendorID == OHVendorIDSony && + _productID == OHProductIDDualSense) + return [[[OHEvdevDualSense alloc] + initWithController: self] autorelease]; + else + return [[[OHEvdevGamepad alloc] + initWithController: self] autorelease]; } @catch (OFInvalidArgumentException *e) { return nil; } } Index: src/hid/OHGameController.h ================================================================== --- src/hid/OHGameController.h +++ src/hid/OHGameController.h @@ -93,7 +93,16 @@ * * @throw OFReadFailedException The controller's state could not be read */ - (void)retrieveState; @end + +#ifdef __cplusplus +extern "C" { +#endif +extern const uint16_t OHVendorIDSony; +extern const uint16_t OHProductIDDualSense; +#ifdef __cplusplus +} +#endif OF_ASSUME_NONNULL_END Index: src/hid/OHGameController.m ================================================================== --- src/hid/OHGameController.m +++ src/hid/OHGameController.m @@ -36,10 +36,13 @@ #endif #ifdef OF_NINTENDO_3DS # import "OHNintendo3DSGameController.h" #endif +const uint16_t OHVendorIDSony = 0x054C; +const uint16_t OHProductIDDualSense = 0x0CE6; + @implementation OHGameController @dynamic name, rawProfile; + (OFArray OF_GENERIC(OHGameController *) *)controllers {