From 6428088e467c9bf16953d1c83f45d51b582b3cc7 Mon Sep 17 00:00:00 2001 From: trigger <5994581+cipherxof@users.noreply.github.com> Date: Fri, 2 May 2025 22:35:45 -0700 Subject: [PATCH 1/2] Qt: "Show in Memory Viewer" context action (#17131) --- rpcs3/rpcs3qt/cheat_manager.cpp | 8 ++++ rpcs3/rpcs3qt/debugger_frame.cpp | 40 +++++++++++++++++- rpcs3/rpcs3qt/debugger_frame.h | 2 + rpcs3/rpcs3qt/hex_validator.h | 20 +++++++++ rpcs3/rpcs3qt/log_frame.cpp | 23 ++++++++++ rpcs3/rpcs3qt/log_frame.h | 1 + rpcs3/rpcs3qt/memory_viewer_panel.cpp | 60 +++++++++++++++++++++++++++ rpcs3/rpcs3qt/memory_viewer_panel.h | 12 ++++++ 8 files changed, 165 insertions(+), 1 deletion(-) diff --git a/rpcs3/rpcs3qt/cheat_manager.cpp b/rpcs3/rpcs3qt/cheat_manager.cpp index 5724999771..8f4d82d9c9 100644 --- a/rpcs3/rpcs3qt/cheat_manager.cpp +++ b/rpcs3/rpcs3qt/cheat_manager.cpp @@ -7,6 +7,7 @@ #include #include "cheat_manager.h" +#include "memory_viewer_panel.h" #include "Emu/System.h" #include "Emu/Memory/vm.h" @@ -829,6 +830,7 @@ cheat_manager_dialog::cheat_manager_dialog(QWidget* parent) QMenu* menu = new QMenu(); QAction* add_to_cheat_list = new QAction(tr("Add to cheat list"), menu); + QAction* show_in_mem_viewer = new QAction(tr("Show in Memory Viewer"), menu); const u32 offset = offsets_found[current_row]; const cheat_type type = static_cast(cbx_cheat_search_type->currentIndex()); @@ -849,7 +851,13 @@ cheat_manager_dialog::cheat_manager_dialog(QWidget* parent) update_cheat_list(); }); + connect(show_in_mem_viewer, &QAction::triggered, this, [offset]() + { + memory_viewer_panel::ShowAtPC(offset); + }); + menu->addAction(add_to_cheat_list); + menu->addAction(show_in_mem_viewer); menu->exec(globalPos); }); diff --git a/rpcs3/rpcs3qt/debugger_frame.cpp b/rpcs3/rpcs3qt/debugger_frame.cpp index 2136c6c9bd..502a01dc09 100644 --- a/rpcs3/rpcs3qt/debugger_frame.cpp +++ b/rpcs3/rpcs3qt/debugger_frame.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include @@ -125,7 +127,8 @@ debugger_frame::debugger_frame(std::shared_ptr gui_settings, QWidg m_regs = new QPlainTextEdit(this); m_regs->setLineWrapMode(QPlainTextEdit::NoWrap); m_regs->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); - + m_regs->setContextMenuPolicy(Qt::CustomContextMenu); + m_debugger_list->setFont(m_mono); m_misc_state->setFont(m_mono); m_regs->setFont(m_mono); @@ -158,6 +161,8 @@ debugger_frame::debugger_frame(std::shared_ptr gui_settings, QWidg body->setLayout(vbox_p_main); setWidget(body); + connect(m_regs, &QPlainTextEdit::customContextMenuRequested, this, &debugger_frame::OnRegsContextMenu); + connect(m_go_to_addr, &QAbstractButton::clicked, this, &debugger_frame::ShowGotoAddressDialog); connect(m_go_to_pc, &QAbstractButton::clicked, this, [this]() { ShowPC(true); }); @@ -1702,3 +1707,36 @@ void debugger_frame::EnableButtons(bool enable) m_btn_step_over->setEnabled(step); m_btn_run->setEnabled(enable); } + +void debugger_frame::OnRegsContextMenu(const QPoint& pos) +{ + QMenu* menu = m_regs->createStandardContextMenu(); + QAction* memory_viewer_action = new QAction(tr("Show in Memory Viewer"), menu); + + connect(memory_viewer_action, &QAction::triggered, this, &debugger_frame::RegsShowMemoryViewerAction); + + menu->addSeparator(); + menu->addAction(memory_viewer_action); + menu->exec(m_regs->mapToGlobal(pos)); +} + +void debugger_frame::RegsShowMemoryViewerAction() +{ + const QTextCursor cursor = m_regs->textCursor(); + if (!cursor.hasSelection()) + { + QMessageBox::warning(this, tr("No Selection"), tr("Please select a hex value first.")); + return; + } + + const QTextDocumentFragment frag(cursor); + const QString selected = frag.toPlainText().trimmed(); + u64 pc = 0; + if (!parse_hex_qstring(selected, &pc)) + { + QMessageBox::critical(this, tr("Invalid Hex"), tr("“%0” is not a valid 32-bit hex value.").arg(selected)); + return; + } + + memory_viewer_panel::ShowAtPC(static_cast(pc), make_check_cpu(get_cpu())); +} diff --git a/rpcs3/rpcs3qt/debugger_frame.h b/rpcs3/rpcs3qt/debugger_frame.h index 46df22e3c8..6837347c3f 100644 --- a/rpcs3/rpcs3qt/debugger_frame.h +++ b/rpcs3/rpcs3qt/debugger_frame.h @@ -137,9 +137,11 @@ public Q_SLOTS: private Q_SLOTS: void OnSelectUnit(); void OnSelectSPUDisassembler(); + void OnRegsContextMenu(const QPoint& pos); void ShowPC(bool user_requested = false); void EnableUpdateTimer(bool enable) const; void RunBtnPress(); + void RegsShowMemoryViewerAction(); }; Q_DECLARE_METATYPE(u32) diff --git a/rpcs3/rpcs3qt/hex_validator.h b/rpcs3/rpcs3qt/hex_validator.h index 68af698bfb..e11624483d 100644 --- a/rpcs3/rpcs3qt/hex_validator.h +++ b/rpcs3/rpcs3qt/hex_validator.h @@ -69,3 +69,23 @@ inline QString normalize_hex_qstring(const QString& input) s.chop(1); return s; } + +inline bool parse_hex_qstring(const QString& input, u64* result, int max_bits = 32) +{ + QString s = input; + int pos = 0; + const HexValidator validator(nullptr, max_bits); + const QValidator::State st = validator.validate(s, pos); + + if (st != QValidator::Acceptable) + return false; + + const QString norm = normalize_hex_qstring(input); + bool ok = false; + const quint64 value = norm.toULongLong(&ok, 16); + + if (ok && result) + *result = static_cast(value); + + return ok; +} diff --git a/rpcs3/rpcs3qt/log_frame.cpp b/rpcs3/rpcs3qt/log_frame.cpp index 50ddb13f1c..fd294553ff 100644 --- a/rpcs3/rpcs3qt/log_frame.cpp +++ b/rpcs3/rpcs3qt/log_frame.cpp @@ -1,6 +1,8 @@ #include "log_frame.h" #include "qt_utils.h" #include "gui_settings.h" +#include "hex_validator.h" +#include "memory_viewer_panel.h" #include "Utilities/lockless.h" #include "util/asm.hpp" @@ -250,6 +252,21 @@ void log_frame::CreateAndConnectActions() Q_EMIT PerformGoToOnDebugger(pte->textCursor().selectedText(), true); }); + m_perform_show_in_mem_viewer = new QAction(tr("Show in Memory Viewer"), this); + connect(m_perform_show_in_mem_viewer, &QAction::triggered, this, [this]() + { + const QPlainTextEdit* pte = (m_tabWidget->currentIndex() == 1 ? m_tty : m_log); + const QString selected = pte->textCursor().selectedText(); + u64 pc = 0; + if (!parse_hex_qstring(selected, &pc)) + { + QMessageBox::critical(this, tr("Invalid Hex"), tr("“%0” is not a valid 32-bit hex value.").arg(selected)); + return; + } + + memory_viewer_panel::ShowAtPC(static_cast(pc)); + }); + m_perform_goto_thread_on_debugger = new QAction(tr("Show Thread On The Debugger"), this); connect(m_perform_goto_thread_on_debugger, &QAction::triggered, [this]() { @@ -354,13 +371,16 @@ void log_frame::CreateAndConnectActions() menu->addAction(m_clear_act); menu->addAction(m_perform_goto_on_debugger); menu->addAction(m_perform_goto_thread_on_debugger); + menu->addAction(m_perform_show_in_mem_viewer); std::shared_ptr goto_signal_accepted = std::make_shared(false); Q_EMIT PerformGoToOnDebugger("", true, true, goto_signal_accepted); m_perform_goto_on_debugger->setEnabled(m_log->textCursor().hasSelection() && *goto_signal_accepted); m_perform_goto_thread_on_debugger->setEnabled(m_log->textCursor().hasSelection() && *goto_signal_accepted); + m_perform_show_in_mem_viewer->setEnabled(m_log->textCursor().hasSelection() && *goto_signal_accepted); m_perform_goto_on_debugger->setToolTip(tr("Jump to the selected hexadecimal address from the log text on the debugger.")); m_perform_goto_thread_on_debugger->setToolTip(tr("Show the thread that corresponds to the thread ID from the log text on the debugger.")); + m_perform_show_in_mem_viewer->setToolTip(tr("Jump to the selected hexadecimal address from the log text on the memory viewer.")); menu->addSeparator(); menu->addActions(m_log_level_acts->actions()); @@ -376,11 +396,14 @@ void log_frame::CreateAndConnectActions() QMenu* menu = m_tty->createStandardContextMenu(); menu->addAction(m_clear_tty_act); menu->addAction(m_perform_goto_on_debugger); + menu->addAction(m_perform_show_in_mem_viewer); std::shared_ptr goto_signal_accepted = std::make_shared(false); Q_EMIT PerformGoToOnDebugger("", false, true, goto_signal_accepted); m_perform_goto_on_debugger->setEnabled(m_tty->textCursor().hasSelection() && *goto_signal_accepted); + m_perform_show_in_mem_viewer->setEnabled(m_tty->textCursor().hasSelection() && *goto_signal_accepted); m_perform_goto_on_debugger->setToolTip(tr("Jump to the selected hexadecimal address from the TTY text on the debugger.")); + m_perform_show_in_mem_viewer->setToolTip(tr("Jump to the selected hexadecimal address from the TTY text on the memory viewer.")); menu->addSeparator(); menu->addAction(m_tty_act); diff --git a/rpcs3/rpcs3qt/log_frame.h b/rpcs3/rpcs3qt/log_frame.h index 7909990c27..0de081863c 100644 --- a/rpcs3/rpcs3qt/log_frame.h +++ b/rpcs3/rpcs3qt/log_frame.h @@ -74,6 +74,7 @@ private: QAction* m_clear_tty_act = nullptr; QAction* m_perform_goto_on_debugger = nullptr; QAction* m_perform_goto_thread_on_debugger = nullptr; + QAction* m_perform_show_in_mem_viewer = nullptr; QActionGroup* m_log_level_acts = nullptr; QAction* m_nothing_act = nullptr; diff --git a/rpcs3/rpcs3qt/memory_viewer_panel.cpp b/rpcs3/rpcs3qt/memory_viewer_panel.cpp index 8905744e77..392b3e0385 100644 --- a/rpcs3/rpcs3qt/memory_viewer_panel.cpp +++ b/rpcs3/rpcs3qt/memory_viewer_panel.cpp @@ -9,6 +9,7 @@ #include "Emu/RSX/RSXThread.h" #include "Emu/RSX/rsx_utils.h" #include "Emu/IdManager.h" +#include "Emu/System.h" #include #include #include @@ -25,6 +26,7 @@ #include "util/logs.hpp" #include "util/asm.hpp" +#include "debugger_frame.h" LOG_CHANNEL(gui_log, "GUI"); @@ -589,6 +591,24 @@ memory_viewer_panel::memory_viewer_panel(QWidget* parent, std::shared_ptr(id, handle_ptr); }); + + if (!g_fxo->try_get()) + { + g_fxo->init(); + } + + auto& fxo = g_fxo->get(); + fxo.last_opened[m_type] = this; + + connect(this, &memory_viewer_panel::destroyed, this, [this]() + { + if (auto fxo = g_fxo->try_get()) + { + auto it = fxo->last_opened.find(m_type); + if (it != fxo->last_opened.end() && it->second == this) + fxo->last_opened.erase(it); + } + }); } memory_viewer_panel::~memory_viewer_panel() @@ -1244,3 +1264,43 @@ void memory_viewer_panel::ShowImage(QWidget* parent, u32 addr, color_format form f_image_viewer->setFixedSize(f_image_viewer->sizeHint()); }); } + +void memory_viewer_panel::ShowAtPC(u32 pc, std::function func) +{ + if (Emu.IsStopped()) + return; + + cpu_thread* cpu = func ? func() : nullptr; + thread_class type = cpu ? cpu->get_class() : thread_class::ppu; + + if (type == thread_class::spu) + { + idm::make(nullptr, nullptr, pc, std::move(func)); + return; + } + + if (const auto* fxo = g_fxo->try_get()) + { + auto it = fxo->last_opened.find(type); + + if (it != fxo->last_opened.end()) + { + memory_viewer_panel* panel = it->second; + + if (panel) + { + panel->SetPC(pc); + panel->scroll(0); + + if (!panel->isVisible()) + panel->show(); + + panel->raise(); + + return; + } + } + } + + idm::make(nullptr, nullptr, pc, std::move(func)); +} diff --git a/rpcs3/rpcs3qt/memory_viewer_panel.h b/rpcs3/rpcs3qt/memory_viewer_panel.h index dc59247991..756323be97 100644 --- a/rpcs3/rpcs3qt/memory_viewer_panel.h +++ b/rpcs3/rpcs3qt/memory_viewer_panel.h @@ -10,6 +10,7 @@ #include #include +#include class QLineEdit; class QCheckBox; @@ -55,6 +56,8 @@ public: memory_viewer_panel(QWidget* parent, std::shared_ptr disasm, u32 addr = 0, std::function func = []() -> cpu_thread* { return {}; }); ~memory_viewer_panel(); + static void ShowAtPC(u32 pc, std::function func = nullptr); + enum class color_format : int { RGB, @@ -137,3 +140,12 @@ struct memory_viewer_handle private: const std::add_pointer_t m_mvp; }; + +struct memory_viewer_fxo +{ + std::map last_opened; + + memory_viewer_fxo() = default; + memory_viewer_fxo(const memory_viewer_fxo&) = delete; + memory_viewer_fxo& operator=(const memory_viewer_fxo&) = delete; +}; From 75b728be7e45847c3a787247024b5f9f011bd41c Mon Sep 17 00:00:00 2001 From: Megamouse Date: Sat, 3 May 2025 10:42:08 +0200 Subject: [PATCH 2/2] Logitech G27 cleanup --- rpcs3/Emu/Io/LogitechG27.cpp | 711 +++++++------- rpcs3/Emu/Io/LogitechG27.h | 113 ++- rpcs3/Emu/Io/LogitechG27Config.cpp | 38 +- rpcs3/Emu/Io/LogitechG27Config.h | 88 +- .../emulated_logitech_g27_settings_dialog.cpp | 868 ++++++++---------- .../emulated_logitech_g27_settings_dialog.h | 25 +- 6 files changed, 886 insertions(+), 957 deletions(-) diff --git a/rpcs3/Emu/Io/LogitechG27.cpp b/rpcs3/Emu/Io/LogitechG27.cpp index 21171e4c71..af6e89e350 100644 --- a/rpcs3/Emu/Io/LogitechG27.cpp +++ b/rpcs3/Emu/Io/LogitechG27.cpp @@ -25,7 +25,7 @@ usb_device_logitech_g27::usb_device_logitech_g27(u32 controller_index, const std device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, UsbDeviceDescriptor{0x0200, 0, 0, 0, 16, 0x046d, 0xc29b, 0x1350, 1, 2, 0, 1}); // parse the raw response like with passthrough device - static const uint8_t raw_config[] = {0x9, 0x2, 0x29, 0x0, 0x1, 0x1, 0x4, 0x80, 0x31, 0x9, 0x4, 0x0, 0x0, 0x2, 0x3, 0x0, 0x0, 0x0, 0x9, 0x21, 0x11, 0x1, 0x21, 0x1, 0x22, 0x85, 0x0, 0x7, 0x5, 0x81, 0x3, 0x10, 0x0, 0x2, 0x7, 0x5, 0x1, 0x3, 0x10, 0x0, 0x2}; + static constexpr u8 raw_config[] = {0x9, 0x2, 0x29, 0x0, 0x1, 0x1, 0x4, 0x80, 0x31, 0x9, 0x4, 0x0, 0x0, 0x2, 0x3, 0x0, 0x0, 0x0, 0x9, 0x21, 0x11, 0x1, 0x21, 0x1, 0x22, 0x85, 0x0, 0x7, 0x5, 0x81, 0x3, 0x10, 0x0, 0x2, 0x7, 0x5, 0x1, 0x3, 0x10, 0x0, 0x2}; auto& conf = device.add_node(UsbDescriptorNode(raw_config[0], raw_config[1], &raw_config[2])); for (unsigned int index = raw_config[0]; index < sizeof(raw_config);) { @@ -33,21 +33,14 @@ usb_device_logitech_g27::usb_device_logitech_g27(u32 controller_index, const std index += raw_config[index]; } - // Initialize effect slots - for (int i = 0; i < 4; i++) - { - m_effect_slots[i].state = G27_FFB_INACTIVE; - m_effect_slots[i].effect_id = -1; - } - - SDL_HapticDirection direction = { - .type = SDL_HAPTIC_POLAR, - .dir = {27000, 0}}; m_default_spring_effect.type = SDL_HAPTIC_SPRING; - m_default_spring_effect.condition.direction = direction; + m_default_spring_effect.condition.direction = SDL_HapticDirection + { + .type = SDL_HAPTIC_POLAR, + .dir = {27000, 0} + }; m_default_spring_effect.condition.length = SDL_HAPTIC_INFINITY; - // for (int i = 0;i < 3;i++) - for (int i = 0; i < 1; i++) + for (int i = 0; i < 1 /*3*/; i++) { m_default_spring_effect.condition.right_sat[i] = 0x7FFF; m_default_spring_effect.condition.left_sat[i] = 0x7FFF; @@ -55,35 +48,21 @@ usb_device_logitech_g27::usb_device_logitech_g27(u32 controller_index, const std m_default_spring_effect.condition.left_coeff[i] = 0x7FFF; } - { - const std::lock_guard lock(m_thread_control_mutex); - m_stop_thread = false; - } - g_cfg_logitech_g27.load(); - bool sdl_init_state = sdl_instance::get_instance().initialize(); - - m_enabled = g_cfg_logitech_g27.enabled.get() && sdl_init_state; + m_enabled = g_cfg_logitech_g27.enabled.get() && sdl_instance::get_instance().initialize(); if (!m_enabled) return; m_house_keeping_thread = std::thread([this]() + { + while (!m_stop_thread) { - while (true) - { - this->m_thread_control_mutex.lock(); - if (this->m_stop_thread) - { - break; - } - this->m_thread_control_mutex.unlock(); - this->sdl_refresh(); - std::this_thread::sleep_for(std::chrono::seconds(5)); - } - this->m_thread_control_mutex.unlock(); - }); + sdl_refresh(); + std::this_thread::sleep_for(std::chrono::seconds(5)); + } + }); } bool usb_device_logitech_g27::open_device() @@ -91,40 +70,38 @@ bool usb_device_logitech_g27::open_device() return m_enabled; } -static void clear_sdl_joysticks(std::map>& joysticks) +static void clear_sdl_joysticks(std::map>& joystick_map) { - for (auto joystick_type : joysticks) + for (auto& [type, joysticks] : joystick_map) { - for (auto joystick : joystick_type.second) + for (SDL_Joystick* joystick : joysticks) { if (joystick) SDL_CloseJoystick(joystick); } } - joysticks.clear(); + joystick_map.clear(); } usb_device_logitech_g27::~usb_device_logitech_g27() { // stop the house keeping thread - { - const std::lock_guard lock(m_thread_control_mutex); - m_stop_thread = true; - } + m_stop_thread = true; + + // wait for the house keeping thread to finish + if (m_house_keeping_thread.joinable()) + m_house_keeping_thread.join(); // Close sdl handles { - const std::lock_guard lock(m_sdl_handles_mutex); - if (m_haptic_handle != nullptr) + const std::lock_guard lock(m_sdl_handles_mutex); + if (m_haptic_handle) { SDL_CloseHaptic(m_haptic_handle); + m_haptic_handle = nullptr; } clear_sdl_joysticks(m_joysticks); } - - // wait for the house keeping thread to finish - if (m_enabled) - m_house_keeping_thread.join(); } std::shared_ptr usb_device_logitech_g27::make_instance(u32 controller_index, const std::array& location) @@ -148,35 +125,29 @@ void usb_device_logitech_g27::control_transfer(u8 bmRequestType, u8 bRequest, u1 usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer); } -static bool sdl_joysticks_equal(std::map>& left, std::map>& right) +static bool sdl_joysticks_equal(std::map>& left, std::map>& right) { if (left.size() != right.size()) { return false; } - for (auto left_joysticks_of_type : left) + for (const auto& [left_type, left_joysticks] : left) { - auto right_joysticks_of_type = right.find(left_joysticks_of_type.first); - if (right_joysticks_of_type == right.end()) + const auto right_joysticks = right.find(left_type); + if (right_joysticks == right.cend()) { return false; } - if (left_joysticks_of_type.second.size() != right_joysticks_of_type->second.size()) + if (left_joysticks.size() != right_joysticks->second.size()) { return false; } - for (auto left_joystick : left_joysticks_of_type.second) + for (const SDL_Joystick* left_joystick : left_joysticks) { - bool found = false; - for (auto right_joystick : right_joysticks_of_type->second) - { - if (left_joystick == right_joystick) + if (std::none_of(right_joysticks->second.begin(), right_joysticks->second.end(), [left_joystick](const SDL_Joystick* right_joystick) { - found = true; - break; - } - } - if (!found) + return left_joystick == right_joystick; + })) { return false; } @@ -187,100 +158,100 @@ static bool sdl_joysticks_equal(std::map>& static inline logitech_g27_sdl_mapping get_runtime_mapping() { - logitech_g27_sdl_mapping mapping; + logitech_g27_sdl_mapping mapping {}; -#define CONVERT_MAPPING(name) \ - { \ - mapping.name.device_type_id = g_cfg_logitech_g27.name.device_type_id.get(); \ - mapping.name.type = static_cast(g_cfg_logitech_g27.name.type.get()); \ - mapping.name.id = static_cast(g_cfg_logitech_g27.name.id.get()); \ - mapping.name.hat = static_cast(g_cfg_logitech_g27.name.hat.get()); \ - mapping.name.reverse = g_cfg_logitech_g27.name.reverse.get(); \ - mapping.name.positive_axis = false; \ - } + const auto convert_mapping = [](const emulated_logitech_g27_mapping& cfg, sdl_mapping& mapping) + { + mapping.device_type_id = cfg.device_type_id.get(); + mapping.type = cfg.type.get(); + mapping.id = cfg.id.get(); + mapping.hat = cfg.hat.get(); + mapping.reverse = cfg.reverse.get(); + mapping.positive_axis = false; + }; - CONVERT_MAPPING(steering); - CONVERT_MAPPING(throttle); - CONVERT_MAPPING(brake); - CONVERT_MAPPING(clutch); - CONVERT_MAPPING(shift_up); - CONVERT_MAPPING(shift_down); + const auto& cfg = g_cfg_logitech_g27; - CONVERT_MAPPING(up); - CONVERT_MAPPING(down); - CONVERT_MAPPING(left); - CONVERT_MAPPING(right); + convert_mapping(cfg.steering, mapping.steering); + convert_mapping(cfg.throttle, mapping.throttle); + convert_mapping(cfg.brake, mapping.brake); + convert_mapping(cfg.clutch, mapping.clutch); + convert_mapping(cfg.shift_up, mapping.shift_up); + convert_mapping(cfg.shift_down, mapping.shift_down); - CONVERT_MAPPING(triangle); - CONVERT_MAPPING(cross); - CONVERT_MAPPING(square); - CONVERT_MAPPING(circle); + convert_mapping(cfg.up, mapping.up); + convert_mapping(cfg.down, mapping.down); + convert_mapping(cfg.left, mapping.left); + convert_mapping(cfg.right, mapping.right); - CONVERT_MAPPING(l2); - CONVERT_MAPPING(l3); - CONVERT_MAPPING(r2); - CONVERT_MAPPING(r3); + convert_mapping(cfg.triangle, mapping.triangle); + convert_mapping(cfg.cross, mapping.cross); + convert_mapping(cfg.square, mapping.square); + convert_mapping(cfg.circle, mapping.circle); - CONVERT_MAPPING(plus); - CONVERT_MAPPING(minus); + convert_mapping(cfg.l2, mapping.l2); + convert_mapping(cfg.l3, mapping.l3); + convert_mapping(cfg.r2, mapping.r2); + convert_mapping(cfg.r3, mapping.r3); - CONVERT_MAPPING(dial_clockwise); - CONVERT_MAPPING(dial_anticlockwise); + convert_mapping(cfg.plus, mapping.plus); + convert_mapping(cfg.minus, mapping.minus); - CONVERT_MAPPING(select); - CONVERT_MAPPING(pause); + convert_mapping(cfg.dial_clockwise, mapping.dial_clockwise); + convert_mapping(cfg.dial_anticlockwise, mapping.dial_anticlockwise); - CONVERT_MAPPING(shifter_1); - CONVERT_MAPPING(shifter_2); - CONVERT_MAPPING(shifter_3); - CONVERT_MAPPING(shifter_4); - CONVERT_MAPPING(shifter_5); - CONVERT_MAPPING(shifter_6); - CONVERT_MAPPING(shifter_r); + convert_mapping(cfg.select, mapping.select); + convert_mapping(cfg.pause, mapping.pause); -#undef CONVERT_MAPPING + convert_mapping(cfg.shifter_1, mapping.shifter_1); + convert_mapping(cfg.shifter_2, mapping.shifter_2); + convert_mapping(cfg.shifter_3, mapping.shifter_3); + convert_mapping(cfg.shifter_4, mapping.shifter_4); + convert_mapping(cfg.shifter_5, mapping.shifter_5); + convert_mapping(cfg.shifter_6, mapping.shifter_6); + convert_mapping(cfg.shifter_r, mapping.shifter_r); return mapping; } void usb_device_logitech_g27::sdl_refresh() { - g_cfg_logitech_g27.m_mutex.lock(); + std::unique_lock lock(g_cfg_logitech_g27.m_mutex); + m_mapping = get_runtime_mapping(); m_reverse_effects = g_cfg_logitech_g27.reverse_effects.get(); - uint32_t ffb_vendor_id = g_cfg_logitech_g27.ffb_device_type_id.get() >> 16; - uint32_t ffb_product_id = g_cfg_logitech_g27.ffb_device_type_id.get() & 0xFFFF; + const u32 ffb_vendor_id = g_cfg_logitech_g27.ffb_device_type_id.get() >> 16; + const u32 ffb_product_id = g_cfg_logitech_g27.ffb_device_type_id.get() & 0xFFFF; - uint32_t led_vendor_id = g_cfg_logitech_g27.led_device_type_id.get() >> 16; - uint32_t led_product_id = g_cfg_logitech_g27.led_device_type_id.get() & 0xFFFF; - g_cfg_logitech_g27.m_mutex.unlock(); + const u32 led_vendor_id = g_cfg_logitech_g27.led_device_type_id.get() >> 16; + const u32 led_product_id = g_cfg_logitech_g27.led_device_type_id.get() & 0xFFFF; + + lock.unlock(); SDL_Joystick* new_led_joystick_handle = nullptr; SDL_Haptic* new_haptic_handle = nullptr; - std::map> new_joysticks; + std::map> new_joysticks; - int joystick_count; - SDL_JoystickID* joystick_ids = SDL_GetJoysticks(&joystick_count); - if (joystick_ids != nullptr) + int joystick_count = 0; + if (SDL_JoystickID* joystick_ids = SDL_GetJoysticks(&joystick_count)) { for (int i = 0; i < joystick_count; i++) { SDL_Joystick* cur_joystick = SDL_OpenJoystick(joystick_ids[i]); - if (cur_joystick == nullptr) + if (!cur_joystick) { logitech_g27_log.error("Failed opening joystick %d, %s", joystick_ids[i], SDL_GetError()); continue; } - uint16_t cur_vendor_id = SDL_GetJoystickVendor(cur_joystick); - uint16_t cur_product_id = SDL_GetJoystickProduct(cur_joystick); - uint32_t joystick_type_id = (cur_vendor_id << 16) | cur_product_id; + const u16 cur_vendor_id = SDL_GetJoystickVendor(cur_joystick); + const u16 cur_product_id = SDL_GetJoystickProduct(cur_joystick); + const u32 joystick_type_id = (cur_vendor_id << 16) | cur_product_id; auto joysticks_of_type = new_joysticks.find(joystick_type_id); if (joysticks_of_type == new_joysticks.end()) { - std::vector joystick_group = {cur_joystick}; - new_joysticks[joystick_type_id] = joystick_group; + new_joysticks[joystick_type_id] = { cur_joystick }; } else { @@ -312,9 +283,9 @@ void usb_device_logitech_g27::sdl_refresh() logitech_g27_log.error("Failed fetching joystick list, %s", SDL_GetError()); } - bool joysticks_changed = !sdl_joysticks_equal(m_joysticks, new_joysticks); - bool haptic_changed = m_haptic_handle != new_haptic_handle; - bool led_joystick_changed = m_led_joystick_handle != new_led_joystick_handle; + const bool joysticks_changed = !sdl_joysticks_equal(m_joysticks, new_joysticks); + const bool haptic_changed = m_haptic_handle != new_haptic_handle; + const bool led_joystick_changed = m_led_joystick_handle != new_led_joystick_handle; // if we should touch the mutex if (joysticks_changed || haptic_changed || led_joystick_changed) @@ -329,10 +300,13 @@ void usb_device_logitech_g27::sdl_refresh() if (haptic_changed) { if (m_haptic_handle) - SDL_CloseHaptic(m_haptic_handle); - for (int i = 0; i < 4; i++) { - m_effect_slots[i].effect_id = -1; + SDL_CloseHaptic(m_haptic_handle); + m_haptic_handle = nullptr; + } + for (logitech_g27_ffb_slot& slot : m_effect_slots) + { + slot.effect_id = -1; } m_default_spring_effect_id = -1; m_led_joystick_handle = new_led_joystick_handle; @@ -356,7 +330,7 @@ void usb_device_logitech_g27::sdl_refresh() } } -static inline int16_t logitech_g27_force_to_level(uint8_t force) +static inline s16 logitech_g27_force_to_level(u8 force) { if (force == 127 || force == 128) { @@ -369,29 +343,29 @@ static inline int16_t logitech_g27_force_to_level(uint8_t force) return ((127 - force) * 0x7FFF * -1) / (127 - 0); } -static inline int16_t logitech_g27_position_to_center(uint8_t left, uint8_t right) +static inline s16 logitech_g27_position_to_center(u8 left, u8 right) { - uint16_t center_unsigned = (((right + left) * 0xFFFF) / 255) / 2; + const u16 center_unsigned = (((right + left) * 0xFFFF) / 255) / 2; return center_unsigned - 0x8000; } -static inline int16_t logitech_g27_high_resolution_position_to_center(uint16_t left, uint16_t right) +static inline s16 logitech_g27_high_resolution_position_to_center(u16 left, u16 right) { - uint16_t center_unsigned = (((right + left) * 0xFFFF) / (0xFFFF >> 5)) / 2; + const u16 center_unsigned = (((right + left) * 0xFFFF) / (0xFFFF >> 5)) / 2; return center_unsigned - 0x8000; } -static inline uint16_t logitech_g27_position_to_width(uint8_t left, uint8_t right) +static inline u16 logitech_g27_position_to_width(u8 left, u8 right) { return ((right - left) * 0xFFFF) / 255; } -static inline uint16_t logitech_g27_high_resolution_position_to_width(uint16_t left, uint16_t right) +static inline u16 logitech_g27_high_resolution_position_to_width(u16 left, u16 right) { return ((right - left) * 0xFFFF) / (0xFFFF >> 5); } -static inline int16_t logitech_g27_coeff_to_coeff(uint8_t coeff, uint8_t invert) +static inline s16 logitech_g27_coeff_to_coeff(u8 coeff, u8 invert) { if (!invert) { @@ -400,7 +374,7 @@ static inline int16_t logitech_g27_coeff_to_coeff(uint8_t coeff, uint8_t invert) return (coeff * 0x7FFF * -1) / 7; } -static inline int16_t logitech_g27_high_resolution_coeff_to_coeff(uint8_t coeff, uint8_t invert) +static inline s16 logitech_g27_high_resolution_coeff_to_coeff(u8 coeff, u8 invert) { if (!invert) { @@ -409,7 +383,7 @@ static inline int16_t logitech_g27_high_resolution_coeff_to_coeff(uint8_t coeff, return (coeff * 0x7FFF * -1) / 15; } -static inline int16_t logitech_g27_friction_coeff_to_coeff(uint8_t coeff, uint8_t invert) +static inline s16 logitech_g27_friction_coeff_to_coeff(u8 coeff, u8 invert) { if (!invert) { @@ -418,17 +392,17 @@ static inline int16_t logitech_g27_friction_coeff_to_coeff(uint8_t coeff, uint8_ return (coeff * 0x7FFF * -1) / 255; } -static inline int16_t logitech_g27_clip_to_saturation(uint8_t clip) +static inline s16 logitech_g27_clip_to_saturation(u8 clip) { return (clip * 0x7FFF) / 255; } -static inline int16_t logitech_g27_amplitude_to_magnitude(uint8_t amplitude) +static inline s16 logitech_g27_amplitude_to_magnitude(u8 amplitude) { return ((amplitude * 0x7FFF) / 2) / 255; } -static inline uint16_t logitech_g27_loops_to_ms(uint16_t loops, bool afap) +static inline u16 logitech_g27_loops_to_ms(u16 loops, bool afap) { if (afap) { @@ -437,21 +411,21 @@ static inline uint16_t logitech_g27_loops_to_ms(uint16_t loops, bool afap) return loops * 2; } -static inline uint16_t axis_to_logitech_g27_steering(int16_t axis) +static inline u16 axis_to_logitech_g27_steering(s16 axis) { - uint16_t unsigned_axis = axis + 0x8000; + const u16 unsigned_axis = axis + 0x8000; return (unsigned_axis * (0xFFFF >> 2)) / 0xFFFF; } -static inline uint8_t axis_to_logitech_g27_pedal(int16_t axis) +static inline u8 axis_to_logitech_g27_pedal(s16 axis) { - uint16_t unsigned_axis = axis + 0x8000; + const u16 unsigned_axis = axis + 0x8000; return (unsigned_axis * (0xFF)) / 0xFFFF; } extern bool is_input_allowed(); -static uint8_t sdl_hat_to_logitech_g27_hat(uint8_t sdl_hat) +static u8 sdl_hat_to_logitech_g27_hat(u8 sdl_hat) { switch (sdl_hat) { @@ -473,21 +447,23 @@ static uint8_t sdl_hat_to_logitech_g27_hat(uint8_t sdl_hat) return 6; case SDL_HAT_LEFTUP: return 7; + default: + break; } return 0; } -static uint8_t hat_components_to_logitech_g27_hat(bool up, bool down, bool left, bool right) +static u8 hat_components_to_logitech_g27_hat(bool up, bool down, bool left, bool right) { - uint8_t sdl_hat = 0; + u8 sdl_hat = 0; if (up) - sdl_hat = sdl_hat | SDL_HAT_UP; + sdl_hat |= SDL_HAT_UP; if (down) - sdl_hat = sdl_hat | SDL_HAT_DOWN; + sdl_hat |= SDL_HAT_DOWN; if (left) - sdl_hat = sdl_hat | SDL_HAT_LEFT; + sdl_hat |= SDL_HAT_LEFT; if (right) - sdl_hat = sdl_hat | SDL_HAT_RIGHT; + sdl_hat |= SDL_HAT_RIGHT; return sdl_hat_to_logitech_g27_hat(sdl_hat); } @@ -495,37 +471,37 @@ static bool fetch_sdl_as_button(SDL_Joystick* joystick, const sdl_mapping& mappi { switch (mapping.type) { - case MAPPING_BUTTON: + case sdl_mapping_type::button: { - bool pressed = SDL_GetJoystickButton(joystick, mapping.id); + const bool pressed = SDL_GetJoystickButton(joystick, static_cast(mapping.id)); return mapping.reverse ? !pressed : pressed; } - case MAPPING_HAT: + case sdl_mapping_type::hat: { - uint8_t hat_value = SDL_GetJoystickHat(joystick, mapping.id); + const u8 hat_value = SDL_GetJoystickHat(joystick, static_cast(mapping.id)); bool pressed = false; switch (mapping.hat) { - case HAT_UP: + case hat_component::up: pressed = (hat_value & SDL_HAT_UP) ? true : false; break; - case HAT_DOWN: + case hat_component::down: pressed = (hat_value & SDL_HAT_DOWN) ? true : false; break; - case HAT_LEFT: + case hat_component::left: pressed = (hat_value & SDL_HAT_LEFT) ? true : false; break; - case HAT_RIGHT: + case hat_component::right: pressed = (hat_value & SDL_HAT_RIGHT) ? true : false; break; - case HAT_NONE: + case hat_component::none: break; } return mapping.reverse ? !pressed : pressed; } - case MAPPING_AXIS: + case sdl_mapping_type::axis: { - int32_t axis_value = SDL_GetJoystickAxis(joystick, mapping.id); + const s32 axis_value = SDL_GetJoystickAxis(joystick, static_cast(mapping.id)); bool pressed = false; if (mapping.positive_axis) { @@ -541,73 +517,67 @@ static bool fetch_sdl_as_button(SDL_Joystick* joystick, const sdl_mapping& mappi return false; } -static int16_t fetch_sdl_as_axis(SDL_Joystick* joystick, const sdl_mapping& mapping) +static s16 fetch_sdl_as_axis(SDL_Joystick* joystick, const sdl_mapping& mapping) { - const static int16_t MAX = 0x7FFF; - const static int16_t MIN = -0x8000; - const static int16_t MID = 0; + constexpr s16 MAX = 0x7FFF; + constexpr s16 MIN = -0x8000; + constexpr s16 MID = 0; switch (mapping.type) { - case MAPPING_BUTTON: + case sdl_mapping_type::button: { - bool pressed = SDL_GetJoystickButton(joystick, mapping.id); + bool pressed = SDL_GetJoystickButton(joystick, static_cast(mapping.id)); if (mapping.reverse) { pressed = !pressed; } - int16_t pressed_value = mapping.positive_axis ? MAX : MIN; - return pressed ? pressed_value : MID; + return pressed ? (mapping.positive_axis ? MAX : MIN) : MID; } - case MAPPING_HAT: + case sdl_mapping_type::hat: { - uint8_t hat_value = SDL_GetJoystickHat(joystick, mapping.id); + const u8 hat_value = SDL_GetJoystickHat(joystick, static_cast(mapping.id)); bool pressed = false; switch (mapping.hat) { - case HAT_UP: + case hat_component::up: pressed = (hat_value & SDL_HAT_UP) ? true : false; break; - case HAT_DOWN: + case hat_component::down: pressed = (hat_value & SDL_HAT_DOWN) ? true : false; break; - case HAT_LEFT: + case hat_component::left: pressed = (hat_value & SDL_HAT_LEFT) ? true : false; break; - case HAT_RIGHT: + case hat_component::right: pressed = (hat_value & SDL_HAT_RIGHT) ? true : false; break; - case HAT_NONE: + case hat_component::none: break; } if (mapping.reverse) { pressed = !pressed; } - int16_t pressed_value = mapping.positive_axis ? MAX : MIN; - return pressed ? pressed_value : MID; + return pressed ? (mapping.positive_axis ? MAX : MIN) : MID; } - case MAPPING_AXIS: + case sdl_mapping_type::axis: { - int32_t axis_value = SDL_GetJoystickAxis(joystick, mapping.id); + s32 axis_value = SDL_GetJoystickAxis(joystick, static_cast(mapping.id)); if (mapping.reverse) - axis_value = axis_value * (-1); - if (axis_value > MAX) - axis_value = MAX; - if (axis_value < MIN) - axis_value = MIN; + axis_value *= -1; if (axis_value == (MIN + 1)) axis_value = MIN; - return axis_value; + return std::clamp(axis_value, MIN, MAX); } } return 0; } -static int16_t fetch_sdl_axis_avg(std::map>& joysticks, const sdl_mapping& mapping) +static s16 fetch_sdl_axis_avg(std::map>& joysticks, const sdl_mapping& mapping) { - const static int16_t MAX = 0x7FFF; - const static int16_t MIN = -0x8000; + constexpr s16 MAX = 0x7FFF; + constexpr s16 MIN = -0x8000; auto joysticks_of_type = joysticks.find(mapping.device_type_id); if (joysticks_of_type == joysticks.end()) @@ -615,22 +585,22 @@ static int16_t fetch_sdl_axis_avg(std::map> return mapping.reverse ? MAX : MIN; } - if (joysticks_of_type->second.size() == 0) + if (joysticks_of_type->second.empty()) { return mapping.reverse ? MAX : MIN; } // TODO account for deadzone and only pick up active devices - int32_t sdl_joysticks_total_value = 0; - for (auto joystick : joysticks_of_type->second) + s32 sdl_joysticks_total_value = 0; + for (SDL_Joystick* joystick : joysticks_of_type->second) { sdl_joysticks_total_value += fetch_sdl_as_axis(joystick, mapping); } - return sdl_joysticks_total_value / joysticks_of_type->second.size(); + return std::clamp(sdl_joysticks_total_value / static_cast(joysticks_of_type->second.size()), MIN, MAX); } -static bool sdl_to_logitech_g27_button(std::map>& joysticks, const sdl_mapping& mapping) +static bool sdl_to_logitech_g27_button(std::map>& joysticks, const sdl_mapping& mapping) { auto joysticks_of_type = joysticks.find(mapping.device_type_id); if (joysticks_of_type == joysticks.end()) @@ -638,38 +608,38 @@ static bool sdl_to_logitech_g27_button(std::mapsecond.size() == 0) + if (joysticks_of_type->second.empty()) { return mapping.reverse; } bool pressed = false; - for (auto joystick : joysticks_of_type->second) + for (SDL_Joystick* joystick : joysticks_of_type->second) { - pressed = pressed || fetch_sdl_as_button(joystick, mapping); + pressed |= fetch_sdl_as_button(joystick, mapping); } return pressed; } -static uint16_t sdl_to_logitech_g27_steering(std::map>& joysticks, const sdl_mapping& mapping) +static u16 sdl_to_logitech_g27_steering(std::map>& joysticks, const sdl_mapping& mapping) { - int16_t avg = fetch_sdl_axis_avg(joysticks, mapping); - uint16_t unsigned_avg = avg + 0x8000; + const s16 avg = fetch_sdl_axis_avg(joysticks, mapping); + const u16 unsigned_avg = avg + 0x8000; return unsigned_avg * (0xFFFF >> 2) / 0xFFFF; } -static uint8_t sdl_to_logitech_g27_pedal(std::map>& joysticks, const sdl_mapping& mapping) +static u8 sdl_to_logitech_g27_pedal(std::map>& joysticks, const sdl_mapping& mapping) { - int16_t avg = fetch_sdl_axis_avg(joysticks, mapping); - uint16_t unsigned_avg = avg + 0x8000; + const s16 avg = fetch_sdl_axis_avg(joysticks, mapping); + const u16 unsigned_avg = avg + 0x8000; return unsigned_avg * 0xFF / 0xFFFF; } -static inline void set_bit(uint8_t* buf, int bit_num, bool set) +static inline void set_bit(u8* buf, int bit_num, bool set) { - int byte_num = bit_num / 8; - bit_num = bit_num % 8; - uint8_t mask = 1 << bit_num; + const int byte_num = bit_num / 8; + bit_num %= 8; + const u8 mask = 1 << bit_num; if (set) buf[byte_num] = buf[byte_num] | mask; else @@ -690,6 +660,7 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp logitech_g27_log.error("Not populating input buffer with a buffer of the size of %u", buf_size); return; } + ensure(buf_size >= 11); memset(buf, 0, buf_size); @@ -699,44 +670,44 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp // Fetch input states from SDL m_sdl_handles_mutex.lock(); - uint16_t steering = sdl_to_logitech_g27_steering(m_joysticks, m_mapping.steering); - uint8_t throttle = sdl_to_logitech_g27_pedal(m_joysticks, m_mapping.throttle); - uint8_t brake = sdl_to_logitech_g27_pedal(m_joysticks, m_mapping.brake); - uint8_t clutch = sdl_to_logitech_g27_pedal(m_joysticks, m_mapping.clutch); - bool shift_up = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shift_up); - bool shift_down = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shift_down); + const u16 steering = sdl_to_logitech_g27_steering(m_joysticks, m_mapping.steering); + const u8 throttle = sdl_to_logitech_g27_pedal(m_joysticks, m_mapping.throttle); + const u8 brake = sdl_to_logitech_g27_pedal(m_joysticks, m_mapping.brake); + const u8 clutch = sdl_to_logitech_g27_pedal(m_joysticks, m_mapping.clutch); + const bool shift_up = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shift_up); + const bool shift_down = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shift_down); - bool up = sdl_to_logitech_g27_button(m_joysticks, m_mapping.up); - bool down = sdl_to_logitech_g27_button(m_joysticks, m_mapping.down); - bool left = sdl_to_logitech_g27_button(m_joysticks, m_mapping.left); - bool right = sdl_to_logitech_g27_button(m_joysticks, m_mapping.right); + const bool up = sdl_to_logitech_g27_button(m_joysticks, m_mapping.up); + const bool down = sdl_to_logitech_g27_button(m_joysticks, m_mapping.down); + const bool left = sdl_to_logitech_g27_button(m_joysticks, m_mapping.left); + const bool right = sdl_to_logitech_g27_button(m_joysticks, m_mapping.right); - bool triangle = sdl_to_logitech_g27_button(m_joysticks, m_mapping.triangle); - bool cross = sdl_to_logitech_g27_button(m_joysticks, m_mapping.cross); - bool square = sdl_to_logitech_g27_button(m_joysticks, m_mapping.square); - bool circle = sdl_to_logitech_g27_button(m_joysticks, m_mapping.circle); + const bool triangle = sdl_to_logitech_g27_button(m_joysticks, m_mapping.triangle); + const bool cross = sdl_to_logitech_g27_button(m_joysticks, m_mapping.cross); + const bool square = sdl_to_logitech_g27_button(m_joysticks, m_mapping.square); + const bool circle = sdl_to_logitech_g27_button(m_joysticks, m_mapping.circle); - bool l2 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.l2); - bool l3 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.l3); - bool r2 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.r2); - bool r3 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.r3); + const bool l2 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.l2); + const bool l3 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.l3); + const bool r2 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.r2); + const bool r3 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.r3); - bool plus = sdl_to_logitech_g27_button(m_joysticks, m_mapping.plus); - bool minus = sdl_to_logitech_g27_button(m_joysticks, m_mapping.minus); + const bool plus = sdl_to_logitech_g27_button(m_joysticks, m_mapping.plus); + const bool minus = sdl_to_logitech_g27_button(m_joysticks, m_mapping.minus); - bool dial_clockwise = sdl_to_logitech_g27_button(m_joysticks, m_mapping.dial_clockwise); - bool dial_anticlockwise = sdl_to_logitech_g27_button(m_joysticks, m_mapping.dial_anticlockwise); + const bool dial_clockwise = sdl_to_logitech_g27_button(m_joysticks, m_mapping.dial_clockwise); + const bool dial_anticlockwise = sdl_to_logitech_g27_button(m_joysticks, m_mapping.dial_anticlockwise); - bool select = sdl_to_logitech_g27_button(m_joysticks, m_mapping.select); - bool pause = sdl_to_logitech_g27_button(m_joysticks, m_mapping.pause); + const bool select = sdl_to_logitech_g27_button(m_joysticks, m_mapping.select); + const bool pause = sdl_to_logitech_g27_button(m_joysticks, m_mapping.pause); - bool shifter_1 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_1); - bool shifter_2 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_2); - bool shifter_3 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_3); - bool shifter_4 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_4); - bool shifter_5 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_5); - bool shifter_6 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_6); - bool shifter_r = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_r); + const bool shifter_1 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_1); + const bool shifter_2 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_2); + const bool shifter_3 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_3); + const bool shifter_4 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_4); + const bool shifter_5 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_5); + const bool shifter_6 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_6); + const bool shifter_r = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_r); m_sdl_handles_mutex.unlock(); // populate buffer @@ -797,19 +768,7 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp // Sending data to wheel if (buf_size < 7) { - char* hex_buf = reinterpret_cast(malloc(buf_size * 3 + 1)); - if (hex_buf == nullptr) - { - logitech_g27_log.error("Unhandled wheel command with size %u != 16", buf_size); - return; - } - int offset = 0; - for (uint32_t i = 0; i < buf_size; i++) - { - offset += sprintf(&hex_buf[offset], "%02x ", buf[i]); - } - logitech_g27_log.error("Unhandled wheel command with size %u != 16, %s", buf_size, hex_buf); - free(hex_buf); + logitech_g27_log.error("Unhandled wheel command with size %u != 16, %s", buf_size, fmt::buf_to_hexstring(buf, buf_size)); return; } @@ -820,7 +779,8 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp SDL_HapticDirection direction = { .type = SDL_HAPTIC_POLAR, - .dir = {27000, 0}}; + .dir = {27000, 0} + }; if (m_reverse_effects) { direction.dir[0] = 9000; @@ -831,7 +791,7 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp // Process effects if (buf[0] == 0xf8) { - const std::lock_guard lock(m_sdl_handles_mutex); + const std::lock_guard lock(m_sdl_handles_mutex); switch (buf[1]) { case 0x01: @@ -886,13 +846,13 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp break; } // Mux into total amount of bulbs on, since sdl only takes intensity - uint8_t new_led_level = 0; + u8 new_led_level = 0; for (int i = 0; i < 5; i++) { new_led_level += (buf[2] & (1 << i)) ? 1 : 0; } - uint8_t intensity = new_led_level * 255 / 5; + const u8 intensity = new_led_level * 255 / 5; SDL_SetJoystickLED(m_led_joystick_handle, intensity, intensity, intensity); break; } @@ -912,9 +872,9 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp } else { - const std::lock_guard lock(m_sdl_handles_mutex); - uint8_t cmd = buf[0] & 0xf; - uint8_t slot_mask = buf[0] >> 4; + const std::lock_guard lock(m_sdl_handles_mutex); + const u8 cmd = buf[0] & 0xf; + const u8 slot_mask = buf[0] >> 4; switch (cmd) { case 0x00: @@ -924,13 +884,13 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp // Download/Download play/Refresh for (int i = 0; i < 4; i++) { - SDL_HapticEffect new_effect = {0}; - // hack: need to reduce Download play spams for some drivers - bool update_hack = false; if (!(slot_mask & (1 << i))) { continue; } + SDL_HapticEffect new_effect {}; + // hack: need to reduce Download play spams for some drivers + bool update_hack = false; bool unknown_effect = false; switch (buf[1]) { @@ -950,20 +910,20 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp new_effect.type = SDL_HAPTIC_SPRING; new_effect.condition.direction = direction; new_effect.condition.length = SDL_HAPTIC_INFINITY; - uint8_t s1 = buf[5] & 1; - uint8_t s2 = (buf[5] >> 4) & 1; + const u8 s1 = buf[5] & 1; + const u8 s2 = (buf[5] >> 4) & 1; // TODO direction cfg - uint16_t saturation = logitech_g27_clip_to_saturation(buf[6]); - int16_t center = 0; - uint16_t deadband = 0; - int16_t left_coeff = 0; - int16_t right_coeff = 0; + const u16 saturation = logitech_g27_clip_to_saturation(buf[6]); + s16 center = 0; + u16 deadband = 0; + s16 left_coeff = 0; + s16 right_coeff = 0; if (buf[1] == 0x01) { - uint8_t d1 = buf[2]; - uint8_t d2 = buf[3]; - uint8_t k1 = buf[4] & (0xf >> 1); - uint8_t k2 = (buf[4] >> 4) & (0xf >> 1); + const u8 d1 = buf[2]; + const u8 d2 = buf[3]; + const u8 k1 = buf[4] & (0xf >> 1); + const u8 k2 = (buf[4] >> 4) & (0xf >> 1); center = logitech_g27_position_to_center(d1, d2); deadband = logitech_g27_position_to_width(d1, d2); left_coeff = logitech_g27_coeff_to_coeff(k1, s1); @@ -971,10 +931,10 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp } else { - uint16_t d1 = (buf[2] << 3) | ((buf[5] >> 1) & (0xf >> 1)); - uint16_t d2 = (buf[3] << 3) | (buf[5] >> 5); - uint8_t k1 = buf[4] & 0xf; - uint8_t k2 = buf[4] >> 4; + const u16 d1 = (buf[2] << 3) | ((buf[5] >> 1) & (0xf >> 1)); + const u16 d2 = (buf[3] << 3) | (buf[5] >> 5); + const u8 k1 = buf[4] & 0xf; + const u8 k2 = buf[4] >> 4; center = logitech_g27_high_resolution_position_to_center(d1, d2); deadband = logitech_g27_high_resolution_position_to_width(d1, d2); left_coeff = logitech_g27_high_resolution_coeff_to_coeff(k1, s1); @@ -982,12 +942,9 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp } if (m_reverse_effects) { - int16_t coeff = right_coeff; - right_coeff = left_coeff; - left_coeff = coeff; + std::swap(left_coeff, right_coeff); } - // for(int j = 0;j < 3;j++) - for (int j = 0; j < 1; j++) + for (int j = 0; j < 1 /*3*/; j++) { new_effect.condition.right_sat[j] = saturation; new_effect.condition.left_sat[j] = saturation; @@ -1005,35 +962,32 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp new_effect.type = SDL_HAPTIC_DAMPER; new_effect.condition.direction = direction; new_effect.condition.length = SDL_HAPTIC_INFINITY; - uint8_t s1 = buf[3] & 1; - uint8_t s2 = buf[5] & 1; + const u8 s1 = buf[3] & 1; + const u8 s2 = buf[5] & 1; // TODO direction cfg - uint16_t saturation = 0x7FFF; - int16_t left_coeff = 0; - int16_t right_coeff = 0; + u16 saturation = 0x7FFF; + s16 left_coeff = 0; + s16 right_coeff = 0; if (buf[1] == 0x02) { - uint8_t k1 = buf[2] & (0xf >> 1); - uint8_t k2 = buf[4] & (0xf >> 1); + const u8 k1 = buf[2] & (0xf >> 1); + const u8 k2 = buf[4] & (0xf >> 1); left_coeff = logitech_g27_coeff_to_coeff(k1, s1); right_coeff = logitech_g27_coeff_to_coeff(k2, s2); } else { - uint8_t k1 = buf[2] & 0xf; - uint8_t k2 = buf[4] & 0xf; + const u8 k1 = buf[2] & 0xf; + const u8 k2 = buf[4] & 0xf; left_coeff = logitech_g27_high_resolution_coeff_to_coeff(k1, s1); right_coeff = logitech_g27_high_resolution_coeff_to_coeff(k2, s2); saturation = logitech_g27_clip_to_saturation(buf[6]); } if (m_reverse_effects) { - int16_t coeff = right_coeff; - right_coeff = left_coeff; - left_coeff = coeff; + std::swap(left_coeff, right_coeff); } - // for(int j = 0;j < 3;j++) - for (int j = 0; j < 1; j++) + for (int j = 0; j < 1 /*3*/; j++) { new_effect.condition.right_sat[j] = saturation; new_effect.condition.left_sat[j] = saturation; @@ -1048,22 +1002,19 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp new_effect.type = SDL_HAPTIC_FRICTION; new_effect.condition.direction = direction; new_effect.condition.length = SDL_HAPTIC_INFINITY; - uint8_t k1 = buf[2]; - uint8_t k2 = buf[3]; - uint8_t s1 = buf[5] & 1; - uint8_t s2 = (buf[5] >> 4) & 1; + const u8 k1 = buf[2]; + const u8 k2 = buf[3]; + const u8 s1 = buf[5] & 1; + const u8 s2 = (buf[5] >> 4) & 1; // TODO direction cfg - int16_t left_coeff = logitech_g27_friction_coeff_to_coeff(k1, s1); - int16_t right_coeff = logitech_g27_friction_coeff_to_coeff(k2, s2); - int16_t saturation = logitech_g27_clip_to_saturation(buf[4]); + s16 left_coeff = logitech_g27_friction_coeff_to_coeff(k1, s1); + s16 right_coeff = logitech_g27_friction_coeff_to_coeff(k2, s2); + const s16 saturation = logitech_g27_clip_to_saturation(buf[4]); if (m_reverse_effects) { - int16_t coeff = right_coeff; - right_coeff = left_coeff; - left_coeff = coeff; + std::swap(left_coeff, right_coeff); } - // for(int j = 0;j < 3;j++) - for (int j = 0; j < 1; j++) + for (int j = 0; j < 1 /*3*/; j++) { new_effect.condition.right_sat[j] = saturation; new_effect.condition.left_sat[j] = saturation; @@ -1080,33 +1031,30 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp new_effect.condition.direction = direction; new_effect.condition.length = SDL_HAPTIC_INFINITY; // TODO direction cfg - uint16_t saturation = logitech_g27_clip_to_saturation(buf[4]); - uint16_t deadband = 2 * 0xFFFF / 255; - int16_t center = 0; - int16_t left_coeff = 0; - int16_t right_coeff = 0; + const u16 saturation = logitech_g27_clip_to_saturation(buf[4]); + const u16 deadband = 2 * 0xFFFF / 255; + s16 center = 0; + s16 left_coeff = 0; + s16 right_coeff = 0; if (buf[1] == 0x03) { - uint8_t k1 = buf[2] & (0xf >> 1); - uint8_t k2 = buf[3] & (0xf >> 1); + const u8 k1 = buf[2] & (0xf >> 1); + const u8 k2 = buf[3] & (0xf >> 1); left_coeff = logitech_g27_coeff_to_coeff(k1, 0); right_coeff = logitech_g27_coeff_to_coeff(k2, 0); } else { - uint8_t k1 = buf[2] & 0xf; - uint8_t k2 = buf[3] & 0xf; + const u8 k1 = buf[2] & 0xf; + const u8 k2 = buf[3] & 0xf; left_coeff = logitech_g27_high_resolution_coeff_to_coeff(k1, 0); right_coeff = logitech_g27_high_resolution_coeff_to_coeff(k2, 0); } if (m_reverse_effects) { - int16_t coeff = right_coeff; - right_coeff = left_coeff; - left_coeff = coeff; + std::swap(left_coeff, right_coeff); } - // for(int j = 0;j < 3;j++) - for (int j = 0; j < 1; j++) + for (int j = 0; j < 1 /*3*/; j++) { new_effect.condition.right_sat[j] = saturation; new_effect.condition.left_sat[j] = saturation; @@ -1124,11 +1072,11 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp new_effect.type = buf[1] == 0x04 ? SDL_HAPTIC_SAWTOOTHUP : SDL_HAPTIC_SAWTOOTHDOWN; new_effect.periodic.direction = direction; new_effect.periodic.length = SDL_HAPTIC_INFINITY; - uint8_t l1 = buf[2]; - uint8_t l2 = buf[3]; - uint8_t l0 = buf[4]; - uint8_t t3 = buf[6] >> 4; - uint8_t inc = buf[6] & 0xf; + const u8 l1 = buf[2]; + const u8 l2 = buf[3]; + const u8 l0 = buf[4]; + const u8 t3 = buf[6] >> 4; + const u8 inc = buf[6] & 0xf; if (inc != 0) new_effect.periodic.period = ((l1 - l2) * logitech_g27_loops_to_ms(t3, !m_fixed_loop)) / inc; else @@ -1146,14 +1094,14 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp // Trapezoid, convert to SDL_HAPTIC_SQUARE or SDL_HAPTIC_TRIANGLE new_effect.periodic.direction = direction; new_effect.periodic.length = SDL_HAPTIC_INFINITY; - uint8_t l1 = buf[2]; - uint8_t l2 = buf[3]; - uint8_t t1 = buf[4]; - uint8_t t2 = buf[5]; - uint8_t t3 = buf[6] >> 4; - uint8_t s = buf[6] & 0xf; - uint16_t total_flat_time = logitech_g27_loops_to_ms(t1 + t2, !m_fixed_loop); - uint16_t total_slope_time = (((l1 - l2) * logitech_g27_loops_to_ms(t3, !m_fixed_loop)) / s) * 2; + const u8 l1 = buf[2]; + const u8 l2 = buf[3]; + const u8 t1 = buf[4]; + const u8 t2 = buf[5]; + const u8 t3 = buf[6] >> 4; + const u8 s = buf[6] & 0xf; + const u16 total_flat_time = logitech_g27_loops_to_ms(t1 + t2, !m_fixed_loop); + const u16 total_slope_time = (((l1 - l2) * logitech_g27_loops_to_ms(t3, !m_fixed_loop)) / s) * 2; if (total_flat_time > total_slope_time) { new_effect.type = SDL_HAPTIC_SQUARE; @@ -1173,11 +1121,11 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp new_effect.type = SDL_HAPTIC_SQUARE; new_effect.periodic.direction = direction; new_effect.periodic.length = SDL_HAPTIC_INFINITY; - uint8_t l1 = buf[2]; - uint8_t l2 = buf[3]; - uint8_t t1 = buf[4]; - uint8_t t2 = buf[5]; - uint8_t p = buf[6]; + const u8 l1 = buf[2]; + const u8 l2 = buf[3]; + const u8 t1 = buf[4]; + const u8 t2 = buf[5]; + const u8 p = buf[6]; new_effect.periodic.period = logitech_g27_loops_to_ms(t1, !m_fixed_loop) + logitech_g27_loops_to_ms(t2, !m_fixed_loop); new_effect.periodic.offset = logitech_g27_force_to_level((l1 + l2) / 2); new_effect.periodic.magnitude = logitech_g27_force_to_level(l1) - new_effect.periodic.offset; @@ -1200,20 +1148,20 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp } new_effect.type = SDL_HAPTIC_CONSTANT; new_effect.constant.direction = direction; - uint8_t l1 = buf[2]; - uint8_t l2 = buf[3]; - uint8_t t1 = buf[4] >> 4; - uint8_t s1 = buf[4] & 0xf; - uint8_t t2 = buf[5] >> 4; - uint8_t s2 = buf[5] & 0xf; - uint8_t d1 = buf[6] & 1; - uint8_t d2 = (buf[6] >> 4) & 1; + const u8 l1 = buf[2]; + const u8 l2 = buf[3]; + const u8 t1 = buf[4] >> 4; + const u8 s1 = buf[4] & 0xf; + const u8 t2 = buf[5] >> 4; + const u8 s2 = buf[5] & 0xf; + const u8 d1 = buf[6] & 1; + const u8 d2 = (buf[6] >> 4) & 1; if (buf[1] == 0x08) { - uint8_t t = i == 0 ? t1 : t2; - uint8_t s = i == 0 ? s1 : s2; - uint8_t d = i == 0 ? d1 : d2; - uint8_t l = i == 0 ? l1 : l2; + const u8 t = i == 0 ? t1 : t2; + const u8 s = i == 0 ? s1 : s2; + const u8 d = i == 0 ? d1 : d2; + const u8 l = i == 0 ? l1 : l2; new_effect.constant.length = SDL_HAPTIC_INFINITY; if (s == 0 || t == 0) { @@ -1258,11 +1206,11 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp // Square new_effect.type = SDL_HAPTIC_SQUARE; new_effect.periodic.direction = direction; - uint8_t a = buf[2]; - uint8_t tl = buf[3]; - uint8_t th = buf[4]; - uint8_t n = buf[5]; - uint16_t t = (th << 8) | tl; + const u8 a = buf[2]; + const u8 tl = buf[3]; + const u8 th = buf[4]; + const u8 n = buf[5]; + const u16 t = (th << 8) | tl; new_effect.periodic.period = logitech_g27_loops_to_ms(t * 2, !m_fixed_loop); new_effect.periodic.magnitude = logitech_g27_amplitude_to_magnitude(a); if (n == 0) @@ -1274,6 +1222,7 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp default: { unknown_effect = true; + break; } } @@ -1283,7 +1232,7 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp continue; } - bool play_effect = (cmd == 0x01 || (cmd == 0x0c && m_effect_slots[i].effect_id == -1)); + const bool play_effect = (cmd == 0x01 || (cmd == 0x0c && m_effect_slots[i].effect_id == -1)); if (update_hack) { @@ -1295,12 +1244,12 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp if (cmd == 0x00 || play_effect) { - if (m_effect_slots[i].effect_id != -1 && m_haptic_handle != nullptr && !update_hack) + if (m_effect_slots[i].effect_id != -1 && m_haptic_handle && !update_hack) { SDL_DestroyHapticEffect(m_haptic_handle, m_effect_slots[i].effect_id); m_effect_slots[i].effect_id = -1; } - if (m_haptic_handle != nullptr && m_effect_slots[i].effect_id == -1) + if (m_haptic_handle && m_effect_slots[i].effect_id == -1) { m_effect_slots[i].effect_id = SDL_CreateHapticEffect(m_haptic_handle, &new_effect); } @@ -1309,15 +1258,15 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp if (!SDL_UpdateHapticEffect(m_haptic_handle, m_effect_slots[i].effect_id, &new_effect)) logitech_g27_log.error("Failed refreshing slot %d sdl effect %d, %s", i, new_effect.type, SDL_GetError()); } - m_effect_slots[i].state = G27_FFB_DOWNLOADED; + m_effect_slots[i].state = logitech_g27_ffb_state::downloaded; m_effect_slots[i].last_effect = new_effect; m_effect_slots[i].last_update = SDL_GetTicks(); - if (m_effect_slots[i].effect_id == -1 && m_haptic_handle != nullptr) + if (m_effect_slots[i].effect_id == -1 && m_haptic_handle) { logitech_g27_log.error("Failed uploading effect %02x %02x %02x %02x %02x %02x %02x to slot %i, %s", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], i, SDL_GetError()); } } - if (play_effect && m_haptic_handle != nullptr) + if (play_effect && m_haptic_handle) { if (m_effect_slots[i].effect_id != -1) { @@ -1330,9 +1279,9 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp { logitech_g27_log.error("Tried to play effect slot %d with sdl effect %d, but upload failed previously", i, m_effect_slots[i].last_effect.type); } - m_effect_slots[i].state = G27_FFB_PLAYING; + m_effect_slots[i].state = logitech_g27_ffb_state::playing; } - if (cmd == 0xc && !play_effect && m_haptic_handle != nullptr) + if (cmd == 0xc && !play_effect && m_haptic_handle) { if (!SDL_UpdateHapticEffect(m_haptic_handle, m_effect_slots[i].effect_id, &new_effect)) { @@ -1352,9 +1301,9 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp { continue; } - if (m_effect_slots[i].state == G27_FFB_PLAYING || m_effect_slots[i].state == G27_FFB_DOWNLOADED) + if (m_effect_slots[i].state == logitech_g27_ffb_state::playing || m_effect_slots[i].state == logitech_g27_ffb_state::downloaded) { - m_effect_slots[i].state = cmd == 0x02 ? G27_FFB_PLAYING : G27_FFB_DOWNLOADED; + m_effect_slots[i].state = cmd == 0x02 ? logitech_g27_ffb_state::playing : logitech_g27_ffb_state::downloaded; if (m_haptic_handle != nullptr) { if (m_effect_slots[i].effect_id == -1) @@ -1408,21 +1357,18 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp case 0x0e: { // Set Default Spring - uint8_t k1 = buf[2] & (0xf >> 1); - uint8_t k2 = buf[3] & (0xf >> 1); - uint16_t saturation = logitech_g27_clip_to_saturation(buf[4]); - int16_t left_coeff = logitech_g27_coeff_to_coeff(k1, 0); - int16_t right_coeff = logitech_g27_coeff_to_coeff(k2, 0); - uint16_t deadband = 2 * 0xFFFF / 255; - int16_t center = 0; + const u8 k1 = buf[2] & (0xf >> 1); + const u8 k2 = buf[3] & (0xf >> 1); + const u16 saturation = logitech_g27_clip_to_saturation(buf[4]); + s16 left_coeff = logitech_g27_coeff_to_coeff(k1, 0); + s16 right_coeff = logitech_g27_coeff_to_coeff(k2, 0); + const u16 deadband = 2 * 0xFFFF / 255; + s16 center = 0; if (m_reverse_effects) { - int16_t coeff = right_coeff; - right_coeff = left_coeff; - left_coeff = coeff; + std::swap(left_coeff, right_coeff); } - // for (int i = 0;i < 3;i++){ - for (int i = 0; i < 1; i++) + for (int i = 0; i < 1 /*3*/; i++) { // TODO direction cfg m_default_spring_effect.condition.right_sat[i] = saturation; @@ -1505,12 +1451,12 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp break; } - uint8_t new_led_level = 0; + u8 new_led_level = 0; for (int i = 0; i < 8; i++) { new_led_level += (buf[1] & (1 << i)) ? 1 : 0; } - uint8_t intensity = new_led_level * 255 / 7; + const u8 intensity = new_led_level * 255 / 7; SDL_SetJoystickLED(m_led_joystick_handle, intensity, intensity, intensity); break; } @@ -1545,6 +1491,7 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp default: { logitech_g27_log.error("Unknown command %02x %02x %02x %02x %02x %02x %02x ignored", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); + break; } } } diff --git a/rpcs3/Emu/Io/LogitechG27.h b/rpcs3/Emu/Io/LogitechG27.h index 72979d0316..4bbdc70dec 100644 --- a/rpcs3/Emu/Io/LogitechG27.h +++ b/rpcs3/Emu/Io/LogitechG27.h @@ -16,72 +16,72 @@ #include #include -enum logitech_g27_ffb_state +enum class logitech_g27_ffb_state { - G27_FFB_INACTIVE, - G27_FFB_DOWNLOADED, - G27_FFB_PLAYING + inactive, + downloaded, + playing }; struct logitech_g27_ffb_slot { - logitech_g27_ffb_state state; - uint64_t last_update; - SDL_HapticEffect last_effect; - int effect_id; + logitech_g27_ffb_state state = logitech_g27_ffb_state::inactive; + u64 last_update = 0; + SDL_HapticEffect last_effect {}; + s32 effect_id = -1; }; struct sdl_mapping { - uint32_t device_type_id; // (vendor_id << 16) | product_id - sdl_mapping_type type; - uint64_t id; - hat_component hat; - bool reverse; - bool positive_axis; + u32 device_type_id = 0; // (vendor_id << 16) | product_id + sdl_mapping_type type = sdl_mapping_type::button; + u64 id = 0; + hat_component hat = hat_component::none; + bool reverse = false; + bool positive_axis = false; }; struct logitech_g27_sdl_mapping { - sdl_mapping steering; - sdl_mapping throttle; - sdl_mapping brake; - sdl_mapping clutch; - sdl_mapping shift_up; - sdl_mapping shift_down; + sdl_mapping steering {}; + sdl_mapping throttle {}; + sdl_mapping brake {}; + sdl_mapping clutch {}; + sdl_mapping shift_up {}; + sdl_mapping shift_down {}; - sdl_mapping up; - sdl_mapping down; - sdl_mapping left; - sdl_mapping right; + sdl_mapping up {}; + sdl_mapping down {}; + sdl_mapping left {}; + sdl_mapping right {}; - sdl_mapping triangle; - sdl_mapping cross; - sdl_mapping square; - sdl_mapping circle; + sdl_mapping triangle {}; + sdl_mapping cross {}; + sdl_mapping square {}; + sdl_mapping circle {}; // mappings based on g27 compat mode on g29 - sdl_mapping l2; - sdl_mapping l3; - sdl_mapping r2; - sdl_mapping r3; + sdl_mapping l2 {}; + sdl_mapping l3 {}; + sdl_mapping r2 {}; + sdl_mapping r3 {}; - sdl_mapping plus; - sdl_mapping minus; + sdl_mapping plus {}; + sdl_mapping minus {}; - sdl_mapping dial_clockwise; - sdl_mapping dial_anticlockwise; + sdl_mapping dial_clockwise {}; + sdl_mapping dial_anticlockwise {}; - sdl_mapping select; - sdl_mapping pause; + sdl_mapping select {}; + sdl_mapping pause {}; - sdl_mapping shifter_1; - sdl_mapping shifter_2; - sdl_mapping shifter_3; - sdl_mapping shifter_4; - sdl_mapping shifter_5; - sdl_mapping shifter_6; - sdl_mapping shifter_r; + sdl_mapping shifter_1 {}; + sdl_mapping shifter_2 {}; + sdl_mapping shifter_3 {}; + sdl_mapping shifter_4 {}; + sdl_mapping shifter_5 {}; + sdl_mapping shifter_6 {}; + sdl_mapping shifter_r {}; }; class usb_device_logitech_g27 : public usb_device_emulated @@ -98,26 +98,25 @@ public: bool open_device() override; private: - u32 m_controller_index; + void sdl_refresh(); - logitech_g27_sdl_mapping m_mapping; - bool m_reverse_effects; + u32 m_controller_index = 0; + + logitech_g27_sdl_mapping m_mapping {}; + bool m_reverse_effects = false; std::mutex m_sdl_handles_mutex; SDL_Joystick* m_led_joystick_handle = nullptr; SDL_Haptic* m_haptic_handle = nullptr; - std::map> m_joysticks; + std::map> m_joysticks; bool m_fixed_loop = false; - uint16_t m_wheel_range = 200; - logitech_g27_ffb_slot m_effect_slots[4]; - SDL_HapticEffect m_default_spring_effect = {0}; - int m_default_spring_effect_id = -1; + u16 m_wheel_range = 200; + std::array m_effect_slots {}; + SDL_HapticEffect m_default_spring_effect {}; + s32 m_default_spring_effect_id = -1; bool m_enabled = false; std::thread m_house_keeping_thread; - std::mutex m_thread_control_mutex; - bool m_stop_thread; - - void sdl_refresh(); + atomic_t m_stop_thread { false }; }; diff --git a/rpcs3/Emu/Io/LogitechG27Config.cpp b/rpcs3/Emu/Io/LogitechG27Config.cpp index e67e1773eb..aa1ebf2af7 100644 --- a/rpcs3/Emu/Io/LogitechG27Config.cpp +++ b/rpcs3/Emu/Io/LogitechG27Config.cpp @@ -5,18 +5,52 @@ #include "Utilities/File.h" #include "LogitechG27Config.h" +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](sdl_mapping_type value) + { + switch (value) + { + case sdl_mapping_type::button: return "button"; + case sdl_mapping_type::hat: return "hat"; + case sdl_mapping_type::axis: return "axis"; + } + + return unknown; + }); +} + +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](hat_component value) + { + switch (value) + { + case hat_component::up: return "up"; + case hat_component::down: return "down"; + case hat_component::left: return "left"; + case hat_component::right: return "right"; + case hat_component::none: return ""; + } + + return unknown; + }); +} + emulated_logitech_g27_config g_cfg_logitech_g27; LOG_CHANNEL(cfg_log, "CFG"); emulated_logitech_g27_config::emulated_logitech_g27_config() - : m_path(fmt::format("%s%s.yml", fs::get_config_dir(true), "LogitechG27")) + : m_path(fs::get_config_dir(true) + "LogitechG27.yml") { } void emulated_logitech_g27_config::reset() { - const std::lock_guard lock(m_mutex); + const std::lock_guard lock(m_mutex); cfg::node::from_default(); } diff --git a/rpcs3/Emu/Io/LogitechG27Config.h b/rpcs3/Emu/Io/LogitechG27Config.h index 929c2372df..52cb7b89f7 100644 --- a/rpcs3/Emu/Io/LogitechG27Config.h +++ b/rpcs3/Emu/Io/LogitechG27Config.h @@ -4,31 +4,31 @@ #include -enum sdl_mapping_type +enum class sdl_mapping_type { - MAPPING_BUTTON = 0, - MAPPING_HAT, - MAPPING_AXIS, + button = 0, + hat, + axis, }; -enum hat_component +enum class hat_component { - HAT_NONE = 0, - HAT_UP, - HAT_DOWN, - HAT_LEFT, - HAT_RIGHT + none = 0, + up, + down, + left, + right }; struct emulated_logitech_g27_mapping : cfg::node { cfg::uint<0, 0xFFFFFFFF> device_type_id; - cfg::uint<0, 0xFFFFFFFF> type; + cfg::_enum type; cfg::uint<0, 0xFFFFFFFFFFFFFFFF> id; - cfg::uint<0, 0xFFFFFFFF> hat; + cfg::_enum hat; cfg::_bool reverse; - emulated_logitech_g27_mapping(cfg::node* owner, std::string name, uint32_t device_type_id_def, sdl_mapping_type type_def, uint64_t id_def, hat_component hat_def, bool reverse_def) + emulated_logitech_g27_mapping(cfg::node* owner, std::string name, u32 device_type_id_def, sdl_mapping_type type_def, uint64_t id_def, hat_component hat_def, bool reverse_def) : cfg::node(owner, std::move(name)), device_type_id(this, "device_type_id", device_type_id_def), type(this, "type", type_def), @@ -46,44 +46,44 @@ public: // TODO these defaults are for a shifter-less G29 + a xbox controller for shifter testing, perhaps find a new default - emulated_logitech_g27_mapping steering{this, "steering", 0x046dc24f, MAPPING_AXIS, 0, HAT_NONE, false}; - emulated_logitech_g27_mapping throttle{this, "throttle", 0x046dc24f, MAPPING_AXIS, 2, HAT_NONE, false}; - emulated_logitech_g27_mapping brake{this, "brake", 0x046dc24f, MAPPING_AXIS, 3, HAT_NONE, false}; - emulated_logitech_g27_mapping clutch{this, "clutch", 0x046dc24f, MAPPING_AXIS, 1, HAT_NONE, false}; - emulated_logitech_g27_mapping shift_up{this, "shift_up", 0x046dc24f, MAPPING_BUTTON, 4, HAT_NONE, false}; - emulated_logitech_g27_mapping shift_down{this, "shift_down", 0x046dc24f, MAPPING_BUTTON, 5, HAT_NONE, false}; + emulated_logitech_g27_mapping steering{this, "steering", 0x046dc24f, sdl_mapping_type::axis, 0, hat_component::none, false}; + emulated_logitech_g27_mapping throttle{this, "throttle", 0x046dc24f, sdl_mapping_type::axis, 2, hat_component::none, false}; + emulated_logitech_g27_mapping brake{this, "brake", 0x046dc24f, sdl_mapping_type::axis, 3, hat_component::none, false}; + emulated_logitech_g27_mapping clutch{this, "clutch", 0x046dc24f, sdl_mapping_type::axis, 1, hat_component::none, false}; + emulated_logitech_g27_mapping shift_up{this, "shift_up", 0x046dc24f, sdl_mapping_type::button, 4, hat_component::none, false}; + emulated_logitech_g27_mapping shift_down{this, "shift_down", 0x046dc24f, sdl_mapping_type::button, 5, hat_component::none, false}; - emulated_logitech_g27_mapping up{this, "up", 0x046dc24f, MAPPING_HAT, 0, HAT_UP, false}; - emulated_logitech_g27_mapping down{this, "down", 0x046dc24f, MAPPING_HAT, 0, HAT_DOWN, false}; - emulated_logitech_g27_mapping left{this, "left", 0x046dc24f, MAPPING_HAT, 0, HAT_LEFT, false}; - emulated_logitech_g27_mapping right{this, "right", 0x046dc24f, MAPPING_HAT, 0, HAT_RIGHT, false}; + emulated_logitech_g27_mapping up{this, "up", 0x046dc24f, sdl_mapping_type::hat, 0, hat_component::up, false}; + emulated_logitech_g27_mapping down{this, "down", 0x046dc24f, sdl_mapping_type::hat, 0, hat_component::down, false}; + emulated_logitech_g27_mapping left{this, "left", 0x046dc24f, sdl_mapping_type::hat, 0, hat_component::left, false}; + emulated_logitech_g27_mapping right{this, "right", 0x046dc24f, sdl_mapping_type::hat, 0, hat_component::right, false}; - emulated_logitech_g27_mapping triangle{this, "triangle", 0x046dc24f, MAPPING_BUTTON, 3, HAT_NONE, false}; - emulated_logitech_g27_mapping cross{this, "cross", 0x046dc24f, MAPPING_BUTTON, 0, HAT_NONE, false}; - emulated_logitech_g27_mapping square{this, "square", 0x046dc24f, MAPPING_BUTTON, 1, HAT_NONE, false}; - emulated_logitech_g27_mapping circle{this, "circle", 0x046dc24f, MAPPING_BUTTON, 2, HAT_NONE, false}; + emulated_logitech_g27_mapping triangle{this, "triangle", 0x046dc24f, sdl_mapping_type::button, 3, hat_component::none, false}; + emulated_logitech_g27_mapping cross{this, "cross", 0x046dc24f, sdl_mapping_type::button, 0, hat_component::none, false}; + emulated_logitech_g27_mapping square{this, "square", 0x046dc24f, sdl_mapping_type::button, 1, hat_component::none, false}; + emulated_logitech_g27_mapping circle{this, "circle", 0x046dc24f, sdl_mapping_type::button, 2, hat_component::none, false}; - emulated_logitech_g27_mapping l2{this, "l2", 0x046dc24f, MAPPING_BUTTON, 7, HAT_NONE, false}; - emulated_logitech_g27_mapping l3{this, "l3", 0x046dc24f, MAPPING_BUTTON, 11, HAT_NONE, false}; - emulated_logitech_g27_mapping r2{this, "r2", 0x046dc24f, MAPPING_BUTTON, 6, HAT_NONE, false}; - emulated_logitech_g27_mapping r3{this, "r3", 0x046dc24f, MAPPING_BUTTON, 10, HAT_NONE, false}; + emulated_logitech_g27_mapping l2{this, "l2", 0x046dc24f, sdl_mapping_type::button, 7, hat_component::none, false}; + emulated_logitech_g27_mapping l3{this, "l3", 0x046dc24f, sdl_mapping_type::button, 11, hat_component::none, false}; + emulated_logitech_g27_mapping r2{this, "r2", 0x046dc24f, sdl_mapping_type::button, 6, hat_component::none, false}; + emulated_logitech_g27_mapping r3{this, "r3", 0x046dc24f, sdl_mapping_type::button, 10, hat_component::none, false}; - emulated_logitech_g27_mapping plus{this, "plus", 0x046dc24f, MAPPING_BUTTON, 19, HAT_NONE, false}; - emulated_logitech_g27_mapping minus{this, "minus", 0x046dc24f, MAPPING_BUTTON, 20, HAT_NONE, false}; + emulated_logitech_g27_mapping plus{this, "plus", 0x046dc24f, sdl_mapping_type::button, 19, hat_component::none, false}; + emulated_logitech_g27_mapping minus{this, "minus", 0x046dc24f, sdl_mapping_type::button, 20, hat_component::none, false}; - emulated_logitech_g27_mapping dial_clockwise{this, "dial_clockwise", 0x046dc24f, MAPPING_BUTTON, 21, HAT_NONE, false}; - emulated_logitech_g27_mapping dial_anticlockwise{this, "dial_anticlockwise", 0x046dc24f, MAPPING_BUTTON, 22, HAT_NONE, false}; + emulated_logitech_g27_mapping dial_clockwise{this, "dial_clockwise", 0x046dc24f, sdl_mapping_type::button, 21, hat_component::none, false}; + emulated_logitech_g27_mapping dial_anticlockwise{this, "dial_anticlockwise", 0x046dc24f, sdl_mapping_type::button, 22, hat_component::none, false}; - emulated_logitech_g27_mapping select{this, "select", 0x046dc24f, MAPPING_BUTTON, 8, HAT_NONE, false}; - emulated_logitech_g27_mapping pause{this, "pause", 0x046dc24f, MAPPING_BUTTON, 9, HAT_NONE, false}; + emulated_logitech_g27_mapping select{this, "select", 0x046dc24f, sdl_mapping_type::button, 8, hat_component::none, false}; + emulated_logitech_g27_mapping pause{this, "pause", 0x046dc24f, sdl_mapping_type::button, 9, hat_component::none, false}; - emulated_logitech_g27_mapping shifter_1{this, "shifter_1", 0x045e028e, MAPPING_BUTTON, 3, HAT_NONE, false}; - emulated_logitech_g27_mapping shifter_2{this, "shifter_2", 0x045e028e, MAPPING_BUTTON, 0, HAT_NONE, false}; - emulated_logitech_g27_mapping shifter_3{this, "shifter_3", 0x045e028e, MAPPING_BUTTON, 2, HAT_NONE, false}; - emulated_logitech_g27_mapping shifter_4{this, "shifter_4", 0x045e028e, MAPPING_BUTTON, 1, HAT_NONE, false}; - emulated_logitech_g27_mapping shifter_5{this, "shifter_5", 0x045e028e, MAPPING_HAT, 0, HAT_UP, false}; - emulated_logitech_g27_mapping shifter_6{this, "shifter_6", 0x045e028e, MAPPING_HAT, 0, HAT_DOWN, false}; - emulated_logitech_g27_mapping shifter_r{this, "shifter_r", 0x045e028e, MAPPING_HAT, 0, HAT_LEFT, false}; + emulated_logitech_g27_mapping shifter_1{this, "shifter_1", 0x045e028e, sdl_mapping_type::button, 3, hat_component::none, false}; + emulated_logitech_g27_mapping shifter_2{this, "shifter_2", 0x045e028e, sdl_mapping_type::button, 0, hat_component::none, false}; + emulated_logitech_g27_mapping shifter_3{this, "shifter_3", 0x045e028e, sdl_mapping_type::button, 2, hat_component::none, false}; + emulated_logitech_g27_mapping shifter_4{this, "shifter_4", 0x045e028e, sdl_mapping_type::button, 1, hat_component::none, false}; + emulated_logitech_g27_mapping shifter_5{this, "shifter_5", 0x045e028e, sdl_mapping_type::hat, 0, hat_component::up, false}; + emulated_logitech_g27_mapping shifter_6{this, "shifter_6", 0x045e028e, sdl_mapping_type::hat, 0, hat_component::down, false}; + emulated_logitech_g27_mapping shifter_r{this, "shifter_r", 0x045e028e, sdl_mapping_type::hat, 0, hat_component::left, false}; cfg::_bool reverse_effects{this, "reverse_effects", true}; cfg::uint<0, 0xFFFFFFFF> ffb_device_type_id{this, "ffb_device_type_id", 0x046dc24f}; diff --git a/rpcs3/rpcs3qt/emulated_logitech_g27_settings_dialog.cpp b/rpcs3/rpcs3qt/emulated_logitech_g27_settings_dialog.cpp index e7a894d6ae..c5bedb88eb 100644 --- a/rpcs3/rpcs3qt/emulated_logitech_g27_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/emulated_logitech_g27_settings_dialog.cpp @@ -19,128 +19,133 @@ LOG_CHANNEL(logitech_g27_cfg_log, "LOGIG27"); -static constexpr const char* DEFAULT_STATUS = " "; +static const QString DEFAULT_STATUS = " "; -enum mapping_device_choice +enum class mapping_device_choice { - CHOICE_NONE = -1, - CHOICE_STEERING = 0, - CHOICE_THROTTLE, - CHOICE_BRAKE, - CHOICE_CLUTCH, - CHOICE_SHIFT_UP, - CHOICE_SHIFT_DOWN, + NONE = -1, + STEERING = 0, + THROTTLE, + BRAKE, + CLUTCH, + SHIFT_UP, + SHIFT_DOWN, - CHOICE_UP, - CHOICE_DOWN, - CHOICE_LEFT, - CHOICE_RIGHT, + UP, + DOWN, + LEFT, + RIGHT, - CHOICE_TRIANGLE, - CHOICE_CROSS, - CHOICE_SQUARE, - CHOICE_CIRCLE, + TRIANGLE, + CROSS, + SQUARE, + CIRCLE, - CHOICE_L2, - CHOICE_L3, - CHOICE_R2, - CHOICE_R3, + L2, + L3, + R2, + R3, - CHOICE_PLUS, - CHOICE_MINUS, + PLUS, + MINUS, - CHOICE_DIAL_CLOCKWISE, - CHOICE_DIAL_ANTICLOCKWISE, + DIAL_CLOCKWISE, + DIAL_ANTICLOCKWISE, - CHOICE_SELECT, - CHOICE_PAUSE, + SELECT, + PAUSE, - CHOICE_SHIFTER_1, - CHOICE_SHIFTER_2, - CHOICE_SHIFTER_3, - CHOICE_SHIFTER_4, - CHOICE_SHIFTER_5, - CHOICE_SHIFTER_6, - CHOICE_SHIFTER_R + SHIFTER_1, + SHIFTER_2, + SHIFTER_3, + SHIFTER_4, + SHIFTER_5, + SHIFTER_6, + SHIFTER_R }; class DeviceChoice : public QWidget { public: - DeviceChoice(QWidget* parent, const char* name) + DeviceChoice(QWidget* parent, const QString& name) : QWidget(parent) { auto layout = new QHBoxLayout(this); setLayout(layout); QLabel* label = new QLabel(this); - label->setText(QString(name)); + label->setText(name); label->setMinimumWidth(400); layout->addWidget(label); m_dropdown = new QComboBox(this); layout->addWidget(m_dropdown); - m_disable_button = new QPushButton(QString("DISABLE"), this); + m_disable_button = new QPushButton(tr("DISABLE"), this); layout->addWidget(m_disable_button); - connect(m_dropdown, &QComboBox::currentIndexChanged, this, [this]() - { - m_device_choice = static_cast(this->m_dropdown->currentIndex()); - update_display(); - }); + connect(m_dropdown, &QComboBox::currentIndexChanged, this, [this](int index) + { + if (index < 0) return; + + const QVariant var = m_dropdown->currentData(); + if (!var.canConvert()) return; + + m_device_choice = static_cast(var.toInt()); + update_display(); + }); connect(m_disable_button, &QPushButton::clicked, this, [this]() - { - m_device_choice = CHOICE_NONE; - update_display(); - }); + { + m_device_choice = mapping_device_choice::NONE; + update_display(); + }); - m_dropdown->setPlaceholderText(QString("-- Disabled --")); + m_dropdown->setPlaceholderText(tr("-- Disabled --")); - m_dropdown->addItem(QString("Steering"), QVariant(CHOICE_STEERING)); - m_dropdown->addItem(QString("Throttle"), QVariant(CHOICE_THROTTLE)); - m_dropdown->addItem(QString("Brake"), QVariant(CHOICE_BRAKE)); - m_dropdown->addItem(QString("Clutch"), QVariant(CHOICE_CLUTCH)); - m_dropdown->addItem(QString("Shift up"), QVariant(CHOICE_SHIFT_UP)); - m_dropdown->addItem(QString("Shift down"), QVariant(CHOICE_SHIFT_DOWN)); + m_dropdown->addItem(tr("Steering"), static_cast(mapping_device_choice::STEERING)); + m_dropdown->addItem(tr("Throttle"), static_cast(mapping_device_choice::THROTTLE)); + m_dropdown->addItem(tr("Brake"), static_cast(mapping_device_choice::BRAKE)); + m_dropdown->addItem(tr("Clutch"), static_cast(mapping_device_choice::CLUTCH)); + m_dropdown->addItem(tr("Shift up"), static_cast(mapping_device_choice::SHIFT_UP)); + m_dropdown->addItem(tr("Shift down"), static_cast(mapping_device_choice::SHIFT_DOWN)); - m_dropdown->addItem(QString("Up"), QVariant(CHOICE_UP)); - m_dropdown->addItem(QString("Down"), QVariant(CHOICE_DOWN)); - m_dropdown->addItem(QString("Left"), QVariant(CHOICE_LEFT)); - m_dropdown->addItem(QString("Right"), QVariant(CHOICE_RIGHT)); + m_dropdown->addItem(tr("Up"), static_cast(mapping_device_choice::UP)); + m_dropdown->addItem(tr("Down"), static_cast(mapping_device_choice::DOWN)); + m_dropdown->addItem(tr("Left"), static_cast(mapping_device_choice::LEFT)); + m_dropdown->addItem(tr("Right"), static_cast(mapping_device_choice::RIGHT)); - m_dropdown->addItem(QString("Triangle"), QVariant(CHOICE_TRIANGLE)); - m_dropdown->addItem(QString("Cross"), QVariant(CHOICE_CROSS)); - m_dropdown->addItem(QString("Square"), QVariant(CHOICE_SQUARE)); - m_dropdown->addItem(QString("Circle"), QVariant(CHOICE_CIRCLE)); + m_dropdown->addItem(tr("Triangle"), static_cast(mapping_device_choice::TRIANGLE)); + m_dropdown->addItem(tr("Cross"), static_cast(mapping_device_choice::CROSS)); + m_dropdown->addItem(tr("Square"), static_cast(mapping_device_choice::SQUARE)); + m_dropdown->addItem(tr("Circle"), static_cast(mapping_device_choice::CIRCLE)); - m_dropdown->addItem(QString("L2"), QVariant(CHOICE_L2)); - m_dropdown->addItem(QString("L3"), QVariant(CHOICE_L3)); - m_dropdown->addItem(QString("R2"), QVariant(CHOICE_R2)); - m_dropdown->addItem(QString("R3"), QVariant(CHOICE_R3)); + m_dropdown->addItem(tr("L2"), static_cast(mapping_device_choice::L2)); + m_dropdown->addItem(tr("L3"), static_cast(mapping_device_choice::L3)); + m_dropdown->addItem(tr("R2"), static_cast(mapping_device_choice::R2)); + m_dropdown->addItem(tr("R3"), static_cast(mapping_device_choice::R3)); - m_dropdown->addItem(QString("L4"), QVariant(CHOICE_PLUS)); - m_dropdown->addItem(QString("L5"), QVariant(CHOICE_MINUS)); + m_dropdown->addItem(tr("L4"), static_cast(mapping_device_choice::PLUS)); + m_dropdown->addItem(tr("L5"), static_cast(mapping_device_choice::MINUS)); - m_dropdown->addItem(QString("R4"), QVariant(CHOICE_DIAL_CLOCKWISE)); - m_dropdown->addItem(QString("R5"), QVariant(CHOICE_DIAL_ANTICLOCKWISE)); + m_dropdown->addItem(tr("R4"), static_cast(mapping_device_choice::DIAL_CLOCKWISE)); + m_dropdown->addItem(tr("R5"), static_cast(mapping_device_choice::DIAL_ANTICLOCKWISE)); - m_dropdown->addItem(QString("Select"), QVariant(CHOICE_SELECT)); - m_dropdown->addItem(QString("Pause"), QVariant(CHOICE_PAUSE)); + m_dropdown->addItem(tr("Select"), static_cast(mapping_device_choice::SELECT)); + m_dropdown->addItem(tr("Pause"), static_cast(mapping_device_choice::PAUSE)); - m_dropdown->addItem(QString("Gear 1"), QVariant(CHOICE_SHIFTER_1)); - m_dropdown->addItem(QString("Gear 2"), QVariant(CHOICE_SHIFTER_2)); - m_dropdown->addItem(QString("Gear 3"), QVariant(CHOICE_SHIFTER_3)); - m_dropdown->addItem(QString("Gear 4"), QVariant(CHOICE_SHIFTER_4)); - m_dropdown->addItem(QString("Gear 5"), QVariant(CHOICE_SHIFTER_5)); - m_dropdown->addItem(QString("Gear 6"), QVariant(CHOICE_SHIFTER_6)); - m_dropdown->addItem(QString("Gear r"), QVariant(CHOICE_SHIFTER_R)); + m_dropdown->addItem(tr("Gear 1"), static_cast(mapping_device_choice::SHIFTER_1)); + m_dropdown->addItem(tr("Gear 2"), static_cast(mapping_device_choice::SHIFTER_2)); + m_dropdown->addItem(tr("Gear 3"), static_cast(mapping_device_choice::SHIFTER_3)); + m_dropdown->addItem(tr("Gear 4"), static_cast(mapping_device_choice::SHIFTER_4)); + m_dropdown->addItem(tr("Gear 5"), static_cast(mapping_device_choice::SHIFTER_5)); + m_dropdown->addItem(tr("Gear 6"), static_cast(mapping_device_choice::SHIFTER_6)); + m_dropdown->addItem(tr("Gear r"), static_cast(mapping_device_choice::SHIFTER_R)); update_display(); } - mapping_device_choice get_device_choice() + mapping_device_choice get_device_choice() const { return m_device_choice; } @@ -158,20 +163,20 @@ public: } private: - mapping_device_choice m_device_choice = CHOICE_NONE; - QComboBox* m_dropdown = nullptr; - QPushButton* m_disable_button = nullptr; - void update_display() { m_dropdown->setCurrentIndex(static_cast(m_device_choice)); } + + mapping_device_choice m_device_choice = mapping_device_choice::NONE; + QComboBox* m_dropdown = nullptr; + QPushButton* m_disable_button = nullptr; }; class Mapping : public QGroupBox { public: - Mapping(QWidget* parent, emulated_logitech_g27_settings_dialog* dialog, bool is_axis, const char* name, bool flip_axis_display) + Mapping(QWidget* parent, emulated_logitech_g27_settings_dialog* dialog, bool is_axis, const QString& name, bool flip_axis_display) : QGroupBox(parent), m_setting_dialog(dialog), m_is_axis(is_axis), m_name(name), m_flip_axis_display(flip_axis_display) { QVBoxLayout* layout = new QVBoxLayout(this); @@ -184,7 +189,7 @@ public: layout->addWidget(horizontal_container); QLabel* label = new QLabel(horizontal_container); - label->setText(QString(name)); + label->setText(name); m_display_box = new QLabel(horizontal_container); m_display_box->setTextFormat(Qt::RichText); @@ -192,19 +197,17 @@ public: m_display_box->setFrameStyle(QFrame::Box); m_display_box->setMinimumWidth(150); - m_map_button = new QPushButton(QString("MAP"), horizontal_container); - m_unmap_button = new QPushButton(QString("UNMAP"), horizontal_container); - m_reverse_checkbox = new QCheckBox(QString("Reverse"), horizontal_container); + m_map_button = new QPushButton(tr("MAP"), horizontal_container); + m_unmap_button = new QPushButton(tr("UNMAP"), horizontal_container); + m_reverse_checkbox = new QCheckBox(tr("Reverse"), horizontal_container); - if (!this->m_is_axis) + if (!m_is_axis) { - m_axis_status = nullptr; - m_button_status = new QCheckBox(QString("Pressed"), horizontal_container); + m_button_status = new QCheckBox(tr("Pressed"), horizontal_container); m_button_status->setDisabled(true); } else { - m_button_status = nullptr; m_axis_status = new QSlider(Qt::Horizontal, this); m_axis_status->setDisabled(true); m_axis_status->setMinimum(-0x8000); @@ -216,134 +219,130 @@ public: horizontal_layout->addWidget(label); horizontal_layout->addWidget(m_display_box); - if (!this->m_is_axis) + if (m_button_status) horizontal_layout->addWidget(m_button_status); horizontal_layout->addWidget(m_map_button); horizontal_layout->addWidget(m_unmap_button); horizontal_layout->addWidget(m_reverse_checkbox); - if (this->m_is_axis) + if (m_axis_status) layout->addWidget(m_axis_status); connect(m_map_button, &QPushButton::clicked, this, [this]() - { - this->m_mapping_in_progress = true; - this->m_timeout_msec = 5500; - this->m_setting_dialog->set_enable(false); - this->m_last_joystick_states = this->m_setting_dialog->get_joystick_states(); - }); + { + m_mapping_in_progress = true; + m_timeout_msec = 5500; + m_setting_dialog->set_enable(false); + m_last_joystick_states = m_setting_dialog->get_joystick_states(); + }); connect(m_unmap_button, &QPushButton::clicked, this, [this]() - { - this->m_mapping.device_type_id = 0; - update_display(); - }); + { + m_mapping.device_type_id = 0; + update_display(); + }); connect(m_reverse_checkbox, &QCheckBox::clicked, this, [this]() - { - this->m_mapping.reverse = this->m_reverse_checkbox->isChecked(); - }); + { + m_mapping.reverse = m_reverse_checkbox->isChecked(); + }); m_tick_timer = new QTimer(this); connect(m_tick_timer, &QTimer::timeout, this, [this]() + { + if (m_mapping_in_progress) { - if (this->m_mapping_in_progress) + const int timeout_sec = m_timeout_msec / 1000; + const std::map& new_joystick_states = m_setting_dialog->get_joystick_states(); + + m_setting_dialog->set_state_text(tr("Input %0 for %1, timeout in %2 %3").arg(m_is_axis ? tr("axis") : tr("button/hat")).arg(m_name).arg(timeout_sec).arg(timeout_sec >= 2 ? tr("seconds") : tr("second"))); + + for (auto& [device_type_id, new_joystick_state] : new_joystick_states) { - char text_buf[128]; - - int timeout_sec = this->m_timeout_msec / 1000; - - const std::map& new_joystick_states = this->m_setting_dialog->get_joystick_states(); - - sprintf(text_buf, "Input %s for %s, timeout in %d %s", this->m_is_axis ? "axis" : "button/hat", this->m_name.c_str(), timeout_sec, timeout_sec >= 2 ? "seconds" : "second"); - this->m_setting_dialog->set_state_text(text_buf); - - for (auto new_joystick_state : new_joystick_states) + const auto last_joystick_state = m_last_joystick_states.find(device_type_id); + if (last_joystick_state == m_last_joystick_states.cend()) { - auto last_joystick_state = this->m_last_joystick_states.find(new_joystick_state.first); - if (last_joystick_state == this->m_last_joystick_states.end()) + continue; + } + + if (m_is_axis) + { + constexpr s16 axis_change_threshold = 0x7FFF / 5; + if (last_joystick_state->second.axes.size() != new_joystick_state.axes.size()) { + logitech_g27_cfg_log.error("During input state change diff, number of axes on %04x:%04x changed", device_type_id >> 16, device_type_id & 0xFFFF); continue; } - - if (this->m_is_axis) + for (usz i = 0; i < new_joystick_state.axes.size(); i++) { - const static int16_t axis_change_threshold = 0x7FFF / 5; - if (last_joystick_state->second.axes.size() != new_joystick_state.second.axes.size()) + const s32 diff = std::abs(last_joystick_state->second.axes[i] - new_joystick_state.axes[i]); + if (diff > axis_change_threshold) { - logitech_g27_cfg_log.error("during input state change diff, number of axes on %04x:%04x changed", new_joystick_state.first >> 16, new_joystick_state.first & 0xFFFF); - continue; - } - for (std::vector::size_type i = 0; i < new_joystick_state.second.axes.size(); i++) - { - int32_t diff = std::abs(last_joystick_state->second.axes[i] - new_joystick_state.second.axes[i]); - if (diff > axis_change_threshold) - { - this->m_mapping_in_progress = false; - this->m_setting_dialog->set_state_text(DEFAULT_STATUS); - this->m_setting_dialog->set_enable(true); - this->m_mapping.device_type_id = new_joystick_state.first; - this->m_mapping.type = MAPPING_AXIS; - this->m_mapping.id = i; - this->m_mapping.hat = HAT_NONE; - break; - } - } - } - else - { - if (last_joystick_state->second.buttons.size() != new_joystick_state.second.buttons.size()) - { - logitech_g27_cfg_log.error("during input state change diff, number of buttons on %04x:%04x changed", new_joystick_state.first >> 16, new_joystick_state.first & 0xFFFF); - continue; - } - if (last_joystick_state->second.hats.size() != new_joystick_state.second.hats.size()) - { - logitech_g27_cfg_log.error("during input state change diff, number of hats on %04x:%04x changed", new_joystick_state.first >> 16, new_joystick_state.first & 0xFFFF); - continue; - } - for (std::vector::size_type i = 0; i < new_joystick_state.second.buttons.size(); i++) - { - if (last_joystick_state->second.buttons[i] != new_joystick_state.second.buttons[i]) - { - this->m_mapping_in_progress = false; - this->m_setting_dialog->set_state_text(DEFAULT_STATUS); - this->m_setting_dialog->set_enable(true); - this->m_mapping.device_type_id = new_joystick_state.first; - this->m_mapping.type = MAPPING_BUTTON; - this->m_mapping.id = i; - this->m_mapping.hat = HAT_NONE; - break; - } - } - for (std::vector::size_type i = 0; i < new_joystick_state.second.hats.size(); i++) - { - if (last_joystick_state->second.hats[i] != new_joystick_state.second.hats[i] && new_joystick_state.second.hats[i] != HAT_NONE) - { - this->m_mapping_in_progress = false; - this->m_setting_dialog->set_state_text(DEFAULT_STATUS); - this->m_setting_dialog->set_enable(true); - this->m_mapping.device_type_id = new_joystick_state.first; - this->m_mapping.type = MAPPING_HAT; - this->m_mapping.id = i; - this->m_mapping.hat = new_joystick_state.second.hats[i]; - break; - } + m_mapping_in_progress = false; + m_setting_dialog->set_state_text(DEFAULT_STATUS); + m_setting_dialog->set_enable(true); + m_mapping.device_type_id = device_type_id; + m_mapping.type = sdl_mapping_type::axis; + m_mapping.id = i; + m_mapping.hat = hat_component::none; + break; } } } - - this->m_timeout_msec = this->m_timeout_msec - 25; - if (this->m_timeout_msec <= 0) + else { - this->m_mapping_in_progress = false; - this->m_setting_dialog->set_state_text(DEFAULT_STATUS); - this->m_setting_dialog->set_enable(true); + if (last_joystick_state->second.buttons.size() != new_joystick_state.buttons.size()) + { + logitech_g27_cfg_log.error("during input state change diff, number of buttons on %04x:%04x changed", device_type_id >> 16, device_type_id & 0xFFFF); + continue; + } + if (last_joystick_state->second.hats.size() != new_joystick_state.hats.size()) + { + logitech_g27_cfg_log.error("during input state change diff, number of hats on %04x:%04x changed", device_type_id >> 16, device_type_id & 0xFFFF); + continue; + } + for (usz i = 0; i < new_joystick_state.buttons.size(); i++) + { + if (last_joystick_state->second.buttons[i] != new_joystick_state.buttons[i]) + { + m_mapping_in_progress = false; + m_setting_dialog->set_state_text(DEFAULT_STATUS); + m_setting_dialog->set_enable(true); + m_mapping.device_type_id = device_type_id; + m_mapping.type = sdl_mapping_type::button; + m_mapping.id = i; + m_mapping.hat = hat_component::none; + break; + } + } + for (usz i = 0; i < new_joystick_state.hats.size(); i++) + { + if (last_joystick_state->second.hats[i] != new_joystick_state.hats[i] && new_joystick_state.hats[i] != hat_component::none) + { + m_mapping_in_progress = false; + m_setting_dialog->set_state_text(DEFAULT_STATUS); + m_setting_dialog->set_enable(true); + m_mapping.device_type_id = device_type_id; + m_mapping.type = sdl_mapping_type::hat; + m_mapping.id = i; + m_mapping.hat = new_joystick_state.hats[i]; + break; + } + } } } - update_display(); - }); + m_timeout_msec -= 25; + if (m_timeout_msec <= 0) + { + m_mapping_in_progress = false; + m_setting_dialog->set_state_text(DEFAULT_STATUS); + m_setting_dialog->set_enable(true); + } + } + + update_display(); + }); m_tick_timer->start(25); } @@ -356,11 +355,11 @@ public: void set_mapping(const sdl_mapping& mapping) { - this->m_mapping = mapping; + m_mapping = mapping; update_display(); } - const sdl_mapping& get_mapping() + const sdl_mapping& get_mapping() const { return m_mapping; } @@ -369,9 +368,9 @@ private: emulated_logitech_g27_settings_dialog* m_setting_dialog = nullptr; DeviceChoice* m_ffb_device = nullptr; DeviceChoice* m_led_device = nullptr; - sdl_mapping m_mapping = {0}; + sdl_mapping m_mapping{}; bool m_is_axis = false; - std::string m_name = ""; + QString m_name; bool m_flip_axis_display = false; QLabel* m_display_box = nullptr; @@ -382,48 +381,15 @@ private: bool m_mapping_in_progress = false; int m_timeout_msec = 5500; QTimer* m_tick_timer = nullptr; - std::map m_last_joystick_states; + std::map m_last_joystick_states; QCheckBox* m_button_status = nullptr; QSlider* m_axis_status = nullptr; void update_display() { - char text_buf[64]; - const char* type_string = nullptr; - switch (m_mapping.type) - { - case MAPPING_BUTTON: - type_string = "button"; - break; - case MAPPING_HAT: - type_string = "hat"; - break; - case MAPPING_AXIS: - type_string = "axis"; - break; - } - const char* hat_string = nullptr; - switch (m_mapping.hat) - { - case HAT_UP: - hat_string = "up"; - break; - case HAT_DOWN: - hat_string = "down"; - break; - case HAT_LEFT: - hat_string = "left"; - break; - case HAT_RIGHT: - hat_string = "right"; - break; - case HAT_NONE: - hat_string = ""; - break; - } - sprintf(text_buf, "%04x:%04x, %s %u %s", m_mapping.device_type_id >> 16, m_mapping.device_type_id & 0xFFFF, type_string, m_mapping.id, hat_string); - m_display_box->setText(QString(text_buf)); + const std::string text = fmt::format("%04x:%04x, %s %u %s", m_mapping.device_type_id >> 16, m_mapping.device_type_id & 0xFFFF, m_mapping.type, m_mapping.id, m_mapping.hat); + m_display_box->setText(QString::fromStdString(text)); m_reverse_checkbox->setChecked(m_mapping.reverse); @@ -432,26 +398,22 @@ private: if (m_axis_status) { - int32_t axis_value = (-0x8000); + s32 axis_value = -0x8000; if (m_mapping.reverse) - axis_value = axis_value * (-1); + axis_value *= -1; if (m_flip_axis_display) - axis_value = axis_value * (-1); - if (axis_value > 0x7FFF) - axis_value = 0x7FFF; - if (axis_value < (-0x8000)) - axis_value = (-0x8000); - m_axis_status->setValue(axis_value); + axis_value *= -1; + m_axis_status->setValue(std::clamp(axis_value, -0x8000, 0x7FFF)); } - const std::map& joystick_states = m_setting_dialog->get_joystick_states(); + const std::map& joystick_states = m_setting_dialog->get_joystick_states(); auto joystick_state = joystick_states.find(m_mapping.device_type_id); if (joystick_state != joystick_states.end()) { switch (m_mapping.type) { - case MAPPING_BUTTON: + case sdl_mapping_type::button: { if (joystick_state->second.buttons.size() <= m_mapping.id) break; @@ -461,7 +423,7 @@ private: m_button_status->setChecked(value); break; } - case MAPPING_HAT: + case sdl_mapping_type::hat: { if (joystick_state->second.hats.size() <= m_mapping.id) break; @@ -471,20 +433,16 @@ private: m_button_status->setChecked(value); break; } - case MAPPING_AXIS: + case sdl_mapping_type::axis: { if (joystick_state->second.axes.size() <= m_mapping.id) break; - int32_t value = joystick_state->second.axes[m_mapping.id]; + s32 value = joystick_state->second.axes[m_mapping.id]; if (m_mapping.reverse) - value = value * (-1); + value *= -1; if (m_flip_axis_display) - value = value * (-1); - if (value > 0x7FFF) - value = 0x7FFF; - else if (value < (-0x8000)) - value = (-0x8000); - m_axis_status->setValue(value); + value *= -1; + m_axis_status->setValue(std::clamp(value, -0x8000, 0x7FFF)); break; } } @@ -494,74 +452,74 @@ private: void emulated_logitech_g27_settings_dialog::save_ui_state_to_config() { -#define SAVE_MAPPING(name, device_choice) \ - { \ - const sdl_mapping& m = m_##name->get_mapping(); \ - g_cfg_logitech_g27.name.device_type_id.set(m.device_type_id); \ - g_cfg_logitech_g27.name.type.set(m.type); \ - g_cfg_logitech_g27.name.id.set(m.id); \ - g_cfg_logitech_g27.name.hat.set(m.hat); \ - g_cfg_logitech_g27.name.reverse.set(m.reverse); \ - if (m_ffb_device->get_device_choice() == device_choice) \ - { \ - g_cfg_logitech_g27.ffb_device_type_id.set(m.device_type_id); \ - } \ - if (m_led_device->get_device_choice() == device_choice) \ - { \ - g_cfg_logitech_g27.led_device_type_id.set(m.device_type_id); \ - } \ - } + const auto save_mapping = [this](emulated_logitech_g27_mapping& mapping, Mapping* ui_mapping, mapping_device_choice device_choice) + { + const sdl_mapping& m = ui_mapping->get_mapping(); + mapping.device_type_id.set(m.device_type_id); + mapping.type.set(m.type); + mapping.id.set(m.id); + mapping.hat.set(m.hat); + mapping.reverse.set(m.reverse); + if (m_ffb_device->get_device_choice() == device_choice) + { + g_cfg_logitech_g27.ffb_device_type_id.set(m.device_type_id); + } + if (m_led_device->get_device_choice() == device_choice) + { + g_cfg_logitech_g27.led_device_type_id.set(m.device_type_id); + } + }; - SAVE_MAPPING(steering, CHOICE_STEERING); - SAVE_MAPPING(throttle, CHOICE_THROTTLE); - SAVE_MAPPING(brake, CHOICE_BRAKE); - SAVE_MAPPING(clutch, CHOICE_CLUTCH); - SAVE_MAPPING(shift_up, CHOICE_SHIFT_UP); - SAVE_MAPPING(shift_down, CHOICE_SHIFT_DOWN); + auto& cfg = g_cfg_logitech_g27; - SAVE_MAPPING(up, CHOICE_UP); - SAVE_MAPPING(down, CHOICE_DOWN); - SAVE_MAPPING(left, CHOICE_LEFT); - SAVE_MAPPING(right, CHOICE_RIGHT); + save_mapping(cfg.steering, m_steering, mapping_device_choice::STEERING); + save_mapping(cfg.throttle, m_throttle, mapping_device_choice::THROTTLE); + save_mapping(cfg.brake, m_brake, mapping_device_choice::BRAKE); + save_mapping(cfg.clutch, m_clutch, mapping_device_choice::CLUTCH); + save_mapping(cfg.shift_up, m_shift_up, mapping_device_choice::SHIFT_UP); + save_mapping(cfg.shift_down, m_shift_down, mapping_device_choice::SHIFT_DOWN); - SAVE_MAPPING(triangle, CHOICE_TRIANGLE); - SAVE_MAPPING(cross, CHOICE_CROSS); - SAVE_MAPPING(square, CHOICE_SQUARE); - SAVE_MAPPING(circle, CHOICE_CIRCLE); + save_mapping(cfg.up, m_up, mapping_device_choice::UP); + save_mapping(cfg.down, m_down, mapping_device_choice::DOWN); + save_mapping(cfg.left, m_left, mapping_device_choice::LEFT); + save_mapping(cfg.right, m_right, mapping_device_choice::RIGHT); - SAVE_MAPPING(l2, CHOICE_L2); - SAVE_MAPPING(l3, CHOICE_L3); - SAVE_MAPPING(r2, CHOICE_R2); - SAVE_MAPPING(r3, CHOICE_R3); + save_mapping(cfg.triangle, m_triangle, mapping_device_choice::TRIANGLE); + save_mapping(cfg.cross, m_cross, mapping_device_choice::CROSS); + save_mapping(cfg.square, m_square, mapping_device_choice::SQUARE); + save_mapping(cfg.circle, m_circle, mapping_device_choice::CIRCLE); - SAVE_MAPPING(plus, CHOICE_PLUS); - SAVE_MAPPING(minus, CHOICE_MINUS); + save_mapping(cfg.l2, m_l2, mapping_device_choice::L2); + save_mapping(cfg.l3, m_l3, mapping_device_choice::L3); + save_mapping(cfg.r2, m_r2, mapping_device_choice::R2); + save_mapping(cfg.r3, m_r3, mapping_device_choice::R3); - SAVE_MAPPING(dial_clockwise, CHOICE_DIAL_CLOCKWISE); - SAVE_MAPPING(dial_anticlockwise, CHOICE_DIAL_ANTICLOCKWISE); + save_mapping(cfg.plus, m_plus, mapping_device_choice::PLUS); + save_mapping(cfg.minus, m_minus, mapping_device_choice::MINUS); - SAVE_MAPPING(select, CHOICE_SELECT); - SAVE_MAPPING(pause, CHOICE_PAUSE); + save_mapping(cfg.dial_clockwise, m_dial_clockwise, mapping_device_choice::DIAL_CLOCKWISE); + save_mapping(cfg.dial_anticlockwise, m_dial_anticlockwise, mapping_device_choice::DIAL_ANTICLOCKWISE); - SAVE_MAPPING(shifter_1, CHOICE_SHIFTER_1); - SAVE_MAPPING(shifter_2, CHOICE_SHIFTER_2); - SAVE_MAPPING(shifter_3, CHOICE_SHIFTER_3); - SAVE_MAPPING(shifter_4, CHOICE_SHIFTER_4); - SAVE_MAPPING(shifter_5, CHOICE_SHIFTER_5); - SAVE_MAPPING(shifter_6, CHOICE_SHIFTER_6); - SAVE_MAPPING(shifter_r, CHOICE_SHIFTER_R); + save_mapping(cfg.select, m_select, mapping_device_choice::SELECT); + save_mapping(cfg.pause, m_pause, mapping_device_choice::PAUSE); -#undef SAVE_MAPPING + save_mapping(cfg.shifter_1, m_shifter_1, mapping_device_choice::SHIFTER_1); + save_mapping(cfg.shifter_2, m_shifter_2, mapping_device_choice::SHIFTER_2); + save_mapping(cfg.shifter_3, m_shifter_3, mapping_device_choice::SHIFTER_3); + save_mapping(cfg.shifter_4, m_shifter_4, mapping_device_choice::SHIFTER_4); + save_mapping(cfg.shifter_5, m_shifter_5, mapping_device_choice::SHIFTER_5); + save_mapping(cfg.shifter_6, m_shifter_6, mapping_device_choice::SHIFTER_6); + save_mapping(cfg.shifter_r, m_shifter_r, mapping_device_choice::SHIFTER_R); g_cfg_logitech_g27.enabled.set(m_enabled->isChecked()); g_cfg_logitech_g27.reverse_effects.set(m_reverse_effects->isChecked()); - if (m_ffb_device->get_device_choice() == CHOICE_NONE) + if (m_ffb_device->get_device_choice() == mapping_device_choice::NONE) { g_cfg_logitech_g27.ffb_device_type_id.set(0); } - if (m_led_device->get_device_choice() == CHOICE_NONE) + if (m_led_device->get_device_choice() == mapping_device_choice::NONE) { g_cfg_logitech_g27.led_device_type_id.set(0); } @@ -569,66 +527,68 @@ void emulated_logitech_g27_settings_dialog::save_ui_state_to_config() void emulated_logitech_g27_settings_dialog::load_ui_state_from_config() { -#define LOAD_MAPPING(name, device_choice) \ - { \ - const sdl_mapping m = { \ - .device_type_id = static_cast(g_cfg_logitech_g27.name.device_type_id.get()), \ - .type = static_cast(g_cfg_logitech_g27.name.type.get()), \ - .id = static_cast(g_cfg_logitech_g27.name.id.get()), \ - .hat = static_cast(g_cfg_logitech_g27.name.hat.get()), \ - .reverse = g_cfg_logitech_g27.name.reverse.get(), \ - .positive_axis = false}; \ - m_##name->set_mapping(m); \ - if (g_cfg_logitech_g27.ffb_device_type_id.get() == m.device_type_id && m_ffb_device->get_device_choice() == CHOICE_NONE) \ - { \ - m_ffb_device->set_device_choice(device_choice); \ - } \ - if (g_cfg_logitech_g27.led_device_type_id.get() == m.device_type_id && m_led_device->get_device_choice() == CHOICE_NONE) \ - { \ - m_led_device->set_device_choice(device_choice); \ - } \ - } + const auto load_mapping = [this](const emulated_logitech_g27_mapping& mapping, Mapping* ui_mapping, mapping_device_choice device_choice) + { + const sdl_mapping m = + { + .device_type_id = mapping.device_type_id.get(), + .type = mapping.type.get(), + .id = mapping.id.get(), + .hat = mapping.hat.get(), + .reverse = mapping.reverse.get(), + .positive_axis = false + }; + ui_mapping->set_mapping(m); + if (g_cfg_logitech_g27.ffb_device_type_id.get() == m.device_type_id && m_ffb_device->get_device_choice() == mapping_device_choice::NONE) + { + m_ffb_device->set_device_choice(device_choice); + } + if (g_cfg_logitech_g27.led_device_type_id.get() == m.device_type_id && m_led_device->get_device_choice() == mapping_device_choice::NONE) + { + m_led_device->set_device_choice(device_choice); + } + }; - LOAD_MAPPING(steering, CHOICE_STEERING); - LOAD_MAPPING(throttle, CHOICE_THROTTLE); - LOAD_MAPPING(brake, CHOICE_BRAKE); - LOAD_MAPPING(clutch, CHOICE_CLUTCH); - LOAD_MAPPING(shift_up, CHOICE_SHIFT_UP); - LOAD_MAPPING(shift_down, CHOICE_SHIFT_DOWN); + const auto& cfg = g_cfg_logitech_g27; - LOAD_MAPPING(up, CHOICE_UP); - LOAD_MAPPING(down, CHOICE_DOWN); - LOAD_MAPPING(left, CHOICE_LEFT); - LOAD_MAPPING(right, CHOICE_RIGHT); + load_mapping(cfg.steering, m_steering, mapping_device_choice::STEERING); + load_mapping(cfg.throttle, m_throttle, mapping_device_choice::THROTTLE); + load_mapping(cfg.brake, m_brake, mapping_device_choice::BRAKE); + load_mapping(cfg.clutch, m_clutch, mapping_device_choice::CLUTCH); + load_mapping(cfg.shift_up, m_shift_up, mapping_device_choice::SHIFT_UP); + load_mapping(cfg.shift_down, m_shift_down, mapping_device_choice::SHIFT_DOWN); - LOAD_MAPPING(triangle, CHOICE_TRIANGLE); - LOAD_MAPPING(cross, CHOICE_CROSS); - LOAD_MAPPING(square, CHOICE_SQUARE); - LOAD_MAPPING(circle, CHOICE_CIRCLE); + load_mapping(cfg.up, m_up, mapping_device_choice::UP); + load_mapping(cfg.down, m_down, mapping_device_choice::DOWN); + load_mapping(cfg.left, m_left, mapping_device_choice::LEFT); + load_mapping(cfg.right, m_right, mapping_device_choice::RIGHT); - LOAD_MAPPING(l2, CHOICE_L2); - LOAD_MAPPING(l3, CHOICE_L3); - LOAD_MAPPING(r2, CHOICE_R2); - LOAD_MAPPING(r3, CHOICE_R3); + load_mapping(cfg.triangle, m_triangle, mapping_device_choice::TRIANGLE); + load_mapping(cfg.cross, m_cross, mapping_device_choice::CROSS); + load_mapping(cfg.square, m_square, mapping_device_choice::SQUARE); + load_mapping(cfg.circle, m_circle, mapping_device_choice::CIRCLE); - LOAD_MAPPING(plus, CHOICE_PLUS); - LOAD_MAPPING(minus, CHOICE_MINUS); + load_mapping(cfg.l2, m_l2, mapping_device_choice::L2); + load_mapping(cfg.l3, m_l3, mapping_device_choice::L3); + load_mapping(cfg.r2, m_r2, mapping_device_choice::R2); + load_mapping(cfg.r3, m_r3, mapping_device_choice::R3); - LOAD_MAPPING(dial_clockwise, CHOICE_DIAL_CLOCKWISE); - LOAD_MAPPING(dial_anticlockwise, CHOICE_DIAL_ANTICLOCKWISE); + load_mapping(cfg.plus, m_plus, mapping_device_choice::PLUS); + load_mapping(cfg.minus, m_minus, mapping_device_choice::MINUS); - LOAD_MAPPING(select, CHOICE_SELECT); - LOAD_MAPPING(pause, CHOICE_PAUSE); + load_mapping(cfg.dial_clockwise, m_dial_clockwise, mapping_device_choice::DIAL_CLOCKWISE); + load_mapping(cfg.dial_anticlockwise, m_dial_anticlockwise, mapping_device_choice::DIAL_ANTICLOCKWISE); - LOAD_MAPPING(shifter_1, CHOICE_SHIFTER_1); - LOAD_MAPPING(shifter_2, CHOICE_SHIFTER_2); - LOAD_MAPPING(shifter_3, CHOICE_SHIFTER_3); - LOAD_MAPPING(shifter_4, CHOICE_SHIFTER_4); - LOAD_MAPPING(shifter_5, CHOICE_SHIFTER_5); - LOAD_MAPPING(shifter_6, CHOICE_SHIFTER_6); - LOAD_MAPPING(shifter_r, CHOICE_SHIFTER_R); + load_mapping(cfg.select, m_select, mapping_device_choice::SELECT); + load_mapping(cfg.pause, m_pause, mapping_device_choice::PAUSE); -#undef LOAD_MAPPING + load_mapping(cfg.shifter_1, m_shifter_1, mapping_device_choice::SHIFTER_1); + load_mapping(cfg.shifter_2, m_shifter_2, mapping_device_choice::SHIFTER_2); + load_mapping(cfg.shifter_3, m_shifter_3, mapping_device_choice::SHIFTER_3); + load_mapping(cfg.shifter_4, m_shifter_4, mapping_device_choice::SHIFTER_4); + load_mapping(cfg.shifter_5, m_shifter_5, mapping_device_choice::SHIFTER_5); + load_mapping(cfg.shifter_6, m_shifter_6, mapping_device_choice::SHIFTER_6); + load_mapping(cfg.shifter_r, m_shifter_r, mapping_device_choice::SHIFTER_R); m_enabled->setChecked(g_cfg_logitech_g27.enabled.get()); m_reverse_effects->setChecked(g_cfg_logitech_g27.reverse_effects.get()); @@ -651,49 +611,49 @@ emulated_logitech_g27_settings_dialog::emulated_logitech_g27_settings_dialog(QWi g_cfg_logitech_g27.load(); connect(buttons, &QDialogButtonBox::clicked, this, [this, buttons](QAbstractButton* button) + { + if (button == buttons->button(QDialogButtonBox::Apply)) { - if (button == buttons->button(QDialogButtonBox::Apply)) - { - save_ui_state_to_config(); - g_cfg_logitech_g27.save(); - load_ui_state_from_config(); - } - else if (button == buttons->button(QDialogButtonBox::Save)) - { - save_ui_state_to_config(); - g_cfg_logitech_g27.save(); - accept(); - } - else if (button == buttons->button(QDialogButtonBox::RestoreDefaults)) - { - if (QMessageBox::question(this, tr("Confirm Reset"), tr("Reset all?")) != QMessageBox::Yes) - return; - g_cfg_logitech_g27.reset(); - load_ui_state_from_config(); - g_cfg_logitech_g27.save(); - } - else if (button == buttons->button(QDialogButtonBox::Cancel)) - { - reject(); - } - }); + save_ui_state_to_config(); + g_cfg_logitech_g27.save(); + load_ui_state_from_config(); + } + else if (button == buttons->button(QDialogButtonBox::Save)) + { + save_ui_state_to_config(); + g_cfg_logitech_g27.save(); + accept(); + } + else if (button == buttons->button(QDialogButtonBox::RestoreDefaults)) + { + if (QMessageBox::question(this, tr("Confirm Reset"), tr("Reset all?")) != QMessageBox::Yes) + return; + g_cfg_logitech_g27.reset(); + load_ui_state_from_config(); + g_cfg_logitech_g27.save(); + } + else if (button == buttons->button(QDialogButtonBox::Cancel)) + { + reject(); + } + }); - QLabel* warning = new QLabel(QString("Warning: Force feedback output were meant for Logitech G27, on stronger wheels please adjust force strength accordingly in your wheel software."), this); + QLabel* warning = new QLabel(tr("Warning: Force feedback output were meant for Logitech G27, on stronger wheels please adjust force strength accordingly in your wheel software."), this); warning->setStyleSheet("color: red;"); warning->setWordWrap(true); v_layout->addWidget(warning); - m_enabled = new QCheckBox(QString("Enabled (requires game restart)"), this); + m_enabled = new QCheckBox(tr("Enabled (requires game restart)"), this); v_layout->addWidget(m_enabled); - m_reverse_effects = new QCheckBox(QString("Reverse force feedback effects"), this); + m_reverse_effects = new QCheckBox(tr("Reverse force feedback effects"), this); v_layout->addWidget(m_reverse_effects); - m_state_text = new QLabel(QString(DEFAULT_STATUS), this); + m_state_text = new QLabel(DEFAULT_STATUS, this); v_layout->addWidget(m_state_text); - m_ffb_device = new DeviceChoice(this, "Use the device with the following mapping for force feedback:"); - m_led_device = new DeviceChoice(this, "Use the device with the following mapping for LED:"); + m_ffb_device = new DeviceChoice(this, tr("Use the device with the following mapping for force feedback:")); + m_led_device = new DeviceChoice(this, tr("Use the device with the following mapping for LED:")); m_mapping_scroll_area = new QScrollArea(this); QWidget* mapping_widget = new QWidget(m_mapping_scroll_area); @@ -707,57 +667,57 @@ emulated_logitech_g27_settings_dialog::emulated_logitech_g27_settings_dialog(QWi v_layout->addWidget(m_mapping_scroll_area); - QLabel* axis_label = new QLabel(QString("Axes:"), mapping_widget); + QLabel* axis_label = new QLabel(tr("Axes:"), mapping_widget); mapping_layout->addWidget(axis_label); - auto add_mapping_setting = [mapping_widget, this, mapping_layout](Mapping*& target, bool is_axis, const char* display_name, bool flip_axis_display) + const auto add_mapping_setting = [mapping_widget, this, mapping_layout](Mapping*& target, bool is_axis, const QString& display_name, bool flip_axis_display) { target = new Mapping(mapping_widget, this, is_axis, display_name, flip_axis_display); mapping_layout->addWidget(target); }; - add_mapping_setting(m_steering, true, "Steering", false); - add_mapping_setting(m_throttle, true, "Throttle", true); - add_mapping_setting(m_brake, true, "Brake", true); - add_mapping_setting(m_clutch, true, "Clutch", true); + add_mapping_setting(m_steering, true, tr("Steering"), false); + add_mapping_setting(m_throttle, true, tr("Throttle"), true); + add_mapping_setting(m_brake, true, tr("Brake"), true); + add_mapping_setting(m_clutch, true, tr("Clutch"), true); - QLabel* button_label = new QLabel(QString("Buttons:"), mapping_widget); + QLabel* button_label = new QLabel(tr("Buttons:"), mapping_widget); mapping_layout->addWidget(button_label); - add_mapping_setting(m_shift_up, false, "Shift up", false); - add_mapping_setting(m_shift_down, false, "Shift down", false); + add_mapping_setting(m_shift_up, false, tr("Shift up"), false); + add_mapping_setting(m_shift_down, false, tr("Shift down"), false); - add_mapping_setting(m_up, false, "Up", false); - add_mapping_setting(m_down, false, "Down", false); - add_mapping_setting(m_left, false, "Left", false); - add_mapping_setting(m_right, false, "Right", false); + add_mapping_setting(m_up, false, tr("Up"), false); + add_mapping_setting(m_down, false, tr("Down"), false); + add_mapping_setting(m_left, false, tr("Left"), false); + add_mapping_setting(m_right, false, tr("Right"), false); - add_mapping_setting(m_triangle, false, "Triangle", false); - add_mapping_setting(m_cross, false, "Cross", false); - add_mapping_setting(m_square, false, "Square", false); - add_mapping_setting(m_circle, false, "Circle", false); + add_mapping_setting(m_triangle, false, tr("Triangle"), false); + add_mapping_setting(m_cross, false, tr("Cross"), false); + add_mapping_setting(m_square, false, tr("Square"), false); + add_mapping_setting(m_circle, false, tr("Circle"), false); - add_mapping_setting(m_l2, false, "L2", false); - add_mapping_setting(m_l3, false, "L3", false); - add_mapping_setting(m_r2, false, "R2", false); - add_mapping_setting(m_r3, false, "R3", false); + add_mapping_setting(m_l2, false, tr("L2"), false); + add_mapping_setting(m_l3, false, tr("L3"), false); + add_mapping_setting(m_r2, false, tr("R2"), false); + add_mapping_setting(m_r3, false, tr("R3"), false); - add_mapping_setting(m_plus, false, "L4", false); - add_mapping_setting(m_minus, false, "L5", false); + add_mapping_setting(m_plus, false, tr("L4"), false); + add_mapping_setting(m_minus, false, tr("L5"), false); - add_mapping_setting(m_dial_clockwise, false, "R4", false); - add_mapping_setting(m_dial_anticlockwise, false, "R5", false); + add_mapping_setting(m_dial_clockwise, false, tr("R4"), false); + add_mapping_setting(m_dial_anticlockwise, false, tr("R5"), false); - add_mapping_setting(m_select, false, "Select", false); - add_mapping_setting(m_pause, false, "Start", false); + add_mapping_setting(m_select, false, tr("Select"), false); + add_mapping_setting(m_pause, false, tr("Start"), false); - add_mapping_setting(m_shifter_1, false, "Gear 1", false); - add_mapping_setting(m_shifter_2, false, "Gear 2", false); - add_mapping_setting(m_shifter_3, false, "Gear 3", false); - add_mapping_setting(m_shifter_4, false, "Gear 4", false); - add_mapping_setting(m_shifter_5, false, "Gear 5", false); - add_mapping_setting(m_shifter_6, false, "Gear 6", false); - add_mapping_setting(m_shifter_r, false, "Gear R", false); + add_mapping_setting(m_shifter_1, false, tr("Gear 1"), false); + add_mapping_setting(m_shifter_2, false, tr("Gear 2"), false); + add_mapping_setting(m_shifter_3, false, tr("Gear 3"), false); + add_mapping_setting(m_shifter_4, false, tr("Gear 4"), false); + add_mapping_setting(m_shifter_5, false, tr("Gear 5"), false); + add_mapping_setting(m_shifter_6, false, tr("Gear 6"), false); + add_mapping_setting(m_shifter_r, false, tr("Gear R"), false); v_layout->addSpacing(20); @@ -777,83 +737,80 @@ emulated_logitech_g27_settings_dialog::emulated_logitech_g27_settings_dialog(QWi emulated_logitech_g27_settings_dialog::~emulated_logitech_g27_settings_dialog() { - for (auto joystick_handle : m_joystick_handles) + for (SDL_Joystick* joystick_handle : m_joystick_handles) { if (joystick_handle) - SDL_CloseJoystick(reinterpret_cast(joystick_handle)); + SDL_CloseJoystick(joystick_handle); } } -static inline hat_component get_sdl_hat_component(uint8_t sdl_hat) +static inline hat_component get_sdl_hat_component(u8 sdl_hat) { if (sdl_hat & SDL_HAT_UP) { - return HAT_UP; + return hat_component::up; } if (sdl_hat & SDL_HAT_DOWN) { - return HAT_DOWN; + return hat_component::down; } if (sdl_hat & SDL_HAT_LEFT) { - return HAT_LEFT; + return hat_component::left; } if (sdl_hat & SDL_HAT_RIGHT) { - return HAT_RIGHT; + return hat_component::right; } - return HAT_NONE; + return hat_component::none; } -const std::map& emulated_logitech_g27_settings_dialog::get_joystick_states() +const std::map& emulated_logitech_g27_settings_dialog::get_joystick_states() { if (!m_sdl_initialized) { return m_last_joystick_states; } - uint64_t now = SDL_GetTicks(); + const u64 now = SDL_GetTicks(); - if (SDL_GetTicks() - m_last_joystick_states_update < 25) + if (now - m_last_joystick_states_update < 25) { return m_last_joystick_states; } m_last_joystick_states_update = now; - std::map new_joystick_states; + std::map new_joystick_states; + std::vector new_joystick_handles; sdl_instance::get_instance().pump_events(); - int joystick_count; - SDL_JoystickID* joystick_ids = SDL_GetJoysticks(&joystick_count); - - std::vector new_joystick_handles; - - if (joystick_ids != nullptr) + int joystick_count = 0; + if (SDL_JoystickID* joystick_ids = SDL_GetJoysticks(&joystick_count)) { for (int i = 0; i < joystick_count; i++) { SDL_Joystick* cur_joystick = SDL_OpenJoystick(joystick_ids[i]); - if (cur_joystick == nullptr) + if (!cur_joystick) { continue; } new_joystick_handles.push_back(cur_joystick); - uint32_t device_type_id = (SDL_GetJoystickVendor(cur_joystick) << 16) | SDL_GetJoystickProduct(cur_joystick); + const u32 device_type_id = (SDL_GetJoystickVendor(cur_joystick) << 16) | SDL_GetJoystickProduct(cur_joystick); auto cur_state = new_joystick_states.find(device_type_id); if (cur_state == new_joystick_states.end()) { - joystick_state s; - int num_axes = SDL_GetNumJoystickAxes(cur_joystick); - int num_buttons = SDL_GetNumJoystickButtons(cur_joystick); - int num_hats = SDL_GetNumJoystickHats(cur_joystick); + joystick_state s {}; + const int num_axes = SDL_GetNumJoystickAxes(cur_joystick); + const int num_buttons = SDL_GetNumJoystickButtons(cur_joystick); + const int num_hats = SDL_GetNumJoystickHats(cur_joystick); for (int j = 0; j < num_axes; j++) { s.axes.push_back(SDL_GetJoystickAxis(cur_joystick, j)); @@ -864,36 +821,36 @@ const std::map& emulated_logitech_g27_settings_dialog: } for (int j = 0; j < num_hats; j++) { - uint8_t sdl_hat = SDL_GetJoystickHat(cur_joystick, j); + const u8 sdl_hat = SDL_GetJoystickHat(cur_joystick, j); s.hats.push_back(get_sdl_hat_component(sdl_hat)); } new_joystick_states[device_type_id] = s; } else { - for (std::vector::size_type j = 0; j < cur_state->second.axes.size(); j++) + for (s32 j = 0; j < static_cast(cur_state->second.axes.size()); j++) { cur_state->second.axes[j] = (cur_state->second.axes[j] + SDL_GetJoystickAxis(cur_joystick, j)) / 2; } - for (std::vector::size_type j = 0; j < cur_state->second.buttons.size(); j++) + for (s32 j = 0; j < static_cast(cur_state->second.buttons.size()); j++) { cur_state->second.buttons[j] = cur_state->second.buttons[j] || SDL_GetJoystickButton(cur_joystick, j); } - for (std::vector::size_type j = 0; j < cur_state->second.hats.size(); j++) + for (s32 j = 0; j < static_cast(cur_state->second.hats.size()); j++) { - if (cur_state->second.hats[j] != HAT_NONE) + if (cur_state->second.hats[j] != hat_component::none) continue; - uint8_t sdl_hat = SDL_GetJoystickHat(cur_joystick, j); + const u8 sdl_hat = SDL_GetJoystickHat(cur_joystick, j); cur_state->second.hats[j] = get_sdl_hat_component(sdl_hat); } } } } - for (auto joystick_handle : m_joystick_handles) + for (SDL_Joystick* joystick_handle : m_joystick_handles) { if (joystick_handle) - SDL_CloseJoystick(reinterpret_cast(joystick_handle)); + SDL_CloseJoystick(joystick_handle); } m_joystick_handles = new_joystick_handles; @@ -902,9 +859,9 @@ const std::map& emulated_logitech_g27_settings_dialog: return m_last_joystick_states; } -void emulated_logitech_g27_settings_dialog::set_state_text(const char* text) +void emulated_logitech_g27_settings_dialog::set_state_text(const QString& text) { - m_state_text->setText(QString(text)); + m_state_text->setText(text); } void emulated_logitech_g27_settings_dialog::set_enable(bool enable) @@ -960,13 +917,4 @@ void emulated_logitech_g27_settings_dialog::set_enable(bool enable) m_mapping_scroll_area->verticalScrollBar()->setSliderPosition(slider_position); } -#else - -// minimal symbols for sdl-less builds automoc -#include "emulated_logitech_g27_settings_dialog.h" - -emulated_logitech_g27_settings_dialog::emulated_logitech_g27_settings_dialog(QWidget* parent) - : QDialog(parent) {} -emulated_logitech_g27_settings_dialog::~emulated_logitech_g27_settings_dialog() {}; - #endif diff --git a/rpcs3/rpcs3qt/emulated_logitech_g27_settings_dialog.h b/rpcs3/rpcs3qt/emulated_logitech_g27_settings_dialog.h index ef28f2eff7..1983cc0a2a 100644 --- a/rpcs3/rpcs3qt/emulated_logitech_g27_settings_dialog.h +++ b/rpcs3/rpcs3qt/emulated_logitech_g27_settings_dialog.h @@ -1,11 +1,12 @@ #pragma once +#ifdef HAVE_SDL3 + #include #include #include #include -#ifdef HAVE_SDL3 #ifndef _MSC_VER #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" @@ -14,7 +15,6 @@ #ifndef _MSC_VER #pragma GCC diagnostic pop #endif -#endif #include #include @@ -22,7 +22,7 @@ struct joystick_state { - std::vector axes; + std::vector axes; std::vector buttons; std::vector hats; }; @@ -36,15 +36,17 @@ class emulated_logitech_g27_settings_dialog : public QDialog public: emulated_logitech_g27_settings_dialog(QWidget* parent = nullptr); - ~emulated_logitech_g27_settings_dialog(); - void set_state_text(const char*); - const std::map& get_joystick_states(); + virtual ~emulated_logitech_g27_settings_dialog(); + void set_state_text(const QString& text); + const std::map& get_joystick_states(); void set_enable(bool enable); private: - std::map m_last_joystick_states; - // hack: need a completed dummy class when linking automoc generated with sdl-less build - std::vector m_joystick_handles; + void load_ui_state_from_config(); + void save_ui_state_to_config(); + + std::map m_last_joystick_states; + std::vector m_joystick_handles; uint64_t m_last_joystick_states_update = 0; bool m_sdl_initialized = false; @@ -97,7 +99,6 @@ private: DeviceChoice* m_led_device = nullptr; QScrollArea* m_mapping_scroll_area = nullptr; - - void load_ui_state_from_config(); - void save_ui_state_to_config(); }; + +#endif