diff options
| author | 2018-11-19 14:24:36 -0500 | |
|---|---|---|
| committer | 2018-11-19 14:24:36 -0500 | |
| commit | 32775125b7af14cf488fdcbc4a61c00507c2d4a5 (patch) | |
| tree | a63293691dff6b54c8fec47050f435118ed3a17e /src | |
| parent | software_keyboard: Use correct offset for inital text string (diff) | |
| download | yuzu-32775125b7af14cf488fdcbc4a61c00507c2d4a5.tar.gz yuzu-32775125b7af14cf488fdcbc4a61c00507c2d4a5.tar.xz yuzu-32775125b7af14cf488fdcbc4a61c00507c2d4a5.zip | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/am/am.cpp | 92 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/applets.cpp | 95 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/applets.h | 56 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/software_keyboard.cpp | 43 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/software_keyboard.h | 12 |
5 files changed, 194 insertions, 104 deletions
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 @@ | |||
| 32 | 32 | ||
| 33 | namespace Service::AM { | 33 | namespace Service::AM { |
| 34 | 34 | ||
| 35 | constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2}; | ||
| 36 | constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7}; | ||
| 37 | |||
| 35 | enum class AppletId : u32 { | 38 | enum class AppletId : u32 { |
| 36 | SoftwareKeyboard = 0x11, | 39 | SoftwareKeyboard = 0x11, |
| 37 | }; | 40 | }; |
| @@ -529,7 +532,8 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { | |||
| 529 | class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { | 532 | class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { |
| 530 | public: | 533 | public: |
| 531 | explicit ILibraryAppletAccessor(std::shared_ptr<Applets::Applet> applet) | 534 | explicit ILibraryAppletAccessor(std::shared_ptr<Applets::Applet> applet) |
| 532 | : ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)) { | 535 | : ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)), |
| 536 | broker(std::make_shared<Applets::AppletDataBroker>()) { | ||
| 533 | // clang-format off | 537 | // clang-format off |
| 534 | static const FunctionInfo functions[] = { | 538 | static const FunctionInfo functions[] = { |
| 535 | {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, | 539 | {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, |
| @@ -554,34 +558,16 @@ public: | |||
| 554 | // clang-format on | 558 | // clang-format on |
| 555 | 559 | ||
| 556 | RegisterHandlers(functions); | 560 | RegisterHandlers(functions); |
| 557 | |||
| 558 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 559 | state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, | ||
| 560 | "ILibraryAppletAccessor:StateChangedEvent"); | ||
| 561 | pop_out_data_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, | ||
| 562 | "ILibraryAppletAccessor:PopDataOutEvent"); | ||
| 563 | pop_interactive_out_data_event = | ||
| 564 | Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, | ||
| 565 | "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); | ||
| 566 | } | 561 | } |
| 567 | 562 | ||
| 568 | private: | 563 | private: |
| 569 | void AppletStorageProxyOutData(IStorage storage) { | ||
| 570 | storage_stack.push(std::make_shared<IStorage>(storage)); | ||
| 571 | pop_out_data_event->Signal(); | ||
| 572 | } | ||
| 573 | |||
| 574 | void AppletStorageProxyOutInteractiveData(IStorage storage) { | ||
| 575 | interactive_storage_stack.push(std::make_shared<IStorage>(storage)); | ||
| 576 | pop_interactive_out_data_event->Signal(); | ||
| 577 | } | ||
| 578 | |||
| 579 | void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { | 564 | void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { |
| 580 | state_changed_event->Signal(); | 565 | const auto event = broker->GetStateChangedEvent(); |
| 566 | event->Signal(); | ||
| 581 | 567 | ||
| 582 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 568 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 583 | rb.Push(RESULT_SUCCESS); | 569 | rb.Push(RESULT_SUCCESS); |
| 584 | rb.PushCopyObjects(state_changed_event); | 570 | rb.PushCopyObjects(event); |
| 585 | 571 | ||
| 586 | LOG_DEBUG(Service_AM, "called"); | 572 | LOG_DEBUG(Service_AM, "called"); |
| 587 | } | 573 | } |
| @@ -604,14 +590,8 @@ private: | |||
| 604 | void Start(Kernel::HLERequestContext& ctx) { | 590 | void Start(Kernel::HLERequestContext& ctx) { |
| 605 | ASSERT(applet != nullptr); | 591 | ASSERT(applet != nullptr); |
| 606 | 592 | ||
| 607 | applet->Initialize(storage_stack); | 593 | applet->Initialize(broker); |
| 608 | while (!storage_stack.empty()) | 594 | applet->Execute(); |
| 609 | storage_stack.pop(); | ||
| 610 | while (!interactive_storage_stack.empty()) | ||
| 611 | interactive_storage_stack.pop(); | ||
| 612 | applet->Execute([this](IStorage storage) { AppletStorageProxyOutData(storage); }, | ||
| 613 | [this](IStorage storage) { AppletStorageProxyOutInteractiveData(storage); }, | ||
| 614 | [this] { state_changed_event->Signal(); }); | ||
| 615 | 595 | ||
| 616 | IPC::ResponseBuilder rb{ctx, 2}; | 596 | IPC::ResponseBuilder rb{ctx, 2}; |
| 617 | rb.Push(RESULT_SUCCESS); | 597 | rb.Push(RESULT_SUCCESS); |
| @@ -621,7 +601,7 @@ private: | |||
| 621 | 601 | ||
| 622 | void PushInData(Kernel::HLERequestContext& ctx) { | 602 | void PushInData(Kernel::HLERequestContext& ctx) { |
| 623 | IPC::RequestParser rp{ctx}; | 603 | IPC::RequestParser rp{ctx}; |
| 624 | storage_stack.push(rp.PopIpcInterface<IStorage>()); | 604 | broker->PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>()); |
| 625 | 605 | ||
| 626 | IPC::ResponseBuilder rb{ctx, 2}; | 606 | IPC::ResponseBuilder rb{ctx, 2}; |
| 627 | rb.Push(RESULT_SUCCESS); | 607 | rb.Push(RESULT_SUCCESS); |
| @@ -632,28 +612,25 @@ private: | |||
| 632 | void PopOutData(Kernel::HLERequestContext& ctx) { | 612 | void PopOutData(Kernel::HLERequestContext& ctx) { |
| 633 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 613 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 634 | 614 | ||
| 635 | if (storage_stack.empty()) { | 615 | const auto storage = broker->PopNormalDataToGame(); |
| 636 | rb.Push(ResultCode(-1)); | 616 | if (storage == nullptr) { |
| 617 | rb.Push(ERR_NO_DATA_IN_CHANNEL); | ||
| 637 | return; | 618 | return; |
| 638 | } | 619 | } |
| 639 | 620 | ||
| 640 | rb.Push(RESULT_SUCCESS); | 621 | rb.Push(RESULT_SUCCESS); |
| 641 | rb.PushIpcInterface<IStorage>(std::move(storage_stack.front())); | 622 | rb.PushIpcInterface<IStorage>(std::move(*storage)); |
| 642 | |||
| 643 | storage_stack.pop(); | ||
| 644 | 623 | ||
| 645 | LOG_DEBUG(Service_AM, "called"); | 624 | LOG_DEBUG(Service_AM, "called"); |
| 646 | } | 625 | } |
| 647 | 626 | ||
| 648 | void PushInteractiveInData(Kernel::HLERequestContext& ctx) { | 627 | void PushInteractiveInData(Kernel::HLERequestContext& ctx) { |
| 649 | IPC::RequestParser rp{ctx}; | 628 | IPC::RequestParser rp{ctx}; |
| 650 | interactive_storage_stack.push(rp.PopIpcInterface<IStorage>()); | 629 | broker->PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>()); |
| 651 | 630 | ||
| 652 | ASSERT(applet->IsInitialized()); | 631 | ASSERT(applet->IsInitialized()); |
| 653 | applet->ReceiveInteractiveData(interactive_storage_stack.back()); | 632 | applet->ExecuteInteractive(); |
| 654 | applet->Execute([this](IStorage storage) { AppletStorageProxyOutData(storage); }, | 633 | applet->Execute(); |
| 655 | [this](IStorage storage) { AppletStorageProxyOutInteractiveData(storage); }, | ||
| 656 | [this] { state_changed_event->Signal(); }); | ||
| 657 | 634 | ||
| 658 | IPC::ResponseBuilder rb{ctx, 2}; | 635 | IPC::ResponseBuilder rb{ctx, 2}; |
| 659 | rb.Push(RESULT_SUCCESS); | 636 | rb.Push(RESULT_SUCCESS); |
| @@ -664,15 +641,14 @@ private: | |||
| 664 | void PopInteractiveOutData(Kernel::HLERequestContext& ctx) { | 641 | void PopInteractiveOutData(Kernel::HLERequestContext& ctx) { |
| 665 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 642 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 666 | 643 | ||
| 667 | if (interactive_storage_stack.empty()) { | 644 | const auto storage = broker->PopInteractiveDataToGame(); |
| 668 | rb.Push(ResultCode(-1)); | 645 | if (storage == nullptr) { |
| 646 | rb.Push(ERR_NO_DATA_IN_CHANNEL); | ||
| 669 | return; | 647 | return; |
| 670 | } | 648 | } |
| 671 | 649 | ||
| 672 | rb.Push(RESULT_SUCCESS); | 650 | rb.Push(RESULT_SUCCESS); |
| 673 | rb.PushIpcInterface<IStorage>(std::move(interactive_storage_stack.front())); | 651 | rb.PushIpcInterface<IStorage>(std::move(*storage)); |
| 674 | |||
| 675 | interactive_storage_stack.pop(); | ||
| 676 | 652 | ||
| 677 | LOG_DEBUG(Service_AM, "called"); | 653 | LOG_DEBUG(Service_AM, "called"); |
| 678 | } | 654 | } |
| @@ -680,7 +656,7 @@ private: | |||
| 680 | void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) { | 656 | void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) { |
| 681 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 657 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 682 | rb.Push(RESULT_SUCCESS); | 658 | rb.Push(RESULT_SUCCESS); |
| 683 | rb.PushCopyObjects(pop_out_data_event); | 659 | rb.PushCopyObjects(broker->GetNormalDataEvent()); |
| 684 | 660 | ||
| 685 | LOG_DEBUG(Service_AM, "called"); | 661 | LOG_DEBUG(Service_AM, "called"); |
| 686 | } | 662 | } |
| @@ -688,17 +664,13 @@ private: | |||
| 688 | void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) { | 664 | void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) { |
| 689 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 665 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 690 | rb.Push(RESULT_SUCCESS); | 666 | rb.Push(RESULT_SUCCESS); |
| 691 | rb.PushCopyObjects(pop_interactive_out_data_event); | 667 | rb.PushCopyObjects(broker->GetInteractiveDataEvent()); |
| 692 | 668 | ||
| 693 | LOG_DEBUG(Service_AM, "called"); | 669 | LOG_DEBUG(Service_AM, "called"); |
| 694 | } | 670 | } |
| 695 | 671 | ||
| 696 | std::shared_ptr<Applets::Applet> applet; | 672 | std::shared_ptr<Applets::Applet> applet; |
| 697 | std::queue<std::shared_ptr<IStorage>> storage_stack; | 673 | std::shared_ptr<Applets::AppletDataBroker> broker; |
| 698 | std::queue<std::shared_ptr<IStorage>> interactive_storage_stack; | ||
| 699 | Kernel::SharedPtr<Kernel::Event> state_changed_event; | ||
| 700 | Kernel::SharedPtr<Kernel::Event> pop_out_data_event; | ||
| 701 | Kernel::SharedPtr<Kernel::Event> pop_interactive_out_data_event; | ||
| 702 | }; | 674 | }; |
| 703 | 675 | ||
| 704 | void IStorage::Open(Kernel::HLERequestContext& ctx) { | 676 | void IStorage::Open(Kernel::HLERequestContext& ctx) { |
| @@ -740,9 +712,12 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { | |||
| 740 | const u64 offset{rp.Pop<u64>()}; | 712 | const u64 offset{rp.Pop<u64>()}; |
| 741 | const std::vector<u8> data{ctx.ReadBuffer()}; | 713 | const std::vector<u8> data{ctx.ReadBuffer()}; |
| 742 | 714 | ||
| 743 | const auto size = std::min<std::size_t>(data.size(), backing.buffer.size() - offset); | 715 | if (data.size() > backing.buffer.size() - offset) { |
| 716 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 717 | rb.Push(ERR_SIZE_OUT_OF_BOUNDS); | ||
| 718 | } | ||
| 744 | 719 | ||
| 745 | std::memcpy(&backing.buffer[offset], data.data(), size); | 720 | std::memcpy(backing.buffer.data() + offset, data.data(), data.size()); |
| 746 | 721 | ||
| 747 | IPC::ResponseBuilder rb{ctx, 2}; | 722 | IPC::ResponseBuilder rb{ctx, 2}; |
| 748 | rb.Push(RESULT_SUCCESS); | 723 | rb.Push(RESULT_SUCCESS); |
| @@ -754,9 +729,12 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { | |||
| 754 | IPC::RequestParser rp{ctx}; | 729 | IPC::RequestParser rp{ctx}; |
| 755 | 730 | ||
| 756 | const u64 offset{rp.Pop<u64>()}; | 731 | const u64 offset{rp.Pop<u64>()}; |
| 757 | std::size_t size{ctx.GetWriteBufferSize()}; | 732 | const std::size_t size{ctx.GetWriteBufferSize()}; |
| 758 | 733 | ||
| 759 | size = std::min<std::size_t>(size, backing.buffer.size() - offset); | 734 | if (size > backing.buffer.size() - offset) { |
| 735 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 736 | rb.Push(ERR_SIZE_OUT_OF_BOUNDS); | ||
| 737 | } | ||
| 760 | 738 | ||
| 761 | ctx.WriteBuffer(backing.buffer.data() + offset, size); | 739 | ctx.WriteBuffer(backing.buffer.data() + offset, size); |
| 762 | 740 | ||
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 @@ | |||
| 4 | 4 | ||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "core/core.h" | ||
| 7 | #include "core/frontend/applets/software_keyboard.h" | 8 | #include "core/frontend/applets/software_keyboard.h" |
| 9 | #include "core/hle/kernel/event.h" | ||
| 10 | #include "core/hle/kernel/server_port.h" | ||
| 8 | #include "core/hle/service/am/am.h" | 11 | #include "core/hle/service/am/am.h" |
| 9 | #include "core/hle/service/am/applets/applets.h" | 12 | #include "core/hle/service/am/applets/applets.h" |
| 10 | 13 | ||
| 11 | namespace Service::AM::Applets { | 14 | namespace Service::AM::Applets { |
| 12 | 15 | ||
| 16 | AppletDataBroker::AppletDataBroker() { | ||
| 17 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 18 | state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, | ||
| 19 | "ILibraryAppletAccessor:StateChangedEvent"); | ||
| 20 | pop_out_data_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, | ||
| 21 | "ILibraryAppletAccessor:PopDataOutEvent"); | ||
| 22 | pop_interactive_out_data_event = Kernel::Event::Create( | ||
| 23 | kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); | ||
| 24 | } | ||
| 25 | |||
| 26 | AppletDataBroker::~AppletDataBroker() = default; | ||
| 27 | |||
| 28 | std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() { | ||
| 29 | if (out_channel.empty()) | ||
| 30 | return nullptr; | ||
| 31 | |||
| 32 | auto out = std::move(out_channel.front()); | ||
| 33 | out_channel.pop(); | ||
| 34 | return out; | ||
| 35 | } | ||
| 36 | |||
| 37 | std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() { | ||
| 38 | if (in_channel.empty()) | ||
| 39 | return nullptr; | ||
| 40 | |||
| 41 | auto out = std::move(in_channel.front()); | ||
| 42 | in_channel.pop(); | ||
| 43 | return out; | ||
| 44 | } | ||
| 45 | |||
| 46 | std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() { | ||
| 47 | if (out_interactive_channel.empty()) | ||
| 48 | return nullptr; | ||
| 49 | |||
| 50 | auto out = std::move(out_interactive_channel.front()); | ||
| 51 | out_interactive_channel.pop(); | ||
| 52 | return out; | ||
| 53 | } | ||
| 54 | |||
| 55 | std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() { | ||
| 56 | if (in_interactive_channel.empty()) | ||
| 57 | return nullptr; | ||
| 58 | |||
| 59 | auto out = std::move(in_interactive_channel.front()); | ||
| 60 | in_interactive_channel.pop(); | ||
| 61 | return out; | ||
| 62 | } | ||
| 63 | |||
| 64 | void AppletDataBroker::PushNormalDataFromGame(IStorage storage) { | ||
| 65 | in_channel.push(std::make_unique<IStorage>(storage)); | ||
| 66 | } | ||
| 67 | |||
| 68 | void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) { | ||
| 69 | out_channel.push(std::make_unique<IStorage>(storage)); | ||
| 70 | pop_out_data_event->Signal(); | ||
| 71 | } | ||
| 72 | |||
| 73 | void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) { | ||
| 74 | in_interactive_channel.push(std::make_unique<IStorage>(storage)); | ||
| 75 | } | ||
| 76 | |||
| 77 | void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) { | ||
| 78 | out_interactive_channel.push(std::make_unique<IStorage>(storage)); | ||
| 79 | pop_interactive_out_data_event->Signal(); | ||
| 80 | } | ||
| 81 | |||
| 82 | void AppletDataBroker::SignalStateChanged() const { | ||
| 83 | state_changed_event->Signal(); | ||
| 84 | } | ||
| 85 | |||
| 86 | Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetNormalDataEvent() const { | ||
| 87 | return pop_out_data_event; | ||
| 88 | } | ||
| 89 | |||
| 90 | Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetInteractiveDataEvent() const { | ||
| 91 | return pop_interactive_out_data_event; | ||
| 92 | } | ||
| 93 | |||
| 94 | Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetStateChangedEvent() const { | ||
| 95 | return state_changed_event; | ||
| 96 | } | ||
| 97 | |||
| 13 | Applet::Applet() = default; | 98 | Applet::Applet() = default; |
| 14 | 99 | ||
| 15 | Applet::~Applet() = default; | 100 | Applet::~Applet() = default; |
| 16 | 101 | ||
| 17 | void Applet::Initialize(std::queue<std::shared_ptr<IStorage>> storage) { | 102 | void Applet::Initialize(std::shared_ptr<AppletDataBroker> broker_) { |
| 18 | storage_stack = std::move(storage); | 103 | broker = std::move(broker_); |
| 104 | |||
| 105 | const auto common = broker->PopNormalDataToApplet(); | ||
| 106 | ASSERT(common != nullptr); | ||
| 19 | 107 | ||
| 20 | const auto common_data = storage_stack.front()->GetData(); | 108 | const auto common_data = common->GetData(); |
| 21 | storage_stack.pop(); | ||
| 22 | 109 | ||
| 23 | ASSERT(common_data.size() >= sizeof(CommonArguments)); | 110 | ASSERT(common_data.size() >= sizeof(CommonArguments)); |
| 24 | std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments)); | 111 | 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 @@ | |||
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | #include <queue> | 9 | #include <queue> |
| 10 | #include "common/swap.h" | 10 | #include "common/swap.h" |
| 11 | #include "core/hle/kernel/event.h" | ||
| 11 | 12 | ||
| 12 | union ResultCode; | 13 | union ResultCode; |
| 13 | 14 | ||
| 14 | namespace Frontend { | ||
| 15 | class SoftwareKeyboardApplet; | ||
| 16 | } | ||
| 17 | |||
| 18 | namespace Service::AM { | 15 | namespace Service::AM { |
| 19 | 16 | ||
| 20 | class IStorage; | 17 | class IStorage; |
| 21 | 18 | ||
| 22 | namespace Applets { | 19 | namespace Applets { |
| 23 | 20 | ||
| 24 | using AppletStorageProxyFunction = std::function<void(IStorage)>; | 21 | class AppletDataBroker final { |
| 25 | using AppletStateProxyFunction = std::function<void()>; | 22 | public: |
| 23 | AppletDataBroker(); | ||
| 24 | ~AppletDataBroker(); | ||
| 25 | |||
| 26 | std::unique_ptr<IStorage> PopNormalDataToGame(); | ||
| 27 | std::unique_ptr<IStorage> PopNormalDataToApplet(); | ||
| 28 | |||
| 29 | std::unique_ptr<IStorage> PopInteractiveDataToGame(); | ||
| 30 | std::unique_ptr<IStorage> PopInteractiveDataToApplet(); | ||
| 31 | |||
| 32 | void PushNormalDataFromGame(IStorage storage); | ||
| 33 | void PushNormalDataFromApplet(IStorage storage); | ||
| 34 | |||
| 35 | void PushInteractiveDataFromGame(IStorage storage); | ||
| 36 | void PushInteractiveDataFromApplet(IStorage storage); | ||
| 37 | |||
| 38 | void SignalStateChanged() const; | ||
| 39 | |||
| 40 | Kernel::SharedPtr<Kernel::Event> GetNormalDataEvent() const; | ||
| 41 | Kernel::SharedPtr<Kernel::Event> GetInteractiveDataEvent() const; | ||
| 42 | Kernel::SharedPtr<Kernel::Event> GetStateChangedEvent() const; | ||
| 43 | |||
| 44 | private: | ||
| 45 | // Queues are named from applet's perspective | ||
| 46 | std::queue<std::unique_ptr<IStorage>> | ||
| 47 | in_channel; // PopNormalDataToApplet and PushNormalDataFromGame | ||
| 48 | std::queue<std::unique_ptr<IStorage>> | ||
| 49 | out_channel; // PopNormalDataToGame and PushNormalDataFromApplet | ||
| 50 | std::queue<std::unique_ptr<IStorage>> | ||
| 51 | in_interactive_channel; // PopInteractiveDataToApplet and PushInteractiveDataFromGame | ||
| 52 | std::queue<std::unique_ptr<IStorage>> | ||
| 53 | out_interactive_channel; // PopInteractiveDataToGame and PushInteractiveDataFromApplet | ||
| 54 | |||
| 55 | Kernel::SharedPtr<Kernel::Event> state_changed_event; | ||
| 56 | Kernel::SharedPtr<Kernel::Event> pop_out_data_event; // Signaled on PushNormalDataFromApplet | ||
| 57 | Kernel::SharedPtr<Kernel::Event> | ||
| 58 | pop_interactive_out_data_event; // Signaled on PushInteractiveDataFromApplet | ||
| 59 | }; | ||
| 26 | 60 | ||
| 27 | class Applet { | 61 | class Applet { |
| 28 | public: | 62 | public: |
| 29 | Applet(); | 63 | Applet(); |
| 30 | virtual ~Applet(); | 64 | virtual ~Applet(); |
| 31 | 65 | ||
| 32 | virtual void Initialize(std::queue<std::shared_ptr<IStorage>> storage); | 66 | virtual void Initialize(std::shared_ptr<AppletDataBroker> broker); |
| 33 | 67 | ||
| 34 | virtual bool TransactionComplete() const = 0; | 68 | virtual bool TransactionComplete() const = 0; |
| 35 | virtual ResultCode GetStatus() const = 0; | 69 | virtual ResultCode GetStatus() const = 0; |
| 36 | virtual void ReceiveInteractiveData(std::shared_ptr<IStorage> storage) = 0; | 70 | virtual void ExecuteInteractive() = 0; |
| 37 | virtual void Execute(AppletStorageProxyFunction out_data, | 71 | virtual void Execute() = 0; |
| 38 | AppletStorageProxyFunction out_interactive_data, | ||
| 39 | AppletStateProxyFunction state) = 0; | ||
| 40 | 72 | ||
| 41 | bool IsInitialized() const { | 73 | bool IsInitialized() const { |
| 42 | return initialized; | 74 | return initialized; |
| @@ -54,7 +86,7 @@ protected: | |||
| 54 | static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size."); | 86 | static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size."); |
| 55 | 87 | ||
| 56 | CommonArguments common_args; | 88 | CommonArguments common_args; |
| 57 | std::queue<std::shared_ptr<IStorage>> storage_stack; | 89 | std::shared_ptr<AppletDataBroker> broker; |
| 58 | bool initialized = false; | 90 | bool initialized = false; |
| 59 | }; | 91 | }; |
| 60 | 92 | ||
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; | |||
| 42 | 42 | ||
| 43 | SoftwareKeyboard::~SoftwareKeyboard() = default; | 43 | SoftwareKeyboard::~SoftwareKeyboard() = default; |
| 44 | 44 | ||
| 45 | void SoftwareKeyboard::Initialize(std::queue<std::shared_ptr<IStorage>> storage_) { | 45 | void SoftwareKeyboard::Initialize(std::shared_ptr<AppletDataBroker> broker_) { |
| 46 | complete = false; | 46 | complete = false; |
| 47 | initial_text.clear(); | 47 | initial_text.clear(); |
| 48 | final_data.clear(); | 48 | final_data.clear(); |
| 49 | 49 | ||
| 50 | Applet::Initialize(std::move(storage_)); | 50 | Applet::Initialize(std::move(broker_)); |
| 51 | 51 | ||
| 52 | ASSERT(storage_stack.size() >= 2); | 52 | const auto keyboard_config_storage = broker->PopNormalDataToApplet(); |
| 53 | const auto& keyboard_config = storage_stack.front()->GetData(); | 53 | ASSERT(keyboard_config_storage != nullptr); |
| 54 | storage_stack.pop(); | 54 | const auto& keyboard_config = keyboard_config_storage->GetData(); |
| 55 | 55 | ||
| 56 | ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig)); | 56 | ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig)); |
| 57 | std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig)); | 57 | std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig)); |
| 58 | 58 | ||
| 59 | const auto& work_buffer = storage_stack.front()->GetData(); | 59 | const auto work_buffer_storage = broker->PopNormalDataToApplet(); |
| 60 | storage_stack.pop(); | 60 | ASSERT(work_buffer_storage != nullptr); |
| 61 | const auto& work_buffer = work_buffer_storage->GetData(); | ||
| 61 | 62 | ||
| 62 | if (config.initial_string_size == 0) | 63 | if (config.initial_string_size == 0) |
| 63 | return; | 64 | return; |
| @@ -76,10 +77,12 @@ ResultCode SoftwareKeyboard::GetStatus() const { | |||
| 76 | return status; | 77 | return status; |
| 77 | } | 78 | } |
| 78 | 79 | ||
| 79 | void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr<IStorage> storage) { | 80 | void SoftwareKeyboard::ExecuteInteractive() { |
| 80 | if (complete) | 81 | if (complete) |
| 81 | return; | 82 | return; |
| 82 | 83 | ||
| 84 | const auto storage = broker->PopInteractiveDataToApplet(); | ||
| 85 | ASSERT(storage != nullptr); | ||
| 83 | const auto data = storage->GetData(); | 86 | const auto data = storage->GetData(); |
| 84 | const auto status = static_cast<bool>(data[0]); | 87 | const auto status = static_cast<bool>(data[0]); |
| 85 | 88 | ||
| @@ -91,15 +94,14 @@ void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr<IStorage> storage) | |||
| 91 | std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string; | 94 | std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string; |
| 92 | std::memcpy(string.data(), data.data() + 4, string.size() * 2); | 95 | std::memcpy(string.data(), data.data() + 4, string.size() * 2); |
| 93 | frontend.SendTextCheckDialog( | 96 | frontend.SendTextCheckDialog( |
| 94 | Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()), state); | 97 | Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()), |
| 98 | [this] { broker->SignalStateChanged(); }); | ||
| 95 | } | 99 | } |
| 96 | } | 100 | } |
| 97 | 101 | ||
| 98 | void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data, | 102 | void SoftwareKeyboard::Execute() { |
| 99 | AppletStorageProxyFunction out_interactive_data, | ||
| 100 | AppletStateProxyFunction state) { | ||
| 101 | if (complete) { | 103 | if (complete) { |
| 102 | out_data(IStorage{final_data}); | 104 | broker->PushNormalDataFromApplet(IStorage{final_data}); |
| 103 | return; | 105 | return; |
| 104 | } | 106 | } |
| 105 | 107 | ||
| @@ -107,9 +109,6 @@ void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data, | |||
| 107 | 109 | ||
| 108 | const auto parameters = ConvertToFrontendParameters(config, initial_text); | 110 | const auto parameters = ConvertToFrontendParameters(config, initial_text); |
| 109 | 111 | ||
| 110 | this->out_data = out_data; | ||
| 111 | this->out_interactive_data = out_interactive_data; | ||
| 112 | this->state = state; | ||
| 113 | frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(text); }, | 112 | frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(text); }, |
| 114 | parameters); | 113 | parameters); |
| 115 | } | 114 | } |
| @@ -147,19 +146,19 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { | |||
| 147 | final_data = output_main; | 146 | final_data = output_main; |
| 148 | 147 | ||
| 149 | if (complete) { | 148 | if (complete) { |
| 150 | out_data(IStorage{output_main}); | 149 | broker->PushNormalDataFromApplet(IStorage{output_main}); |
| 151 | } else { | 150 | } else { |
| 152 | out_data(IStorage{output_main}); | 151 | broker->PushNormalDataFromApplet(IStorage{output_main}); |
| 153 | out_interactive_data(IStorage{output_sub}); | 152 | broker->PushInteractiveDataFromApplet(IStorage{output_sub}); |
| 154 | } | 153 | } |
| 155 | 154 | ||
| 156 | state(); | 155 | broker->SignalStateChanged(); |
| 157 | } else { | 156 | } else { |
| 158 | status = ResultCode(-1); | 157 | status = ResultCode(-1); |
| 159 | output_main[0] = 1; | 158 | output_main[0] = 1; |
| 160 | complete = true; | 159 | complete = true; |
| 161 | out_data(IStorage{output_main}); | 160 | broker->PushNormalDataFromApplet(IStorage{output_main}); |
| 162 | state(); | 161 | broker->SignalStateChanged(); |
| 163 | } | 162 | } |
| 164 | } | 163 | } |
| 165 | } // namespace Service::AM::Applets | 164 | } // 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: | |||
| 50 | SoftwareKeyboard(); | 50 | SoftwareKeyboard(); |
| 51 | ~SoftwareKeyboard() override; | 51 | ~SoftwareKeyboard() override; |
| 52 | 52 | ||
| 53 | void Initialize(std::queue<std::shared_ptr<IStorage>> storage) override; | 53 | void Initialize(std::shared_ptr<AppletDataBroker> broker) override; |
| 54 | 54 | ||
| 55 | bool TransactionComplete() const override; | 55 | bool TransactionComplete() const override; |
| 56 | ResultCode GetStatus() const override; | 56 | ResultCode GetStatus() const override; |
| 57 | void ReceiveInteractiveData(std::shared_ptr<IStorage> storage) override; | 57 | void ExecuteInteractive() override; |
| 58 | void Execute(AppletStorageProxyFunction out_data, | 58 | void Execute() override; |
| 59 | AppletStorageProxyFunction out_interactive_data, | ||
| 60 | AppletStateProxyFunction state) override; | ||
| 61 | 59 | ||
| 62 | void WriteText(std::optional<std::u16string> text); | 60 | void WriteText(std::optional<std::u16string> text); |
| 63 | 61 | ||
| @@ -67,10 +65,6 @@ private: | |||
| 67 | bool complete = false; | 65 | bool complete = false; |
| 68 | std::vector<u8> final_data; | 66 | std::vector<u8> final_data; |
| 69 | ResultCode status = ResultCode(-1); | 67 | ResultCode status = ResultCode(-1); |
| 70 | |||
| 71 | AppletStorageProxyFunction out_data; | ||
| 72 | AppletStorageProxyFunction out_interactive_data; | ||
| 73 | AppletStateProxyFunction state; | ||
| 74 | }; | 68 | }; |
| 75 | 69 | ||
| 76 | } // namespace Service::AM::Applets | 70 | } // namespace Service::AM::Applets |