commit
59155b4d5e
|
@ -4,7 +4,7 @@
|
|||
|
||||
#include "Core/IOS/USB/USB_KBD.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <array>
|
||||
#include <queue>
|
||||
|
||||
#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<SMessageData>();
|
||||
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<u8, 256> 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<u8, 256> 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<u8, 256> s_key_codes_qwerty{};
|
||||
|
||||
u8 USB_KBD::m_KeyCodesAZERTY[256] = {0};
|
||||
constexpr std::array<u8, 256> s_key_codes_azerty{};
|
||||
#endif
|
||||
} // Anonymous namespace
|
||||
|
||||
USB_KBD::MessageData::MessageData(MessageType type, u8 modifiers, PressedKeyData pressed_keys)
|
||||
: msg_type{Common::swap32(static_cast<u32>(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<int>(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
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#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<u8, 6>;
|
||||
|
||||
#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>,
|
||||
"MessageData must be trivially copyable, as it's copied into emulated memory.");
|
||||
#pragma pack(pop)
|
||||
std::queue<SMessageData> m_MessageQueue;
|
||||
std::queue<MessageData> m_message_queue;
|
||||
|
||||
bool m_OldKeyBuffer[256];
|
||||
u8 m_OldModifiers;
|
||||
std::array<bool, 256> 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
|
||||
|
|
Loading…
Reference in New Issue