Refactor Wiimote and GunCon3 integration: Update button mapping and configuration handling

This commit is contained in:
Barış Hamil 2026-02-15 14:15:37 +03:00
parent 2af6fe0524
commit 6a3a77f188
7 changed files with 38 additions and 122 deletions

View file

@ -237,24 +237,24 @@ bool usb_device_guncon3::handle_wiimote(GunCon3_data& gc)
if (!ws.connected)
return false;
const auto map = wm->get_mapping();
const auto& map = get_wiimote_config().guncon_mapping;
const auto is_pressed = [&](wiimote_button btn) { return (ws.buttons & static_cast<u16>(btn)) != 0; };
if (is_pressed(map.trigger)) gc.btn_trigger = 1;
if (is_pressed(map.trigger.get())) 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;
if (is_pressed(map.a1.get())) gc.btn_a1 = 1;
if (is_pressed(map.a2.get())) gc.btn_a2 = 1;
if (is_pressed(map.a3.get())) gc.btn_a3 = 1;
if (is_pressed(map.b1.get())) gc.btn_b1 = 1;
if (is_pressed(map.b2.get())) gc.btn_b2 = 1;
if (is_pressed(map.b3.get())) gc.btn_b3 = 1;
if (is_pressed(map.c1.get())) gc.btn_c1 = 1;
if (is_pressed(map.c2.get())) 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 (is_pressed(map.b1_alt.get())) gc.btn_b1 = 1;
if (is_pressed(map.b2_alt.get())) gc.btn_b2 = 1;
if (ws.ir[0].x < 1023)
{

View file

@ -44,14 +44,14 @@ bool cfg_wiimote::load()
{
if (fs::file f{path, fs::read})
{
return this->cfg::node::from_string(f.to_string());
return cfg::node::from_string(f.to_string());
}
return false;
}
void cfg_wiimote::save() const
{
if (!this->cfg::node::save(path))
if (!cfg::node::save(path))
{
wiimote_log.error("Failed to save wiimote config to '%s'", path);
}

View file

@ -11,9 +11,9 @@ struct cfg_wiimote : cfg::node
cfg::_bool use_for_guncon{ this, "UseForGunCon", true };
struct node_mapping : cfg::node
struct node_guncon_mapping : cfg::node
{
node_mapping(cfg::node* _parent) : cfg::node(_parent, "Mapping") {}
node_guncon_mapping(cfg::node* _parent) : cfg::node(_parent, "GunCon Mapping") {}
cfg::_enum<wiimote_button> trigger{ this, "Trigger", wiimote_button::B };
cfg::_enum<wiimote_button> a1{ this, "A1", wiimote_button::A };
@ -27,7 +27,7 @@ struct cfg_wiimote : cfg::node
cfg::_enum<wiimote_button> b1_alt{ this, "B1_Alt", wiimote_button::Up };
cfg::_enum<wiimote_button> b2_alt{ this, "B2_Alt", wiimote_button::Down };
} mapping{ this };
} guncon_mapping{ this };
const std::string path;
};

View file

@ -207,46 +207,6 @@ bool wiimote_device::update()
static wiimote_handler* s_instance = nullptr;
void wiimote_handler::load_config()
{
auto& cfg = get_wiimote_config();
if (cfg.load())
{
std::unique_lock lock(m_mutex);
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();
}
}
void wiimote_handler::save_config()
{
{
std::shared_lock lock(m_mutex);
auto& cfg = get_wiimote_config();
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();
}
wiimote_handler::wiimote_handler()
{
if (!s_instance)
@ -258,7 +218,7 @@ wiimote_handler::wiimote_handler()
m_devices.push_back(std::make_unique<wiimote_device>());
}
load_config();
get_wiimote_config().load();
}
wiimote_handler::~wiimote_handler()
@ -304,21 +264,6 @@ usz wiimote_handler::get_device_count()
return m_devices.size();
}
void wiimote_handler::set_mapping(const wiimote_guncon_mapping& mapping)
{
{
std::unique_lock lock(m_mutex);
m_mapping = mapping;
}
save_config();
}
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_state> wiimote_handler::get_states()
{
std::shared_lock lock(m_mutex);

View file

@ -65,17 +65,11 @@ public:
std::vector<wiimote_state> get_states();
usz get_device_count();
void set_mapping(const wiimote_guncon_mapping& mapping);
wiimote_guncon_mapping get_mapping() const;
private:
std::unique_ptr<named_thread<std::function<void()>>> m_thread;
atomic_t<bool> m_running{false};
std::vector<std::unique_ptr<wiimote_device>> m_devices;
shared_mutex m_mutex;
wiimote_guncon_mapping m_mapping {};
void thread_proc();
void load_config();
void save_config();
};

View file

@ -27,19 +27,3 @@ enum class wiimote_button : u16
Minus = 0x1000,
Home = 0x8000
};
struct wiimote_guncon_mapping
{
wiimote_button trigger = wiimote_button::B;
wiimote_button a1 = wiimote_button::A;
wiimote_button a2 = wiimote_button::Minus;
wiimote_button a3 = wiimote_button::Left;
wiimote_button b1 = wiimote_button::One;
wiimote_button b2 = wiimote_button::Two;
wiimote_button b3 = wiimote_button::Home;
wiimote_button c1 = wiimote_button::Plus;
wiimote_button c2 = wiimote_button::Right;
wiimote_button b1_alt = wiimote_button::Up;
wiimote_button b2_alt = wiimote_button::Down;
};

View file

@ -23,12 +23,16 @@ wiimote_settings_dialog::wiimote_settings_dialog(QWidget* parent)
connect(ui->useForGunCon, &QCheckBox::toggled, this, [](bool checked)
{
get_wiimote_config().use_for_guncon.set(checked);
get_wiimote_config().save();
});
update_list();
connect(ui->buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, this, &wiimote_settings_dialog::restore_defaults);
connect(this, &QDialog::finished, this, []()
{
get_wiimote_config().save();
});
// Timer updates both state AND device list (auto-refresh)
QTimer* timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &wiimote_settings_dialog::update_state);
@ -40,8 +44,7 @@ wiimote_settings_dialog::wiimote_settings_dialog(QWidget* parent)
void wiimote_settings_dialog::populate_mappings()
{
auto* wm = wiimote_handler::get_instance();
if (!wm) return;
const auto& cfg = get_wiimote_config().guncon_mapping;
const std::array<std::pair<QString, wiimote_button>, 12> buttons = {
{ { tr("None"), wiimote_button::None },
@ -58,10 +61,9 @@ void wiimote_settings_dialog::populate_mappings()
{ tr("D-Pad Right"), wiimote_button::Right } }
};
wiimote_guncon_mapping current = wm->get_mapping();
const std::array<wiimote_button*, 9> targets = {
&current.trigger, &current.a1, &current.a2, &current.c1,
&current.b1, &current.b2, &current.b3, &current.a3, &current.c2
const std::array<wiimote_button, 9> targets = {
cfg.trigger.get(), cfg.a1.get(), cfg.a2.get(), cfg.c1.get(),
cfg.b1.get(), cfg.b2.get(), cfg.b3.get(), cfg.a3.get(), cfg.c2.get()
};
ensure(m_boxes.size() == targets.size());
@ -76,7 +78,7 @@ void wiimote_settings_dialog::populate_mappings()
}
// Set current selection
const int index = m_boxes[i]->findData(QVariant::fromValue(static_cast<u16>(*targets[i])));
const int index = m_boxes[i]->findData(QVariant::fromValue(static_cast<u16>(targets[i])));
if (index >= 0) m_boxes[i]->setCurrentIndex(index);
// Connect change signal
@ -89,22 +91,18 @@ void wiimote_settings_dialog::populate_mappings()
void wiimote_settings_dialog::restore_defaults()
{
auto* wm = wiimote_handler::get_instance();
if (!wm) return;
// Reset to default mapping
const wiimote_guncon_mapping default_map {};
wm->set_mapping(default_map);
get_wiimote_config().from_default();
get_wiimote_config().use_for_guncon.set(true);
ui->useForGunCon->setChecked(true);
ui->useForGunCon->setChecked(get_wiimote_config().use_for_guncon.get());
// Update UI
for (auto* box : m_boxes) box->blockSignals(true);
const auto& cfg = get_wiimote_config().guncon_mapping;
const std::array<wiimote_button, 9> targets = {
default_map.trigger, default_map.a1, default_map.a2, default_map.c1,
default_map.b1, default_map.b2, default_map.b3, default_map.a3, default_map.c2
cfg.trigger.get(), cfg.a1.get(), cfg.a2.get(), cfg.c1.get(),
cfg.b1.get(), cfg.b2.get(), cfg.b3.get(), cfg.a3.get(), cfg.c2.get()
};
ensure(m_boxes.size() == targets.size());
@ -120,23 +118,18 @@ void wiimote_settings_dialog::restore_defaults()
void wiimote_settings_dialog::apply_mappings()
{
auto* wm = wiimote_handler::get_instance();
if (!wm) return;
wiimote_guncon_mapping map {};
const std::array<wiimote_button*, 9> targets = {
&map.trigger, &map.a1, &map.a2, &map.c1,
&map.b1, &map.b2, &map.b3, &map.a3, &map.c2
auto& cfg = get_wiimote_config().guncon_mapping;
const std::array<cfg::_enum<wiimote_button>*, 9> targets = {
&cfg.trigger, &cfg.a1, &cfg.a2, &cfg.c1,
&cfg.b1, &cfg.b2, &cfg.b3, &cfg.a3, &cfg.c2
};
ensure(m_boxes.size() == targets.size());
for (usz i = 0; i < m_boxes.size(); ++i)
{
*targets[i] = static_cast<wiimote_button>(m_boxes[i]->currentData().toUInt());
targets[i]->set(static_cast<wiimote_button>(m_boxes[i]->currentData().toUInt()));
}
wm->set_mapping(map);
}
void wiimote_settings_dialog::update_state()