commit
59155b4d5e
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
#include "Core/IOS/USB/USB_KBD.h"
|
#include "Core/IOS/USB/USB_KBD.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <array>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
|
@ -22,156 +22,11 @@
|
||||||
|
|
||||||
namespace IOS::HLE::Device
|
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
|
// Crazy ugly
|
||||||
#ifdef _WIN32
|
#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,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x2A, // Backspace
|
0x2A, // Backspace
|
||||||
0x2B, // Tab
|
0x2B, // Tab
|
||||||
|
@ -241,11 +96,9 @@ u8 USB_KBD::m_KeyCodesQWERTY[256] = {
|
||||||
0x34, // '''
|
0x34, // '''
|
||||||
0x00, //
|
0x00, //
|
||||||
0x00, // Nothing interesting past this point.
|
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,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x2A, // Backspace
|
0x2A, // Backspace
|
||||||
0x2B, // Tab
|
0x2B, // Tab
|
||||||
|
@ -315,11 +168,143 @@ u8 USB_KBD::m_KeyCodesAZERTY[256] = {
|
||||||
0x00, // ' '
|
0x00, // ' '
|
||||||
0x38, // '!'
|
0x38, // '!'
|
||||||
0x00, // Nothing interesting past this point.
|
0x00, // Nothing interesting past this point.
|
||||||
|
|
||||||
};
|
};
|
||||||
#else
|
#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
|
#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
|
} // namespace IOS::HLE::Device
|
||||||
|
|
|
@ -4,8 +4,10 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Core/IOS/Device.h"
|
#include "Core/IOS/Device.h"
|
||||||
|
@ -24,31 +26,35 @@ public:
|
||||||
void Update() override;
|
void Update() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum
|
enum class MessageType : u32
|
||||||
{
|
{
|
||||||
MSG_KBD_CONNECT = 0,
|
KeyboardConnect = 0,
|
||||||
MSG_KBD_DISCONNECT = 1,
|
KeyboardDisconnect = 1,
|
||||||
MSG_EVENT = 2
|
Event = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using PressedKeyData = std::array<u8, 6>;
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
struct SMessageData
|
struct MessageData
|
||||||
{
|
{
|
||||||
u32 MsgType;
|
MessageType msg_type{};
|
||||||
u32 Unk1;
|
u32 unk1 = 0;
|
||||||
u8 Modifiers;
|
u8 modifiers = 0;
|
||||||
u8 Unk2;
|
u8 unk2 = 0;
|
||||||
u8 PressedKeys[6];
|
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)
|
#pragma pack(pop)
|
||||||
std::queue<SMessageData> m_MessageQueue;
|
std::queue<MessageData> m_message_queue;
|
||||||
|
|
||||||
bool m_OldKeyBuffer[256];
|
std::array<bool, 256> m_old_key_buffer{};
|
||||||
u8 m_OldModifiers;
|
u8 m_old_modifiers = 0;
|
||||||
|
|
||||||
virtual bool IsKeyPressed(int _Key);
|
bool IsKeyPressed(int key) const;
|
||||||
|
|
||||||
// This stuff should probably die
|
// This stuff should probably die
|
||||||
enum
|
enum
|
||||||
|
@ -56,8 +62,6 @@ private:
|
||||||
KBD_LAYOUT_QWERTY = 0,
|
KBD_LAYOUT_QWERTY = 0,
|
||||||
KBD_LAYOUT_AZERTY = 1
|
KBD_LAYOUT_AZERTY = 1
|
||||||
};
|
};
|
||||||
int m_KeyboardLayout;
|
int m_keyboard_layout = KBD_LAYOUT_QWERTY;
|
||||||
static u8 m_KeyCodesQWERTY[256];
|
|
||||||
static u8 m_KeyCodesAZERTY[256];
|
|
||||||
};
|
};
|
||||||
} // namespace IOS::HLE::Device
|
} // namespace IOS::HLE::Device
|
||||||
|
|
Loading…
Reference in New Issue