From 2a6ebadf66051362cdcf07d722f7e2d3cee14c82 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 25 May 2015 23:30:20 -0500 Subject: HLE/APT: Initial HLE support for applets. Currently only the SWKBD is emulated, and there's currently no way to ask the user for input, so it always returns "Subv" as the text. --- src/core/hle/applets/applet.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/core/hle/applets/applet.cpp (limited to 'src/core/hle/applets/applet.cpp') diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp new file mode 100644 index 000000000..1f447e5fc --- /dev/null +++ b/src/core/hle/applets/applet.cpp @@ -0,0 +1,40 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "common/logging/log.h" + +#include "core/hle/applets/applet.h" +#include "core/hle/applets/swkbd.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace HLE { +namespace Applets { + +static std::unordered_map> applets; + +ResultCode Applet::Create(Service::APT::AppletId id) { + switch (id) { + case Service::APT::AppletId::SoftwareKeyboard1: + case Service::APT::AppletId::SoftwareKeyboard2: + applets[id] = std::make_shared(id); + break; + default: + // TODO(Subv): Find the right error code + return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotSupported, ErrorLevel::Permanent); + } + + return RESULT_SUCCESS; +} + +std::shared_ptr Applet::Get(Service::APT::AppletId id) { + auto itr = applets.find(id); + if (itr != applets.end()) + return itr->second; + return nullptr; +} + +} +} // namespace -- cgit v1.2.3 From 621ee10eae0546d4ec3f9e911e113aa9ee609c22 Mon Sep 17 00:00:00 2001 From: Subv Date: Tue, 26 May 2015 11:00:26 -0500 Subject: Applets: Add infrastructure to allow custom drawing and input handling in Applets. --- src/core/hle/applets/applet.cpp | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'src/core/hle/applets/applet.cpp') diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp index 1f447e5fc..689f5adc8 100644 --- a/src/core/hle/applets/applet.cpp +++ b/src/core/hle/applets/applet.cpp @@ -5,15 +5,35 @@ #include "common/assert.h" #include "common/logging/log.h" +#include "core/core_timing.h" #include "core/hle/applets/applet.h" #include "core/hle/applets/swkbd.h" //////////////////////////////////////////////////////////////////////////////////////////////////// +// Specializes std::hash for AppletId, so that we can use it in std::unordered_map. +// Workaround for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970 +namespace std { + template <> + struct hash { + typedef Service::APT::AppletId argument_type; + typedef std::size_t result_type; + + result_type operator()(const argument_type& id_code) const { + typedef std::underlying_type::type Type; + return std::hash()(static_cast(id_code)); + } + }; +} + namespace HLE { namespace Applets { static std::unordered_map> applets; +static u32 applet_update_event = -1; ///< The CoreTiming event identifier for the Applet update callback. +/// The interval at which the Applet update callback will be called. +static const u64 applet_update_interval_microseconds = 16666; +std::shared_ptr g_current_applet = nullptr; ///< The applet that is currently executing ResultCode Applet::Create(Service::APT::AppletId id) { switch (id) { @@ -36,5 +56,23 @@ std::shared_ptr Applet::Get(Service::APT::AppletId id) { return nullptr; } +/// Handles updating the current Applet every time it's called. +static void AppletUpdateEvent(u64, int cycles_late) { + if (g_current_applet && g_current_applet->IsRunning()) + g_current_applet->Update(); + + CoreTiming::ScheduleEvent(usToCycles(applet_update_interval) - cycles_late, + applet_update_event); +} + +void Init() { + applet_update_event = CoreTiming::RegisterEvent("HLE Applet Update Event", AppletUpdateEvent); + CoreTiming::ScheduleEvent(usToCycles(applet_update_interval), applet_update_event); +} + +void Shutdown() { + CoreTiming::UnscheduleEvent(applet_update_event, 0); +} + } } // namespace -- cgit v1.2.3 From 725d5eea7879fa152c51f15fd76003d3c6bc44ed Mon Sep 17 00:00:00 2001 From: Subv Date: Wed, 27 May 2015 15:21:06 -0500 Subject: Applets: Reworked how the Applet update event is handled. Applets are now cleaned up in AppletUpdateEvent after calling their respective Update method. --- src/core/hle/applets/applet.cpp | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) (limited to 'src/core/hle/applets/applet.cpp') diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp index 689f5adc8..4dcce729a 100644 --- a/src/core/hle/applets/applet.cpp +++ b/src/core/hle/applets/applet.cpp @@ -31,9 +31,8 @@ namespace Applets { static std::unordered_map> applets; static u32 applet_update_event = -1; ///< The CoreTiming event identifier for the Applet update callback. -/// The interval at which the Applet update callback will be called. -static const u64 applet_update_interval_microseconds = 16666; -std::shared_ptr g_current_applet = nullptr; ///< The applet that is currently executing +/// The interval at which the Applet update callback will be called, 16.6ms +static const u64 applet_update_interval_us = 16666; ResultCode Applet::Create(Service::APT::AppletId id) { switch (id) { @@ -57,21 +56,38 @@ std::shared_ptr Applet::Get(Service::APT::AppletId id) { } /// Handles updating the current Applet every time it's called. -static void AppletUpdateEvent(u64, int cycles_late) { - if (g_current_applet && g_current_applet->IsRunning()) - g_current_applet->Update(); +static void AppletUpdateEvent(u64 applet_id, int cycles_late) { + Service::APT::AppletId id = static_cast(applet_id); + std::shared_ptr applet = Applet::Get(id); + ASSERT_MSG(applet != nullptr, "Applet doesn't exist! applet_id=%08X", id); - CoreTiming::ScheduleEvent(usToCycles(applet_update_interval) - cycles_late, - applet_update_event); + applet->Update(); + + // If the applet is still running after the last update, reschedule the event + if (applet->IsRunning()) { + CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us) - cycles_late, + applet_update_event, applet_id); + } else { + // Otherwise the applet has terminated, in which case we should clean it up + applets[id] = nullptr; + } +} + +ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) { + ResultCode result = StartImpl(parameter); + if (result.IsError()) + return result; + // Schedule the update event + CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event, static_cast(id)); + return result; } void Init() { + // Register the applet update callback applet_update_event = CoreTiming::RegisterEvent("HLE Applet Update Event", AppletUpdateEvent); - CoreTiming::ScheduleEvent(usToCycles(applet_update_interval), applet_update_event); } void Shutdown() { - CoreTiming::UnscheduleEvent(applet_update_event, 0); } } -- cgit v1.2.3