From b673857d7dfc72f38d9242b315cd590b859795ff Mon Sep 17 00:00:00 2001
From: german77 <juangerman-13@hotmail.com>
Date: Sat, 13 Nov 2021 23:25:45 -0600
Subject: [PATCH] core/hid: Improve accuracy of the keyboard implementation

---
 src/common/settings_input.h                   |  35 +-
 src/core/hid/emulated_devices.cpp             |   3 +-
 src/core/hid/hid_types.h                      | 398 ++++++++++++------
 .../hle/service/hid/controllers/keyboard.cpp  |   1 +
 src/core/hle/service/hid/hid.cpp              |  35 +-
 src/core/hle/service/hid/hid.h                |   2 +
 src/input_common/drivers/keyboard.cpp         |  53 ++-
 src/input_common/drivers/keyboard.h           |   7 +
 src/input_common/main.cpp                     |   9 +
 src/input_common/main.h                       |   3 +
 src/yuzu/bootmanager.cpp                      | 276 +++++++++++-
 src/yuzu/bootmanager.h                        |   6 +
 src/yuzu/configuration/config.cpp             | 167 +-------
 13 files changed, 682 insertions(+), 313 deletions(-)

diff --git a/src/common/settings_input.h b/src/common/settings_input.h
index 2c0eb31d39..a2982fca46 100644
--- a/src/common/settings_input.h
+++ b/src/common/settings_input.h
@@ -129,7 +129,6 @@ extern const std::array<const char*, NumMouseButtons> mapping;
 namespace NativeKeyboard {
 enum Keys {
     None,
-    Error,
 
     A = 4,
     B,
@@ -167,22 +166,22 @@ enum Keys {
     N8,
     N9,
     N0,
-    Enter,
+    Return,
     Escape,
     Backspace,
     Tab,
     Space,
     Minus,
-    Equal,
-    LeftBrace,
-    RightBrace,
-    Backslash,
+    Plus,
+    OpenBracket,
+    CloseBracket,
+    Pipe,
     Tilde,
     Semicolon,
-    Apostrophe,
-    Grave,
+    Quote,
+    Backquote,
     Comma,
-    Dot,
+    Period,
     Slash,
     CapsLockKey,
 
@@ -199,7 +198,7 @@ enum Keys {
     F11,
     F12,
 
-    SystemRequest,
+    PrintScreen,
     ScrollLockKey,
     Pause,
     Insert,
@@ -268,8 +267,18 @@ enum Keys {
     ScrollLockActive,
     KPComma,
 
-    KPLeftParenthesis,
-    KPRightParenthesis,
+    Ro = 0x87,
+    KatakanaHiragana,
+    Yen,
+    Henkan,
+    Muhenkan,
+    NumPadCommaPc98,
+
+    HangulEnglish = 0x90,
+    Hanja,
+    KatakanaKey,
+    HiraganaKey,
+    ZenkakuHankaku,
 
     LeftControlKey = 0xE0,
     LeftShiftKey,
@@ -318,6 +327,8 @@ enum Modifiers {
     CapsLock,
     ScrollLock,
     NumLock,
+    Katakana,
+    Hiragana,
 
     NumKeyboardMods,
 };
diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp
index e97470240e..0d840a0035 100644
--- a/src/core/hid/emulated_devices.cpp
+++ b/src/core/hid/emulated_devices.cpp
@@ -170,13 +170,14 @@ void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback,
         return;
     }
 
+    // Index should be converted from NativeKeyboard to KeyboardKeyIndex
     UpdateKey(index, current_status.value);
 
     TriggerOnChange(DeviceTriggerType::Keyboard);
 }
 
 void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) {
-    constexpr u8 KEYS_PER_BYTE = 8;
+    constexpr std::size_t KEYS_PER_BYTE = 8;
     auto& entry = device_status.keyboard_state.key[key_index / KEYS_PER_BYTE];
     const u8 mask = static_cast<u8>(1 << (key_index % KEYS_PER_BYTE));
     if (status) {
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
index 41bc65ce20..af95f3aff9 100644
--- a/src/core/hid/hid_types.h
+++ b/src/core/hid/hid_types.h
@@ -12,6 +12,195 @@
 
 namespace Core::HID {
 
+enum class DeviceIndex : u8 {
+    Left = 0,
+    Right = 1,
+    None = 2,
+    MaxDeviceIndex = 3,
+};
+
+// This is nn::hid::NpadButton
+enum class NpadButton : u64 {
+    None = 0,
+    A = 1U << 0,
+    B = 1U << 1,
+    X = 1U << 2,
+    Y = 1U << 3,
+    StickL = 1U << 4,
+    StickR = 1U << 5,
+    L = 1U << 6,
+    R = 1U << 7,
+    ZL = 1U << 8,
+    ZR = 1U << 9,
+    Plus = 1U << 10,
+    Minus = 1U << 11,
+
+    Left = 1U << 12,
+    Up = 1U << 13,
+    Right = 1U << 14,
+    Down = 1U << 15,
+
+    StickLLeft = 1U << 16,
+    StickLUp = 1U << 17,
+    StickLRight = 1U << 18,
+    StickLDown = 1U << 19,
+
+    StickRLeft = 1U << 20,
+    StickRUp = 1U << 21,
+    StickRRight = 1U << 22,
+    StickRDown = 1U << 23,
+
+    LeftSL = 1U << 24,
+    LeftSR = 1U << 25,
+
+    RightSL = 1U << 26,
+    RightSR = 1U << 27,
+
+    Palma = 1U << 28,
+    Verification = 1U << 29,
+    HandheldLeftB = 1U << 30,
+    LagonCLeft = 1U << 31,
+    LagonCUp = 1ULL << 32,
+    LagonCRight = 1ULL << 33,
+    LagonCDown = 1ULL << 34,
+};
+DECLARE_ENUM_FLAG_OPERATORS(NpadButton);
+
+enum class KeyboardKeyIndex : u32 {
+    A = 4,
+    B = 5,
+    C = 6,
+    D = 7,
+    E = 8,
+    F = 9,
+    G = 10,
+    H = 11,
+    I = 12,
+    J = 13,
+    K = 14,
+    L = 15,
+    M = 16,
+    N = 17,
+    O = 18,
+    P = 19,
+    Q = 20,
+    R = 21,
+    S = 22,
+    T = 23,
+    U = 24,
+    V = 25,
+    W = 26,
+    X = 27,
+    Y = 28,
+    Z = 29,
+    D1 = 30,
+    D2 = 31,
+    D3 = 32,
+    D4 = 33,
+    D5 = 34,
+    D6 = 35,
+    D7 = 36,
+    D8 = 37,
+    D9 = 38,
+    D0 = 39,
+    Return = 40,
+    Escape = 41,
+    Backspace = 42,
+    Tab = 43,
+    Space = 44,
+    Minus = 45,
+    Plus = 46,
+    OpenBracket = 47,
+    CloseBracket = 48,
+    Pipe = 49,
+    Tilde = 50,
+    Semicolon = 51,
+    Quote = 52,
+    Backquote = 53,
+    Comma = 54,
+    Period = 55,
+    Slash = 56,
+    CapsLock = 57,
+    F1 = 58,
+    F2 = 59,
+    F3 = 60,
+    F4 = 61,
+    F5 = 62,
+    F6 = 63,
+    F7 = 64,
+    F8 = 65,
+    F9 = 66,
+    F10 = 67,
+    F11 = 68,
+    F12 = 69,
+    PrintScreen = 70,
+    ScrollLock = 71,
+    Pause = 72,
+    Insert = 73,
+    Home = 74,
+    PageUp = 75,
+    Delete = 76,
+    End = 77,
+    PageDown = 78,
+    RightArrow = 79,
+    LeftArrow = 80,
+    DownArrow = 81,
+    UpArrow = 82,
+    NumLock = 83,
+    NumPadDivide = 84,
+    NumPadMultiply = 85,
+    NumPadSubtract = 86,
+    NumPadAdd = 87,
+    NumPadEnter = 88,
+    NumPad1 = 89,
+    NumPad2 = 90,
+    NumPad3 = 91,
+    NumPad4 = 92,
+    NumPad5 = 93,
+    NumPad6 = 94,
+    NumPad7 = 95,
+    NumPad8 = 96,
+    NumPad9 = 97,
+    NumPad0 = 98,
+    NumPadDot = 99,
+    Backslash = 100,
+    Application = 101,
+    Power = 102,
+    NumPadEquals = 103,
+    F13 = 104,
+    F14 = 105,
+    F15 = 106,
+    F16 = 107,
+    F17 = 108,
+    F18 = 109,
+    F19 = 110,
+    F20 = 111,
+    F21 = 112,
+    F22 = 113,
+    F23 = 114,
+    F24 = 115,
+    NumPadComma = 133,
+    Ro = 135,
+    KatakanaHiragana = 136,
+    Yen = 137,
+    Henkan = 138,
+    Muhenkan = 139,
+    NumPadCommaPc98 = 140,
+    HangulEnglish = 144,
+    Hanja = 145,
+    Katakana = 146,
+    Hiragana = 147,
+    ZenkakuHankaku = 148,
+    LeftControl = 224,
+    LeftShift = 225,
+    LeftAlt = 226,
+    LeftGui = 227,
+    RightControl = 228,
+    RightShift = 229,
+    RightAlt = 230,
+    RightGui = 231,
+};
+
 // This is nn::hid::NpadIdType
 enum class NpadIdType : u32 {
     Player1 = 0x0,
@@ -28,62 +217,6 @@ enum class NpadIdType : u32 {
     Invalid = 0xFFFFFFFF,
 };
 
-/// Converts a NpadIdType to an array index.
-constexpr size_t NpadIdTypeToIndex(NpadIdType npad_id_type) {
-    switch (npad_id_type) {
-    case NpadIdType::Player1:
-        return 0;
-    case NpadIdType::Player2:
-        return 1;
-    case NpadIdType::Player3:
-        return 2;
-    case NpadIdType::Player4:
-        return 3;
-    case NpadIdType::Player5:
-        return 4;
-    case NpadIdType::Player6:
-        return 5;
-    case NpadIdType::Player7:
-        return 6;
-    case NpadIdType::Player8:
-        return 7;
-    case NpadIdType::Handheld:
-        return 8;
-    case NpadIdType::Other:
-        return 9;
-    default:
-        return 0;
-    }
-}
-
-/// Converts an array index to a NpadIdType
-constexpr NpadIdType IndexToNpadIdType(size_t index) {
-    switch (index) {
-    case 0:
-        return NpadIdType::Player1;
-    case 1:
-        return NpadIdType::Player2;
-    case 2:
-        return NpadIdType::Player3;
-    case 3:
-        return NpadIdType::Player4;
-    case 4:
-        return NpadIdType::Player5;
-    case 5:
-        return NpadIdType::Player6;
-    case 6:
-        return NpadIdType::Player7;
-    case 7:
-        return NpadIdType::Player8;
-    case 8:
-        return NpadIdType::Handheld;
-    case 9:
-        return NpadIdType::Other;
-    default:
-        return NpadIdType::Invalid;
-    }
-}
-
 // This is nn::hid::NpadStyleIndex
 enum class NpadStyleIndex : u8 {
     None = 0,
@@ -124,6 +257,27 @@ enum class NpadStyleSet : u32 {
 };
 static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size");
 
+// This is nn::hid::VibrationDevicePosition
+enum class VibrationDevicePosition : u32 {
+    None = 0,
+    Left = 1,
+    Right = 2,
+};
+
+// This is nn::hid::VibrationDeviceType
+enum class VibrationDeviceType : u32 {
+    Unknown = 0,
+    LinearResonantActuator = 1,
+    GcErm = 2,
+};
+
+// This is nn::hid::VibrationGcErmCommand
+enum class VibrationGcErmCommand : u64 {
+    Stop = 0,
+    Start = 1,
+    StopHard = 2,
+};
+
 // This is nn::hid::NpadStyleTag
 struct NpadStyleTag {
     union {
@@ -220,53 +374,6 @@ struct LedPattern {
     };
 };
 
-// This is nn::hid::NpadButton
-enum class NpadButton : u64 {
-    None = 0,
-    A = 1U << 0,
-    B = 1U << 1,
-    X = 1U << 2,
-    Y = 1U << 3,
-    StickL = 1U << 4,
-    StickR = 1U << 5,
-    L = 1U << 6,
-    R = 1U << 7,
-    ZL = 1U << 8,
-    ZR = 1U << 9,
-    Plus = 1U << 10,
-    Minus = 1U << 11,
-
-    Left = 1U << 12,
-    Up = 1U << 13,
-    Right = 1U << 14,
-    Down = 1U << 15,
-
-    StickLLeft = 1U << 16,
-    StickLUp = 1U << 17,
-    StickLRight = 1U << 18,
-    StickLDown = 1U << 19,
-
-    StickRLeft = 1U << 20,
-    StickRUp = 1U << 21,
-    StickRRight = 1U << 22,
-    StickRDown = 1U << 23,
-
-    LeftSL = 1U << 24,
-    LeftSR = 1U << 25,
-
-    RightSL = 1U << 26,
-    RightSR = 1U << 27,
-
-    Palma = 1U << 28,
-    Verification = 1U << 29,
-    HandheldLeftB = 1U << 30,
-    LagonCLeft = 1U << 31,
-    LagonCUp = 1ULL << 32,
-    LagonCRight = 1ULL << 33,
-    LagonCDown = 1ULL << 34,
-};
-DECLARE_ENUM_FLAG_OPERATORS(NpadButton);
-
 struct NpadButtonState {
     union {
         NpadButton raw{};
@@ -342,13 +449,6 @@ struct DebugPadButton {
 };
 static_assert(sizeof(DebugPadButton) == 0x4, "DebugPadButton is an invalid size");
 
-enum class DeviceIndex : u8 {
-    Left = 0,
-    Right = 1,
-    None = 2,
-    MaxDeviceIndex = 3,
-};
-
 // This is nn::hid::ConsoleSixAxisSensorHandle
 struct ConsoleSixAxisSensorHandle {
     u8 unknown_1;
@@ -383,20 +483,6 @@ struct VibrationDeviceHandle {
 };
 static_assert(sizeof(VibrationDeviceHandle) == 4, "SixAxisSensorHandle is an invalid size");
 
-// This is nn::hid::VibrationDeviceType
-enum class VibrationDeviceType : u32 {
-    Unknown = 0,
-    LinearResonantActuator = 1,
-    GcErm = 2,
-};
-
-// This is nn::hid::VibrationDevicePosition
-enum class VibrationDevicePosition : u32 {
-    None = 0,
-    Left = 1,
-    Right = 2,
-};
-
 // This is nn::hid::VibrationValue
 struct VibrationValue {
     f32 low_amplitude;
@@ -406,13 +492,6 @@ struct VibrationValue {
 };
 static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size.");
 
-// This is nn::hid::VibrationGcErmCommand
-enum class VibrationGcErmCommand : u64 {
-    Stop = 0,
-    Start = 1,
-    StopHard = 2,
-};
-
 // This is nn::hid::VibrationDeviceInfo
 struct VibrationDeviceInfo {
     VibrationDeviceType type{};
@@ -482,4 +561,61 @@ struct MouseState {
     MouseAttribute attribute;
 };
 static_assert(sizeof(MouseState) == 0x28, "MouseState is an invalid size");
+
+/// Converts a NpadIdType to an array index.
+constexpr size_t NpadIdTypeToIndex(NpadIdType npad_id_type) {
+    switch (npad_id_type) {
+    case NpadIdType::Player1:
+        return 0;
+    case NpadIdType::Player2:
+        return 1;
+    case NpadIdType::Player3:
+        return 2;
+    case NpadIdType::Player4:
+        return 3;
+    case NpadIdType::Player5:
+        return 4;
+    case NpadIdType::Player6:
+        return 5;
+    case NpadIdType::Player7:
+        return 6;
+    case NpadIdType::Player8:
+        return 7;
+    case NpadIdType::Handheld:
+        return 8;
+    case NpadIdType::Other:
+        return 9;
+    default:
+        return 0;
+    }
+}
+
+/// Converts an array index to a NpadIdType
+constexpr NpadIdType IndexToNpadIdType(size_t index) {
+    switch (index) {
+    case 0:
+        return NpadIdType::Player1;
+    case 1:
+        return NpadIdType::Player2;
+    case 2:
+        return NpadIdType::Player3;
+    case 3:
+        return NpadIdType::Player4;
+    case 4:
+        return NpadIdType::Player5;
+    case 5:
+        return NpadIdType::Player6;
+    case 6:
+        return NpadIdType::Player7;
+    case 7:
+        return NpadIdType::Player8;
+    case 8:
+        return NpadIdType::Handheld;
+    case 9:
+        return NpadIdType::Other;
+    default:
+        return NpadIdType::Invalid;
+    }
+}
+
 } // namespace Core::HID
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index d6505dbc51..0ef8af0e69 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -42,6 +42,7 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing,
 
         next_state.key = keyboard_state;
         next_state.modifier = keyboard_modifier_state;
+        // This is always enabled on HW. Check what it actually does
         next_state.modifier.unknown.Assign(1);
     }
 
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 496b55d0ef..e740b43314 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -35,8 +35,9 @@ namespace Service::HID {
 
 // Updating period for each HID device.
 // Period time is obtained by measuring the number of samples in a second on HW using a homebrew
-constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000};    // (4ms, 250Hz)
-constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
+constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000};      // (4ms, 250Hz)
+constexpr auto keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
+constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000};   // (5ms, 200Hz)
 constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
 
 IAppletResource::IAppletResource(Core::System& system_,
@@ -78,14 +79,21 @@ IAppletResource::IAppletResource(Core::System& system_,
             const auto guard = LockService();
             UpdateControllers(user_data, ns_late);
         });
+    keyboard_update_event = Core::Timing::CreateEvent(
+        "HID::UpdatekeyboardCallback",
+        [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+            const auto guard = LockService();
+            UpdateKeyboard(user_data, ns_late);
+        });
     motion_update_event = Core::Timing::CreateEvent(
-        "HID::MotionPadCallback",
+        "HID::UpdateMotionCallback",
         [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
             const auto guard = LockService();
             UpdateMotion(user_data, ns_late);
         });
 
     system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event);
+    system.CoreTiming().ScheduleEvent(keyboard_update_ns, keyboard_update_event);
     system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event);
 
     system.HIDCore().ReloadInputDevices();
@@ -101,6 +109,7 @@ void IAppletResource::DeactivateController(HidController controller) {
 
 IAppletResource::~IAppletResource() {
     system.CoreTiming().UnscheduleEvent(pad_update_event, 0);
+    system.CoreTiming().UnscheduleEvent(keyboard_update_event, 0);
     system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
 }
 
@@ -117,18 +126,36 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
     auto& core_timing = system.CoreTiming();
 
     for (const auto& controller : controllers) {
+        // Keyboard has it's own update event
+        if (controller == controllers[static_cast<size_t>(HidController::Keyboard)]) {
+            continue;
+        }
         controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(),
                              SHARED_MEMORY_SIZE);
     }
 
     // If ns_late is higher than the update rate ignore the delay
-    if (ns_late > motion_update_ns) {
+    if (ns_late > pad_update_ns) {
         ns_late = {};
     }
 
     core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event);
 }
 
+void IAppletResource::UpdateKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+    auto& core_timing = system.CoreTiming();
+
+    controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(
+        core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE);
+
+    // If ns_late is higher than the update rate ignore the delay
+    if (ns_late > keyboard_update_ns) {
+        ns_late = {};
+    }
+
+    core_timing.ScheduleEvent(keyboard_update_ns - ns_late, keyboard_update_event);
+}
+
 void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
     auto& core_timing = system.CoreTiming();
 
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 973e6a8acf..bbad165f89 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -70,11 +70,13 @@ private:
 
     void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
     void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
+    void UpdateKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
     void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
 
     KernelHelpers::ServiceContext& service_context;
 
     std::shared_ptr<Core::Timing::EventType> pad_update_event;
+    std::shared_ptr<Core::Timing::EventType> keyboard_update_event;
     std::shared_ptr<Core::Timing::EventType> motion_update_event;
 
     std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
diff --git a/src/input_common/drivers/keyboard.cpp b/src/input_common/drivers/keyboard.cpp
index 549704e89a..328fe1ac16 100644
--- a/src/input_common/drivers/keyboard.cpp
+++ b/src/input_common/drivers/keyboard.cpp
@@ -3,26 +3,71 @@
 // Refer to the license.txt file included
 
 #include "common/param_package.h"
+#include "common/settings_input.h"
 #include "input_common/drivers/keyboard.h"
 
 namespace InputCommon {
 
-constexpr PadIdentifier identifier = {
+constexpr PadIdentifier key_identifier = {
     .guid = Common::UUID{Common::INVALID_UUID},
     .port = 0,
     .pad = 0,
 };
+constexpr PadIdentifier modifier_identifier = {
+    .guid = Common::UUID{Common::INVALID_UUID},
+    .port = 0,
+    .pad = 1,
+};
 
 Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) {
-    PreSetController(identifier);
+    PreSetController(key_identifier);
+    PreSetController(modifier_identifier);
 }
 
 void Keyboard::PressKey(int key_code) {
-    SetButton(identifier, key_code, true);
+    SetButton(key_identifier, key_code, true);
 }
 
 void Keyboard::ReleaseKey(int key_code) {
-    SetButton(identifier, key_code, false);
+    SetButton(key_identifier, key_code, false);
+}
+
+void Keyboard::SetModifiers(int key_modifiers) {
+    for (int i = 0; i < 32; ++i) {
+        bool key_value = ((key_modifiers >> i) & 0x1) != 0;
+        SetButton(modifier_identifier, i, key_value);
+        // Use the modifier to press the key button equivalent
+        switch (i) {
+        case Settings::NativeKeyboard::LeftControl:
+            SetButton(key_identifier, Settings::NativeKeyboard::LeftControlKey, key_value);
+            break;
+        case Settings::NativeKeyboard::LeftShift:
+            SetButton(key_identifier, Settings::NativeKeyboard::LeftShiftKey, key_value);
+            break;
+        case Settings::NativeKeyboard::LeftAlt:
+            SetButton(key_identifier, Settings::NativeKeyboard::LeftAltKey, key_value);
+            break;
+        case Settings::NativeKeyboard::LeftMeta:
+            SetButton(key_identifier, Settings::NativeKeyboard::LeftMetaKey, key_value);
+            break;
+        case Settings::NativeKeyboard::RightControl:
+            SetButton(key_identifier, Settings::NativeKeyboard::RightControlKey, key_value);
+            break;
+        case Settings::NativeKeyboard::RightShift:
+            SetButton(key_identifier, Settings::NativeKeyboard::RightShiftKey, key_value);
+            break;
+        case Settings::NativeKeyboard::RightAlt:
+            SetButton(key_identifier, Settings::NativeKeyboard::RightAltKey, key_value);
+            break;
+        case Settings::NativeKeyboard::RightMeta:
+            SetButton(key_identifier, Settings::NativeKeyboard::RightMetaKey, key_value);
+            break;
+        default:
+            // Other modifier keys should be pressed with PressKey since they stay enabled until
+            // next press
+            break;
+        }
+    }
 }
 
 void Keyboard::ReleaseAllKeys() {
diff --git a/src/input_common/drivers/keyboard.h b/src/input_common/drivers/keyboard.h
index 46fe785764..2ab92fd6c2 100644
--- a/src/input_common/drivers/keyboard.h
+++ b/src/input_common/drivers/keyboard.h
@@ -28,6 +28,13 @@ public:
      */
     void ReleaseKey(int key_code);
 
+    /**
+     * Sets the status of all keyboard modifier keys
+     * @param key_modifiers the code of the key to release
+     */
+    void SetModifiers(int key_modifiers);
+
+    /// Sets all keys to the non pressed state
     void ReleaseAllKeys();
 
     /// Used for automapping features
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index df36a337c7..ae2518f53c 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -402,6 +402,15 @@ std::string GenerateKeyboardParam(int key_code) {
     return param.Serialize();
 }
 
+std::string GenerateModdifierKeyboardParam(int key_code) {
+    Common::ParamPackage param;
+    param.Set("engine", "keyboard");
+    param.Set("code", key_code);
+    param.Set("toggle", false);
+    param.Set("pad", 1);
+    return param.Serialize();
+}
+
 std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
                                         int key_modifier, float modifier_scale) {
     Common::ParamPackage circle_pad_param{
diff --git a/src/input_common/main.h b/src/input_common/main.h
index a4a24d076e..9ea3954658 100644
--- a/src/input_common/main.h
+++ b/src/input_common/main.h
@@ -134,6 +134,9 @@ private:
 /// Generates a serialized param package for creating a keyboard button device.
 std::string GenerateKeyboardParam(int key_code);
 
+/// Generates a serialized param package for creating a moddifier keyboard button device.
+std::string GenerateModdifierKeyboardParam(int key_code);
+
 /// Generates a serialized param package for creating an analog device taking input from keyboard.
 std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
                                         int key_modifier, float modifier_scale);
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 3c5590a017..61513a5b41 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -392,15 +392,287 @@ void GRenderWindow::closeEvent(QCloseEvent* event) {
     QWidget::closeEvent(event);
 }
 
+int GRenderWindow::QtKeyToSwitchKey(Qt::Key qt_key) {
+    switch (qt_key) {
+    case Qt::Key_A:
+        return Settings::NativeKeyboard::A;
+    case Qt::Key_B:
+        return Settings::NativeKeyboard::B;
+    case Qt::Key_C:
+        return Settings::NativeKeyboard::C;
+    case Qt::Key_D:
+        return Settings::NativeKeyboard::D;
+    case Qt::Key_E:
+        return Settings::NativeKeyboard::E;
+    case Qt::Key_F:
+        return Settings::NativeKeyboard::F;
+    case Qt::Key_G:
+        return Settings::NativeKeyboard::G;
+    case Qt::Key_H:
+        return Settings::NativeKeyboard::H;
+    case Qt::Key_I:
+        return Settings::NativeKeyboard::I;
+    case Qt::Key_J:
+        return Settings::NativeKeyboard::J;
+    case Qt::Key_K:
+        return Settings::NativeKeyboard::K;
+    case Qt::Key_L:
+        return Settings::NativeKeyboard::L;
+    case Qt::Key_M:
+        return Settings::NativeKeyboard::M;
+    case Qt::Key_N:
+        return Settings::NativeKeyboard::N;
+    case Qt::Key_O:
+        return Settings::NativeKeyboard::O;
+    case Qt::Key_P:
+        return Settings::NativeKeyboard::P;
+    case Qt::Key_Q:
+        return Settings::NativeKeyboard::Q;
+    case Qt::Key_R:
+        return Settings::NativeKeyboard::R;
+    case Qt::Key_S:
+        return Settings::NativeKeyboard::S;
+    case Qt::Key_T:
+        return Settings::NativeKeyboard::T;
+    case Qt::Key_U:
+        return Settings::NativeKeyboard::U;
+    case Qt::Key_V:
+        return Settings::NativeKeyboard::V;
+    case Qt::Key_W:
+        return Settings::NativeKeyboard::W;
+    case Qt::Key_X:
+        return Settings::NativeKeyboard::X;
+    case Qt::Key_Y:
+        return Settings::NativeKeyboard::Y;
+    case Qt::Key_Z:
+        return Settings::NativeKeyboard::Z;
+    case Qt::Key_1:
+        return Settings::NativeKeyboard::N1;
+    case Qt::Key_2:
+        return Settings::NativeKeyboard::N2;
+    case Qt::Key_3:
+        return Settings::NativeKeyboard::N3;
+    case Qt::Key_4:
+        return Settings::NativeKeyboard::N4;
+    case Qt::Key_5:
+        return Settings::NativeKeyboard::N5;
+    case Qt::Key_6:
+        return Settings::NativeKeyboard::N6;
+    case Qt::Key_7:
+        return Settings::NativeKeyboard::N7;
+    case Qt::Key_8:
+        return Settings::NativeKeyboard::N8;
+    case Qt::Key_9:
+        return Settings::NativeKeyboard::N9;
+    case Qt::Key_0:
+        return Settings::NativeKeyboard::N0;
+    case Qt::Key_Return:
+        return Settings::NativeKeyboard::Return;
+    case Qt::Key_Escape:
+        return Settings::NativeKeyboard::Escape;
+    case Qt::Key_Backspace:
+        return Settings::NativeKeyboard::Backspace;
+    case Qt::Key_Tab:
+        return Settings::NativeKeyboard::Tab;
+    case Qt::Key_Space:
+        return Settings::NativeKeyboard::Space;
+    case Qt::Key_Minus:
+        return Settings::NativeKeyboard::Minus;
+    case Qt::Key_Plus:
+    case Qt::Key_questiondown:
+        return Settings::NativeKeyboard::Plus;
+    case Qt::Key_BracketLeft:
+    case Qt::Key_BraceLeft:
+        return Settings::NativeKeyboard::OpenBracket;
+    case Qt::Key_BracketRight:
+    case Qt::Key_BraceRight:
+        return Settings::NativeKeyboard::CloseBracket;
+    case Qt::Key_Bar:
+        return Settings::NativeKeyboard::Pipe;
+    case Qt::Key_Dead_Tilde:
+        return Settings::NativeKeyboard::Tilde;
+    case Qt::Key_Ntilde:
+    case Qt::Key_Semicolon:
+        return Settings::NativeKeyboard::Semicolon;
+    case Qt::Key_Apostrophe:
+        return Settings::NativeKeyboard::Quote;
+    case Qt::Key_Dead_Grave:
+        return Settings::NativeKeyboard::Backquote;
+    case Qt::Key_Comma:
+        return Settings::NativeKeyboard::Comma;
+    case Qt::Key_Period:
+        return Settings::NativeKeyboard::Period;
+    case Qt::Key_Slash:
+        return Settings::NativeKeyboard::Slash;
+    case Qt::Key_CapsLock:
+        return Settings::NativeKeyboard::CapsLock;
+    case Qt::Key_F1:
+        return Settings::NativeKeyboard::F1;
+    case Qt::Key_F2:
+        return Settings::NativeKeyboard::F2;
+    case Qt::Key_F3:
+        return Settings::NativeKeyboard::F3;
+    case Qt::Key_F4:
+        return Settings::NativeKeyboard::F4;
+    case Qt::Key_F5:
+        return Settings::NativeKeyboard::F5;
+    case Qt::Key_F6:
+        return Settings::NativeKeyboard::F6;
+    case Qt::Key_F7:
+        return Settings::NativeKeyboard::F7;
+    case Qt::Key_F8:
+        return Settings::NativeKeyboard::F8;
+    case Qt::Key_F9:
+        return Settings::NativeKeyboard::F9;
+    case Qt::Key_F10:
+        return Settings::NativeKeyboard::F10;
+    case Qt::Key_F11:
+        return Settings::NativeKeyboard::F11;
+    case Qt::Key_F12:
+        return Settings::NativeKeyboard::F12;
+    case Qt::Key_Print:
+        return Settings::NativeKeyboard::PrintScreen;
+    case Qt::Key_ScrollLock:
+        return Settings::NativeKeyboard::ScrollLock;
+    case Qt::Key_Pause:
+        return Settings::NativeKeyboard::Pause;
+    case Qt::Key_Insert:
+        return Settings::NativeKeyboard::Insert;
+    case Qt::Key_Home:
+        return Settings::NativeKeyboard::Home;
+    case Qt::Key_PageUp:
+        return Settings::NativeKeyboard::PageUp;
+    case Qt::Key_Delete:
+        return Settings::NativeKeyboard::Delete;
+    case Qt::Key_End:
+        return Settings::NativeKeyboard::End;
+    case Qt::Key_PageDown:
+        return Settings::NativeKeyboard::PageDown;
+    case Qt::Key_Right:
+        return Settings::NativeKeyboard::Right;
+    case Qt::Key_Left:
+        return Settings::NativeKeyboard::Left;
+    case Qt::Key_Down:
+        return Settings::NativeKeyboard::Down;
+    case Qt::Key_Up:
+        return Settings::NativeKeyboard::Up;
+    case Qt::Key_NumLock:
+        return Settings::NativeKeyboard::NumLock;
+    // Numpad keys are missing here
+    case Qt::Key_F13:
+        return Settings::NativeKeyboard::F13;
+    case Qt::Key_F14:
+        return Settings::NativeKeyboard::F14;
+    case Qt::Key_F15:
+        return Settings::NativeKeyboard::F15;
+    case Qt::Key_F16:
+        return Settings::NativeKeyboard::F16;
+    case Qt::Key_F17:
+        return Settings::NativeKeyboard::F17;
+    case Qt::Key_F18:
+        return Settings::NativeKeyboard::F18;
+    case Qt::Key_F19:
+        return Settings::NativeKeyboard::F19;
+    case Qt::Key_F20:
+        return Settings::NativeKeyboard::F20;
+    case Qt::Key_F21:
+        return Settings::NativeKeyboard::F21;
+    case Qt::Key_F22:
+        return Settings::NativeKeyboard::F22;
+    case Qt::Key_F23:
+        return Settings::NativeKeyboard::F23;
+    case Qt::Key_F24:
+        return Settings::NativeKeyboard::F24;
+    // case Qt:::
+    //    return Settings::NativeKeyboard::KPComma;
+    // case Qt:::
+    //    return Settings::NativeKeyboard::Ro;
+    case Qt::Key_Hiragana_Katakana:
+        return Settings::NativeKeyboard::KatakanaHiragana;
+    case Qt::Key_yen:
+        return Settings::NativeKeyboard::Yen;
+    case Qt::Key_Henkan:
+        return Settings::NativeKeyboard::Henkan;
+    case Qt::Key_Muhenkan:
+        return Settings::NativeKeyboard::Muhenkan;
+    // case Qt:::
+    //    return Settings::NativeKeyboard::NumPadCommaPc98;
+    case Qt::Key_Hangul:
+        return Settings::NativeKeyboard::HangulEnglish;
+    case Qt::Key_Hangul_Hanja:
+        return Settings::NativeKeyboard::Hanja;
+    case Qt::Key_Katakana:
+        return Settings::NativeKeyboard::KatakanaKey;
+    case Qt::Key_Hiragana:
+        return Settings::NativeKeyboard::HiraganaKey;
+    case Qt::Key_Zenkaku_Hankaku:
+        return Settings::NativeKeyboard::ZenkakuHankaku;
+    // Modifier keys are handled by the modifier property
+    default:
+        return 0;
+    }
+}
+
+int GRenderWindow::QtModifierToSwitchModdifier(quint32 qt_moddifiers) {
+    int moddifier = 0;
+    // The values are obtained through testing, Qt doesn't seem to provide a proper enum
+    if ((qt_moddifiers & 0x1) != 0) {
+        moddifier |= 1 << Settings::NativeKeyboard::LeftShift;
+    }
+    if ((qt_moddifiers & 0x2) != 0) {
+        moddifier |= 1 << Settings::NativeKeyboard::LeftControl;
+    }
+    if ((qt_moddifiers & 0x4) != 0) {
+        moddifier |= 1 << Settings::NativeKeyboard::LeftAlt;
+    }
+    if ((qt_moddifiers & 0x08) != 0) {
+        moddifier |= 1 << Settings::NativeKeyboard::LeftMeta;
+    }
+    if ((qt_moddifiers & 0x10) != 0) {
+        moddifier |= 1 << Settings::NativeKeyboard::RightShift;
+    }
+    if ((qt_moddifiers & 0x20) != 0) {
+        moddifier |= 1 << Settings::NativeKeyboard::RightControl;
+    }
+    if ((qt_moddifiers & 0x40) != 0) {
+        moddifier |= 1 << Settings::NativeKeyboard::RightAlt;
+    }
+    if ((qt_moddifiers & 0x80) != 0) {
+        moddifier |= 1 << Settings::NativeKeyboard::RightMeta;
+    }
+    if ((qt_moddifiers & 0x100) != 0) {
+        moddifier |= 1 << Settings::NativeKeyboard::CapsLock;
+    }
+    if ((qt_moddifiers & 0x200) != 0) {
+        moddifier |= 1 << Settings::NativeKeyboard::NumLock;
+    }
+    // Verify the last two keys
+    if ((qt_moddifiers & 0x400) != 0) {
+        moddifier |= 1 << Settings::NativeKeyboard::Katakana;
+    }
+    if ((qt_moddifiers & 0x800) != 0) {
+        moddifier |= 1 << Settings::NativeKeyboard::Hiragana;
+    }
+    return moddifier;
+}
+
 void GRenderWindow::keyPressEvent(QKeyEvent* event) {
     if (!event->isAutoRepeat()) {
-        input_subsystem->GetKeyboard()->PressKey(event->key());
+        const auto moddifier = QtModifierToSwitchModdifier(event->nativeModifiers());
+        // Replace event->key() with event->nativeVirtualKey() since the second one provides raw key
+        // buttons
+        const auto key = QtKeyToSwitchKey(Qt::Key(event->key()));
+        input_subsystem->GetKeyboard()->SetModifiers(moddifier);
+        input_subsystem->GetKeyboard()->PressKey(key);
     }
 }
 
 void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
     if (!event->isAutoRepeat()) {
-        input_subsystem->GetKeyboard()->ReleaseKey(event->key());
+        const auto moddifier = QtModifierToSwitchModdifier(event->nativeModifiers());
+        const auto key = QtKeyToSwitchKey(Qt::Key(event->key()));
+        input_subsystem->GetKeyboard()->SetModifiers(moddifier);
+        input_subsystem->GetKeyboard()->ReleaseKey(key);
     }
 }
 
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index 95594f81ca..c42d139beb 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -158,6 +158,12 @@ public:
 
     void resizeEvent(QResizeEvent* event) override;
 
+    /// Converts a Qt keybard key into NativeKeyboard key
+    static int QtKeyToSwitchKey(Qt::Key qt_keys);
+
+    /// Converts a Qt modifier keys into NativeKeyboard modifier keys
+    static int QtModifierToSwitchModdifier(quint32 qt_moddifiers);
+
     void keyPressEvent(QKeyEvent* event) override;
     void keyReleaseEvent(QKeyEvent* event) override;
 
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 7669fe4748..ccf274895f 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -65,157 +65,6 @@ const std::array<int, Settings::NativeMouseButton::NumMouseButtons> Config::defa
         Qt::Key_BracketLeft, Qt::Key_BracketRight, Qt::Key_Apostrophe, Qt::Key_Minus, Qt::Key_Equal,
 };
 
-const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> Config::default_keyboard_keys = {
-    0,
-    0,
-    0,
-    0,
-    Qt::Key_A,
-    Qt::Key_B,
-    Qt::Key_C,
-    Qt::Key_D,
-    Qt::Key_E,
-    Qt::Key_F,
-    Qt::Key_G,
-    Qt::Key_H,
-    Qt::Key_I,
-    Qt::Key_J,
-    Qt::Key_K,
-    Qt::Key_L,
-    Qt::Key_M,
-    Qt::Key_N,
-    Qt::Key_O,
-    Qt::Key_P,
-    Qt::Key_Q,
-    Qt::Key_R,
-    Qt::Key_S,
-    Qt::Key_T,
-    Qt::Key_U,
-    Qt::Key_V,
-    Qt::Key_W,
-    Qt::Key_X,
-    Qt::Key_Y,
-    Qt::Key_Z,
-    Qt::Key_1,
-    Qt::Key_2,
-    Qt::Key_3,
-    Qt::Key_4,
-    Qt::Key_5,
-    Qt::Key_6,
-    Qt::Key_7,
-    Qt::Key_8,
-    Qt::Key_9,
-    Qt::Key_0,
-    Qt::Key_Enter,
-    Qt::Key_Escape,
-    Qt::Key_Backspace,
-    Qt::Key_Tab,
-    Qt::Key_Space,
-    Qt::Key_Minus,
-    Qt::Key_Equal,
-    Qt::Key_BracketLeft,
-    Qt::Key_BracketRight,
-    Qt::Key_Backslash,
-    Qt::Key_Dead_Tilde,
-    Qt::Key_Semicolon,
-    Qt::Key_Apostrophe,
-    Qt::Key_Dead_Grave,
-    Qt::Key_Comma,
-    Qt::Key_Period,
-    Qt::Key_Slash,
-    Qt::Key_CapsLock,
-
-    Qt::Key_F1,
-    Qt::Key_F2,
-    Qt::Key_F3,
-    Qt::Key_F4,
-    Qt::Key_F5,
-    Qt::Key_F6,
-    Qt::Key_F7,
-    Qt::Key_F8,
-    Qt::Key_F9,
-    Qt::Key_F10,
-    Qt::Key_F11,
-    Qt::Key_F12,
-
-    Qt::Key_SysReq,
-    Qt::Key_ScrollLock,
-    Qt::Key_Pause,
-    Qt::Key_Insert,
-    Qt::Key_Home,
-    Qt::Key_PageUp,
-    Qt::Key_Delete,
-    Qt::Key_End,
-    Qt::Key_PageDown,
-    Qt::Key_Right,
-    Qt::Key_Left,
-    Qt::Key_Down,
-    Qt::Key_Up,
-
-    Qt::Key_NumLock,
-    Qt::Key_Slash,
-    Qt::Key_Asterisk,
-    Qt::Key_Minus,
-    Qt::Key_Plus,
-    Qt::Key_Enter,
-    Qt::Key_1,
-    Qt::Key_2,
-    Qt::Key_3,
-    Qt::Key_4,
-    Qt::Key_5,
-    Qt::Key_6,
-    Qt::Key_7,
-    Qt::Key_8,
-    Qt::Key_9,
-    Qt::Key_0,
-    Qt::Key_Period,
-
-    0,
-    0,
-    Qt::Key_PowerOff,
-    Qt::Key_Equal,
-
-    Qt::Key_F13,
-    Qt::Key_F14,
-    Qt::Key_F15,
-    Qt::Key_F16,
-    Qt::Key_F17,
-    Qt::Key_F18,
-    Qt::Key_F19,
-    Qt::Key_F20,
-    Qt::Key_F21,
-    Qt::Key_F22,
-    Qt::Key_F23,
-    Qt::Key_F24,
-
-    Qt::Key_Open,
-    Qt::Key_Help,
-    Qt::Key_Menu,
-    0,
-    Qt::Key_Stop,
-    Qt::Key_AudioRepeat,
-    Qt::Key_Undo,
-    Qt::Key_Cut,
-    Qt::Key_Copy,
-    Qt::Key_Paste,
-    Qt::Key_Find,
-    Qt::Key_VolumeMute,
-    Qt::Key_VolumeUp,
-    Qt::Key_VolumeDown,
-    Qt::Key_CapsLock,
-    Qt::Key_NumLock,
-    Qt::Key_ScrollLock,
-    Qt::Key_Comma,
-
-    Qt::Key_ParenLeft,
-    Qt::Key_ParenRight,
-};
-
-const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> Config::default_keyboard_mods = {
-    Qt::Key_Control, Qt::Key_Shift, Qt::Key_Alt,   Qt::Key_ApplicationLeft,
-    Qt::Key_Control, Qt::Key_Shift, Qt::Key_AltGr, Qt::Key_ApplicationRight,
-};
-
 // This shouldn't have anything except static initializers (no functions). So
 // QKeySequence(...).toString() is NOT ALLOWED HERE.
 // This must be in alphabetical order according to action name as it must have the same order as
@@ -496,14 +345,14 @@ void Config::ReadDebugValues() {
 void Config::ReadKeyboardValues() {
     ReadBasicSetting(Settings::values.keyboard_enabled);
 
-    std::transform(default_keyboard_keys.begin(), default_keyboard_keys.end(),
-                   Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam);
-    std::transform(default_keyboard_mods.begin(), default_keyboard_mods.end(),
-                   Settings::values.keyboard_keys.begin() +
-                       Settings::NativeKeyboard::LeftControlKey,
-                   InputCommon::GenerateKeyboardParam);
-    std::transform(default_keyboard_mods.begin(), default_keyboard_mods.end(),
-                   Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam);
+    for (std::size_t i = 0; i < Settings::values.keyboard_keys.size(); ++i) {
+        Settings::values.keyboard_keys[i] = InputCommon::GenerateKeyboardParam(static_cast<int>(i));
+    }
+
+    for (std::size_t i = 0; i < Settings::values.keyboard_mods.size(); ++i) {
+        Settings::values.keyboard_mods[i] =
+            InputCommon::GenerateModdifierKeyboardParam(static_cast<int>(i));
+    }
 }
 
 void Config::ReadMouseValues() {