diff --git a/GlosSITarget/InputRedirector.cpp b/GlosSITarget/InputRedirector.cpp index 0b7b774..70d21b8 100644 --- a/GlosSITarget/InputRedirector.cpp +++ b/GlosSITarget/InputRedirector.cpp @@ -19,6 +19,8 @@ limitations under the License. #include #include +#include "Overlay.h" + InputRedirector::InputRedirector() { #ifdef _WIN32 @@ -47,6 +49,34 @@ void InputRedirector::run() { run_ = vigem_connected_; controller_thread_ = std::thread(&InputRedirector::runLoop, this); +#ifdef _WIN32 + Overlay::AddOverlayElem([this]() { + ImGui::SetNextWindowPos({650, 450}, ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSizeConstraints({400, 270}, {1000, 1000}); + ImGui::Begin("Controller Emulation"); + int countcopy = max_controller_count_; + ImGui::SliderInt("Max. controller count", &countcopy, 0, XUSER_MAX_COUNT); + max_controller_count_ = countcopy; + bool enable_rumbe_copy = enable_rumble_; + ImGui::Checkbox("Enable Rumble", &enable_rumbe_copy); + enable_rumble_ = enable_rumbe_copy; + if (ImGui::CollapsingHeader("Advanced")) { + ImGui::Text("GlosSI uses different USB-IDs for it's emulated controllers"); + ImGui::Text("This can cause issues with some games"); + ImGui::Text("When changing this, it's advised to also set Max. controller count"); + ImGui::Text("to prevent having multiple mirrored controllers plugged in"); + ImGui::Spacing(); + ImGui::Text("If enabled, Device hiding can't show if a controller is emulated."); + bool use_real_copy = use_real_vid_pid_; + ImGui::Checkbox("Use real USB-IDs", &use_real_copy); + if (use_real_vid_pid_ != use_real_copy) { + use_real_vid_pid_changed_ = true; + } + use_real_vid_pid_ = use_real_copy; + } + ImGui::End(); + }); +#endif } void InputRedirector::stop() @@ -69,8 +99,19 @@ void InputRedirector::runLoop() } while (run_) { #ifdef _WIN32 - - for (int i = 0; i < XUSER_MAX_COUNT; i++) { + if (use_real_vid_pid_changed_) { + // unplug all. + use_real_vid_pid_changed_ = false; + for (int i = 0; i < XUSER_MAX_COUNT; i++) { + unplugVigemX360(i); + } + } + if (max_controller_count_ < XUSER_MAX_COUNT) { + for (int i = max_controller_count_; i < XUSER_MAX_COUNT; i++) { + unplugVigemX360(i); + } + } + for (int i = 0; i < XUSER_MAX_COUNT && i < max_controller_count_; i++) { XINPUT_STATE state{}; if (XInputGetState(i, &state) == ERROR_SUCCESS) { if (vt_x360_[i] != nullptr) { @@ -90,8 +131,12 @@ void InputRedirector::runLoop() // Additonaly, Steam does pick up the emulated controller this way, and Hides it from our application // but Steam ONLY does this if it is configured to support X360 controller rebinding!!! // Otherwise, this application (GloSC/GlosSI) will pickup the emulated controller as well! - vigem_target_set_vid(vt_x360_[i], 0x28de); //VALVE_DIRECTINPUT_GAMEPAD_VID - // vigem_target_set_pid(vt_x360_[i], 0x11FF); //VALVE_DIRECTINPUT_GAMEPAD_PID + // This however is configurable withon GlosSI overlay; + // Multiple controllers can be worked around with by setting max count. + if (!use_real_vid_pid_) { + vigem_target_set_vid(vt_x360_[i], 0x28de); //VALVE_DIRECTINPUT_GAMEPAD_VID + // vigem_target_set_pid(vt_x360_[i], 0x11FF); //VALVE_DIRECTINPUT_GAMEPAD_PID + } // TODO: MAYBE!: In a future version, use something like OpenXInput //and filter out emulated controllers to support a greater amount of controllers simultaneously @@ -113,12 +158,7 @@ void InputRedirector::runLoop() } } else { - if (vt_x360_[i] != nullptr) { - if (VIGEM_SUCCESS(vigem_target_remove(driver_, vt_x360_[i]))) { - spdlog::info("Unplugged controller {}, {}", i, vigem_target_get_index(vt_x360_[i])); - vt_x360_[i] = nullptr; - } - } + unplugVigemX360(i); } } sf::sleep(sf::milliseconds(1)); @@ -130,6 +170,9 @@ void InputRedirector::runLoop() #ifdef _WIN32 void InputRedirector::controllerCallback(PVIGEM_CLIENT client, PVIGEM_TARGET Target, UCHAR LargeMotor, UCHAR SmallMotor, UCHAR LedNumber, LPVOID UserData) { + if (!enable_rumble_) { + return; + } XINPUT_VIBRATION vibration; ZeroMemory(&vibration, sizeof(XINPUT_VIBRATION)); vibration.wLeftMotorSpeed = LargeMotor * 0xff; //Controllers only use 1 byte, XInput-API uses two, ViGEm also only uses one, like the hardware does, so we have to multiply @@ -137,4 +180,14 @@ void InputRedirector::controllerCallback(PVIGEM_CLIENT client, PVIGEM_TARGET Tar XInputSetState(reinterpret_cast(UserData), &vibration); } + +void InputRedirector::unplugVigemX360(int idx) +{ + if (vt_x360_[idx] != nullptr) { + if (VIGEM_SUCCESS(vigem_target_remove(driver_, vt_x360_[idx]))) { + spdlog::info("Unplugged controller {}, {}", idx, vigem_target_get_index(vt_x360_[idx])); + vt_x360_[idx] = nullptr; + } + } +} #endif diff --git a/GlosSITarget/InputRedirector.h b/GlosSITarget/InputRedirector.h index 659e29a..953b089 100644 --- a/GlosSITarget/InputRedirector.h +++ b/GlosSITarget/InputRedirector.h @@ -35,12 +35,21 @@ class InputRedirector { static constexpr int start_delay_ms_ = 2000; bool run_ = false; - int controller_count_ = 0; + int overlay_elem_id_ = -1; #ifdef _WIN32 PVIGEM_CLIENT driver_; + + // variables for overlay element; run in different thread + std::atomic max_controller_count_ = XUSER_MAX_COUNT; + static inline std::atomic enable_rumble_ = true; + static inline std::atomic use_real_vid_pid_ = false; + static inline std::atomic use_real_vid_pid_changed_ = false; + PVIGEM_TARGET vt_x360_[XUSER_MAX_COUNT]{}; bool vigem_connected_; static void CALLBACK controllerCallback(PVIGEM_CLIENT client, PVIGEM_TARGET Target, UCHAR LargeMotor, UCHAR SmallMotor, UCHAR LedNumber, LPVOID UserData); + void unplugVigemX360(int idx); + #endif std::thread controller_thread_;