ime: implement libIme and shared host overlay

This commit is contained in:
nmzik
2026-08-09 02:58:49 +02:00
parent e3890febaa
commit 37aa6f88b0
10 changed files with 1552 additions and 166 deletions
@@ -1,36 +0,0 @@
#ifndef EMULATOR_SRC_GRAPHICS_PRESENTATION_IMEDIALOGOVERLAY_H_
#define EMULATOR_SRC_GRAPHICS_PRESENTATION_IMEDIALOGOVERLAY_H_
#include "common/common.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include <memory>
union SDL_Event;
namespace Libs::Graphics {
struct GraphicContext;
void InitializeImeDialogInput();
void ShutdownImeDialogInput();
bool ProcessImeDialogInput(const SDL_Event& event);
class ImeDialogOverlay final {
public:
explicit ImeDialogOverlay(GraphicContext& graphics);
~ImeDialogOverlay();
KYTY_CLASS_NO_COPY(ImeDialogOverlay);
[[nodiscard]] bool PrepareFrame(vk::Extent2D extent, vk::Format format, uint32_t image_count);
void Record(vk::CommandBuffer command, vk::ImageView target);
void ReleaseVulkan();
private:
struct Impl;
std::unique_ptr<Impl> m_impl;
};
} // namespace Libs::Graphics
#endif // EMULATOR_SRC_GRAPHICS_PRESENTATION_IMEDIALOGOVERLAY_H_
@@ -1,4 +1,4 @@
#include "graphics/presentation/imeDialogOverlay.h"
#include "graphics/presentation/imeOverlay.h"
#include "SDL.h"
#include "common/assert.h"
@@ -7,6 +7,7 @@
#include "imgui.h"
#include "imgui_impl_vulkan.h"
#include "libs/controller.h"
#include "libs/ime.h"
#include "libs/imeDialog.h"
#include <algorithm>
@@ -26,7 +27,181 @@ namespace Libs::Graphics {
namespace {
namespace Ime = Libs::Dialog::ImeDialog;
namespace CoreIme = Libs::Ime;
namespace DialogIme = Libs::Dialog::ImeDialog;
namespace Ime {
enum class Type : uint32_t { Default = 0, BasicLatin = 1, Url = 2, Mail = 3, Number = 4 };
enum class EnterLabel : uint32_t { Default = 0, Send = 1, Search = 2, Go = 3 };
enum class Alignment : uint32_t { Start = 0, Center = 1, End = 2 };
enum class ExternalAction : uint8_t {
None,
Text,
Backspace,
MoveLeft,
MoveRight,
Cancel,
Accept,
Newline,
};
struct Keycode {
uint16_t keycode = 0;
char16_t character = u'\0';
uint32_t status = 0;
uint32_t type = 0;
int32_t user_id = 0;
uint32_t resource_id = 0;
uint64_t timestamp = 0;
};
struct ExternalInput {
Keycode key;
ExternalAction action = ExternalAction::None;
std::u16string text;
};
struct HostSnapshot {
uint64_t generation = 0;
Type type = Type::Default;
EnterLabel enter_label = EnterLabel::Default;
uint32_t option = 0;
uint32_t max_text_length = 0;
uint32_t cursor = 0;
uint32_t disable_device = 0;
bool key_panel_visible = true;
float posx = 0.0f;
float posy = 0.0f;
Alignment horizontal_alignment = Alignment::Start;
Alignment vertical_alignment = Alignment::Start;
uint32_t panel_width = 0;
uint32_t panel_height = 0;
std::u16string text;
std::u16string title;
std::u16string placeholder;
};
constexpr uint32_t OPTION_MULTILINE = 0x00000001;
constexpr uint32_t OPTION_NO_AUTO_CAPITALIZE = 0x00000002;
constexpr uint32_t OPTION_PASSWORD = 0x00000004;
constexpr uint32_t OPTION_FIXED_POSITION = 0x00000040;
constexpr uint32_t OPTION_DISABLE_POSITION_ADJ = 0x00000800;
constexpr uint32_t OPTION_USE_OVER_2K = 0x00004000;
constexpr uint32_t DISABLE_DEVICE_CONTROLLER = 0x00000001;
constexpr uint32_t DISABLE_DEVICE_EXT_KEYBOARD = 0x00000002;
constexpr uint64_t CORE_GENERATION_BIT = uint64_t {1} << 63;
uint64_t PackCoreGeneration(uint64_t generation) {
return generation | CORE_GENERATION_BIT;
}
bool IsCoreGeneration(uint64_t generation) {
return (generation & CORE_GENERATION_BIT) != 0;
}
uint64_t UnpackGeneration(uint64_t generation) {
return generation & ~CORE_GENERATION_BIT;
}
bool GetHostSnapshot(HostSnapshot* snapshot) {
if (snapshot == nullptr) {
return false;
}
CoreIme::HostSnapshot core;
if (CoreIme::GetHostSnapshot(&core)) {
snapshot->generation = PackCoreGeneration(core.generation);
snapshot->type = static_cast<Type>(core.type);
snapshot->enter_label = static_cast<EnterLabel>(core.enter_label);
snapshot->option = core.option;
snapshot->max_text_length = core.max_text_length;
snapshot->cursor = core.cursor;
snapshot->disable_device = core.disable_device;
snapshot->key_panel_visible = core.key_panel_visible;
snapshot->posx = core.posx;
snapshot->posy = core.posy;
snapshot->horizontal_alignment = static_cast<Alignment>(core.horizontal_alignment);
snapshot->vertical_alignment = static_cast<Alignment>(core.vertical_alignment);
snapshot->panel_width = core.panel_width;
snapshot->panel_height = core.panel_height;
snapshot->text = std::move(core.text);
snapshot->title.clear();
snapshot->placeholder.clear();
return true;
}
DialogIme::HostSnapshot dialog;
if (!DialogIme::GetHostSnapshot(&dialog)) {
return false;
}
snapshot->generation = dialog.generation;
snapshot->type = static_cast<Type>(dialog.type);
snapshot->enter_label = static_cast<EnterLabel>(dialog.enter_label);
snapshot->option = dialog.option;
snapshot->max_text_length = dialog.max_text_length;
snapshot->cursor = dialog.cursor;
snapshot->disable_device = dialog.disable_device;
snapshot->key_panel_visible = dialog.key_panel_visible;
snapshot->posx = dialog.posx;
snapshot->posy = dialog.posy;
snapshot->horizontal_alignment = static_cast<Alignment>(dialog.horizontal_alignment);
snapshot->vertical_alignment = static_cast<Alignment>(dialog.vertical_alignment);
snapshot->panel_width = dialog.panel_width;
snapshot->panel_height = dialog.panel_height;
snapshot->text = std::move(dialog.text);
snapshot->title = std::move(dialog.title);
snapshot->placeholder = std::move(dialog.placeholder);
return true;
}
bool HostInsertText(uint64_t generation, std::u16string_view text) {
return IsCoreGeneration(generation)
? CoreIme::HostInsertText(UnpackGeneration(generation), text)
: DialogIme::HostInsertText(generation, text);
}
bool HostBackspace(uint64_t generation) {
return IsCoreGeneration(generation) ? CoreIme::HostBackspace(UnpackGeneration(generation))
: DialogIme::HostBackspace(generation);
}
bool HostAccept(uint64_t generation) {
return IsCoreGeneration(generation) ? CoreIme::HostAccept(UnpackGeneration(generation))
: DialogIme::HostAccept(generation);
}
bool HostCancel(uint64_t generation) {
return IsCoreGeneration(generation) ? CoreIme::HostCancel(UnpackGeneration(generation))
: DialogIme::HostCancel(generation);
}
bool HostQueueExternalInput(uint64_t generation, ExternalInput input) {
if (!IsCoreGeneration(generation)) {
DialogIme::ExternalInput dialog;
dialog.key.keycode = input.key.keycode;
dialog.key.character = input.key.character;
dialog.key.status = input.key.status;
dialog.key.type = input.key.type;
dialog.key.user_id = input.key.user_id;
dialog.key.resource_id = input.key.resource_id;
dialog.key.timestamp = input.key.timestamp;
dialog.action = static_cast<DialogIme::ExternalAction>(input.action);
dialog.text = std::move(input.text);
return DialogIme::HostQueueExternalInput(generation, std::move(dialog));
}
CoreIme::ExternalInput core;
core.key.keycode = input.key.keycode;
core.key.character = input.key.character;
core.key.status = input.key.status;
core.key.type = input.key.type;
core.key.user_id = input.key.user_id;
core.key.resource_id = input.key.resource_id;
core.key.timestamp = input.key.timestamp;
core.action = static_cast<CoreIme::ExternalAction>(input.action);
core.text = std::move(input.text);
return CoreIme::HostQueueExternalInput(UnpackGeneration(generation), std::move(core));
}
} // namespace Ime
constexpr size_t INPUT_QUEUE_CAPACITY = 128;
@@ -114,28 +289,25 @@ void RetryVisibilityWakeup() {
}
}
void OnVisibilityChanged(bool visible, uint64_t generation) {
void RefreshVisibility() {
std::scoped_lock visibility_lock(g_visibility_mutex);
if (!g_input_lifecycle_active) {
return;
}
if (generation < g_generation || (generation == g_generation && visible == g_active)) {
Ime::HostSnapshot snapshot;
const bool visible = Ime::GetHostSnapshot(&snapshot);
const uint64_t generation = visible ? snapshot.generation : g_generation;
if (visible == g_active && (!visible || generation == g_generation)) {
return;
}
g_generation = generation;
bool capture_controller = false;
bool capture_keyboard = false;
bool multiline = false;
if (visible) {
Ime::HostSnapshot snapshot;
if (Ime::GetHostSnapshot(&snapshot) && snapshot.generation == generation) {
capture_controller = (snapshot.disable_device & Ime::DISABLE_DEVICE_CONTROLLER) == 0;
capture_keyboard = (snapshot.disable_device & Ime::DISABLE_DEVICE_EXT_KEYBOARD) == 0;
multiline = (snapshot.option & Ime::OPTION_MULTILINE) != 0;
} else {
visible = false;
}
capture_controller = (snapshot.disable_device & Ime::DISABLE_DEVICE_CONTROLLER) == 0;
capture_keyboard = (snapshot.disable_device & Ime::DISABLE_DEVICE_EXT_KEYBOARD) == 0;
multiline = (snapshot.option & Ime::OPTION_MULTILINE) != 0;
}
const bool was_controller = std::exchange(g_controller_captured, capture_controller);
if (capture_controller || was_controller) {
@@ -156,6 +328,14 @@ void OnVisibilityChanged(bool visible, uint64_t generation) {
}
}
void OnCoreVisibilityChanged(bool, uint64_t) {
RefreshVisibility();
}
void OnDialogVisibilityChanged(bool, uint64_t) {
RefreshVisibility();
}
uint32_t ExternalKeyStatus(SDL_Keymod modifiers, bool character_valid) {
uint32_t status = 0x00000001 | (character_valid ? 0x00000002 : 0);
if ((modifiers & KMOD_LCTRL) != 0) status |= 0x00000100;
@@ -305,7 +485,7 @@ void CheckVulkanResult(VkResult result) {
} // namespace
void InitializeImeDialogInput() {
void InitializeImeInput() {
const Uint32 type = SDL_RegisterEvents(1);
EXIT_IF(type == static_cast<Uint32>(-1));
{
@@ -313,15 +493,14 @@ void InitializeImeDialogInput() {
g_input_lifecycle_active = true;
g_visibility_event.store(type, std::memory_order_release);
}
Ime::SetVisibilityCallback(OnVisibilityChanged);
Ime::HostSnapshot snapshot;
if (Ime::GetHostSnapshot(&snapshot)) {
OnVisibilityChanged(true, snapshot.generation);
}
CoreIme::SetVisibilityCallback(OnCoreVisibilityChanged);
DialogIme::SetVisibilityCallback(OnDialogVisibilityChanged);
RefreshVisibility();
}
void ShutdownImeDialogInput() {
Ime::SetVisibilityCallback(nullptr);
void ShutdownImeInput() {
CoreIme::SetVisibilityCallback(nullptr);
DialogIme::SetVisibilityCallback(nullptr);
{
std::scoped_lock lock(g_visibility_mutex);
g_input_lifecycle_active = false;
@@ -346,7 +525,13 @@ void ShutdownImeDialogInput() {
}
}
bool ProcessImeDialogInput(const SDL_Event& event) {
ImeVisualState GetImeVisualState() noexcept {
const auto core = CoreIme::GetVisualState();
const auto dialog = DialogIme::GetVisualState();
return {core.active || dialog.active, core.revision + dialog.revision};
}
bool ProcessImeInput(const SDL_Event& event) {
RetryVisibilityWakeup();
if (event.type == g_visibility_event.load(std::memory_order_acquire)) {
VisibilityUpdate update {};
@@ -465,7 +650,7 @@ bool ProcessImeDialogInput(const SDL_Event& event) {
}
}
struct ImeDialogOverlay::Impl {
struct ImeOverlay::Impl {
explicit Impl(GraphicContext& context): graphics(context) {}
~Impl() {
@@ -488,7 +673,7 @@ struct ImeDialogOverlay::Impl {
io.LogFilename = nullptr;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
io.BackendPlatformName = "Kyty ImeDialog input";
io.BackendPlatformName = "Kyty IME input";
ImGui::StyleColorsDark();
auto& style = ImGui::GetStyle();
style.WindowRounding = 10.0f;
@@ -680,7 +865,7 @@ struct ImeDialogOverlay::Impl {
ImGui::SetNextWindowSize({width, height}, ImGuiCond_Always);
constexpr ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoSavedSettings;
ImGui::Begin("##ImeDialog", nullptr, flags);
ImGui::Begin("##Ime", nullptr, flags);
const std::u16string title = snapshot.title.empty() ? u"Enter text" : snapshot.title;
if (!snapshot.key_panel_visible) {
@@ -856,20 +1041,19 @@ struct ImeDialogOverlay::Impl {
std::chrono::steady_clock::time_point last_frame;
};
ImeDialogOverlay::ImeDialogOverlay(GraphicContext& graphics)
: m_impl(std::make_unique<Impl>(graphics)) {}
ImeOverlay::ImeOverlay(GraphicContext& graphics): m_impl(std::make_unique<Impl>(graphics)) {}
ImeDialogOverlay::~ImeDialogOverlay() = default;
ImeOverlay::~ImeOverlay() = default;
bool ImeDialogOverlay::PrepareFrame(vk::Extent2D extent, vk::Format format, uint32_t image_count) {
bool ImeOverlay::PrepareFrame(vk::Extent2D extent, vk::Format format, uint32_t image_count) {
return m_impl->PrepareFrame(extent, format, image_count);
}
void ImeDialogOverlay::Record(vk::CommandBuffer command, vk::ImageView target) {
void ImeOverlay::Record(vk::CommandBuffer command, vk::ImageView target) {
m_impl->Record(command, target);
}
void ImeDialogOverlay::ReleaseVulkan() {
void ImeOverlay::ReleaseVulkan() {
m_impl->ReleaseVulkan();
}
+42
View File
@@ -0,0 +1,42 @@
#ifndef EMULATOR_SRC_GRAPHICS_PRESENTATION_IMEOVERLAY_H_
#define EMULATOR_SRC_GRAPHICS_PRESENTATION_IMEOVERLAY_H_
#include "common/common.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include <memory>
union SDL_Event;
namespace Libs::Graphics {
struct GraphicContext;
struct ImeVisualState {
bool active;
uint64_t revision;
};
void InitializeImeInput();
void ShutdownImeInput();
bool ProcessImeInput(const SDL_Event& event);
ImeVisualState GetImeVisualState() noexcept;
class ImeOverlay final {
public:
explicit ImeOverlay(GraphicContext& graphics);
~ImeOverlay();
KYTY_CLASS_NO_COPY(ImeOverlay);
[[nodiscard]] bool PrepareFrame(vk::Extent2D extent, vk::Format format, uint32_t image_count);
void Record(vk::CommandBuffer command, vk::ImageView target);
void ReleaseVulkan();
private:
struct Impl;
std::unique_ptr<Impl> m_impl;
};
} // namespace Libs::Graphics
#endif // EMULATOR_SRC_GRAPHICS_PRESENTATION_IMEOVERLAY_H_
+15 -16
View File
@@ -31,13 +31,12 @@
#include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/vma.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include "graphics/presentation/imeDialogOverlay.h"
#include "graphics/presentation/imeOverlay.h"
#include "graphics/presentation/presenter.h"
#include "graphics/presentation/renderDoc.h"
#include "graphics/presentation/videoOut.h"
#include "graphics/presentation/window/windowInternal.h"
#include "libs/controller.h"
#include "libs/imeDialog.h"
#include "loader/systemContent.h"
#include <algorithm>
@@ -345,17 +344,17 @@ private:
void Destroy();
void RefreshSurfaceSize();
WindowContext& m_window;
vk::SwapchainKHR m_handle = nullptr;
vk::Format m_format = vk::Format::eUndefined;
vk::Extent2D m_extent {};
std::vector<vk::Image> m_images;
std::vector<vk::ImageView> m_image_views;
std::vector<vk::Semaphore> m_image_acquired;
std::vector<vk::Semaphore> m_render_complete;
std::unique_ptr<ImeDialogOverlay> m_ime_overlay;
uint32_t m_image_index = static_cast<uint32_t>(-1);
uint32_t m_frame_index = 0;
WindowContext& m_window;
vk::SwapchainKHR m_handle = nullptr;
vk::Format m_format = vk::Format::eUndefined;
vk::Extent2D m_extent {};
std::vector<vk::Image> m_images;
std::vector<vk::ImageView> m_image_views;
std::vector<vk::Semaphore> m_image_acquired;
std::vector<vk::Semaphore> m_render_complete;
std::unique_ptr<ImeOverlay> m_ime_overlay;
uint32_t m_image_index = static_cast<uint32_t>(-1);
uint32_t m_frame_index = 0;
};
struct Presenter::Impl {
@@ -618,7 +617,7 @@ Swapchain::Status Swapchain::AcquireNextImage() {
bool Swapchain::PrepareImeOverlay() {
if (m_ime_overlay == nullptr) {
m_ime_overlay = std::make_unique<ImeDialogOverlay>(m_window.graphic_ctx);
m_ime_overlay = std::make_unique<ImeOverlay>(m_window.graphic_ctx);
}
return m_ime_overlay->PrepareFrame(m_extent, m_format, ImageCount());
}
@@ -807,7 +806,7 @@ bool Presenter::IsGuestPaused() const noexcept {
}
bool Presenter::NeedsImeRefresh() const noexcept {
const auto visual = Dialog::ImeDialog::GetVisualState();
const auto visual = GetImeVisualState();
return visual.active ||
visual.revision != m_impl->presented_ime_revision.load(std::memory_order_acquire);
}
@@ -843,7 +842,7 @@ void Presenter::Present(Frame& frame, bool reuse) {
m_impl->RecoverSwapchain(Swapchain::Status::Recreate);
}
const auto ime_visual = Dialog::ImeDialog::GetVisualState();
const auto ime_visual = GetImeVisualState();
auto& swapchain = m_impl->swapchain;
for (uint32_t attempt = 0; attempt < 2; attempt++) {
auto status = swapchain.AcquireNextImage();
@@ -31,7 +31,7 @@
#include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/vma.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include "graphics/presentation/imeDialogOverlay.h"
#include "graphics/presentation/imeOverlay.h"
#include "graphics/presentation/presenter.h"
#include "graphics/presentation/renderDoc.h"
#include "graphics/presentation/videoOut.h"
@@ -1015,7 +1015,7 @@ void WindowContext::RecreateSurface() {
}
WindowContext::~WindowContext() {
ShutdownImeDialogInput();
ShutdownImeInput();
presenter.reset();
LibKernel::Memory::InstallGpuResources(nullptr);
render_context.reset();
+8 -9
View File
@@ -31,7 +31,7 @@
#include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/vma.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include "graphics/presentation/imeDialogOverlay.h"
#include "graphics/presentation/imeOverlay.h"
#include "graphics/presentation/renderDoc.h"
#include "graphics/presentation/window/hostInput.h"
#include "graphics/presentation/window/windowInternal.h"
@@ -477,7 +477,7 @@ void WindowContext::ProcessEvent(double time_s) {
auto& game = loop;
auto* event = &game.event;
EXIT_IF(SDL_GetEventState(SDL_DISPLAYEVENT) != SDL_ENABLE);
if (ProcessImeDialogInput(*event)) {
if (ProcessImeInput(*event)) {
return;
}
@@ -783,7 +783,7 @@ static void WindowCreate(WindowContext& context) {
EXIT("%s\n", SDL_GetError());
}
HostInputInit();
InitializeImeDialogInput();
InitializeImeInput();
LOGF("WindowCreate(): width = %d, height = %d\n", width, height);
@@ -938,7 +938,6 @@ void WindowContext::UpdateTitle() {
static constexpr auto build_type = "Unknown";
#endif
const auto now = Common::Timer::QueryPerformanceCounter();
const auto frequency = Common::Timer::QueryPerformanceFrequency();
frame_num++;
@@ -950,11 +949,11 @@ void WindowContext::UpdateTitle() {
fps_frames = 0;
}
auto fps = fmt::format("[{} | {}] {}{}{}{}{}{}[{}] [{}], frame: {}, fps: {:f}", KYTY_BUILD_LABEL,
build_type, (has_title ? title : ""), (has_title ? ", " : ""),
(has_title_id ? title_id : ""), (has_title_id ? ", " : ""),
(has_app_ver ? app_ver : ""), (has_app_ver ? " " : ""), device_name,
processor_name, frame_num, current_fps);
auto fps = fmt::format(
"[{} | {}] {}{}{}{}{}{}[{}] [{}], frame: {}, fps: {:f}", KYTY_BUILD_LABEL, build_type,
(has_title ? title : ""), (has_title ? ", " : ""), (has_title_id ? title_id : ""),
(has_title_id ? ", " : ""), (has_app_ver ? app_ver : ""), (has_app_ver ? " " : ""),
device_name, processor_name, frame_num, current_fps);
#if defined(__APPLE__)
// AppKit traps on title changes off the main thread; fire-and-forget keeps present pacing.
+1020
View File
File diff suppressed because it is too large Load Diff
+245
View File
@@ -0,0 +1,245 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_LIBS_IME_H_
#define EMULATOR_INCLUDE_EMULATOR_LIBS_IME_H_
#include "common/abi.h"
#include <cstddef>
#include <cstdint>
#include <string>
#include <string_view>
namespace Libs::Ime {
constexpr uint32_t WORK_BUFFER_SIZE = 20 * 1024;
constexpr uint32_t MAX_TEXT_LENGTH = 2048;
enum class Type : uint32_t { Default = 0, BasicLatin = 1, Url = 2, Mail = 3, Number = 4 };
enum class EnterLabel : uint32_t { Default = 0, Send = 1, Search = 2, Go = 3 };
enum class Alignment : uint32_t { Start = 0, Center = 1, End = 2 };
struct Event;
struct Keycode;
using TextFilter = int32_t(KYTY_SYSV_ABI*)(char16_t* out_text, uint32_t* out_text_length,
const char16_t* source_text,
uint32_t source_text_length);
using EventHandler = void(KYTY_SYSV_ABI*)(void* arg, const Event* event);
using ExtKeyboardFilter = int(KYTY_SYSV_ABI*)(const Keycode* source_keycode, uint16_t* out_keycode,
uint32_t* out_status, void* reserved);
struct Color {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
struct Caret {
float x;
float y;
uint32_t height;
uint32_t index;
};
struct TextGeometry {
float x;
float y;
uint32_t width;
uint32_t height;
};
struct Rect {
float x;
float y;
uint32_t width;
uint32_t height;
};
enum class TextAreaMode : uint32_t { Disable = 0, Edit = 1, Preedit = 2, Select = 3 };
struct TextAreaProperty {
TextAreaMode mode;
uint32_t index;
int32_t length;
};
struct EditText {
char16_t* str;
uint32_t caret_index;
uint32_t area_num;
TextAreaProperty text_area[4];
};
struct KeyboardResourceIdArray {
int32_t user_id;
uint32_t resource_id[5];
};
struct Keycode {
uint16_t keycode;
char16_t character;
uint32_t status;
uint32_t type;
int32_t user_id;
uint32_t resource_id;
uint64_t timestamp;
};
union EventParam {
Rect rect;
EditText text;
uint32_t caret_move;
Keycode keycode;
KeyboardResourceIdArray resource_id_array;
uint64_t reserved[8];
};
struct Event {
uint32_t id;
EventParam param;
};
struct Param {
int32_t user_id;
Type type;
uint64_t supported_languages;
EnterLabel enter_label;
uint32_t input_method;
TextFilter filter;
uint32_t option;
uint32_t max_text_length;
char16_t* input_text_buffer;
float posx;
float posy;
Alignment horizontal_alignment;
Alignment vertical_alignment;
void* work;
void* arg;
EventHandler handler;
int8_t reserved[8];
};
struct ExtendedParam {
uint32_t option;
Color color_base;
Color color_line;
Color color_text_field;
Color color_preedit;
Color color_button_default;
Color color_button_function;
Color color_button_symbol;
Color color_text;
Color color_special;
uint32_t priority;
const char* additional_dictionary_path;
ExtKeyboardFilter ext_keyboard_filter;
uint32_t disable_device;
uint32_t ext_keyboard_mode;
int8_t reserved[60];
};
struct KeyboardParam {
uint32_t option;
int8_t reserved1[4];
void* arg;
EventHandler handler;
int8_t reserved2[8];
};
struct KeyboardInfo {
int32_t user_id;
uint32_t device;
uint32_t type;
uint32_t repeat_delay;
uint32_t repeat_rate;
uint32_t status;
int8_t reserved[12];
};
enum class ExternalAction : uint8_t {
None,
Text,
Backspace,
MoveLeft,
MoveRight,
Cancel,
Accept,
Newline,
};
struct ExternalInput {
Keycode key;
ExternalAction action;
std::u16string text;
};
static_assert(sizeof(Caret) == 0x10);
static_assert(sizeof(TextGeometry) == 0x10);
static_assert(sizeof(TextAreaProperty) == 0x0c);
static_assert(sizeof(EditText) == 0x40);
static_assert(sizeof(EventParam) == 0x40);
static_assert(alignof(EventParam) == 0x08);
static_assert(sizeof(Event) == 0x48);
static_assert(offsetof(Event, param) == 0x08);
static_assert(sizeof(Param) == 0x60);
static_assert(offsetof(Param, input_text_buffer) == 0x28);
static_assert(offsetof(Param, work) == 0x40);
static_assert(offsetof(Param, handler) == 0x50);
static_assert(sizeof(ExtendedParam) == 0x88);
static_assert(offsetof(ExtendedParam, additional_dictionary_path) == 0x30);
static_assert(sizeof(KeyboardParam) == 0x20);
static_assert(sizeof(KeyboardResourceIdArray) == 0x18);
static_assert(sizeof(KeyboardInfo) == 0x24);
static_assert(sizeof(Keycode) == 0x20);
struct VisualState {
bool active;
uint64_t revision;
};
struct HostSnapshot {
uint64_t generation;
Type type;
EnterLabel enter_label;
uint32_t option;
uint32_t max_text_length;
uint32_t cursor;
uint32_t disable_device;
bool key_panel_visible;
float posx;
float posy;
Alignment horizontal_alignment;
Alignment vertical_alignment;
uint32_t panel_width;
uint32_t panel_height;
std::u16string text;
};
using VisibilityCallback = void (*)(bool visible, uint64_t generation);
void KYTY_SYSV_ABI ImeParamInit(Param* param);
int KYTY_SYSV_ABI ImeGetPanelSize(const Param* param, uint32_t* width, uint32_t* height);
int KYTY_SYSV_ABI ImeOpen(const Param* param, const ExtendedParam* extended);
int KYTY_SYSV_ABI ImeUpdate(EventHandler handler);
int KYTY_SYSV_ABI ImeClose();
int KYTY_SYSV_ABI ImeSetText(const char16_t* text, uint32_t length);
int KYTY_SYSV_ABI ImeSetCaret(const Caret* caret);
int KYTY_SYSV_ABI ImeSetTextGeometry(TextAreaMode mode, const TextGeometry* geometry);
int KYTY_SYSV_ABI ImeKeyboardOpen(int32_t user_id, const KeyboardParam* param);
int KYTY_SYSV_ABI ImeKeyboardClose(int32_t user_id);
int KYTY_SYSV_ABI ImeKeyboardGetResourceId(int32_t user_id, KeyboardResourceIdArray* resource_ids);
int KYTY_SYSV_ABI ImeKeyboardGetInfo(uint32_t resource_id, KeyboardInfo* info);
int KYTY_SYSV_ABI ImeKeyboardSetMode(int32_t user_id, uint32_t mode);
VisualState GetVisualState() noexcept;
void SetVisibilityCallback(VisibilityCallback callback) noexcept;
bool GetHostSnapshot(HostSnapshot* snapshot);
bool HostInsertText(uint64_t generation, std::u16string_view text);
bool HostBackspace(uint64_t generation);
bool HostAccept(uint64_t generation);
bool HostCancel(uint64_t generation);
bool HostQueueExternalInput(uint64_t generation, ExternalInput input);
} // namespace Libs::Ime
#endif // EMULATOR_INCLUDE_EMULATOR_LIBS_IME_H_
-72
View File
@@ -3804,77 +3804,6 @@ LIB_DEFINE(InitPlatform_1_Random) {
} // namespace LibRandom
namespace LibIme {
LIB_VERSION("Ime", 1, "Ime", 1, 1);
static int KYTY_SYSV_ABI ImeKeyboardOpen(int user_id, const void* param) {
PRINT_NAME();
LOGF("\t user_id = %d\n"
"\t param = 0x%016" PRIx64 "\n",
user_id, reinterpret_cast<uint64_t>(param));
return 0;
}
static int KYTY_SYSV_ABI ImeKeyboardClose(int user_id) {
PRINT_NAME();
LOGF("\t user_id = %d\n", user_id);
return 0;
}
static int KYTY_SYSV_ABI ImeKeyboardGetResourceId(int user_id, void* resource_id_array) {
PRINT_NAME();
LOGF("\t user_id = %d\n"
"\t resource_id_array = 0x%016" PRIx64 "\n",
user_id, reinterpret_cast<uint64_t>(resource_id_array));
return 0;
}
static int KYTY_SYSV_ABI ImeKeyboardGetInfo(uint32_t resource_id, void* info) {
PRINT_NAME();
LOGF("\t resource_id = 0x%08" PRIx32 "\n"
"\t info = 0x%016" PRIx64 "\n",
resource_id, reinterpret_cast<uint64_t>(info));
return 0;
}
static int KYTY_SYSV_ABI ImeKeyboardSetMode(int user_id, uint32_t mode) {
PRINT_NAME();
LOGF("\t user_id = %d\n"
"\t mode = 0x%08" PRIx32 "\n",
user_id, mode);
return 0;
}
static int KYTY_SYSV_ABI ImeUpdate(void* handler) {
PRINT_NAME();
// LOGF("\t handler = 0x%016" PRIx64 "\n", reinterpret_cast<uint64_t>(handler));
return 0;
}
LIB_DEFINE(InitPlatform_1_Ime) {
LIB_FUNC("eaFXjfJv3xs", LibIme::ImeKeyboardOpen);
LIB_FUNC("PMVehSlfZ94", LibIme::ImeKeyboardClose);
LIB_FUNC("dKadqZFgKKQ", LibIme::ImeKeyboardGetResourceId);
LIB_FUNC("VkqLPArfFdc", LibIme::ImeKeyboardGetInfo);
LIB_FUNC("ua+13Hk9kKs", LibIme::ImeKeyboardSetMode);
LIB_FUNC("-4GCfYdNF1s", LibIme::ImeUpdate);
}
} // namespace LibIme
namespace LibRemoteplay {
LIB_VERSION("Remoteplay", 1, "Remoteplay", 1, 1);
@@ -3994,7 +3923,6 @@ LIB_DEFINE(InitPlatform_1_SharePlay) {
LIB_DEFINE(InitPlatform_1) {
LibRandom::InitPlatform_1_Random(s);
LibIme::InitPlatform_1_Ime(s);
LibRemoteplay::InitPlatform_1_Remoteplay(s);
LibWebBrowserDialog::InitPlatform_1_WebBrowserDialog(s);
LibGameLiveStreaming::InitPlatform_1_GameLiveStreaming(s);
+5
View File
@@ -34,6 +34,10 @@ namespace LibKeyboard {
LIB_DEFINE(InitKeyboard_1);
} // namespace LibKeyboard
namespace Ime {
LIB_DEFINE(InitPlatform_1_Ime);
} // namespace Ime
namespace LibUlt {
LIB_DEFINE(InitUlt_1);
} // namespace LibUlt
@@ -89,6 +93,7 @@ void InitAll(Loader::SymbolDatabase* s) {
LIB_LOAD(InitLibKernel_1);
LIB_LOAD(LibMouse::InitMouse_1);
LIB_LOAD(LibKeyboard::InitKeyboard_1);
LIB_LOAD(Ime::InitPlatform_1_Ime);
LIB_LOAD(InitNet_1);
LIB_LOAD(InitPad_1);
LIB_LOAD(InitPlayGo_1);