From 089473661ec86a2e69be0a8da8c75569a10ec265 Mon Sep 17 00:00:00 2001 From: Electronicks Date: Wed, 20 Sep 2023 13:34:37 -0600 Subject: [PATCH] Bugfixes for 3.5.1 --- CHANGELOG.md | 16 ++++++ JoyShockMapper/src/DigitalButton.cpp | 26 ++-------- JoyShockMapper/src/Mapping.cpp | 6 ++- JoyShockMapper/src/SDL2Wrapper.cpp | 6 +-- JoyShockMapper/src/SettingsManager.cpp | 4 +- JoyShockMapper/src/main.cpp | 42 +++++++++------- JoyShockMapper/src/win32/Gamepad.cpp | 67 ++++++++++++++++++++++---- 7 files changed, 113 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 292a5a5..f679439 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,22 @@ This is a summary of new features and bugfixes. Read the README to learn how to ## Known issues * SDL always merges joycons behind the scene into a single controller. JSM is not able to split them. Use legacy-JSL version to use this feature. +## 3.5.1 + +Nick fixes everything he broke with his "improvements" + +### Bugfixes +* Restore digital binding of virtual gamepad trigggers X_LT, X_RT, PS_L2 AND PS_R2. +* Fix turbo binding of virtual controller buttons. Use Toggle as well for 50-50 press time instead of 40ms. +* Fix Dualsense Edge new button bindings (left buttons were inverted: LSL and RSR are grips) +* Add VIRTUAL_CONTROLLER and HIDE_MINIMIZED as settings exempted from resetting on RESET_BINDINGS +* Restore scroll stick mode +* Fix Ds4 virtual controller connect with UP stuck +* Fix Ds4 virtual controller touch adding a second ghost touch at 0,0 +* Fix Ds4 virtual controller HOME and CAPTURE buttons +* Robustness fix at cleanup +* Fix Armor X Pro PS mode's M2 button + ## 3.5.0 Nick updates C++ standard to C++20, Add Setting Manager, Create Stick and Autoload objects, Update ViGEm, SDL2 and JSL dependencies to latest, diff --git a/JoyShockMapper/src/DigitalButton.cpp b/JoyShockMapper/src/DigitalButton.cpp index a1ebd67..8cbc1fe 100644 --- a/JoyShockMapper/src/DigitalButton.cpp +++ b/JoyShockMapper/src/DigitalButton.cpp @@ -172,21 +172,12 @@ struct DigitalButtonImpl : public pocket_fsm::PimplBase, public EventActionIf void ApplyBtnPress(KeyCode key) override { - if (key.code >= X_UP && key.code <= X_START || key.code == PS_HOME || key.code == PS_PAD_CLICK) + if (key.code >= X_UP && key.code <= X_START || key.code == PS_HOME || + key.code == PS_PAD_CLICK || key.code == X_LT || key.code == X_RT) { if (_context->_vigemController) _context->_vigemController->setButton(key, true); } - else if (key.code == X_LT) - { - if (_context->_vigemController) - _context->_vigemController->setLeftTrigger(1.f); - } - else if (key.code == X_RT) - { - if (_context->_vigemController) - _context->_vigemController->setRightTrigger(1.f); - } else if (key.code == VK_NONAME) { if (_context->nn == 0) @@ -201,7 +192,8 @@ struct DigitalButtonImpl : public pocket_fsm::PimplBase, public EventActionIf void ApplyBtnRelease(KeyCode key) override { - if (key.code >= X_UP && key.code <= X_START || key.code == PS_HOME || key.code == PS_PAD_CLICK) + if (key.code >= X_UP && key.code <= X_START || key.code == PS_HOME || + key.code == PS_PAD_CLICK || key.code == X_LT || key.code == X_RT) { if (_context->_vigemController) { @@ -209,16 +201,6 @@ struct DigitalButtonImpl : public pocket_fsm::PimplBase, public EventActionIf ClearAllActiveToggle(key); } } - else if (key.code == X_LT) - { - if (_context->_vigemController) - _context->_vigemController->setLeftTrigger(0.f); - } - else if (key.code == X_RT) - { - if (_context->_vigemController) - _context->_vigemController->setRightTrigger(0.f); - } else if (key.code != NO_HOLD_MAPPED) { // DEBUG_LOG << "Releasing key " << key.name << endl; diff --git a/JoyShockMapper/src/Mapping.cpp b/JoyShockMapper/src/Mapping.cpp index f0bca35..2036330 100644 --- a/JoyShockMapper/src/Mapping.cpp +++ b/JoyShockMapper/src/Mapping.cpp @@ -217,7 +217,6 @@ bool Mapping::AddMapping(KeyCode key, EventModifier evtMod, ActionModifier actMo { case ActionModifier::Toggle: apply = bind(&EventActionIf::ApplyButtonToggle, placeholders::_1, key, apply, release); - release = EventActionIf::Callback(); break; case ActionModifier::Instant: { @@ -232,13 +231,16 @@ bool Mapping::AddMapping(KeyCode key, EventModifier evtMod, ActionModifier actMo } // Insert release first because in turbo's case apply and release are the same but we want release to apply first - InsertEventMapping(releaseEvt, release); InsertEventMapping(applyEvt, apply); if (evtMod == EventModifier::TurboPress) { // On turbo you also always need to clear the turbo on release InsertEventMapping(BtnEvent::OnRelease, release); } + else + { + InsertEventMapping(releaseEvt, release); + } stringstream ss; // Update Description diff --git a/JoyShockMapper/src/SDL2Wrapper.cpp b/JoyShockMapper/src/SDL2Wrapper.cpp index 66a42c1..9f35ad3 100644 --- a/JoyShockMapper/src/SDL2Wrapper.cpp +++ b/JoyShockMapper/src/SDL2Wrapper.cpp @@ -96,7 +96,7 @@ struct ControllerDevice } if (vid == 0x24c6) // PowerA { - _ctrlr_type = JS_TYPE_XBOX_SERIES; + _ctrlr_type = JS_TYPE_XBOX_SERIES; } if (vid == 0x045e) // Microsoft Vendor ID { @@ -472,9 +472,9 @@ struct SdlInstance : public JslWrapper case JS_TYPE_DS: buttons |= SDL_GameControllerGetButton(_controllerMap[deviceId]->_sdlController, SDL_CONTROLLER_BUTTON_MISC1) > 0 ? 1 << JSOFFSET_MIC : 0; buttons |= SDL_GameControllerGetButton(_controllerMap[deviceId]->_sdlController, SDL_CONTROLLER_BUTTON_PADDLE1) > 0 ? 1 << JSOFFSET_SR : 0; - buttons |= SDL_GameControllerGetButton(_controllerMap[deviceId]->_sdlController, SDL_CONTROLLER_BUTTON_PADDLE2) > 0 ? 1 << JSOFFSET_FNL : 0; + buttons |= SDL_GameControllerGetButton(_controllerMap[deviceId]->_sdlController, SDL_CONTROLLER_BUTTON_PADDLE2) > 0 ? 1 << JSOFFSET_SL : 0; buttons |= SDL_GameControllerGetButton(_controllerMap[deviceId]->_sdlController, SDL_CONTROLLER_BUTTON_PADDLE3) > 0 ? 1 << JSOFFSET_FNR : 0; - buttons |= SDL_GameControllerGetButton(_controllerMap[deviceId]->_sdlController, SDL_CONTROLLER_BUTTON_PADDLE4) > 0 ? 1 << JSOFFSET_SL : 0; + buttons |= SDL_GameControllerGetButton(_controllerMap[deviceId]->_sdlController, SDL_CONTROLLER_BUTTON_PADDLE4) > 0 ? 1 << JSOFFSET_FNL : 0; // Intentional fall through to the next case case JS_TYPE_DS4: buttons |= SDL_GameControllerGetButton(_controllerMap[deviceId]->_sdlController, SDL_CONTROLLER_BUTTON_TOUCHPAD) > 0 ? 1 << JSOFFSET_CAPTURE : 0; diff --git a/JoyShockMapper/src/SettingsManager.cpp b/JoyShockMapper/src/SettingsManager.cpp index 6c4c08d..197cd25 100644 --- a/JoyShockMapper/src/SettingsManager.cpp +++ b/JoyShockMapper/src/SettingsManager.cpp @@ -22,8 +22,10 @@ void SettingsManager::resetAllSettings() static std::set exceptions = { SettingID::AUTOLOAD, SettingID::JSM_DIRECTORY, + SettingID::HIDE_MINIMIZED, + SettingID::VIRTUAL_CONTROLLER, }; return exceptions.find(kvPair.first) == exceptions.end(); }; ranges::for_each(_settings | views::filter(exceptions), callReset); -} \ No newline at end of file +} diff --git a/JoyShockMapper/src/main.cpp b/JoyShockMapper/src/main.cpp index 477bf9a..e99843a 100644 --- a/JoyShockMapper/src/main.cpp +++ b/JoyShockMapper/src/main.cpp @@ -231,6 +231,9 @@ class JoyShock { touchpads.push_back(TouchStick(i, _context, handle)); } + left_stick.scroll.init(buttons[int(ButtonID::LLEFT)], buttons[int(ButtonID::LRIGHT)]); + right_stick.scroll.init(buttons[int(ButtonID::RLEFT)], buttons[int(ButtonID::RRIGHT)]); + motion_stick.scroll.init(buttons[int(ButtonID::MLEFT)], buttons[int(ButtonID::MRIGHT)]); touch_scroll_x.init(touchpads[0].buttons.find(ButtonID::TLEFT)->second, touchpads[0].buttons.find(ButtonID::TRIGHT)->second); touch_scroll_y.init(touchpads[0].buttons.find(ButtonID::TUP)->second, touchpads[0].buttons.find(ButtonID::TDOWN)->second); updateGridSize(); @@ -1722,6 +1725,10 @@ void JoyShock::processStick(float stickX, float stickY, Stick &stick, float mous stick.scroll.processScroll(angle - lastAngle, getSetting(SettingID::SCROLL_SENS).x(), time_now); } } + else + { + CERR << "Scroll object for stick " << stick._stickMode << " was not initialized!\n"; + } } else if (stickMode == StickMode::NO_MOUSE || stickMode == StickMode::INNER_RING || stickMode == StickMode::OUTER_RING) { // Do not do if invalid @@ -2097,20 +2104,19 @@ void DisplayTouchInfo(int id, optional xy, optional prevXY = n void TouchCallback(int jcHandle, TOUCH_STATE newState, TOUCH_STATE prevState, float delta_time) { - - // if (current.t0Down || previous.t0Down) + //if (newState.t0Down || prevState.t0Down) //{ - // DisplayTouchInfo(current.t0Down ? current.t0Id : previous.t0Id, - // current.t0Down ? optional({ current.t0X, current.t0Y }) : nullopt, - // previous.t0Down ? optional({ previous.t0X, previous.t0Y }) : nullopt); - // } + // DisplayTouchInfo(newState.t0Down ? newState.t0Id : prevState.t0Id, + // newState.t0Down ? optional({ newState.t0X, newState.t0Y }) : nullopt, + // prevState.t0Down ? optional({ prevState.t0X, prevState.t0Y }) : nullopt); + //} - // if (current.t1Down || previous.t1Down) + //if (newState.t1Down || prevState.t1Down) //{ - // DisplayTouchInfo(current.t1Down ? current.t1Id : previous.t1Id, - // current.t1Down ? optional({ current.t1X, current.t1Y }) : nullopt, - // previous.t1Down ? optional({ previous.t1X, previous.t1Y }) : nullopt); - // } + // DisplayTouchInfo(newState.t1Down ? newState.t1Id : prevState.t1Id, + // newState.t1Down ? optional({ newState.t1X, newState.t1Y }) : nullopt, + // prevState.t1Down ? optional({ prevState.t1X, prevState.t1Y }) : nullopt); + //} shared_ptr js = handle_to_joyshock[jcHandle]; int tpSizeX, tpSizeY; @@ -2154,17 +2160,17 @@ void TouchCallback(int jcHandle, TOUCH_STATE newState, TOUCH_STATE prevState, fl int index0 = -1, index1 = -1; if (point0.isDown()) { - float row = floorf(point0.posY * grid_size.value().y()); - float col = floorf(point0.posX * grid_size.value().x()); - // cout << "I should be in button " << row << " " << col << endl; + float row = ceilf(point0.posY * grid_size.value().y()) - 1.f; + float col = ceilf(point0.posX * grid_size.value().x()) - 1.f; + // COUT << "I should be in button " << row << " " << col << endl; index0 = int(row * grid_size.value().x() + col); } if (point1.isDown()) { - float row = floorf(point1.posY * grid_size.value().y()); - float col = floorf(point1.posX * grid_size.value().x()); - // cout << "I should be in button " << row << " " << col << endl; + float row = ceilf(point1.posY * grid_size.value().y()) - 1.f; + float col = ceilf(point1.posX * grid_size.value().x()) - 1.f; + // COUT << "I should be in button " << row << " " << col << endl; index1 = int(row * grid_size.value().x() + col); } @@ -3490,11 +3496,13 @@ void OnVirtualControllerChange(const ControllerScheme &newScheme) for (auto &js : handle_to_joyshock) { // Display an error message if any vigem is no good. + lock_guard guard(js.second->_context->callback_lock); if (!js.second->CheckVigemState()) { break; } } + // TODO: on NONE clear mappings with vigem commands? } void RefreshAutoLoadHelp(JSMAssignment *autoloadCmd) diff --git a/JoyShockMapper/src/win32/Gamepad.cpp b/JoyShockMapper/src/win32/Gamepad.cpp index 5851644..76c507a 100644 --- a/JoyShockMapper/src/win32/Gamepad.cpp +++ b/JoyShockMapper/src/win32/Gamepad.cpp @@ -7,6 +7,7 @@ #include #include #include +#include // // Link against SetupAPI @@ -55,13 +56,18 @@ union UDs4OutputBuffer inline void DS4_REPORT_EX_INIT(DS4_REPORT_EX* ds4reportEx) { // Preserve button state - auto buttons = ds4reportEx->Report.wButtons; memset(ds4reportEx, 0, (sizeof(DS4_REPORT_EX))); - ds4reportEx->Report.wButtons = buttons; - ds4reportEx->Report.bThumbLX = 0x7F; - ds4reportEx->Report.bThumbLY = 0x7F; - ds4reportEx->Report.bThumbRX = 0x7F; - ds4reportEx->Report.bThumbRY = 0x7F; + ds4reportEx->Report.bThumbLX = 0x80; + ds4reportEx->Report.bThumbLY = 0x80; + ds4reportEx->Report.bThumbRX = 0x80; + ds4reportEx->Report.bThumbRY = 0x80; + + //DS4_SET_DPAD(ds4reportEx, DS4_BUTTON_DPAD_NONE); + ds4reportEx->Report.wButtons &= ~0xF; + ds4reportEx->Report.wButtons |= (USHORT)DS4_BUTTON_DPAD_NONE; + + ds4reportEx->Report.sCurrentTouch.bIsUpTrackingNum1 = 0x80; + ds4reportEx->Report.sCurrentTouch.bIsUpTrackingNum2 = 0x80; } template @@ -237,6 +243,8 @@ class VigemGamepad : public Gamepad } PVIGEM_TARGET _gamepad = nullptr; + bool isLeftTriggerPressedDigitally = false; + bool isRightTriggerPressedDigitally = false; private : Callback _notification = nullptr; @@ -308,6 +316,16 @@ class XboxGamepad : public VigemGamepad { op(_stateX360.wButtons, found->second); } + else if (btn.code == X_LT) + { + isLeftTriggerPressedDigitally = pressed; + setLeftTrigger(1.0f); + } + else if (btn.code == X_RT) + { + isRightTriggerPressedDigitally = pressed; + setRightTrigger(1.0f); + } } void setLeftStick(float x, float y) override { @@ -332,6 +350,11 @@ class XboxGamepad : public VigemGamepad { if (isInitialized()) { + if (isLeftTriggerPressedDigitally) + setLeftTrigger(1.0f); + if (isRightTriggerPressedDigitally) + setRightTrigger(1.0f); + vigem_target_x360_update(VigemClient::get(), _gamepad, _stateX360); auto buttons = _stateX360.wButtons; XUSB_REPORT_INIT(&_stateX360); @@ -377,6 +400,7 @@ class Ds4Gamepad : public VigemGamepad if (_errorMsg.empty()) { + lock_guard guard(_gamepadLock); // Allocate handle to identify new pad _gamepad = vigem_target_ds4_alloc(); @@ -396,6 +420,7 @@ class Ds4Gamepad : public VigemGamepad { if (isInitialized()) { + lock_guard guard(_gamepadLock); // We're done with this pad, free resources (this disconnects the virtual device) if (PVIGEM_CLIENT client = VigemClient::get(); client != nullptr) { @@ -406,13 +431,19 @@ class Ds4Gamepad : public VigemGamepad _pollDs4Thread.join(); } + VIGEM_ERROR awaitOutputReportTimeout(UDs4OutputBuffer &out) + { + lock_guard guard(_gamepadLock); + return vigem_target_ds4_await_output_report_timeout(VigemClient::get(), _gamepad, 1000, &out.buffer); + } + void pollDs4() { UDs4OutputBuffer out; Indicator ind; - for (auto result = vigem_target_ds4_await_output_report_timeout(VigemClient::get(), _gamepad, 1000, &out.buffer); + for (auto result = awaitOutputReportTimeout(out); result == VIGEM_ERROR_NONE || result == VIGEM_ERROR_TIMED_OUT; - result = vigem_target_ds4_await_output_report_timeout(VigemClient::get(), _gamepad, 1000, &out.buffer)) + result = awaitOutputReportTimeout(out)) { if (result == VIGEM_ERROR_NONE) { @@ -518,8 +549,17 @@ class Ds4Gamepad : public VigemGamepad { if (isInitialized()) { + if (isLeftTriggerPressedDigitally) + setLeftTrigger(1.0f); + if (isRightTriggerPressedDigitally) + setRightTrigger(1.0f); + vigem_target_ds4_update_ex(VigemClient::get(), _gamepad, _stateDS4); + auto buttons = _stateDS4.Report.wButtons; + auto special = _stateDS4.Report.bSpecial; DS4_REPORT_EX_INIT(&_stateDS4); + _stateDS4.Report.wButtons = buttons; + _stateDS4.Report.bSpecial = special; } } @@ -535,6 +575,7 @@ class Ds4Gamepad : public VigemGamepad std::optional _touchId1 = 0; std::optional _touchId2 = 0; std::thread _pollDs4Thread; + std::mutex _gamepadLock; }; class PSHat @@ -812,7 +853,15 @@ void Ds4Gamepad::setButton(KeyCode btn, bool pressed) case PS_R3: op_w(_stateDS4.Report.wButtons, DS4_BUTTON_THUMB_RIGHT); break; - default: + case PS_L2: + isLeftTriggerPressedDigitally = pressed; + op_w(_stateDS4.Report.wButtons, DS4_BUTTON_TRIGGER_LEFT); + setLeftTrigger(pressed ? 1.0f : 0.f); + break; + case PS_R2: + isRightTriggerPressedDigitally = pressed; + op_w(_stateDS4.Report.wButtons, DS4_BUTTON_TRIGGER_RIGHT); + setRightTrigger(pressed ? 1.0f : 0.f); break; } }