mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-07-19 01:15:34 -05:00
IOS/KBD: Add keyboard support for SDL3 backend
This commit is contained in:
parent
d1d0fd6742
commit
a806645510
|
|
@ -351,6 +351,11 @@ if(USE_UPNP)
|
|||
target_link_libraries(common PRIVATE Miniupnpc::miniupnpc)
|
||||
endif()
|
||||
|
||||
if(ENABLE_SDL)
|
||||
target_link_libraries(common PRIVATE SDL3::SDL3)
|
||||
target_compile_definitions(common PRIVATE -DHAVE_SDL3)
|
||||
endif()
|
||||
|
||||
if(ENABLE_LLVM)
|
||||
find_package(LLVM CONFIG)
|
||||
if(LLVM_FOUND)
|
||||
|
|
|
|||
|
|
@ -4,12 +4,25 @@
|
|||
#include "Common/Keyboard.h"
|
||||
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#elif defined(HAVE_SDL3)
|
||||
#include <SDL3/SDL_events.h>
|
||||
#include <SDL3/SDL_keyboard.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SDL3
|
||||
// Will be overridden by Dolphin's SDL InputBackend
|
||||
u32 Common::KeyboardContext::s_sdl_init_event_type(-1);
|
||||
u32 Common::KeyboardContext::s_sdl_update_event_type(-1);
|
||||
u32 Common::KeyboardContext::s_sdl_quit_event_type(-1);
|
||||
#endif
|
||||
|
||||
#include "Core/Config/MainSettings.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
// Crazy ugly
|
||||
|
|
@ -173,59 +186,183 @@ u8 MapVirtualKeyToHID(u8 virtual_key, int keyboard_layout)
|
|||
#else
|
||||
u8 MapVirtualKeyToHID(u8 virtual_key, int keyboard_layout)
|
||||
{
|
||||
// SDL3 keyboard state uses scan codes already based on HID usage id
|
||||
return virtual_key;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::weak_ptr<Common::KeyboardContext> s_keyboard_context;
|
||||
std::mutex s_keyboard_context_mutex;
|
||||
|
||||
// Will be updated by DolphinQt's Host:
|
||||
// - SetRenderHandle
|
||||
// - SetFullscreen
|
||||
Common::KeyboardContext::HandlerState s_handler_state{};
|
||||
} // Anonymous namespace
|
||||
|
||||
namespace Common
|
||||
{
|
||||
bool Common::IsVirtualKeyPressed(int virtual_key)
|
||||
KeyboardContext::KeyboardContext()
|
||||
{
|
||||
if (Config::Get(Config::MAIN_WII_KEYBOARD))
|
||||
Init();
|
||||
}
|
||||
|
||||
KeyboardContext::~KeyboardContext()
|
||||
{
|
||||
if (Config::Get(Config::MAIN_WII_KEYBOARD))
|
||||
Quit();
|
||||
}
|
||||
|
||||
void KeyboardContext::Init()
|
||||
{
|
||||
#if !defined(_WIN32) && defined(HAVE_SDL3)
|
||||
SDL_Event event{s_sdl_init_event_type};
|
||||
SDL_PushEvent(&event);
|
||||
m_keyboard_state = SDL_GetKeyboardState(nullptr);
|
||||
#endif
|
||||
m_is_ready = true;
|
||||
}
|
||||
|
||||
void KeyboardContext::Quit()
|
||||
{
|
||||
m_is_ready = false;
|
||||
#if !defined(_WIN32) && defined(HAVE_SDL3)
|
||||
SDL_Event event{s_sdl_quit_event_type};
|
||||
SDL_PushEvent(&event);
|
||||
#endif
|
||||
}
|
||||
|
||||
void* KeyboardContext::HandlerState::GetHandle() const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (is_rendering_to_main && !is_fullscreen)
|
||||
return main_handle;
|
||||
#endif
|
||||
return renderer_handle;
|
||||
}
|
||||
|
||||
void KeyboardContext::NotifyInit()
|
||||
{
|
||||
if (auto self = s_keyboard_context.lock())
|
||||
self->Init();
|
||||
}
|
||||
|
||||
void KeyboardContext::NotifyHandlerChanged(const KeyboardContext::HandlerState& state)
|
||||
{
|
||||
s_handler_state = state;
|
||||
if (s_keyboard_context.expired())
|
||||
return;
|
||||
#if !defined(_WIN32) && defined(HAVE_SDL3)
|
||||
SDL_Event event{s_sdl_update_event_type};
|
||||
SDL_PushEvent(&event);
|
||||
#endif
|
||||
}
|
||||
|
||||
void KeyboardContext::NotifyQuit()
|
||||
{
|
||||
if (auto self = s_keyboard_context.lock())
|
||||
self->Quit();
|
||||
}
|
||||
|
||||
void* KeyboardContext::GetWindowHandle()
|
||||
{
|
||||
return s_handler_state.GetHandle();
|
||||
}
|
||||
|
||||
std::shared_ptr<KeyboardContext> KeyboardContext::GetInstance()
|
||||
{
|
||||
const std::lock_guard guard(s_keyboard_context_mutex);
|
||||
std::shared_ptr<KeyboardContext> ptr = s_keyboard_context.lock();
|
||||
if (!ptr)
|
||||
{
|
||||
ptr = std::shared_ptr<KeyboardContext>(new KeyboardContext);
|
||||
s_keyboard_context = ptr;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
HIDPressedState KeyboardContext::GetPressedState(int keyboard_layout) const
|
||||
{
|
||||
return m_is_ready ? HIDPressedState{.modifiers = PollHIDModifiers(),
|
||||
.pressed_keys = PollHIDPressedKeys(keyboard_layout)} :
|
||||
HIDPressedState{};
|
||||
}
|
||||
|
||||
bool KeyboardContext::IsVirtualKeyPressed(int virtual_key) const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return (GetAsyncKeyState(virtual_key) & 0x8000) != 0;
|
||||
#elif defined(HAVE_SDL3)
|
||||
if (virtual_key >= SDL_SCANCODE_COUNT)
|
||||
return false;
|
||||
return m_keyboard_state[virtual_key];
|
||||
#else
|
||||
// TODO: do it for non-Windows platforms
|
||||
// TODO: Android implementation
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
u8 Common::PollHIDModifiers()
|
||||
u8 KeyboardContext::PollHIDModifiers() const
|
||||
{
|
||||
u8 modifiers = 0;
|
||||
#ifdef _WIN32
|
||||
|
||||
using VkHidPair = std::pair<int, u8>;
|
||||
|
||||
// References:
|
||||
// https://learn.microsoft.com/windows/win32/inputdev/virtual-key-codes
|
||||
// https://wiki.libsdl.org/SDL3/SDL_Scancode
|
||||
// https://www.usb.org/document-library/device-class-definition-hid-111
|
||||
//
|
||||
// HID modifiers:
|
||||
// Bit 0 - LEFT CTRL
|
||||
// Bit 1 - LEFT SHIFT
|
||||
// Bit 2 - LEFT ALT
|
||||
// Bit 3 - LEFT GUI
|
||||
// Bit 4 - RIGHT CTRL
|
||||
// Bit 5 - RIGHT SHIFT
|
||||
// Bit 6 - RIGHT ALT
|
||||
// Bit 7 - RIGHT GUI
|
||||
static const std::vector<VkHidPair> MODIFIERS_MAP{
|
||||
{VK_LCONTROL, 0x01}, // HID modifier: Bit 0 - LEFT CTRL
|
||||
{VK_LSHIFT, 0x02}, // HID modifier: Bit 1 - LEFT SHIFT
|
||||
{VK_LMENU, 0x04}, // HID modifier: Bit 2 - LEFT ALT
|
||||
{VK_LWIN, 0x08}, // HID modifier: Bit 3 - LEFT GUI
|
||||
{VK_RCONTROL, 0x10}, // HID modifier: Bit 4 - RIGHT CTRL
|
||||
{VK_RSHIFT, 0x20}, // HID modifier: Bit 5 - RIGHT SHIFT
|
||||
{VK_RMENU, 0x40}, // HID modifier: Bit 6 - RIGHT ALT
|
||||
{VK_RWIN, 0x80} // HID modifier: Bit 7 - RIGHT GUI
|
||||
#ifdef _WIN32
|
||||
{VK_LCONTROL, 0x01}, {VK_LSHIFT, 0x02}, {VK_LMENU, 0x04},
|
||||
{VK_LWIN, 0x08}, {VK_RCONTROL, 0x10}, {VK_RSHIFT, 0x20},
|
||||
{VK_RMENU, 0x40}, {VK_RWIN, 0x80}
|
||||
#elif defined(HAVE_SDL3)
|
||||
{SDL_SCANCODE_LCTRL, 0x01}, {SDL_SCANCODE_LSHIFT, 0x02}, {SDL_SCANCODE_LALT, 0x04},
|
||||
{SDL_SCANCODE_LGUI, 0x08}, {SDL_SCANCODE_RCTRL, 0x10}, {SDL_SCANCODE_RSHIFT, 0x20},
|
||||
{SDL_SCANCODE_RALT, 0x40}, {SDL_SCANCODE_RGUI, 0x80}
|
||||
#else
|
||||
// TODO: Android implementation
|
||||
#endif
|
||||
};
|
||||
|
||||
for (const auto& [virtual_key, hid_modifier] : MODIFIERS_MAP)
|
||||
{
|
||||
if (IsVirtualKeyPressed(virtual_key))
|
||||
modifiers |= hid_modifier;
|
||||
}
|
||||
#else
|
||||
// TODO: Implementation for non-Windows platforms
|
||||
#endif
|
||||
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
HIDPressedKeys PollHIDPressedKeys(int keyboard_layout)
|
||||
HIDPressedKeys KeyboardContext::PollHIDPressedKeys(int keyboard_layout) const
|
||||
{
|
||||
HIDPressedKeys pressed_keys{};
|
||||
auto it = pressed_keys.begin();
|
||||
|
||||
#ifdef _WIN32
|
||||
for (std::size_t virtual_key = 0; virtual_key < KEYBOARD_STATE_SIZE; ++virtual_key)
|
||||
const std::size_t begin = 0;
|
||||
const std::size_t end = KEYBOARD_STATE_SIZE;
|
||||
#elif defined(HAVE_SDL3)
|
||||
const std::size_t begin = SDL_SCANCODE_A;
|
||||
const std::size_t end = SDL_SCANCODE_LCTRL;
|
||||
#else
|
||||
const std::size_t begin = 0;
|
||||
const std::size_t end = 0;
|
||||
#endif
|
||||
|
||||
for (std::size_t virtual_key = begin; virtual_key < end; ++virtual_key)
|
||||
{
|
||||
if (!IsVirtualKeyPressed(static_cast<int>(virtual_key)))
|
||||
continue;
|
||||
|
|
@ -234,9 +371,6 @@ HIDPressedKeys PollHIDPressedKeys(int keyboard_layout)
|
|||
if (++it == pressed_keys.end())
|
||||
break;
|
||||
}
|
||||
#else
|
||||
// TODO: Implementation for non-Windows platforms
|
||||
#endif
|
||||
return pressed_keys;
|
||||
}
|
||||
} // namespace Common
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
|
|
@ -17,7 +18,55 @@ enum
|
|||
|
||||
using HIDPressedKeys = std::array<u8, 6>;
|
||||
|
||||
bool IsVirtualKeyPressed(int virtual_key);
|
||||
u8 PollHIDModifiers();
|
||||
HIDPressedKeys PollHIDPressedKeys(int keyboard_layout);
|
||||
struct HIDPressedState
|
||||
{
|
||||
u8 modifiers = 0;
|
||||
HIDPressedKeys pressed_keys{};
|
||||
|
||||
auto operator<=>(const HIDPressedState&) const = default;
|
||||
};
|
||||
|
||||
class KeyboardContext
|
||||
{
|
||||
public:
|
||||
~KeyboardContext();
|
||||
|
||||
struct HandlerState
|
||||
{
|
||||
void* main_handle = nullptr;
|
||||
void* renderer_handle = nullptr;
|
||||
bool is_fullscreen = false;
|
||||
bool is_rendering_to_main = false;
|
||||
|
||||
void* GetHandle() const;
|
||||
};
|
||||
|
||||
static void NotifyInit();
|
||||
static void NotifyHandlerChanged(const HandlerState& state);
|
||||
static void NotifyQuit();
|
||||
static void* GetWindowHandle();
|
||||
static std::shared_ptr<KeyboardContext> GetInstance();
|
||||
|
||||
HIDPressedState GetPressedState(int keyboard_layout) const;
|
||||
|
||||
#ifdef HAVE_SDL3
|
||||
static u32 s_sdl_init_event_type;
|
||||
static u32 s_sdl_update_event_type;
|
||||
static u32 s_sdl_quit_event_type;
|
||||
#endif
|
||||
|
||||
private:
|
||||
KeyboardContext();
|
||||
|
||||
void Init();
|
||||
void Quit();
|
||||
bool IsVirtualKeyPressed(int virtual_key) const;
|
||||
u8 PollHIDModifiers() const;
|
||||
HIDPressedKeys PollHIDPressedKeys(int keyboard_layout) const;
|
||||
|
||||
bool m_is_ready = false;
|
||||
#ifdef HAVE_SDL3
|
||||
const bool* m_keyboard_state = nullptr;
|
||||
#endif
|
||||
};
|
||||
} // namespace Common
|
||||
|
|
|
|||
|
|
@ -15,161 +15,7 @@
|
|||
|
||||
namespace IOS::HLE
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// Crazy ugly
|
||||
#ifdef _WIN32
|
||||
constexpr std::array<u8, 256> s_key_codes_qwerty{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x2A, // Backspace
|
||||
0x2B, // Tab
|
||||
0x00, 0x00,
|
||||
0x00, // Clear
|
||||
0x28, // Return
|
||||
0x00, 0x00,
|
||||
0x00, // Shift
|
||||
0x00, // Control
|
||||
0x00, // ALT
|
||||
0x48, // Pause
|
||||
0x39, // Capital
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x29, // Escape
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x2C, // Space
|
||||
0x4B, // Prior
|
||||
0x4E, // Next
|
||||
0x4D, // End
|
||||
0x4A, // Home
|
||||
0x50, // Left
|
||||
0x52, // Up
|
||||
0x4F, // Right
|
||||
0x51, // Down
|
||||
0x00, 0x00, 0x00,
|
||||
0x46, // Print screen
|
||||
0x49, // Insert
|
||||
0x4C, // Delete
|
||||
0x00,
|
||||
// 0 -> 9
|
||||
0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
// A -> Z
|
||||
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13,
|
||||
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Numpad 0 -> 9
|
||||
0x62, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61,
|
||||
0x55, // Multiply
|
||||
0x57, // Add
|
||||
0x00, // Separator
|
||||
0x56, // Subtract
|
||||
0x63, // Decimal
|
||||
0x54, // Divide
|
||||
// F1 -> F12
|
||||
0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
|
||||
// F13 -> F24
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x53, // Numlock
|
||||
0x47, // Scroll lock
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Modifier keys
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x33, // ';'
|
||||
0x2E, // Plus
|
||||
0x36, // Comma
|
||||
0x2D, // Minus
|
||||
0x37, // Period
|
||||
0x38, // '/'
|
||||
0x35, // '~'
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x2F, // '['
|
||||
0x32, // '\'
|
||||
0x30, // ']'
|
||||
0x34, // '''
|
||||
0x00, //
|
||||
0x00, // Nothing interesting past this point.
|
||||
};
|
||||
|
||||
constexpr std::array<u8, 256> s_key_codes_azerty{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x2A, // Backspace
|
||||
0x2B, // Tab
|
||||
0x00, 0x00,
|
||||
0x00, // Clear
|
||||
0x28, // Return
|
||||
0x00, 0x00,
|
||||
0x00, // Shift
|
||||
0x00, // Control
|
||||
0x00, // ALT
|
||||
0x48, // Pause
|
||||
0x39, // Capital
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x29, // Escape
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x2C, // Space
|
||||
0x4B, // Prior
|
||||
0x4E, // Next
|
||||
0x4D, // End
|
||||
0x4A, // Home
|
||||
0x50, // Left
|
||||
0x52, // Up
|
||||
0x4F, // Right
|
||||
0x51, // Down
|
||||
0x00, 0x00, 0x00,
|
||||
0x46, // Print screen
|
||||
0x49, // Insert
|
||||
0x4C, // Delete
|
||||
0x00,
|
||||
// 0 -> 9
|
||||
0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
// A -> Z
|
||||
0x14, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x33, 0x11, 0x12, 0x13,
|
||||
0x04, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1D, 0x1B, 0x1C, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Numpad 0 -> 9
|
||||
0x62, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61,
|
||||
0x55, // Multiply
|
||||
0x57, // Add
|
||||
0x00, // Separator
|
||||
0x56, // Subtract
|
||||
0x63, // Decimal
|
||||
0x54, // Divide
|
||||
// F1 -> F12
|
||||
0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
|
||||
// F13 -> F24
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x53, // Numlock
|
||||
0x47, // Scroll lock
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Modifier keys
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x30, // '$'
|
||||
0x2E, // Plus
|
||||
0x10, // Comma
|
||||
0x00, // Minus
|
||||
0x36, // Period
|
||||
0x37, // '/'
|
||||
0x34, // ' '
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x2D, // ')'
|
||||
0x32, // '\'
|
||||
0x2F, // '^'
|
||||
0x00, // ' '
|
||||
0x38, // '!'
|
||||
0x00, // Nothing interesting past this point.
|
||||
};
|
||||
#else
|
||||
constexpr std::array<u8, 256> s_key_codes_qwerty{};
|
||||
|
||||
constexpr std::array<u8, 256> s_key_codes_azerty{};
|
||||
#endif
|
||||
} // Anonymous namespace
|
||||
|
||||
USB_KBD::MessageData::MessageData(MessageType type, const State& state)
|
||||
USB_KBD::MessageData::MessageData(MessageType type, const Common::HIDPressedState& state)
|
||||
: msg_type{Common::swap32(static_cast<u32>(type))}, modifiers{state.modifiers},
|
||||
pressed_keys{state.pressed_keys}
|
||||
{
|
||||
|
|
@ -192,11 +38,21 @@ std::optional<IPCReply> USB_KBD::Open(const OpenRequest& request)
|
|||
|
||||
m_message_queue = {};
|
||||
m_previous_state = {};
|
||||
m_keyboard_context = Common::KeyboardContext::GetInstance();
|
||||
|
||||
// m_message_queue.emplace(MessageType::KeyboardConnect, {});
|
||||
return Device::Open(request);
|
||||
}
|
||||
|
||||
std::optional<IPCReply> USB_KBD::Close(u32 fd)
|
||||
{
|
||||
INFO_LOG_FMT(IOS, "USB_KBD: Close");
|
||||
|
||||
m_keyboard_context.reset();
|
||||
|
||||
return Device::Close(fd);
|
||||
}
|
||||
|
||||
std::optional<IPCReply> USB_KBD::Write(const ReadWriteRequest& request)
|
||||
{
|
||||
// Stubbed.
|
||||
|
|
@ -218,11 +74,13 @@ std::optional<IPCReply> USB_KBD::IOCtl(const IOCtlRequest& request)
|
|||
|
||||
void USB_KBD::Update()
|
||||
{
|
||||
if (!Config::Get(Config::MAIN_WII_KEYBOARD) || Core::WantsDeterminism() || !m_is_active)
|
||||
if (!Config::Get(Config::MAIN_WII_KEYBOARD) || Core::WantsDeterminism() || !m_is_active ||
|
||||
!m_keyboard_context)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const State current_state{.modifiers = Common::PollHIDModifiers(),
|
||||
.pressed_keys = Common::PollHIDPressedKeys(m_keyboard_layout)};
|
||||
const auto current_state = m_keyboard_context->GetPressedState(m_keyboard_layout);
|
||||
|
||||
if (current_state == m_previous_state)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ public:
|
|||
USB_KBD(EmulationKernel& ios, const std::string& device_name);
|
||||
|
||||
std::optional<IPCReply> Open(const OpenRequest& request) override;
|
||||
std::optional<IPCReply> Close(u32 fd) override;
|
||||
std::optional<IPCReply> Write(const ReadWriteRequest& request) override;
|
||||
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
|
||||
void Update() override;
|
||||
|
|
@ -31,14 +32,6 @@ private:
|
|||
Event = 2
|
||||
};
|
||||
|
||||
struct State
|
||||
{
|
||||
u8 modifiers = 0;
|
||||
Common::HIDPressedKeys pressed_keys{};
|
||||
|
||||
auto operator<=>(const State&) const = default;
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct MessageData
|
||||
{
|
||||
|
|
@ -48,13 +41,14 @@ private:
|
|||
u8 unk2 = 0;
|
||||
Common::HIDPressedKeys pressed_keys{};
|
||||
|
||||
MessageData(MessageType msg_type, const State& state);
|
||||
MessageData(MessageType msg_type, const Common::HIDPressedState& state);
|
||||
};
|
||||
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<MessageData> m_message_queue;
|
||||
State m_previous_state;
|
||||
Common::HIDPressedState m_previous_state;
|
||||
int m_keyboard_layout = Common::KBD_LAYOUT_QWERTY;
|
||||
std::shared_ptr<Common::KeyboardContext> m_keyboard_context;
|
||||
};
|
||||
} // namespace IOS::HLE
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "Common/Keyboard.h"
|
||||
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
|
|
@ -60,6 +62,11 @@ void Host::SetRenderHandle(void* handle)
|
|||
{
|
||||
m_render_to_main = Config::Get(Config::MAIN_RENDER_TO_MAIN);
|
||||
|
||||
Common::KeyboardContext::NotifyHandlerChanged({.main_handle = m_main_window_handle.load(),
|
||||
.renderer_handle = handle,
|
||||
.is_fullscreen = m_render_fullscreen.load(),
|
||||
.is_rendering_to_main = m_render_to_main.load()});
|
||||
|
||||
if (m_render_handle == handle)
|
||||
return;
|
||||
|
||||
|
|
@ -174,6 +181,11 @@ void Host::SetRenderFullscreen(bool fullscreen)
|
|||
{
|
||||
m_render_fullscreen = fullscreen;
|
||||
|
||||
Common::KeyboardContext::NotifyHandlerChanged({.main_handle = m_main_window_handle.load(),
|
||||
.renderer_handle = m_render_handle.load(),
|
||||
.is_fullscreen = fullscreen,
|
||||
.is_rendering_to_main = m_render_to_main.load()});
|
||||
|
||||
if (g_gfx && g_gfx->IsFullscreen() != fullscreen && g_ActiveConfig.ExclusiveFullscreenEnabled())
|
||||
{
|
||||
RunWithGPUThreadInactive([fullscreen] { g_gfx->SetFullscreen(fullscreen); });
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "Common/Config/Config.h"
|
||||
#include "Common/Contains.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/Keyboard.h"
|
||||
|
||||
#include "Core/AchievementManager.h"
|
||||
#include "Core/Config/GraphicsSettings.h"
|
||||
|
|
@ -938,7 +939,13 @@ bool Settings::IsUSBKeyboardConnected() const
|
|||
void Settings::SetUSBKeyboardConnected(bool connected)
|
||||
{
|
||||
if (IsUSBKeyboardConnected() != connected)
|
||||
{
|
||||
Config::SetBaseOrCurrent(Config::MAIN_WII_KEYBOARD, connected);
|
||||
if (connected)
|
||||
Common::KeyboardContext::NotifyInit();
|
||||
else
|
||||
Common::KeyboardContext::NotifyQuit();
|
||||
}
|
||||
}
|
||||
|
||||
bool Settings::IsWiiSpeakMuted() const
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "InputCommon/ControllerInterface/SDL/SDL.h"
|
||||
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
|
@ -14,6 +15,7 @@
|
|||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "Common/Event.h"
|
||||
#include "Common/Keyboard.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/ScopeGuard.h"
|
||||
#include "Common/Thread.h"
|
||||
|
|
@ -21,10 +23,83 @@
|
|||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/HW/SI/SI.h"
|
||||
#include "Core/HW/SI/SI_Device.h"
|
||||
#include "Core/Host.h"
|
||||
|
||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||
#include "InputCommon/ControllerInterface/SDL/SDLGamepad.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
using UniqueSDLWindow = std::unique_ptr<SDL_Window, void (*)(SDL_Window*)>;
|
||||
|
||||
// Based on sdl2-compat 76eb981a4c376bcaf615c0af37d46512ba45cfb8
|
||||
SDL_Window* SDL_CreateWindowFrom(void* handle)
|
||||
{
|
||||
SDL_PropertiesID props = SDL_CreateProperties();
|
||||
if (!props)
|
||||
return nullptr;
|
||||
|
||||
if (const char* hint = SDL_GetHint("SDL_VIDEO_WINDOW_SHARE_PIXEL_FORMAT"); hint)
|
||||
{
|
||||
// This hint is a pointer (in string form) of the address of
|
||||
// the window to share a pixel format with
|
||||
SDL_Window* other_window = nullptr;
|
||||
if (SDL_sscanf(hint, "%p", &other_window))
|
||||
{
|
||||
void* ptr = SDL_GetPointerProperty(SDL_GetWindowProperties(other_window),
|
||||
SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr);
|
||||
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_CREATE_WIN32_PIXEL_FORMAT_HWND_POINTER, ptr);
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (SDL_GetHintBoolean("SDL_VIDEO_FOREIGN_WINDOW_OPENGL", false))
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true);
|
||||
|
||||
if (SDL_GetHintBoolean("SDL_VIDEO_FOREIGN_WINDOW_VULKAN", false))
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_VULKAN_BOOLEAN, true);
|
||||
|
||||
SDL_SetPointerProperty(props, "sdl2-compat.external_window", handle);
|
||||
SDL_Window* window = SDL_CreateWindowWithProperties(props);
|
||||
SDL_DestroyProperties(props);
|
||||
|
||||
// SDL3 has per-window text input, so we must enable on this window if it's active
|
||||
if (SDL_EventEnabled(SDL_EVENT_TEXT_INPUT))
|
||||
{
|
||||
props = SDL_CreateProperties();
|
||||
SDL_SetNumberProperty(props, SDL_PROP_TEXTINPUT_TYPE_NUMBER, SDL_TEXTINPUT_TYPE_TEXT);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_TEXTINPUT_CAPITALIZATION_NUMBER, SDL_CAPITALIZE_NONE);
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_TEXTINPUT_AUTOCORRECT_BOOLEAN, false);
|
||||
SDL_StartTextInputWithProperties(window, props);
|
||||
SDL_DestroyProperties(props);
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
std::optional<const char*> UpdateKeyboardHandle(UniqueSDLWindow* unique_window)
|
||||
{
|
||||
std::optional<const char*> error;
|
||||
|
||||
void* keyboard_handle = Common::KeyboardContext::GetWindowHandle();
|
||||
SDL_Window* keyboard_window = SDL_CreateWindowFrom(keyboard_handle);
|
||||
if (keyboard_window == nullptr)
|
||||
error = SDL_GetError();
|
||||
|
||||
unique_window->reset(keyboard_window);
|
||||
if (error.has_value())
|
||||
return error;
|
||||
|
||||
// SDL aggressive hooking might make the window borderless sometimes
|
||||
if (!Host_RendererIsFullscreen())
|
||||
{
|
||||
SDL_SetWindowFullscreen(keyboard_window, 0);
|
||||
SDL_SetWindowBordered(keyboard_window, true);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace ciface::SDL
|
||||
{
|
||||
|
||||
|
|
@ -45,6 +120,7 @@ private:
|
|||
Uint32 m_stop_event_type;
|
||||
Uint32 m_populate_event_type;
|
||||
std::thread m_hotplug_thread;
|
||||
UniqueSDLWindow m_keyboard_window{nullptr, SDL_DestroyWindow};
|
||||
};
|
||||
|
||||
std::unique_ptr<ciface::InputBackend> CreateInputBackend(ControllerInterface* controller_interface)
|
||||
|
|
@ -180,7 +256,7 @@ InputBackend::InputBackend(ControllerInterface* controller_interface)
|
|||
return;
|
||||
}
|
||||
|
||||
const Uint32 custom_events_start = SDL_RegisterEvents(2);
|
||||
const Uint32 custom_events_start = SDL_RegisterEvents(5);
|
||||
if (custom_events_start == static_cast<Uint32>(-1))
|
||||
{
|
||||
ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to register custom events");
|
||||
|
|
@ -188,6 +264,9 @@ InputBackend::InputBackend(ControllerInterface* controller_interface)
|
|||
}
|
||||
m_stop_event_type = custom_events_start;
|
||||
m_populate_event_type = custom_events_start + 1;
|
||||
Common::KeyboardContext::s_sdl_init_event_type = custom_events_start + 2;
|
||||
Common::KeyboardContext::s_sdl_update_event_type = custom_events_start + 3;
|
||||
Common::KeyboardContext::s_sdl_quit_event_type = custom_events_start + 4;
|
||||
|
||||
// Drain all of the events and add the initial joysticks before returning. Otherwise, the
|
||||
// individual joystick events as well as the custom populate event will be handled _after_
|
||||
|
|
@ -287,6 +366,40 @@ bool InputBackend::HandleEventAndContinue(const SDL_Event& e)
|
|||
{
|
||||
return false;
|
||||
}
|
||||
else if (e.type == Common::KeyboardContext::s_sdl_init_event_type)
|
||||
{
|
||||
if (!SDL_InitSubSystem(SDL_INIT_VIDEO))
|
||||
{
|
||||
ERROR_LOG_FMT(IOS_USB, "SDL failed to init subsystem to capture keyboard input: {}",
|
||||
SDL_GetError());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (const auto error = UpdateKeyboardHandle(&m_keyboard_window); error.has_value())
|
||||
{
|
||||
ERROR_LOG_FMT(IOS_USB, "SDL failed to attach window to capture keyboard input: {}", *error);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (e.type == Common::KeyboardContext::s_sdl_update_event_type)
|
||||
{
|
||||
if (!SDL_WasInit(SDL_INIT_VIDEO))
|
||||
return true;
|
||||
|
||||
// Release previous SDLWindow
|
||||
m_keyboard_window.reset();
|
||||
|
||||
if (const auto error = UpdateKeyboardHandle(&m_keyboard_window); error.has_value())
|
||||
{
|
||||
ERROR_LOG_FMT(IOS_USB, "SDL failed to switch window to capture keyboard input: {}", *error);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (e.type == Common::KeyboardContext::s_sdl_quit_event_type)
|
||||
{
|
||||
m_keyboard_window.reset();
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user