refactor(subsystems&ime): RAII lifecycle

This commit is contained in:
nmzik
2026-08-11 16:12:38 +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) {
Log::WriteFatal(BuildFatalReport(title, text, file, line));
SubsystemsListSingleton::Instance()->ShutdownAll();
Subsystems::EmergencyShutdownActive();
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;
KYTY_SUBSYSTEM_INIT(Config) {
void Initialize() {
EXIT_IF(g_config != nullptr);
g_config = std::make_unique<ConfigOptions>();
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Config) {}
KYTY_SUBSYSTEM_DESTROY(Config) {}
void Shutdown() {
g_config.reset();
}
void Load(const ConfigOptions& cfg) {
EXIT_IF(g_config == nullptr);
+8 -2
View File
@@ -2,7 +2,6 @@
#define KYTY_COMMON_EMULATOR_CONFIG_H_
#include "common/common.h"
#include "common/subsystems.h"
#include <filesystem>
#include <string>
@@ -10,7 +9,14 @@
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 };
+2 -8
View File
@@ -149,7 +149,7 @@ void WriteFatal(fmt::text_style style, std::string_view text) {
Flush();
}
KYTY_SUBSYSTEM_INIT(Log) {
void Initialize() {
g_initialized = true;
switch (Config::GetPrintfDirection()) {
case Config::OutputDirection::Silent: g_direction = Direction::Silent; break;
@@ -161,13 +161,7 @@ KYTY_SUBSYSTEM_INIT(Log) {
SetupLogger();
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Log) {
Flush();
std::lock_guard lock(g_logger_mutex);
g_logger.reset();
}
KYTY_SUBSYSTEM_DESTROY(Log) {
void Shutdown() {
Flush();
std::lock_guard lock(g_logger_mutex);
g_logger.reset();
+9 -2
View File
@@ -2,7 +2,6 @@
#define KYTY_COMMON_LOGGING_LOG_H_
#include "common/common.h"
#include "common/subsystems.h"
#include <fmt/color.h>
#include <fmt/printf.h>
@@ -10,7 +9,15 @@
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 };
+5 -14
View File
@@ -1,7 +1,6 @@
#include "common/profiler.h"
#include "common/emulatorConfig.h"
#include "common/subsystems.h"
#include <algorithm>
#include <common/TracyProtocol.hpp>
@@ -55,13 +54,7 @@ void SetThreadName(const char* name) {
}
}
void Close() {
if (tracy::ProfilerAvailable()) {
tracy::ShutdownProfiler();
}
}
KYTY_SUBSYSTEM_INIT(Profiler) {
void Initialize() {
switch (Config::GetProfilerDirection()) {
case Config::ProfilerDirection::Network:
if (!tracy::ProfilerAvailable()) {
@@ -78,12 +71,10 @@ KYTY_SUBSYSTEM_INIT(Profiler) {
}
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Profiler) {
Close();
}
KYTY_SUBSYSTEM_DESTROY(Profiler) {
Close();
void Shutdown() {
if (tracy::ProfilerAvailable()) {
tracy::ShutdownProfiler();
}
}
} // namespace Profiler
+9 -2
View File
@@ -2,7 +2,6 @@
#define KYTY_COMMON_PROFILER_H_
#include "common/common.h"
#include "common/subsystems.h"
#include <cstdint>
#include <optional>
@@ -42,7 +41,15 @@ private:
void EndBlock();
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
+25 -214
View File
@@ -1,232 +1,43 @@
#include "common/subsystems.h"
#include "common/assert.h"
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <memory>
#include <string>
namespace Common {
class SubsystemPrivate {
public:
SubsystemPrivate() = default;
virtual ~SubsystemPrivate() = default;
static Subsystems* g_active_subsystems = nullptr;
KYTY_CLASS_NO_COPY(SubsystemPrivate);
Subsystems::Subsystems(bool print): m_print(print) {
m_active.reserve(16);
g_active_subsystems = this;
}
bool failed {false};
std::string fail_msg;
};
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;
Subsystems::~Subsystems() {
Destroy();
if (g_active_subsystems == this) {
g_active_subsystems = nullptr;
}
}
void Add(Subsystem* s, std::initializer_list<Subsystem*> deps) {
EXIT_IF(!s);
const char* name = s->Id();
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);
void Subsystems::Destroy() {
for (auto it = m_active.rbegin(); it != m_active.rend(); ++it) {
if (it->shutdown != nullptr) {
it->shutdown();
}
node->initialized = false;
}
m_active.clear();
}
bool InitAll(bool print_msg) {
while (SubsListStruct* n = FindNextToInitialize()) {
n->s->Init(&parent);
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;
void Subsystems::EmergencyShutdown() {
for (auto it = m_active.rbegin(); it != m_active.rend(); ++it) {
if (it->emergency_shutdown != nullptr) {
it->emergency_shutdown();
}
return true;
}
m_active.clear();
}
void DestroyAll(bool print_msg) {
for (SubsListStruct* n = last_init; n != nullptr; n = n->prev_init) {
n->s->Destroy(&parent);
n->initialized = false;
if (print_msg) {
printf("Destroyed: %s\n", n->name);
}
}
last_init = nullptr;
void Subsystems::EmergencyShutdownActive() {
if (g_active_subsystems != nullptr) {
g_active_subsystems->EmergencyShutdown();
}
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
+41 -70
View File
@@ -2,90 +2,61 @@
#define KYTY_COMMON_SUBSYSTEMS_H_
#include "common/common.h"
#include "common/singleton.h"
#include <initializer_list>
#include <memory>
#include <cstdio>
#include <vector>
namespace Common {
class Subsystem;
class SubsystemsListPrivate;
class SubsystemPrivate;
class SubsystemsList {
class Subsystems {
public:
SubsystemsList();
virtual ~SubsystemsList();
void SetArgs(int argc, char* argv[]);
using Callback = void (*)();
// void Add(Subsystem* s, const char* name, ...);
void Add(Subsystem* s, std::initializer_list<Subsystem*> deps);
explicit Subsystems(bool print = false);
~Subsystems();
bool InitAll(bool print_msg = false);
void DestroyAll(bool print_msg = false);
template <typename Lifecycle>
void Initialize() {
Lifecycle::initialize();
m_active.push_back({ShutdownCallback<Lifecycle>(), EmergencyCallback<Lifecycle>()});
if (m_print) {
std::printf("Initialized: %s\n", Lifecycle::name);
}
}
int* GetArgc();
char** GetArgv();
void Destroy();
void EmergencyShutdown();
[[nodiscard]] const char* GetFailName() const;
[[nodiscard]] const char* GetFailMsg() const;
static void EmergencyShutdownActive();
void ShutdownAll();
static SubsystemsList* Instance() { return Common::Singleton<SubsystemsList>::Instance(); }
KYTY_CLASS_NO_COPY(SubsystemsList);
KYTY_CLASS_NO_COPY(Subsystems);
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
#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 std::atomic<int> g_thread_counter = 0;
KYTY_SUBSYSTEM_INIT(Threads) {
void InitializeThreads() {
g_main_thread = std::this_thread::get_id();
g_main_thread_int = Thread::GetThreadIdUnique();
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Threads) {}
KYTY_SUBSYSTEM_DESTROY(Threads) {}
Thread::Thread(thread_func_t func, void* arg)
: m_thread(std::make_unique<ThreadPrivate>(func, arg)) {
while (!m_thread->started) {
+1 -2
View File
@@ -2,14 +2,13 @@
#define KYTY_COMMON_THREADS_H_
#include "common/common.h"
#include "common/subsystems.h"
#include <memory>
#include <string>
namespace Common {
KYTY_SUBSYSTEM_DEFINE(Threads);
void InitializeThreads();
using thread_func_t = void (*)(void*);
using wait_poll_func_t = void (*)();
+18 -36
View File
@@ -2,7 +2,6 @@
#include "common/abi.h"
#include "common/assert.h"
#include "common/commonSubsystem.h"
#include "common/emulatorConfig.h"
#include "common/file.h"
#include "common/logging/log.h"
@@ -43,7 +42,7 @@ static void KytyClose() {
LOGF("done!\n");
Common::SubsystemsListSingleton::Instance()->ShutdownAll();
Common::Subsystems::EmergencyShutdownActive();
}
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());
auto* slist = Common::SubsystemsList::Instance();
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);
subsystems.Initialize<Config::Lifecycle>();
Config::Load(cfg);
slist->Add(log, {core, config});
slist->InitAll(true);
subsystems.Initialize<Log::Lifecycle>();
if (Common::File::IsFileExisting(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});
slist->Add(controller, {core, log, config});
slist->Add(file_system, {core, log, pthread});
slist->Add(graphics, {core, log, pthread, memory, config, profiler, controller});
slist->Add(memory, {core, log});
slist->Add(network, {core, log, pthread});
slist->Add(profiler, {core, config});
slist->Add(pthread, {core, log, timer});
slist->Add(timer, {core, log});
slist->InitAll(true);
// Initialization order is explicit; destruction is automatic and reversed.
subsystems.Initialize<Loader::Timer::Lifecycle>();
subsystems.Initialize<Libs::LibKernel::PthreadLifecycle>();
subsystems.Initialize<Profiler::Lifecycle>();
subsystems.Initialize<Libs::Network::Lifecycle>();
subsystems.Initialize<Libs::LibKernel::Memory::Lifecycle>();
subsystems.Initialize<Libs::LibKernel::FileSystem::Lifecycle>();
subsystems.Initialize<Libs::Controller::Lifecycle>();
subsystems.Initialize<Libs::Audio::Lifecycle>();
subsystems.Initialize<Libs::Graphics::Lifecycle>();
}
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");
}
const auto param_json = options.app0_dir / "sce_sys" / "param.json";
Init(options.config, param_json);
const auto param_json = options.app0_dir / "sce_sys" / "param.json";
Common::Subsystems subsystems(true);
Init(options.config, param_json, subsystems);
ClearDebugTextureFolder();
+20 -122
View File
@@ -32,64 +32,21 @@ namespace DialogIme = Libs::Dialog::ImeDialog;
namespace Ime {
enum class Type : uint32_t { Default = 0, BasicLatin = 1, Url = 2, Mail = 3, Number = 4 };
enum class EnterLabel : uint32_t { Default = 0, Send = 1, Search = 2, Go = 3 };
enum class Alignment : uint32_t { Start = 0, Center = 1, End = 2 };
enum class ExternalAction : uint8_t {
None,
Text,
Backspace,
MoveLeft,
MoveRight,
Cancel,
Accept,
Newline,
};
using Type = ImeCommon::Type;
using EnterLabel = ImeCommon::EnterLabel;
using Alignment = ImeCommon::Alignment;
using ExternalAction = ImeCommon::ExternalAction;
using ExternalInput = ImeCommon::ExternalInput;
using HostSnapshot = ImeCommon::HostSnapshot;
struct Keycode {
uint16_t keycode = 0;
char16_t character = u'\0';
uint32_t status = 0;
uint32_t type = 0;
int32_t user_id = 0;
uint32_t resource_id = 0;
uint64_t timestamp = 0;
};
struct ExternalInput {
Keycode key;
ExternalAction action = ExternalAction::None;
std::u16string text;
};
struct HostSnapshot {
uint64_t generation = 0;
Type type = Type::Default;
EnterLabel enter_label = EnterLabel::Default;
uint32_t option = 0;
uint32_t max_text_length = 0;
uint32_t cursor = 0;
uint32_t disable_device = 0;
bool key_panel_visible = true;
float posx = 0.0f;
float posy = 0.0f;
Alignment horizontal_alignment = Alignment::Start;
Alignment vertical_alignment = Alignment::Start;
uint32_t panel_width = 0;
uint32_t panel_height = 0;
std::u16string text;
std::u16string title;
std::u16string placeholder;
};
constexpr uint32_t OPTION_MULTILINE = 0x00000001;
constexpr uint32_t OPTION_NO_AUTO_CAPITALIZE = 0x00000002;
constexpr uint32_t OPTION_PASSWORD = 0x00000004;
constexpr uint32_t OPTION_FIXED_POSITION = 0x00000040;
constexpr uint32_t OPTION_DISABLE_POSITION_ADJ = 0x00000800;
constexpr uint32_t OPTION_USE_OVER_2K = 0x00004000;
constexpr uint32_t DISABLE_DEVICE_CONTROLLER = 0x00000001;
constexpr uint32_t DISABLE_DEVICE_EXT_KEYBOARD = 0x00000002;
constexpr uint32_t OPTION_MULTILINE = ImeCommon::OPTION_MULTILINE;
constexpr uint32_t OPTION_NO_AUTO_CAPITALIZE = ImeCommon::OPTION_NO_AUTO_CAPITALIZE;
constexpr uint32_t OPTION_PASSWORD = ImeCommon::OPTION_PASSWORD;
constexpr uint32_t OPTION_FIXED_POSITION = ImeCommon::OPTION_FIXED_POSITION;
constexpr uint32_t OPTION_DISABLE_POSITION_ADJ = ImeCommon::OPTION_DISABLE_POSITION_ADJUST;
constexpr uint32_t OPTION_USE_OVER_2K = ImeCommon::OPTION_USE_OVER_2K;
constexpr uint32_t DISABLE_DEVICE_CONTROLLER = ImeCommon::DISABLE_DEVICE_CONTROLLER;
constexpr uint32_t DISABLE_DEVICE_EXT_KEYBOARD = ImeCommon::DISABLE_DEVICE_EXT_KEYBOARD;
constexpr uint64_t CORE_GENERATION_BIT = uint64_t {1} << 63;
uint64_t PackCoreGeneration(uint64_t generation) {
@@ -108,49 +65,11 @@ bool GetHostSnapshot(HostSnapshot* snapshot) {
if (snapshot == nullptr) {
return false;
}
CoreIme::HostSnapshot core;
if (CoreIme::GetHostSnapshot(&core)) {
snapshot->generation = PackCoreGeneration(core.generation);
snapshot->type = static_cast<Type>(core.type);
snapshot->enter_label = static_cast<EnterLabel>(core.enter_label);
snapshot->option = core.option;
snapshot->max_text_length = core.max_text_length;
snapshot->cursor = core.cursor;
snapshot->disable_device = core.disable_device;
snapshot->key_panel_visible = core.key_panel_visible;
snapshot->posx = core.posx;
snapshot->posy = core.posy;
snapshot->horizontal_alignment = static_cast<Alignment>(core.horizontal_alignment);
snapshot->vertical_alignment = static_cast<Alignment>(core.vertical_alignment);
snapshot->panel_width = core.panel_width;
snapshot->panel_height = core.panel_height;
snapshot->text = std::move(core.text);
snapshot->title.clear();
snapshot->placeholder.clear();
if (CoreIme::GetHostSnapshot(snapshot)) {
snapshot->generation = PackCoreGeneration(snapshot->generation);
return true;
}
DialogIme::HostSnapshot dialog;
if (!DialogIme::GetHostSnapshot(&dialog)) {
return false;
}
snapshot->generation = dialog.generation;
snapshot->type = static_cast<Type>(dialog.type);
snapshot->enter_label = static_cast<EnterLabel>(dialog.enter_label);
snapshot->option = dialog.option;
snapshot->max_text_length = dialog.max_text_length;
snapshot->cursor = dialog.cursor;
snapshot->disable_device = dialog.disable_device;
snapshot->key_panel_visible = dialog.key_panel_visible;
snapshot->posx = dialog.posx;
snapshot->posy = dialog.posy;
snapshot->horizontal_alignment = static_cast<Alignment>(dialog.horizontal_alignment);
snapshot->vertical_alignment = static_cast<Alignment>(dialog.vertical_alignment);
snapshot->panel_width = dialog.panel_width;
snapshot->panel_height = dialog.panel_height;
snapshot->text = std::move(dialog.text);
snapshot->title = std::move(dialog.title);
snapshot->placeholder = std::move(dialog.placeholder);
return true;
return DialogIme::GetHostSnapshot(snapshot);
}
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) {
if (!IsCoreGeneration(generation)) {
DialogIme::ExternalInput dialog;
dialog.key.keycode = input.key.keycode;
dialog.key.character = input.key.character;
dialog.key.status = input.key.status;
dialog.key.type = input.key.type;
dialog.key.user_id = input.key.user_id;
dialog.key.resource_id = input.key.resource_id;
dialog.key.timestamp = input.key.timestamp;
dialog.action = static_cast<DialogIme::ExternalAction>(input.action);
dialog.text = std::move(input.text);
return DialogIme::HostQueueExternalInput(generation, std::move(dialog));
}
CoreIme::ExternalInput core;
core.key.keycode = input.key.keycode;
core.key.character = input.key.character;
core.key.status = input.key.status;
core.key.type = input.key.type;
core.key.user_id = input.key.user_id;
core.key.resource_id = input.key.resource_id;
core.key.timestamp = input.key.timestamp;
core.action = static_cast<CoreIme::ExternalAction>(input.action);
core.text = std::move(input.text);
return CoreIme::HostQueueExternalInput(UnpackGeneration(generation), std::move(core));
return IsCoreGeneration(generation)
? CoreIme::HostQueueExternalInput(UnpackGeneration(generation), std::move(input))
: DialogIme::HostQueueExternalInput(generation, std::move(input));
}
} // namespace Ime
@@ -22,7 +22,6 @@
#include "common/logging/log.h"
#include "common/profiler.h"
#include "common/stringUtils.h"
#include "common/subsystems.h"
#include "common/systemInfo.h"
#include "common/threads.h"
#include "common/timer.h"
@@ -22,7 +22,6 @@
#include "common/logging/log.h"
#include "common/profiler.h"
#include "common/stringUtils.h"
#include "common/subsystems.h"
#include "common/systemInfo.h"
#include "common/threads.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;
}
KYTY_SUBSYSTEM_INIT(FileSystem) {
void Initialize() {
g_mount_points = new MountPoints;
g_files = new FileDescriptors;
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(FileSystem) {
void EmergencyShutdown() {
if (g_files != nullptr) {
g_files->CloseAll();
}
}
KYTY_SUBSYSTEM_DESTROY(FileSystem) {
if (g_files != nullptr) {
g_files->CloseAll();
}
void Shutdown() {
EmergencyShutdown();
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) {
+10 -2
View File
@@ -4,7 +4,6 @@
#include "common/abi.h"
#include "common/common.h"
#include "common/stringUtils.h"
#include "common/subsystems.h"
#include "kernel/pthread.h"
#include <filesystem>
@@ -33,7 +32,16 @@ struct FileStat {
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 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);
KYTY_SUBSYSTEM_INIT(Memory) {
void Initialize() {
g_flexible_memory_size_frozen = true;
VirtualMemory::Init();
g_guest_address_space = std::make_unique<GuestAddressSpace>(PhysicalMemory::TotalSize());
@@ -988,9 +988,7 @@ KYTY_SUBSYSTEM_INIT(Memory) {
EXIT_IF(!SelfTestSub64SharedPlaceholderAlias());
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Memory) {}
KYTY_SUBSYSTEM_DESTROY(Memory) {
void Shutdown() {
g_pooled_memory.reset();
g_flexible_memory.reset();
g_physical_memory.reset();
+8 -2
View File
@@ -3,7 +3,6 @@
#include "common/abi.h"
#include "common/common.h"
#include "common/subsystems.h"
#include "common/virtualMemory.h"
namespace Libs::Graphics {
@@ -13,7 +12,14 @@ enum class PageFaultAccess;
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);
+1 -5
View File
@@ -1124,7 +1124,7 @@ void* PthreadCreateMainGuestStack() {
return stack_top;
}
KYTY_SUBSYSTEM_INIT(Pthread) {
void Initialize() {
PRINT_NAME_ENABLE(false);
EXIT_IF(g_pthread_context != nullptr);
@@ -1157,10 +1157,6 @@ KYTY_SUBSYSTEM_INIT(Pthread) {
thread.Detach();
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Pthread) {}
KYTY_SUBSYSTEM_DESTROY(Pthread) {}
static int PthreadAttrCopy(PthreadAttr* dst, const PthreadAttr* src) {
if (dst == nullptr || *dst == nullptr || src == nullptr || *src == nullptr) {
return KERNEL_ERROR_EINVAL;
+6 -2
View File
@@ -3,7 +3,6 @@
#include "common/abi.h"
#include "common/common.h"
#include "common/subsystems.h"
// IWYU pragma: no_include <pthread.h>
@@ -19,7 +18,12 @@ namespace Libs {
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 PthreadPrivate;
+2 -4
View File
@@ -43,7 +43,7 @@ namespace Libs::Graphics {
static RenderContext* g_renderer = nullptr;
KYTY_SUBSYSTEM_INIT(Graphics) {
void Initialize() {
// Some games lock up if this is not called first
if (Config::RenderDocEnabled()) {
RenderDocInit();
@@ -59,9 +59,7 @@ KYTY_SUBSYSTEM_INIT(Graphics) {
ShaderInit();
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Graphics) {}
KYTY_SUBSYSTEM_DESTROY(Graphics) {
void Shutdown() {
EXIT_IF(g_renderer == nullptr);
g_renderer->ShutdownGpu();
VideoOut::VideoOutShutdown();
+8 -2
View File
@@ -3,7 +3,6 @@
#include "common/abi.h"
#include "common/common.h"
#include "common/subsystems.h"
#include "kernel/eventQueue.h"
namespace Libs::Graphics {
@@ -21,7 +20,14 @@ struct MemoryRange {
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);
+11 -13
View File
@@ -181,15 +181,13 @@ uint32_t AudioOutOutputs(const OutputParam* params, uint32_t num, bool blocking)
} // namespace AudioInternal
KYTY_SUBSYSTEM_INIT(Audio) {
void Initialize() {
EXIT_IF(g_audio != nullptr);
g_audio = new Audio;
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Audio) {}
KYTY_SUBSYSTEM_DESTROY(Audio) {
void Shutdown() {
delete g_audio;
g_audio = nullptr;
}
@@ -1461,14 +1459,14 @@ struct Ngs2CustomSamplerRackOption {
};
union Ngs2RackOptionUnion {
Ngs2RackOption common;
Ngs2SamplerRackOption sampler;
Ngs2MasteringRackOption mastering;
Ngs2SubmixerRackOption submixer;
Ngs2ReverbRackOption reverb;
Ngs2CustomSubmixerRackOption custom_submixer;
Ngs2RackOption common;
Ngs2SamplerRackOption sampler;
Ngs2MasteringRackOption mastering;
Ngs2SubmixerRackOption submixer;
Ngs2ReverbRackOption reverb;
Ngs2CustomSubmixerRackOption custom_submixer;
Ngs2CustomMasteringRackOption custom_mastering;
Ngs2CustomSamplerRackOption custom_sampler;
Ngs2CustomSamplerRackOption custom_sampler;
};
struct Ngs2ContextBufferInfo {
@@ -2653,8 +2651,8 @@ int KYTY_SYSV_ABI Ngs2VoiceGetState(uintptr_t voice_handle, Ngs2VoiceState* stat
switch (voice->rack->type) {
case Ngs2RackType::Submixer: {
EXIT_NOT_IMPLEMENTED(state_size != sizeof(Ngs2SubmixerVoiceState));
auto* submixer = reinterpret_cast<Ngs2SubmixerVoiceState*>(state);
*submixer = {};
auto* submixer = reinterpret_cast<Ngs2SubmixerVoiceState*>(state);
*submixer = {};
submixer->voice_state.state_flags = Ngs2GetStateFlags(voice);
LOGF("\t state_flags = %u\n", submixer->voice_state.state_flags);
break;
+8 -3
View File
@@ -3,11 +3,16 @@
#include "common/abi.h"
#include "common/common.h"
#include "common/subsystems.h"
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 {
+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;
}
KYTY_SUBSYSTEM_INIT(Controller) {
void Initialize() {
EXIT_IF(g_controller != nullptr);
g_controller = new GameController;
g_controller->Connect(HOST_INPUT_CONTROLLER_ID);
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Controller) {}
KYTY_SUBSYSTEM_DESTROY(Controller) {}
void Shutdown() {
delete g_controller;
g_controller = nullptr;
}
void GameController::Connect(int id) {
Common::LockGuard lock(m_mutex);
+8 -3
View File
@@ -3,11 +3,16 @@
#include "common/abi.h"
#include "common/common.h"
#include "common/subsystems.h"
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;
+80 -231
View File
@@ -55,13 +55,13 @@ constexpr uint32_t VALID_KEYBOARD_OPTIONS = 0x0000003f;
constexpr uint32_t VALID_KEYBOARD_MODE = 0x0000007f;
constexpr uint64_t VALID_LANGUAGES = 0x00000001ff1fffffULL;
constexpr uint32_t OPTION_MULTILINE = 0x00000001;
constexpr uint32_t OPTION_PASSWORD = 0x00000004;
constexpr uint32_t OPTION_EXT_KEYBOARD = 0x00000010;
constexpr uint32_t OPTION_EXPANDED_PREEDIT = 0x00001000;
constexpr uint32_t OPTION_USE_OVER_2K = 0x00004000;
constexpr uint32_t OPTION_MULTILINE = ImeCommon::OPTION_MULTILINE;
constexpr uint32_t OPTION_PASSWORD = ImeCommon::OPTION_PASSWORD;
constexpr uint32_t OPTION_EXT_KEYBOARD = ImeCommon::OPTION_EXT_KEYBOARD;
constexpr uint32_t OPTION_EXPANDED_PREEDIT = ImeCommon::OPTION_EXPANDED_PREEDIT;
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;
struct QueuedEvent {
@@ -71,18 +71,15 @@ struct QueuedEvent {
};
struct State {
bool open = false;
bool event_overflow = false;
uint64_t generation = 0;
uint64_t revision = 0;
uint32_t option = 0;
uint32_t max_text_length = 0;
uint32_t cursor = 0;
bool open = false;
bool event_overflow = false;
uint64_t generation = 0;
uint64_t revision = 0;
Param param {};
ExtendedParam extended {};
void* arg = nullptr;
EventHandler handler = nullptr;
std::u16string text;
ImeCommon::TextEditEngine editor;
std::deque<QueuedEvent> events;
std::vector<ExternalInput> external_inputs;
};
@@ -130,97 +127,6 @@ bool ValidateText(const char16_t* text, uint32_t length, bool multiline, uint32_
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) {
if (const auto callback = g_visibility_callback.load(std::memory_order_acquire);
callback != nullptr) {
@@ -247,7 +153,7 @@ void SyncGuestText(char16_t* work, char16_t* input, uint32_t max_length, std::u1
void SyncTextBuffersLocked() {
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) {
@@ -263,53 +169,33 @@ QueuedEvent MakeTextEventLocked(uint32_t id, uint32_t edit_index, int32_t edit_l
QueuedEvent queued;
queued.event.id = id;
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.text_area[0] = {TextAreaMode::Edit, edit_index, edit_length};
queued.text_payload = true;
queued.text = g_state.text;
queued.text = g_state.editor.GetText();
return queued;
}
bool CommitFilteredText(uint64_t generation, uint64_t revision, std::u16string old_text,
std::u16string candidate, uint32_t cursor, TextFilter filter,
uint32_t max_length, bool multiline) {
ImeCommon::TextEditEngine candidate, TextFilter filter, bool multiline) {
if (filter != nullptr) {
std::vector<char16_t> output(max_length + 1, u'\0');
uint32_t output_length = max_length;
if (filter(output.data(), &output_length, candidate.c_str(),
static_cast<uint32_t>(candidate.size())) == 0 &&
output_length <= max_length) {
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::u16string filtered;
if (ImeCommon::RunTextFilter(filter, candidate.GetText(), candidate.GetMaxLength(),
&filtered) &&
ImeCommon::IsValidInputText(filtered, multiline)) {
candidate.ReplaceText(std::move(filtered), candidate.GetCursor());
}
}
std::scoped_lock lock(g_mutex);
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;
}
size_t prefix = 0;
while (prefix < old_text.size() && prefix < candidate.size() &&
old_text[prefix] == candidate[prefix]) {
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));
const auto edit = ImeCommon::ComputeEditDelta(old_text, candidate.GetText());
g_state.editor = std::move(candidate);
QueueEventLocked(MakeTextEventLocked(1, edit.index, edit.length));
UpdateRevisionLocked();
return true;
}
@@ -475,16 +361,13 @@ int KYTY_SYSV_ABI ImeOpen(const Param* param, const ExtendedParam* extended) {
g_state.open = true;
g_state.generation = next_generation;
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;
if (extended != nullptr) {
g_state.extended = *extended;
}
g_state.arg = param->arg;
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);
SyncTextBuffersLocked();
@@ -550,7 +433,7 @@ int KYTY_SYSV_ABI ImeUpdate(EventHandler handler) {
while (!g_state.events.empty()) {
dispatch.push_back({g_state.arg, std::move(g_state.events.front()),
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.events.pop_front();
}
@@ -607,14 +490,14 @@ int KYTY_SYSV_ABI ImeSetText(const char16_t* text, uint32_t length) {
if (text == nullptr) {
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;
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)) {
return ERROR_INVALID_TEXT;
}
g_state.text.assign(text, text + actual_length);
g_state.cursor = NormalizeCursor(g_state.text, g_state.cursor);
g_state.editor.ReplaceText(std::u16string(text, text + actual_length),
g_state.editor.GetCursor());
SyncTextBuffersLocked();
UpdateRevisionLocked();
return OK;
@@ -628,10 +511,10 @@ int KYTY_SYSV_ABI ImeSetCaret(const Caret* caret) {
if (caret == nullptr) {
return ERROR_INVALID_ADDRESS;
}
if (caret->index > g_state.text.size()) {
if (caret->index > g_state.editor.GetText().size()) {
return ERROR_INVALID_PARAM;
}
g_state.cursor = NormalizeCursor(g_state.text, caret->index);
g_state.editor.SetCursor(caret->index);
UpdateRevisionLocked();
return OK;
}
@@ -644,7 +527,7 @@ int KYTY_SYSV_ABI ImeSetTextGeometry(TextAreaMode mode, const TextGeometry* geom
if (geometry == nullptr) {
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_y = over_2k ? 2160.0f : 1080.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->type = g_state.param.type;
snapshot->enter_label = g_state.param.enter_label;
snapshot->option = g_state.option;
snapshot->max_text_length = g_state.max_text_length;
snapshot->cursor = g_state.cursor;
snapshot->option = g_state.editor.GetOption();
snapshot->max_text_length = g_state.editor.GetMaxLength();
snapshot->cursor = g_state.editor.GetCursor();
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;
snapshot->posx = g_state.param.posx;
snapshot->posy = g_state.param.posy;
@@ -766,92 +649,65 @@ bool GetHostSnapshot(HostSnapshot* snapshot) {
snapshot->vertical_alignment = g_state.param.vertical_alignment;
snapshot->panel_width = g_state.param.type == Type::Number ? 370 : 793;
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_height *= 2;
}
snapshot->text = g_state.text;
snapshot->text = g_state.editor.GetText();
snapshot->title.clear();
snapshot->placeholder.clear();
return true;
}
static bool ApplyInsertText(uint64_t generation, std::u16string_view text) {
uint64_t revision = 0;
uint32_t cursor = 0;
uint32_t max_length = 0;
bool multiline = false;
TextFilter filter = nullptr;
std::u16string old_text;
std::u16string candidate;
uint64_t revision = 0;
bool multiline = false;
TextFilter filter = nullptr;
std::u16string old_text;
ImeCommon::TextEditEngine candidate;
{
std::scoped_lock lock(g_mutex);
if (!g_state.open || g_state.generation != generation || text.empty()) {
return false;
}
uint32_t valid_length = 0;
multiline = (g_state.option & OPTION_MULTILINE) != 0;
if (!ValidateText(text.data(), static_cast<uint32_t>(text.size()), multiline,
&valid_length) ||
valid_length != text.size()) {
multiline = (g_state.editor.GetOption() & OPTION_MULTILINE) != 0;
if (!ImeCommon::IsValidInputText(text, multiline)) {
return false;
}
std::u16string allowed;
for (const char16_t value: 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) {
candidate = g_state.editor;
if (!candidate.Insert(text)) {
return false;
}
allowed.resize(std::min(allowed.size(), available));
if (!allowed.empty() && allowed.back() >= 0xd800 && allowed.back() <= 0xdbff) {
allowed.pop_back();
}
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());
revision = g_state.revision;
filter = g_state.param.filter;
old_text = g_state.editor.GetText();
}
return CommitFilteredText(generation, revision, std::move(old_text), std::move(candidate),
cursor, filter, max_length, multiline);
filter, multiline);
}
static bool ApplyBackspace(uint64_t generation) {
uint64_t revision = 0;
uint32_t cursor = 0;
uint32_t max_length = 0;
bool multiline = false;
TextFilter filter = nullptr;
std::u16string old_text;
std::u16string candidate;
uint64_t revision = 0;
bool multiline = false;
TextFilter filter = nullptr;
std::u16string old_text;
ImeCommon::TextEditEngine candidate;
{
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;
}
uint32_t first = g_state.cursor - 1;
if (first > 0 && g_state.text[first] >= 0xdc00 && g_state.text[first] <= 0xdfff &&
g_state.text[first - 1] >= 0xd800 && g_state.text[first - 1] <= 0xdbff) {
first--;
candidate = g_state.editor;
if (!candidate.Backspace()) {
return false;
}
revision = g_state.revision;
max_length = g_state.max_text_length;
multiline = (g_state.option & OPTION_MULTILINE) != 0;
filter = g_state.param.filter;
old_text = g_state.text;
candidate = old_text;
candidate.erase(first, g_state.cursor - first);
cursor = first;
revision = g_state.revision;
multiline = (g_state.editor.GetOption() & OPTION_MULTILINE) != 0;
filter = g_state.param.filter;
old_text = g_state.editor.GetText();
}
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) {
@@ -859,25 +715,14 @@ static bool ApplyMoveCursor(uint64_t generation, int delta) {
if (!g_state.open || g_state.generation != generation || delta == 0) {
return false;
}
const uint32_t old_cursor = g_state.cursor;
int next =
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) {
const uint32_t old_cursor = g_state.editor.GetCursor();
if (!g_state.editor.MoveCursor(delta)) {
return false;
}
const uint32_t direction = g_state.cursor > old_cursor ? 2 : 1;
const uint32_t steps = static_cast<uint32_t>(
std::abs(static_cast<int>(g_state.cursor) - static_cast<int>(old_cursor)));
const uint32_t new_cursor = g_state.editor.GetCursor();
const uint32_t direction = new_cursor > old_cursor ? 2 : 1;
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++) {
QueuedEvent event;
event.event.id = 2;
@@ -962,7 +807,7 @@ void ApplyExternalInputs() {
generation = g_state.generation;
filter = g_state.extended.ext_keyboard_filter;
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);
}
for (auto& input: inputs) {
@@ -978,7 +823,7 @@ void ApplyExternalInputs() {
uint16_t keycode = input.key.keycode;
uint32_t status = input.key.status;
if (filter(&input.key, &keycode, &status, nullptr) == 0) {
accepted = ApplyKeyboardFilterOutput(&input, keycode, status, multiline);
accepted = ImeCommon::ApplyKeyboardFilterOutput(&input, keycode, status, multiline);
}
}
if (!accepted) {
@@ -999,6 +844,8 @@ void ApplyExternalInputs() {
} // namespace
#if !defined(KYTY_IME_TESTS)
LIB_VERSION("Ime", 1, "Ime", 1, 1);
LIB_DEFINE(InitPlatform_1_Ime) {
@@ -1017,4 +864,6 @@ LIB_DEFINE(InitPlatform_1_Ime) {
LIB_FUNC("ua+13Hk9kKs", ImeKeyboardSetMode);
}
#endif
} // namespace Libs::Ime
+15 -86
View File
@@ -1,7 +1,7 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_LIBS_IME_H_
#define EMULATOR_INCLUDE_EMULATOR_LIBS_IME_H_
#include "common/abi.h"
#include "libs/imeCommon.h"
#include <cstddef>
#include <cstdint>
@@ -11,28 +11,19 @@
namespace Libs::Ime {
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 };
enum class EnterLabel : uint32_t { Default = 0, Send = 1, Search = 2, Go = 3 };
enum class Alignment : uint32_t { Start = 0, Center = 1, End = 2 };
using Type = ImeCommon::Type;
using EnterLabel = ImeCommon::EnterLabel;
using Alignment = ImeCommon::Alignment;
struct Event;
struct Keycode;
using TextFilter = int32_t(KYTY_SYSV_ABI*)(char16_t* out_text, uint32_t* out_text_length,
const char16_t* source_text,
uint32_t source_text_length);
using Keycode = ImeCommon::Keycode;
using TextFilter = ImeCommon::TextFilter;
using EventHandler = void(KYTY_SYSV_ABI*)(void* arg, const Event* event);
using ExtKeyboardFilter = int(KYTY_SYSV_ABI*)(const Keycode* source_keycode, uint16_t* out_keycode,
uint32_t* out_status, void* reserved);
struct Color {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
using ExtKeyboardFilter = ImeCommon::ExtKeyboardFilter;
using Color = ImeCommon::Color;
struct Caret {
float x;
@@ -75,16 +66,6 @@ struct KeyboardResourceIdArray {
uint32_t resource_id[5];
};
struct Keycode {
uint16_t keycode;
char16_t character;
uint32_t status;
uint32_t type;
int32_t user_id;
uint32_t resource_id;
uint64_t timestamp;
};
union EventParam {
Rect rect;
EditText text;
@@ -119,24 +100,7 @@ struct Param {
int8_t reserved[8];
};
struct ExtendedParam {
uint32_t option;
Color color_base;
Color color_line;
Color color_text_field;
Color color_preedit;
Color color_button_default;
Color color_button_function;
Color color_button_symbol;
Color color_text;
Color color_special;
uint32_t priority;
const char* additional_dictionary_path;
ExtKeyboardFilter ext_keyboard_filter;
uint32_t disable_device;
uint32_t ext_keyboard_mode;
int8_t reserved[60];
};
using ExtendedParam = ImeCommon::ExtendedParam;
struct KeyboardParam {
uint32_t option;
@@ -156,22 +120,8 @@ struct KeyboardInfo {
int8_t reserved[12];
};
enum class ExternalAction : uint8_t {
None,
Text,
Backspace,
MoveLeft,
MoveRight,
Cancel,
Accept,
Newline,
};
struct ExternalInput {
Keycode key;
ExternalAction action;
std::u16string text;
};
using ExternalAction = ImeCommon::ExternalAction;
using ExternalInput = ImeCommon::ExternalInput;
static_assert(sizeof(Caret) == 0x10);
static_assert(sizeof(TextGeometry) == 0x10);
@@ -192,30 +142,9 @@ static_assert(sizeof(KeyboardResourceIdArray) == 0x18);
static_assert(sizeof(KeyboardInfo) == 0x24);
static_assert(sizeof(Keycode) == 0x20);
struct VisualState {
bool active;
uint64_t revision;
};
struct HostSnapshot {
uint64_t generation;
Type type;
EnterLabel enter_label;
uint32_t option;
uint32_t max_text_length;
uint32_t cursor;
uint32_t disable_device;
bool key_panel_visible;
float posx;
float posy;
Alignment horizontal_alignment;
Alignment vertical_alignment;
uint32_t panel_width;
uint32_t panel_height;
std::u16string text;
};
using VisibilityCallback = void (*)(bool visible, uint64_t generation);
using VisualState = ImeCommon::VisualState;
using HostSnapshot = ImeCommon::HostSnapshot;
using VisibilityCallback = ImeCommon::VisibilityCallback;
void KYTY_SYSV_ABI ImeParamInit(Param* param);
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 {};
bool input_changed = false;
bool commit_pending = false;
uint32_t cursor = 0;
std::u16string original_text;
std::u16string current_text;
ImeCommon::TextEditEngine editor;
std::u16string title;
std::u16string placeholder;
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; });
}
bool IsValidUtf16(std::u16string_view text);
bool ReadBounded(const char16_t* text, uint32_t limit, std::u16string* out) {
out->clear();
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) {
const char16_t value = text[i];
if (value == u'\0') {
return IsValidUtf16(*out);
return ImeCommon::IsValidUtf16(*out);
}
if (i == limit) {
return false;
@@ -92,128 +89,6 @@ bool ReadBounded(const char16_t* text, uint32_t limit, std::u16string* out) {
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) {
if (state.param.input_text_buffer == nullptr) {
return;
@@ -355,7 +230,7 @@ void ApplyFilterAndCommit() {
return;
}
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;
generation = g_state.generation;
revision = g_state.revision;
@@ -363,14 +238,10 @@ void ApplyFilterAndCommit() {
}
if (filter != nullptr) {
std::vector<char16_t> output(IME_DIALOG_MAX_TEXT_LENGTH + 1, u'\0');
uint32_t output_length = IME_DIALOG_MAX_TEXT_LENGTH;
if (filter(output.data(), &output_length, source.c_str(),
static_cast<uint32_t>(source.size())) == 0 &&
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);
std::u16string filtered;
if (ImeCommon::RunTextFilter(filter, source, IME_DIALOG_MAX_TEXT_LENGTH, &filtered)) {
source = std::move(filtered);
ImeCommon::ClampText(&source, max_length);
}
}
@@ -386,13 +257,12 @@ void ApplyFilterAndCommit() {
return;
}
if (!g_state.input_changed) {
g_state.current_text = std::move(source);
g_state.cursor = NormalizeCursor(g_state.current_text, g_state.cursor);
g_state.editor.ReplaceText(std::move(source), g_state.editor.GetCursor());
}
const auto& committed =
g_state.status == Status::Finished && g_state.end_status != EndStatus::Ok
? g_state.original_text
: g_state.current_text;
: g_state.editor.GetText();
WriteGuestText(g_state, committed);
g_state.commit_pending = false;
}
@@ -451,8 +321,8 @@ void ApplyExternalInputs() {
uint16_t output_keycode = input.key.keycode;
uint32_t output_status = input.key.status;
if (filter(&input.key, &output_keycode, &output_status, nullptr) == 0) {
accepted =
ApplyKeyboardFilterOutput(&input, output_keycode, output_status, multiline);
accepted = ImeCommon::ApplyKeyboardFilterOutput(&input, output_keycode,
output_status, multiline);
}
}
if (!accepted) {
@@ -528,9 +398,9 @@ int KYTY_SYSV_ABI ImeDialogInit(const Param* param, const ExtendedParam* extende
if (extended != nullptr) {
g_state.extended = *extended;
}
g_state.original_text = initial;
g_state.current_text = std::move(initial);
g_state.cursor = static_cast<uint32_t>(g_state.current_text.size());
g_state.original_text = initial;
g_state.editor.Reset(param->type, param->option, param->max_text_length,
std::move(initial));
g_state.title = std::move(title);
g_state.placeholder = std::move(placeholder);
g_state.commit_pending = true;
@@ -664,7 +534,7 @@ bool GetHostSnapshot(HostSnapshot* snapshot) {
snapshot->enter_label = g_state.param.enter_label;
snapshot->option = g_state.param.option;
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->key_panel_visible = (g_state.param.option & OPTION_EXT_KEYBOARD) == 0 ||
(g_state.extended.option & 0x00000400) == 0;
@@ -674,7 +544,7 @@ bool GetHostSnapshot(HostSnapshot* snapshot) {
snapshot->vertical_alignment = g_state.param.vertical_alignment;
ComputePanelSize(g_state.param, &g_state.extended, &snapshot->panel_width,
&snapshot->panel_height);
snapshot->text = g_state.current_text;
snapshot->text = g_state.editor.GetText();
snapshot->title = g_state.title;
snapshot->placeholder = g_state.placeholder;
return true;
@@ -682,38 +552,9 @@ bool GetHostSnapshot(HostSnapshot* snapshot) {
bool HostInsertText(uint64_t generation, std::u16string_view text) {
std::scoped_lock lock(g_mutex);
if (!MatchRunningGeneration(generation) || text.empty()) {
if (!MatchRunningGeneration(generation) || !g_state.editor.Insert(text)) {
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.commit_pending = true;
return true;
@@ -721,17 +562,9 @@ bool HostInsertText(uint64_t generation, std::u16string_view text) {
bool HostBackspace(uint64_t generation) {
std::scoped_lock lock(g_mutex);
if (!MatchRunningGeneration(generation) || g_state.cursor == 0) {
if (!MatchRunningGeneration(generation) || !g_state.editor.Backspace()) {
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.commit_pending = true;
return true;
@@ -739,26 +572,7 @@ bool HostBackspace(uint64_t generation) {
bool HostMoveCursor(uint64_t generation, int delta) {
std::scoped_lock lock(g_mutex);
if (!MatchRunningGeneration(generation) || delta == 0) {
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;
return MatchRunningGeneration(generation) && g_state.editor.MoveCursor(delta);
}
bool HostAccept(uint64_t generation) {
+25 -99
View File
@@ -1,7 +1,7 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_LIBS_IMEDIALOG_H_
#define EMULATOR_INCLUDE_EMULATOR_LIBS_IMEDIALOG_H_
#include "common/abi.h"
#include "libs/imeCommon.h"
#include <cstddef>
#include <cstdint>
@@ -10,53 +10,43 @@
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_PLACEHOLDER_LENGTH = 64;
enum class Status : uint32_t { None = 0, Running = 1, Finished = 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 };
enum class EnterLabel : uint32_t { Default = 0, Send = 1, Search = 2, Go = 3 };
enum class Alignment : uint32_t { Start = 0, Center = 1, End = 2 };
using Type = ImeCommon::Type;
using EnterLabel = ImeCommon::EnterLabel;
using Alignment = ImeCommon::Alignment;
enum Option : uint32_t {
OPTION_MULTILINE = 0x00000001,
OPTION_NO_AUTO_CAPITALIZE = 0x00000002,
OPTION_PASSWORD = 0x00000004,
OPTION_MULTILINE = ImeCommon::OPTION_MULTILINE,
OPTION_NO_AUTO_CAPITALIZE = ImeCommon::OPTION_NO_AUTO_CAPITALIZE,
OPTION_PASSWORD = ImeCommon::OPTION_PASSWORD,
OPTION_LANGUAGES_FORCED = 0x00000008,
OPTION_EXT_KEYBOARD = 0x00000010,
OPTION_EXT_KEYBOARD = ImeCommon::OPTION_EXT_KEYBOARD,
OPTION_NO_LEARNING = 0x00000020,
OPTION_FIXED_POSITION = 0x00000040,
OPTION_FIXED_POSITION = ImeCommon::OPTION_FIXED_POSITION,
OPTION_DISABLE_COPY_PASTE = 0x00000080,
OPTION_DISABLE_RESUME = 0x00000100,
OPTION_DISABLE_AUTO_SPACE = 0x00000200,
OPTION_DISABLE_POSITION_ADJ = 0x00000800,
OPTION_EXPANDED_PREEDIT = 0x00001000,
OPTION_DISABLE_POSITION_ADJ = ImeCommon::OPTION_DISABLE_POSITION_ADJUST,
OPTION_EXPANDED_PREEDIT = ImeCommon::OPTION_EXPANDED_PREEDIT,
OPTION_JAPANESE_CAPS_LOCK = 0x00002000,
OPTION_USE_OVER_2K = 0x00004000,
OPTION_USE_OVER_2K = ImeCommon::OPTION_USE_OVER_2K,
};
enum DisableDevice : uint32_t {
DISABLE_DEVICE_CONTROLLER = 0x00000001,
DISABLE_DEVICE_EXT_KEYBOARD = 0x00000002,
DISABLE_DEVICE_CONTROLLER = ImeCommon::DISABLE_DEVICE_CONTROLLER,
DISABLE_DEVICE_EXT_KEYBOARD = ImeCommon::DISABLE_DEVICE_EXT_KEYBOARD,
DISABLE_DEVICE_REMOTE_OSK = 0x00000004,
};
struct Color {
uint8_t r;
uint8_t g;
uint8_t b;
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);
using Color = ImeCommon::Color;
using Keycode = ImeCommon::Keycode;
using TextFilter = ImeCommon::TextFilter;
using ExtKeyboardFilter = ImeCommon::ExtKeyboardFilter;
struct Param {
int32_t user_id;
@@ -82,24 +72,7 @@ struct Result {
int8_t reserved[12];
};
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];
};
using ExtendedParam = ImeCommon::ExtendedParam;
struct PositionAndForm {
uint32_t type;
@@ -111,32 +84,8 @@ struct PositionAndForm {
uint32_t height;
};
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;
};
enum class ExternalAction : uint8_t {
None,
Text,
Backspace,
MoveLeft,
MoveRight,
Cancel,
Accept,
Newline,
};
struct ExternalInput {
Keycode key;
ExternalAction action;
std::u16string text;
};
using ExternalAction = ImeCommon::ExternalAction;
using ExternalInput = ImeCommon::ExternalInput;
static_assert(sizeof(Param) == 0x60);
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(Keycode) == 0x20);
struct VisualState {
bool active;
uint64_t revision;
};
struct HostSnapshot {
uint64_t generation;
Type type;
EnterLabel enter_label;
uint32_t option;
uint32_t max_text_length;
uint32_t cursor;
uint32_t disable_device;
bool key_panel_visible;
float posx;
float posy;
Alignment horizontal_alignment;
Alignment vertical_alignment;
uint32_t panel_width;
uint32_t panel_height;
std::u16string text;
std::u16string title;
std::u16string placeholder;
};
using VisibilityCallback = void (*)(bool visible, uint64_t generation);
using VisualState = ImeCommon::VisualState;
using HostSnapshot = ImeCommon::HostSnapshot;
using VisibilityCallback = ImeCommon::VisibilityCallback;
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,
+5 -4
View File
@@ -237,15 +237,16 @@ private:
static Network* g_net = nullptr;
KYTY_SUBSYSTEM_INIT(Network) {
void Initialize() {
EXIT_IF(g_net != nullptr);
g_net = new Network;
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Network) {}
KYTY_SUBSYSTEM_DESTROY(Network) {}
void Shutdown() {
delete g_net;
g_net = nullptr;
}
int Network::PoolCreate(const char* name, int size) {
Common::LockGuard lock(m_mutex);
+8 -3
View File
@@ -3,11 +3,16 @@
#include "common/abi.h"
#include "common/common.h"
#include "common/subsystems.h"
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 {
-9
View File
@@ -2,21 +2,12 @@
#include "common/abi.h"
#include "common/dateTime.h"
#include "common/subsystems.h"
#include "loader/timer.h"
namespace Loader::Timer {
static Common::Timer g_timer;
KYTY_SUBSYSTEM_INIT(Timer) {
Start();
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Timer) {}
KYTY_SUBSYSTEM_DESTROY(Timer) {}
void Start() {
g_timer.Start();
}
+5 -4
View File
@@ -4,18 +4,19 @@
#include "common/abi.h"
#include "common/common.h"
#include "common/dateTime.h"
#include "common/subsystems.h"
namespace Loader::Timer {
KYTY_SUBSYSTEM_DEFINE(Timer);
void Start();
double GetTimeMs();
Common::Time GetTime();
uint64_t GetCounter();
uint64_t GetFrequency();
struct Lifecycle {
static constexpr const char* name = "Timer";
static constexpr auto initialize = Loader::Timer::Start;
};
} // namespace Loader::Timer
#endif /* EMULATOR_INCLUDE_EMULATOR_LOADER_TIMER_H_ */
+3 -21
View File
@@ -1,5 +1,4 @@
#include "common/common.h"
#include "common/commonSubsystem.h"
#include "common/dateTime.h"
#include "common/debug.h"
#include "common/file.h"
@@ -7,6 +6,7 @@
#include "common/platform/sysDbg.h"
#include "common/stringUtils.h"
#include "common/threads.h"
#include "common/virtualMemory.h"
#include "emulator.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[]) {
auto& slist = *SubsystemsList::Instance();
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;
}
VirtualMemory::Init();
InitializeThreads();
RunOptions options;
bool show_help = false;
if (argc < 2) {
PrintUsage();
slist.DestroyAll(false);
return 0;
}
if (!ParseArgs(argc, argv, options, show_help)) {
PrintUsage();
slist.DestroyAll(false);
return 1;
}
if (show_help) {
PrintUsage();
slist.DestroyAll(false);
return 0;
}
Run(options);
slist.DestroyAll(false);
return 0;
}
+6 -4
View File
@@ -1,6 +1,7 @@
#include "common/assert.h"
#include "common/emulatorConfig.h"
#include "common/logging/log.h"
#include "common/subsystems.h"
#include "common/threads.h"
#include "gpu_test_shaders/gpu_test_ms_depth_spv.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() {
static bool config_initialized = false;
if (!config_initialized) {
Common::ThreadsSubsystem::Instance()->Init(nullptr);
Config::ConfigSubsystem::Instance()->Init(nullptr);
static Common::Subsystems subsystems;
Common::InitializeThreads();
subsystems.Initialize<Config::Lifecycle>();
Config::ConfigOptions options;
options.printf_direction = Config::OutputDirection::Silent;
Config::Load(options);
Log::LogSubsystem::Instance()->Init(nullptr);
Libs::LibKernel::Memory::MemorySubsystem::Instance()->Init(nullptr);
subsystems.Initialize<Log::Lifecycle>();
subsystems.Initialize<Libs::LibKernel::Memory::Lifecycle>();
config_initialized = true;
}
}
+6 -20
View File
@@ -1,4 +1,3 @@
#include "common/commonSubsystem.h"
#include "common/emulatorConfig.h"
#include "common/file.h"
#include "common/logging/log.h"
@@ -97,28 +96,16 @@ void InitSubsystems() {
return;
}
static char arg0[] = "virtual_memory_allocation_tests";
static char* argv[] = {arg0};
auto* slist = Common::SubsystemsList::Instance();
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");
static Common::Subsystems subsystems;
Common::VirtualMemory::Init();
Common::InitializeThreads();
subsystems.Initialize<Config::Lifecycle>();
Config::ConfigOptions options;
options.printf_direction = Config::OutputDirection::Silent;
Config::Load(options);
slist->Add(log, {core, config});
Check("InitSubsystems", slist->InitAll(false), "failed to initialize logging subsystem");
subsystems.Initialize<Log::Lifecycle>();
const auto param_json = std::filesystem::temp_directory_path() /
("kyty_virtual_memory_" +
@@ -140,8 +127,7 @@ void InitSubsystems() {
"failed to read flexible memory size from param.json");
Libs::LibKernel::Memory::SetFlexibleMemorySize(flexible_memory_size);
slist->Add(memory, {core, log, thread});
Check("InitSubsystems", slist->InitAll(false), "failed to initialize memory subsystem");
subsystems.Initialize<Libs::LibKernel::Memory::Lifecycle>();
initialized = true;
}
+5 -3
View File
@@ -1,6 +1,7 @@
#include "common/emulatorConfig.h"
#include "common/logging/log.h"
#include "common/stringUtils.h"
#include "common/subsystems.h"
#include "common/threads.h"
#include "graphics/guest_gpu/hardwareContext.h"
#include "graphics/guest_gpu/pm4.h"
@@ -344,12 +345,13 @@ void SetIdentityInterpolatorSettings(ShaderPixelInputInfo* input_info) {
void EnsureConfigInitialized() {
static bool config_initialized = false;
if (!config_initialized) {
Common::ThreadsSubsystem::Instance()->Init(nullptr);
Config::ConfigSubsystem::Instance()->Init(nullptr);
static Common::Subsystems subsystems;
Common::InitializeThreads();
subsystems.Initialize<Config::Lifecycle>();
Config::ConfigOptions options;
options.printf_direction = Config::OutputDirection::Silent;
Config::Load(options);
Log::LogSubsystem::Instance()->Init(nullptr);
subsystems.Initialize<Log::Lifecycle>();
ShaderInit();
config_initialized = true;
}