From 498db18f2c1717028bf6f3ec891242876ca86810 Mon Sep 17 00:00:00 2001 From: Sepalani Date: Fri, 2 May 2025 15:29:34 +0400 Subject: [PATCH] Keyboard: Add a configuration window Add MAIN_WII_KEYBOARD_TRANSLATION to toggle the layout translation --- Source/Core/Common/Keyboard.cpp | 5 +- Source/Core/Core/Config/MainSettings.cpp | 2 + Source/Core/Core/Config/MainSettings.h | 1 + Source/Core/DolphinQt/CMakeLists.txt | 2 + Source/Core/DolphinQt/DolphinQt.vcxproj | 2 + .../Core/DolphinQt/EmulatedUSB/Keyboard.cpp | 90 +++++++++++++++++++ Source/Core/DolphinQt/EmulatedUSB/Keyboard.h | 17 ++++ Source/Core/DolphinQt/MainWindow.cpp | 14 +++ Source/Core/DolphinQt/MainWindow.h | 3 + Source/Core/DolphinQt/MenuBar.cpp | 1 + Source/Core/DolphinQt/MenuBar.h | 1 + 11 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 Source/Core/DolphinQt/EmulatedUSB/Keyboard.cpp create mode 100644 Source/Core/DolphinQt/EmulatedUSB/Keyboard.h diff --git a/Source/Core/Common/Keyboard.cpp b/Source/Core/Common/Keyboard.cpp index c93c97bd2a..29d8cef59e 100644 --- a/Source/Core/Common/Keyboard.cpp +++ b/Source/Core/Common/Keyboard.cpp @@ -140,7 +140,10 @@ int GetGameLayout() u8 MapVirtualKeyToHID(u8 virtual_key, int host_layout, int game_layout) { // SDL3 keyboard state uses scan codes already based on HID usage id - return TranslateUsageID(virtual_key, host_layout, game_layout); + u8 usage_id = virtual_key; + if (Config::Get(Config::MAIN_WII_KEYBOARD_TRANSLATION)) + usage_id = TranslateUsageID(usage_id, host_layout, game_layout); + return usage_id; } std::weak_ptr s_keyboard_context; diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index a89565bb6a..8fb4704586 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -198,6 +198,8 @@ const Info MAIN_WII_SD_CARD_FILESIZE{{System::Main, "Core", "WiiSDCardFiles const Info MAIN_WII_KEYBOARD{{System::Main, "Core", "WiiKeyboard"}, false}; const Info MAIN_WII_KEYBOARD_HOST_LAYOUT{{System::Main, "Core", "WiiKeyboardHostLayout"}, 0}; const Info MAIN_WII_KEYBOARD_GAME_LAYOUT{{System::Main, "Core", "WiiKeyboardGameLayout"}, 0}; +const Info MAIN_WII_KEYBOARD_TRANSLATION{{System::Main, "Core", "WiiKeyboardTranslation"}, + false}; const Info MAIN_WIIMOTE_CONTINUOUS_SCANNING{ {System::Main, "Core", "WiimoteContinuousScanning"}, false}; const Info MAIN_WIIMOTE_AUTO_CONNECT_ADDRESSES{ diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index 6fe42bb279..1d39f23b0d 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -110,6 +110,7 @@ extern const Info MAIN_WII_SD_CARD_FILESIZE; extern const Info MAIN_WII_KEYBOARD; extern const Info MAIN_WII_KEYBOARD_HOST_LAYOUT; extern const Info MAIN_WII_KEYBOARD_GAME_LAYOUT; +extern const Info MAIN_WII_KEYBOARD_TRANSLATION; extern const Info MAIN_WIIMOTE_CONTINUOUS_SCANNING; extern const Info MAIN_WIIMOTE_AUTO_CONNECT_ADDRESSES; extern const Info MAIN_WIIMOTE_ENABLE_SPEAKER; diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index f277a982b6..b20fcc4c9e 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -249,6 +249,8 @@ add_executable(dolphin-emu DiscordHandler.h DiscordJoinRequestDialog.cpp DiscordJoinRequestDialog.h + EmulatedUSB/Keyboard.cpp + EmulatedUSB/Keyboard.h EmulatedUSB/WiiSpeakWindow.cpp EmulatedUSB/WiiSpeakWindow.h FIFO/FIFOAnalyzer.cpp diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj index 0250f7260e..5c538b9610 100644 --- a/Source/Core/DolphinQt/DolphinQt.vcxproj +++ b/Source/Core/DolphinQt/DolphinQt.vcxproj @@ -158,6 +158,7 @@ + @@ -380,6 +381,7 @@ + diff --git a/Source/Core/DolphinQt/EmulatedUSB/Keyboard.cpp b/Source/Core/DolphinQt/EmulatedUSB/Keyboard.cpp new file mode 100644 index 0000000000..e21b390b36 --- /dev/null +++ b/Source/Core/DolphinQt/EmulatedUSB/Keyboard.cpp @@ -0,0 +1,90 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "DolphinQt/EmulatedUSB/Keyboard.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "Common/Keyboard.h" +#include "Core/Config/MainSettings.h" +#include "DolphinQt/Config/ConfigControls/ConfigBool.h" +#include "DolphinQt/Settings.h" + +KeyboardWindow::KeyboardWindow(QWidget* parent) : QWidget(parent) +{ + // i18n: Window for managing the Wii keyboard emulation + setWindowTitle(tr("Keyboard Manager")); + setObjectName(QStringLiteral("keyboard_manager")); + setMinimumSize(QSize(500, 200)); + + auto* main_layout = new QVBoxLayout(); + + { + auto* group = new QGroupBox(); + auto* hbox_layout = new QHBoxLayout(); + hbox_layout->setAlignment(Qt::AlignHCenter); + auto* checkbox_emulate = new QCheckBox(tr("Emulate USB keyboard"), this); + checkbox_emulate->setChecked(Settings::Instance().IsUSBKeyboardConnected()); + connect(checkbox_emulate, &QCheckBox::toggled, this, &KeyboardWindow::EmulateKeyboard); + connect(&Settings::Instance(), &Settings::USBKeyboardConnectionChanged, checkbox_emulate, + &QCheckBox::setChecked); + hbox_layout->addWidget(checkbox_emulate); + group->setLayout(hbox_layout); + + main_layout->addWidget(group); + } + + { + auto* group = new QGroupBox(tr("Layout Configuration")); + auto* grid_layout = new QGridLayout(); + auto* checkbox_translate = + new ConfigBool(tr("Enable partial translation"), Config::MAIN_WII_KEYBOARD_TRANSLATION); + grid_layout->addWidget(checkbox_translate, 0, 0, 1, 2, Qt::AlignLeft); + + auto create_combo = [checkbox_translate, grid_layout](int row, const QString& name, + const auto& config_info) { + grid_layout->addWidget(new QLabel(name), row, 0); + auto* combo = new QComboBox(); + + combo->addItem(tr("Automatic detection"), Common::KeyboardLayout::AUTO); + combo->addItem(QStringLiteral("QWERTY"), Common::KeyboardLayout::QWERTY); + combo->addItem(QStringLiteral("AZERTY"), Common::KeyboardLayout::AZERTY); + combo->addItem(QStringLiteral("QWERTZ"), Common::KeyboardLayout::QWERTZ); + combo->setCurrentIndex(combo->findData(Config::Get(config_info))); + combo->setEnabled(checkbox_translate->isChecked()); + + connect(combo, &QComboBox::currentIndexChanged, combo, [combo, config_info] { + const auto keyboard_layout = combo->currentData(); + if (!keyboard_layout.isValid()) + return; + + Config::SetBaseOrCurrent(config_info, keyboard_layout.toInt()); + Common::KeyboardContext::UpdateLayout(); + }); + connect(checkbox_translate, &QCheckBox::toggled, combo, &QComboBox::setEnabled); + + grid_layout->addWidget(combo, row, 1); + }; + + create_combo(1, tr("Host layout:"), Config::MAIN_WII_KEYBOARD_HOST_LAYOUT); + create_combo(2, tr("Game layout:"), Config::MAIN_WII_KEYBOARD_GAME_LAYOUT); + group->setLayout(grid_layout); + + main_layout->addWidget(group); + } + + setLayout(main_layout); +} + +KeyboardWindow::~KeyboardWindow() = default; + +void KeyboardWindow::EmulateKeyboard(bool emulate) const +{ + Settings::Instance().SetUSBKeyboardConnected(emulate); +} diff --git a/Source/Core/DolphinQt/EmulatedUSB/Keyboard.h b/Source/Core/DolphinQt/EmulatedUSB/Keyboard.h new file mode 100644 index 0000000000..73d3547744 --- /dev/null +++ b/Source/Core/DolphinQt/EmulatedUSB/Keyboard.h @@ -0,0 +1,17 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +class KeyboardWindow : public QWidget +{ + Q_OBJECT +public: + explicit KeyboardWindow(QWidget* parent = nullptr); + ~KeyboardWindow() override; + +private: + void EmulateKeyboard(bool emulate) const; +}; diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 488ca8ecd6..c2afac0a64 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -93,6 +93,7 @@ #include "DolphinQt/Debugger/ThreadWidget.h" #include "DolphinQt/Debugger/WatchWidget.h" #include "DolphinQt/DiscordHandler.h" +#include "DolphinQt/EmulatedUSB/Keyboard.h" #include "DolphinQt/EmulatedUSB/WiiSpeakWindow.h" #include "DolphinQt/FIFO/FIFOPlayerWindow.h" #include "DolphinQt/GCMemcardManager.h" @@ -579,6 +580,7 @@ void MainWindow::ConnectMenuBar() connect(m_menu_bar, &MenuBar::ShowSkylanderPortal, this, &MainWindow::ShowSkylanderPortal); connect(m_menu_bar, &MenuBar::ShowInfinityBase, this, &MainWindow::ShowInfinityBase); connect(m_menu_bar, &MenuBar::ShowWiiSpeakWindow, this, &MainWindow::ShowWiiSpeakWindow); + connect(m_menu_bar, &MenuBar::ShowKeyboard, this, &MainWindow::ShowKeyboard); connect(m_menu_bar, &MenuBar::ConnectWiiRemote, this, &MainWindow::OnConnectWiiRemote); #ifdef USE_RETRO_ACHIEVEMENTS @@ -1425,6 +1427,18 @@ void MainWindow::ShowWiiSpeakWindow() m_wii_speak_window->activateWindow(); } +void MainWindow::ShowKeyboard() +{ + if (!m_keyboard_window) + { + m_keyboard_window = new KeyboardWindow(); + } + + m_keyboard_window->show(); + m_keyboard_window->raise(); + m_keyboard_window->activateWindow(); +} + void MainWindow::StateLoad() { QString dialog_path = (Config::Get(Config::MAIN_CURRENT_STATE_PATH).empty()) ? diff --git a/Source/Core/DolphinQt/MainWindow.h b/Source/Core/DolphinQt/MainWindow.h index d648e6189c..0ac2d4ed81 100644 --- a/Source/Core/DolphinQt/MainWindow.h +++ b/Source/Core/DolphinQt/MainWindow.h @@ -36,6 +36,7 @@ class GBATASInputWindow; class GCTASInputWindow; class HotkeyScheduler; class InfinityBaseWindow; +class KeyboardWindow; class JITWidget; class LogConfigWidget; class LogWidget; @@ -177,6 +178,7 @@ private: void ShowSkylanderPortal(); void ShowInfinityBase(); void ShowWiiSpeakWindow(); + void ShowKeyboard(); void ShowMemcardManager(); void ShowResourcePackManager(); void ShowCheatsManager(); @@ -249,6 +251,7 @@ private: SkylanderPortalWindow* m_skylander_window = nullptr; InfinityBaseWindow* m_infinity_window = nullptr; WiiSpeakWindow* m_wii_speak_window = nullptr; + KeyboardWindow* m_keyboard_window = nullptr; MappingWindow* m_hotkey_window = nullptr; FreeLookWindow* m_freelook_window = nullptr; diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp index 6f21030294..82b6291557 100644 --- a/Source/Core/DolphinQt/MenuBar.cpp +++ b/Source/Core/DolphinQt/MenuBar.cpp @@ -280,6 +280,7 @@ void MenuBar::AddToolsMenu() usb_device_menu->addAction(tr("&Skylanders Portal"), this, &MenuBar::ShowSkylanderPortal); usb_device_menu->addAction(tr("&Infinity Base"), this, &MenuBar::ShowInfinityBase); usb_device_menu->addAction(tr("&Wii Speak"), this, &MenuBar::ShowWiiSpeakWindow); + usb_device_menu->addAction(tr("&Keyboard"), this, &MenuBar::ShowKeyboard); tools_menu->addMenu(usb_device_menu); tools_menu->addSeparator(); diff --git a/Source/Core/DolphinQt/MenuBar.h b/Source/Core/DolphinQt/MenuBar.h index 934772e72c..075155739c 100644 --- a/Source/Core/DolphinQt/MenuBar.h +++ b/Source/Core/DolphinQt/MenuBar.h @@ -95,6 +95,7 @@ signals: void ShowSkylanderPortal(); void ShowInfinityBase(); void ShowWiiSpeakWindow(); + void ShowKeyboard(); void ConnectWiiRemote(int id); #ifdef USE_RETRO_ACHIEVEMENTS