From 66bb72df627f192da99b82f4f467aae55c9ce179 Mon Sep 17 00:00:00 2001 From: patters-match <55089098+patters-match@users.noreply.github.com> Date: Thu, 22 Feb 2024 14:15:43 +0000 Subject: [PATCH] Add support for up to 16bit and signed axis values --- Adaptoid_N64.ini | 46 ++++ source/ControllerPatcher.cpp | 1 + source/ControllerPatcher.hpp | 4 +- source/ControllerPatcherDefs.h | 23 ++ source/config/ConfigValues.hpp | 22 ++ source/patcher/ControllerPatcherUtils.cpp | 307 +++++++++++++++++----- source/patcher/ControllerPatcherUtils.hpp | 13 +- 7 files changed, 354 insertions(+), 62 deletions(-) create mode 100644 Adaptoid_N64.ini 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/source/ControllerPatcher.cpp b/source/ControllerPatcher.cpp index de54c7d..22c6f95 100644 --- a/source/ControllerPatcher.cpp +++ b/source/ControllerPatcher.cpp @@ -476,6 +476,7 @@ bool ControllerPatcher::Init(const char * pathToConfig){ InitSysHIDFunctionPointers(); InitVPadFunctionPointers(); InitPadScoreFunctionPointers(); + // log_init_(); gSamplingCallback = (wpad_sampling_callback_t)((u32)KPADRead + 0x1F0); if(*(u32*)gSamplingCallback != FIRST_INSTRUCTION_IN_SAMPLING_CALLBACK){ diff --git a/source/ControllerPatcher.hpp b/source/ControllerPatcher.hpp index d3b2f11..9fd8c7d 100644 --- a/source/ControllerPatcher.hpp +++ b/source/ControllerPatcher.hpp @@ -109,7 +109,7 @@ class ControllerPatcher{ static CONTROLLER_PATCHER_RESULT_OR_ERROR enableControllerMapping(); /** - 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(); @@ -171,7 +171,7 @@ class ControllerPatcher{ static bool isControllerConnectedAndActive(UController_Type type,s32 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(); diff --git a/source/ControllerPatcherDefs.h b/source/ControllerPatcherDefs.h index 7b6434b..0c348a2 100644 --- a/source/ControllerPatcherDefs.h +++ b/source/ControllerPatcherDefs.h @@ -199,6 +199,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/config/ConfigValues.hpp b/source/config/ConfigValues.hpp index bdacafc..a72ea26 100644 --- a/source/config/ConfigValues.hpp +++ b/source/config/ConfigValues.hpp @@ -267,6 +267,28 @@ private: 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 e898ca8..3b5dc3d 100644 --- a/source/patcher/ControllerPatcherUtils.cpp +++ b/source/patcher/ControllerPatcherUtils.cpp @@ -324,6 +324,17 @@ CONTROLLER_PATCHER_RESULT_OR_ERROR ControllerPatcherUtils::getActivePad(u32 hidm * Stick functions *---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +s16 ControllerPatcherUtils::signExtendValue(u16 input, u8 bit_length) { + // Check if the input is negative in its original bit length + if (input & (1 << (bit_length - 1))) { + // Sign-extend the value + return (s16)(input | (~((1 << bit_length) - 1))); + } else { + // Input is non-negative; return it directly with proper casting + return (s16)input; + } +} + CONTROLLER_PATCHER_RESULT_OR_ERROR ControllerPatcherUtils::normalizeStickValues(Vec2D * stick){ if(stick == NULL) return CONTROLLER_PATCHER_ERROR_NULL_POINTER; @@ -344,30 +355,24 @@ CONTROLLER_PATCHER_RESULT_OR_ERROR ControllerPatcherUtils::normalizeStickValues( return CONTROLLER_PATCHER_ERROR_NONE; } -f32 ControllerPatcherUtils::convertAnalogValue(u8 value, u8 default_val, u8 min, u8 max, u8 invert,u8 deadzone){ - s8 new_value = (s8)(value - default_val); - u8 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)); - }else{ - return -1.0f*(new_value / (1.0f*range)); +f32 ControllerPatcherUtils::convertAnalogValue(s32 value, s32 default_val, s32 min, s32 max, u8 invert, u8 deadzone){ + if(value >= max) return invert == 0x01 ? -1.0f : 1.0f; + if(value <= min) return invert == 0x01 ? 1.0f : -1.0f; + + s32 range = 0; + s32 adjustedValue = value - default_val; + + if(std::abs(adjustedValue) <= (s32)deadzone) return 0.0f; + + if(adjustedValue > 0) { + range = max - (default_val + deadzone); + adjustedValue -= deadzone; + } else { + range = (default_val - deadzone) - min; + adjustedValue += deadzone; } + f32 normalizedValue = (f32)adjustedValue / range; + return invert == 0x01 ? -normalizedValue : normalizedValue; } Vec2D ControllerPatcherUtils::getAnalogValueByButtons(u8 stick_values){ @@ -441,59 +446,216 @@ CONTROLLER_PATCHER_RESULT_OR_ERROR ControllerPatcherUtils::convertAnalogSticks(H if(cur_data == NULL) return CONTROLLER_PATCHER_ERROR_NULL_POINTER; s32 deadzone = 0; + u16 l_stick_x_axis_input = 0; + u16 l_stick_y_axis_input = 0; + u16 r_stick_x_axis_input = 0; + u16 r_stick_y_axis_input = 0; + s16 l_stick_x_axis_signed = 0; + s16 l_stick_y_axis_signed = 0; + s16 r_stick_x_axis_signed = 0; + s16 r_stick_y_axis_signed = 0; - if( config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X][0] != CONTROLLER_PATCHER_INVALIDVALUE){ + u16 l_stick_x_axis_min = 0; + u16 l_stick_x_axis_max = 0; + u16 l_stick_x_axis_def = 0; + u16 l_stick_y_axis_min = 0; + u16 l_stick_y_axis_max = 0; + u16 l_stick_y_axis_def = 0; + u16 r_stick_x_axis_min = 0; + u16 r_stick_x_axis_max = 0; + u16 r_stick_x_axis_def = 0; + u16 r_stick_y_axis_min = 0; + u16 r_stick_y_axis_max = 0; + u16 r_stick_y_axis_def = 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]; + deadzone = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_DEADZONE][1]; + } + // Read 1st byte of axis HID data & Min/Max/Default values + l_stick_x_axis_input = cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X][0]]; + l_stick_x_axis_min = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_MINMAX][0]; + l_stick_x_axis_max = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_MINMAX][1]; + l_stick_x_axis_def = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X][1]; + + if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_BIT_LENGTH][0] == CONTROLLER_PATCHER_VALUE_SET && config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_BIT_LENGTH][1] > 8){ + // Need more than 8 bits, read 2nd byte of axis HID data + l_stick_x_axis_input |= (cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X][0] + 1] << 8); + + if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_BIT_OFFSET][0] == CONTROLLER_PATCHER_VALUE_SET){ + // Shift right to trim unwanted leading bits + l_stick_x_axis_input >>= config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_BIT_OFFSET][1]; + } + // Mask off unwanted trailing bits + l_stick_x_axis_input &= ((1 << config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_BIT_LENGTH][1]) - 1); + + // Combine most significant bytes of Min/Max/Default values + l_stick_x_axis_min |= (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_MINMAX_MSB][0] << 8); + l_stick_x_axis_max |= (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_MINMAX_MSB][1] << 8); + if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_DEFAULT_MSB][0] == CONTROLLER_PATCHER_VALUE_SET){ + l_stick_x_axis_def |= (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_DEFAULT_MSB][1] << 8); + } } - buffer->lstick.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_X_SIGNED][1]) { + // Extend sign bits if axis HID data is signed + l_stick_x_axis_signed = signExtendValue(l_stick_x_axis_input, config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_BIT_LENGTH][1]); + + buffer->lstick.x += convertAnalogValue(l_stick_x_axis_signed, + (s16)l_stick_x_axis_def, + (s16)l_stick_x_axis_min, + (s16)l_stick_x_axis_max, + config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_INVERT][1], + deadzone); + } else { + buffer->lstick.x += convertAnalogValue(l_stick_x_axis_input, + l_stick_x_axis_def, + l_stick_x_axis_min, + l_stick_x_axis_max, + 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){ + 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]; + deadzone = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_DEADZONE][1]; + } + // Read 1st byte of axis HID data & Min/Max/Default values + l_stick_y_axis_input = cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y][0]]; + l_stick_y_axis_min = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_MINMAX][0]; + l_stick_y_axis_max = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_MINMAX][1]; + l_stick_y_axis_def = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y][1]; + + if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_BIT_LENGTH][0] == CONTROLLER_PATCHER_VALUE_SET && config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_BIT_LENGTH][1] > 8){ + // Need more than 8 bits, read 2nd byte of axis HID data + l_stick_y_axis_input |= (cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y][0] + 1] << 8); + if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_BIT_OFFSET][0] == CONTROLLER_PATCHER_VALUE_SET){ + // Shift right to trim unwanted leading bits + l_stick_y_axis_input >>= config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_BIT_OFFSET][1]; + } + // Mask off unwanted trailing bits + l_stick_y_axis_input &= ((1 << config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_BIT_LENGTH][1]) - 1); + + // Combine most significant bytes of Min/Max/Default values + l_stick_y_axis_min |= (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_MINMAX_MSB][0] << 8); + l_stick_y_axis_max |= (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_MINMAX_MSB][1] << 8); + if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_DEFAULT_MSB][0] == CONTROLLER_PATCHER_VALUE_SET){ + l_stick_y_axis_def |= (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_DEFAULT_MSB][1] << 8); + } + } + if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_SIGNED][1]) { + // Extend sign bits if axis HID data is signed + l_stick_y_axis_signed = signExtendValue(l_stick_y_axis_input, config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_BIT_LENGTH][1]); + buffer->lstick.y += convertAnalogValue(l_stick_y_axis_signed, + (s16)l_stick_y_axis_def, + (s16)l_stick_y_axis_min, + (s16)l_stick_y_axis_max, + config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_INVERT][1], + deadzone); + } else { + buffer->lstick.y += convertAnalogValue(l_stick_y_axis_input, + l_stick_y_axis_def, + l_stick_y_axis_min, + l_stick_y_axis_max, + config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y_INVERT][1], + deadzone); } - buffer->lstick.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){ + 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]; + deadzone = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_DEADZONE][1]; } + // Read 1st byte of axis HID data & Min/Max/Default values + r_stick_x_axis_input = cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X][0]]; + r_stick_x_axis_min = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_MINMAX][0]; + r_stick_x_axis_max = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_MINMAX][1]; + r_stick_x_axis_def = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X][1]; + + if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_BIT_LENGTH][0] == CONTROLLER_PATCHER_VALUE_SET && config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_BIT_LENGTH][1] > 8){ + // Need more than 8 bits, read 2nd byte of axis HID data + r_stick_x_axis_input |= (cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X][0] + 1] << 8); + if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_BIT_OFFSET][0] == CONTROLLER_PATCHER_VALUE_SET){ + // Shift right to trim unwanted leading bits + r_stick_x_axis_input >>= config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_BIT_OFFSET][1]; + } + // Mask off unwanted trailing bits + r_stick_x_axis_input &= ((1 << config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_BIT_LENGTH][1]) - 1); - buffer->rstick.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); + // Combine most significant bytes of Min/Max/Default values + r_stick_x_axis_min |= (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_MINMAX_MSB][0] << 8); + r_stick_x_axis_max |= (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_MINMAX_MSB][1] << 8); + if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_DEFAULT_MSB][0] == CONTROLLER_PATCHER_VALUE_SET){ + r_stick_x_axis_def |= (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_DEFAULT_MSB][1] << 8); + } + } + if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_SIGNED][1]) { + // Extend sign bits if axis HID data is signed + r_stick_x_axis_signed = signExtendValue(r_stick_x_axis_input, config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_BIT_LENGTH][1]); + buffer->rstick.x += convertAnalogValue(r_stick_x_axis_signed, + (s16)r_stick_x_axis_def, + (s16)r_stick_x_axis_min, + (s16)r_stick_x_axis_max, + config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X_INVERT][1], + deadzone); + } else { + buffer->rstick.x += convertAnalogValue(r_stick_x_axis_input, + r_stick_x_axis_def, + r_stick_x_axis_min, + r_stick_x_axis_max, + 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){ + 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]; + deadzone = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_DEADZONE][1]; } + // Read 1st byte of axis HID data & Min/Max/Default values + r_stick_y_axis_input = cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y][0]]; + r_stick_y_axis_min = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_MINMAX][0]; + r_stick_y_axis_max = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_MINMAX][1]; + r_stick_y_axis_def = config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y][1]; + + if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_BIT_LENGTH][0] == CONTROLLER_PATCHER_VALUE_SET && config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_BIT_LENGTH][1] > 8){ + // Need more than 8 bits, read 2nd byte of axis HID data + r_stick_y_axis_input |= (cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y][0] + 1] << 8); + if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_BIT_OFFSET][0] == CONTROLLER_PATCHER_VALUE_SET){ + // Shift right to trim unwanted leading bits + r_stick_y_axis_input >>= config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_BIT_OFFSET][1]; + } + // Mask off unwanted trailing bits + r_stick_y_axis_input &= ((1 << config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_BIT_LENGTH][1]) - 1); - buffer->rstick.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); + // Combine most significant bytes of Min/Max/Default values + r_stick_y_axis_min |= (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_MINMAX_MSB][0] << 8); + r_stick_y_axis_max |= (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_MINMAX_MSB][1] << 8); + if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_DEFAULT_MSB][0] == CONTROLLER_PATCHER_VALUE_SET){ + r_stick_y_axis_def |= (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_DEFAULT_MSB][1] << 8); + } + } + if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_SIGNED][1]) { + // Extend sign bits if axis HID data is signed + r_stick_y_axis_signed = signExtendValue(r_stick_y_axis_input, config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_BIT_LENGTH][1]); + buffer->rstick.y += convertAnalogValue(r_stick_y_axis_signed, + (s16)r_stick_y_axis_def, + (s16)r_stick_y_axis_min, + (s16)r_stick_y_axis_max, + config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_INVERT][1], + deadzone); + } else { + buffer->rstick.y += convertAnalogValue(r_stick_y_axis_input, + r_stick_y_axis_def, + r_stick_y_axis_min, + r_stick_y_axis_max, + config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y_INVERT][1], + deadzone); + } } u8 stick_values = 0; @@ -554,10 +716,37 @@ CONTROLLER_PATCHER_RESULT_OR_ERROR ControllerPatcherUtils::convertAnalogSticks(H } } - /*log_printf("LX %f(%02X) LY %f(%02X) RX %f(%02X) RY %f(%02X)\n",buffer->lstick.x,cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X][0]], - buffer->lstick.y,cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_Y][0]], - buffer->rstick.x,cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_X][0]], - buffer->rstick.y,cur_data[config_controller[deviceslot][CONTRPS_VPAD_BUTTON_R_STICK_Y][0]]);*/ + // if (config_controller[deviceslot][CONTRPS_VPAD_BUTTON_L_STICK_X_SIGNED][1]) { + // s16 temp_l_stick_x_axis_min = (s16)l_stick_x_axis_min; + // s16 temp_l_stick_y_axis_min = (s16)l_stick_y_axis_min; + // s16 temp_l_stick_x_axis_def = (s16)l_stick_x_axis_def; + // s16 temp_l_stick_y_axis_def = (s16)l_stick_y_axis_def; + // s16 temp_l_stick_x_axis_max = (s16)l_stick_x_axis_max; + // s16 temp_l_stick_y_axis_max = (s16)l_stick_y_axis_max; + // log_printf( + // "MinX %+5d %04X DefX %+5d MaxX %+5d %04X MinY %+5d %04X DefY %+5d MaxY %+5d %04X X %+1.3f(%+5d %04X) Y %+1.3f(%+5d %04X)\n", + // temp_l_stick_x_axis_min,l_stick_x_axis_min, + // temp_l_stick_x_axis_def, + // temp_l_stick_x_axis_max,l_stick_x_axis_max, + // temp_l_stick_y_axis_min,l_stick_y_axis_min, + // temp_l_stick_y_axis_def, + // temp_l_stick_y_axis_max,l_stick_y_axis_max, + // buffer->lstick.x,l_stick_x_axis_signed,l_stick_x_axis_signed, + // buffer->lstick.y,l_stick_y_axis_signed,l_stick_y_axis_signed + // ); + // } else { + // log_printf( + // "MinX %+5d %04X DefX %+5d MaxX %+5d %04X MinY %+5d %04X DefY %+5d MaxY %+5d %04X X %+1.3f(%+5d %04X) Y %+1.3f(%+5d %04X)\n", + // l_stick_x_axis_min,l_stick_x_axis_min, + // l_stick_x_axis_def, + // l_stick_x_axis_max,l_stick_x_axis_max, + // l_stick_y_axis_min,l_stick_y_axis_min, + // l_stick_y_axis_def, + // l_stick_y_axis_max,l_stick_y_axis_max, + // buffer->lstick.x,l_stick_x_axis_input,l_stick_x_axis_input, + // buffer->lstick.y,l_stick_y_axis_input,l_stick_y_axis_input + // ); + // } } return CONTROLLER_PATCHER_ERROR_NONE; diff --git a/source/patcher/ControllerPatcherUtils.hpp b/source/patcher/ControllerPatcherUtils.hpp index eac3e26..f04af6c 100644 --- a/source/patcher/ControllerPatcherUtils.hpp +++ b/source/patcher/ControllerPatcherUtils.hpp @@ -166,6 +166,17 @@ class ControllerPatcherUtils{ /*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * Stick functions *---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ + + /** + \brief Sign-extend negative numbers of lower bit lengths into s16 type + + \param input Input value (from HID data) + \param bit_length Bit length of this input number + + \return The number in s16 type + **/ + static s16 signExtendValue(u16 input, u8 bit_length); + /** \brief Normalizes the stick to valid values. @@ -187,7 +198,7 @@ class ControllerPatcherUtils{ \return When the functions failed result < 0 is returned. If the result is >= 0 the function was successful. **/ - static f32 convertAnalogValue(u8 value, u8 default_val, u8 min, u8 max, u8 invert,u8 deadzone); + static f32 convertAnalogValue(s32 value, s32 default_val, s32 min, s32 max, u8 invert,u8 deadzone); /** \brief Calculates a the stick data (Vec2D) from given digital direction.