mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-08-18 22:42:23 +00:00
ime: implement libIme and shared host overlay
This commit is contained in:
@@ -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_
|
||||
+215
-31
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
@@ -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();
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+245
@@ -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_
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user