diff --git a/Source/Core/Core/IOS/USB/USB_KBD.cpp b/Source/Core/Core/IOS/USB/USB_KBD.cpp index d690cc27e6..77deb65948 100644 --- a/Source/Core/Core/IOS/USB/USB_KBD.cpp +++ b/Source/Core/Core/IOS/USB/USB_KBD.cpp @@ -4,7 +4,7 @@ #include "Core/IOS/USB/USB_KBD.h" -#include +#include #include #include "Common/FileUtil.h" @@ -22,156 +22,11 @@ namespace IOS::HLE::Device { -USB_KBD::SMessageData::SMessageData(u32 type, u8 modifiers, u8* pressed_keys) +namespace { - MsgType = Common::swap32(type); - Unk1 = 0; // swapped - Modifiers = modifiers; - Unk2 = 0; - - if (pressed_keys) // Doesn't need to be in a specific order - memcpy(PressedKeys, pressed_keys, sizeof(PressedKeys)); - else - memset(PressedKeys, 0, sizeof(PressedKeys)); -} - -// TODO: support in netplay/movies. - -USB_KBD::USB_KBD(Kernel& ios, const std::string& device_name) : Device(ios, device_name) -{ -} - -IPCCommandResult USB_KBD::Open(const OpenRequest& request) -{ - INFO_LOG(IOS, "USB_KBD: Open"); - IniFile ini; - ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); - ini.GetOrCreateSection("USB Keyboard")->Get("Layout", &m_KeyboardLayout, KBD_LAYOUT_QWERTY); - - m_MessageQueue = std::queue(); - for (bool& pressed : m_OldKeyBuffer) - { - pressed = false; - } - - m_OldModifiers = 0x00; - - // m_MessageQueue.push(SMessageData(MSG_KBD_CONNECT, 0, nullptr)); - return Device::Open(request); -} - -IPCCommandResult USB_KBD::Write(const ReadWriteRequest& request) -{ - // Stubbed. - return GetDefaultReply(IPC_SUCCESS); -} - -IPCCommandResult USB_KBD::IOCtl(const IOCtlRequest& request) -{ - if (SConfig::GetInstance().m_WiiKeyboard && !Core::WantsDeterminism() && - ControlReference::InputGateOn() && !m_MessageQueue.empty()) - { - Memory::CopyToEmu(request.buffer_out, &m_MessageQueue.front(), sizeof(SMessageData)); - m_MessageQueue.pop(); - } - return GetDefaultReply(IPC_SUCCESS); -} - -bool USB_KBD::IsKeyPressed(int _Key) -{ -#ifdef _WIN32 - if (GetAsyncKeyState(_Key) & 0x8000) - return true; - else - return false; -#else - // TODO: do it for non-Windows platforms - return false; -#endif -} - -void USB_KBD::Update() -{ - if (!SConfig::GetInstance().m_WiiKeyboard || Core::WantsDeterminism() || !m_is_active) - return; - - u8 Modifiers = 0x00; - u8 PressedKeys[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - bool GotEvent = false; - int num_pressed_keys = 0; - for (int i = 0; i < 256; i++) - { - bool KeyPressedNow = IsKeyPressed(i); - bool KeyPressedBefore = m_OldKeyBuffer[i]; - u8 KeyCode = 0; - - if (KeyPressedNow ^ KeyPressedBefore) - { - if (KeyPressedNow) - { - switch (m_KeyboardLayout) - { - case KBD_LAYOUT_QWERTY: - KeyCode = m_KeyCodesQWERTY[i]; - break; - - case KBD_LAYOUT_AZERTY: - KeyCode = m_KeyCodesAZERTY[i]; - break; - } - - if (KeyCode == 0x00) - continue; - - PressedKeys[num_pressed_keys] = KeyCode; - - num_pressed_keys++; - if (num_pressed_keys == 6) - break; - } - - GotEvent = true; - } - - m_OldKeyBuffer[i] = KeyPressedNow; - } - -#ifdef _WIN32 - if (GetAsyncKeyState(VK_LCONTROL) & 0x8000) - Modifiers |= 0x01; - if (GetAsyncKeyState(VK_LSHIFT) & 0x8000) - Modifiers |= 0x02; - if (GetAsyncKeyState(VK_MENU) & 0x8000) - Modifiers |= 0x04; - if (GetAsyncKeyState(VK_LWIN) & 0x8000) - Modifiers |= 0x08; - if (GetAsyncKeyState(VK_RCONTROL) & 0x8000) - Modifiers |= 0x10; - if (GetAsyncKeyState(VK_RSHIFT) & 0x8000) - Modifiers |= 0x20; - if (GetAsyncKeyState(VK_MENU) & - 0x8000) // TODO: VK_MENU is for ALT, not for ALT GR (ALT GR seems to work though...) - Modifiers |= 0x40; - if (GetAsyncKeyState(VK_RWIN) & 0x8000) - Modifiers |= 0x80; -#else -// TODO: modifiers for non-Windows platforms -#endif - - if (Modifiers ^ m_OldModifiers) - { - GotEvent = true; - m_OldModifiers = Modifiers; - } - - if (GotEvent) - m_MessageQueue.push(SMessageData(MSG_EVENT, Modifiers, PressedKeys)); -} - // Crazy ugly #ifdef _WIN32 -u8 USB_KBD::m_KeyCodesQWERTY[256] = { - +constexpr std::array s_key_codes_qwerty{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, // Backspace 0x2B, // Tab @@ -241,11 +96,9 @@ u8 USB_KBD::m_KeyCodesQWERTY[256] = { 0x34, // ''' 0x00, // 0x00, // Nothing interesting past this point. - }; -u8 USB_KBD::m_KeyCodesAZERTY[256] = { - +constexpr std::array s_key_codes_azerty{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, // Backspace 0x2B, // Tab @@ -315,11 +168,143 @@ u8 USB_KBD::m_KeyCodesAZERTY[256] = { 0x00, // ' ' 0x38, // '!' 0x00, // Nothing interesting past this point. - }; #else -u8 USB_KBD::m_KeyCodesQWERTY[256] = {0}; +constexpr std::array s_key_codes_qwerty{}; -u8 USB_KBD::m_KeyCodesAZERTY[256] = {0}; +constexpr std::array s_key_codes_azerty{}; #endif +} // Anonymous namespace + +USB_KBD::MessageData::MessageData(MessageType type, u8 modifiers, PressedKeyData pressed_keys) + : msg_type{Common::swap32(static_cast(type))}, modifiers{modifiers}, pressed_keys{ + pressed_keys} +{ +} + +// TODO: support in netplay/movies. + +USB_KBD::USB_KBD(Kernel& ios, const std::string& device_name) : Device(ios, device_name) +{ +} + +IPCCommandResult USB_KBD::Open(const OpenRequest& request) +{ + INFO_LOG(IOS, "USB_KBD: Open"); + IniFile ini; + ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); + ini.GetOrCreateSection("USB Keyboard")->Get("Layout", &m_keyboard_layout, KBD_LAYOUT_QWERTY); + + m_message_queue = {}; + m_old_key_buffer.fill(false); + m_old_modifiers = 0x00; + + // m_message_queue.emplace(MessageType::KeyboardConnect, 0, PressedKeyData{}); + return Device::Open(request); +} + +IPCCommandResult USB_KBD::Write(const ReadWriteRequest& request) +{ + // Stubbed. + return GetDefaultReply(IPC_SUCCESS); +} + +IPCCommandResult USB_KBD::IOCtl(const IOCtlRequest& request) +{ + if (SConfig::GetInstance().m_WiiKeyboard && !Core::WantsDeterminism() && + ControlReference::InputGateOn() && !m_message_queue.empty()) + { + Memory::CopyToEmu(request.buffer_out, &m_message_queue.front(), sizeof(MessageData)); + m_message_queue.pop(); + } + return GetDefaultReply(IPC_SUCCESS); +} + +bool USB_KBD::IsKeyPressed(int key) const +{ +#ifdef _WIN32 + return (GetAsyncKeyState(key) & 0x8000) != 0; +#else + // TODO: do it for non-Windows platforms + return false; +#endif +} + +void USB_KBD::Update() +{ + if (!SConfig::GetInstance().m_WiiKeyboard || Core::WantsDeterminism() || !m_is_active) + return; + + u8 modifiers = 0x00; + PressedKeyData pressed_keys{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + bool got_event = false; + size_t num_pressed_keys = 0; + for (size_t i = 0; i < m_old_key_buffer.size(); i++) + { + const bool key_pressed_now = IsKeyPressed(static_cast(i)); + const bool key_pressed_before = m_old_key_buffer[i]; + u8 key_code = 0; + + if (key_pressed_now ^ key_pressed_before) + { + if (key_pressed_now) + { + switch (m_keyboard_layout) + { + case KBD_LAYOUT_QWERTY: + key_code = s_key_codes_qwerty[i]; + break; + + case KBD_LAYOUT_AZERTY: + key_code = s_key_codes_azerty[i]; + break; + } + + if (key_code == 0x00) + continue; + + pressed_keys[num_pressed_keys] = key_code; + + num_pressed_keys++; + if (num_pressed_keys == pressed_keys.size()) + break; + } + + got_event = true; + } + + m_old_key_buffer[i] = key_pressed_now; + } + +#ifdef _WIN32 + if (GetAsyncKeyState(VK_LCONTROL) & 0x8000) + modifiers |= 0x01; + if (GetAsyncKeyState(VK_LSHIFT) & 0x8000) + modifiers |= 0x02; + if (GetAsyncKeyState(VK_MENU) & 0x8000) + modifiers |= 0x04; + if (GetAsyncKeyState(VK_LWIN) & 0x8000) + modifiers |= 0x08; + if (GetAsyncKeyState(VK_RCONTROL) & 0x8000) + modifiers |= 0x10; + if (GetAsyncKeyState(VK_RSHIFT) & 0x8000) + modifiers |= 0x20; + // TODO: VK_MENU is for ALT, not for ALT GR (ALT GR seems to work though...) + if (GetAsyncKeyState(VK_MENU) & 0x8000) + modifiers |= 0x40; + if (GetAsyncKeyState(VK_RWIN) & 0x8000) + modifiers |= 0x80; +#else +// TODO: modifiers for non-Windows platforms +#endif + + if (modifiers ^ m_old_modifiers) + { + got_event = true; + m_old_modifiers = modifiers; + } + + if (got_event) + m_message_queue.emplace(MessageType::Event, modifiers, pressed_keys); +} } // namespace IOS::HLE::Device diff --git a/Source/Core/Core/IOS/USB/USB_KBD.h b/Source/Core/Core/IOS/USB/USB_KBD.h index 92cc16cd63..3928714e20 100644 --- a/Source/Core/Core/IOS/USB/USB_KBD.h +++ b/Source/Core/Core/IOS/USB/USB_KBD.h @@ -4,8 +4,10 @@ #pragma once +#include #include #include +#include #include "Common/CommonTypes.h" #include "Core/IOS/Device.h" @@ -24,31 +26,35 @@ public: void Update() override; private: - enum + enum class MessageType : u32 { - MSG_KBD_CONNECT = 0, - MSG_KBD_DISCONNECT = 1, - MSG_EVENT = 2 + KeyboardConnect = 0, + KeyboardDisconnect = 1, + Event = 2 }; + using PressedKeyData = std::array; + #pragma pack(push, 1) - struct SMessageData + struct MessageData { - u32 MsgType; - u32 Unk1; - u8 Modifiers; - u8 Unk2; - u8 PressedKeys[6]; + MessageType msg_type{}; + u32 unk1 = 0; + u8 modifiers = 0; + u8 unk2 = 0; + PressedKeyData pressed_keys{}; - SMessageData(u32 msg_type, u8 modifiers, u8* pressed_keys); + MessageData(MessageType msg_type, u8 modifiers, PressedKeyData pressed_keys); }; + static_assert(std::is_trivially_copyable_v, + "MessageData must be trivially copyable, as it's copied into emulated memory."); #pragma pack(pop) - std::queue m_MessageQueue; + std::queue m_message_queue; - bool m_OldKeyBuffer[256]; - u8 m_OldModifiers; + std::array m_old_key_buffer{}; + u8 m_old_modifiers = 0; - virtual bool IsKeyPressed(int _Key); + bool IsKeyPressed(int key) const; // This stuff should probably die enum @@ -56,8 +62,6 @@ private: KBD_LAYOUT_QWERTY = 0, KBD_LAYOUT_AZERTY = 1 }; - int m_KeyboardLayout; - static u8 m_KeyCodesQWERTY[256]; - static u8 m_KeyCodesAZERTY[256]; + int m_keyboard_layout = KBD_LAYOUT_QWERTY; }; } // namespace IOS::HLE::Device