Index: src/OFGameController.h ================================================================== --- src/OFGameController.h +++ src/OFGameController.h @@ -35,10 +35,11 @@ @interface OFGameController: OFObject { #ifdef OF_LINUX OFString *_path; int _fd; + uint16_t _vendorID, _productID; OFString *_name; OFMutableSet *_buttons, *_pressedButtons; bool _hasLeftAnalogStick, _hasRightAnalogStick; OFPoint _leftAnalogStickPosition, _rightAnalogStickPosition; int32_t _leftAnalogStickMinX, _leftAnalogStickMaxX; Index: src/platform/Linux/OFGameController.m ================================================================== --- src/platform/Linux/OFGameController.m +++ src/platform/Linux/OFGameController.m @@ -36,10 +36,13 @@ #import "OFInvalidArgumentException.h" #import "OFOpenItemFailedException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" +static const uint16_t vendorIDNintendo = 0x057E; +static const uint16_t productIDN64Controller = 0x2019; + @interface OFGameController () - (instancetype)of_initWithPath: (OFString *)path OF_METHOD_FAMILY(init); - (void)of_processEvents; @end @@ -48,12 +51,35 @@ BTN_TR2, BTN_SELECT, BTN_START, BTN_MODE, BTN_THUMBL, BTN_THUMBR, BTN_DPAD_UP, BTN_DPAD_DOWN, BTN_DPAD_LEFT, BTN_DPAD_RIGHT }; static OFString * -buttonToName(uint16_t button) +buttonToName(uint16_t button, uint16_t vendorID, uint16_t productID) { + if (vendorID == vendorIDNintendo && + productID == productIDN64Controller) { + switch (button) { + case BTN_TL2: + return @"Z"; + case BTN_Y: + return @"C-Stick Left"; + case BTN_C: + return @"C-Stick Right"; + case BTN_SELECT: + return @"C-Stick Up"; + case BTN_X: + return @"C-Stick Down"; + case BTN_MODE: + return @"Home"; + case BTN_Z: + return @"Capture"; + case BTN_THUMBL: + case BTN_THUMBR: + return nil; + } + } + switch (button) { case BTN_A: return @"A"; case BTN_B: return @"B"; @@ -166,10 +192,11 @@ EV_MAX) / OF_ULONG_BIT] = { 0 }; unsigned long keyBits[OFRoundUpToPowerOf2(OF_ULONG_BIT, KEY_MAX) / OF_ULONG_BIT] = { 0 }; unsigned long absBits[OFRoundUpToPowerOf2(OF_ULONG_BIT, ABS_MAX) / OF_ULONG_BIT] = { 0 }; + struct input_id inputID; char name[128]; _path = [path copy]; if ((_fd = open([_path cStringWithEncoding: encoding], @@ -189,20 +216,32 @@ -1) @throw [OFInitializationFailedException exception]; if (!OFBitSetIsSet(keyBits, BTN_GAMEPAD)) @throw [OFInvalidArgumentException exception]; + + if (ioctl(_fd, EVIOCGID, &inputID) == -1) + @throw [OFInvalidArgumentException exception]; + + _vendorID = inputID.vendor; + _productID = inputID.product; if (ioctl(_fd, EVIOCGNAME(sizeof(name)), name) == -1) @throw [OFInitializationFailedException exception]; _name = [[OFString alloc] initWithCString: name encoding: encoding]; _buttons = [[OFMutableSet alloc] init]; - for (size_t i = 0; i < sizeof(buttons) / sizeof(*buttons); i++) - [_buttons addObject: buttonToName(buttons[i])]; + for (size_t i = 0; i < sizeof(buttons) / sizeof(*buttons); + i++) { + OFString *buttonName = + buttonToName(buttons[i], _vendorID, _productID); + + if (buttonName != nil) + [_buttons addObject: buttonName]; + } _pressedButtons = [[OFMutableSet alloc] init]; if (OFBitSetIsSet(evBits, EV_ABS)) { if (ioctl(_fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), @@ -290,10 +329,12 @@ - (void)of_processEvents { struct input_event event; for (;;) { + OFString *name; + errno = 0; if (read(_fd, &event, sizeof(event)) < (int)sizeof(event)) { if (errno == EWOULDBLOCK) return; @@ -304,16 +345,17 @@ errNo: errno]; } switch (event.type) { case EV_KEY: - if (event.value) - [_pressedButtons addObject: - buttonToName(event.code)]; - else - [_pressedButtons removeObject: - buttonToName(event.code)]; + if ((name = buttonToName(event.code, _vendorID, + _productID)) != nil) { + if (event.value) + [_pressedButtons addObject: name]; + else + [_pressedButtons removeObject: name]; + } break; case EV_ABS: switch (event.code) { case ABS_X: _leftAnalogStickPosition.x = scale(event.value,