core/hid: Improve accuracy of the keyboard implementation

This commit is contained in:
german77 2021-11-13 23:25:45 -06:00 committed by Narr the Reg
parent 7fcfe24a3e
commit b673857d7d
13 changed files with 682 additions and 313 deletions

View File

@ -129,7 +129,6 @@ extern const std::array<const char*, NumMouseButtons> mapping;
namespace NativeKeyboard { namespace NativeKeyboard {
enum Keys { enum Keys {
None, None,
Error,
A = 4, A = 4,
B, B,
@ -167,22 +166,22 @@ enum Keys {
N8, N8,
N9, N9,
N0, N0,
Enter, Return,
Escape, Escape,
Backspace, Backspace,
Tab, Tab,
Space, Space,
Minus, Minus,
Equal, Plus,
LeftBrace, OpenBracket,
RightBrace, CloseBracket,
Backslash, Pipe,
Tilde, Tilde,
Semicolon, Semicolon,
Apostrophe, Quote,
Grave, Backquote,
Comma, Comma,
Dot, Period,
Slash, Slash,
CapsLockKey, CapsLockKey,
@ -199,7 +198,7 @@ enum Keys {
F11, F11,
F12, F12,
SystemRequest, PrintScreen,
ScrollLockKey, ScrollLockKey,
Pause, Pause,
Insert, Insert,
@ -268,8 +267,18 @@ enum Keys {
ScrollLockActive, ScrollLockActive,
KPComma, KPComma,
KPLeftParenthesis, Ro = 0x87,
KPRightParenthesis, KatakanaHiragana,
Yen,
Henkan,
Muhenkan,
NumPadCommaPc98,
HangulEnglish = 0x90,
Hanja,
KatakanaKey,
HiraganaKey,
ZenkakuHankaku,
LeftControlKey = 0xE0, LeftControlKey = 0xE0,
LeftShiftKey, LeftShiftKey,
@ -318,6 +327,8 @@ enum Modifiers {
CapsLock, CapsLock,
ScrollLock, ScrollLock,
NumLock, NumLock,
Katakana,
Hiragana,
NumKeyboardMods, NumKeyboardMods,
}; };

View File

@ -170,13 +170,14 @@ void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback,
return; return;
} }
// Index should be converted from NativeKeyboard to KeyboardKeyIndex
UpdateKey(index, current_status.value); UpdateKey(index, current_status.value);
TriggerOnChange(DeviceTriggerType::Keyboard); TriggerOnChange(DeviceTriggerType::Keyboard);
} }
void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) { 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]; auto& entry = device_status.keyboard_state.key[key_index / KEYS_PER_BYTE];
const u8 mask = static_cast<u8>(1 << (key_index % KEYS_PER_BYTE)); const u8 mask = static_cast<u8>(1 << (key_index % KEYS_PER_BYTE));
if (status) { if (status) {

View File

@ -12,6 +12,195 @@
namespace Core::HID { 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 // This is nn::hid::NpadIdType
enum class NpadIdType : u32 { enum class NpadIdType : u32 {
Player1 = 0x0, Player1 = 0x0,
@ -28,62 +217,6 @@ enum class NpadIdType : u32 {
Invalid = 0xFFFFFFFF, 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 // This is nn::hid::NpadStyleIndex
enum class NpadStyleIndex : u8 { enum class NpadStyleIndex : u8 {
None = 0, None = 0,
@ -124,6 +257,27 @@ enum class NpadStyleSet : u32 {
}; };
static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size"); 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 // This is nn::hid::NpadStyleTag
struct NpadStyleTag { struct NpadStyleTag {
union { 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 { struct NpadButtonState {
union { union {
NpadButton raw{}; NpadButton raw{};
@ -342,13 +449,6 @@ struct DebugPadButton {
}; };
static_assert(sizeof(DebugPadButton) == 0x4, "DebugPadButton is an invalid size"); 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 // This is nn::hid::ConsoleSixAxisSensorHandle
struct ConsoleSixAxisSensorHandle { struct ConsoleSixAxisSensorHandle {
u8 unknown_1; u8 unknown_1;
@ -383,20 +483,6 @@ struct VibrationDeviceHandle {
}; };
static_assert(sizeof(VibrationDeviceHandle) == 4, "SixAxisSensorHandle is an invalid size"); 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 // This is nn::hid::VibrationValue
struct VibrationValue { struct VibrationValue {
f32 low_amplitude; f32 low_amplitude;
@ -406,13 +492,6 @@ struct VibrationValue {
}; };
static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size."); 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 // This is nn::hid::VibrationDeviceInfo
struct VibrationDeviceInfo { struct VibrationDeviceInfo {
VibrationDeviceType type{}; VibrationDeviceType type{};
@ -482,4 +561,61 @@ struct MouseState {
MouseAttribute attribute; MouseAttribute attribute;
}; };
static_assert(sizeof(MouseState) == 0x28, "MouseState is an invalid size"); 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 } // namespace Core::HID

View File

@ -42,6 +42,7 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing,
next_state.key = keyboard_state; next_state.key = keyboard_state;
next_state.modifier = keyboard_modifier_state; next_state.modifier = keyboard_modifier_state;
// This is always enabled on HW. Check what it actually does
next_state.modifier.unknown.Assign(1); next_state.modifier.unknown.Assign(1);
} }

View File

@ -36,6 +36,7 @@ namespace Service::HID {
// Updating period for each HID device. // Updating period for each HID device.
// Period time is obtained by measuring the number of samples in a second on HW using a homebrew // 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 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 auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
@ -78,14 +79,21 @@ IAppletResource::IAppletResource(Core::System& system_,
const auto guard = LockService(); const auto guard = LockService();
UpdateControllers(user_data, ns_late); 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( motion_update_event = Core::Timing::CreateEvent(
"HID::MotionPadCallback", "HID::UpdateMotionCallback",
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
const auto guard = LockService(); const auto guard = LockService();
UpdateMotion(user_data, ns_late); UpdateMotion(user_data, ns_late);
}); });
system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); 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.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event);
system.HIDCore().ReloadInputDevices(); system.HIDCore().ReloadInputDevices();
@ -101,6 +109,7 @@ void IAppletResource::DeactivateController(HidController controller) {
IAppletResource::~IAppletResource() { IAppletResource::~IAppletResource() {
system.CoreTiming().UnscheduleEvent(pad_update_event, 0); system.CoreTiming().UnscheduleEvent(pad_update_event, 0);
system.CoreTiming().UnscheduleEvent(keyboard_update_event, 0);
system.CoreTiming().UnscheduleEvent(motion_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(); auto& core_timing = system.CoreTiming();
for (const auto& controller : controllers) { 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(), controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(),
SHARED_MEMORY_SIZE); SHARED_MEMORY_SIZE);
} }
// If ns_late is higher than the update rate ignore the delay // 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 = {}; ns_late = {};
} }
core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event); 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) { void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming(); auto& core_timing = system.CoreTiming();

View File

@ -70,11 +70,13 @@ private:
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 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); void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
KernelHelpers::ServiceContext& service_context; KernelHelpers::ServiceContext& service_context;
std::shared_ptr<Core::Timing::EventType> pad_update_event; 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::shared_ptr<Core::Timing::EventType> motion_update_event;
std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>

View File

@ -3,26 +3,71 @@
// Refer to the license.txt file included // Refer to the license.txt file included
#include "common/param_package.h" #include "common/param_package.h"
#include "common/settings_input.h"
#include "input_common/drivers/keyboard.h" #include "input_common/drivers/keyboard.h"
namespace InputCommon { namespace InputCommon {
constexpr PadIdentifier identifier = { constexpr PadIdentifier key_identifier = {
.guid = Common::UUID{Common::INVALID_UUID}, .guid = Common::UUID{Common::INVALID_UUID},
.port = 0, .port = 0,
.pad = 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_) { Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) {
PreSetController(identifier); PreSetController(key_identifier);
PreSetController(modifier_identifier);
} }
void Keyboard::PressKey(int key_code) { void Keyboard::PressKey(int key_code) {
SetButton(identifier, key_code, true); SetButton(key_identifier, key_code, true);
} }
void Keyboard::ReleaseKey(int key_code) { 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() { void Keyboard::ReleaseAllKeys() {

View File

@ -28,6 +28,13 @@ public:
*/ */
void ReleaseKey(int key_code); 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(); void ReleaseAllKeys();
/// Used for automapping features /// Used for automapping features

View File

@ -402,6 +402,15 @@ std::string GenerateKeyboardParam(int key_code) {
return param.Serialize(); 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, std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
int key_modifier, float modifier_scale) { int key_modifier, float modifier_scale) {
Common::ParamPackage circle_pad_param{ Common::ParamPackage circle_pad_param{

View File

@ -134,6 +134,9 @@ private:
/// Generates a serialized param package for creating a keyboard button device. /// Generates a serialized param package for creating a keyboard button device.
std::string GenerateKeyboardParam(int key_code); 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. /// 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, std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
int key_modifier, float modifier_scale); int key_modifier, float modifier_scale);

View File

@ -392,15 +392,287 @@ void GRenderWindow::closeEvent(QCloseEvent* event) {
QWidget::closeEvent(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) { void GRenderWindow::keyPressEvent(QKeyEvent* event) {
if (!event->isAutoRepeat()) { 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) { void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
if (!event->isAutoRepeat()) { 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);
} }
} }

View File

@ -158,6 +158,12 @@ public:
void resizeEvent(QResizeEvent* event) override; 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 keyPressEvent(QKeyEvent* event) override;
void keyReleaseEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override;

View File

@ -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, 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 // This shouldn't have anything except static initializers (no functions). So
// QKeySequence(...).toString() is NOT ALLOWED HERE. // QKeySequence(...).toString() is NOT ALLOWED HERE.
// This must be in alphabetical order according to action name as it must have the same order as // 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() { void Config::ReadKeyboardValues() {
ReadBasicSetting(Settings::values.keyboard_enabled); ReadBasicSetting(Settings::values.keyboard_enabled);
std::transform(default_keyboard_keys.begin(), default_keyboard_keys.end(), for (std::size_t i = 0; i < Settings::values.keyboard_keys.size(); ++i) {
Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam); Settings::values.keyboard_keys[i] = InputCommon::GenerateKeyboardParam(static_cast<int>(i));
std::transform(default_keyboard_mods.begin(), default_keyboard_mods.end(), }
Settings::values.keyboard_keys.begin() +
Settings::NativeKeyboard::LeftControlKey, for (std::size_t i = 0; i < Settings::values.keyboard_mods.size(); ++i) {
InputCommon::GenerateKeyboardParam); Settings::values.keyboard_mods[i] =
std::transform(default_keyboard_mods.begin(), default_keyboard_mods.end(), InputCommon::GenerateModdifierKeyboardParam(static_cast<int>(i));
Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam); }
} }
void Config::ReadMouseValues() { void Config::ReadMouseValues() {