IOS/KBD: Add keyboard support for SDL3 backend

This commit is contained in:
Sepalani 2025-04-22 15:51:52 +04:00
commit 58f6eb887c
8 changed files with 361 additions and 38 deletions

View file

@ -354,6 +354,11 @@ if(OPROFILE_FOUND)
target_link_libraries(common PRIVATE OProfile::OProfile) target_link_libraries(common PRIVATE OProfile::OProfile)
endif() endif()
if(ENABLE_SDL)
target_link_libraries(common PRIVATE SDL3::SDL3)
target_compile_definitions(common PRIVATE -DHAVE_SDL3)
endif()
if(ENABLE_LLVM) if(ENABLE_LLVM)
find_package(LLVM CONFIG) find_package(LLVM CONFIG)
if(LLVM_FOUND) if(LLVM_FOUND)

View file

@ -4,12 +4,25 @@
#include "Common/Keyboard.h" #include "Common/Keyboard.h"
#include <array> #include <array>
#include <mutex>
#include <utility> #include <utility>
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#elif defined(HAVE_SDL3)
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_keyboard.h>
#endif #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 namespace
{ {
// Crazy ugly // Crazy ugly
@ -173,59 +186,183 @@ u8 MapVirtualKeyToHID(u8 virtual_key, int keyboard_layout)
#else #else
u8 MapVirtualKeyToHID(u8 virtual_key, int keyboard_layout) u8 MapVirtualKeyToHID(u8 virtual_key, int keyboard_layout)
{ {
// SDL3 keyboard state uses scan codes already based on HID usage id
return virtual_key; return virtual_key;
} }
#endif #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 } // Anonymous namespace
namespace Common 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 #ifdef _WIN32
return (GetAsyncKeyState(virtual_key) & 0x8000) != 0; 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 #else
// TODO: do it for non-Windows platforms // TODO: Android implementation
return false; return false;
#endif #endif
} }
u8 Common::PollHIDModifiers() u8 KeyboardContext::PollHIDModifiers() const
{ {
u8 modifiers = 0; u8 modifiers = 0;
#ifdef _WIN32
using VkHidPair = std::pair<int, u8>; using VkHidPair = std::pair<int, u8>;
// References: // References:
// https://learn.microsoft.com/windows/win32/inputdev/virtual-key-codes // 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 // 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{ static const std::vector<VkHidPair> MODIFIERS_MAP{
{VK_LCONTROL, 0x01}, // HID modifier: Bit 0 - LEFT CTRL #ifdef _WIN32
{VK_LSHIFT, 0x02}, // HID modifier: Bit 1 - LEFT SHIFT {VK_LCONTROL, 0x01}, {VK_LSHIFT, 0x02}, {VK_LMENU, 0x04},
{VK_LMENU, 0x04}, // HID modifier: Bit 2 - LEFT ALT {VK_LWIN, 0x08}, {VK_RCONTROL, 0x10}, {VK_RSHIFT, 0x20},
{VK_LWIN, 0x08}, // HID modifier: Bit 3 - LEFT GUI {VK_RMENU, 0x40}, {VK_RWIN, 0x80}
{VK_RCONTROL, 0x10}, // HID modifier: Bit 4 - RIGHT CTRL #elif defined(HAVE_SDL3)
{VK_RSHIFT, 0x20}, // HID modifier: Bit 5 - RIGHT SHIFT {SDL_SCANCODE_LCTRL, 0x01}, {SDL_SCANCODE_LSHIFT, 0x02}, {SDL_SCANCODE_LALT, 0x04},
{VK_RMENU, 0x40}, // HID modifier: Bit 6 - RIGHT ALT {SDL_SCANCODE_LGUI, 0x08}, {SDL_SCANCODE_RCTRL, 0x10}, {SDL_SCANCODE_RSHIFT, 0x20},
{VK_RWIN, 0x80} // HID modifier: Bit 7 - RIGHT GUI {SDL_SCANCODE_RALT, 0x40}, {SDL_SCANCODE_RGUI, 0x80}
#else
// TODO: Android implementation
#endif
}; };
for (const auto& [virtual_key, hid_modifier] : MODIFIERS_MAP) for (const auto& [virtual_key, hid_modifier] : MODIFIERS_MAP)
{ {
if (IsVirtualKeyPressed(virtual_key)) if (IsVirtualKeyPressed(virtual_key))
modifiers |= hid_modifier; modifiers |= hid_modifier;
} }
#else
// TODO: Implementation for non-Windows platforms
#endif
return modifiers; return modifiers;
} }
HIDPressedKeys PollHIDPressedKeys(int keyboard_layout) HIDPressedKeys KeyboardContext::PollHIDPressedKeys(int keyboard_layout) const
{ {
HIDPressedKeys pressed_keys{}; HIDPressedKeys pressed_keys{};
auto it = pressed_keys.begin(); auto it = pressed_keys.begin();
#ifdef _WIN32 #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))) if (!IsVirtualKeyPressed(static_cast<int>(virtual_key)))
continue; continue;
@ -234,9 +371,6 @@ HIDPressedKeys PollHIDPressedKeys(int keyboard_layout)
if (++it == pressed_keys.end()) if (++it == pressed_keys.end())
break; break;
} }
#else
// TODO: Implementation for non-Windows platforms
#endif
return pressed_keys; return pressed_keys;
} }
} // namespace Common } // namespace Common

View file

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <array> #include <array>
#include <memory>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
@ -17,7 +18,55 @@ enum
using HIDPressedKeys = std::array<u8, 6>; using HIDPressedKeys = std::array<u8, 6>;
bool IsVirtualKeyPressed(int virtual_key); struct HIDPressedState
u8 PollHIDModifiers(); {
HIDPressedKeys PollHIDPressedKeys(int keyboard_layout); 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 } // namespace Common

View file

@ -15,7 +15,7 @@
namespace IOS::HLE namespace IOS::HLE
{ {
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}, : msg_type{Common::swap32(static_cast<u32>(type))}, modifiers{state.modifiers},
pressed_keys{state.pressed_keys} pressed_keys{state.pressed_keys}
{ {
@ -38,11 +38,21 @@ std::optional<IPCReply> USB_KBD::Open(const OpenRequest& request)
m_message_queue = {}; m_message_queue = {};
m_previous_state = {}; m_previous_state = {};
m_keyboard_context = Common::KeyboardContext::GetInstance();
// m_message_queue.emplace(MessageType::KeyboardConnect, {}); // m_message_queue.emplace(MessageType::KeyboardConnect, {});
return Device::Open(request); 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) std::optional<IPCReply> USB_KBD::Write(const ReadWriteRequest& request)
{ {
// Stubbed. // Stubbed.
@ -64,11 +74,13 @@ std::optional<IPCReply> USB_KBD::IOCtl(const IOCtlRequest& request)
void USB_KBD::Update() 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; return;
}
const State current_state{.modifiers = Common::PollHIDModifiers(), const auto current_state = m_keyboard_context->GetPressedState(m_keyboard_layout);
.pressed_keys = Common::PollHIDPressedKeys(m_keyboard_layout)};
if (current_state == m_previous_state) if (current_state == m_previous_state)
return; return;

View file

@ -19,6 +19,7 @@ public:
USB_KBD(EmulationKernel& ios, const std::string& device_name); USB_KBD(EmulationKernel& ios, const std::string& device_name);
std::optional<IPCReply> Open(const OpenRequest& request) override; 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> Write(const ReadWriteRequest& request) override;
std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override; std::optional<IPCReply> IOCtl(const IOCtlRequest& request) override;
void Update() override; void Update() override;
@ -31,14 +32,6 @@ private:
Event = 2 Event = 2
}; };
struct State
{
u8 modifiers = 0;
Common::HIDPressedKeys pressed_keys{};
auto operator<=>(const State&) const = default;
};
#pragma pack(push, 1) #pragma pack(push, 1)
struct MessageData struct MessageData
{ {
@ -48,13 +41,14 @@ private:
u8 unk2 = 0; u8 unk2 = 0;
Common::HIDPressedKeys pressed_keys{}; 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>, static_assert(std::is_trivially_copyable_v<MessageData>,
"MessageData must be trivially copyable, as it's copied into emulated memory."); "MessageData must be trivially copyable, as it's copied into emulated memory.");
#pragma pack(pop) #pragma pack(pop)
std::queue<MessageData> m_message_queue; std::queue<MessageData> m_message_queue;
State m_previous_state; Common::HIDPressedState m_previous_state;
int m_keyboard_layout = Common::KBD_LAYOUT_QWERTY; int m_keyboard_layout = Common::KBD_LAYOUT_QWERTY;
std::shared_ptr<Common::KeyboardContext> m_keyboard_context;
}; };
} // namespace IOS::HLE } // namespace IOS::HLE

View file

@ -16,6 +16,7 @@
#endif #endif
#include "Common/Common.h" #include "Common/Common.h"
#include "Common/Keyboard.h"
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
@ -62,6 +63,11 @@ void Host::SetRenderHandle(void* handle)
{ {
m_render_to_main = Config::Get(Config::MAIN_RENDER_TO_MAIN); 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) if (m_render_handle == handle)
return; return;
@ -176,6 +182,11 @@ void Host::SetRenderFullscreen(bool fullscreen)
{ {
m_render_fullscreen = 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()) if (g_gfx && g_gfx->IsFullscreen() != fullscreen && g_ActiveConfig.ExclusiveFullscreenEnabled())
{ {
RunWithGPUThreadInactive([fullscreen] { g_gfx->SetFullscreen(fullscreen); }); RunWithGPUThreadInactive([fullscreen] { g_gfx->SetFullscreen(fullscreen); });

View file

@ -24,6 +24,7 @@
#include "Common/Config/Config.h" #include "Common/Config/Config.h"
#include "Common/Contains.h" #include "Common/Contains.h"
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
#include "Common/Keyboard.h"
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Core/AchievementManager.h" #include "Core/AchievementManager.h"
@ -789,6 +790,10 @@ void Settings::SetUSBKeyboardConnected(bool connected)
if (IsUSBKeyboardConnected() != connected) if (IsUSBKeyboardConnected() != connected)
{ {
Config::SetBaseOrCurrent(Config::MAIN_WII_KEYBOARD, connected); Config::SetBaseOrCurrent(Config::MAIN_WII_KEYBOARD, connected);
if (connected)
Common::KeyboardContext::NotifyInit();
else
Common::KeyboardContext::NotifyQuit();
emit USBKeyboardConnectionChanged(connected); emit USBKeyboardConnectionChanged(connected);
} }
} }

View file

@ -3,6 +3,7 @@
#include "InputCommon/ControllerInterface/SDL/SDL.h" #include "InputCommon/ControllerInterface/SDL/SDL.h"
#include <optional>
#include <span> #include <span>
#include <thread> #include <thread>
#include <vector> #include <vector>
@ -14,12 +15,86 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include "Common/Event.h" #include "Common/Event.h"
#include "Common/Keyboard.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/ScopeGuard.h" #include "Common/ScopeGuard.h"
#include "Core/Host.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "InputCommon/ControllerInterface/SDL/SDLGamepad.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 namespace ciface::SDL
{ {
@ -40,6 +115,7 @@ private:
Uint32 m_stop_event_type; Uint32 m_stop_event_type;
Uint32 m_populate_event_type; Uint32 m_populate_event_type;
std::thread m_hotplug_thread; std::thread m_hotplug_thread;
UniqueSDLWindow m_keyboard_window{nullptr, SDL_DestroyWindow};
}; };
std::unique_ptr<ciface::InputBackend> CreateInputBackend(ControllerInterface* controller_interface) std::unique_ptr<ciface::InputBackend> CreateInputBackend(ControllerInterface* controller_interface)
@ -155,7 +231,7 @@ InputBackend::InputBackend(ControllerInterface* controller_interface)
return; 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)) if (custom_events_start == static_cast<Uint32>(-1))
{ {
ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to register custom events"); ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to register custom events");
@ -163,6 +239,9 @@ InputBackend::InputBackend(ControllerInterface* controller_interface)
} }
m_stop_event_type = custom_events_start; m_stop_event_type = custom_events_start;
m_populate_event_type = custom_events_start + 1; 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 // 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_ // individual joystick events as well as the custom populate event will be handled _after_
@ -285,6 +364,40 @@ bool InputBackend::HandleEventAndContinue(const SDL_Event& e)
{ {
return false; 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; return true;
} }