Index: src/OFGameController.h ================================================================== --- src/OFGameController.h +++ src/OFGameController.h @@ -197,15 +197,18 @@ int _fd; uint16_t _vendorID, _productID; OFString *_name; OFMutableSet *_buttons, *_pressedButtons; bool _hasLeftAnalogStick, _hasRightAnalogStick; + bool _hasZLPressure, _hasZRPressure; OFPoint _leftAnalogStickPosition, _rightAnalogStickPosition; + float _ZLPressure, _ZRPressure; int32_t _leftAnalogStickMinX, _leftAnalogStickMaxX; int32_t _leftAnalogStickMinY, _leftAnalogStickMaxY; int32_t _rightAnalogStickMinX, _rightAnalogStickMaxX; int32_t _rightAnalogStickMinY, _rightAnalogStickMaxY; + int32_t _ZLMinPressure, _ZLMaxPressure, _ZRMinPressure, _ZRMaxPressure; #endif } #ifdef OF_HAVE_CLASS_PROPERTIES @property (class, readonly, nonatomic) @@ -218,17 +221,18 @@ @property (readonly, nonatomic, copy) OFString *name; /** * @brief The buttons the controller has. */ -@property (readonly, nonatomic, copy) OFSet OF_GENERIC(OFString *) *buttons; +@property (readonly, nonatomic, copy) + OFSet OF_GENERIC(OFGameControllerButton) *buttons; /** * @brief The currently pressed buttons on the controller. */ @property (readonly, nonatomic, copy) - OFSet OF_GENERIC(OFString *) *pressedButtons; + OFSet OF_GENERIC(OFGameControllerButton) *pressedButtons; /** * @brief Whether the controller has a left analog stick. */ @property (readonly, nonatomic) bool hasLeftAnalogStick; @@ -258,8 +262,18 @@ * @return The available controllers */ + (OFArray OF_GENERIC(OFGameController *) *)controllers; - (instancetype)init OF_UNAVAILABLE; + +/** + * @brief Returns how hard the specified button is pressed. + * + * The returned value is in the range from 0 to 1. + * + * @param button The button for which to return how hard it is pressed. + * @return How hard the specified button is pressed + */ +- (float)pressureForButton: (OFGameControllerButton)button; @end OF_ASSUME_NONNULL_END Index: src/OFGameController.m ================================================================== --- src/OFGameController.m +++ src/OFGameController.m @@ -67,7 +67,12 @@ - (instancetype)init { OF_INVALID_INIT_METHOD } + +- (float)pressureForButton: (OFGameControllerButton)button +{ + return 0; +} @end #endif Index: src/platform/Linux/OFGameController.m ================================================================== --- src/platform/Linux/OFGameController.m +++ src/platform/Linux/OFGameController.m @@ -53,11 +53,11 @@ 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 }; -static OFString * +static OFGameControllerButton buttonToName(uint16_t button, uint16_t vendorID, uint16_t productID) { if (vendorID == vendorIDMicrosoft && productID == productIDXbox360Controller) { switch (button) { @@ -242,11 +242,11 @@ encoding: encoding]; _buttons = [[OFMutableSet alloc] init]; for (size_t i = 0; i < sizeof(buttons) / sizeof(*buttons); i++) { - OFString *buttonName = + OFGameControllerButton buttonName = buttonToName(buttons[i], _vendorID, _productID); if (buttonName != nil) [_buttons addObject: buttonName]; } @@ -309,14 +309,39 @@ OFGameControllerButtonDPadUp]; [_buttons addObject: OFGameControllerButtonDPadDown]; } - if (OFBitSetIsSet(absBits, ABS_Z)) + if (OFBitSetIsSet(absBits, ABS_Z)) { + struct input_absinfo info; + + _hasZLPressure = true; + + if (ioctl(_fd, EVIOCGABS(ABS_Z), &info) == -1) + @throw [OFInitializationFailedException + exception]; + + _ZLMinPressure = info.minimum; + _ZLMaxPressure = info.maximum; + [_buttons addObject: OFGameControllerButtonZL]; - if (OFBitSetIsSet(absBits, ABS_RZ)) + } + + if (OFBitSetIsSet(absBits, ABS_RZ)) { + struct input_absinfo info; + + _hasZRPressure = true; + + if (ioctl(_fd, EVIOCGABS(ABS_RZ), &info) == -1) + @throw [OFInitializationFailedException + exception]; + + _ZRMinPressure = info.minimum; + _ZRMaxPressure = info.maximum; + [_buttons addObject: OFGameControllerButtonZR]; + } } [_buttons makeImmutable]; } @catch (id e) { [self release]; @@ -343,11 +368,11 @@ - (void)of_processEvents { struct input_event event; for (;;) { - OFString *name; + OFGameControllerButton name; errno = 0; if (read(_fd, &event, sizeof(event)) < (int)sizeof(event)) { if (errno == EWOULDBLOCK) @@ -424,19 +449,25 @@ [_pressedButtons removeObject: OFGameControllerButtonDPadDown]; } break; case ABS_Z: - if (event.value > 0) + _ZLPressure = scale(event.value, + _ZLMinPressure, _ZLMaxPressure); + + if (_ZLPressure > 0) [_pressedButtons addObject: OFGameControllerButtonZL]; else [_pressedButtons removeObject: OFGameControllerButtonZL]; break; case ABS_RZ: - if (event.value > 0) + _ZRPressure = scale(event.value, + _ZRMinPressure, _ZRMaxPressure); + + if (_ZRPressure > 0) [_pressedButtons addObject: OFGameControllerButtonZR]; else [_pressedButtons removeObject: OFGameControllerButtonZR]; @@ -482,11 +513,26 @@ - (OFPoint)rightAnalogStickPosition { [self of_processEvents]; return _rightAnalogStickPosition; } + +- (float)pressureForButton: (OFGameControllerButton)button +{ + if ([button isEqual: OFGameControllerButtonZL] && _hasZLPressure) { + [self of_processEvents]; + return _ZLPressure; + } + + if ([button isEqual: OFGameControllerButtonZR] && _hasZRPressure) { + [self of_processEvents]; + return _ZRPressure; + } + + return ([self.pressedButtons containsObject: button] ? 1 : 0); +} - (OFString *)description { return [OFString stringWithFormat: @"<%@: %@>", self.class, self.name]; } @end Index: src/platform/Nintendo3DS/OFGameController.m ================================================================== --- src/platform/Nintendo3DS/OFGameController.m +++ src/platform/Nintendo3DS/OFGameController.m @@ -71,11 +71,11 @@ - (OFString *)name { return @"Nintendo 3DS"; } -- (OFSet *)buttons +- (OFSet OF_GENERIC(OFGameControllerButton) *)buttons { return [OFSet setWithObjects: OFGameControllerButtonA, OFGameControllerButtonB, OFGameControllerButtonSelect, OFGameControllerButtonStart, OFGameControllerButtonDPadRight, OFGameControllerButtonDPadLeft, OFGameControllerButtonDPadUp, @@ -85,13 +85,14 @@ OFGameControllerButtonZR, OFGameControllerButtonCPadRight, OFGameControllerButtonCPadLeft, OFGameControllerButtonCPadUp, OFGameControllerButtonCPadDown, nil]; } -- (OFSet *)pressedButtons +- (OFSet OF_GENERIC(OFGameControllerButton) *)pressedButtons { - OFMutableSet *pressedButtons = [OFMutableSet setWithCapacity: 18]; + OFMutableSet OF_GENERIC(OFGameControllerButton) *pressedButtons = + [OFMutableSet setWithCapacity: 18]; u32 keys; hidScanInput(); keys = hidKeysHeld(); @@ -154,11 +155,16 @@ return OFMakePoint( (float)pos.dx / (pos.dx < 0 ? -INT16_MIN : INT16_MAX), (float)pos.dy / (pos.dy < 0 ? -INT16_MIN : INT16_MAX)); } + +- (float)pressureForButton: (OFGameControllerButton)button +{ + return ([self.pressedButtons containsObject: button] ? 1 : 0); +} - (OFString *)description { return [OFString stringWithFormat: @"<%@: %@>", self.class, self.name]; } @end Index: src/platform/NintendoDS/OFGameController.m ================================================================== --- src/platform/NintendoDS/OFGameController.m +++ src/platform/NintendoDS/OFGameController.m @@ -71,11 +71,11 @@ - (OFString *)name { return @"Nintendo DS"; } -- (OFSet *)buttons +- (OFSet OF_GENERIC(OFGameControllerButton) *)buttons { return [OFSet setWithObjects: OFGameControllerButtonA, OFGameControllerButtonB, OFGameControllerButtonSelect, OFGameControllerButtonStart, OFGameControllerButtonDPadRight, OFGameControllerButtonDPadLeft, OFGameControllerButtonDPadUp, @@ -82,13 +82,14 @@ OFGameControllerButtonDPadDown, OFGameControllerButtonR, OFGameControllerButtonL, OFGameControllerButtonX, OFGameControllerButtonY, nil]; } -- (OFSet *)pressedButtons +- (OFSet OF_GENERIC(OFGameControllerButton) *)pressedButtons { - OFMutableSet *pressedButtons = [OFMutableSet setWithCapacity: 12]; + OFMutableSet OF_GENERIC(OFGameControllerButton) *pressedButtons = + [OFMutableSet setWithCapacity: 12]; uint32 keys; scanKeys(); keys = keysCurrent(); @@ -129,11 +130,16 @@ - (bool)hasRightAnalogStick { return false; } + +- (float)pressureForButton: (OFGameControllerButton)button +{ + return ([self.pressedButtons containsObject: button] ? 1 : 0); +} - (OFString *)description { return [OFString stringWithFormat: @"<%@: %@>", self.class, self.name]; } @end Index: tests/gamecontroller/GameControllerTests.m ================================================================== --- tests/gamecontroller/GameControllerTests.m +++ tests/gamecontroller/GameControllerTests.m @@ -41,23 +41,33 @@ for (;;) { [OFStdOut setCursorPosition: OFMakePoint(0, 0)]; for (OFGameController *controller in controllers) { - OFArray *buttons = + OFArray OF_GENERIC(OFGameControllerButton) *buttons = controller.buttons.allObjects.sortedArray; size_t i = 0; [OFStdOut setForegroundColor: [OFColor green]]; [OFStdOut writeLine: controller.name]; - for (OFString *button in buttons) { - bool pressed = [controller.pressedButtons - containsObject: button]; + for (OFGameControllerButton button in buttons) { + float pressure = + [controller pressureForButton: button]; - [OFStdOut setForegroundColor: (pressed - ? [OFColor yellow] : [OFColor gray])]; + if (pressure == 1) + [OFStdOut setForegroundColor: + [OFColor red]]; + else if (pressure > 0.5) + [OFStdOut setForegroundColor: + [OFColor yellow]]; + else if (pressure > 0) + [OFStdOut setForegroundColor: + [OFColor green]]; + else + [OFStdOut setForegroundColor: + [OFColor gray]]; [OFStdOut writeFormat: @"[%@]", button]; if (++i == 5) { [OFStdOut writeString: @"\n"];