applet: Add AppletDataBroker to manage HLE to AM service interaction
This cleans up most of the callbacks and such in the Applets::Applet interface, while also properly implementing all four data channels.
This commit is contained in:
parent
96535c13a5
commit
32775125b7
|
@ -32,6 +32,9 @@
|
||||||
|
|
||||||
namespace Service::AM {
|
namespace Service::AM {
|
||||||
|
|
||||||
|
constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2};
|
||||||
|
constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7};
|
||||||
|
|
||||||
enum class AppletId : u32 {
|
enum class AppletId : u32 {
|
||||||
SoftwareKeyboard = 0x11,
|
SoftwareKeyboard = 0x11,
|
||||||
};
|
};
|
||||||
|
@ -529,7 +532,8 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
|
||||||
class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
|
class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
|
||||||
public:
|
public:
|
||||||
explicit ILibraryAppletAccessor(std::shared_ptr<Applets::Applet> applet)
|
explicit ILibraryAppletAccessor(std::shared_ptr<Applets::Applet> applet)
|
||||||
: ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)) {
|
: ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)),
|
||||||
|
broker(std::make_shared<Applets::AppletDataBroker>()) {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
|
{0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
|
||||||
|
@ -554,34 +558,16 @@ public:
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
auto& kernel = Core::System::GetInstance().Kernel();
|
|
||||||
state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
|
|
||||||
"ILibraryAppletAccessor:StateChangedEvent");
|
|
||||||
pop_out_data_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
|
|
||||||
"ILibraryAppletAccessor:PopDataOutEvent");
|
|
||||||
pop_interactive_out_data_event =
|
|
||||||
Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
|
|
||||||
"ILibraryAppletAccessor:PopInteractiveDataOutEvent");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void AppletStorageProxyOutData(IStorage storage) {
|
|
||||||
storage_stack.push(std::make_shared<IStorage>(storage));
|
|
||||||
pop_out_data_event->Signal();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppletStorageProxyOutInteractiveData(IStorage storage) {
|
|
||||||
interactive_storage_stack.push(std::make_shared<IStorage>(storage));
|
|
||||||
pop_interactive_out_data_event->Signal();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) {
|
void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) {
|
||||||
state_changed_event->Signal();
|
const auto event = broker->GetStateChangedEvent();
|
||||||
|
event->Signal();
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushCopyObjects(state_changed_event);
|
rb.PushCopyObjects(event);
|
||||||
|
|
||||||
LOG_DEBUG(Service_AM, "called");
|
LOG_DEBUG(Service_AM, "called");
|
||||||
}
|
}
|
||||||
|
@ -604,14 +590,8 @@ private:
|
||||||
void Start(Kernel::HLERequestContext& ctx) {
|
void Start(Kernel::HLERequestContext& ctx) {
|
||||||
ASSERT(applet != nullptr);
|
ASSERT(applet != nullptr);
|
||||||
|
|
||||||
applet->Initialize(storage_stack);
|
applet->Initialize(broker);
|
||||||
while (!storage_stack.empty())
|
applet->Execute();
|
||||||
storage_stack.pop();
|
|
||||||
while (!interactive_storage_stack.empty())
|
|
||||||
interactive_storage_stack.pop();
|
|
||||||
applet->Execute([this](IStorage storage) { AppletStorageProxyOutData(storage); },
|
|
||||||
[this](IStorage storage) { AppletStorageProxyOutInteractiveData(storage); },
|
|
||||||
[this] { state_changed_event->Signal(); });
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
@ -621,7 +601,7 @@ private:
|
||||||
|
|
||||||
void PushInData(Kernel::HLERequestContext& ctx) {
|
void PushInData(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
storage_stack.push(rp.PopIpcInterface<IStorage>());
|
broker->PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>());
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
@ -632,28 +612,25 @@ private:
|
||||||
void PopOutData(Kernel::HLERequestContext& ctx) {
|
void PopOutData(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
|
|
||||||
if (storage_stack.empty()) {
|
const auto storage = broker->PopNormalDataToGame();
|
||||||
rb.Push(ResultCode(-1));
|
if (storage == nullptr) {
|
||||||
|
rb.Push(ERR_NO_DATA_IN_CHANNEL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushIpcInterface<IStorage>(std::move(storage_stack.front()));
|
rb.PushIpcInterface<IStorage>(std::move(*storage));
|
||||||
|
|
||||||
storage_stack.pop();
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_AM, "called");
|
LOG_DEBUG(Service_AM, "called");
|
||||||
}
|
}
|
||||||
|
|
||||||
void PushInteractiveInData(Kernel::HLERequestContext& ctx) {
|
void PushInteractiveInData(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
interactive_storage_stack.push(rp.PopIpcInterface<IStorage>());
|
broker->PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>());
|
||||||
|
|
||||||
ASSERT(applet->IsInitialized());
|
ASSERT(applet->IsInitialized());
|
||||||
applet->ReceiveInteractiveData(interactive_storage_stack.back());
|
applet->ExecuteInteractive();
|
||||||
applet->Execute([this](IStorage storage) { AppletStorageProxyOutData(storage); },
|
applet->Execute();
|
||||||
[this](IStorage storage) { AppletStorageProxyOutInteractiveData(storage); },
|
|
||||||
[this] { state_changed_event->Signal(); });
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
@ -664,15 +641,14 @@ private:
|
||||||
void PopInteractiveOutData(Kernel::HLERequestContext& ctx) {
|
void PopInteractiveOutData(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
|
|
||||||
if (interactive_storage_stack.empty()) {
|
const auto storage = broker->PopInteractiveDataToGame();
|
||||||
rb.Push(ResultCode(-1));
|
if (storage == nullptr) {
|
||||||
|
rb.Push(ERR_NO_DATA_IN_CHANNEL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushIpcInterface<IStorage>(std::move(interactive_storage_stack.front()));
|
rb.PushIpcInterface<IStorage>(std::move(*storage));
|
||||||
|
|
||||||
interactive_storage_stack.pop();
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_AM, "called");
|
LOG_DEBUG(Service_AM, "called");
|
||||||
}
|
}
|
||||||
|
@ -680,7 +656,7 @@ private:
|
||||||
void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) {
|
void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushCopyObjects(pop_out_data_event);
|
rb.PushCopyObjects(broker->GetNormalDataEvent());
|
||||||
|
|
||||||
LOG_DEBUG(Service_AM, "called");
|
LOG_DEBUG(Service_AM, "called");
|
||||||
}
|
}
|
||||||
|
@ -688,17 +664,13 @@ private:
|
||||||
void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) {
|
void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushCopyObjects(pop_interactive_out_data_event);
|
rb.PushCopyObjects(broker->GetInteractiveDataEvent());
|
||||||
|
|
||||||
LOG_DEBUG(Service_AM, "called");
|
LOG_DEBUG(Service_AM, "called");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Applets::Applet> applet;
|
std::shared_ptr<Applets::Applet> applet;
|
||||||
std::queue<std::shared_ptr<IStorage>> storage_stack;
|
std::shared_ptr<Applets::AppletDataBroker> broker;
|
||||||
std::queue<std::shared_ptr<IStorage>> interactive_storage_stack;
|
|
||||||
Kernel::SharedPtr<Kernel::Event> state_changed_event;
|
|
||||||
Kernel::SharedPtr<Kernel::Event> pop_out_data_event;
|
|
||||||
Kernel::SharedPtr<Kernel::Event> pop_interactive_out_data_event;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void IStorage::Open(Kernel::HLERequestContext& ctx) {
|
void IStorage::Open(Kernel::HLERequestContext& ctx) {
|
||||||
|
@ -740,9 +712,12 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
|
||||||
const u64 offset{rp.Pop<u64>()};
|
const u64 offset{rp.Pop<u64>()};
|
||||||
const std::vector<u8> data{ctx.ReadBuffer()};
|
const std::vector<u8> data{ctx.ReadBuffer()};
|
||||||
|
|
||||||
const auto size = std::min<std::size_t>(data.size(), backing.buffer.size() - offset);
|
if (data.size() > backing.buffer.size() - offset) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
|
||||||
|
}
|
||||||
|
|
||||||
std::memcpy(&backing.buffer[offset], data.data(), size);
|
std::memcpy(backing.buffer.data() + offset, data.data(), data.size());
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
@ -754,9 +729,12 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
const u64 offset{rp.Pop<u64>()};
|
const u64 offset{rp.Pop<u64>()};
|
||||||
std::size_t size{ctx.GetWriteBufferSize()};
|
const std::size_t size{ctx.GetWriteBufferSize()};
|
||||||
|
|
||||||
size = std::min<std::size_t>(size, backing.buffer.size() - offset);
|
if (size > backing.buffer.size() - offset) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
|
||||||
|
}
|
||||||
|
|
||||||
ctx.WriteBuffer(backing.buffer.data() + offset, size);
|
ctx.WriteBuffer(backing.buffer.data() + offset, size);
|
||||||
|
|
||||||
|
|
|
@ -4,21 +4,108 @@
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/frontend/applets/software_keyboard.h"
|
#include "core/frontend/applets/software_keyboard.h"
|
||||||
|
#include "core/hle/kernel/event.h"
|
||||||
|
#include "core/hle/kernel/server_port.h"
|
||||||
#include "core/hle/service/am/am.h"
|
#include "core/hle/service/am/am.h"
|
||||||
#include "core/hle/service/am/applets/applets.h"
|
#include "core/hle/service/am/applets/applets.h"
|
||||||
|
|
||||||
namespace Service::AM::Applets {
|
namespace Service::AM::Applets {
|
||||||
|
|
||||||
|
AppletDataBroker::AppletDataBroker() {
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
|
||||||
|
"ILibraryAppletAccessor:StateChangedEvent");
|
||||||
|
pop_out_data_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
|
||||||
|
"ILibraryAppletAccessor:PopDataOutEvent");
|
||||||
|
pop_interactive_out_data_event = Kernel::Event::Create(
|
||||||
|
kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
|
||||||
|
}
|
||||||
|
|
||||||
|
AppletDataBroker::~AppletDataBroker() = default;
|
||||||
|
|
||||||
|
std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
|
||||||
|
if (out_channel.empty())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto out = std::move(out_channel.front());
|
||||||
|
out_channel.pop();
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
|
||||||
|
if (in_channel.empty())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto out = std::move(in_channel.front());
|
||||||
|
in_channel.pop();
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
|
||||||
|
if (out_interactive_channel.empty())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto out = std::move(out_interactive_channel.front());
|
||||||
|
out_interactive_channel.pop();
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
|
||||||
|
if (in_interactive_channel.empty())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto out = std::move(in_interactive_channel.front());
|
||||||
|
in_interactive_channel.pop();
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppletDataBroker::PushNormalDataFromGame(IStorage storage) {
|
||||||
|
in_channel.push(std::make_unique<IStorage>(storage));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) {
|
||||||
|
out_channel.push(std::make_unique<IStorage>(storage));
|
||||||
|
pop_out_data_event->Signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) {
|
||||||
|
in_interactive_channel.push(std::make_unique<IStorage>(storage));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) {
|
||||||
|
out_interactive_channel.push(std::make_unique<IStorage>(storage));
|
||||||
|
pop_interactive_out_data_event->Signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppletDataBroker::SignalStateChanged() const {
|
||||||
|
state_changed_event->Signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetNormalDataEvent() const {
|
||||||
|
return pop_out_data_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetInteractiveDataEvent() const {
|
||||||
|
return pop_interactive_out_data_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetStateChangedEvent() const {
|
||||||
|
return state_changed_event;
|
||||||
|
}
|
||||||
|
|
||||||
Applet::Applet() = default;
|
Applet::Applet() = default;
|
||||||
|
|
||||||
Applet::~Applet() = default;
|
Applet::~Applet() = default;
|
||||||
|
|
||||||
void Applet::Initialize(std::queue<std::shared_ptr<IStorage>> storage) {
|
void Applet::Initialize(std::shared_ptr<AppletDataBroker> broker_) {
|
||||||
storage_stack = std::move(storage);
|
broker = std::move(broker_);
|
||||||
|
|
||||||
const auto common_data = storage_stack.front()->GetData();
|
const auto common = broker->PopNormalDataToApplet();
|
||||||
storage_stack.pop();
|
ASSERT(common != nullptr);
|
||||||
|
|
||||||
|
const auto common_data = common->GetData();
|
||||||
|
|
||||||
ASSERT(common_data.size() >= sizeof(CommonArguments));
|
ASSERT(common_data.size() >= sizeof(CommonArguments));
|
||||||
std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments));
|
std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments));
|
||||||
|
|
|
@ -8,35 +8,67 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
|
#include "core/hle/kernel/event.h"
|
||||||
|
|
||||||
union ResultCode;
|
union ResultCode;
|
||||||
|
|
||||||
namespace Frontend {
|
|
||||||
class SoftwareKeyboardApplet;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Service::AM {
|
namespace Service::AM {
|
||||||
|
|
||||||
class IStorage;
|
class IStorage;
|
||||||
|
|
||||||
namespace Applets {
|
namespace Applets {
|
||||||
|
|
||||||
using AppletStorageProxyFunction = std::function<void(IStorage)>;
|
class AppletDataBroker final {
|
||||||
using AppletStateProxyFunction = std::function<void()>;
|
public:
|
||||||
|
AppletDataBroker();
|
||||||
|
~AppletDataBroker();
|
||||||
|
|
||||||
|
std::unique_ptr<IStorage> PopNormalDataToGame();
|
||||||
|
std::unique_ptr<IStorage> PopNormalDataToApplet();
|
||||||
|
|
||||||
|
std::unique_ptr<IStorage> PopInteractiveDataToGame();
|
||||||
|
std::unique_ptr<IStorage> PopInteractiveDataToApplet();
|
||||||
|
|
||||||
|
void PushNormalDataFromGame(IStorage storage);
|
||||||
|
void PushNormalDataFromApplet(IStorage storage);
|
||||||
|
|
||||||
|
void PushInteractiveDataFromGame(IStorage storage);
|
||||||
|
void PushInteractiveDataFromApplet(IStorage storage);
|
||||||
|
|
||||||
|
void SignalStateChanged() const;
|
||||||
|
|
||||||
|
Kernel::SharedPtr<Kernel::Event> GetNormalDataEvent() const;
|
||||||
|
Kernel::SharedPtr<Kernel::Event> GetInteractiveDataEvent() const;
|
||||||
|
Kernel::SharedPtr<Kernel::Event> GetStateChangedEvent() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Queues are named from applet's perspective
|
||||||
|
std::queue<std::unique_ptr<IStorage>>
|
||||||
|
in_channel; // PopNormalDataToApplet and PushNormalDataFromGame
|
||||||
|
std::queue<std::unique_ptr<IStorage>>
|
||||||
|
out_channel; // PopNormalDataToGame and PushNormalDataFromApplet
|
||||||
|
std::queue<std::unique_ptr<IStorage>>
|
||||||
|
in_interactive_channel; // PopInteractiveDataToApplet and PushInteractiveDataFromGame
|
||||||
|
std::queue<std::unique_ptr<IStorage>>
|
||||||
|
out_interactive_channel; // PopInteractiveDataToGame and PushInteractiveDataFromApplet
|
||||||
|
|
||||||
|
Kernel::SharedPtr<Kernel::Event> state_changed_event;
|
||||||
|
Kernel::SharedPtr<Kernel::Event> pop_out_data_event; // Signaled on PushNormalDataFromApplet
|
||||||
|
Kernel::SharedPtr<Kernel::Event>
|
||||||
|
pop_interactive_out_data_event; // Signaled on PushInteractiveDataFromApplet
|
||||||
|
};
|
||||||
|
|
||||||
class Applet {
|
class Applet {
|
||||||
public:
|
public:
|
||||||
Applet();
|
Applet();
|
||||||
virtual ~Applet();
|
virtual ~Applet();
|
||||||
|
|
||||||
virtual void Initialize(std::queue<std::shared_ptr<IStorage>> storage);
|
virtual void Initialize(std::shared_ptr<AppletDataBroker> broker);
|
||||||
|
|
||||||
virtual bool TransactionComplete() const = 0;
|
virtual bool TransactionComplete() const = 0;
|
||||||
virtual ResultCode GetStatus() const = 0;
|
virtual ResultCode GetStatus() const = 0;
|
||||||
virtual void ReceiveInteractiveData(std::shared_ptr<IStorage> storage) = 0;
|
virtual void ExecuteInteractive() = 0;
|
||||||
virtual void Execute(AppletStorageProxyFunction out_data,
|
virtual void Execute() = 0;
|
||||||
AppletStorageProxyFunction out_interactive_data,
|
|
||||||
AppletStateProxyFunction state) = 0;
|
|
||||||
|
|
||||||
bool IsInitialized() const {
|
bool IsInitialized() const {
|
||||||
return initialized;
|
return initialized;
|
||||||
|
@ -54,7 +86,7 @@ protected:
|
||||||
static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
|
static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
|
||||||
|
|
||||||
CommonArguments common_args;
|
CommonArguments common_args;
|
||||||
std::queue<std::shared_ptr<IStorage>> storage_stack;
|
std::shared_ptr<AppletDataBroker> broker;
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -42,22 +42,23 @@ SoftwareKeyboard::SoftwareKeyboard() = default;
|
||||||
|
|
||||||
SoftwareKeyboard::~SoftwareKeyboard() = default;
|
SoftwareKeyboard::~SoftwareKeyboard() = default;
|
||||||
|
|
||||||
void SoftwareKeyboard::Initialize(std::queue<std::shared_ptr<IStorage>> storage_) {
|
void SoftwareKeyboard::Initialize(std::shared_ptr<AppletDataBroker> broker_) {
|
||||||
complete = false;
|
complete = false;
|
||||||
initial_text.clear();
|
initial_text.clear();
|
||||||
final_data.clear();
|
final_data.clear();
|
||||||
|
|
||||||
Applet::Initialize(std::move(storage_));
|
Applet::Initialize(std::move(broker_));
|
||||||
|
|
||||||
ASSERT(storage_stack.size() >= 2);
|
const auto keyboard_config_storage = broker->PopNormalDataToApplet();
|
||||||
const auto& keyboard_config = storage_stack.front()->GetData();
|
ASSERT(keyboard_config_storage != nullptr);
|
||||||
storage_stack.pop();
|
const auto& keyboard_config = keyboard_config_storage->GetData();
|
||||||
|
|
||||||
ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig));
|
ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig));
|
||||||
std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig));
|
std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig));
|
||||||
|
|
||||||
const auto& work_buffer = storage_stack.front()->GetData();
|
const auto work_buffer_storage = broker->PopNormalDataToApplet();
|
||||||
storage_stack.pop();
|
ASSERT(work_buffer_storage != nullptr);
|
||||||
|
const auto& work_buffer = work_buffer_storage->GetData();
|
||||||
|
|
||||||
if (config.initial_string_size == 0)
|
if (config.initial_string_size == 0)
|
||||||
return;
|
return;
|
||||||
|
@ -76,10 +77,12 @@ ResultCode SoftwareKeyboard::GetStatus() const {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr<IStorage> storage) {
|
void SoftwareKeyboard::ExecuteInteractive() {
|
||||||
if (complete)
|
if (complete)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const auto storage = broker->PopInteractiveDataToApplet();
|
||||||
|
ASSERT(storage != nullptr);
|
||||||
const auto data = storage->GetData();
|
const auto data = storage->GetData();
|
||||||
const auto status = static_cast<bool>(data[0]);
|
const auto status = static_cast<bool>(data[0]);
|
||||||
|
|
||||||
|
@ -91,15 +94,14 @@ void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr<IStorage> storage)
|
||||||
std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string;
|
std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string;
|
||||||
std::memcpy(string.data(), data.data() + 4, string.size() * 2);
|
std::memcpy(string.data(), data.data() + 4, string.size() * 2);
|
||||||
frontend.SendTextCheckDialog(
|
frontend.SendTextCheckDialog(
|
||||||
Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()), state);
|
Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()),
|
||||||
|
[this] { broker->SignalStateChanged(); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data,
|
void SoftwareKeyboard::Execute() {
|
||||||
AppletStorageProxyFunction out_interactive_data,
|
|
||||||
AppletStateProxyFunction state) {
|
|
||||||
if (complete) {
|
if (complete) {
|
||||||
out_data(IStorage{final_data});
|
broker->PushNormalDataFromApplet(IStorage{final_data});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,9 +109,6 @@ void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data,
|
||||||
|
|
||||||
const auto parameters = ConvertToFrontendParameters(config, initial_text);
|
const auto parameters = ConvertToFrontendParameters(config, initial_text);
|
||||||
|
|
||||||
this->out_data = out_data;
|
|
||||||
this->out_interactive_data = out_interactive_data;
|
|
||||||
this->state = state;
|
|
||||||
frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(text); },
|
frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(text); },
|
||||||
parameters);
|
parameters);
|
||||||
}
|
}
|
||||||
|
@ -147,19 +146,19 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
|
||||||
final_data = output_main;
|
final_data = output_main;
|
||||||
|
|
||||||
if (complete) {
|
if (complete) {
|
||||||
out_data(IStorage{output_main});
|
broker->PushNormalDataFromApplet(IStorage{output_main});
|
||||||
} else {
|
} else {
|
||||||
out_data(IStorage{output_main});
|
broker->PushNormalDataFromApplet(IStorage{output_main});
|
||||||
out_interactive_data(IStorage{output_sub});
|
broker->PushInteractiveDataFromApplet(IStorage{output_sub});
|
||||||
}
|
}
|
||||||
|
|
||||||
state();
|
broker->SignalStateChanged();
|
||||||
} else {
|
} else {
|
||||||
status = ResultCode(-1);
|
status = ResultCode(-1);
|
||||||
output_main[0] = 1;
|
output_main[0] = 1;
|
||||||
complete = true;
|
complete = true;
|
||||||
out_data(IStorage{output_main});
|
broker->PushNormalDataFromApplet(IStorage{output_main});
|
||||||
state();
|
broker->SignalStateChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace Service::AM::Applets
|
} // namespace Service::AM::Applets
|
||||||
|
|
|
@ -50,14 +50,12 @@ public:
|
||||||
SoftwareKeyboard();
|
SoftwareKeyboard();
|
||||||
~SoftwareKeyboard() override;
|
~SoftwareKeyboard() override;
|
||||||
|
|
||||||
void Initialize(std::queue<std::shared_ptr<IStorage>> storage) override;
|
void Initialize(std::shared_ptr<AppletDataBroker> broker) override;
|
||||||
|
|
||||||
bool TransactionComplete() const override;
|
bool TransactionComplete() const override;
|
||||||
ResultCode GetStatus() const override;
|
ResultCode GetStatus() const override;
|
||||||
void ReceiveInteractiveData(std::shared_ptr<IStorage> storage) override;
|
void ExecuteInteractive() override;
|
||||||
void Execute(AppletStorageProxyFunction out_data,
|
void Execute() override;
|
||||||
AppletStorageProxyFunction out_interactive_data,
|
|
||||||
AppletStateProxyFunction state) override;
|
|
||||||
|
|
||||||
void WriteText(std::optional<std::u16string> text);
|
void WriteText(std::optional<std::u16string> text);
|
||||||
|
|
||||||
|
@ -67,10 +65,6 @@ private:
|
||||||
bool complete = false;
|
bool complete = false;
|
||||||
std::vector<u8> final_data;
|
std::vector<u8> final_data;
|
||||||
ResultCode status = ResultCode(-1);
|
ResultCode status = ResultCode(-1);
|
||||||
|
|
||||||
AppletStorageProxyFunction out_data;
|
|
||||||
AppletStorageProxyFunction out_interactive_data;
|
|
||||||
AppletStateProxyFunction state;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::AM::Applets
|
} // namespace Service::AM::Applets
|
||||||
|
|
Loading…
Reference in a new issue