diff --git a/Adaptoid_N64.ini b/Adaptoid_N64.ini new file mode 100644 index 0000000..dc092c4 --- /dev/null +++ b/Adaptoid_N64.ini @@ -0,0 +1,46 @@ +// Wish Technologies Adaptoid N64-to-USB-HID converter +// Must be mapped to GamePad for the buffering to work properly (not to a Pro Controller) +[vid=0x06F7,pid=0x0001] + +// A / B / L / R buttons +VPAD_BUTTON_A = 0x03, 0x01 +// VPAD_BUTTON_B = 0x03, 0x08 +VPAD_BUTTON_X = 0x03, 0x08 // Wii U SM64 port uses X rather than B +VPAD_BUTTON_L = 0x03, 0x40 +VPAD_BUTTON_R = 0x03, 0x80 + +// N64 Start button mapped to Wii U + button +VPAD_BUTTON_PLUS = 0x04, 0x01 + +// N64 Z trigger mapped to Wii U ZL trigger +VPAD_BUTTON_ZL = 0x04, 0x02 + +// N64 C buttons mapped to Wii U right stick +VPAD_R_STICK_UP = 0x03, 0x20 +VPAD_R_STICK_DOWN = 0x03, 0x02 +VPAD_R_STICK_LEFT = 0x03, 0x10 +VPAD_R_STICK_RIGHT = 0x03, 0x04 + +// N64 Dpad mapped to Wii U Dpad +VPAD_BUTTON_UP = 0x04, 0x04 +VPAD_BUTTON_DOWN = 0x04, 0x08 +VPAD_BUTTON_LEFT = 0x04, 0x10 +VPAD_BUTTON_RIGHT = 0x04, 0x20 + +// N64 Stick mapped to Wii U Left Stick +VPad_L_Stick_X = 0x00, 0x00 +// VPad_L_Stick_X_Default_MSB = 0x00 // Most significant byte - not needed, since zero +VPad_L_Stick_X_Bit_Length = 0x0C // 12bit HID axis report +VPad_L_Stick_X_Signed = True // Range includes negative values +VPad_L_Stick_X_MinMax = 0x50, 0xB0 // -1200 to 1200 expressed as s16 type (two's complement, i.e. 0xFB50 to 0x04B0) +VPad_L_Stick_X_MinMax_MSB = 0xFB, 0x04 // Most significant bytes +VPad_L_Stick_Y = 0x01, 0x00 +// VPad_L_Stick_Y_Default_MSB = 0x00 +VPad_L_Stick_Y_Bit_Length = 0x0C +VPad_L_Stick_Y_Bit_Offset = 0x04 // Second 12bit stick axis report is not byte-aligned +VPad_L_Stick_Y_Signed = True +VPad_L_Stick_Y_MinMax = 0x50, 0xB0 +VPad_L_Stick_Y_MinMax_MSB = 0xFB, 0x04 +VPad_L_Stick_Y_Invert = True +VPad_L_Stick_X_Deadzone = 0x20 // Customize for your controller wear state +VPad_L_Stick_Y_Deadzone = 0x20 diff --git a/include/controller_patcher/ControllerPatcher.hpp b/include/controller_patcher/ControllerPatcher.hpp index 20c2b38..8cfb1d6 100644 --- a/include/controller_patcher/ControllerPatcher.hpp +++ b/include/controller_patcher/ControllerPatcher.hpp @@ -111,7 +111,7 @@ class ControllerPatcher { static CONTROLLER_PATCHER_RESULT_OR_ERROR UpdateSamplingFunctionAddress(); /** - Disbale the Controller mapping. Afterwards all connected controllers will be used for the gamepad. + Disable the Controller mapping. Afterwards all connected controllers will be used for the gamepad. @return When the functions failed result < 0 is returned. If the result is == 0 the function was successful. **/ static CONTROLLER_PATCHER_RESULT_OR_ERROR disableControllerMapping(); @@ -173,7 +173,7 @@ class ControllerPatcher { static BOOL isControllerConnectedAndActive(UController_Type type, int32_t mapping_slot = 0); /** - Search for a connected mouse and returns a pointer to it's data. + Search for a connected mouse and returns a pointer to its data. @return A pointer to the first connected mouse that is found. NULL if no mouse is connected. **/ static HID_Mouse_Data *getMouseData(); @@ -241,7 +241,7 @@ class ControllerPatcher { static CONTROLLER_PATCHER_RESULT_OR_ERROR setKPADConnectedCallback(int32_t chan, WPADConnectCallback callback); - static CONTROLLER_PATCHER_RESULT_OR_ERROR setKPADExtensionCallback(int32_t chan, WPADConnectCallback callback); + static CONTROLLER_PATCHER_RESULT_OR_ERROR setKPADExtensionCallback(int32_t chan, WPADExtensionCallback callback); static CONTROLLER_PATCHER_RESULT_OR_ERROR setWPADConnectCallback(int32_t chan, WPADConnectCallback callback); diff --git a/include/controller_patcher/ControllerPatcherDefs.h b/include/controller_patcher/ControllerPatcherDefs.h index d3eed1d..7472624 100644 --- a/include/controller_patcher/ControllerPatcherDefs.h +++ b/include/controller_patcher/ControllerPatcherDefs.h @@ -196,6 +196,29 @@ enum Controller_Patcher_Settings { CONTRPS_PAD4_FILTER, //! CONTRPS_PAD5_FILTER, //! CONTRPS_MOUSE_STICK, + + /* Additions for multi-byte stick encoding */ + CONTRPS_VPAD_BUTTON_L_STICK_X_BIT_LENGTH, //! 8 / 12 / 16bits, code defaults to 8 + CONTRPS_VPAD_BUTTON_L_STICK_Y_BIT_LENGTH, + CONTRPS_VPAD_BUTTON_R_STICK_X_BIT_LENGTH, + CONTRPS_VPAD_BUTTON_R_STICK_Y_BIT_LENGTH, + CONTRPS_VPAD_BUTTON_L_STICK_X_BIT_OFFSET, //! Data may not be byte-aligned + CONTRPS_VPAD_BUTTON_L_STICK_Y_BIT_OFFSET, + CONTRPS_VPAD_BUTTON_R_STICK_X_BIT_OFFSET, + CONTRPS_VPAD_BUTTON_R_STICK_Y_BIT_OFFSET, + CONTRPS_VPAD_BUTTON_L_STICK_X_MINMAX_MSB, //! MinMax most significant bytes for >8 bit length values + CONTRPS_VPAD_BUTTON_L_STICK_Y_MINMAX_MSB, + CONTRPS_VPAD_BUTTON_R_STICK_X_MINMAX_MSB, + CONTRPS_VPAD_BUTTON_R_STICK_Y_MINMAX_MSB, + CONTRPS_VPAD_BUTTON_L_STICK_X_DEFAULT_MSB, //! Stick default value most significant byte for >8 bit length values + CONTRPS_VPAD_BUTTON_L_STICK_Y_DEFAULT_MSB, + CONTRPS_VPAD_BUTTON_R_STICK_X_DEFAULT_MSB, + CONTRPS_VPAD_BUTTON_R_STICK_Y_DEFAULT_MSB, + CONTRPS_VPAD_BUTTON_L_STICK_X_SIGNED, //! Is the data signed (two's complement)? + CONTRPS_VPAD_BUTTON_L_STICK_Y_SIGNED, + CONTRPS_VPAD_BUTTON_R_STICK_X_SIGNED, + CONTRPS_VPAD_BUTTON_R_STICK_Y_SIGNED, + CONTRPS_MAX_VALUE }; /** diff --git a/source/ControllerPatcher.cpp b/source/ControllerPatcher.cpp index 9c10a50..eff92f6 100644 --- a/source/ControllerPatcher.cpp +++ b/source/ControllerPatcher.cpp @@ -1166,7 +1166,7 @@ CONTROLLER_PATCHER_RESULT_OR_ERROR ControllerPatcher::setKPADConnectedCallback(i return CONTROLLER_PATCHER_ERROR_NONE; } -CONTROLLER_PATCHER_RESULT_OR_ERROR ControllerPatcher::setKPADExtensionCallback(int32_t chan, WPADConnectCallback callback) { +CONTROLLER_PATCHER_RESULT_OR_ERROR ControllerPatcher::setKPADExtensionCallback(int32_t chan, WPADExtensionCallback callback) { if (chan >= 4) { return CONTROLLER_PATCHER_ERROR_INVALID_CHAN; } diff --git a/source/config/ConfigValues.hpp b/source/config/ConfigValues.hpp index 462f14b..86b8e75 100644 --- a/source/config/ConfigValues.hpp +++ b/source/config/ConfigValues.hpp @@ -259,6 +259,28 @@ class ConfigValues { CONTPRStringToValueSingle["VPAD_R_STICK_X_INVERT"] = CONTRPS_VPAD_BUTTON_R_STICK_X_INVERT; CONTPRStringToValueSingle["VPAD_R_STICK_Y_INVERT"] = CONTRPS_VPAD_BUTTON_R_STICK_Y_INVERT; + /* Additions for multi-byte stick encoding */ + CONTPRStringToValueSingle["VPAD_L_STICK_X_BIT_LENGTH"] = CONTRPS_VPAD_BUTTON_L_STICK_X_BIT_LENGTH; + CONTPRStringToValueSingle["VPAD_L_STICK_Y_BIT_LENGTH"] = CONTRPS_VPAD_BUTTON_L_STICK_Y_BIT_LENGTH; + CONTPRStringToValueSingle["VPAD_R_STICK_X_BIT_LENGTH"] = CONTRPS_VPAD_BUTTON_R_STICK_X_BIT_LENGTH; + CONTPRStringToValueSingle["VPAD_R_STICK_Y_BIT_LENGTH"] = CONTRPS_VPAD_BUTTON_R_STICK_Y_BIT_LENGTH; + CONTPRStringToValueSingle["VPAD_L_STICK_X_BIT_OFFSET"] = CONTRPS_VPAD_BUTTON_L_STICK_X_BIT_OFFSET; + CONTPRStringToValueSingle["VPAD_L_STICK_Y_BIT_OFFSET"] = CONTRPS_VPAD_BUTTON_L_STICK_Y_BIT_OFFSET; + CONTPRStringToValueSingle["VPAD_R_STICK_X_BIT_OFFSET"] = CONTRPS_VPAD_BUTTON_R_STICK_X_BIT_OFFSET; + CONTPRStringToValueSingle["VPAD_R_STICK_Y_BIT_OFFSET"] = CONTRPS_VPAD_BUTTON_R_STICK_Y_BIT_OFFSET; + CONTPRStringToValue["VPAD_L_STICK_X_MINMAX_MSB"] = CONTRPS_VPAD_BUTTON_L_STICK_X_MINMAX_MSB; + CONTPRStringToValue["VPAD_L_STICK_Y_MINMAX_MSB"] = CONTRPS_VPAD_BUTTON_L_STICK_Y_MINMAX_MSB; + CONTPRStringToValue["VPAD_R_STICK_X_MINMAX_MSB"] = CONTRPS_VPAD_BUTTON_R_STICK_X_MINMAX_MSB; + CONTPRStringToValue["VPAD_R_STICK_Y_MINMAX_MSB"] = CONTRPS_VPAD_BUTTON_R_STICK_Y_MINMAX_MSB; + CONTPRStringToValueSingle["VPAD_L_STICK_X_DEFAULT_MSB"] = CONTRPS_VPAD_BUTTON_L_STICK_X_DEFAULT_MSB; + CONTPRStringToValueSingle["VPAD_L_STICK_Y_DEFAULT_MSB"] = CONTRPS_VPAD_BUTTON_L_STICK_Y_DEFAULT_MSB; + CONTPRStringToValueSingle["VPAD_R_STICK_X_DEFAULT_MSB"] = CONTRPS_VPAD_BUTTON_R_STICK_X_DEFAULT_MSB; + CONTPRStringToValueSingle["VPAD_R_STICK_Y_DEFAULT_MSB"] = CONTRPS_VPAD_BUTTON_R_STICK_Y_DEFAULT_MSB; + CONTPRStringToValueSingle["VPAD_L_STICK_X_SIGNED"] = CONTRPS_VPAD_BUTTON_L_STICK_X_SIGNED; + CONTPRStringToValueSingle["VPAD_L_STICK_Y_SIGNED"] = CONTRPS_VPAD_BUTTON_L_STICK_Y_SIGNED; + CONTPRStringToValueSingle["VPAD_R_STICK_X_SIGNED"] = CONTRPS_VPAD_BUTTON_R_STICK_X_SIGNED; + CONTPRStringToValueSingle["VPAD_R_STICK_Y_SIGNED"] = CONTRPS_VPAD_BUTTON_R_STICK_Y_SIGNED; + CONTPRStringToValueSingle["DOUBLE_USE"] = CONTRPS_DOUBLE_USE; CONTPRStringToValueSingle["PAD_COUNT"] = CONTRPS_PAD_COUNT; diff --git a/source/patcher/ControllerPatcherUtils.cpp b/source/patcher/ControllerPatcherUtils.cpp index bf081f8..018f82a 100644 --- a/source/patcher/ControllerPatcherUtils.cpp +++ b/source/patcher/ControllerPatcherUtils.cpp @@ -362,6 +362,17 @@ CONTROLLER_PATCHER_RESULT_OR_ERROR ControllerPatcherUtils::getActivePad(uint32_t * Stick functions *---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +int16_t ControllerPatcherUtils::signExtendValue(uint16_t input, uint8_t bit_length) { + // Check if the input is negative in its original bit length + if (input & (1 << (bit_length - 1))) { + // Sign-extend the value + return (int16_t)(input | (~((1 << bit_length) - 1))); + } else { + // Input is non-negative; return it directly with proper casting + return (int16_t)input; + } +} + CONTROLLER_PATCHER_RESULT_OR_ERROR ControllerPatcherUtils::normalizeStickValues(VPADVec2D *stick) { if (stick == NULL) return CONTROLLER_PATCHER_ERROR_NULL_POINTER; @@ -390,30 +401,24 @@ CONTROLLER_PATCHER_RESULT_OR_ERROR ControllerPatcherUtils::normalizeStickValues( return CONTROLLER_PATCHER_ERROR_NONE; } -float ControllerPatcherUtils::convertAnalogValue(uint8_t value, uint8_t default_val, uint8_t min, uint8_t max, uint8_t invert, uint8_t deadzone) { - int8_t new_value = (int8_t) (value - default_val); - uint8_t range = 0; - if (value >= max) { - if (invert == 0x01) return -1.0f; - return 1.0f; - } else if (value <= min) { - if (invert == 0x01) return 1.0f; - return -1.0f; - } - if ((value - deadzone) > default_val) { - new_value -= deadzone; - range = (max - (default_val + deadzone)); - } else if ((value + deadzone) < default_val) { - new_value += deadzone; - range = ((default_val - deadzone) - min); - } else { - return 0.0f; - } - if (invert != 0x01) { - return (new_value / (1.0f * range)); +float ControllerPatcherUtils::convertAnalogValue(int32_t value, int32_t default_val, int32_t min, int32_t max, uint8_t invert, uint8_t deadzone){ + if(value >= max) return invert == 0x01 ? -1.0f : 1.0f; + if(value <= min) return invert == 0x01 ? 1.0f : -1.0f; + + int32_t range = 0; + int32_t adjustedValue = value - default_val; + + if(std::abs(adjustedValue) <= (int32_t)deadzone) return 0.0f; + + if(adjustedValue > 0) { + range = max - (default_val + deadzone); + adjustedValue -= deadzone; } else { - return -1.0f * (new_value / (1.0f * range)); + range = (default_val - deadzone) - min; + adjustedValue += deadzone; } + float normalizedValue = (float)adjustedValue / range; + return invert == 0x01 ? -normalizedValue : normalizedValue; } VPADVec2D ControllerPatcherUtils::getAnalogValueByButtons(uint8_t stick_values) { @@ -486,61 +491,33 @@ CONTROLLER_PATCHER_RESULT_OR_ERROR ControllerPatcherUtils::convertAnalogSticks(H uint8_t *cur_data = &data->data_union.controller.cur_hid_data[0]; if (cur_data == NULL) return CONTROLLER_PATCHER_ERROR_NULL_POINTER; - int32_t deadzone = 0; - - if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X][0] != CONTROLLER_PATCHER_INVALIDVALUE) { - if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_DEADZONE][0] == CONTROLLER_PATCHER_VALUE_SET) { - deadzone = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_DEADZONE][1]; - } - - buffer->leftStick.x += convertAnalogValue(cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X][0]], - config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X][1], - config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_MINMAX][0], - config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_MINMAX][1], - config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_INVERT][1], - deadzone); - } - - if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y][0] != CONTROLLER_PATCHER_INVALIDVALUE) { - deadzone = 0; - if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_DEADZONE][0] == CONTROLLER_PATCHER_VALUE_SET) { - deadzone = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_DEADZONE][1]; - } - buffer->leftStick.y += convertAnalogValue(cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y][0]], - config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y][1], - config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_MINMAX][0], - config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_MINMAX][1], - config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_INVERT][1], - deadzone); - } - - if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X][0] != CONTROLLER_PATCHER_INVALIDVALUE) { - deadzone = 0; - if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_DEADZONE][0] == CONTROLLER_PATCHER_VALUE_SET) { - deadzone = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_DEADZONE][1]; - } - - buffer->rightStick.x += convertAnalogValue(cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X][0]], - config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X][1], - config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_MINMAX][0], - config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_MINMAX][1], - config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_INVERT][1], - deadzone); - } - - if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y][0] != CONTROLLER_PATCHER_INVALIDVALUE) { - deadzone = 0; - if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_DEADZONE][0] == CONTROLLER_PATCHER_VALUE_SET) { - deadzone = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_DEADZONE][1]; - } - - buffer->rightStick.y += convertAnalogValue(cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y][0]], - config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y][1], - config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_MINMAX][0], - config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_MINMAX][1], - config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_INVERT][1], - deadzone); - } + processStickAxis(buffer->leftStick.x, cur_data, deviceslot, + CONTRPS_VPAD_BUTTON_L_STICK_X, CONTRPS_VPAD_BUTTON_L_STICK_X_DEADZONE, + CONTRPS_VPAD_BUTTON_L_STICK_X_MINMAX, CONTRPS_VPAD_BUTTON_L_STICK_X_BIT_LENGTH, + CONTRPS_VPAD_BUTTON_L_STICK_X_BIT_OFFSET, CONTRPS_VPAD_BUTTON_L_STICK_X_MINMAX_MSB, + CONTRPS_VPAD_BUTTON_L_STICK_X_DEFAULT_MSB, CONTRPS_VPAD_BUTTON_L_STICK_X_SIGNED, + CONTRPS_VPAD_BUTTON_L_STICK_X_INVERT); + + processStickAxis(buffer->leftStick.y, cur_data, deviceslot, + CONTRPS_VPAD_BUTTON_L_STICK_Y, CONTRPS_VPAD_BUTTON_L_STICK_Y_DEADZONE, + CONTRPS_VPAD_BUTTON_L_STICK_Y_MINMAX, CONTRPS_VPAD_BUTTON_L_STICK_Y_BIT_LENGTH, + CONTRPS_VPAD_BUTTON_L_STICK_Y_BIT_OFFSET, CONTRPS_VPAD_BUTTON_L_STICK_Y_MINMAX_MSB, + CONTRPS_VPAD_BUTTON_L_STICK_Y_DEFAULT_MSB, CONTRPS_VPAD_BUTTON_L_STICK_Y_SIGNED, + CONTRPS_VPAD_BUTTON_L_STICK_Y_INVERT); + + processStickAxis(buffer->rightStick.x, cur_data, deviceslot, + CONTRPS_VPAD_BUTTON_R_STICK_X, CONTRPS_VPAD_BUTTON_R_STICK_X_DEADZONE, + CONTRPS_VPAD_BUTTON_R_STICK_X_MINMAX, CONTRPS_VPAD_BUTTON_R_STICK_X_BIT_LENGTH, + CONTRPS_VPAD_BUTTON_R_STICK_X_BIT_OFFSET, CONTRPS_VPAD_BUTTON_R_STICK_X_MINMAX_MSB, + CONTRPS_VPAD_BUTTON_R_STICK_X_DEFAULT_MSB, CONTRPS_VPAD_BUTTON_R_STICK_X_SIGNED, + CONTRPS_VPAD_BUTTON_R_STICK_X_INVERT); + + processStickAxis(buffer->rightStick.y, cur_data, deviceslot, + CONTRPS_VPAD_BUTTON_R_STICK_Y, CONTRPS_VPAD_BUTTON_R_STICK_Y_DEADZONE, + CONTRPS_VPAD_BUTTON_R_STICK_Y_MINMAX, CONTRPS_VPAD_BUTTON_R_STICK_Y_BIT_LENGTH, + CONTRPS_VPAD_BUTTON_R_STICK_Y_BIT_OFFSET, CONTRPS_VPAD_BUTTON_R_STICK_Y_MINMAX_MSB, + CONTRPS_VPAD_BUTTON_R_STICK_Y_DEFAULT_MSB, CONTRPS_VPAD_BUTTON_R_STICK_Y_SIGNED, + CONTRPS_VPAD_BUTTON_R_STICK_Y_INVERT); uint8_t stick_values = 0; @@ -631,15 +608,68 @@ CONTROLLER_PATCHER_RESULT_OR_ERROR ControllerPatcherUtils::convertAnalogSticks(H } } } + } + return CONTROLLER_PATCHER_ERROR_NONE; +} + +CONTROLLER_PATCHER_RESULT_OR_ERROR ControllerPatcherUtils::processStickAxis( + float &buffer_axis, const uint8_t *cur_data, int32_t deviceslot, + uint8_t axis_code, uint8_t axis_deadzone_code, + uint8_t axis_minmax_code, uint8_t axis_bit_length_code, + uint8_t axis_bit_offset_code, uint8_t axis_minmax_msb_code, + uint8_t axis_default_msb_code, uint8_t axis_signed_code, + uint8_t axis_invert_code) { + + if (cur_data == NULL) return CONTROLLER_PATCHER_ERROR_NULL_POINTER; + + if (config_controller[deviceslot][axis_code][0] != CONTROLLER_PATCHER_INVALIDVALUE) { + uint8_t deadzone = (config_controller[deviceslot][axis_deadzone_code][0] == CONTROLLER_PATCHER_VALUE_SET) + ? config_controller[deviceslot][axis_deadzone_code][1] + : 0; + + // Read 1st byte of axis HID data & Min/Max/Default values + uint16_t axis_input = cur_data[config_controller[deviceslot][axis_code][0]]; + uint16_t axis_min = config_controller[deviceslot][axis_minmax_code][0]; + uint16_t axis_max = config_controller[deviceslot][axis_minmax_code][1]; + uint16_t axis_default = config_controller[deviceslot][axis_code][1]; + + // Axis report larger than 8 bits? + if (config_controller[deviceslot][axis_bit_length_code][0] == CONTROLLER_PATCHER_VALUE_SET && + config_controller[deviceslot][axis_bit_length_code][1] > 8) { + + // Read 2nd byte of axis HID data + axis_input |= (cur_data[config_controller[deviceslot][axis_code][0] + 1] << 8); + + if (config_controller[deviceslot][axis_bit_offset_code][0] == CONTROLLER_PATCHER_VALUE_SET) { + // Shift right to trim unwanted leading bits + axis_input >>= config_controller[deviceslot][axis_bit_offset_code][1]; + } + + // Mask off unwanted trailing bits + axis_input &= ((1 << config_controller[deviceslot][axis_bit_length_code][1]) - 1); + + // Combine most significant bytes of Min/Max/Default values + axis_min |= (config_controller[deviceslot][axis_minmax_msb_code][0] << 8); + axis_max |= (config_controller[deviceslot][axis_minmax_msb_code][1] << 8); + if (config_controller[deviceslot][axis_default_msb_code][0] == CONTROLLER_PATCHER_VALUE_SET) { + axis_default |= (config_controller[deviceslot][axis_default_msb_code][1] << 8); + } + } - /*log_printf("LX %f(%02X) LY %f(%02X) RX %f(%02X) RY %f(%02X)",buffer->leftStick.x,cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X][0]], - buffer->leftStick.y,cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y][0]], - buffer->rightStick.x,cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X][0]], - buffer->rightStick.y,cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y][0]]);*/ + if (config_controller[deviceslot][axis_signed_code][1]) { + // Extend sign bits if axis HID data is signed + int16_t signed_input = signExtendValue(axis_input, config_controller[deviceslot][axis_bit_length_code][1]); + buffer_axis += convertAnalogValue(signed_input, (int16_t)axis_default, (int16_t)axis_min, (int16_t)axis_max, + config_controller[deviceslot][axis_invert_code][1], deadzone); + } else { + buffer_axis += convertAnalogValue(axis_input, axis_default, axis_min, axis_max, + config_controller[deviceslot][axis_invert_code][1], deadzone); + } } return CONTROLLER_PATCHER_ERROR_NONE; } + CONTROLLER_PATCHER_RESULT_OR_ERROR ControllerPatcherUtils::setEmulatedSticks(VPADStatus *buffer, uint32_t *last_emulatedSticks) { if (buffer == NULL || last_emulatedSticks == NULL) return CONTROLLER_PATCHER_ERROR_NULL_POINTER; diff --git a/source/patcher/ControllerPatcherUtils.hpp b/source/patcher/ControllerPatcherUtils.hpp index 8710167..90b2be7 100644 --- a/source/patcher/ControllerPatcherUtils.hpp +++ b/source/patcher/ControllerPatcherUtils.hpp @@ -167,6 +167,40 @@ class ControllerPatcherUtils { /*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * Stick functions *---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ + /** + \brief Process HID report data for a stick axis. + + \param buffer_axis Reference to axis buffer + \param cur_data Pointer to the device HID data + \param deviceslot Device slot + \param axis_code CONTRPS_VPAD_BUTTON_*_STICK_* start byte in HID data of axis report, default value + \param axis_deadzone_code CONTRPS_VPAD_BUTTON_*_STICK_*_DEADZONE axis deadzone + \param axis_minmax_code CONTRPS_VPAD_BUTTON_*_STICK_*_MINMAX least significant bytes for axis min, axis max + \param axis_bit_length_code CONTRPS_VPAD_BUTTON_*_STICK_*_BIT_LENGTH 8 to 16 bits supported + \param axis_bit_offset_code CONTRPS_VPAD_BUTTON_*_STICK_*_BIT_OFFSET not all HID data is byte-aligned (Adaptoid uses 2 x 12bit axes) + \param axis_minmax_msb_code CONTRPS_VPAD_BUTTON_*_STICK_*_MINMAX_MSB most significant bytes for axis min, axis max + \param axis_default_msb_code CONTRPS_VPAD_BUTTON_*_STICK_*_DEFAULT_MSB most significant byte for axis default value + \param axis_signed_code CONTRPS_VPAD_BUTTON_*_STICK_*_SIGNED is axis report a signed value? + \param axis_invert_code CONTRPS_VPAD_BUTTON_*_STICK_*_INVERT invert axis? + + \return When the functions failed result < 0 is returned. If the result is >= 0 the function was successful. + **/ + static CONTROLLER_PATCHER_RESULT_OR_ERROR processStickAxis(float &buffer_axis, const uint8_t *cur_data, int32_t deviceslot, + uint8_t axis_code, uint8_t axis_deadzone_code, uint8_t axis_minmax_code, + uint8_t axis_bit_length_code, uint8_t axis_bit_offset_code, + uint8_t axis_minmax_msb_code, uint8_t axis_default_msb_code, + uint8_t axis_signed_code, uint8_t axis_invert_code); + + /** + \brief Sign-extend negative numbers of lower bit lengths into int16_t type + + \param input Input value (from HID data) + \param bit_length Bit length of this input number + + \return The number in int16_t type + **/ + static int16_t signExtendValue(uint16_t input, uint8_t bit_length); + /** \brief Normalizes the stick to valid values. @@ -188,8 +222,7 @@ class ControllerPatcherUtils { \return When the functions failed result < 0 is returned. If the result is >= 0 the function was successful. **/ - static float convertAnalogValue(uint8_t value, uint8_t default_val, uint8_t min, uint8_t max, uint8_t invert, uint8_t deadzone); - + static float convertAnalogValue(int32_t value, int32_t default_val, int32_t min, int32_t max, uint8_t invert,uint8_t deadzone); /** \brief Calculates a the stick data (VPADVec2D) from given digital direction.