diff --git a/rpcs3/Emu/Io/GunCon3.cpp b/rpcs3/Emu/Io/GunCon3.cpp index 5338091c45..9f45fa99b0 100644 --- a/rpcs3/Emu/Io/GunCon3.cpp +++ b/rpcs3/Emu/Io/GunCon3.cpp @@ -3,6 +3,7 @@ #include "MouseHandler.h" #include "Emu/IdManager.h" #include "Emu/Io/guncon3_config.h" +#include "Emu/Io/wiimote_config.h" #include "Emu/Cell/lv2/sys_usbd.h" #include "Emu/system_config.h" #include "Emu/RSX/Overlays/overlay_cursor.h" @@ -212,11 +213,14 @@ extern bool is_input_allowed(); bool usb_device_guncon3::handle_wiimote(GunCon3_data& gc) { + if (!get_wiimote_config().use_for_guncon.get()) + return false; + 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; + s64 my_wiimote_index = -1; { std::lock_guard lock(s_instances_mutex); auto found = std::find(s_instances.begin(), s_instances.end(), this); diff --git a/rpcs3/Emu/Io/wiimote_config.cpp b/rpcs3/Emu/Io/wiimote_config.cpp index 9825fa6741..c840781208 100644 --- a/rpcs3/Emu/Io/wiimote_config.cpp +++ b/rpcs3/Emu/Io/wiimote_config.cpp @@ -4,6 +4,30 @@ LOG_CHANNEL(wiimote_log, "Wiimote"); +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](wiimote_button value) + { + switch (value) + { + case wiimote_button::None: return "None"; + case wiimote_button::Left: return "Left"; + case wiimote_button::Right: return "Right"; + case wiimote_button::Down: return "Down"; + case wiimote_button::Up: return "Up"; + case wiimote_button::Plus: return "Plus"; + case wiimote_button::Two: return "Two"; + case wiimote_button::One: return "One"; + case wiimote_button::B: return "B"; + case wiimote_button::A: return "A"; + case wiimote_button::Minus: return "Minus"; + case wiimote_button::Home: return "Home"; + } + return unknown; + }); +} + cfg_wiimote& get_wiimote_config() { static cfg_wiimote instance; @@ -20,14 +44,14 @@ bool cfg_wiimote::load() { if (fs::file f{path, fs::read}) { - return from_string(f.to_string()); + return this->cfg::node::from_string(f.to_string()); } return false; } void cfg_wiimote::save() const { - if (!cfg::node::save(path)) + if (!this->cfg::node::save(path)) { wiimote_log.error("Failed to save wiimote config to '%s'", path); } diff --git a/rpcs3/Emu/Io/wiimote_config.h b/rpcs3/Emu/Io/wiimote_config.h index 2d3334cdbb..53737fe93f 100644 --- a/rpcs3/Emu/Io/wiimote_config.h +++ b/rpcs3/Emu/Io/wiimote_config.h @@ -1,29 +1,32 @@ #pragma once #include "Utilities/Config.h" +#include "Input/wiimote_handler.h" -struct cfg_wiimote final : cfg::node +struct cfg_wiimote : cfg::node { cfg_wiimote(); bool load(); void save() const; + cfg::_bool use_for_guncon{ this, "UseForGunCon", true }; + struct node_mapping : cfg::node { node_mapping(cfg::node* _parent) : cfg::node(_parent, "Mapping") {} - cfg::uint<0, 0xFFFF> trigger{ this, "Trigger", 0x0400 }; - cfg::uint<0, 0xFFFF> a1{ this, "A1", 0x0800 }; - cfg::uint<0, 0xFFFF> a2{ this, "A2", 0x1000 }; - cfg::uint<0, 0xFFFF> a3{ this, "A3", 0x0001 }; - cfg::uint<0, 0xFFFF> b1{ this, "B1", 0x0200 }; - cfg::uint<0, 0xFFFF> b2{ this, "B2", 0x0100 }; - cfg::uint<0, 0xFFFF> b3{ this, "B3", 0x8000 }; - cfg::uint<0, 0xFFFF> c1{ this, "C1", 0x0010 }; - cfg::uint<0, 0xFFFF> c2{ this, "C2", 0x0002 }; + cfg::_enum trigger{ this, "Trigger", wiimote_button::B }; + cfg::_enum a1{ this, "A1", wiimote_button::A }; + cfg::_enum a2{ this, "A2", wiimote_button::Minus }; + cfg::_enum a3{ this, "A3", wiimote_button::Left }; + cfg::_enum b1{ this, "B1", wiimote_button::One }; + cfg::_enum b2{ this, "B2", wiimote_button::Two }; + cfg::_enum b3{ this, "B3", wiimote_button::Home }; + cfg::_enum c1{ this, "C1", wiimote_button::Plus }; + cfg::_enum c2{ this, "C2", wiimote_button::Right }; - cfg::uint<0, 0xFFFF> b1_alt{ this, "B1_Alt", 0x0008 }; - cfg::uint<0, 0xFFFF> b2_alt{ this, "B2_Alt", 0x0004 }; + cfg::_enum b1_alt{ this, "B1_Alt", wiimote_button::Up }; + cfg::_enum b2_alt{ this, "B2_Alt", wiimote_button::Down }; } mapping{ this }; const std::string path; diff --git a/rpcs3/Input/wiimote_handler.cpp b/rpcs3/Input/wiimote_handler.cpp index afcc3ac660..194be77ba7 100644 --- a/rpcs3/Input/wiimote_handler.cpp +++ b/rpcs3/Input/wiimote_handler.cpp @@ -213,17 +213,17 @@ void wiimote_handler::load_config() if (cfg.load()) { std::unique_lock lock(m_mutex); - m_mapping.trigger = static_cast(cfg.mapping.trigger.get()); - m_mapping.a1 = static_cast(cfg.mapping.a1.get()); - m_mapping.a2 = static_cast(cfg.mapping.a2.get()); - m_mapping.a3 = static_cast(cfg.mapping.a3.get()); - m_mapping.b1 = static_cast(cfg.mapping.b1.get()); - m_mapping.b2 = static_cast(cfg.mapping.b2.get()); - m_mapping.b3 = static_cast(cfg.mapping.b3.get()); - m_mapping.c1 = static_cast(cfg.mapping.c1.get()); - m_mapping.c2 = static_cast(cfg.mapping.c2.get()); - m_mapping.b1_alt = static_cast(cfg.mapping.b1_alt.get()); - m_mapping.b2_alt = static_cast(cfg.mapping.b2_alt.get()); + m_mapping.trigger = cfg.mapping.trigger.get(); + m_mapping.a1 = cfg.mapping.a1.get(); + m_mapping.a2 = cfg.mapping.a2.get(); + m_mapping.a3 = cfg.mapping.a3.get(); + m_mapping.b1 = cfg.mapping.b1.get(); + m_mapping.b2 = cfg.mapping.b2.get(); + m_mapping.b3 = cfg.mapping.b3.get(); + m_mapping.c1 = cfg.mapping.c1.get(); + m_mapping.c2 = cfg.mapping.c2.get(); + m_mapping.b1_alt = cfg.mapping.b1_alt.get(); + m_mapping.b2_alt = cfg.mapping.b2_alt.get(); } } @@ -232,17 +232,17 @@ void wiimote_handler::save_config() { std::shared_lock lock(m_mutex); auto& cfg = get_wiimote_config(); - cfg.mapping.trigger.set(static_cast(m_mapping.trigger)); - cfg.mapping.a1.set(static_cast(m_mapping.a1)); - cfg.mapping.a2.set(static_cast(m_mapping.a2)); - cfg.mapping.a3.set(static_cast(m_mapping.a3)); - cfg.mapping.b1.set(static_cast(m_mapping.b1)); - cfg.mapping.b2.set(static_cast(m_mapping.b2)); - cfg.mapping.b3.set(static_cast(m_mapping.b3)); - cfg.mapping.c1.set(static_cast(m_mapping.c1)); - cfg.mapping.c2.set(static_cast(m_mapping.c2)); - cfg.mapping.b1_alt.set(static_cast(m_mapping.b1_alt)); - cfg.mapping.b2_alt.set(static_cast(m_mapping.b2_alt)); + cfg.mapping.trigger.set(m_mapping.trigger); + cfg.mapping.a1.set(m_mapping.a1); + cfg.mapping.a2.set(m_mapping.a2); + cfg.mapping.a3.set(m_mapping.a3); + cfg.mapping.b1.set(m_mapping.b1); + cfg.mapping.b2.set(m_mapping.b2); + cfg.mapping.b3.set(m_mapping.b3); + cfg.mapping.c1.set(m_mapping.c1); + cfg.mapping.c2.set(m_mapping.c2); + cfg.mapping.b1_alt.set(m_mapping.b1_alt); + cfg.mapping.b2_alt.set(m_mapping.b2_alt); } get_wiimote_config().save(); } diff --git a/rpcs3/Input/wiimote_handler.h b/rpcs3/Input/wiimote_handler.h index 6179938381..d9d415aa9d 100644 --- a/rpcs3/Input/wiimote_handler.h +++ b/rpcs3/Input/wiimote_handler.h @@ -102,6 +102,8 @@ public: void start(); void stop(); + bool is_running() const { return m_running; } + std::vector get_states(); usz get_device_count(); diff --git a/rpcs3/rpcs3qt/wiimote_settings_dialog.cpp b/rpcs3/rpcs3qt/wiimote_settings_dialog.cpp index e0d93a620f..a491418586 100644 --- a/rpcs3/rpcs3qt/wiimote_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/wiimote_settings_dialog.cpp @@ -1,9 +1,12 @@ #include "stdafx.h" #include "wiimote_settings_dialog.h" #include "Input/wiimote_handler.h" +#include "Emu/Io/wiimote_config.h" #include #include #include +#include +#include wiimote_settings_dialog::wiimote_settings_dialog(QWidget* parent) : QDialog(parent) @@ -16,8 +19,18 @@ wiimote_settings_dialog::wiimote_settings_dialog(QWidget* parent) ui->cb_b1, ui->cb_b2, ui->cb_b3, ui->cb_a3, ui->cb_c2 }; + if (auto* use_guncon = findChild( "useForGunCon")) + { + use_guncon->setChecked(get_wiimote_config().use_for_guncon.get()); + connect(use_guncon, &QCheckBox::toggled, this, [](bool checked) + { + get_wiimote_config().use_for_guncon.set(checked); + get_wiimote_config().save(); + }); + } + update_list(); - connect(ui->restoreDefaultsButton, &QPushButton::clicked, this, &wiimote_settings_dialog::restore_defaults); + connect(ui->buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, this, &wiimote_settings_dialog::restore_defaults); // Timer updates both state AND device list (auto-refresh) QTimer* timer = new QTimer(this); @@ -88,6 +101,10 @@ void wiimote_settings_dialog::restore_defaults() const wiimote_guncon_mapping default_map {}; wm->set_mapping(default_map); + get_wiimote_config().use_for_guncon.set(true); + if (auto* use_guncon = findChild( "useForGunCon")) + use_guncon->setChecked(true); + // Update UI for (auto* box : m_boxes) box->blockSignals(true); @@ -132,16 +149,9 @@ void wiimote_settings_dialog::update_state() { const int index = ui->wiimoteList->currentRow(); auto* wm = wiimote_handler::get_instance(); - if (!wm || index < 0) - { - ui->connectionStatus->setText(tr("N/A")); - ui->buttonState->setText(tr("N/A")); - ui->irData->setText(tr("N/A")); - return; - } + const auto states = wm && wm->is_running() ? wm->get_states() : std::vector{}; - const auto states = wm->get_states(); - if (static_cast(index) >= states.size()) + if (!wm || !wm->is_running() || index < 0 || static_cast(index) >= states.size()) { ui->connectionStatus->setText(tr("N/A")); ui->buttonState->setText(tr("N/A")); @@ -153,17 +163,18 @@ void wiimote_settings_dialog::update_state() ui->connectionStatus->setText(state.connected ? tr("Connected") : tr("Disconnected")); QStringList pressed_buttons; - if (state.buttons & 0x0001) pressed_buttons << tr("Left"); - if (state.buttons & 0x0002) pressed_buttons << tr("Right"); - if (state.buttons & 0x0004) pressed_buttons << tr("Down"); - if (state.buttons & 0x0008) pressed_buttons << tr("Up"); - if (state.buttons & 0x0010) pressed_buttons << tr("Plus"); - if (state.buttons & 0x0100) pressed_buttons << tr("2"); - if (state.buttons & 0x0200) pressed_buttons << tr("1"); - if (state.buttons & 0x0400) pressed_buttons << tr("B"); - if (state.buttons & 0x0800) pressed_buttons << tr("A"); - if (state.buttons & 0x1000) pressed_buttons << tr("Minus"); - if (state.buttons & 0x8000) pressed_buttons << tr("Home"); + const auto is_pressed = [&](wiimote_button btn) { return (state.buttons & static_cast(btn)) != 0; }; + if (is_pressed(wiimote_button::Left)) pressed_buttons << tr("Left"); + if (is_pressed(wiimote_button::Right)) pressed_buttons << tr("Right"); + if (is_pressed(wiimote_button::Down)) pressed_buttons << tr("Down"); + if (is_pressed(wiimote_button::Up)) pressed_buttons << tr("Up"); + if (is_pressed(wiimote_button::Plus)) pressed_buttons << tr("Plus"); + if (is_pressed(wiimote_button::Two)) pressed_buttons << tr("2"); + if (is_pressed(wiimote_button::One)) pressed_buttons << tr("1"); + if (is_pressed(wiimote_button::B)) pressed_buttons << tr("B"); + if (is_pressed(wiimote_button::A)) pressed_buttons << tr("A"); + if (is_pressed(wiimote_button::Minus)) pressed_buttons << tr("Minus"); + if (is_pressed(wiimote_button::Home)) pressed_buttons << tr("Home"); QString button_text = QString("0x%1").arg(state.buttons, 4, 16, QChar('0')).toUpper(); if (!pressed_buttons.isEmpty()) @@ -173,15 +184,32 @@ void wiimote_settings_dialog::update_state() ui->buttonState->setText(button_text); QString ir_text; - QPixmap pixmap(ui->irVisual->size()); + const int w = ui->irVisual->width(); + const int h = ui->irVisual->height(); + QPixmap pixmap(w, h); pixmap.fill(Qt::black); QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing); - // Draw center crosshair + // Calculate 4:3 drawing area (Wiimote IR space is 1024x768) + int draw_w, draw_h; + if (w * 3 > h * 4) // wider than 4:3 + { + draw_h = h; + draw_w = h * 4 / 3; + } + else + { + draw_w = w; + draw_h = w * 3 / 4; + } + const int offset_x = (w - draw_w) / 2; + const int offset_y = (h - draw_h) / 2; + + // Draw center crosshair in the 4:3 area painter.setPen(QPen(Qt::darkGray, 1, Qt::DashLine)); - painter.drawLine(pixmap.width() / 2, 0, pixmap.width() / 2, pixmap.height()); - painter.drawLine(0, pixmap.height() / 2, pixmap.width(), pixmap.height() / 2); + painter.drawLine(offset_x + draw_w / 2, offset_y, offset_x + draw_w / 2, offset_y + draw_h); + painter.drawLine(offset_x, offset_y + draw_h / 2, offset_x + draw_w, offset_y + draw_h / 2); static const std::array colors = { Qt::red, Qt::green, Qt::blue, Qt::yellow }; @@ -191,10 +219,9 @@ void wiimote_settings_dialog::update_state() { ir_text += QString("[%1: %2, %3] ").arg(i).arg(state.ir[i].x).arg(state.ir[i].y); - // Map 0..1023 X and 0..767 Y to pixmap coordinates - // Wiimote X/Y are inverted relative to pointing direction - const float x = ((1023 - state.ir[i].x) / 1023.0f) * pixmap.width(); - const float y = (state.ir[i].y / 767.0f) * pixmap.height(); + // Map 0..1023 X and 0..767 Y to 4:3 drawing area + const float x = offset_x + ((1023.0f - state.ir[i].x) / 1023.0f) * draw_w; + const float y = offset_y + (state.ir[i].y / 767.0f) * draw_h; painter.setPen(colors[i]); painter.setBrush(colors[i]); @@ -209,7 +236,7 @@ void wiimote_settings_dialog::update_state() void wiimote_settings_dialog::update_list() { auto* wm = wiimote_handler::get_instance(); - if (!wm) + if (!wm || !wm->is_running()) { if (ui->wiimoteList->count() != 1 || ui->wiimoteList->item(0)->text() != tr("Wiimote Manager not initialized.")) { @@ -221,7 +248,17 @@ void wiimote_settings_dialog::update_list() const auto states = wm->get_states(); - // Only update if the list content actually changed (avoid flicker) + if (states.empty()) + { + if (ui->wiimoteList->count() != 1 || ui->wiimoteList->item(0)->text() != tr("No Wiimotes found.")) + { + ui->wiimoteList->clear(); + ui->wiimoteList->addItem(tr("No Wiimotes found.")); + } + return; + } + + // Only update if the list count changed (avoid flicker) if (static_cast(ui->wiimoteList->count()) != states.size()) { const int current_row = ui->wiimoteList->currentRow(); @@ -251,13 +288,9 @@ void wiimote_settings_dialog::update_list() QString label = tr("Wiimote #%1").arg(i + 1); if (!states[i].connected) label += " (" + tr("Disconnected") + ")"; - if (static_cast(i) < ui->wiimoteList->count()) + if (QListWidgetItem* item = ui->wiimoteList->item(static_cast(i)); item && item->text() != label) { - QListWidgetItem* item = ui->wiimoteList->item(static_cast(i)); - if (item && item->text() != label) - { - item->setText(label); - } + item->setText(label); } } } diff --git a/rpcs3/rpcs3qt/wiimote_settings_dialog.ui b/rpcs3/rpcs3qt/wiimote_settings_dialog.ui index 1c879fe9fd..33b2df2d04 100644 --- a/rpcs3/rpcs3qt/wiimote_settings_dialog.ui +++ b/rpcs3/rpcs3qt/wiimote_settings_dialog.ui @@ -14,6 +14,22 @@ Wiimote Settings + + + + General Settings + + + + + + Enable Wiimote for GunCon Emulation + + + + + + @@ -205,38 +221,14 @@ - - - - - Restore Defaults - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Close - - - - + + + Qt::Horizontal + + + QDialogButtonBox::Close|QDialogButtonBox::RestoreDefaults + +