diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 6d79159dcb..59434a8452 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -401,7 +401,6 @@ target_sources(rpcs3_emu PRIVATE Io/GameTablet.cpp Io/GHLtar.cpp Io/GunCon3.cpp - Io/WiimoteManager.cpp Io/Infinity.cpp Io/interception.cpp Io/KamenRider.cpp diff --git a/rpcs3/Emu/Io/GunCon3.cpp b/rpcs3/Emu/Io/GunCon3.cpp index 9df8af72c2..b4d0c3f7d2 100644 --- a/rpcs3/Emu/Io/GunCon3.cpp +++ b/rpcs3/Emu/Io/GunCon3.cpp @@ -9,7 +9,7 @@ #include "Emu/Io/guncon3_config.h" #include "Emu/Cell/lv2/sys_usbd.h" #include "Emu/system_config.h" -#include "WiimoteManager.h" +#include "Input/wiimote_handler.h" #include "Input/pad_thread.h" #include "Emu/RSX/Overlays/overlay_cursor.h" @@ -210,6 +210,78 @@ void usb_device_guncon3::control_transfer(u8 bmRequestType, u8 bRequest, u16 wVa extern bool is_input_allowed(); +bool usb_device_guncon3::handle_wiimote(GunCon3_data& gc) +{ + auto* wm = wiimote_handler::get_instance(); + auto states = wm->get_states(); + + // Determine which Wiimote to use based on our ordinal position among all GunCons + int my_wiimote_index = -1; + { + std::lock_guard lock(s_instances_mutex); + auto found = std::find(s_instances.begin(), s_instances.end(), this); + if (found != s_instances.end()) + { + my_wiimote_index = std::distance(s_instances.begin(), found); + } + } + + if (my_wiimote_index < 0 || static_cast(my_wiimote_index) >= states.size()) + return false; + + const auto& ws = states[my_wiimote_index]; + if (!ws.connected) + return false; + + const auto map = wm->get_mapping(); + const auto is_pressed = [&](wiimote_button btn) { return (ws.buttons & static_cast(btn)) != 0; }; + + if (is_pressed(map.trigger)) gc.btn_trigger = 1; + + // Wiimote to GunCon3 Button Mapping + if (is_pressed(map.a1)) gc.btn_a1 = 1; + if (is_pressed(map.a2)) gc.btn_a2 = 1; + if (is_pressed(map.a3)) gc.btn_a3 = 1; + if (is_pressed(map.b1)) gc.btn_b1 = 1; + if (is_pressed(map.b2)) gc.btn_b2 = 1; + if (is_pressed(map.b3)) gc.btn_b3 = 1; + if (is_pressed(map.c1)) gc.btn_c1 = 1; + if (is_pressed(map.c2)) gc.btn_c2 = 1; + + // Secondary / Hardcoded Alts + if (is_pressed(map.b1_alt)) gc.btn_b1 = 1; + if (is_pressed(map.b2_alt)) gc.btn_b2 = 1; + + if (ws.ir[0].x < 1023) + { + // Map Wiimote IR (0..1023) to GunCon3 range (-32768..32767) + const s32 raw_x = ws.ir[0].x; + const s32 raw_y = ws.ir[0].y; + + const s32 x_res = 32767 - (raw_x * 65535 / 1023); + const s32 y_res = 32767 - (raw_y * 65535 / 767); + + gc.gun_x = static_cast(std::clamp(x_res, -32768, 32767)); + gc.gun_y = static_cast(std::clamp(y_res, -32768, 32767)); + + if (g_cfg.io.show_move_cursor) + { + const s16 ax = static_cast((gc.gun_x + 32768) * rsx::overlays::overlay::virtual_width / 65535); + const s16 ay = static_cast((32767 - gc.gun_y) * rsx::overlays::overlay::virtual_height / 65535); + rsx::overlays::set_cursor(rsx::overlays::cursor_offset::cell_gem + my_wiimote_index, ax, ay, { 1.0f, 1.0f, 1.0f, 1.0f }, 100'000, false); + } + + if (ws.ir[1].x < 1023) + { + const s32 dx = static_cast(ws.ir[0].x) - ws.ir[1].x; + const s32 dy = static_cast(ws.ir[0].y) - ws.ir[1].y; + gc.gun_z = static_cast(std::sqrt(dx * dx + dy * dy)); + } + } + + return true; +} + void usb_device_guncon3::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) { transfer->fake = true; @@ -229,93 +301,13 @@ void usb_device_guncon3::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, GunCon3_data gc{}; gc.stick_ax = gc.stick_ay = gc.stick_bx = gc.stick_by = 0x7f; - auto* wm = wiimote_manager::get_instance(); - auto states = wm->get_states(); - - // Determine which Wiimote to use based on our ordinal position among all GunCons - int my_wiimote_index = -1; + if (!is_input_allowed()) { - std::lock_guard lock(s_instances_mutex); - // Since we sort by pointer adress/controller_index in add, and search by this ptr - // Actually lower_bound needs a value. std::find is safer for pointer identity. - auto found = std::find(s_instances.begin(), s_instances.end(), this); - if (found != s_instances.end()) - { - my_wiimote_index = std::distance(s_instances.begin(), found); - } - } - - if (my_wiimote_index >= 0 && static_cast(my_wiimote_index) < states.size()) - { - const auto& ws = states[my_wiimote_index]; - if (!ws.connected) - { - // Disconnected Wiimote, provide default neutral state for this GunCon - std::memcpy(buf, &gc, std::min(buf_size, sizeof(gc))); - return; - } - - const auto map = wm->get_mapping(); - - const auto is_pressed = [&](wiimote_button btn) { return (ws.buttons & static_cast(btn)) != 0; }; - - if (is_pressed(map.trigger)) gc.btn_trigger = 1; - - // Wiimote to GunCon3 Button Mapping - if (is_pressed(map.a1)) gc.btn_a1 = 1; - if (is_pressed(map.a2)) gc.btn_a2 = 1; - if (is_pressed(map.a3)) gc.btn_a3 = 1; - if (is_pressed(map.b1)) gc.btn_b1 = 1; - if (is_pressed(map.b2)) gc.btn_b2 = 1; - if (is_pressed(map.b3)) gc.btn_b3 = 1; - if (is_pressed(map.c1)) gc.btn_c1 = 1; - if (is_pressed(map.c2)) gc.btn_c2 = 1; - - // Secondary / Hardcoded Alts (if kept in mapping struct) - if (is_pressed(map.b1_alt)) gc.btn_b1 = 1; - if (is_pressed(map.b2_alt)) gc.btn_b2 = 1; - - if (ws.ir[0].x < 1023) - { - // Only use the primary pointer to avoid jumping between multiple IR points - const s32 raw_x = ws.ir[0].x; - const s32 raw_y = ws.ir[0].y; - - // Map to GunCon3 range (-32768..32767) - // X calculation (Right = 32767, Left = -32768) - const s32 x_res = 32767 - (raw_x * 65535 / 1023); - // Y calculation (Top = 32767, Bottom = -32768) - // Swapping to inverted mapping as per user feedback - const s32 y_res = 32767 - (raw_y * 65535 / 767); - - gc.gun_x = static_cast(std::clamp(x_res, -32768, 32767)); - gc.gun_y = static_cast(std::clamp(y_res, -32768, 32767)); - - if (g_cfg.io.show_move_cursor) - { - // Draw the actual GunCon3 output to the overlay - // Mapping GunCon3 range back to virtual_width/height - const s16 ax = static_cast((gc.gun_x + 32768) * rsx::overlays::overlay::virtual_width / 65535); - const s16 ay = static_cast((32767 - gc.gun_y) * rsx::overlays::overlay::virtual_height / 65535); - - // Use my_wiimote_index for color/cursor selection (0=Red, 1=Green...) - rsx::overlays::set_cursor(rsx::overlays::cursor_offset::cell_gem + my_wiimote_index, ax, ay, { 1.0f, 1.0f, 1.0f, 1.0f }, 100'000, false); - } - - if (ws.ir[1].x < 1023) - { - // Calculate "Z" (distance) based on spread of first two points to emulate depth sensor - const s32 dx = static_cast(ws.ir[0].x) - ws.ir[1].x; - const s32 dy = static_cast(ws.ir[0].y) - ws.ir[1].y; - gc.gun_z = static_cast(std::sqrt(dx * dx + dy * dy)); - } - } - guncon3_encode(&gc, buf, m_key.data()); return; } - if (!is_input_allowed()) + if (handle_wiimote(gc)) { guncon3_encode(&gc, buf, m_key.data()); return; diff --git a/rpcs3/Emu/Io/GunCon3.h b/rpcs3/Emu/Io/GunCon3.h index 2cdbb27e20..d69183057a 100644 --- a/rpcs3/Emu/Io/GunCon3.h +++ b/rpcs3/Emu/Io/GunCon3.h @@ -17,6 +17,8 @@ private: u32 m_controller_index; std::array m_key{}; + bool handle_wiimote(struct GunCon3_data& gc); + static inline std::vector s_instances; static inline std::mutex s_instances_mutex; }; diff --git a/rpcs3/Emu/Io/WiimoteManager.cpp b/rpcs3/Input/wiimote_handler.cpp similarity index 94% rename from rpcs3/Emu/Io/WiimoteManager.cpp rename to rpcs3/Input/wiimote_handler.cpp index 23a049cecc..ef7b64f4f6 100644 --- a/rpcs3/Emu/Io/WiimoteManager.cpp +++ b/rpcs3/Input/wiimote_handler.cpp @@ -1,5 +1,5 @@ #include "stdafx.h" -#include "WiimoteManager.h" +#include "wiimote_handler.h" #include "Input/hid_instance.h" #include "Emu/System.h" #include "Emu/system_config.h" @@ -217,14 +217,14 @@ bool wiimote_device::update() return true; } -static wiimote_manager* s_instance = nullptr; +static wiimote_handler* s_instance = nullptr; static std::string get_config_path() { return fs::get_config_dir(true) + "wiimote.yml"; } -void wiimote_manager::load_config() +void wiimote_handler::load_config() { const std::string path = get_config_path(); fs::file f(path, fs::read); @@ -260,7 +260,7 @@ void wiimote_manager::load_config() m_mapping = map; } -void wiimote_manager::save_config() +void wiimote_handler::save_config() { YAML::Node root; { @@ -281,7 +281,7 @@ void wiimote_manager::save_config() fs::write_file(get_config_path(), fs::rewrite, emitter.c_str(), emitter.size()); } -wiimote_manager::wiimote_manager() +wiimote_handler::wiimote_handler() { if (!s_instance) s_instance = this; @@ -295,19 +295,19 @@ wiimote_manager::wiimote_manager() load_config(); } -wiimote_manager::~wiimote_manager() +wiimote_handler::~wiimote_handler() { stop(); if (s_instance == this) s_instance = nullptr; } -wiimote_manager* wiimote_manager::get_instance() +wiimote_handler* wiimote_handler::get_instance() { return s_instance; } -void wiimote_manager::start() +void wiimote_handler::start() { if (m_running) return; @@ -315,22 +315,22 @@ void wiimote_manager::start() if (!hid_instance::get_instance().initialize()) return; m_running = true; - m_thread = std::thread(&wiimote_manager::thread_proc, this); + m_thread = std::thread(&wiimote_handler::thread_proc, this); } -void wiimote_manager::stop() +void wiimote_handler::stop() { m_running = false; if (m_thread.joinable()) m_thread.join(); } -size_t wiimote_manager::get_device_count() +size_t wiimote_handler::get_device_count() { std::shared_lock lock(m_mutex); return m_devices.size(); } -void wiimote_manager::set_mapping(const wiimote_guncon_mapping& mapping) +void wiimote_handler::set_mapping(const wiimote_guncon_mapping& mapping) { { std::unique_lock lock(m_mutex); @@ -339,13 +339,13 @@ void wiimote_manager::set_mapping(const wiimote_guncon_mapping& mapping) save_config(); } -wiimote_guncon_mapping wiimote_manager::get_mapping() const +wiimote_guncon_mapping wiimote_handler::get_mapping() const { // shared_lock not strictly needed for trivial copy but good practice if it becomes complex return m_mapping; } -std::vector wiimote_manager::get_states() +std::vector wiimote_handler::get_states() { std::shared_lock lock(m_mutex); std::vector states; @@ -359,7 +359,7 @@ std::vector wiimote_manager::get_states() } -void wiimote_manager::thread_proc() +void wiimote_handler::thread_proc() { thread_ctrl::set_name("WiiMoteManager"); diff --git a/rpcs3/Emu/Io/WiimoteManager.h b/rpcs3/Input/wiimote_handler.h similarity index 95% rename from rpcs3/Emu/Io/WiimoteManager.h rename to rpcs3/Input/wiimote_handler.h index 770f4b3735..326b9f3145 100644 --- a/rpcs3/Emu/Io/WiimoteManager.h +++ b/rpcs3/Input/wiimote_handler.h @@ -88,13 +88,13 @@ private: bool write_reg(u32 addr, const std::vector& data); }; -class wiimote_manager +class wiimote_handler { public: - wiimote_manager(); - ~wiimote_manager(); + wiimote_handler(); + ~wiimote_handler(); - static wiimote_manager* get_instance(); + static wiimote_handler* get_instance(); void start(); void stop(); diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 9749f60fcd..9d7baffa3b 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -193,6 +193,7 @@ + @@ -236,6 +237,9 @@ true + + true + true @@ -539,6 +543,9 @@ true + + true + true @@ -825,6 +832,7 @@ + @@ -943,6 +951,7 @@ + @@ -968,6 +977,7 @@ + @@ -1149,6 +1159,7 @@ + @@ -1223,6 +1234,16 @@ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\protobuf\protobuf\src" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing %(Identity)... + .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\protobuf\protobuf\src" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing %(Identity)... + .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\protobuf\protobuf\src" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" + $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... @@ -2021,6 +2042,7 @@ + @@ -2172,6 +2194,16 @@ .\QTGeneratedFiles\ui_%(Filename).h;%(Outputs) "$(QTDIR)\bin\uic.exe" -o ".\QTGeneratedFiles\ui_%(Filename).h" "%(FullPath)" + + $(QTDIR)\bin\uic.exe;%(AdditionalInputs) + Uic%27ing %(Identity)... + .\QTGeneratedFiles\ui_%(Filename).h;%(Outputs) + "$(QTDIR)\bin\uic.exe" -o ".\QTGeneratedFiles\ui_%(Filename).h" "%(FullPath)" + $(QTDIR)\bin\uic.exe;%(AdditionalInputs) + Uic%27ing %(Identity)... + .\QTGeneratedFiles\ui_%(Filename).h;%(Outputs) + "$(QTDIR)\bin\uic.exe" -o ".\QTGeneratedFiles\ui_%(Filename).h" "%(FullPath)" + $(QTDIR)\bin\uic.exe;%(AdditionalInputs) Uic%27ing %(Identity)... diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index a011ddf62e..c908eff52b 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -315,6 +315,9 @@ Io\MMJoystick + + Io + Io\XInput @@ -897,6 +900,9 @@ Generated Files\Release + + Io + Io @@ -954,6 +960,15 @@ Generated Files\Release + + Gui\settings + + + Generated Files\Debug + + + Generated Files\Release + Gui\ps_move_tracker_dialog @@ -1280,6 +1295,9 @@ Io\DS4 + + Io + Io\XInput @@ -1394,6 +1412,9 @@ Gui\misc dialogs + + Io + Io @@ -1409,6 +1430,9 @@ Generated Files + + Generated Files + Generated Files @@ -1765,9 +1789,15 @@ Form Files + + Form Files + Gui\settings + + Gui\settings + Form Files diff --git a/rpcs3/rpcs3qt/CMakeLists.txt b/rpcs3/rpcs3qt/CMakeLists.txt index 7390c6b507..4f4d515bfa 100644 --- a/rpcs3/rpcs3qt/CMakeLists.txt +++ b/rpcs3/rpcs3qt/CMakeLists.txt @@ -174,6 +174,7 @@ add_library(rpcs3_ui STATIC ../Input/sdl_instance.cpp ../Input/sdl_pad_handler.cpp ../Input/skateboard_pad_handler.cpp + ../Input/wiimote_handler.cpp ../Input/xinput_pad_handler.cpp "../resources.qrc" diff --git a/rpcs3/rpcs3qt/gui_application.cpp b/rpcs3/rpcs3qt/gui_application.cpp index 4c7aaf7c0c..0f5cdc86e7 100644 --- a/rpcs3/rpcs3qt/gui_application.cpp +++ b/rpcs3/rpcs3qt/gui_application.cpp @@ -127,8 +127,8 @@ bool gui_application::Init() } m_emu_settings = std::make_shared(); - m_wiimote_manager = std::make_unique(); - m_wiimote_manager->start(); + m_wiimote_handler = std::make_unique(); + m_wiimote_handler->start(); m_gui_settings = std::make_shared(); m_persistent_settings = std::make_shared(); diff --git a/rpcs3/rpcs3qt/gui_application.h b/rpcs3/rpcs3qt/gui_application.h index a0b2604927..af10100bf3 100644 --- a/rpcs3/rpcs3qt/gui_application.h +++ b/rpcs3/rpcs3qt/gui_application.h @@ -13,7 +13,7 @@ #include "main_application.h" #include "Emu/System.h" -#include "Emu/Io/WiimoteManager.h" +#include "Input/wiimote_handler.h" #include "Input/raw_mouse_handler.h" #include @@ -112,7 +112,7 @@ private: std::deque> m_sound_effects{}; - std::unique_ptr m_wiimote_manager; + std::unique_ptr m_wiimote_handler; std::shared_ptr m_emu_settings; std::shared_ptr m_gui_settings; std::shared_ptr m_persistent_settings; diff --git a/rpcs3/rpcs3qt/wiimote_settings_dialog.cpp b/rpcs3/rpcs3qt/wiimote_settings_dialog.cpp index 5a6e89dbea..edf82492ef 100644 --- a/rpcs3/rpcs3qt/wiimote_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/wiimote_settings_dialog.cpp @@ -1,7 +1,7 @@ #include "stdafx.h" #include "wiimote_settings_dialog.h" #include "Emu/System.h" -#include "Emu/Io/WiimoteManager.h" +#include "Input/wiimote_handler.h" #include #include #include @@ -27,7 +27,7 @@ wiimote_settings_dialog::~wiimote_settings_dialog() = default; void wiimote_settings_dialog::populate_mappings() { - auto* wm = wiimote_manager::get_instance(); + auto* wm = wiimote_handler::get_instance(); if (!wm) return; const QPair buttons[] = { @@ -78,7 +78,7 @@ void wiimote_settings_dialog::populate_mappings() void wiimote_settings_dialog::restore_defaults() { - auto* wm = wiimote_manager::get_instance(); + auto* wm = wiimote_handler::get_instance(); if (!wm) return; // Reset to default mapping @@ -124,7 +124,7 @@ void wiimote_settings_dialog::restore_defaults() void wiimote_settings_dialog::apply_mappings() { - auto* wm = wiimote_manager::get_instance(); + auto* wm = wiimote_handler::get_instance(); if (!wm) return; wiimote_guncon_mapping map; @@ -153,7 +153,7 @@ void wiimote_settings_dialog::apply_mappings() void wiimote_settings_dialog::update_state() { int index = ui->wiimoteList->currentRow(); - auto* wm = wiimote_manager::get_instance(); + auto* wm = wiimote_handler::get_instance(); if (!wm || index < 0) { ui->connectionStatus->setText(tr("N/A")); @@ -230,7 +230,7 @@ void wiimote_settings_dialog::update_state() void wiimote_settings_dialog::update_list() { - auto* wm = wiimote_manager::get_instance(); + auto* wm = wiimote_handler::get_instance(); if (!wm) { if (ui->wiimoteList->count() != 1 || ui->wiimoteList->item(0)->text() != tr("Wiimote Manager not initialized."))