From 7901de2b75bf527790c3c24e6667b275e2ebeb2b Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 9 Nov 2018 17:02:50 -0500 Subject: svc: Implement svcCreateTransferMemory Seems to be used and created identically to SharedMemory, so just reuse that. --- src/core/hle/kernel/svc.cpp | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 2e7c9d094..20af65ee7 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1194,9 +1194,39 @@ static ResultCode ResetSignal(Handle handle) { /// Creates a TransferMemory object static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) { - LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size, - permissions); - *handle = 0; + LOG_DEBUG(Kernel_SVC, "called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size, + permissions); + + if (!Common::Is4KBAligned(addr)) { + LOG_ERROR(Kernel_SVC, "Address ({:016X}) is not page aligned!", addr); + return ERR_INVALID_ADDRESS; + } + + if (!Common::Is4KBAligned(size) || size == 0) { + LOG_ERROR(Kernel_SVC, "Size ({:016X}) is not page aligned or equal to zero!", size); + return ERR_INVALID_ADDRESS; + } + + if (addr + size <= addr) { + LOG_ERROR(Kernel_SVC, "Address and size cause overflow! (address={:016X}, size={:016X})", + addr, size); + return ERR_INVALID_ADDRESS_STATE; + } + + if (permissions > static_cast(MemoryPermission::ReadWrite) || + permissions == static_cast(MemoryPermission::Write)) { + LOG_ERROR(Kernel_SVC, "Invalid memory permissions for transfer memory! (perms={:08X})", + permissions); + return ERR_INVALID_MEMORY_PERMISSIONS; + } + + auto& kernel = Core::System::GetInstance().Kernel(); + auto& handle_table = Core::CurrentProcess()->GetHandleTable(); + const auto perms = static_cast(permissions); + const auto shared_mem_handle = SharedMemory::Create( + kernel, handle_table.Get(CurrentProcess), size, perms, perms, addr); + + CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle)); return RESULT_SUCCESS; } -- cgit v1.2.3 From 76d515327b14c54036065167cb5dedcc5bf29eb2 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 9 Nov 2018 20:01:20 -0500 Subject: am: Implement CreateTransferMemoryStorage Creates an AM::IStorage object with the contents of the transfer memory located at the handle provided. --- src/core/hle/service/am/am.cpp | 25 +++++++++++++++++++++++++ src/core/hle/service/am/am.h | 1 + 2 files changed, 26 insertions(+) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 3758ecae1..a7716d80b 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -704,6 +704,31 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called, size={}", size); } +void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + rp.SetCurrentOffset(3); + const auto handle{rp.Pop()}; + + const auto shared_mem = + Core::System::GetInstance().CurrentProcess()->GetHandleTable().Get( + handle); + + if (shared_mem == nullptr) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultCode(-1)); + return; + } + + std::vector memory(shared_mem->size); + std::memcpy(memory.data(), shared_mem->backing_block->data() + shared_mem->backing_block_offset, + memory.size()); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(std::make_shared(std::move(memory))); +} + IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") { // clang-format off static const FunctionInfo functions[] = { diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 5a3fcba8f..50b2775ea 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -163,6 +163,7 @@ public: private: void CreateLibraryApplet(Kernel::HLERequestContext& ctx); void CreateStorage(Kernel::HLERequestContext& ctx); + void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx); }; class IApplicationFunctions final : public ServiceFramework { -- cgit v1.2.3 From c7b6c9de9c4004399edf8a010b74fee1127c7682 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 9 Nov 2018 20:04:07 -0500 Subject: am: Move IStorageAccessor to header and update backing buffer Writes to an AM::IStorage object through an IStorageAccessor will now be preserved once the accessor is destroyed. --- src/core/hle/service/am/am.cpp | 100 +++++++++++++++-------------------------- src/core/hle/service/am/am.h | 26 +++++++++++ 2 files changed, 62 insertions(+), 64 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index a7716d80b..c7344608c 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -587,87 +587,59 @@ private: } }; -class ILibraryAppletAccessor final : public ServiceFramework { -public: - explicit ILibraryAppletAccessor() : ServiceFramework("ILibraryAppletAccessor") { - // clang-format off +IStorageAccessor::IStorageAccessor(IStorage& storage) + : ServiceFramework("IStorageAccessor"), backing(storage) { + // clang-format off static const FunctionInfo functions[] = { - {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, - {1, nullptr, "IsCompleted"}, - {10, &ILibraryAppletAccessor::Start, "Start"}, - {20, nullptr, "RequestExit"}, - {25, nullptr, "Terminate"}, - {30, &ILibraryAppletAccessor::GetResult, "GetResult"}, - {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, - {100, &ILibraryAppletAccessor::PushInData, "PushInData"}, - {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"}, - {102, nullptr, "PushExtraStorage"}, - {103, nullptr, "PushInteractiveInData"}, - {104, nullptr, "PopInteractiveOutData"}, - {105, nullptr, "GetPopOutDataEvent"}, - {106, nullptr, "GetPopInteractiveOutDataEvent"}, - {110, nullptr, "NeedsToExitProcess"}, - {120, nullptr, "GetLibraryAppletInfo"}, - {150, nullptr, "RequestForAppletToGetForeground"}, - {160, nullptr, "GetIndirectLayerConsumerHandle"}, + {0, &IStorageAccessor::GetSize, "GetSize"}, + {10, &IStorageAccessor::Write, "Write"}, + {11, &IStorageAccessor::Read, "Read"}, }; - // 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"); - } +void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 4}; -private: - void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { - state_changed_event->Signal(); + rb.Push(RESULT_SUCCESS); + rb.Push(static_cast(backing.buffer.size())); - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(state_changed_event); + LOG_DEBUG(Service_AM, "called"); +} - LOG_WARNING(Service_AM, "(STUBBED) called"); - } +void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; - void GetResult(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); + const u64 offset{rp.Pop()}; + const std::vector data{ctx.ReadBuffer()}; - LOG_WARNING(Service_AM, "(STUBBED) called"); - } + const auto size = std::min(data.size(), backing.buffer.size() - offset); - void Start(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); + std::memcpy(&backing.buffer[offset], data.data(), size); - LOG_WARNING(Service_AM, "(STUBBED) called"); - } + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); - void PushInData(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - storage_stack.push(rp.PopIpcInterface()); + LOG_DEBUG(Service_AM, "called, offset={}", offset); +} - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); +void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; - LOG_DEBUG(Service_AM, "called"); - } + const u64 offset{rp.Pop()}; + std::size_t size{ctx.GetWriteBufferSize()}; - void PopOutData(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(std::move(storage_stack.top())); + size = std::min(size, backing.buffer.size() - offset); - storage_stack.pop(); + ctx.WriteBuffer(backing.buffer.data() + offset, size); - LOG_DEBUG(Service_AM, "called"); - } + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); - std::stack> storage_stack; - Kernel::SharedPtr state_changed_event; -}; + LOG_DEBUG(Service_AM, "called, offset={}", offset); +} ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") { static const FunctionInfo functions[] = { @@ -675,7 +647,7 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple {1, nullptr, "TerminateAllLibraryApplets"}, {2, nullptr, "AreAnyLibraryAppletsLeft"}, {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, - {11, nullptr, "CreateTransferMemoryStorage"}, + {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"}, {12, nullptr, "CreateHandleStorage"}, }; RegisterHandlers(functions); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 50b2775ea..640901e4a 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -155,6 +155,32 @@ private: std::shared_ptr msg_queue; }; +class IStorage final : public ServiceFramework { +public: + explicit IStorage(std::vector buffer); + + const std::vector& GetData() const; + +private: + std::vector buffer; + + void Open(Kernel::HLERequestContext& ctx); + + friend class IStorageAccessor; +}; + +class IStorageAccessor final : public ServiceFramework { +public: + explicit IStorageAccessor(IStorage& backing); + +private: + IStorage& backing; + + void GetSize(Kernel::HLERequestContext& ctx); + void Write(Kernel::HLERequestContext& ctx); + void Read(Kernel::HLERequestContext& ctx); +}; + class ILibraryAppletCreator final : public ServiceFramework { public: ILibraryAppletCreator(); -- cgit v1.2.3 From 0682a908c0ab79a5137f408cafc3aff07c7c7be5 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 9 Nov 2018 20:04:43 -0500 Subject: am: Move AM::IStorage to header Needs to be accessible by applet files. --- src/core/hle/service/am/am.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index c7344608c..35481b201 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -481,6 +481,22 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& LOG_DEBUG(Service_AM, "called"); } +IStorage::IStorage(std::vector buffer) + : ServiceFramework("IStorage"), buffer(std::move(buffer)) { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IStorage::Open, "Open"}, + {1, nullptr, "OpenTransferStorage"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +const std::vector& IStorage::GetData() const { + return buffer; +} + void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { const bool use_docked_mode{Settings::values.use_docked_mode}; IPC::ResponseBuilder rb{ctx, 3}; -- cgit v1.2.3 From 5ce6b8fea7122fb8267252d09d4416769637702d Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 9 Nov 2018 20:06:50 -0500 Subject: am: Convert storage stack to vector std::stack was no longer suitable for non-trivial operations --- src/core/hle/service/am/am.cpp | 86 +++++++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 27 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 35481b201..a872bea0c 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -516,31 +516,56 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); } -class IStorageAccessor final : public ServiceFramework { +class ILibraryAppletAccessor final : public ServiceFramework { public: - explicit IStorageAccessor(std::vector buffer) - : ServiceFramework("IStorageAccessor"), buffer(std::move(buffer)) { + explicit ILibraryAppletAccessor(std::shared_ptr applet) + : ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)) { // clang-format off static const FunctionInfo functions[] = { - {0, &IStorageAccessor::GetSize, "GetSize"}, - {10, &IStorageAccessor::Write, "Write"}, - {11, &IStorageAccessor::Read, "Read"}, + {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, + {1, nullptr, "IsCompleted"}, + {10, &ILibraryAppletAccessor::Start, "Start"}, + {20, nullptr, "RequestExit"}, + {25, nullptr, "Terminate"}, + {30, &ILibraryAppletAccessor::GetResult, "GetResult"}, + {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, + {100, &ILibraryAppletAccessor::PushInData, "PushInData"}, + {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"}, + {102, nullptr, "PushExtraStorage"}, + {103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"}, + {104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"}, + {105, nullptr, "GetPopOutDataEvent"}, + {106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"}, + {110, nullptr, "NeedsToExitProcess"}, + {120, nullptr, "GetLibraryAppletInfo"}, + {150, nullptr, "RequestForAppletToGetForeground"}, + {160, nullptr, "GetIndirectLayerConsumerHandle"}, }; // clang-format on RegisterHandlers(functions); + + auto& kernel = Core::System::GetInstance().Kernel(); + state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, + "ILibraryAppletAccessor:StateChangedEvent"); } private: - std::vector buffer; + void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { + state_changed_event->Signal(); - void GetSize(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 4}; + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(state_changed_event); + + LOG_WARNING(Service_AM, "(STUBBED) called"); + } + void GetResult(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - rb.Push(static_cast(buffer.size())); - LOG_DEBUG(Service_AM, "called"); + LOG_WARNING(Service_AM, "(STUBBED) called"); } void Write(Kernel::HLERequestContext& ctx) { @@ -551,21 +576,25 @@ private: ASSERT(offset + data.size() <= buffer.size()); - std::memcpy(&buffer[offset], data.data(), data.size()); + void PushInData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + storage_stack.push_back(rp.PopIpcInterface()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_DEBUG(Service_AM, "called, offset={}", offset); + LOG_DEBUG(Service_AM, "called"); } - void Read(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; + void PopOutData(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(std::move(storage_stack.back())); - const u64 offset{rp.Pop()}; - const std::size_t size{ctx.GetWriteBufferSize()}; + storage_stack.pop_back(); - ASSERT(offset + size <= buffer.size()); + LOG_DEBUG(Service_AM, "called"); + } ctx.WriteBuffer(buffer.data() + offset, size); @@ -590,18 +619,21 @@ public: RegisterHandlers(functions); } -private: - std::vector buffer; + std::shared_ptr applet; + std::vector> storage_stack; + std::vector> interactive_storage_stack; + Kernel::SharedPtr state_changed_event; + Kernel::SharedPtr pop_interactive_out_data_event; +}; - void Open(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; +void IStorage::Open(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(buffer); + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(*this); - LOG_DEBUG(Service_AM, "called"); - } -}; + LOG_DEBUG(Service_AM, "called"); +} IStorageAccessor::IStorageAccessor(IStorage& storage) : ServiceFramework("IStorageAccessor"), backing(storage) { -- cgit v1.2.3 From ba03bfa4309664d55d585c89271d9656f8385a78 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 9 Nov 2018 20:07:42 -0500 Subject: am: Implement PopInteractiveOutData and PushInteractiveInData Used by software keyboard applet for data transfer. --- src/core/hle/service/am/am.cpp | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index a872bea0c..b78489df7 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -548,6 +548,9 @@ public: auto& kernel = Core::System::GetInstance().Kernel(); state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:StateChangedEvent"); + pop_interactive_out_data_event = + Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, + "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); } private: @@ -596,27 +599,34 @@ private: LOG_DEBUG(Service_AM, "called"); } - ctx.WriteBuffer(buffer.data() + offset, size); + void PushInteractiveInData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + interactive_storage_stack.push_back(rp.PopIpcInterface()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_DEBUG(Service_AM, "called, offset={}", offset); + LOG_DEBUG(Service_AM, "called"); } -}; -class IStorage final : public ServiceFramework { -public: - explicit IStorage(std::vector buffer) - : ServiceFramework("IStorage"), buffer(std::move(buffer)) { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IStorage::Open, "Open"}, - {1, nullptr, "OpenTransferStorage"}, - }; - // clang-format on + void PopInteractiveOutData(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(std::move(interactive_storage_stack.back())); - RegisterHandlers(functions); + interactive_storage_stack.pop_back(); + + LOG_DEBUG(Service_AM, "called"); + } + + void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) { + pop_interactive_out_data_event->Signal(); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(pop_interactive_out_data_event); + + LOG_WARNING(Service_AM, "(STUBBED) called"); } std::shared_ptr applet; -- cgit v1.2.3 From 731b4bd69185e741282415b66cc39fd482c039b9 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 9 Nov 2018 20:08:25 -0500 Subject: am: Unstub ILibraryAppletAccessor::Start Now starts the applet provided in constructor. --- src/core/hle/service/am/am.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index b78489df7..4b7aacbac 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -6,10 +6,14 @@ #include #include #include +#include "applets/applets.h" +#include "applets/software_keyboard.h" +#include "audio_core/audio_renderer.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/shared_memory.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" @@ -28,6 +32,10 @@ namespace Service::AM { +enum class AppletId : u32 { + SoftwareKeyboard = 0x11, +}; + constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA; struct LaunchParameters { @@ -571,13 +579,17 @@ private: LOG_WARNING(Service_AM, "(STUBBED) called"); } - void Write(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; + void Start(Kernel::HLERequestContext& ctx) { + ASSERT(applet != nullptr); - const u64 offset{rp.Pop()}; - const std::vector data{ctx.ReadBuffer()}; + applet->Initialize(storage_stack); + interactive_storage_stack.push_back(std::make_shared(applet->Execute())); + state_changed_event->Signal(); + pop_interactive_out_data_event->Signal(); - ASSERT(offset + data.size() <= buffer.size()); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } void PushInData(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; -- cgit v1.2.3 From 5b95de0c9cbe5185283e36426035798e05555c21 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 9 Nov 2018 20:09:37 -0500 Subject: am/applets: Add Applet superclass to describe a generic applet Adds an Initialize and Execute methods which are used by the ILibraryAppletAccessor to start and control the applet. --- src/core/hle/service/am/applets/applets.cpp | 29 ++++++++++++++++++ src/core/hle/service/am/applets/applets.h | 46 +++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 src/core/hle/service/am/applets/applets.cpp create mode 100644 src/core/hle/service/am/applets/applets.h (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp new file mode 100644 index 000000000..8cc4b0f1a --- /dev/null +++ b/src/core/hle/service/am/applets/applets.cpp @@ -0,0 +1,29 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/frontend/applets/software_keyboard.h" +#include "core/hle/service/am/applets/applets.h" + +namespace Service::AM::Applets { + +std::shared_ptr software_keyboard = + std::make_shared(); + +void Applet::Initialize(std::vector> storage) { + storage_stack = std::move(storage); + initialized = true; +} + +void RegisterSoftwareKeyboard(std::shared_ptr applet) { + if (applet == nullptr) + return; + + software_keyboard = std::move(applet); +} + +std::shared_ptr GetSoftwareKeyboard() { + return software_keyboard; +} + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h new file mode 100644 index 000000000..1f91392b4 --- /dev/null +++ b/src/core/hle/service/am/applets/applets.h @@ -0,0 +1,46 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include "common/swap.h" + +namespace Frontend { +class SoftwareKeyboardApplet; +} + +namespace Service::AM { + +class IStorage; + +namespace Applets { + +class Applet { +public: + virtual void Initialize(std::vector> storage); + + virtual IStorage Execute() = 0; + +protected: + struct CommonArguments { + u32_le arguments_version; + u32_le size; + u32_le library_version; + u32_le theme_color; + u8 play_startup_sound; + u64_le system_tick; + }; + static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size."); + + std::vector> storage_stack; + bool initialized = false; +}; + +void RegisterSoftwareKeyboard(std::shared_ptr applet); +std::shared_ptr GetSoftwareKeyboard(); + +} // namespace Applets +} // namespace Service::AM -- cgit v1.2.3 From de16c1e45326a5bb587a2c270b9b39042b245f7c Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 9 Nov 2018 20:12:12 -0500 Subject: am/applets: Add connector between frontend and AM applet classes Provides a middleman between the Frontend provider class and the expected AM::Applets::Applet class needed by ILibraryAppletAccessor --- .../hle/service/am/applets/software_keyboard.cpp | 71 ++++++++++++++++++++++ .../hle/service/am/applets/software_keyboard.h | 57 +++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 src/core/hle/service/am/applets/software_keyboard.cpp create mode 100644 src/core/hle/service/am/applets/software_keyboard.h (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp new file mode 100644 index 000000000..ad1797ef1 --- /dev/null +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -0,0 +1,71 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "common/string_util.h" +#include "core/frontend/applets/software_keyboard.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/applets/software_keyboard.h" + +namespace Service::AM::Applets { + +constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8; +constexpr std::size_t DEFAULT_MAX_LENGTH = 500; + +static Frontend::SoftwareKeyboardApplet::Parameters ConvertToFrontendParameters( + KeyboardConfig config, std::u16string initial_text) { + Frontend::SoftwareKeyboardApplet::Parameters params{}; + + params.submit_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( + config.submit_text.data(), config.submit_text.size()); + params.header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( + config.header_text.data(), config.header_text.size()); + params.sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.sub_text.data(), + config.sub_text.size()); + params.guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.guide_text.data(), + config.guide_text.size()); + params.initial_text = initial_text; + params.max_length = config.length_limit == 0 ? DEFAULT_MAX_LENGTH : config.length_limit; + params.password = static_cast(config.is_password); + params.cursor_at_beginning = static_cast(config.initial_cursor_position); + params.value = static_cast(config.keyset_disable_bitmask); + + return params; +} + +void SoftwareKeyboard::Initialize(std::vector> storage_) { + Applet::Initialize(std::move(storage_)); + + ASSERT(storage_stack.size() >= 2); + const auto& keyboard_config = storage_stack[1]->GetData(); + ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig)); + std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig)); + + ASSERT_MSG(config.text_check == 0, "Text check software keyboard mode is not implemented!"); + + const auto& work_buffer = storage_stack[2]->GetData(); + std::memcpy(initial_text.data(), work_buffer.data() + config.initial_string_offset, + config.initial_string_size); +} + +IStorage SoftwareKeyboard::Execute() { + const auto frontend{GetSoftwareKeyboard()}; + ASSERT(frontend != nullptr); + + const auto parameters = ConvertToFrontendParameters(config, initial_text); + + std::u16string text; + const auto success = frontend->GetText(parameters, text); + + std::vector output(SWKBD_OUTPUT_BUFFER_SIZE); + + if (success) { + output[0] = 1; + std::memcpy(output.data() + 4, text.data(), + std::min(text.size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4)); + } + + return IStorage{output}; +} +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h new file mode 100644 index 000000000..9a37ba45f --- /dev/null +++ b/src/core/hle/service/am/applets/software_keyboard.h @@ -0,0 +1,57 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_funcs.h" +#include "core/hle/service/am/applets/applets.h" + +namespace Service::AM::Applets { + +enum class KeysetDisable : u32 { + Space = 0x02, + Address = 0x04, + Percent = 0x08, + Slashes = 0x10, + Numbers = 0x40, + DownloadCode = 0x80, +}; + +struct KeyboardConfig { + INSERT_PADDING_BYTES(4); + std::array submit_text; + u16_le left_symbol_key; + u16_le right_symbol_key; + INSERT_PADDING_BYTES(1); + KeysetDisable keyset_disable_bitmask; + u32_le initial_cursor_position; + std::array header_text; + std::array sub_text; + std::array guide_text; + u32_le length_limit; + INSERT_PADDING_BYTES(4); + u32_le is_password; + INSERT_PADDING_BYTES(6); + bool draw_background; + u32_le initial_string_offset; + u32_le initial_string_size; + u32_le user_dictionary_offset; + u32_le user_dictionary_size; + bool text_check; + u64_le text_check_callback; +}; +static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect size."); + +class SoftwareKeyboard final : public Applet { +public: + void Initialize(std::vector> storage) override; + + IStorage Execute() override; + +private: + KeyboardConfig config; + std::u16string initial_text; +}; + +} // namespace Service::AM::Applets -- cgit v1.2.3 From 48fcb43585132e52acaf9d859dd5d39fb308cb14 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 9 Nov 2018 20:14:01 -0500 Subject: am: Construct and use proper applets with ILibraryAppletAccessor Allows use of software keyboard applet and future applets to be easily added by adding enum ID and a switch case. --- src/core/hle/service/am/am.cpp | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 4b7aacbac..53580d673 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -725,11 +725,36 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple ILibraryAppletCreator::~ILibraryAppletCreator() = default; +static std::shared_ptr GetAppletFromId(AppletId id) { + switch (id) { + case AppletId::SoftwareKeyboard: + return std::make_shared(); + default: + UNREACHABLE_MSG("Unimplemented AppletId [{:08X}]!", static_cast(id)); + return nullptr; + } +} + void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_id = rp.PopRaw(); + const auto applet_mode = rp.PopRaw(); + + LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", + static_cast(applet_id), applet_mode); + + const auto applet = GetAppletFromId(applet_id); + + if (applet == nullptr) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultCode(-1)); + return; + } + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(); + rb.PushIpcInterface(applet); LOG_DEBUG(Service_AM, "called"); } -- cgit v1.2.3 From e696ed1f4d20f28f8b26c637498962938df7d96f Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 11 Nov 2018 16:39:25 -0500 Subject: am: Deglobalize software keyboard applet --- src/core/hle/kernel/svc.cpp | 8 ++++---- src/core/hle/service/am/am.cpp | 14 +++++++++----- src/core/hle/service/am/am.h | 10 ++++++---- src/core/hle/service/am/applets/applets.cpp | 16 +++------------- src/core/hle/service/am/applets/applets.h | 10 +++++++--- src/core/hle/service/am/applets/software_keyboard.cpp | 12 ++++++++++-- src/core/hle/service/am/applets/software_keyboard.h | 9 +++++++++ 7 files changed, 48 insertions(+), 31 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 20af65ee7..f84b00a00 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1207,14 +1207,15 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 return ERR_INVALID_ADDRESS; } - if (addr + size <= addr) { + if (!IsValidAddressRange(addr, size)) { LOG_ERROR(Kernel_SVC, "Address and size cause overflow! (address={:016X}, size={:016X})", addr, size); return ERR_INVALID_ADDRESS_STATE; } - if (permissions > static_cast(MemoryPermission::ReadWrite) || - permissions == static_cast(MemoryPermission::Write)) { + const auto perms = static_cast(permissions); + if (perms != MemoryPermission::None && perms != MemoryPermission::Read && + perms != MemoryPermission::ReadWrite) { LOG_ERROR(Kernel_SVC, "Invalid memory permissions for transfer memory! (perms={:08X})", permissions); return ERR_INVALID_MEMORY_PERMISSIONS; @@ -1222,7 +1223,6 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 auto& kernel = Core::System::GetInstance().Kernel(); auto& handle_table = Core::CurrentProcess()->GetHandleTable(); - const auto perms = static_cast(permissions); const auto shared_mem_handle = SharedMemory::Create( kernel, handle_table.Get(CurrentProcess), size, perms, perms, addr); diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 53580d673..fc464270e 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -501,6 +501,8 @@ IStorage::IStorage(std::vector buffer) RegisterHandlers(functions); } +IStorage::~IStorage() = default; + const std::vector& IStorage::GetData() const { return buffer; } @@ -670,6 +672,8 @@ IStorageAccessor::IStorageAccessor(IStorage& storage) RegisterHandlers(functions); } +IStorageAccessor::~IStorageAccessor() = default; + void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; @@ -685,7 +689,7 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { const u64 offset{rp.Pop()}; const std::vector data{ctx.ReadBuffer()}; - const auto size = std::min(data.size(), backing.buffer.size() - offset); + const auto size = std::min(data.size(), backing.buffer.size() - offset); std::memcpy(&backing.buffer[offset], data.data(), size); @@ -701,7 +705,7 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { const u64 offset{rp.Pop()}; std::size_t size{ctx.GetWriteBufferSize()}; - size = std::min(size, backing.buffer.size() - offset); + size = std::min(size, backing.buffer.size() - offset); ctx.WriteBuffer(backing.buffer.data() + offset, size); @@ -787,9 +791,9 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex return; } - std::vector memory(shared_mem->size); - std::memcpy(memory.data(), shared_mem->backing_block->data() + shared_mem->backing_block_offset, - memory.size()); + const auto mem_begin = shared_mem->backing_block->begin() + shared_mem->backing_block_offset; + const auto mem_end = mem_begin + shared_mem->size; + std::vector memory{mem_begin, mem_end}; IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 640901e4a..44c1bcde5 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -158,27 +158,29 @@ private: class IStorage final : public ServiceFramework { public: explicit IStorage(std::vector buffer); + ~IStorage() override; const std::vector& GetData() const; private: - std::vector buffer; - void Open(Kernel::HLERequestContext& ctx); + std::vector buffer; + friend class IStorageAccessor; }; class IStorageAccessor final : public ServiceFramework { public: explicit IStorageAccessor(IStorage& backing); + ~IStorageAccessor() override; private: - IStorage& backing; - void GetSize(Kernel::HLERequestContext& ctx); void Write(Kernel::HLERequestContext& ctx); void Read(Kernel::HLERequestContext& ctx); + + IStorage& backing; }; class ILibraryAppletCreator final : public ServiceFramework { diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 8cc4b0f1a..03b9d83e7 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -7,23 +7,13 @@ namespace Service::AM::Applets { -std::shared_ptr software_keyboard = - std::make_shared(); +Applet::Applet() = default; + +Applet::~Applet() = default; void Applet::Initialize(std::vector> storage) { storage_stack = std::move(storage); initialized = true; } -void RegisterSoftwareKeyboard(std::shared_ptr applet) { - if (applet == nullptr) - return; - - software_keyboard = std::move(applet); -} - -std::shared_ptr GetSoftwareKeyboard() { - return software_keyboard; -} - } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 1f91392b4..47db22fb4 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -20,10 +20,17 @@ namespace Applets { class Applet { public: + Applet(); + virtual ~Applet(); + virtual void Initialize(std::vector> storage); virtual IStorage Execute() = 0; + bool IsInitialized() const { + return initialized; + } + protected: struct CommonArguments { u32_le arguments_version; @@ -39,8 +46,5 @@ protected: bool initialized = false; }; -void RegisterSoftwareKeyboard(std::shared_ptr applet); -std::shared_ptr GetSoftwareKeyboard(); - } // namespace Applets } // namespace Service::AM diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index ad1797ef1..556dea3e4 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -2,8 +2,10 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include "common/assert.h" #include "common/string_util.h" +#include "core/core.h" #include "core/frontend/applets/software_keyboard.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/software_keyboard.h" @@ -11,11 +13,13 @@ namespace Service::AM::Applets { constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8; +constexpr std::size_t SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE = 0x7D4; constexpr std::size_t DEFAULT_MAX_LENGTH = 500; +constexpr bool INTERACTIVE_STATUS_OK = false; -static Frontend::SoftwareKeyboardApplet::Parameters ConvertToFrontendParameters( +static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters( KeyboardConfig config, std::u16string initial_text) { - Frontend::SoftwareKeyboardApplet::Parameters params{}; + Core::Frontend::SoftwareKeyboardParameters params{}; params.submit_text = Common::UTF16StringFromFixedZeroTerminatedBuffer( config.submit_text.data(), config.submit_text.size()); @@ -34,6 +38,10 @@ static Frontend::SoftwareKeyboardApplet::Parameters ConvertToFrontendParameters( return params; } +SoftwareKeyboard::SoftwareKeyboard() = default; + +SoftwareKeyboard::~SoftwareKeyboard() = default; + void SoftwareKeyboard::Initialize(std::vector> storage_) { Applet::Initialize(std::move(storage_)); diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h index 9a37ba45f..9d77f5802 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h @@ -5,6 +5,7 @@ #pragma once #include "common/common_funcs.h" +#include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applets.h" namespace Service::AM::Applets { @@ -45,13 +46,21 @@ static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect siz class SoftwareKeyboard final : public Applet { public: + SoftwareKeyboard(); + ~SoftwareKeyboard() override; + void Initialize(std::vector> storage) override; + bool TransactionComplete() const override; + ResultCode GetStatus() const override; + void ReceiveInteractiveData(std::shared_ptr storage) override; IStorage Execute() override; private: KeyboardConfig config; std::u16string initial_text; + bool complete = false; + std::vector final_data; }; } // namespace Service::AM::Applets -- cgit v1.2.3 From fed6ab14c37f196f2a2fd378b46d7e5bd0118224 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 11 Nov 2018 16:41:31 -0500 Subject: am: Implement text check software keyboard mode Allows the game to verify and send a message to the frontend. --- src/core/hle/service/am/am.cpp | 37 ++++++++++-- src/core/hle/service/am/applets/applets.h | 5 ++ .../hle/service/am/applets/software_keyboard.cpp | 67 +++++++++++++++++++--- 3 files changed, 95 insertions(+), 14 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index fc464270e..ea00c5c72 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -544,7 +544,7 @@ public: {102, nullptr, "PushExtraStorage"}, {103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"}, {104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"}, - {105, nullptr, "GetPopOutDataEvent"}, + {105, &ILibraryAppletAccessor::GetPopOutDataEvent, "GetPopOutDataEvent"}, {106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"}, {110, nullptr, "NeedsToExitProcess"}, {120, nullptr, "GetLibraryAppletInfo"}, @@ -558,6 +558,8 @@ public: 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"); @@ -585,9 +587,16 @@ private: ASSERT(applet != nullptr); applet->Initialize(storage_stack); - interactive_storage_stack.push_back(std::make_shared(applet->Execute())); + const auto data = std::make_shared(applet->Execute()); state_changed_event->Signal(); - pop_interactive_out_data_event->Signal(); + + if (applet->TransactionComplete()) { + storage_stack.push_back(data); + pop_out_data_event->Signal(); + } else { + interactive_storage_stack.push_back(data); + pop_interactive_out_data_event->Signal(); + } IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -617,6 +626,19 @@ private: IPC::RequestParser rp{ctx}; interactive_storage_stack.push_back(rp.PopIpcInterface()); + ASSERT(applet->IsInitialized()); + applet->ReceiveInteractiveData(interactive_storage_stack.back()); + const auto data = std::make_shared(applet->Execute()); + state_changed_event->Signal(); + + if (applet->TransactionComplete()) { + storage_stack.push_back(data); + pop_out_data_event->Signal(); + } else { + interactive_storage_stack.push_back(data); + pop_interactive_out_data_event->Signal(); + } + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -633,9 +655,13 @@ private: LOG_DEBUG(Service_AM, "called"); } - void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) { - pop_interactive_out_data_event->Signal(); + void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(pop_out_data_event); + } + void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(pop_interactive_out_data_event); @@ -647,6 +673,7 @@ private: std::vector> storage_stack; std::vector> interactive_storage_stack; Kernel::SharedPtr state_changed_event; + Kernel::SharedPtr pop_out_data_event; Kernel::SharedPtr pop_interactive_out_data_event; }; diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 47db22fb4..6d90eb608 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -8,6 +8,8 @@ #include #include "common/swap.h" +union ResultCode; + namespace Frontend { class SoftwareKeyboardApplet; } @@ -25,6 +27,9 @@ public: virtual void Initialize(std::vector> storage); + virtual bool TransactionComplete() const = 0; + virtual ResultCode GetStatus() const = 0; + virtual void ReceiveInteractiveData(std::shared_ptr storage) = 0; virtual IStorage Execute() = 0; bool IsInitialized() const { diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 556dea3e4..044a16264 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -50,28 +50,77 @@ void SoftwareKeyboard::Initialize(std::vector> storage ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig)); std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig)); - ASSERT_MSG(config.text_check == 0, "Text check software keyboard mode is not implemented!"); - const auto& work_buffer = storage_stack[2]->GetData(); - std::memcpy(initial_text.data(), work_buffer.data() + config.initial_string_offset, - config.initial_string_size); + + if (config.initial_string_size == 0) + return; + + std::vector string(config.initial_string_size); + std::memcpy(string.data(), work_buffer.data() + 4, string.size() * 2); + initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()); +} + +bool SoftwareKeyboard::TransactionComplete() const { + return complete; +} + +ResultCode SoftwareKeyboard::GetStatus() const { + return RESULT_SUCCESS; +} + +void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr storage) { + if (complete) + return; + + const auto data = storage->GetData(); + const auto status = static_cast(data[0]); + + if (status == INTERACTIVE_STATUS_OK) { + complete = true; + } else { + const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()}; + + std::array string; + std::memcpy(string.data(), data.data() + 4, string.size() * 2); + frontend.SendTextCheckDialog( + Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size())); + } } IStorage SoftwareKeyboard::Execute() { - const auto frontend{GetSoftwareKeyboard()}; - ASSERT(frontend != nullptr); + if (complete) + return IStorage{final_data}; + + const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()}; const auto parameters = ConvertToFrontendParameters(config, initial_text); std::u16string text; - const auto success = frontend->GetText(parameters, text); + const auto success = frontend.GetText(parameters, text); std::vector output(SWKBD_OUTPUT_BUFFER_SIZE); if (success) { - output[0] = 1; + if (config.text_check) { + const auto size = static_cast(text.size() * 2 + 4); + std::memcpy(output.data(), &size, sizeof(u32)); + } else { + output[0] = 1; + } + std::memcpy(output.data() + 4, text.data(), - std::min(text.size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4)); + std::min(text.size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4)); + } else { + complete = true; + final_data = std::move(output); + return IStorage{final_data}; + } + + complete = !config.text_check; + + if (complete) { + final_data = std::move(output); + return IStorage{final_data}; } return IStorage{output}; -- cgit v1.2.3 From 3cf7246e376445320e2b55165265228736f65214 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 11 Nov 2018 16:57:59 -0500 Subject: am: Implement ILibraryAppletAccessor IsCompleted and GetResult --- src/core/hle/service/am/am.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index ea00c5c72..3201e2d4b 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -533,7 +533,7 @@ public: // clang-format off static const FunctionInfo functions[] = { {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, - {1, nullptr, "IsCompleted"}, + {1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"}, {10, &ILibraryAppletAccessor::Start, "Start"}, {20, nullptr, "RequestExit"}, {25, nullptr, "Terminate"}, @@ -576,11 +576,15 @@ private: LOG_WARNING(Service_AM, "(STUBBED) called"); } - void GetResult(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2}; + void IsCompleted(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); + rb.Push(applet->TransactionComplete()); + } - LOG_WARNING(Service_AM, "(STUBBED) called"); + void GetResult(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(applet->GetStatus()); } void Start(Kernel::HLERequestContext& ctx) { -- cgit v1.2.3 From 7cfb29de23836aa1873bbb108e3d25a0e9dcfa6d Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 11 Nov 2018 20:16:38 -0500 Subject: am: Allow applets to push multiple and different channels of data --- src/core/hle/service/am/am.cpp | 34 ++++++++++------------ src/core/hle/service/am/applets/applets.h | 6 +++- .../hle/service/am/applets/software_keyboard.cpp | 27 +++++++---------- .../hle/service/am/applets/software_keyboard.h | 3 +- 4 files changed, 34 insertions(+), 36 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 3201e2d4b..3f8d97d31 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -566,6 +566,16 @@ public: } private: + void AppletStorageProxyOutData(IStorage storage) { + storage_stack.push_back(std::make_shared(storage)); + pop_out_data_event->Signal(); + } + + void AppletStorageProxyOutInteractiveData(IStorage storage) { + interactive_storage_stack.push_back(std::make_shared(storage)); + pop_interactive_out_data_event->Signal(); + } + void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { state_changed_event->Signal(); @@ -591,17 +601,11 @@ private: ASSERT(applet != nullptr); applet->Initialize(storage_stack); - const auto data = std::make_shared(applet->Execute()); + applet->Execute( + [this](IStorage storage) { AppletStorageProxyOutData(storage); }, + [this](IStorage storage) { AppletStorageProxyOutInteractiveData(storage); }); state_changed_event->Signal(); - if (applet->TransactionComplete()) { - storage_stack.push_back(data); - pop_out_data_event->Signal(); - } else { - interactive_storage_stack.push_back(data); - pop_interactive_out_data_event->Signal(); - } - IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } @@ -632,17 +636,11 @@ private: ASSERT(applet->IsInitialized()); applet->ReceiveInteractiveData(interactive_storage_stack.back()); - const auto data = std::make_shared(applet->Execute()); + applet->Execute( + [this](IStorage storage) { AppletStorageProxyOutData(storage); }, + [this](IStorage storage) { AppletStorageProxyOutInteractiveData(storage); }); state_changed_event->Signal(); - if (applet->TransactionComplete()) { - storage_stack.push_back(data); - pop_out_data_event->Signal(); - } else { - interactive_storage_stack.push_back(data); - pop_interactive_out_data_event->Signal(); - } - IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 6d90eb608..7fbaaf2f3 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include "common/swap.h" @@ -20,6 +21,8 @@ class IStorage; namespace Applets { +using AppletStorageProxyFunction = std::function; + class Applet { public: Applet(); @@ -30,7 +33,8 @@ public: virtual bool TransactionComplete() const = 0; virtual ResultCode GetStatus() const = 0; virtual void ReceiveInteractiveData(std::shared_ptr storage) = 0; - virtual IStorage Execute() = 0; + virtual void Execute(AppletStorageProxyFunction out_data, + AppletStorageProxyFunction out_interactive_data) = 0; bool IsInitialized() const { return initialized; diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 044a16264..7352f3bdf 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -87,42 +87,37 @@ void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr storage) } } -IStorage SoftwareKeyboard::Execute() { +void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data, + AppletStorageProxyFunction out_interactive_data) { if (complete) - return IStorage{final_data}; + return; const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()}; const auto parameters = ConvertToFrontendParameters(config, initial_text); - std::u16string text; - const auto success = frontend.GetText(parameters, text); + const auto res = frontend.GetText(parameters); std::vector output(SWKBD_OUTPUT_BUFFER_SIZE); - if (success) { + if (res.has_value()) { if (config.text_check) { - const auto size = static_cast(text.size() * 2 + 4); + const auto size = static_cast(res->size() * 2 + 4); std::memcpy(output.data(), &size, sizeof(u32)); } else { output[0] = 1; } - std::memcpy(output.data() + 4, text.data(), - std::min(text.size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4)); + std::memcpy(output.data() + 4, res->data(), + std::min(res->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4)); } else { complete = true; - final_data = std::move(output); - return IStorage{final_data}; + out_data(IStorage{output}); + return; } complete = !config.text_check; - if (complete) { - final_data = std::move(output); - return IStorage{final_data}; - } - - return IStorage{output}; + (complete ? out_data : out_interactive_data)(IStorage{output}); } } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h index 9d77f5802..66de4bc59 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h @@ -54,7 +54,8 @@ public: bool TransactionComplete() const override; ResultCode GetStatus() const override; void ReceiveInteractiveData(std::shared_ptr storage) override; - IStorage Execute() override; + void Execute(AppletStorageProxyFunction out_data, + AppletStorageProxyFunction out_interactive_data) override; private: KeyboardConfig config; -- cgit v1.2.3 From 8b433beff34c382e50334bb59c4f71394845558c Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 12 Nov 2018 11:08:09 -0500 Subject: software_keyboard: Make GetText asynchronous a --- src/core/hle/service/am/am.cpp | 2 +- src/core/hle/service/am/applets/software_keyboard.cpp | 19 ++++++++++++++----- src/core/hle/service/am/applets/software_keyboard.h | 5 +++++ 3 files changed, 20 insertions(+), 6 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 3f8d97d31..d040d4776 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -718,7 +718,7 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { const u64 offset{rp.Pop()}; const std::vector data{ctx.ReadBuffer()}; - const auto size = std::min(data.size(), backing.buffer.size() - offset); + const auto size = std::min(data.size(), backing.buffer.size() - offset); std::memcpy(&backing.buffer[offset], data.data(), size); diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 7352f3bdf..66b34d5ac 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -43,6 +43,10 @@ SoftwareKeyboard::SoftwareKeyboard() = default; SoftwareKeyboard::~SoftwareKeyboard() = default; void SoftwareKeyboard::Initialize(std::vector> storage_) { + complete = false; + initial_text.clear(); + final_data.clear(); + Applet::Initialize(std::move(storage_)); ASSERT(storage_stack.size() >= 2); @@ -96,20 +100,25 @@ void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data, const auto parameters = ConvertToFrontendParameters(config, initial_text); - const auto res = frontend.GetText(parameters); + this->out_data = out_data; + this->out_interactive_data = out_interactive_data; + frontend.RequestText([this](std::optional text) { WriteText(text); }, + parameters); +} +void SoftwareKeyboard::WriteText(std::optional text) { std::vector output(SWKBD_OUTPUT_BUFFER_SIZE); - if (res.has_value()) { + if (text.has_value()) { if (config.text_check) { - const auto size = static_cast(res->size() * 2 + 4); + const auto size = static_cast(text->size() * 2 + 4); std::memcpy(output.data(), &size, sizeof(u32)); } else { output[0] = 1; } - std::memcpy(output.data() + 4, res->data(), - std::min(res->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4)); + std::memcpy(output.data() + 4, text->data(), + std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4)); } else { complete = true; out_data(IStorage{output}); diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h index 66de4bc59..b08bff3d7 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h @@ -57,11 +57,16 @@ public: void Execute(AppletStorageProxyFunction out_data, AppletStorageProxyFunction out_interactive_data) override; + void WriteText(std::optional text); + private: KeyboardConfig config; std::u16string initial_text; bool complete = false; std::vector final_data; + + AppletStorageProxyFunction out_data; + AppletStorageProxyFunction out_interactive_data; }; } // namespace Service::AM::Applets -- cgit v1.2.3 From 6209fe0c27a5557c20ff6350a94f6e074e0285dc Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 16 Nov 2018 22:20:09 -0500 Subject: software_keyboard: Push buffer size to offset 0x4 in output data --- src/core/hle/service/am/am.cpp | 30 ++++++++++++++-------- src/core/hle/service/am/applets/applets.h | 4 ++- .../hle/service/am/applets/software_keyboard.cpp | 18 +++++++++---- .../hle/service/am/applets/software_keyboard.h | 5 +++- 4 files changed, 39 insertions(+), 18 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index d040d4776..470253ef1 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -583,31 +583,38 @@ private: rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(state_changed_event); - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_DEBUG(Service_AM, "called"); } void IsCompleted(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); rb.Push(applet->TransactionComplete()); + + LOG_DEBUG(Service_AM, "called"); } void GetResult(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(applet->GetStatus()); + + LOG_DEBUG(Service_AM, "called"); } void Start(Kernel::HLERequestContext& ctx) { ASSERT(applet != nullptr); applet->Initialize(storage_stack); - applet->Execute( - [this](IStorage storage) { AppletStorageProxyOutData(storage); }, - [this](IStorage storage) { AppletStorageProxyOutInteractiveData(storage); }); - state_changed_event->Signal(); + storage_stack.clear(); + interactive_storage_stack.clear(); + applet->Execute([this](IStorage storage) { AppletStorageProxyOutData(storage); }, + [this](IStorage storage) { AppletStorageProxyOutInteractiveData(storage); }, + [this] { state_changed_event->Signal(); }); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); + + LOG_DEBUG(Service_AM, "called"); } void PushInData(Kernel::HLERequestContext& ctx) { @@ -636,10 +643,9 @@ private: ASSERT(applet->IsInitialized()); applet->ReceiveInteractiveData(interactive_storage_stack.back()); - applet->Execute( - [this](IStorage storage) { AppletStorageProxyOutData(storage); }, - [this](IStorage storage) { AppletStorageProxyOutInteractiveData(storage); }); - state_changed_event->Signal(); + applet->Execute([this](IStorage storage) { AppletStorageProxyOutData(storage); }, + [this](IStorage storage) { AppletStorageProxyOutInteractiveData(storage); }, + [this] { state_changed_event->Signal(); }); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -661,6 +667,8 @@ private: IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(pop_out_data_event); + + LOG_DEBUG(Service_AM, "called"); } void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) { @@ -668,7 +676,7 @@ private: rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(pop_interactive_out_data_event); - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_DEBUG(Service_AM, "called"); } std::shared_ptr applet; @@ -734,7 +742,7 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { const u64 offset{rp.Pop()}; std::size_t size{ctx.GetWriteBufferSize()}; - size = std::min(size, backing.buffer.size() - offset); + size = std::min(size, backing.buffer.size() - offset); ctx.WriteBuffer(backing.buffer.data() + offset, size); diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 7fbaaf2f3..1ffa09420 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -22,6 +22,7 @@ class IStorage; namespace Applets { using AppletStorageProxyFunction = std::function; +using AppletStateProxyFunction = std::function; class Applet { public: @@ -34,7 +35,8 @@ public: virtual ResultCode GetStatus() const = 0; virtual void ReceiveInteractiveData(std::shared_ptr storage) = 0; virtual void Execute(AppletStorageProxyFunction out_data, - AppletStorageProxyFunction out_interactive_data) = 0; + AppletStorageProxyFunction out_interactive_data, + AppletStateProxyFunction state) = 0; bool IsInitialized() const { return initialized; diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 66b34d5ac..bb28a2e8d 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -69,7 +69,7 @@ bool SoftwareKeyboard::TransactionComplete() const { } ResultCode SoftwareKeyboard::GetStatus() const { - return RESULT_SUCCESS; + return status; } void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr storage) { @@ -92,7 +92,8 @@ void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr storage) } void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data, - AppletStorageProxyFunction out_interactive_data) { + AppletStorageProxyFunction out_interactive_data, + AppletStateProxyFunction state) { if (complete) return; @@ -102,6 +103,7 @@ void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data, this->out_data = out_data; this->out_interactive_data = out_interactive_data; + this->state = state; frontend.RequestText([this](std::optional text) { WriteText(text); }, parameters); } @@ -110,6 +112,7 @@ void SoftwareKeyboard::WriteText(std::optional text) { std::vector output(SWKBD_OUTPUT_BUFFER_SIZE); if (text.has_value()) { + status = RESULT_SUCCESS; if (config.text_check) { const auto size = static_cast(text->size() * 2 + 4); std::memcpy(output.data(), &size, sizeof(u32)); @@ -117,9 +120,12 @@ void SoftwareKeyboard::WriteText(std::optional text) { output[0] = 1; } - std::memcpy(output.data() + 4, text->data(), - std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4)); + const auto size = static_cast(text->size()); + std::memcpy(output.data() + 4, &size, sizeof(u32)); + std::memcpy(output.data() + 8, text->data(), + std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8)); } else { + status = ResultCode(-1); complete = true; out_data(IStorage{output}); return; @@ -127,6 +133,8 @@ void SoftwareKeyboard::WriteText(std::optional text) { complete = !config.text_check; - (complete ? out_data : out_interactive_data)(IStorage{output}); + out_data(IStorage{output}); + out_interactive_data(IStorage{output}); + state(); } } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h index b08bff3d7..9629f6408 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h @@ -55,7 +55,8 @@ public: ResultCode GetStatus() const override; void ReceiveInteractiveData(std::shared_ptr storage) override; void Execute(AppletStorageProxyFunction out_data, - AppletStorageProxyFunction out_interactive_data) override; + AppletStorageProxyFunction out_interactive_data, + AppletStateProxyFunction state) override; void WriteText(std::optional text); @@ -64,9 +65,11 @@ private: std::u16string initial_text; bool complete = false; std::vector final_data; + ResultCode status = ResultCode(-1); AppletStorageProxyFunction out_data; AppletStorageProxyFunction out_interactive_data; + AppletStateProxyFunction state; }; } // namespace Service::AM::Applets -- cgit v1.2.3 From 19b2571aecfff680c7a414c505eafc26264b6f2f Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sat, 17 Nov 2018 12:18:03 -0500 Subject: applet: Add operation completed callback --- src/core/hle/service/am/am.cpp | 6 ++++-- src/core/hle/service/am/applets/software_keyboard.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 470253ef1..5cbcb8d91 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -605,8 +605,10 @@ private: ASSERT(applet != nullptr); applet->Initialize(storage_stack); - storage_stack.clear(); - interactive_storage_stack.clear(); + while (!storage_stack.empty()) + 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(); }); diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index bb28a2e8d..039bfcc0f 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -87,7 +87,7 @@ void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr storage) std::array string; std::memcpy(string.data(), data.data() + 4, string.size() * 2); frontend.SendTextCheckDialog( - Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size())); + Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()), state); } } -- cgit v1.2.3 From 4ee087fb3ca2b1e064422b73195a8ff7698721d9 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sat, 17 Nov 2018 12:19:06 -0500 Subject: applet: Use std::queue instead of std::vector for storage stack --- src/core/hle/service/am/am.cpp | 32 +++++++++++++++------- src/core/hle/service/am/applets/applets.cpp | 12 +++++++- src/core/hle/service/am/applets/applets.h | 7 +++-- .../hle/service/am/applets/software_keyboard.cpp | 9 ++++-- .../hle/service/am/applets/software_keyboard.h | 2 +- 5 files changed, 44 insertions(+), 18 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 5cbcb8d91..d92a46b00 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -567,12 +567,12 @@ public: private: void AppletStorageProxyOutData(IStorage storage) { - storage_stack.push_back(std::make_shared(storage)); + storage_stack.push(std::make_shared(storage)); pop_out_data_event->Signal(); } void AppletStorageProxyOutInteractiveData(IStorage storage) { - interactive_storage_stack.push_back(std::make_shared(storage)); + interactive_storage_stack.push(std::make_shared(storage)); pop_interactive_out_data_event->Signal(); } @@ -621,7 +621,7 @@ private: void PushInData(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - storage_stack.push_back(rp.PopIpcInterface()); + storage_stack.push(rp.PopIpcInterface()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -631,17 +631,23 @@ private: void PopOutData(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + + if (storage_stack.empty()) { + rb.Push(ResultCode(-1)); + return; + } + rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(std::move(storage_stack.back())); + rb.PushIpcInterface(std::move(storage_stack.front())); - storage_stack.pop_back(); + storage_stack.pop(); LOG_DEBUG(Service_AM, "called"); } void PushInteractiveInData(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - interactive_storage_stack.push_back(rp.PopIpcInterface()); + interactive_storage_stack.push(rp.PopIpcInterface()); ASSERT(applet->IsInitialized()); applet->ReceiveInteractiveData(interactive_storage_stack.back()); @@ -657,10 +663,16 @@ private: void PopInteractiveOutData(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + + if (interactive_storage_stack.empty()) { + rb.Push(ResultCode(-1)); + return; + } + rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(std::move(interactive_storage_stack.back())); + rb.PushIpcInterface(std::move(interactive_storage_stack.front())); - interactive_storage_stack.pop_back(); + interactive_storage_stack.pop(); LOG_DEBUG(Service_AM, "called"); } @@ -682,8 +694,8 @@ private: } std::shared_ptr applet; - std::vector> storage_stack; - std::vector> interactive_storage_stack; + std::queue> storage_stack; + std::queue> interactive_storage_stack; Kernel::SharedPtr state_changed_event; Kernel::SharedPtr pop_out_data_event; Kernel::SharedPtr pop_interactive_out_data_event; diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 03b9d83e7..be950d320 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -2,7 +2,10 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include +#include "common/assert.h" #include "core/frontend/applets/software_keyboard.h" +#include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applets.h" namespace Service::AM::Applets { @@ -11,8 +14,15 @@ Applet::Applet() = default; Applet::~Applet() = default; -void Applet::Initialize(std::vector> storage) { +void Applet::Initialize(std::queue> storage) { storage_stack = std::move(storage); + + const auto common_data = storage_stack.front()->GetData(); + storage_stack.pop(); + + ASSERT(common_data.size() >= sizeof(CommonArguments)); + std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments)); + initialized = true; } diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 1ffa09420..a6a9bf77b 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -6,7 +6,7 @@ #include #include -#include +#include #include "common/swap.h" union ResultCode; @@ -29,7 +29,7 @@ public: Applet(); virtual ~Applet(); - virtual void Initialize(std::vector> storage); + virtual void Initialize(std::queue> storage); virtual bool TransactionComplete() const = 0; virtual ResultCode GetStatus() const = 0; @@ -53,7 +53,8 @@ protected: }; static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size."); - std::vector> storage_stack; + CommonArguments common_args; + std::queue> storage_stack; bool initialized = false; }; diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 039bfcc0f..a5ffa1f31 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -42,7 +42,7 @@ SoftwareKeyboard::SoftwareKeyboard() = default; SoftwareKeyboard::~SoftwareKeyboard() = default; -void SoftwareKeyboard::Initialize(std::vector> storage_) { +void SoftwareKeyboard::Initialize(std::queue> storage_) { complete = false; initial_text.clear(); final_data.clear(); @@ -50,11 +50,14 @@ void SoftwareKeyboard::Initialize(std::vector> storage Applet::Initialize(std::move(storage_)); ASSERT(storage_stack.size() >= 2); - const auto& keyboard_config = storage_stack[1]->GetData(); + const auto& keyboard_config = storage_stack.front()->GetData(); + storage_stack.pop(); + ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig)); std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig)); - const auto& work_buffer = storage_stack[2]->GetData(); + const auto& work_buffer = storage_stack.front()->GetData(); + storage_stack.pop(); if (config.initial_string_size == 0) return; diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h index 9629f6408..9544d6b1b 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h @@ -49,7 +49,7 @@ public: SoftwareKeyboard(); ~SoftwareKeyboard() override; - void Initialize(std::vector> storage) override; + void Initialize(std::queue> storage) override; bool TransactionComplete() const override; ResultCode GetStatus() const override; -- cgit v1.2.3 From 02e6602baaf36d7c148739eae922fa91ba4818fd Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sat, 17 Nov 2018 12:20:16 -0500 Subject: software_keyboard: Push all data over all channels on dialog completion --- .../hle/service/am/applets/software_keyboard.cpp | 44 +++++++++++++--------- 1 file changed, 26 insertions(+), 18 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index a5ffa1f31..5661cc98d 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -97,8 +97,10 @@ void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr storage) void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data, AppletStorageProxyFunction out_interactive_data, AppletStateProxyFunction state) { - if (complete) + if (complete) { + out_data(IStorage{final_data}); return; + } const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()}; @@ -112,32 +114,38 @@ void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data, } void SoftwareKeyboard::WriteText(std::optional text) { - std::vector output(SWKBD_OUTPUT_BUFFER_SIZE); + std::vector output_main(SWKBD_OUTPUT_BUFFER_SIZE); if (text.has_value()) { + std::vector output_sub(SWKBD_OUTPUT_BUFFER_SIZE); status = RESULT_SUCCESS; - if (config.text_check) { - const auto size = static_cast(text->size() * 2 + 4); - std::memcpy(output.data(), &size, sizeof(u32)); + + const u64 size = text->size() * 2 + 8; + std::memcpy(output_sub.data(), &size, sizeof(u64)); + std::memcpy(output_sub.data() + 8, text->data(), + std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8)); + + output_main[0] = config.text_check; + std::memcpy(output_main.data() + 4, text->data(), + std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4)); + + complete = !config.text_check; + final_data = output_main; + + if (complete) { + out_data(IStorage{output_main}); } else { - output[0] = 1; + out_data(IStorage{output_main}); + out_interactive_data(IStorage{output_sub}); } - const auto size = static_cast(text->size()); - std::memcpy(output.data() + 4, &size, sizeof(u32)); - std::memcpy(output.data() + 8, text->data(), - std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8)); + state(); } else { status = ResultCode(-1); + output_main[0] = 1; complete = true; - out_data(IStorage{output}); - return; + out_data(IStorage{output_main}); + state(); } - - complete = !config.text_check; - - out_data(IStorage{output}); - out_interactive_data(IStorage{output}); - state(); } } // namespace Service::AM::Applets -- cgit v1.2.3 From ea680bea60ac772a80c797365edaa7c86ab8459a Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 18 Nov 2018 23:14:48 -0500 Subject: software_keyboard: Check for UTF-8 config flag --- .../hle/service/am/applets/software_keyboard.cpp | 29 ++++++++++++++++------ .../hle/service/am/applets/software_keyboard.h | 3 ++- 2 files changed, 23 insertions(+), 9 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 5661cc98d..0ef052be6 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -120,14 +120,27 @@ void SoftwareKeyboard::WriteText(std::optional text) { std::vector output_sub(SWKBD_OUTPUT_BUFFER_SIZE); status = RESULT_SUCCESS; - const u64 size = text->size() * 2 + 8; - std::memcpy(output_sub.data(), &size, sizeof(u64)); - std::memcpy(output_sub.data() + 8, text->data(), - std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8)); - - output_main[0] = config.text_check; - std::memcpy(output_main.data() + 4, text->data(), - std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4)); + if (config.utf_8) { + const u64 size = text->size() + 8; + const auto new_text = Common::UTF16ToUTF8(*text); + + std::memcpy(output_sub.data(), &size, sizeof(u64)); + std::memcpy(output_sub.data() + 8, new_text.data(), + std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 8)); + + output_main[0] = config.text_check; + std::memcpy(output_main.data() + 4, new_text.data(), + std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4)); + } else { + const u64 size = text->size() * 2 + 8; + std::memcpy(output_sub.data(), &size, sizeof(u64)); + std::memcpy(output_sub.data() + 8, text->data(), + std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8)); + + output_main[0] = config.text_check; + std::memcpy(output_main.data() + 4, text->data(), + std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4)); + } complete = !config.text_check; final_data = output_main; diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h index 9544d6b1b..e0a9479c2 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h @@ -33,7 +33,8 @@ struct KeyboardConfig { u32_le length_limit; INSERT_PADDING_BYTES(4); u32_le is_password; - INSERT_PADDING_BYTES(6); + INSERT_PADDING_BYTES(5); + bool utf_8; bool draw_background; u32_le initial_string_offset; u32_le initial_string_size; -- cgit v1.2.3 From 96535c13a51a8ccece9965185250ae5d2a89dabf Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 19 Nov 2018 11:22:04 -0500 Subject: software_keyboard: Use correct offset for inital text string --- src/core/hle/service/am/applets/software_keyboard.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 0ef052be6..816b5fb5f 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -63,7 +63,8 @@ void SoftwareKeyboard::Initialize(std::queue> storage_ return; std::vector string(config.initial_string_size); - std::memcpy(string.data(), work_buffer.data() + 4, string.size() * 2); + std::memcpy(string.data(), work_buffer.data() + config.initial_string_offset, + string.size() * 2); initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()); } -- cgit v1.2.3 From 32775125b7af14cf488fdcbc4a61c00507c2d4a5 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 19 Nov 2018 14:24:36 -0500 Subject: 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. --- src/core/hle/service/am/am.cpp | 92 ++++++++------------- src/core/hle/service/am/applets/applets.cpp | 95 +++++++++++++++++++++- src/core/hle/service/am/applets/applets.h | 56 ++++++++++--- .../hle/service/am/applets/software_keyboard.cpp | 43 +++++----- .../hle/service/am/applets/software_keyboard.h | 12 +-- 5 files changed, 194 insertions(+), 104 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index d92a46b00..fd14af1e7 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -32,6 +32,9 @@ 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 { SoftwareKeyboard = 0x11, }; @@ -529,7 +532,8 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { class ILibraryAppletAccessor final : public ServiceFramework { public: explicit ILibraryAppletAccessor(std::shared_ptr applet) - : ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)) { + : ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)), + broker(std::make_shared()) { // clang-format off static const FunctionInfo functions[] = { {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, @@ -554,34 +558,16 @@ public: // clang-format on 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: - void AppletStorageProxyOutData(IStorage storage) { - storage_stack.push(std::make_shared(storage)); - pop_out_data_event->Signal(); - } - - void AppletStorageProxyOutInteractiveData(IStorage storage) { - interactive_storage_stack.push(std::make_shared(storage)); - pop_interactive_out_data_event->Signal(); - } - void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { - state_changed_event->Signal(); + const auto event = broker->GetStateChangedEvent(); + event->Signal(); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(state_changed_event); + rb.PushCopyObjects(event); LOG_DEBUG(Service_AM, "called"); } @@ -604,14 +590,8 @@ private: void Start(Kernel::HLERequestContext& ctx) { ASSERT(applet != nullptr); - applet->Initialize(storage_stack); - while (!storage_stack.empty()) - 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(); }); + applet->Initialize(broker); + applet->Execute(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -621,7 +601,7 @@ private: void PushInData(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - storage_stack.push(rp.PopIpcInterface()); + broker->PushNormalDataFromGame(*rp.PopIpcInterface()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -632,28 +612,25 @@ private: void PopOutData(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - if (storage_stack.empty()) { - rb.Push(ResultCode(-1)); + const auto storage = broker->PopNormalDataToGame(); + if (storage == nullptr) { + rb.Push(ERR_NO_DATA_IN_CHANNEL); return; } rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(std::move(storage_stack.front())); - - storage_stack.pop(); + rb.PushIpcInterface(std::move(*storage)); LOG_DEBUG(Service_AM, "called"); } void PushInteractiveInData(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - interactive_storage_stack.push(rp.PopIpcInterface()); + broker->PushInteractiveDataFromGame(*rp.PopIpcInterface()); ASSERT(applet->IsInitialized()); - applet->ReceiveInteractiveData(interactive_storage_stack.back()); - applet->Execute([this](IStorage storage) { AppletStorageProxyOutData(storage); }, - [this](IStorage storage) { AppletStorageProxyOutInteractiveData(storage); }, - [this] { state_changed_event->Signal(); }); + applet->ExecuteInteractive(); + applet->Execute(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -664,15 +641,14 @@ private: void PopInteractiveOutData(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - if (interactive_storage_stack.empty()) { - rb.Push(ResultCode(-1)); + const auto storage = broker->PopInteractiveDataToGame(); + if (storage == nullptr) { + rb.Push(ERR_NO_DATA_IN_CHANNEL); return; } rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface(std::move(interactive_storage_stack.front())); - - interactive_storage_stack.pop(); + rb.PushIpcInterface(std::move(*storage)); LOG_DEBUG(Service_AM, "called"); } @@ -680,7 +656,7 @@ private: void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(pop_out_data_event); + rb.PushCopyObjects(broker->GetNormalDataEvent()); LOG_DEBUG(Service_AM, "called"); } @@ -688,17 +664,13 @@ private: void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(pop_interactive_out_data_event); + rb.PushCopyObjects(broker->GetInteractiveDataEvent()); LOG_DEBUG(Service_AM, "called"); } std::shared_ptr applet; - std::queue> storage_stack; - std::queue> interactive_storage_stack; - Kernel::SharedPtr state_changed_event; - Kernel::SharedPtr pop_out_data_event; - Kernel::SharedPtr pop_interactive_out_data_event; + std::shared_ptr broker; }; void IStorage::Open(Kernel::HLERequestContext& ctx) { @@ -740,9 +712,12 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { const u64 offset{rp.Pop()}; const std::vector data{ctx.ReadBuffer()}; - const auto size = std::min(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}; rb.Push(RESULT_SUCCESS); @@ -754,9 +729,12 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u64 offset{rp.Pop()}; - std::size_t size{ctx.GetWriteBufferSize()}; + const std::size_t size{ctx.GetWriteBufferSize()}; - size = std::min(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); diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index be950d320..c81bd59b2 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -4,21 +4,108 @@ #include #include "common/assert.h" +#include "core/core.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/applets/applets.h" 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 AppletDataBroker::PopNormalDataToGame() { + if (out_channel.empty()) + return nullptr; + + auto out = std::move(out_channel.front()); + out_channel.pop(); + return out; +} + +std::unique_ptr AppletDataBroker::PopNormalDataToApplet() { + if (in_channel.empty()) + return nullptr; + + auto out = std::move(in_channel.front()); + in_channel.pop(); + return out; +} + +std::unique_ptr 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 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(storage)); +} + +void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) { + out_channel.push(std::make_unique(storage)); + pop_out_data_event->Signal(); +} + +void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) { + in_interactive_channel.push(std::make_unique(storage)); +} + +void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) { + out_interactive_channel.push(std::make_unique(storage)); + pop_interactive_out_data_event->Signal(); +} + +void AppletDataBroker::SignalStateChanged() const { + state_changed_event->Signal(); +} + +Kernel::SharedPtr AppletDataBroker::GetNormalDataEvent() const { + return pop_out_data_event; +} + +Kernel::SharedPtr AppletDataBroker::GetInteractiveDataEvent() const { + return pop_interactive_out_data_event; +} + +Kernel::SharedPtr AppletDataBroker::GetStateChangedEvent() const { + return state_changed_event; +} + Applet::Applet() = default; Applet::~Applet() = default; -void Applet::Initialize(std::queue> storage) { - storage_stack = std::move(storage); +void Applet::Initialize(std::shared_ptr broker_) { + broker = std::move(broker_); + + const auto common = broker->PopNormalDataToApplet(); + ASSERT(common != nullptr); - const auto common_data = storage_stack.front()->GetData(); - storage_stack.pop(); + const auto common_data = common->GetData(); ASSERT(common_data.size() >= sizeof(CommonArguments)); std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments)); diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index a6a9bf77b..136445649 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -8,35 +8,67 @@ #include #include #include "common/swap.h" +#include "core/hle/kernel/event.h" union ResultCode; -namespace Frontend { -class SoftwareKeyboardApplet; -} - namespace Service::AM { class IStorage; namespace Applets { -using AppletStorageProxyFunction = std::function; -using AppletStateProxyFunction = std::function; +class AppletDataBroker final { +public: + AppletDataBroker(); + ~AppletDataBroker(); + + std::unique_ptr PopNormalDataToGame(); + std::unique_ptr PopNormalDataToApplet(); + + std::unique_ptr PopInteractiveDataToGame(); + std::unique_ptr PopInteractiveDataToApplet(); + + void PushNormalDataFromGame(IStorage storage); + void PushNormalDataFromApplet(IStorage storage); + + void PushInteractiveDataFromGame(IStorage storage); + void PushInteractiveDataFromApplet(IStorage storage); + + void SignalStateChanged() const; + + Kernel::SharedPtr GetNormalDataEvent() const; + Kernel::SharedPtr GetInteractiveDataEvent() const; + Kernel::SharedPtr GetStateChangedEvent() const; + +private: + // Queues are named from applet's perspective + std::queue> + in_channel; // PopNormalDataToApplet and PushNormalDataFromGame + std::queue> + out_channel; // PopNormalDataToGame and PushNormalDataFromApplet + std::queue> + in_interactive_channel; // PopInteractiveDataToApplet and PushInteractiveDataFromGame + std::queue> + out_interactive_channel; // PopInteractiveDataToGame and PushInteractiveDataFromApplet + + Kernel::SharedPtr state_changed_event; + Kernel::SharedPtr pop_out_data_event; // Signaled on PushNormalDataFromApplet + Kernel::SharedPtr + pop_interactive_out_data_event; // Signaled on PushInteractiveDataFromApplet +}; class Applet { public: Applet(); virtual ~Applet(); - virtual void Initialize(std::queue> storage); + virtual void Initialize(std::shared_ptr broker); virtual bool TransactionComplete() const = 0; virtual ResultCode GetStatus() const = 0; - virtual void ReceiveInteractiveData(std::shared_ptr storage) = 0; - virtual void Execute(AppletStorageProxyFunction out_data, - AppletStorageProxyFunction out_interactive_data, - AppletStateProxyFunction state) = 0; + virtual void ExecuteInteractive() = 0; + virtual void Execute() = 0; bool IsInitialized() const { return initialized; @@ -54,7 +86,7 @@ protected: static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size."); CommonArguments common_args; - std::queue> storage_stack; + std::shared_ptr broker; bool initialized = false; }; diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 816b5fb5f..ca9ef7e7d 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -42,22 +42,23 @@ SoftwareKeyboard::SoftwareKeyboard() = default; SoftwareKeyboard::~SoftwareKeyboard() = default; -void SoftwareKeyboard::Initialize(std::queue> storage_) { +void SoftwareKeyboard::Initialize(std::shared_ptr broker_) { complete = false; initial_text.clear(); final_data.clear(); - Applet::Initialize(std::move(storage_)); + Applet::Initialize(std::move(broker_)); - ASSERT(storage_stack.size() >= 2); - const auto& keyboard_config = storage_stack.front()->GetData(); - storage_stack.pop(); + const auto keyboard_config_storage = broker->PopNormalDataToApplet(); + ASSERT(keyboard_config_storage != nullptr); + const auto& keyboard_config = keyboard_config_storage->GetData(); ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig)); std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig)); - const auto& work_buffer = storage_stack.front()->GetData(); - storage_stack.pop(); + const auto work_buffer_storage = broker->PopNormalDataToApplet(); + ASSERT(work_buffer_storage != nullptr); + const auto& work_buffer = work_buffer_storage->GetData(); if (config.initial_string_size == 0) return; @@ -76,10 +77,12 @@ ResultCode SoftwareKeyboard::GetStatus() const { return status; } -void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr storage) { +void SoftwareKeyboard::ExecuteInteractive() { if (complete) return; + const auto storage = broker->PopInteractiveDataToApplet(); + ASSERT(storage != nullptr); const auto data = storage->GetData(); const auto status = static_cast(data[0]); @@ -91,15 +94,14 @@ void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr storage) std::array string; std::memcpy(string.data(), data.data() + 4, string.size() * 2); frontend.SendTextCheckDialog( - Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()), state); + Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()), + [this] { broker->SignalStateChanged(); }); } } -void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data, - AppletStorageProxyFunction out_interactive_data, - AppletStateProxyFunction state) { +void SoftwareKeyboard::Execute() { if (complete) { - out_data(IStorage{final_data}); + broker->PushNormalDataFromApplet(IStorage{final_data}); return; } @@ -107,9 +109,6 @@ void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data, 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 text) { WriteText(text); }, parameters); } @@ -147,19 +146,19 @@ void SoftwareKeyboard::WriteText(std::optional text) { final_data = output_main; if (complete) { - out_data(IStorage{output_main}); + broker->PushNormalDataFromApplet(IStorage{output_main}); } else { - out_data(IStorage{output_main}); - out_interactive_data(IStorage{output_sub}); + broker->PushNormalDataFromApplet(IStorage{output_main}); + broker->PushInteractiveDataFromApplet(IStorage{output_sub}); } - state(); + broker->SignalStateChanged(); } else { status = ResultCode(-1); output_main[0] = 1; complete = true; - out_data(IStorage{output_main}); - state(); + broker->PushNormalDataFromApplet(IStorage{output_main}); + broker->SignalStateChanged(); } } } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h index e0a9479c2..405c58851 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h @@ -50,14 +50,12 @@ public: SoftwareKeyboard(); ~SoftwareKeyboard() override; - void Initialize(std::queue> storage) override; + void Initialize(std::shared_ptr broker) override; bool TransactionComplete() const override; ResultCode GetStatus() const override; - void ReceiveInteractiveData(std::shared_ptr storage) override; - void Execute(AppletStorageProxyFunction out_data, - AppletStorageProxyFunction out_interactive_data, - AppletStateProxyFunction state) override; + void ExecuteInteractive() override; + void Execute() override; void WriteText(std::optional text); @@ -67,10 +65,6 @@ private: bool complete = false; std::vector final_data; ResultCode status = ResultCode(-1); - - AppletStorageProxyFunction out_data; - AppletStorageProxyFunction out_interactive_data; - AppletStateProxyFunction state; }; } // namespace Service::AM::Applets -- cgit v1.2.3 From d68795c665fe73da55f0427d1ff05281d46c3de9 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 19 Nov 2018 15:10:01 -0500 Subject: software_keyboard: Return correct result code on user cancel operation --- src/core/hle/service/am/applets/applets.cpp | 1 - src/core/hle/service/am/applets/software_keyboard.cpp | 4 +--- src/core/hle/service/am/applets/software_keyboard.h | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index c81bd59b2..8adb81823 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -5,7 +5,6 @@ #include #include "common/assert.h" #include "core/core.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" diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index ca9ef7e7d..aec6bf2a7 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -74,7 +74,7 @@ bool SoftwareKeyboard::TransactionComplete() const { } ResultCode SoftwareKeyboard::GetStatus() const { - return status; + return RESULT_SUCCESS; } void SoftwareKeyboard::ExecuteInteractive() { @@ -118,7 +118,6 @@ void SoftwareKeyboard::WriteText(std::optional text) { if (text.has_value()) { std::vector output_sub(SWKBD_OUTPUT_BUFFER_SIZE); - status = RESULT_SUCCESS; if (config.utf_8) { const u64 size = text->size() + 8; @@ -154,7 +153,6 @@ void SoftwareKeyboard::WriteText(std::optional text) { broker->SignalStateChanged(); } else { - status = ResultCode(-1); output_main[0] = 1; complete = true; broker->PushNormalDataFromApplet(IStorage{output_main}); diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h index 405c58851..16e1fff66 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h @@ -64,7 +64,6 @@ private: std::u16string initial_text; bool complete = false; std::vector final_data; - ResultCode status = ResultCode(-1); }; } // namespace Service::AM::Applets -- cgit v1.2.3 From a9fa890f14afc84307884aa802b6255c906054d9 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 19 Nov 2018 16:30:17 -0500 Subject: software_keyboard: Fix erroneous extra PushNormalData --- src/core/hle/service/am/applets/software_keyboard.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index aec6bf2a7..c4b76a515 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -127,7 +127,7 @@ void SoftwareKeyboard::WriteText(std::optional text) { std::memcpy(output_sub.data() + 8, new_text.data(), std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 8)); - output_main[0] = config.text_check; + output_main[0] = INTERACTIVE_STATUS_OK; std::memcpy(output_main.data() + 4, new_text.data(), std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4)); } else { @@ -136,7 +136,7 @@ void SoftwareKeyboard::WriteText(std::optional text) { std::memcpy(output_sub.data() + 8, text->data(), std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8)); - output_main[0] = config.text_check; + output_main[0] = INTERACTIVE_STATUS_OK; std::memcpy(output_main.data() + 4, text->data(), std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4)); } @@ -147,7 +147,6 @@ void SoftwareKeyboard::WriteText(std::optional text) { if (complete) { broker->PushNormalDataFromApplet(IStorage{output_main}); } else { - broker->PushNormalDataFromApplet(IStorage{output_main}); broker->PushInteractiveDataFromApplet(IStorage{output_sub}); } -- cgit v1.2.3