refactor(subsystems&ime): RAII lifecycle

This commit is contained in:
nmzik
2026-08-11 14:53:16 +02:00
parent 34cf130e4d
commit 4980efa9b7
43 changed files with 816 additions and 1256 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ static std::string BuildFatalReport(const char* title, std::string_view text, co
static int DbgReport(const char* title, std::string_view text, const char* file, int line) { static int DbgReport(const char* title, std::string_view text, const char* file, int line) {
Log::WriteFatal(BuildFatalReport(title, text, file, line)); Log::WriteFatal(BuildFatalReport(title, text, file, line));
SubsystemsListSingleton::Instance()->ShutdownAll(); Subsystems::EmergencyShutdownActive();
return 1; return 1;
} }
-21
View File
@@ -1,21 +0,0 @@
#include "common/commonSubsystem.h"
#include "common/byteBuffer.h" // IWYU pragma: associated
#include "common/common.h" // IWYU pragma: associated
#include "common/debug.h" // IWYU pragma: associated
#include "common/hash.h" // IWYU pragma: associated
#include "common/magicEnum.h" // IWYU pragma: associated
#include "common/singleton.h" // IWYU pragma: associated
#include "common/virtualMemory.h"
namespace Common {
KYTY_SUBSYSTEM_INIT(Common) {
VirtualMemory::Init();
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Common) {}
KYTY_SUBSYSTEM_DESTROY(Common) {}
} // namespace Common
-12
View File
@@ -1,12 +0,0 @@
#ifndef KYTY_COMMON_COMMON_SUBSYSTEM_H_
#define KYTY_COMMON_COMMON_SUBSYSTEM_H_
#include "common/subsystems.h"
namespace Common {
KYTY_SUBSYSTEM_DEFINE(Common);
} // namespace Common
#endif /* KYTY_COMMON_COMMON_SUBSYSTEM_H_ */
+4 -4
View File
@@ -9,15 +9,15 @@ namespace Config {
static std::unique_ptr<ConfigOptions> g_config; static std::unique_ptr<ConfigOptions> g_config;
KYTY_SUBSYSTEM_INIT(Config) { void Initialize() {
EXIT_IF(g_config != nullptr); EXIT_IF(g_config != nullptr);
g_config = std::make_unique<ConfigOptions>(); g_config = std::make_unique<ConfigOptions>();
} }
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Config) {} void Shutdown() {
g_config.reset();
KYTY_SUBSYSTEM_DESTROY(Config) {} }
void Load(const ConfigOptions& cfg) { void Load(const ConfigOptions& cfg) {
EXIT_IF(g_config == nullptr); EXIT_IF(g_config == nullptr);
+8 -2
View File
@@ -2,7 +2,6 @@
#define KYTY_COMMON_EMULATOR_CONFIG_H_ #define KYTY_COMMON_EMULATOR_CONFIG_H_
#include "common/common.h" #include "common/common.h"
#include "common/subsystems.h"
#include <filesystem> #include <filesystem>
#include <string> #include <string>
@@ -10,7 +9,14 @@
namespace Config { namespace Config {
KYTY_SUBSYSTEM_DEFINE(Config); void Initialize();
void Shutdown();
struct Lifecycle {
static constexpr const char* name = "Config";
static constexpr auto initialize = Config::Initialize;
static constexpr auto shutdown = Config::Shutdown;
};
enum class ShaderOptimizationType { None, Size, Performance }; enum class ShaderOptimizationType { None, Size, Performance };
+2 -8
View File
@@ -149,7 +149,7 @@ void WriteFatal(fmt::text_style style, std::string_view text) {
Flush(); Flush();
} }
KYTY_SUBSYSTEM_INIT(Log) { void Initialize() {
g_initialized = true; g_initialized = true;
switch (Config::GetPrintfDirection()) { switch (Config::GetPrintfDirection()) {
case Config::OutputDirection::Silent: g_direction = Direction::Silent; break; case Config::OutputDirection::Silent: g_direction = Direction::Silent; break;
@@ -161,13 +161,7 @@ KYTY_SUBSYSTEM_INIT(Log) {
SetupLogger(); SetupLogger();
} }
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Log) { void Shutdown() {
Flush();
std::lock_guard lock(g_logger_mutex);
g_logger.reset();
}
KYTY_SUBSYSTEM_DESTROY(Log) {
Flush(); Flush();
std::lock_guard lock(g_logger_mutex); std::lock_guard lock(g_logger_mutex);
g_logger.reset(); g_logger.reset();
+9 -2
View File
@@ -2,7 +2,6 @@
#define KYTY_COMMON_LOGGING_LOG_H_ #define KYTY_COMMON_LOGGING_LOG_H_
#include "common/common.h" #include "common/common.h"
#include "common/subsystems.h"
#include <fmt/color.h> #include <fmt/color.h>
#include <fmt/printf.h> #include <fmt/printf.h>
@@ -10,7 +9,15 @@
namespace Log { namespace Log {
KYTY_SUBSYSTEM_DEFINE(Log); void Initialize();
void Shutdown();
struct Lifecycle {
static constexpr const char* name = "Log";
static constexpr auto initialize = Log::Initialize;
static constexpr auto shutdown = Log::Shutdown;
static constexpr auto emergency_shutdown = Log::Shutdown;
};
enum class Direction { Silent, Console, File }; enum class Direction { Silent, Console, File };
+5 -14
View File
@@ -1,7 +1,6 @@
#include "common/profiler.h" #include "common/profiler.h"
#include "common/emulatorConfig.h" #include "common/emulatorConfig.h"
#include "common/subsystems.h"
#include <algorithm> #include <algorithm>
#include <common/TracyProtocol.hpp> #include <common/TracyProtocol.hpp>
@@ -55,13 +54,7 @@ void SetThreadName(const char* name) {
} }
} }
void Close() { void Initialize() {
if (tracy::ProfilerAvailable()) {
tracy::ShutdownProfiler();
}
}
KYTY_SUBSYSTEM_INIT(Profiler) {
switch (Config::GetProfilerDirection()) { switch (Config::GetProfilerDirection()) {
case Config::ProfilerDirection::Network: case Config::ProfilerDirection::Network:
if (!tracy::ProfilerAvailable()) { if (!tracy::ProfilerAvailable()) {
@@ -78,12 +71,10 @@ KYTY_SUBSYSTEM_INIT(Profiler) {
} }
} }
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Profiler) { void Shutdown() {
Close(); if (tracy::ProfilerAvailable()) {
} tracy::ShutdownProfiler();
}
KYTY_SUBSYSTEM_DESTROY(Profiler) {
Close();
} }
} // namespace Profiler } // namespace Profiler
+9 -2
View File
@@ -2,7 +2,6 @@
#define KYTY_COMMON_PROFILER_H_ #define KYTY_COMMON_PROFILER_H_
#include "common/common.h" #include "common/common.h"
#include "common/subsystems.h"
#include <cstdint> #include <cstdint>
#include <optional> #include <optional>
@@ -42,7 +41,15 @@ private:
void EndBlock(); void EndBlock();
void SetThreadName(const char* name); void SetThreadName(const char* name);
KYTY_SUBSYSTEM_DEFINE(Profiler); void Initialize();
void Shutdown();
struct Lifecycle {
static constexpr const char* name = "Profiler";
static constexpr auto initialize = Profiler::Initialize;
static constexpr auto shutdown = Profiler::Shutdown;
static constexpr auto emergency_shutdown = Profiler::Shutdown;
};
} // namespace Profiler } // namespace Profiler
+25 -214
View File
@@ -1,232 +1,43 @@
#include "common/subsystems.h" #include "common/subsystems.h"
#include "common/assert.h"
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <memory>
#include <string>
namespace Common { namespace Common {
class SubsystemPrivate { static Subsystems* g_active_subsystems = nullptr;
public:
SubsystemPrivate() = default;
virtual ~SubsystemPrivate() = default;
KYTY_CLASS_NO_COPY(SubsystemPrivate); Subsystems::Subsystems(bool print): m_print(print) {
m_active.reserve(16);
g_active_subsystems = this;
}
bool failed {false}; Subsystems::~Subsystems() {
std::string fail_msg; Destroy();
}; if (g_active_subsystems == this) {
g_active_subsystems = nullptr;
class SubsystemsListPrivate {
public:
explicit SubsystemsListPrivate(SubsystemsList& p): parent(p) {}
virtual ~SubsystemsListPrivate() = default;
void SetArgs(int argc, char** argv) {
this->m_argc = argc;
this->m_argv = argv;
} }
}
void Add(Subsystem* s, std::initializer_list<Subsystem*> deps) { void Subsystems::Destroy() {
EXIT_IF(!s); for (auto it = m_active.rbegin(); it != m_active.rend(); ++it) {
if (it->shutdown != nullptr) {
const char* name = s->Id(); it->shutdown();
EXIT_IF(FindByName(name) != nullptr);
auto nl = std::make_unique<SubsListStruct>();
nl->s = s;
nl->name = name;
nl->deps = nullptr;
nl->next = std::move(list);
nl->prev_init = nullptr;
auto* node = nl.get();
list = std::move(nl);
for (auto* dep: deps) {
const char* str = dep->Id();
auto l = std::make_unique<DepsListStruct>();
l->dep_name = str;
l->next = std::move(node->deps);
node->deps = std::move(l);
} }
node->initialized = false;
} }
m_active.clear();
}
bool InitAll(bool print_msg) { void Subsystems::EmergencyShutdown() {
while (SubsListStruct* n = FindNextToInitialize()) { for (auto it = m_active.rbegin(); it != m_active.rend(); ++it) {
n->s->Init(&parent); if (it->emergency_shutdown != nullptr) {
it->emergency_shutdown();
if (n->s->m_p->failed) {
fail_msg = n->s->m_p->fail_msg.c_str();
fail_name = n->name;
return false;
}
if (print_msg) {
printf("Initialized: %s\n", n->name);
}
n->initialized = true;
SubsListStruct* last = last_init;
last_init = n;
n->prev_init = last;
} }
return true;
} }
m_active.clear();
}
void DestroyAll(bool print_msg) { void Subsystems::EmergencyShutdownActive() {
for (SubsListStruct* n = last_init; n != nullptr; n = n->prev_init) { if (g_active_subsystems != nullptr) {
n->s->Destroy(&parent); g_active_subsystems->EmergencyShutdown();
n->initialized = false;
if (print_msg) {
printf("Destroyed: %s\n", n->name);
}
}
last_init = nullptr;
} }
void ShutdownAll() {
for (SubsListStruct* n = last_init; n != nullptr; n = n->prev_init) {
n->s->UnexpectedShutdown(&parent);
n->initialized = false;
}
last_init = nullptr;
}
struct DepsListStruct {
const char* dep_name;
std::unique_ptr<DepsListStruct> next;
};
struct SubsListStruct {
Subsystem* s;
const char* name;
std::unique_ptr<DepsListStruct> deps;
std::unique_ptr<SubsListStruct> next;
SubsListStruct* prev_init;
bool initialized;
};
[[nodiscard]] SubsListStruct* FindByName(const char* name) const {
for (SubsListStruct* n = list.get(); n != nullptr; n = n->next.get()) {
if (std::strcmp(n->name, name) == 0) {
return n;
}
}
return nullptr;
}
[[nodiscard]] SubsListStruct* FindNextToInitialize() const {
for (SubsListStruct* n = list.get(); n != nullptr; n = n->next.get()) {
if (n->initialized) {
continue;
}
DepsListStruct* d = n->deps.get();
for (; d != nullptr; d = d->next.get()) {
SubsListStruct* s = FindByName(d->dep_name);
if ((s == nullptr) || !s->initialized) {
break;
}
}
if (d == nullptr) {
return n;
}
}
return nullptr;
}
KYTY_CLASS_NO_COPY(SubsystemsListPrivate);
std::unique_ptr<SubsListStruct> list;
SubsListStruct* last_init = nullptr;
int m_argc = 0;
char** m_argv = nullptr;
const char* fail_msg = nullptr;
const char* fail_name = nullptr;
SubsystemsList& parent;
};
SubsystemsList::SubsystemsList(): m_p(std::make_unique<SubsystemsListPrivate>(*this)) {}
SubsystemsList::~SubsystemsList() = default;
void SubsystemsList::Add(Subsystem* s, std::initializer_list<Subsystem*> deps) {
m_p->Add(s, deps);
}
bool SubsystemsList::InitAll(bool print_msg) {
return m_p->InitAll(print_msg);
}
void SubsystemsList::DestroyAll(bool print_msg) {
m_p->DestroyAll(print_msg);
}
int* SubsystemsList::GetArgc() {
return &m_p->m_argc;
}
char** SubsystemsList::GetArgv() {
return m_p->m_argv;
}
Subsystem::Subsystem(): m_p(std::make_unique<SubsystemPrivate>()) {}
Subsystem::~Subsystem() = default;
void Subsystem::Fail(const char* format, ...) {
va_list args {};
va_start(args, format);
va_list args_copy {};
va_copy(args_copy, args);
int len = std::vsnprintf(nullptr, 0, format, args_copy);
va_end(args_copy);
if (len > 0) {
std::string msg(static_cast<size_t>(len) + 1, '\0');
std::vsnprintf(msg.data(), msg.size(), format, args);
m_p->fail_msg = msg.c_str();
m_p->failed = true;
}
va_end(args);
}
const char* SubsystemsList::GetFailName() const {
return m_p->fail_name;
}
const char* SubsystemsList::GetFailMsg() const {
return m_p->fail_msg;
}
void SubsystemsList::SetArgs(int argc, char* argv[]) {
m_p->SetArgs(argc, argv);
}
void SubsystemsList::ShutdownAll() {
m_p->ShutdownAll();
} }
} // namespace Common } // namespace Common
+41 -70
View File
@@ -2,90 +2,61 @@
#define KYTY_COMMON_SUBSYSTEMS_H_ #define KYTY_COMMON_SUBSYSTEMS_H_
#include "common/common.h" #include "common/common.h"
#include "common/singleton.h"
#include <initializer_list> #include <cstdio>
#include <memory> #include <vector>
namespace Common { namespace Common {
class Subsystem; class Subsystems {
class SubsystemsListPrivate;
class SubsystemPrivate;
class SubsystemsList {
public: public:
SubsystemsList(); using Callback = void (*)();
virtual ~SubsystemsList();
void SetArgs(int argc, char* argv[]);
// void Add(Subsystem* s, const char* name, ...); explicit Subsystems(bool print = false);
void Add(Subsystem* s, std::initializer_list<Subsystem*> deps); ~Subsystems();
bool InitAll(bool print_msg = false); template <typename Lifecycle>
void DestroyAll(bool print_msg = false); void Initialize() {
Lifecycle::initialize();
m_active.push_back({ShutdownCallback<Lifecycle>(), EmergencyCallback<Lifecycle>()});
if (m_print) {
std::printf("Initialized: %s\n", Lifecycle::name);
}
}
int* GetArgc(); void Destroy();
char** GetArgv(); void EmergencyShutdown();
[[nodiscard]] const char* GetFailName() const; static void EmergencyShutdownActive();
[[nodiscard]] const char* GetFailMsg() const;
void ShutdownAll(); KYTY_CLASS_NO_COPY(Subsystems);
static SubsystemsList* Instance() { return Common::Singleton<SubsystemsList>::Instance(); }
KYTY_CLASS_NO_COPY(SubsystemsList);
private: private:
std::unique_ptr<SubsystemsListPrivate> m_p; template <typename Lifecycle>
static consteval Callback ShutdownCallback() {
if constexpr (requires { Lifecycle::shutdown; }) {
return Lifecycle::shutdown;
}
return nullptr;
}
template <typename Lifecycle>
static consteval Callback EmergencyCallback() {
if constexpr (requires { Lifecycle::emergency_shutdown; }) {
return Lifecycle::emergency_shutdown;
}
return nullptr;
}
struct Entry {
Callback shutdown;
Callback emergency_shutdown;
};
std::vector<Entry> m_active;
bool m_print;
}; };
using SubsystemsListSingleton = Common::Singleton<SubsystemsList>;
class Subsystem {
public:
Subsystem();
virtual ~Subsystem();
virtual const char* Id() = 0;
virtual void Init(SubsystemsList* parent) = 0;
virtual void Destroy(SubsystemsList* parent) = 0;
virtual void UnexpectedShutdown(SubsystemsList* parent) = 0;
friend class SubsystemsListPrivate;
KYTY_CLASS_NO_COPY(Subsystem);
protected:
void Fail(const char* format, ...) KYTY_FORMAT_PRINTF(2, 3);
private:
std::unique_ptr<SubsystemPrivate> m_p;
};
#define KYTY_SUBSYSTEM_DEFINE(s) \
class s##Subsystem: public Common::Subsystem { \
public: \
static Subsystem* Instance() { return Common::Singleton<s##Subsystem>::Instance(); } \
const char* Id() { return #s; } \
void Init(Common::SubsystemsList* parent); \
void Destroy(Common::SubsystemsList* parent); \
void UnexpectedShutdown(Common::SubsystemsList* parent); \
}; \
typedef Common::Singleton<s##Subsystem> s##SubsystemSingleton;
#define KYTY_SUBSYSTEM_INIT(s) \
void s##Subsystem::Init([[maybe_unused]] Common::SubsystemsList* parent)
#define KYTY_SUBSYSTEM_DESTROY(s) \
void s##Subsystem::Destroy([[maybe_unused]] Common::SubsystemsList* parent)
#define KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(s) \
void s##Subsystem::UnexpectedShutdown([[maybe_unused]] Common::SubsystemsList* parent)
// #define KYTY_SUBSYSTEM_ADD(list, s, ...) list.push_back(s##SubsystemSingleton::Instance(), #s,
// __VA_ARGS__); #define KYTY_SUBSYSTEM_ADD2(list, ...) list.Add2(s##SubsystemSingleton::Instance(),
// __VA_ARGS__);
} // namespace Common } // namespace Common
#endif /* KYTY_COMMON_SUBSYSTEMS_H_ */ #endif /* KYTY_COMMON_SUBSYSTEMS_H_ */
+1 -5
View File
@@ -252,15 +252,11 @@ static thread_id_t g_main_thread;
static int g_main_thread_int; static int g_main_thread_int;
static std::atomic<int> g_thread_counter = 0; static std::atomic<int> g_thread_counter = 0;
KYTY_SUBSYSTEM_INIT(Threads) { void InitializeThreads() {
g_main_thread = std::this_thread::get_id(); g_main_thread = std::this_thread::get_id();
g_main_thread_int = Thread::GetThreadIdUnique(); g_main_thread_int = Thread::GetThreadIdUnique();
} }
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Threads) {}
KYTY_SUBSYSTEM_DESTROY(Threads) {}
Thread::Thread(thread_func_t func, void* arg) Thread::Thread(thread_func_t func, void* arg)
: m_thread(std::make_unique<ThreadPrivate>(func, arg)) { : m_thread(std::make_unique<ThreadPrivate>(func, arg)) {
while (!m_thread->started) { while (!m_thread->started) {
+1 -2
View File
@@ -2,14 +2,13 @@
#define KYTY_COMMON_THREADS_H_ #define KYTY_COMMON_THREADS_H_
#include "common/common.h" #include "common/common.h"
#include "common/subsystems.h"
#include <memory> #include <memory>
#include <string> #include <string>
namespace Common { namespace Common {
KYTY_SUBSYSTEM_DEFINE(Threads); void InitializeThreads();
using thread_func_t = void (*)(void*); using thread_func_t = void (*)(void*);
using wait_poll_func_t = void (*)(); using wait_poll_func_t = void (*)();
+18 -36
View File
@@ -2,7 +2,6 @@
#include "common/abi.h" #include "common/abi.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/commonSubsystem.h"
#include "common/emulatorConfig.h" #include "common/emulatorConfig.h"
#include "common/file.h" #include "common/file.h"
#include "common/logging/log.h" #include "common/logging/log.h"
@@ -43,7 +42,7 @@ static void KytyClose() {
LOGF("done!\n"); LOGF("done!\n");
Common::SubsystemsListSingleton::Instance()->ShutdownAll(); Common::Subsystems::EmergencyShutdownActive();
} }
static void MountOrCreateDir(const std::filesystem::path& dir, const std::string& point) { static void MountOrCreateDir(const std::filesystem::path& dir, const std::string& point) {
@@ -105,30 +104,13 @@ static void ClearDebugTextureFolder() {
} }
} }
static void Init(const Config::ConfigOptions& cfg, const std::filesystem::path& param_json) { static void Init(const Config::ConfigOptions& cfg, const std::filesystem::path& param_json,
Common::Subsystems& subsystems) {
EXIT_IF(!Common::Thread::IsMainThread()); EXIT_IF(!Common::Thread::IsMainThread());
auto* slist = Common::SubsystemsList::Instance(); subsystems.Initialize<Config::Lifecycle>();
auto* audio = Libs::Audio::AudioSubsystem::Instance();
auto* config = Config::ConfigSubsystem::Instance();
auto* controller = Libs::Controller::ControllerSubsystem::Instance();
auto* core = Common::CommonSubsystem::Instance();
auto* file_system = Libs::LibKernel::FileSystem::FileSystemSubsystem::Instance();
auto* graphics = Libs::Graphics::GraphicsSubsystem::Instance();
auto* log = Log::LogSubsystem::Instance();
auto* memory = Libs::LibKernel::Memory::MemorySubsystem::Instance();
auto* network = Libs::Network::NetworkSubsystem::Instance();
auto* profiler = Profiler::ProfilerSubsystem::Instance();
auto* pthread = Libs::LibKernel::PthreadSubsystem::Instance();
auto* timer = Loader::Timer::TimerSubsystem::Instance();
slist->Add(config, {core});
slist->InitAll(true);
Config::Load(cfg); Config::Load(cfg);
slist->Add(log, {core, config}); subsystems.Initialize<Log::Lifecycle>();
slist->InitAll(true);
if (Common::File::IsFileExisting(param_json)) { if (Common::File::IsFileExisting(param_json)) {
Loader::SystemContentLoadParamSfo(param_json); Loader::SystemContentLoadParamSfo(param_json);
@@ -138,17 +120,16 @@ static void Init(const Config::ConfigOptions& cfg, const std::filesystem::path&
} }
} }
slist->Add(audio, {core, log, pthread, memory}); // Initialization order is explicit; destruction is automatic and reversed.
slist->Add(controller, {core, log, config}); subsystems.Initialize<Loader::Timer::Lifecycle>();
slist->Add(file_system, {core, log, pthread}); subsystems.Initialize<Libs::LibKernel::PthreadLifecycle>();
slist->Add(graphics, {core, log, pthread, memory, config, profiler, controller}); subsystems.Initialize<Profiler::Lifecycle>();
slist->Add(memory, {core, log}); subsystems.Initialize<Libs::Network::Lifecycle>();
slist->Add(network, {core, log, pthread}); subsystems.Initialize<Libs::LibKernel::Memory::Lifecycle>();
slist->Add(profiler, {core, config}); subsystems.Initialize<Libs::LibKernel::FileSystem::Lifecycle>();
slist->Add(pthread, {core, log, timer}); subsystems.Initialize<Libs::Controller::Lifecycle>();
slist->Add(timer, {core, log}); subsystems.Initialize<Libs::Audio::Lifecycle>();
subsystems.Initialize<Libs::Graphics::Lifecycle>();
slist->InitAll(true);
} }
static void LoadElf(const std::filesystem::path& elf, bool dbg_print_reloc = false, static void LoadElf(const std::filesystem::path& elf, bool dbg_print_reloc = false,
@@ -189,8 +170,9 @@ void Run(const RunOptions& options) {
EXIT("ELF is required\n"); EXIT("ELF is required\n");
} }
const auto param_json = options.app0_dir / "sce_sys" / "param.json"; const auto param_json = options.app0_dir / "sce_sys" / "param.json";
Init(options.config, param_json); Common::Subsystems subsystems(true);
Init(options.config, param_json, subsystems);
ClearDebugTextureFolder(); ClearDebugTextureFolder();
+20 -122
View File
@@ -32,64 +32,21 @@ namespace DialogIme = Libs::Dialog::ImeDialog;
namespace Ime { namespace Ime {
enum class Type : uint32_t { Default = 0, BasicLatin = 1, Url = 2, Mail = 3, Number = 4 }; using Type = ImeCommon::Type;
enum class EnterLabel : uint32_t { Default = 0, Send = 1, Search = 2, Go = 3 }; using EnterLabel = ImeCommon::EnterLabel;
enum class Alignment : uint32_t { Start = 0, Center = 1, End = 2 }; using Alignment = ImeCommon::Alignment;
enum class ExternalAction : uint8_t { using ExternalAction = ImeCommon::ExternalAction;
None, using ExternalInput = ImeCommon::ExternalInput;
Text, using HostSnapshot = ImeCommon::HostSnapshot;
Backspace,
MoveLeft,
MoveRight,
Cancel,
Accept,
Newline,
};
struct Keycode { constexpr uint32_t OPTION_MULTILINE = ImeCommon::OPTION_MULTILINE;
uint16_t keycode = 0; constexpr uint32_t OPTION_NO_AUTO_CAPITALIZE = ImeCommon::OPTION_NO_AUTO_CAPITALIZE;
char16_t character = u'\0'; constexpr uint32_t OPTION_PASSWORD = ImeCommon::OPTION_PASSWORD;
uint32_t status = 0; constexpr uint32_t OPTION_FIXED_POSITION = ImeCommon::OPTION_FIXED_POSITION;
uint32_t type = 0; constexpr uint32_t OPTION_DISABLE_POSITION_ADJ = ImeCommon::OPTION_DISABLE_POSITION_ADJUST;
int32_t user_id = 0; constexpr uint32_t OPTION_USE_OVER_2K = ImeCommon::OPTION_USE_OVER_2K;
uint32_t resource_id = 0; constexpr uint32_t DISABLE_DEVICE_CONTROLLER = ImeCommon::DISABLE_DEVICE_CONTROLLER;
uint64_t timestamp = 0; constexpr uint32_t DISABLE_DEVICE_EXT_KEYBOARD = ImeCommon::DISABLE_DEVICE_EXT_KEYBOARD;
};
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; constexpr uint64_t CORE_GENERATION_BIT = uint64_t {1} << 63;
uint64_t PackCoreGeneration(uint64_t generation) { uint64_t PackCoreGeneration(uint64_t generation) {
@@ -108,49 +65,11 @@ bool GetHostSnapshot(HostSnapshot* snapshot) {
if (snapshot == nullptr) { if (snapshot == nullptr) {
return false; return false;
} }
CoreIme::HostSnapshot core; if (CoreIme::GetHostSnapshot(snapshot)) {
if (CoreIme::GetHostSnapshot(&core)) { snapshot->generation = PackCoreGeneration(snapshot->generation);
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; return true;
} }
DialogIme::HostSnapshot dialog; return DialogIme::GetHostSnapshot(snapshot);
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) { bool HostInsertText(uint64_t generation, std::u16string_view text) {
@@ -175,30 +94,9 @@ bool HostCancel(uint64_t generation) {
} }
bool HostQueueExternalInput(uint64_t generation, ExternalInput input) { bool HostQueueExternalInput(uint64_t generation, ExternalInput input) {
if (!IsCoreGeneration(generation)) { return IsCoreGeneration(generation)
DialogIme::ExternalInput dialog; ? CoreIme::HostQueueExternalInput(UnpackGeneration(generation), std::move(input))
dialog.key.keycode = input.key.keycode; : DialogIme::HostQueueExternalInput(generation, std::move(input));
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 } // namespace Ime
@@ -22,7 +22,6 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/profiler.h" #include "common/profiler.h"
#include "common/stringUtils.h" #include "common/stringUtils.h"
#include "common/subsystems.h"
#include "common/systemInfo.h" #include "common/systemInfo.h"
#include "common/threads.h" #include "common/threads.h"
#include "common/timer.h" #include "common/timer.h"
@@ -22,7 +22,6 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/profiler.h" #include "common/profiler.h"
#include "common/stringUtils.h" #include "common/stringUtils.h"
#include "common/subsystems.h"
#include "common/systemInfo.h" #include "common/systemInfo.h"
#include "common/threads.h" #include "common/threads.h"
#include "common/timer.h" #include "common/timer.h"
+8 -6
View File
@@ -337,21 +337,23 @@ std::filesystem::path MountPoints::GetRealDirectory(const std::string& mounted_d
return mounted_directory; return mounted_directory;
} }
KYTY_SUBSYSTEM_INIT(FileSystem) { void Initialize() {
g_mount_points = new MountPoints; g_mount_points = new MountPoints;
g_files = new FileDescriptors; g_files = new FileDescriptors;
} }
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(FileSystem) { void EmergencyShutdown() {
if (g_files != nullptr) { if (g_files != nullptr) {
g_files->CloseAll(); g_files->CloseAll();
} }
} }
KYTY_SUBSYSTEM_DESTROY(FileSystem) { void Shutdown() {
if (g_files != nullptr) { EmergencyShutdown();
g_files->CloseAll(); delete g_files;
} delete g_mount_points;
g_files = nullptr;
g_mount_points = nullptr;
} }
void Mount(const std::filesystem::path& folder, const std::string& point) { void Mount(const std::filesystem::path& folder, const std::string& point) {
+10 -2
View File
@@ -4,7 +4,6 @@
#include "common/abi.h" #include "common/abi.h"
#include "common/common.h" #include "common/common.h"
#include "common/stringUtils.h" #include "common/stringUtils.h"
#include "common/subsystems.h"
#include "kernel/pthread.h" #include "kernel/pthread.h"
#include <filesystem> #include <filesystem>
@@ -33,7 +32,16 @@ struct FileStat {
unsigned int: (8 / 2) * (16 - static_cast<int>(sizeof(KernelTimespec))); unsigned int: (8 / 2) * (16 - static_cast<int>(sizeof(KernelTimespec)));
}; };
KYTY_SUBSYSTEM_DEFINE(FileSystem); void Initialize();
void Shutdown();
void EmergencyShutdown();
struct Lifecycle {
static constexpr const char* name = "FileSystem";
static constexpr auto initialize = Libs::LibKernel::FileSystem::Initialize;
static constexpr auto shutdown = Libs::LibKernel::FileSystem::Shutdown;
static constexpr auto emergency_shutdown = Libs::LibKernel::FileSystem::EmergencyShutdown;
};
void Mount(const std::filesystem::path& folder, const std::string& point); void Mount(const std::filesystem::path& folder, const std::string& point);
void Umount(const std::string& folder_or_point); void Umount(const std::string& folder_or_point);
+2 -4
View File
@@ -976,7 +976,7 @@ static bool SelfTestSub64SharedPlaceholderAlias() {
static bool ReplaceFixedRangeWithReserved(uint64_t start, uint64_t size); static bool ReplaceFixedRangeWithReserved(uint64_t start, uint64_t size);
KYTY_SUBSYSTEM_INIT(Memory) { void Initialize() {
g_flexible_memory_size_frozen = true; g_flexible_memory_size_frozen = true;
VirtualMemory::Init(); VirtualMemory::Init();
g_guest_address_space = std::make_unique<GuestAddressSpace>(PhysicalMemory::TotalSize()); g_guest_address_space = std::make_unique<GuestAddressSpace>(PhysicalMemory::TotalSize());
@@ -988,9 +988,7 @@ KYTY_SUBSYSTEM_INIT(Memory) {
EXIT_IF(!SelfTestSub64SharedPlaceholderAlias()); EXIT_IF(!SelfTestSub64SharedPlaceholderAlias());
} }
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Memory) {} void Shutdown() {
KYTY_SUBSYSTEM_DESTROY(Memory) {
g_pooled_memory.reset(); g_pooled_memory.reset();
g_flexible_memory.reset(); g_flexible_memory.reset();
g_physical_memory.reset(); g_physical_memory.reset();
+8 -2
View File
@@ -3,7 +3,6 @@
#include "common/abi.h" #include "common/abi.h"
#include "common/common.h" #include "common/common.h"
#include "common/subsystems.h"
#include "common/virtualMemory.h" #include "common/virtualMemory.h"
namespace Libs::Graphics { namespace Libs::Graphics {
@@ -13,7 +12,14 @@ enum class PageFaultAccess;
namespace Libs::LibKernel::Memory { namespace Libs::LibKernel::Memory {
KYTY_SUBSYSTEM_DEFINE(Memory); void Initialize();
void Shutdown();
struct Lifecycle {
static constexpr const char* name = "Memory";
static constexpr auto initialize = Libs::LibKernel::Memory::Initialize;
static constexpr auto shutdown = Libs::LibKernel::Memory::Shutdown;
};
using callback_func_t = void (*)(uintptr_t addr, size_t size); using callback_func_t = void (*)(uintptr_t addr, size_t size);
+1 -5
View File
@@ -1124,7 +1124,7 @@ void* PthreadCreateMainGuestStack() {
return stack_top; return stack_top;
} }
KYTY_SUBSYSTEM_INIT(Pthread) { void Initialize() {
PRINT_NAME_ENABLE(false); PRINT_NAME_ENABLE(false);
EXIT_IF(g_pthread_context != nullptr); EXIT_IF(g_pthread_context != nullptr);
@@ -1157,10 +1157,6 @@ KYTY_SUBSYSTEM_INIT(Pthread) {
thread.Detach(); thread.Detach();
} }
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Pthread) {}
KYTY_SUBSYSTEM_DESTROY(Pthread) {}
static int PthreadAttrCopy(PthreadAttr* dst, const PthreadAttr* src) { static int PthreadAttrCopy(PthreadAttr* dst, const PthreadAttr* src) {
if (dst == nullptr || *dst == nullptr || src == nullptr || *src == nullptr) { if (dst == nullptr || *dst == nullptr || src == nullptr || *src == nullptr) {
return KERNEL_ERROR_EINVAL; return KERNEL_ERROR_EINVAL;
+6 -2
View File
@@ -3,7 +3,6 @@
#include "common/abi.h" #include "common/abi.h"
#include "common/common.h" #include "common/common.h"
#include "common/subsystems.h"
// IWYU pragma: no_include <pthread.h> // IWYU pragma: no_include <pthread.h>
@@ -19,7 +18,12 @@ namespace Libs {
namespace LibKernel { namespace LibKernel {
KYTY_SUBSYSTEM_DEFINE(Pthread); void Initialize();
struct PthreadLifecycle {
static constexpr const char* name = "Pthread";
static constexpr auto initialize = Libs::LibKernel::Initialize;
};
struct PthreadAttrPrivate; struct PthreadAttrPrivate;
struct PthreadPrivate; struct PthreadPrivate;
+2 -4
View File
@@ -43,7 +43,7 @@ namespace Libs::Graphics {
static RenderContext* g_renderer = nullptr; static RenderContext* g_renderer = nullptr;
KYTY_SUBSYSTEM_INIT(Graphics) { void Initialize() {
// Some games lock up if this is not called first // Some games lock up if this is not called first
if (Config::RenderDocEnabled()) { if (Config::RenderDocEnabled()) {
RenderDocInit(); RenderDocInit();
@@ -59,9 +59,7 @@ KYTY_SUBSYSTEM_INIT(Graphics) {
ShaderInit(); ShaderInit();
} }
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Graphics) {} void Shutdown() {
KYTY_SUBSYSTEM_DESTROY(Graphics) {
EXIT_IF(g_renderer == nullptr); EXIT_IF(g_renderer == nullptr);
g_renderer->ShutdownGpu(); g_renderer->ShutdownGpu();
VideoOut::VideoOutShutdown(); VideoOut::VideoOutShutdown();
+8 -2
View File
@@ -3,7 +3,6 @@
#include "common/abi.h" #include "common/abi.h"
#include "common/common.h" #include "common/common.h"
#include "common/subsystems.h"
#include "kernel/eventQueue.h" #include "kernel/eventQueue.h"
namespace Libs::Graphics { namespace Libs::Graphics {
@@ -21,7 +20,14 @@ struct MemoryRange {
uint64_t m_size; uint64_t m_size;
}; };
KYTY_SUBSYSTEM_DEFINE(Graphics); void Initialize();
void Shutdown();
struct Lifecycle {
static constexpr const char* name = "Graphics";
static constexpr auto initialize = Libs::Graphics::Initialize;
static constexpr auto shutdown = Libs::Graphics::Shutdown;
};
void GraphicsDbgDumpDcb(const char* type, uint32_t num_dw, uint32_t* cmd_buffer); void GraphicsDbgDumpDcb(const char* type, uint32_t num_dw, uint32_t* cmd_buffer);
+11 -13
View File
@@ -181,15 +181,13 @@ uint32_t AudioOutOutputs(const OutputParam* params, uint32_t num, bool blocking)
} // namespace AudioInternal } // namespace AudioInternal
KYTY_SUBSYSTEM_INIT(Audio) { void Initialize() {
EXIT_IF(g_audio != nullptr); EXIT_IF(g_audio != nullptr);
g_audio = new Audio; g_audio = new Audio;
} }
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Audio) {} void Shutdown() {
KYTY_SUBSYSTEM_DESTROY(Audio) {
delete g_audio; delete g_audio;
g_audio = nullptr; g_audio = nullptr;
} }
@@ -1461,14 +1459,14 @@ struct Ngs2CustomSamplerRackOption {
}; };
union Ngs2RackOptionUnion { union Ngs2RackOptionUnion {
Ngs2RackOption common; Ngs2RackOption common;
Ngs2SamplerRackOption sampler; Ngs2SamplerRackOption sampler;
Ngs2MasteringRackOption mastering; Ngs2MasteringRackOption mastering;
Ngs2SubmixerRackOption submixer; Ngs2SubmixerRackOption submixer;
Ngs2ReverbRackOption reverb; Ngs2ReverbRackOption reverb;
Ngs2CustomSubmixerRackOption custom_submixer; Ngs2CustomSubmixerRackOption custom_submixer;
Ngs2CustomMasteringRackOption custom_mastering; Ngs2CustomMasteringRackOption custom_mastering;
Ngs2CustomSamplerRackOption custom_sampler; Ngs2CustomSamplerRackOption custom_sampler;
}; };
struct Ngs2ContextBufferInfo { struct Ngs2ContextBufferInfo {
@@ -2653,8 +2651,8 @@ int KYTY_SYSV_ABI Ngs2VoiceGetState(uintptr_t voice_handle, Ngs2VoiceState* stat
switch (voice->rack->type) { switch (voice->rack->type) {
case Ngs2RackType::Submixer: { case Ngs2RackType::Submixer: {
EXIT_NOT_IMPLEMENTED(state_size != sizeof(Ngs2SubmixerVoiceState)); EXIT_NOT_IMPLEMENTED(state_size != sizeof(Ngs2SubmixerVoiceState));
auto* submixer = reinterpret_cast<Ngs2SubmixerVoiceState*>(state); auto* submixer = reinterpret_cast<Ngs2SubmixerVoiceState*>(state);
*submixer = {}; *submixer = {};
submixer->voice_state.state_flags = Ngs2GetStateFlags(voice); submixer->voice_state.state_flags = Ngs2GetStateFlags(voice);
LOGF("\t state_flags = %u\n", submixer->voice_state.state_flags); LOGF("\t state_flags = %u\n", submixer->voice_state.state_flags);
break; break;
+8 -3
View File
@@ -3,11 +3,16 @@
#include "common/abi.h" #include "common/abi.h"
#include "common/common.h" #include "common/common.h"
#include "common/subsystems.h"
namespace Libs::Audio { namespace Libs::Audio {
KYTY_SUBSYSTEM_DEFINE(Audio); void Initialize();
void Shutdown();
struct Lifecycle {
static constexpr const char* name = "Audio";
static constexpr auto initialize = Libs::Audio::Initialize;
static constexpr auto shutdown = Libs::Audio::Shutdown;
};
namespace AudioOut { namespace AudioOut {
+5 -4
View File
@@ -112,16 +112,17 @@ static void pad_fill_data(PadData* data, const ControllerState& state, bool conn
data->device_unique_data_len = 0; data->device_unique_data_len = 0;
} }
KYTY_SUBSYSTEM_INIT(Controller) { void Initialize() {
EXIT_IF(g_controller != nullptr); EXIT_IF(g_controller != nullptr);
g_controller = new GameController; g_controller = new GameController;
g_controller->Connect(HOST_INPUT_CONTROLLER_ID); g_controller->Connect(HOST_INPUT_CONTROLLER_ID);
} }
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Controller) {} void Shutdown() {
delete g_controller;
KYTY_SUBSYSTEM_DESTROY(Controller) {} g_controller = nullptr;
}
void GameController::Connect(int id) { void GameController::Connect(int id) {
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
+8 -3
View File
@@ -3,11 +3,16 @@
#include "common/abi.h" #include "common/abi.h"
#include "common/common.h" #include "common/common.h"
#include "common/subsystems.h"
namespace Libs::Controller { namespace Libs::Controller {
KYTY_SUBSYSTEM_DEFINE(Controller); void Initialize();
void Shutdown();
struct Lifecycle {
static constexpr const char* name = "Controller";
static constexpr auto initialize = Libs::Controller::Initialize;
static constexpr auto shutdown = Libs::Controller::Shutdown;
};
constexpr int HOST_INPUT_CONTROLLER_ID = -1000; constexpr int HOST_INPUT_CONTROLLER_ID = -1000;
+80 -231
View File
@@ -55,13 +55,13 @@ constexpr uint32_t VALID_KEYBOARD_OPTIONS = 0x0000003f;
constexpr uint32_t VALID_KEYBOARD_MODE = 0x0000007f; constexpr uint32_t VALID_KEYBOARD_MODE = 0x0000007f;
constexpr uint64_t VALID_LANGUAGES = 0x00000001ff1fffffULL; constexpr uint64_t VALID_LANGUAGES = 0x00000001ff1fffffULL;
constexpr uint32_t OPTION_MULTILINE = 0x00000001; constexpr uint32_t OPTION_MULTILINE = ImeCommon::OPTION_MULTILINE;
constexpr uint32_t OPTION_PASSWORD = 0x00000004; constexpr uint32_t OPTION_PASSWORD = ImeCommon::OPTION_PASSWORD;
constexpr uint32_t OPTION_EXT_KEYBOARD = 0x00000010; constexpr uint32_t OPTION_EXT_KEYBOARD = ImeCommon::OPTION_EXT_KEYBOARD;
constexpr uint32_t OPTION_EXPANDED_PREEDIT = 0x00001000; constexpr uint32_t OPTION_EXPANDED_PREEDIT = ImeCommon::OPTION_EXPANDED_PREEDIT;
constexpr uint32_t OPTION_USE_OVER_2K = 0x00004000; constexpr uint32_t OPTION_USE_OVER_2K = ImeCommon::OPTION_USE_OVER_2K;
constexpr uint32_t EXT_OPTION_HIDE_KEY_PANEL = 0x00000400; constexpr uint32_t EXT_OPTION_HIDE_KEY_PANEL = ImeCommon::EXT_OPTION_HIDE_KEY_PANEL;
constexpr size_t EVENT_QUEUE_CAPACITY = 128; constexpr size_t EVENT_QUEUE_CAPACITY = 128;
struct QueuedEvent { struct QueuedEvent {
@@ -71,18 +71,15 @@ struct QueuedEvent {
}; };
struct State { struct State {
bool open = false; bool open = false;
bool event_overflow = false; bool event_overflow = false;
uint64_t generation = 0; uint64_t generation = 0;
uint64_t revision = 0; uint64_t revision = 0;
uint32_t option = 0;
uint32_t max_text_length = 0;
uint32_t cursor = 0;
Param param {}; Param param {};
ExtendedParam extended {}; ExtendedParam extended {};
void* arg = nullptr; void* arg = nullptr;
EventHandler handler = nullptr; EventHandler handler = nullptr;
std::u16string text; ImeCommon::TextEditEngine editor;
std::deque<QueuedEvent> events; std::deque<QueuedEvent> events;
std::vector<ExternalInput> external_inputs; std::vector<ExternalInput> external_inputs;
}; };
@@ -130,97 +127,6 @@ bool ValidateText(const char16_t* text, uint32_t length, bool multiline, uint32_
return true; return true;
} }
bool IsAllowedInput(char16_t value, Type type, uint32_t option) {
if (value == u'\r' || value == u'\0') {
return false;
}
if (value == u'\n') {
return (option & OPTION_MULTILINE) != 0;
}
if (type == Type::Number) {
return (value >= u'0' && value <= u'9') || value == u',' || value == u'-' || value == u'.';
}
if (type == Type::BasicLatin) {
return value >= u' ' && value <= u'~';
}
return true;
}
char16_t HidCharacter(uint16_t keycode, uint32_t status) {
const bool shift = (status & 0x00002200) != 0;
const bool caps = (status & 0x00020000) != 0;
if (keycode >= 4 && keycode <= 29) {
return static_cast<char16_t>(((shift != caps) ? u'A' : u'a') + keycode - 4);
}
if (keycode >= 30 && keycode <= 39) {
static constexpr char16_t plain[] = u"1234567890";
static constexpr char16_t shifted[] = u"!@#$%^&*()";
return (shift ? shifted : plain)[keycode - 30];
}
if (keycode == 44) {
return u' ';
}
if (keycode >= 45 && keycode <= 56) {
static constexpr char16_t plain[] = u"-=[]\\#;'`,./";
static constexpr char16_t shifted[] = u"_+{}|~:\"~<>?";
return (shift ? shifted : plain)[keycode - 45];
}
if (keycode >= 89 && keycode <= 98) {
static constexpr char16_t keypad[] = u"1234567890";
return keypad[keycode - 89];
}
return keycode == 99 ? u'.' : u'\0';
}
bool ApplyKeyboardFilterOutput(ExternalInput* input, uint16_t keycode, uint32_t status,
bool multiline) {
constexpr uint32_t KEYCODE_VALID = 0x00000001;
constexpr uint32_t CHARACTER_VALID = 0x00000002;
if (keycode == input->key.keycode && status == input->key.status) {
return true;
}
if ((status & KEYCODE_VALID) == 0 || keycode == 0) {
return input->action == ExternalAction::Text && (status & CHARACTER_VALID) != 0;
}
input->key.keycode = keycode;
input->key.status = status;
input->text.clear();
switch (keycode) {
case 40:
case 88:
case 158:
input->action = multiline ? ExternalAction::Newline : ExternalAction::Accept;
break;
case 41: input->action = ExternalAction::Cancel; break;
case 42:
case 187: input->action = ExternalAction::Backspace; break;
case 43:
case 186: input->action = ExternalAction::None; break;
case 79: input->action = ExternalAction::MoveRight; break;
case 80: input->action = ExternalAction::MoveLeft; break;
default: {
const char16_t character = HidCharacter(keycode, status);
if (character == u'\0') {
return false;
}
input->action = ExternalAction::Text;
input->key.character = character;
input->text.push_back(character);
break;
}
}
return true;
}
uint32_t NormalizeCursor(std::u16string_view text, uint32_t cursor) {
cursor = std::min<uint32_t>(cursor, static_cast<uint32_t>(text.size()));
if (cursor > 0 && cursor < text.size() && text[cursor - 1] >= 0xd800 &&
text[cursor - 1] <= 0xdbff && text[cursor] >= 0xdc00 && text[cursor] <= 0xdfff) {
cursor++;
}
return cursor;
}
void NotifyVisibility(bool visible, uint64_t generation) { void NotifyVisibility(bool visible, uint64_t generation) {
if (const auto callback = g_visibility_callback.load(std::memory_order_acquire); if (const auto callback = g_visibility_callback.load(std::memory_order_acquire);
callback != nullptr) { callback != nullptr) {
@@ -247,7 +153,7 @@ void SyncGuestText(char16_t* work, char16_t* input, uint32_t max_length, std::u1
void SyncTextBuffersLocked() { void SyncTextBuffersLocked() {
SyncGuestText(static_cast<char16_t*>(g_state.param.work), g_state.param.input_text_buffer, SyncGuestText(static_cast<char16_t*>(g_state.param.work), g_state.param.input_text_buffer,
g_state.max_text_length, g_state.text); g_state.editor.GetMaxLength(), g_state.editor.GetText());
} }
bool QueueEventLocked(QueuedEvent event) { bool QueueEventLocked(QueuedEvent event) {
@@ -263,53 +169,33 @@ QueuedEvent MakeTextEventLocked(uint32_t id, uint32_t edit_index, int32_t edit_l
QueuedEvent queued; QueuedEvent queued;
queued.event.id = id; queued.event.id = id;
queued.event.param.text.str = static_cast<char16_t*>(g_state.param.work); queued.event.param.text.str = static_cast<char16_t*>(g_state.param.work);
queued.event.param.text.caret_index = g_state.cursor; queued.event.param.text.caret_index = g_state.editor.GetCursor();
queued.event.param.text.area_num = 1; queued.event.param.text.area_num = 1;
queued.event.param.text.text_area[0] = {TextAreaMode::Edit, edit_index, edit_length}; queued.event.param.text.text_area[0] = {TextAreaMode::Edit, edit_index, edit_length};
queued.text_payload = true; queued.text_payload = true;
queued.text = g_state.text; queued.text = g_state.editor.GetText();
return queued; return queued;
} }
bool CommitFilteredText(uint64_t generation, uint64_t revision, std::u16string old_text, bool CommitFilteredText(uint64_t generation, uint64_t revision, std::u16string old_text,
std::u16string candidate, uint32_t cursor, TextFilter filter, ImeCommon::TextEditEngine candidate, TextFilter filter, bool multiline) {
uint32_t max_length, bool multiline) {
if (filter != nullptr) { if (filter != nullptr) {
std::vector<char16_t> output(max_length + 1, u'\0'); std::u16string filtered;
uint32_t output_length = max_length; if (ImeCommon::RunTextFilter(filter, candidate.GetText(), candidate.GetMaxLength(),
if (filter(output.data(), &output_length, candidate.c_str(), &filtered) &&
static_cast<uint32_t>(candidate.size())) == 0 && ImeCommon::IsValidInputText(filtered, multiline)) {
output_length <= max_length) { candidate.ReplaceText(std::move(filtered), candidate.GetCursor());
uint32_t actual_length = 0;
if (ValidateText(output.data(), output_length, multiline, &actual_length) &&
actual_length == output_length) {
candidate.assign(output.data(), output.data() + output_length);
}
} }
} }
std::scoped_lock lock(g_mutex); std::scoped_lock lock(g_mutex);
if (!g_state.open || g_state.generation != generation || g_state.revision != revision || if (!g_state.open || g_state.generation != generation || g_state.revision != revision ||
g_state.text != old_text || candidate == old_text) { g_state.editor.GetText() != old_text || candidate.GetText() == old_text) {
return false; return false;
} }
size_t prefix = 0; const auto edit = ImeCommon::ComputeEditDelta(old_text, candidate.GetText());
while (prefix < old_text.size() && prefix < candidate.size() && g_state.editor = std::move(candidate);
old_text[prefix] == candidate[prefix]) { QueueEventLocked(MakeTextEventLocked(1, edit.index, edit.length));
prefix++;
}
size_t old_tail = old_text.size();
size_t new_tail = candidate.size();
while (old_tail > prefix && new_tail > prefix &&
old_text[old_tail - 1] == candidate[new_tail - 1]) {
old_tail--;
new_tail--;
}
const int32_t edit_length =
static_cast<int32_t>(new_tail - prefix) - static_cast<int32_t>(old_tail - prefix);
g_state.text = std::move(candidate);
g_state.cursor = NormalizeCursor(g_state.text, cursor);
QueueEventLocked(MakeTextEventLocked(1, static_cast<uint32_t>(prefix), edit_length));
UpdateRevisionLocked(); UpdateRevisionLocked();
return true; return true;
} }
@@ -475,16 +361,13 @@ int KYTY_SYSV_ABI ImeOpen(const Param* param, const ExtendedParam* extended) {
g_state.open = true; g_state.open = true;
g_state.generation = next_generation; g_state.generation = next_generation;
g_state.revision = next_revision; g_state.revision = next_revision;
g_state.option = param->option;
g_state.max_text_length = param->max_text_length;
g_state.cursor = static_cast<uint32_t>(text.size());
g_state.param = *param; g_state.param = *param;
if (extended != nullptr) { if (extended != nullptr) {
g_state.extended = *extended; g_state.extended = *extended;
} }
g_state.arg = param->arg; g_state.arg = param->arg;
g_state.handler = param->handler; g_state.handler = param->handler;
g_state.text = std::move(text); g_state.editor.Reset(param->type, param->option, param->max_text_length, std::move(text));
std::memset(param->work, 0, WORK_BUFFER_SIZE); std::memset(param->work, 0, WORK_BUFFER_SIZE);
SyncTextBuffersLocked(); SyncTextBuffersLocked();
@@ -550,7 +433,7 @@ int KYTY_SYSV_ABI ImeUpdate(EventHandler handler) {
while (!g_state.events.empty()) { while (!g_state.events.empty()) {
dispatch.push_back({g_state.arg, std::move(g_state.events.front()), dispatch.push_back({g_state.arg, std::move(g_state.events.front()),
static_cast<char16_t*>(g_state.param.work), static_cast<char16_t*>(g_state.param.work),
g_state.param.input_text_buffer, g_state.max_text_length, g_state.param.input_text_buffer, g_state.editor.GetMaxLength(),
g_state.generation}); g_state.generation});
g_state.events.pop_front(); g_state.events.pop_front();
} }
@@ -607,14 +490,14 @@ int KYTY_SYSV_ABI ImeSetText(const char16_t* text, uint32_t length) {
if (text == nullptr) { if (text == nullptr) {
return ERROR_INVALID_ADDRESS; return ERROR_INVALID_ADDRESS;
} }
const uint32_t clamped_length = std::min(length, g_state.max_text_length); const uint32_t clamped_length = std::min(length, g_state.editor.GetMaxLength());
uint32_t actual_length = 0; uint32_t actual_length = 0;
if (!ValidateText(text, clamped_length, (g_state.option & OPTION_MULTILINE) != 0, if (!ValidateText(text, clamped_length, (g_state.editor.GetOption() & OPTION_MULTILINE) != 0,
&actual_length)) { &actual_length)) {
return ERROR_INVALID_TEXT; return ERROR_INVALID_TEXT;
} }
g_state.text.assign(text, text + actual_length); g_state.editor.ReplaceText(std::u16string(text, text + actual_length),
g_state.cursor = NormalizeCursor(g_state.text, g_state.cursor); g_state.editor.GetCursor());
SyncTextBuffersLocked(); SyncTextBuffersLocked();
UpdateRevisionLocked(); UpdateRevisionLocked();
return OK; return OK;
@@ -628,10 +511,10 @@ int KYTY_SYSV_ABI ImeSetCaret(const Caret* caret) {
if (caret == nullptr) { if (caret == nullptr) {
return ERROR_INVALID_ADDRESS; return ERROR_INVALID_ADDRESS;
} }
if (caret->index > g_state.text.size()) { if (caret->index > g_state.editor.GetText().size()) {
return ERROR_INVALID_PARAM; return ERROR_INVALID_PARAM;
} }
g_state.cursor = NormalizeCursor(g_state.text, caret->index); g_state.editor.SetCursor(caret->index);
UpdateRevisionLocked(); UpdateRevisionLocked();
return OK; return OK;
} }
@@ -644,7 +527,7 @@ int KYTY_SYSV_ABI ImeSetTextGeometry(TextAreaMode mode, const TextGeometry* geom
if (geometry == nullptr) { if (geometry == nullptr) {
return ERROR_INVALID_ADDRESS; return ERROR_INVALID_ADDRESS;
} }
const bool over_2k = (g_state.option & OPTION_USE_OVER_2K) != 0; const bool over_2k = (g_state.editor.GetOption() & OPTION_USE_OVER_2K) != 0;
const float max_x = over_2k ? 3840.0f : 1920.0f; const float max_x = over_2k ? 3840.0f : 1920.0f;
const float max_y = over_2k ? 2160.0f : 1080.0f; const float max_y = over_2k ? 2160.0f : 1080.0f;
if (!std::isfinite(geometry->x) || !std::isfinite(geometry->y) || geometry->x < 0.0f || if (!std::isfinite(geometry->x) || !std::isfinite(geometry->y) || geometry->x < 0.0f ||
@@ -754,11 +637,11 @@ bool GetHostSnapshot(HostSnapshot* snapshot) {
snapshot->generation = g_state.generation; snapshot->generation = g_state.generation;
snapshot->type = g_state.param.type; snapshot->type = g_state.param.type;
snapshot->enter_label = g_state.param.enter_label; snapshot->enter_label = g_state.param.enter_label;
snapshot->option = g_state.option; snapshot->option = g_state.editor.GetOption();
snapshot->max_text_length = g_state.max_text_length; snapshot->max_text_length = g_state.editor.GetMaxLength();
snapshot->cursor = g_state.cursor; snapshot->cursor = g_state.editor.GetCursor();
snapshot->disable_device = g_state.extended.disable_device; snapshot->disable_device = g_state.extended.disable_device;
snapshot->key_panel_visible = (g_state.option & OPTION_EXT_KEYBOARD) == 0 || snapshot->key_panel_visible = (g_state.editor.GetOption() & OPTION_EXT_KEYBOARD) == 0 ||
(g_state.extended.option & EXT_OPTION_HIDE_KEY_PANEL) == 0; (g_state.extended.option & EXT_OPTION_HIDE_KEY_PANEL) == 0;
snapshot->posx = g_state.param.posx; snapshot->posx = g_state.param.posx;
snapshot->posy = g_state.param.posy; snapshot->posy = g_state.param.posy;
@@ -766,92 +649,65 @@ bool GetHostSnapshot(HostSnapshot* snapshot) {
snapshot->vertical_alignment = g_state.param.vertical_alignment; snapshot->vertical_alignment = g_state.param.vertical_alignment;
snapshot->panel_width = g_state.param.type == Type::Number ? 370 : 793; snapshot->panel_width = g_state.param.type == Type::Number ? 370 : 793;
snapshot->panel_height = g_state.param.type == Type::Number ? 402 : 408; snapshot->panel_height = g_state.param.type == Type::Number ? 402 : 408;
if ((g_state.option & OPTION_USE_OVER_2K) != 0) { if ((g_state.editor.GetOption() & OPTION_USE_OVER_2K) != 0) {
snapshot->panel_width *= 2; snapshot->panel_width *= 2;
snapshot->panel_height *= 2; snapshot->panel_height *= 2;
} }
snapshot->text = g_state.text; snapshot->text = g_state.editor.GetText();
snapshot->title.clear();
snapshot->placeholder.clear();
return true; return true;
} }
static bool ApplyInsertText(uint64_t generation, std::u16string_view text) { static bool ApplyInsertText(uint64_t generation, std::u16string_view text) {
uint64_t revision = 0; uint64_t revision = 0;
uint32_t cursor = 0; bool multiline = false;
uint32_t max_length = 0; TextFilter filter = nullptr;
bool multiline = false; std::u16string old_text;
TextFilter filter = nullptr; ImeCommon::TextEditEngine candidate;
std::u16string old_text;
std::u16string candidate;
{ {
std::scoped_lock lock(g_mutex); std::scoped_lock lock(g_mutex);
if (!g_state.open || g_state.generation != generation || text.empty()) { if (!g_state.open || g_state.generation != generation || text.empty()) {
return false; return false;
} }
uint32_t valid_length = 0; multiline = (g_state.editor.GetOption() & OPTION_MULTILINE) != 0;
multiline = (g_state.option & OPTION_MULTILINE) != 0; if (!ImeCommon::IsValidInputText(text, multiline)) {
if (!ValidateText(text.data(), static_cast<uint32_t>(text.size()), multiline,
&valid_length) ||
valid_length != text.size()) {
return false; return false;
} }
std::u16string allowed; candidate = g_state.editor;
for (const char16_t value: text) { if (!candidate.Insert(text)) {
if (IsAllowedInput(value, g_state.param.type, g_state.option)) {
allowed.push_back(value);
}
}
const size_t available = g_state.max_text_length - g_state.text.size();
if (allowed.empty() || available == 0) {
return false; return false;
} }
allowed.resize(std::min(allowed.size(), available)); revision = g_state.revision;
if (!allowed.empty() && allowed.back() >= 0xd800 && allowed.back() <= 0xdbff) { filter = g_state.param.filter;
allowed.pop_back(); old_text = g_state.editor.GetText();
}
if (allowed.empty()) {
return false;
}
revision = g_state.revision;
max_length = g_state.max_text_length;
filter = g_state.param.filter;
old_text = g_state.text;
candidate = old_text;
candidate.insert(g_state.cursor, allowed);
cursor = g_state.cursor + static_cast<uint32_t>(allowed.size());
} }
return CommitFilteredText(generation, revision, std::move(old_text), std::move(candidate), return CommitFilteredText(generation, revision, std::move(old_text), std::move(candidate),
cursor, filter, max_length, multiline); filter, multiline);
} }
static bool ApplyBackspace(uint64_t generation) { static bool ApplyBackspace(uint64_t generation) {
uint64_t revision = 0; uint64_t revision = 0;
uint32_t cursor = 0; bool multiline = false;
uint32_t max_length = 0; TextFilter filter = nullptr;
bool multiline = false; std::u16string old_text;
TextFilter filter = nullptr; ImeCommon::TextEditEngine candidate;
std::u16string old_text;
std::u16string candidate;
{ {
std::scoped_lock lock(g_mutex); std::scoped_lock lock(g_mutex);
if (!g_state.open || g_state.generation != generation || g_state.cursor == 0) { if (!g_state.open || g_state.generation != generation) {
return false; return false;
} }
uint32_t first = g_state.cursor - 1; candidate = g_state.editor;
if (first > 0 && g_state.text[first] >= 0xdc00 && g_state.text[first] <= 0xdfff && if (!candidate.Backspace()) {
g_state.text[first - 1] >= 0xd800 && g_state.text[first - 1] <= 0xdbff) { return false;
first--;
} }
revision = g_state.revision; revision = g_state.revision;
max_length = g_state.max_text_length; multiline = (g_state.editor.GetOption() & OPTION_MULTILINE) != 0;
multiline = (g_state.option & OPTION_MULTILINE) != 0; filter = g_state.param.filter;
filter = g_state.param.filter; old_text = g_state.editor.GetText();
old_text = g_state.text;
candidate = old_text;
candidate.erase(first, g_state.cursor - first);
cursor = first;
} }
return CommitFilteredText(generation, revision, std::move(old_text), std::move(candidate), return CommitFilteredText(generation, revision, std::move(old_text), std::move(candidate),
cursor, filter, max_length, multiline); filter, multiline);
} }
static bool ApplyMoveCursor(uint64_t generation, int delta) { static bool ApplyMoveCursor(uint64_t generation, int delta) {
@@ -859,25 +715,14 @@ static bool ApplyMoveCursor(uint64_t generation, int delta) {
if (!g_state.open || g_state.generation != generation || delta == 0) { if (!g_state.open || g_state.generation != generation || delta == 0) {
return false; return false;
} }
const uint32_t old_cursor = g_state.cursor; const uint32_t old_cursor = g_state.editor.GetCursor();
int next = if (!g_state.editor.MoveCursor(delta)) {
std::clamp(static_cast<int>(old_cursor) + delta, 0, static_cast<int>(g_state.text.size()));
if (delta < 0 && next > 0 && next < static_cast<int>(g_state.text.size()) &&
g_state.text[next] >= 0xdc00 && g_state.text[next] <= 0xdfff &&
g_state.text[next - 1] >= 0xd800 && g_state.text[next - 1] <= 0xdbff) {
next--;
} else if (delta > 0 && next > 0 && next < static_cast<int>(g_state.text.size()) &&
g_state.text[next - 1] >= 0xd800 && g_state.text[next - 1] <= 0xdbff &&
g_state.text[next] >= 0xdc00 && g_state.text[next] <= 0xdfff) {
next++;
}
g_state.cursor = static_cast<uint32_t>(next);
if (g_state.cursor == old_cursor) {
return false; return false;
} }
const uint32_t direction = g_state.cursor > old_cursor ? 2 : 1; const uint32_t new_cursor = g_state.editor.GetCursor();
const uint32_t steps = static_cast<uint32_t>( const uint32_t direction = new_cursor > old_cursor ? 2 : 1;
std::abs(static_cast<int>(g_state.cursor) - static_cast<int>(old_cursor))); const uint32_t steps = static_cast<uint32_t>(
std::abs(static_cast<int>(new_cursor) - static_cast<int>(old_cursor)));
for (uint32_t i = 0; i < steps; i++) { for (uint32_t i = 0; i < steps; i++) {
QueuedEvent event; QueuedEvent event;
event.event.id = 2; event.event.id = 2;
@@ -962,7 +807,7 @@ void ApplyExternalInputs() {
generation = g_state.generation; generation = g_state.generation;
filter = g_state.extended.ext_keyboard_filter; filter = g_state.extended.ext_keyboard_filter;
user_id = g_state.param.user_id; user_id = g_state.param.user_id;
multiline = (g_state.option & OPTION_MULTILINE) != 0; multiline = (g_state.editor.GetOption() & OPTION_MULTILINE) != 0;
inputs.swap(g_state.external_inputs); inputs.swap(g_state.external_inputs);
} }
for (auto& input: inputs) { for (auto& input: inputs) {
@@ -978,7 +823,7 @@ void ApplyExternalInputs() {
uint16_t keycode = input.key.keycode; uint16_t keycode = input.key.keycode;
uint32_t status = input.key.status; uint32_t status = input.key.status;
if (filter(&input.key, &keycode, &status, nullptr) == 0) { if (filter(&input.key, &keycode, &status, nullptr) == 0) {
accepted = ApplyKeyboardFilterOutput(&input, keycode, status, multiline); accepted = ImeCommon::ApplyKeyboardFilterOutput(&input, keycode, status, multiline);
} }
} }
if (!accepted) { if (!accepted) {
@@ -999,6 +844,8 @@ void ApplyExternalInputs() {
} // namespace } // namespace
#if !defined(KYTY_IME_TESTS)
LIB_VERSION("Ime", 1, "Ime", 1, 1); LIB_VERSION("Ime", 1, "Ime", 1, 1);
LIB_DEFINE(InitPlatform_1_Ime) { LIB_DEFINE(InitPlatform_1_Ime) {
@@ -1017,4 +864,6 @@ LIB_DEFINE(InitPlatform_1_Ime) {
LIB_FUNC("ua+13Hk9kKs", ImeKeyboardSetMode); LIB_FUNC("ua+13Hk9kKs", ImeKeyboardSetMode);
} }
#endif
} // namespace Libs::Ime } // namespace Libs::Ime
+15 -86
View File
@@ -1,7 +1,7 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_LIBS_IME_H_ #ifndef EMULATOR_INCLUDE_EMULATOR_LIBS_IME_H_
#define EMULATOR_INCLUDE_EMULATOR_LIBS_IME_H_ #define EMULATOR_INCLUDE_EMULATOR_LIBS_IME_H_
#include "common/abi.h" #include "libs/imeCommon.h"
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
@@ -11,28 +11,19 @@
namespace Libs::Ime { namespace Libs::Ime {
constexpr uint32_t WORK_BUFFER_SIZE = 20 * 1024; constexpr uint32_t WORK_BUFFER_SIZE = 20 * 1024;
constexpr uint32_t MAX_TEXT_LENGTH = 2048; constexpr uint32_t MAX_TEXT_LENGTH = ImeCommon::MAX_TEXT_LENGTH;
enum class Type : uint32_t { Default = 0, BasicLatin = 1, Url = 2, Mail = 3, Number = 4 }; using Type = ImeCommon::Type;
enum class EnterLabel : uint32_t { Default = 0, Send = 1, Search = 2, Go = 3 }; using EnterLabel = ImeCommon::EnterLabel;
enum class Alignment : uint32_t { Start = 0, Center = 1, End = 2 }; using Alignment = ImeCommon::Alignment;
struct Event; struct Event;
struct Keycode;
using TextFilter = int32_t(KYTY_SYSV_ABI*)(char16_t* out_text, uint32_t* out_text_length, using Keycode = ImeCommon::Keycode;
const char16_t* source_text, using TextFilter = ImeCommon::TextFilter;
uint32_t source_text_length);
using EventHandler = void(KYTY_SYSV_ABI*)(void* arg, const Event* event); 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, using ExtKeyboardFilter = ImeCommon::ExtKeyboardFilter;
uint32_t* out_status, void* reserved); using Color = ImeCommon::Color;
struct Color {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
struct Caret { struct Caret {
float x; float x;
@@ -75,16 +66,6 @@ struct KeyboardResourceIdArray {
uint32_t resource_id[5]; 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 { union EventParam {
Rect rect; Rect rect;
EditText text; EditText text;
@@ -119,24 +100,7 @@ struct Param {
int8_t reserved[8]; int8_t reserved[8];
}; };
struct ExtendedParam { using ExtendedParam = ImeCommon::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 { struct KeyboardParam {
uint32_t option; uint32_t option;
@@ -156,22 +120,8 @@ struct KeyboardInfo {
int8_t reserved[12]; int8_t reserved[12];
}; };
enum class ExternalAction : uint8_t { using ExternalAction = ImeCommon::ExternalAction;
None, using ExternalInput = ImeCommon::ExternalInput;
Text,
Backspace,
MoveLeft,
MoveRight,
Cancel,
Accept,
Newline,
};
struct ExternalInput {
Keycode key;
ExternalAction action;
std::u16string text;
};
static_assert(sizeof(Caret) == 0x10); static_assert(sizeof(Caret) == 0x10);
static_assert(sizeof(TextGeometry) == 0x10); static_assert(sizeof(TextGeometry) == 0x10);
@@ -192,30 +142,9 @@ static_assert(sizeof(KeyboardResourceIdArray) == 0x18);
static_assert(sizeof(KeyboardInfo) == 0x24); static_assert(sizeof(KeyboardInfo) == 0x24);
static_assert(sizeof(Keycode) == 0x20); static_assert(sizeof(Keycode) == 0x20);
struct VisualState { using VisualState = ImeCommon::VisualState;
bool active; using HostSnapshot = ImeCommon::HostSnapshot;
uint64_t revision; using VisibilityCallback = ImeCommon::VisibilityCallback;
};
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); 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 ImeGetPanelSize(const Param* param, uint32_t* width, uint32_t* height);
+259
View File
@@ -0,0 +1,259 @@
#include "libs/imeCommon.h"
#include <algorithm>
#include <vector>
namespace Libs::ImeCommon {
namespace {
constexpr bool IsHighSurrogate(char16_t value) {
return value >= 0xd800 && value <= 0xdbff;
}
constexpr bool IsLowSurrogate(char16_t value) {
return value >= 0xdc00 && value <= 0xdfff;
}
char16_t HidCharacter(uint16_t keycode, uint32_t status) {
const bool shift = (status & 0x00002200) != 0;
const bool caps = (status & 0x00020000) != 0;
if (keycode >= 4 && keycode <= 29) {
return static_cast<char16_t>(((shift != caps) ? u'A' : u'a') + keycode - 4);
}
if (keycode >= 30 && keycode <= 39) {
static constexpr char16_t plain[] = u"1234567890";
static constexpr char16_t shifted[] = u"!@#$%^&*()";
return (shift ? shifted : plain)[keycode - 30];
}
if (keycode == 44) {
return u' ';
}
if (keycode >= 45 && keycode <= 56) {
static constexpr char16_t plain[] = u"-=[]\\#;'`,./";
static constexpr char16_t shifted[] = u"_+{}|~:\"~<>?";
return (shift ? shifted : plain)[keycode - 45];
}
if (keycode >= 89 && keycode <= 98) {
static constexpr char16_t keypad[] = u"1234567890";
return keypad[keycode - 89];
}
return keycode == 99 ? u'.' : u'\0';
}
} // namespace
bool IsValidUtf16(std::u16string_view text) {
for (size_t i = 0; i < text.size(); i++) {
if (IsHighSurrogate(text[i])) {
if (++i >= text.size() || !IsLowSurrogate(text[i])) {
return false;
}
} else if (IsLowSurrogate(text[i])) {
return false;
}
}
return true;
}
bool IsValidInputText(std::u16string_view text, bool multiline) {
if (!IsValidUtf16(text)) {
return false;
}
return std::none_of(text.begin(), text.end(), [multiline](char16_t value) {
return value == u'\0' || (!multiline && (value == u'\n' || value == u'\r'));
});
}
bool IsAllowedInput(char16_t value, Type type, uint32_t option) {
if (value == u'\r' || value == u'\0') {
return false;
}
if (value == u'\n') {
return (option & OPTION_MULTILINE) != 0;
}
if (type == Type::Number) {
return (value >= u'0' && value <= u'9') || value == u',' || value == u'-' || value == u'.';
}
if (type == Type::BasicLatin) {
return value >= u' ' && value <= u'~';
}
return true;
}
uint32_t NormalizeCursor(std::u16string_view text, uint32_t cursor) {
cursor = std::min<uint32_t>(cursor, static_cast<uint32_t>(text.size()));
if (cursor > 0 && cursor < text.size() && IsHighSurrogate(text[cursor - 1]) &&
IsLowSurrogate(text[cursor])) {
cursor++;
}
return cursor;
}
void ClampText(std::u16string* text, uint32_t limit) {
if (text->size() <= limit) {
return;
}
text->resize(limit);
if (!text->empty() && IsHighSurrogate(text->back())) {
text->pop_back();
}
}
EditDelta ComputeEditDelta(std::u16string_view before, std::u16string_view after) {
size_t prefix = 0;
while (prefix < before.size() && prefix < after.size() && before[prefix] == after[prefix]) {
prefix++;
}
size_t before_tail = before.size();
size_t after_tail = after.size();
while (before_tail > prefix && after_tail > prefix &&
before[before_tail - 1] == after[after_tail - 1]) {
before_tail--;
after_tail--;
}
return {static_cast<uint32_t>(prefix),
static_cast<int32_t>(after_tail - prefix) - static_cast<int32_t>(before_tail - prefix)};
}
bool RunTextFilter(TextFilter filter, const std::u16string& source, uint32_t output_capacity,
std::u16string* output) {
if (filter == nullptr || output == nullptr) {
return false;
}
std::vector<char16_t> buffer(static_cast<size_t>(output_capacity) + 1, u'\0');
uint32_t output_length = output_capacity;
if (filter(buffer.data(), &output_length, source.c_str(),
static_cast<uint32_t>(source.size())) != 0 ||
output_length > output_capacity ||
!IsValidUtf16(std::u16string_view(buffer.data(), output_length))) {
return false;
}
output->assign(buffer.data(), buffer.data() + output_length);
return true;
}
bool ApplyKeyboardFilterOutput(ExternalInput* input, uint16_t keycode, uint32_t status,
bool multiline) {
constexpr uint32_t KEYCODE_VALID = 0x00000001;
constexpr uint32_t CHARACTER_VALID = 0x00000002;
if (keycode == input->key.keycode && status == input->key.status) {
return true;
}
if ((status & KEYCODE_VALID) == 0 || keycode == 0) {
return input->action == ExternalAction::Text && (status & CHARACTER_VALID) != 0;
}
input->key.keycode = keycode;
input->key.status = status;
input->text.clear();
switch (keycode) {
case 40:
case 88:
case 158:
input->action = multiline ? ExternalAction::Newline : ExternalAction::Accept;
break;
case 41: input->action = ExternalAction::Cancel; break;
case 42:
case 187: input->action = ExternalAction::Backspace; break;
case 43:
case 186: input->action = ExternalAction::None; break;
case 79: input->action = ExternalAction::MoveRight; break;
case 80: input->action = ExternalAction::MoveLeft; break;
default: {
const char16_t character = HidCharacter(keycode, status);
if (character == u'\0') {
return false;
}
input->action = ExternalAction::Text;
input->key.character = character;
input->text.push_back(character);
break;
}
}
return true;
}
void TextEditEngine::Reset(Type type, uint32_t option, uint32_t max_length, std::u16string text) {
m_type = type;
m_option = option;
m_max_length = max_length;
ClampText(&text, max_length);
m_text = std::move(text);
m_cursor = static_cast<uint32_t>(m_text.size());
}
bool TextEditEngine::Insert(std::u16string_view text, EditDelta* edit) {
if (text.empty() || !IsValidUtf16(text)) {
return false;
}
std::u16string allowed;
allowed.reserve(text.size());
for (const char16_t value: text) {
if (IsAllowedInput(value, m_type, m_option)) {
allowed.push_back(value);
}
}
const size_t available = m_max_length - m_text.size();
if (allowed.empty() || available == 0) {
return false;
}
allowed.resize(std::min(allowed.size(), available));
if (!allowed.empty() && IsHighSurrogate(allowed.back())) {
allowed.pop_back();
}
if (allowed.empty()) {
return false;
}
if (edit != nullptr) {
*edit = {m_cursor, static_cast<int32_t>(allowed.size())};
}
m_text.insert(m_cursor, allowed);
m_cursor += static_cast<uint32_t>(allowed.size());
return true;
}
bool TextEditEngine::Backspace(EditDelta* edit) {
if (m_cursor == 0) {
return false;
}
uint32_t first = m_cursor - 1;
if (first > 0 && IsLowSurrogate(m_text[first]) && IsHighSurrogate(m_text[first - 1])) {
first--;
}
if (edit != nullptr) {
*edit = {first, -static_cast<int32_t>(m_cursor - first)};
}
m_text.erase(first, m_cursor - first);
m_cursor = first;
return true;
}
bool TextEditEngine::MoveCursor(int delta) {
if (delta == 0) {
return false;
}
int next = std::clamp(static_cast<int>(m_cursor) + delta, 0, static_cast<int>(m_text.size()));
if (delta < 0 && next > 0 && next < static_cast<int>(m_text.size()) &&
IsLowSurrogate(m_text[next]) && IsHighSurrogate(m_text[next - 1])) {
next--;
} else if (delta > 0 && next > 0 && next < static_cast<int>(m_text.size()) &&
IsHighSurrogate(m_text[next - 1]) && IsLowSurrogate(m_text[next])) {
next++;
}
if (next == static_cast<int>(m_cursor)) {
return false;
}
m_cursor = static_cast<uint32_t>(next);
return true;
}
void TextEditEngine::ReplaceText(std::u16string text, uint32_t cursor) {
ClampText(&text, m_max_length);
m_text = std::move(text);
m_cursor = NormalizeCursor(m_text, cursor);
}
void TextEditEngine::SetCursor(uint32_t cursor) {
m_cursor = NormalizeCursor(m_text, cursor);
}
} // namespace Libs::ImeCommon
+159
View File
@@ -0,0 +1,159 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_LIBS_IMECOMMON_H_
#define EMULATOR_INCLUDE_EMULATOR_LIBS_IMECOMMON_H_
#include "common/abi.h"
#include <cstddef>
#include <cstdint>
#include <string>
#include <string_view>
namespace Libs::ImeCommon {
constexpr uint32_t MAX_TEXT_LENGTH = 2048;
constexpr uint32_t OPTION_MULTILINE = 0x00000001;
constexpr uint32_t OPTION_NO_AUTO_CAPITALIZE = 0x00000002;
constexpr uint32_t OPTION_PASSWORD = 0x00000004;
constexpr uint32_t OPTION_EXT_KEYBOARD = 0x00000010;
constexpr uint32_t OPTION_FIXED_POSITION = 0x00000040;
constexpr uint32_t OPTION_DISABLE_POSITION_ADJUST = 0x00000800;
constexpr uint32_t OPTION_EXPANDED_PREEDIT = 0x00001000;
constexpr uint32_t OPTION_USE_OVER_2K = 0x00004000;
constexpr uint32_t EXT_OPTION_HIDE_KEY_PANEL = 0x00000400;
constexpr uint32_t DISABLE_DEVICE_CONTROLLER = 0x00000001;
constexpr uint32_t DISABLE_DEVICE_EXT_KEYBOARD = 0x00000002;
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 Color {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
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;
};
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 ExtKeyboardFilter = int(KYTY_SYSV_ABI*)(const Keycode* source_keycode, uint16_t* out_keycode,
uint32_t* out_status, void* reserved);
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];
};
enum class ExternalAction : uint8_t {
None,
Text,
Backspace,
MoveLeft,
MoveRight,
Cancel,
Accept,
Newline,
};
struct ExternalInput {
Keycode key {};
ExternalAction action = ExternalAction::None;
std::u16string text;
};
struct VisualState {
bool active;
uint64_t revision;
};
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;
};
using VisibilityCallback = void (*)(bool visible, uint64_t generation);
struct EditDelta {
uint32_t index = 0;
int32_t length = 0;
};
class TextEditEngine {
public:
void Reset(Type type, uint32_t option, uint32_t max_length, std::u16string text);
bool Insert(std::u16string_view text, EditDelta* edit = nullptr);
bool Backspace(EditDelta* edit = nullptr);
bool MoveCursor(int delta);
void ReplaceText(std::u16string text, uint32_t cursor);
void SetCursor(uint32_t cursor);
[[nodiscard]] Type GetType() const { return m_type; }
[[nodiscard]] uint32_t GetOption() const { return m_option; }
[[nodiscard]] uint32_t GetMaxLength() const { return m_max_length; }
[[nodiscard]] uint32_t GetCursor() const { return m_cursor; }
[[nodiscard]] const std::u16string& GetText() const { return m_text; }
private:
Type m_type = Type::Default;
uint32_t m_option = 0;
uint32_t m_max_length = 0;
uint32_t m_cursor = 0;
std::u16string m_text;
};
[[nodiscard]] bool IsValidUtf16(std::u16string_view text);
[[nodiscard]] bool IsValidInputText(std::u16string_view text, bool multiline);
[[nodiscard]] bool IsAllowedInput(char16_t value, Type type, uint32_t option);
[[nodiscard]] uint32_t NormalizeCursor(std::u16string_view text, uint32_t cursor);
void ClampText(std::u16string* text, uint32_t limit);
[[nodiscard]] EditDelta ComputeEditDelta(std::u16string_view before, std::u16string_view after);
[[nodiscard]] bool RunTextFilter(TextFilter filter, const std::u16string& source,
uint32_t output_capacity, std::u16string* output);
[[nodiscard]] bool ApplyKeyboardFilterOutput(ExternalInput* input, uint16_t keycode,
uint32_t status, bool multiline);
} // namespace Libs::ImeCommon
#endif // EMULATOR_INCLUDE_EMULATOR_LIBS_IMECOMMON_H_
+19 -205
View File
@@ -53,9 +53,8 @@ struct State {
ExtendedParam extended {}; ExtendedParam extended {};
bool input_changed = false; bool input_changed = false;
bool commit_pending = false; bool commit_pending = false;
uint32_t cursor = 0;
std::u16string original_text; std::u16string original_text;
std::u16string current_text; ImeCommon::TextEditEngine editor;
std::u16string title; std::u16string title;
std::u16string placeholder; std::u16string placeholder;
std::vector<ExternalInput> external_inputs; std::vector<ExternalInput> external_inputs;
@@ -71,8 +70,6 @@ bool AllZero(const int8_t* data, size_t size) {
return std::all_of(data, data + size, [](int8_t value) { return value == 0; }); return std::all_of(data, data + size, [](int8_t value) { return value == 0; });
} }
bool IsValidUtf16(std::u16string_view text);
bool ReadBounded(const char16_t* text, uint32_t limit, std::u16string* out) { bool ReadBounded(const char16_t* text, uint32_t limit, std::u16string* out) {
out->clear(); out->clear();
if (text == nullptr) { if (text == nullptr) {
@@ -82,7 +79,7 @@ bool ReadBounded(const char16_t* text, uint32_t limit, std::u16string* out) {
for (uint32_t i = 0; i <= limit; ++i) { for (uint32_t i = 0; i <= limit; ++i) {
const char16_t value = text[i]; const char16_t value = text[i];
if (value == u'\0') { if (value == u'\0') {
return IsValidUtf16(*out); return ImeCommon::IsValidUtf16(*out);
} }
if (i == limit) { if (i == limit) {
return false; return false;
@@ -92,128 +89,6 @@ bool ReadBounded(const char16_t* text, uint32_t limit, std::u16string* out) {
return false; return false;
} }
bool IsValidUtf16(std::u16string_view text) {
for (size_t i = 0; i < text.size(); i++) {
const char16_t current = text[i];
if (current >= 0xd800 && current <= 0xdbff) {
if (++i >= text.size() || text[i] < 0xdc00 || text[i] > 0xdfff) {
return false;
}
} else if (current >= 0xdc00 && current <= 0xdfff) {
return false;
}
}
return true;
}
bool IsAllowedInput(char16_t value, Type type, uint32_t option) {
if (value == u'\r') {
return false;
}
if (value == u'\n') {
return (option & OPTION_MULTILINE) != 0;
}
if (value == u'\0') {
return false;
}
if (type == Type::Number) {
return (value >= u'0' && value <= u'9') || value == u',' || value == u'-' || value == u'.';
}
if (type == Type::BasicLatin) {
return value >= u' ' && value <= u'~';
}
return true;
}
char16_t HidCharacter(uint16_t keycode, uint32_t status) {
const bool shift = (status & 0x00002200) != 0;
const bool caps = (status & 0x00020000) != 0;
if (keycode >= 4 && keycode <= 29) {
const bool upper = shift != caps;
return static_cast<char16_t>((upper ? u'A' : u'a') + keycode - 4);
}
if (keycode >= 30 && keycode <= 39) {
static constexpr char16_t plain[] = u"1234567890";
static constexpr char16_t shifted[] = u"!@#$%^&*()";
return (shift ? shifted : plain)[keycode - 30];
}
if (keycode == 44) {
return u' ';
}
if (keycode >= 45 && keycode <= 56) {
static constexpr char16_t plain[] = u"-=[]\\#;'`,./";
static constexpr char16_t shifted[] = u"_+{}|~:\"~<>?";
return (shift ? shifted : plain)[keycode - 45];
}
if (keycode >= 89 && keycode <= 98) {
static constexpr char16_t keypad[] = u"1234567890";
return keypad[keycode - 89];
}
if (keycode == 99) {
return u'.';
}
return u'\0';
}
bool ApplyKeyboardFilterOutput(ExternalInput* input, uint16_t keycode, uint32_t status,
bool multiline) {
constexpr uint32_t KEYCODE_VALID = 0x00000001;
constexpr uint32_t CHARACTER_VALID = 0x00000002;
if (keycode == input->key.keycode && status == input->key.status) {
return true;
}
if ((status & KEYCODE_VALID) == 0 || keycode == 0) {
return input->action == ExternalAction::Text && (status & CHARACTER_VALID) != 0;
}
input->key.keycode = keycode;
input->key.status = status;
input->text.clear();
switch (keycode) {
case 40:
case 88:
case 158:
input->action = multiline ? ExternalAction::Newline : ExternalAction::Accept;
break;
case 41: input->action = ExternalAction::Cancel; break;
case 42:
case 187: input->action = ExternalAction::Backspace; break;
case 43:
case 186: input->action = ExternalAction::None; break;
case 79: input->action = ExternalAction::MoveRight; break;
case 80: input->action = ExternalAction::MoveLeft; break;
default: {
const char16_t character = HidCharacter(keycode, status);
if (character == u'\0') {
return false;
}
input->action = ExternalAction::Text;
input->key.character = character;
input->text.push_back(character);
break;
}
}
return true;
}
void ClampText(std::u16string* text, uint32_t limit) {
if (text->size() <= limit) {
return;
}
text->resize(limit);
if (!text->empty() && text->back() >= 0xd800 && text->back() <= 0xdbff) {
text->pop_back();
}
}
uint32_t NormalizeCursor(std::u16string_view text, uint32_t cursor) {
cursor = std::min<uint32_t>(cursor, static_cast<uint32_t>(text.size()));
if (cursor > 0 && cursor < text.size() && text[cursor - 1] >= 0xd800 &&
text[cursor - 1] <= 0xdbff && text[cursor] >= 0xdc00 && text[cursor] <= 0xdfff) {
cursor++;
}
return cursor;
}
void WriteGuestText(const State& state, const std::u16string& text) { void WriteGuestText(const State& state, const std::u16string& text) {
if (state.param.input_text_buffer == nullptr) { if (state.param.input_text_buffer == nullptr) {
return; return;
@@ -355,7 +230,7 @@ void ApplyFilterAndCommit() {
return; return;
} }
filter = g_state.input_changed ? g_state.param.filter : nullptr; filter = g_state.input_changed ? g_state.param.filter : nullptr;
source = g_state.current_text; source = g_state.editor.GetText();
max_length = g_state.param.max_text_length; max_length = g_state.param.max_text_length;
generation = g_state.generation; generation = g_state.generation;
revision = g_state.revision; revision = g_state.revision;
@@ -363,14 +238,10 @@ void ApplyFilterAndCommit() {
} }
if (filter != nullptr) { if (filter != nullptr) {
std::vector<char16_t> output(IME_DIALOG_MAX_TEXT_LENGTH + 1, u'\0'); std::u16string filtered;
uint32_t output_length = IME_DIALOG_MAX_TEXT_LENGTH; if (ImeCommon::RunTextFilter(filter, source, IME_DIALOG_MAX_TEXT_LENGTH, &filtered)) {
if (filter(output.data(), &output_length, source.c_str(), source = std::move(filtered);
static_cast<uint32_t>(source.size())) == 0 && ImeCommon::ClampText(&source, max_length);
output_length <= IME_DIALOG_MAX_TEXT_LENGTH &&
IsValidUtf16(std::u16string_view(output.data(), output_length))) {
source.assign(output.data(), output.data() + output_length);
ClampText(&source, max_length);
} }
} }
@@ -386,13 +257,12 @@ void ApplyFilterAndCommit() {
return; return;
} }
if (!g_state.input_changed) { if (!g_state.input_changed) {
g_state.current_text = std::move(source); g_state.editor.ReplaceText(std::move(source), g_state.editor.GetCursor());
g_state.cursor = NormalizeCursor(g_state.current_text, g_state.cursor);
} }
const auto& committed = const auto& committed =
g_state.status == Status::Finished && g_state.end_status != EndStatus::Ok g_state.status == Status::Finished && g_state.end_status != EndStatus::Ok
? g_state.original_text ? g_state.original_text
: g_state.current_text; : g_state.editor.GetText();
WriteGuestText(g_state, committed); WriteGuestText(g_state, committed);
g_state.commit_pending = false; g_state.commit_pending = false;
} }
@@ -451,8 +321,8 @@ void ApplyExternalInputs() {
uint16_t output_keycode = input.key.keycode; uint16_t output_keycode = input.key.keycode;
uint32_t output_status = input.key.status; uint32_t output_status = input.key.status;
if (filter(&input.key, &output_keycode, &output_status, nullptr) == 0) { if (filter(&input.key, &output_keycode, &output_status, nullptr) == 0) {
accepted = accepted = ImeCommon::ApplyKeyboardFilterOutput(&input, output_keycode,
ApplyKeyboardFilterOutput(&input, output_keycode, output_status, multiline); output_status, multiline);
} }
} }
if (!accepted) { if (!accepted) {
@@ -528,9 +398,9 @@ int KYTY_SYSV_ABI ImeDialogInit(const Param* param, const ExtendedParam* extende
if (extended != nullptr) { if (extended != nullptr) {
g_state.extended = *extended; g_state.extended = *extended;
} }
g_state.original_text = initial; g_state.original_text = initial;
g_state.current_text = std::move(initial); g_state.editor.Reset(param->type, param->option, param->max_text_length,
g_state.cursor = static_cast<uint32_t>(g_state.current_text.size()); std::move(initial));
g_state.title = std::move(title); g_state.title = std::move(title);
g_state.placeholder = std::move(placeholder); g_state.placeholder = std::move(placeholder);
g_state.commit_pending = true; g_state.commit_pending = true;
@@ -664,7 +534,7 @@ bool GetHostSnapshot(HostSnapshot* snapshot) {
snapshot->enter_label = g_state.param.enter_label; snapshot->enter_label = g_state.param.enter_label;
snapshot->option = g_state.param.option; snapshot->option = g_state.param.option;
snapshot->max_text_length = g_state.param.max_text_length; snapshot->max_text_length = g_state.param.max_text_length;
snapshot->cursor = g_state.cursor; snapshot->cursor = g_state.editor.GetCursor();
snapshot->disable_device = g_state.extended.disable_device; snapshot->disable_device = g_state.extended.disable_device;
snapshot->key_panel_visible = (g_state.param.option & OPTION_EXT_KEYBOARD) == 0 || snapshot->key_panel_visible = (g_state.param.option & OPTION_EXT_KEYBOARD) == 0 ||
(g_state.extended.option & 0x00000400) == 0; (g_state.extended.option & 0x00000400) == 0;
@@ -674,7 +544,7 @@ bool GetHostSnapshot(HostSnapshot* snapshot) {
snapshot->vertical_alignment = g_state.param.vertical_alignment; snapshot->vertical_alignment = g_state.param.vertical_alignment;
ComputePanelSize(g_state.param, &g_state.extended, &snapshot->panel_width, ComputePanelSize(g_state.param, &g_state.extended, &snapshot->panel_width,
&snapshot->panel_height); &snapshot->panel_height);
snapshot->text = g_state.current_text; snapshot->text = g_state.editor.GetText();
snapshot->title = g_state.title; snapshot->title = g_state.title;
snapshot->placeholder = g_state.placeholder; snapshot->placeholder = g_state.placeholder;
return true; return true;
@@ -682,38 +552,9 @@ bool GetHostSnapshot(HostSnapshot* snapshot) {
bool HostInsertText(uint64_t generation, std::u16string_view text) { bool HostInsertText(uint64_t generation, std::u16string_view text) {
std::scoped_lock lock(g_mutex); std::scoped_lock lock(g_mutex);
if (!MatchRunningGeneration(generation) || text.empty()) { if (!MatchRunningGeneration(generation) || !g_state.editor.Insert(text)) {
return false; return false;
} }
if (!IsValidUtf16(text)) {
return false;
}
std::u16string allowed;
allowed.reserve(text.size());
for (const char16_t value: text) {
if (IsAllowedInput(value, g_state.param.type, g_state.param.option)) {
allowed.push_back(value);
}
}
if (allowed.empty()) {
return false;
}
const size_t available = g_state.param.max_text_length - g_state.current_text.size();
if (available == 0) {
return false;
}
std::u16string insertion(std::u16string_view(allowed).substr(0, available));
if (insertion.size() < allowed.size() && !insertion.empty() && insertion.back() >= 0xd800 &&
insertion.back() <= 0xdbff) {
insertion.pop_back();
}
if (insertion.empty()) {
return false;
}
std::u16string candidate = g_state.current_text;
candidate.insert(g_state.cursor, insertion);
g_state.current_text = std::move(candidate);
g_state.cursor += static_cast<uint32_t>(insertion.size());
g_state.input_changed = true; g_state.input_changed = true;
g_state.commit_pending = true; g_state.commit_pending = true;
return true; return true;
@@ -721,17 +562,9 @@ bool HostInsertText(uint64_t generation, std::u16string_view text) {
bool HostBackspace(uint64_t generation) { bool HostBackspace(uint64_t generation) {
std::scoped_lock lock(g_mutex); std::scoped_lock lock(g_mutex);
if (!MatchRunningGeneration(generation) || g_state.cursor == 0) { if (!MatchRunningGeneration(generation) || !g_state.editor.Backspace()) {
return false; return false;
} }
uint32_t first = g_state.cursor - 1;
if (first > 0 && g_state.current_text[first] >= 0xdc00 &&
g_state.current_text[first] <= 0xdfff && g_state.current_text[first - 1] >= 0xd800 &&
g_state.current_text[first - 1] <= 0xdbff) {
first--;
}
g_state.current_text.erase(first, g_state.cursor - first);
g_state.cursor = first;
g_state.input_changed = true; g_state.input_changed = true;
g_state.commit_pending = true; g_state.commit_pending = true;
return true; return true;
@@ -739,26 +572,7 @@ bool HostBackspace(uint64_t generation) {
bool HostMoveCursor(uint64_t generation, int delta) { bool HostMoveCursor(uint64_t generation, int delta) {
std::scoped_lock lock(g_mutex); std::scoped_lock lock(g_mutex);
if (!MatchRunningGeneration(generation) || delta == 0) { return MatchRunningGeneration(generation) && g_state.editor.MoveCursor(delta);
return false;
}
int next = std::clamp(static_cast<int>(g_state.cursor) + delta, 0,
static_cast<int>(g_state.current_text.size()));
if (delta < 0 && next > 0 && next < static_cast<int>(g_state.current_text.size()) &&
g_state.current_text[next] >= 0xdc00 && g_state.current_text[next] <= 0xdfff &&
g_state.current_text[next - 1] >= 0xd800 && g_state.current_text[next - 1] <= 0xdbff) {
next--;
} else if (delta > 0 && next > 0 && next < static_cast<int>(g_state.current_text.size()) &&
g_state.current_text[next - 1] >= 0xd800 &&
g_state.current_text[next - 1] <= 0xdbff && g_state.current_text[next] >= 0xdc00 &&
g_state.current_text[next] <= 0xdfff) {
next++;
}
if (next == static_cast<int>(g_state.cursor)) {
return false;
}
g_state.cursor = static_cast<uint32_t>(next);
return true;
} }
bool HostAccept(uint64_t generation) { bool HostAccept(uint64_t generation) {
+25 -99
View File
@@ -1,7 +1,7 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_LIBS_IMEDIALOG_H_ #ifndef EMULATOR_INCLUDE_EMULATOR_LIBS_IMEDIALOG_H_
#define EMULATOR_INCLUDE_EMULATOR_LIBS_IMEDIALOG_H_ #define EMULATOR_INCLUDE_EMULATOR_LIBS_IMEDIALOG_H_
#include "common/abi.h" #include "libs/imeCommon.h"
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
@@ -10,53 +10,43 @@
namespace Libs::Dialog::ImeDialog { namespace Libs::Dialog::ImeDialog {
constexpr uint32_t IME_DIALOG_MAX_TEXT_LENGTH = 2048; constexpr uint32_t IME_DIALOG_MAX_TEXT_LENGTH = ImeCommon::MAX_TEXT_LENGTH;
constexpr uint32_t IME_DIALOG_MAX_TITLE_LENGTH = 128; constexpr uint32_t IME_DIALOG_MAX_TITLE_LENGTH = 128;
constexpr uint32_t IME_DIALOG_MAX_PLACEHOLDER_LENGTH = 64; constexpr uint32_t IME_DIALOG_MAX_PLACEHOLDER_LENGTH = 64;
enum class Status : uint32_t { None = 0, Running = 1, Finished = 2 }; enum class Status : uint32_t { None = 0, Running = 1, Finished = 2 };
enum class EndStatus : uint32_t { Ok = 0, UserCanceled = 1, Aborted = 2 }; enum class EndStatus : uint32_t { Ok = 0, UserCanceled = 1, Aborted = 2 };
enum class Type : uint32_t { Default = 0, BasicLatin = 1, Url = 2, Mail = 3, Number = 4 }; using Type = ImeCommon::Type;
enum class EnterLabel : uint32_t { Default = 0, Send = 1, Search = 2, Go = 3 }; using EnterLabel = ImeCommon::EnterLabel;
enum class Alignment : uint32_t { Start = 0, Center = 1, End = 2 }; using Alignment = ImeCommon::Alignment;
enum Option : uint32_t { enum Option : uint32_t {
OPTION_MULTILINE = 0x00000001, OPTION_MULTILINE = ImeCommon::OPTION_MULTILINE,
OPTION_NO_AUTO_CAPITALIZE = 0x00000002, OPTION_NO_AUTO_CAPITALIZE = ImeCommon::OPTION_NO_AUTO_CAPITALIZE,
OPTION_PASSWORD = 0x00000004, OPTION_PASSWORD = ImeCommon::OPTION_PASSWORD,
OPTION_LANGUAGES_FORCED = 0x00000008, OPTION_LANGUAGES_FORCED = 0x00000008,
OPTION_EXT_KEYBOARD = 0x00000010, OPTION_EXT_KEYBOARD = ImeCommon::OPTION_EXT_KEYBOARD,
OPTION_NO_LEARNING = 0x00000020, OPTION_NO_LEARNING = 0x00000020,
OPTION_FIXED_POSITION = 0x00000040, OPTION_FIXED_POSITION = ImeCommon::OPTION_FIXED_POSITION,
OPTION_DISABLE_COPY_PASTE = 0x00000080, OPTION_DISABLE_COPY_PASTE = 0x00000080,
OPTION_DISABLE_RESUME = 0x00000100, OPTION_DISABLE_RESUME = 0x00000100,
OPTION_DISABLE_AUTO_SPACE = 0x00000200, OPTION_DISABLE_AUTO_SPACE = 0x00000200,
OPTION_DISABLE_POSITION_ADJ = 0x00000800, OPTION_DISABLE_POSITION_ADJ = ImeCommon::OPTION_DISABLE_POSITION_ADJUST,
OPTION_EXPANDED_PREEDIT = 0x00001000, OPTION_EXPANDED_PREEDIT = ImeCommon::OPTION_EXPANDED_PREEDIT,
OPTION_JAPANESE_CAPS_LOCK = 0x00002000, OPTION_JAPANESE_CAPS_LOCK = 0x00002000,
OPTION_USE_OVER_2K = 0x00004000, OPTION_USE_OVER_2K = ImeCommon::OPTION_USE_OVER_2K,
}; };
enum DisableDevice : uint32_t { enum DisableDevice : uint32_t {
DISABLE_DEVICE_CONTROLLER = 0x00000001, DISABLE_DEVICE_CONTROLLER = ImeCommon::DISABLE_DEVICE_CONTROLLER,
DISABLE_DEVICE_EXT_KEYBOARD = 0x00000002, DISABLE_DEVICE_EXT_KEYBOARD = ImeCommon::DISABLE_DEVICE_EXT_KEYBOARD,
DISABLE_DEVICE_REMOTE_OSK = 0x00000004, DISABLE_DEVICE_REMOTE_OSK = 0x00000004,
}; };
struct Color { using Color = ImeCommon::Color;
uint8_t r; using Keycode = ImeCommon::Keycode;
uint8_t g; using TextFilter = ImeCommon::TextFilter;
uint8_t b; using ExtKeyboardFilter = ImeCommon::ExtKeyboardFilter;
uint8_t a;
};
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 ExtKeyboardFilter = int(KYTY_SYSV_ABI*)(const Keycode* source_keycode, uint16_t* out_keycode,
uint32_t* out_status, void* reserved);
struct Param { struct Param {
int32_t user_id; int32_t user_id;
@@ -82,24 +72,7 @@ struct Result {
int8_t reserved[12]; int8_t reserved[12];
}; };
struct ExtendedParam { using ExtendedParam = ImeCommon::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 PositionAndForm { struct PositionAndForm {
uint32_t type; uint32_t type;
@@ -111,32 +84,8 @@ struct PositionAndForm {
uint32_t height; uint32_t height;
}; };
struct Keycode { using ExternalAction = ImeCommon::ExternalAction;
uint16_t keycode; using ExternalInput = ImeCommon::ExternalInput;
char16_t character;
uint32_t status;
uint32_t type;
int32_t user_id;
uint32_t resource_id;
uint64_t timestamp;
};
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(Param) == 0x60); static_assert(sizeof(Param) == 0x60);
static_assert(offsetof(Param, input_text_buffer) == 0x28); static_assert(offsetof(Param, input_text_buffer) == 0x28);
@@ -147,32 +96,9 @@ static_assert(offsetof(ExtendedParam, additional_dictionary_path) == 0x30);
static_assert(sizeof(PositionAndForm) == 0x1c); static_assert(sizeof(PositionAndForm) == 0x1c);
static_assert(sizeof(Keycode) == 0x20); static_assert(sizeof(Keycode) == 0x20);
struct VisualState { using VisualState = ImeCommon::VisualState;
bool active; using HostSnapshot = ImeCommon::HostSnapshot;
uint64_t revision; using VisibilityCallback = ImeCommon::VisibilityCallback;
};
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;
std::u16string title;
std::u16string placeholder;
};
using VisibilityCallback = void (*)(bool visible, uint64_t generation);
int KYTY_SYSV_ABI ImeDialogGetPanelSize(const Param* param, uint32_t* width, uint32_t* height); int KYTY_SYSV_ABI ImeDialogGetPanelSize(const Param* param, uint32_t* width, uint32_t* height);
int KYTY_SYSV_ABI ImeDialogGetPanelSizeExtended(const Param* param, const ExtendedParam* extended, int KYTY_SYSV_ABI ImeDialogGetPanelSizeExtended(const Param* param, const ExtendedParam* extended,
+5 -4
View File
@@ -237,15 +237,16 @@ private:
static Network* g_net = nullptr; static Network* g_net = nullptr;
KYTY_SUBSYSTEM_INIT(Network) { void Initialize() {
EXIT_IF(g_net != nullptr); EXIT_IF(g_net != nullptr);
g_net = new Network; g_net = new Network;
} }
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Network) {} void Shutdown() {
delete g_net;
KYTY_SUBSYSTEM_DESTROY(Network) {} g_net = nullptr;
}
int Network::PoolCreate(const char* name, int size) { int Network::PoolCreate(const char* name, int size) {
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
+8 -3
View File
@@ -3,11 +3,16 @@
#include "common/abi.h" #include "common/abi.h"
#include "common/common.h" #include "common/common.h"
#include "common/subsystems.h"
namespace Libs::Network { namespace Libs::Network {
KYTY_SUBSYSTEM_DEFINE(Network); void Initialize();
void Shutdown();
struct Lifecycle {
static constexpr const char* name = "Network";
static constexpr auto initialize = Libs::Network::Initialize;
static constexpr auto shutdown = Libs::Network::Shutdown;
};
namespace Net { namespace Net {
-9
View File
@@ -2,21 +2,12 @@
#include "common/abi.h" #include "common/abi.h"
#include "common/dateTime.h" #include "common/dateTime.h"
#include "common/subsystems.h"
#include "loader/timer.h" #include "loader/timer.h"
namespace Loader::Timer { namespace Loader::Timer {
static Common::Timer g_timer; static Common::Timer g_timer;
KYTY_SUBSYSTEM_INIT(Timer) {
Start();
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Timer) {}
KYTY_SUBSYSTEM_DESTROY(Timer) {}
void Start() { void Start() {
g_timer.Start(); g_timer.Start();
} }
+5 -4
View File
@@ -4,18 +4,19 @@
#include "common/abi.h" #include "common/abi.h"
#include "common/common.h" #include "common/common.h"
#include "common/dateTime.h" #include "common/dateTime.h"
#include "common/subsystems.h"
namespace Loader::Timer { namespace Loader::Timer {
KYTY_SUBSYSTEM_DEFINE(Timer);
void Start(); void Start();
double GetTimeMs(); double GetTimeMs();
Common::Time GetTime(); Common::Time GetTime();
uint64_t GetCounter(); uint64_t GetCounter();
uint64_t GetFrequency(); uint64_t GetFrequency();
struct Lifecycle {
static constexpr const char* name = "Timer";
static constexpr auto initialize = Loader::Timer::Start;
};
} // namespace Loader::Timer } // namespace Loader::Timer
#endif /* EMULATOR_INCLUDE_EMULATOR_LOADER_TIMER_H_ */ #endif /* EMULATOR_INCLUDE_EMULATOR_LOADER_TIMER_H_ */
+3 -21
View File
@@ -1,5 +1,4 @@
#include "common/common.h" #include "common/common.h"
#include "common/commonSubsystem.h"
#include "common/dateTime.h" #include "common/dateTime.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/file.h" #include "common/file.h"
@@ -7,6 +6,7 @@
#include "common/platform/sysDbg.h" #include "common/platform/sysDbg.h"
#include "common/stringUtils.h" #include "common/stringUtils.h"
#include "common/threads.h" #include "common/threads.h"
#include "common/virtualMemory.h"
#include "emulator.h" #include "emulator.h"
#include "kytyGitVersion.h" #include "kytyGitVersion.h"
@@ -275,46 +275,28 @@ static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_he
} }
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
auto& slist = *SubsystemsList::Instance(); VirtualMemory::Init();
InitializeThreads();
slist.SetArgs(argc, argv);
auto* core = CommonSubsystem::Instance();
auto* threads = ThreadsSubsystem::Instance();
slist.Add(core, {});
slist.Add(threads, {core});
if (!slist.InitAll(false)) {
::printf("Failed to initialize '%s' subsystem: %s\n", slist.GetFailName(),
slist.GetFailMsg());
return 1;
}
RunOptions options; RunOptions options;
bool show_help = false; bool show_help = false;
if (argc < 2) { if (argc < 2) {
PrintUsage(); PrintUsage();
slist.DestroyAll(false);
return 0; return 0;
} }
if (!ParseArgs(argc, argv, options, show_help)) { if (!ParseArgs(argc, argv, options, show_help)) {
PrintUsage(); PrintUsage();
slist.DestroyAll(false);
return 1; return 1;
} }
if (show_help) { if (show_help) {
PrintUsage(); PrintUsage();
slist.DestroyAll(false);
return 0; return 0;
} }
Run(options); Run(options);
slist.DestroyAll(false);
return 0; return 0;
} }
+6 -4
View File
@@ -1,6 +1,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/emulatorConfig.h" #include "common/emulatorConfig.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/subsystems.h"
#include "common/threads.h" #include "common/threads.h"
#include "gpu_test_shaders/gpu_test_ms_depth_spv.h" #include "gpu_test_shaders/gpu_test_ms_depth_spv.h"
#include "graphics/guest_gpu/command_processor/commandProcessor.h" #include "graphics/guest_gpu/command_processor/commandProcessor.h"
@@ -706,13 +707,14 @@ void Require(const char* shader_name, const char* stage, bool value, const std::
void EnsureConfigInitialized() { void EnsureConfigInitialized() {
static bool config_initialized = false; static bool config_initialized = false;
if (!config_initialized) { if (!config_initialized) {
Common::ThreadsSubsystem::Instance()->Init(nullptr); static Common::Subsystems subsystems;
Config::ConfigSubsystem::Instance()->Init(nullptr); Common::InitializeThreads();
subsystems.Initialize<Config::Lifecycle>();
Config::ConfigOptions options; Config::ConfigOptions options;
options.printf_direction = Config::OutputDirection::Silent; options.printf_direction = Config::OutputDirection::Silent;
Config::Load(options); Config::Load(options);
Log::LogSubsystem::Instance()->Init(nullptr); subsystems.Initialize<Log::Lifecycle>();
Libs::LibKernel::Memory::MemorySubsystem::Instance()->Init(nullptr); subsystems.Initialize<Libs::LibKernel::Memory::Lifecycle>();
config_initialized = true; config_initialized = true;
} }
} }
+6 -20
View File
@@ -1,4 +1,3 @@
#include "common/commonSubsystem.h"
#include "common/emulatorConfig.h" #include "common/emulatorConfig.h"
#include "common/file.h" #include "common/file.h"
#include "common/logging/log.h" #include "common/logging/log.h"
@@ -97,28 +96,16 @@ void InitSubsystems() {
return; return;
} }
static char arg0[] = "virtual_memory_allocation_tests"; static Common::Subsystems subsystems;
static char* argv[] = {arg0}; Common::VirtualMemory::Init();
Common::InitializeThreads();
auto* slist = Common::SubsystemsList::Instance(); subsystems.Initialize<Config::Lifecycle>();
auto* core = Common::CommonSubsystem::Instance();
auto* config = Config::ConfigSubsystem::Instance();
auto* log = Log::LogSubsystem::Instance();
auto* memory = Libs::LibKernel::Memory::MemorySubsystem::Instance();
auto* thread = Common::ThreadsSubsystem::Instance();
slist->SetArgs(1, argv);
slist->Add(thread, {});
slist->Add(core, {});
slist->Add(config, {core});
Check("InitSubsystems", slist->InitAll(false), "failed to initialize base subsystems");
Config::ConfigOptions options; Config::ConfigOptions options;
options.printf_direction = Config::OutputDirection::Silent; options.printf_direction = Config::OutputDirection::Silent;
Config::Load(options); Config::Load(options);
slist->Add(log, {core, config}); subsystems.Initialize<Log::Lifecycle>();
Check("InitSubsystems", slist->InitAll(false), "failed to initialize logging subsystem");
const auto param_json = std::filesystem::temp_directory_path() / const auto param_json = std::filesystem::temp_directory_path() /
("kyty_virtual_memory_" + ("kyty_virtual_memory_" +
@@ -140,8 +127,7 @@ void InitSubsystems() {
"failed to read flexible memory size from param.json"); "failed to read flexible memory size from param.json");
Libs::LibKernel::Memory::SetFlexibleMemorySize(flexible_memory_size); Libs::LibKernel::Memory::SetFlexibleMemorySize(flexible_memory_size);
slist->Add(memory, {core, log, thread}); subsystems.Initialize<Libs::LibKernel::Memory::Lifecycle>();
Check("InitSubsystems", slist->InitAll(false), "failed to initialize memory subsystem");
initialized = true; initialized = true;
} }
+5 -3
View File
@@ -1,6 +1,7 @@
#include "common/emulatorConfig.h" #include "common/emulatorConfig.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/stringUtils.h" #include "common/stringUtils.h"
#include "common/subsystems.h"
#include "common/threads.h" #include "common/threads.h"
#include "graphics/guest_gpu/hardwareContext.h" #include "graphics/guest_gpu/hardwareContext.h"
#include "graphics/guest_gpu/pm4.h" #include "graphics/guest_gpu/pm4.h"
@@ -344,12 +345,13 @@ void SetIdentityInterpolatorSettings(ShaderPixelInputInfo* input_info) {
void EnsureConfigInitialized() { void EnsureConfigInitialized() {
static bool config_initialized = false; static bool config_initialized = false;
if (!config_initialized) { if (!config_initialized) {
Common::ThreadsSubsystem::Instance()->Init(nullptr); static Common::Subsystems subsystems;
Config::ConfigSubsystem::Instance()->Init(nullptr); Common::InitializeThreads();
subsystems.Initialize<Config::Lifecycle>();
Config::ConfigOptions options; Config::ConfigOptions options;
options.printf_direction = Config::OutputDirection::Silent; options.printf_direction = Config::OutputDirection::Silent;
Config::Load(options); Config::Load(options);
Log::LogSubsystem::Instance()->Init(nullptr); subsystems.Initialize<Log::Lifecycle>();
ShaderInit(); ShaderInit();
config_initialized = true; config_initialized = true;
} }