Browse Source
HLE/APT: Initial HLE support for applets.
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.pull/15/merge
9 changed files with 410 additions and 50 deletions
-
4src/core/CMakeLists.txt
-
40src/core/hle/applets/applet.cpp
-
53src/core/hle/applets/applet.h
-
73src/core/hle/applets/swkbd.cpp
-
67src/core/hle/applets/swkbd.h
-
139src/core/hle/service/apt/apt.cpp
-
49src/core/hle/service/apt/apt.h
-
31src/core/hle/service/apt/apt_a.cpp
-
4src/core/hle/service/apt/apt_u.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<Service::APT::AppletId, std::shared_ptr<Applet>> 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<SoftwareKeyboard>(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> Applet::Get(Service::APT::AppletId id) { |
|||
auto itr = applets.find(id); |
|||
if (itr != applets.end()) |
|||
return itr->second; |
|||
return nullptr; |
|||
} |
|||
|
|||
} |
|||
} // namespace
|
|||
@ -0,0 +1,53 @@ |
|||
// Copyright 2015 Citra Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include "common/common_types.h" |
|||
#include "core/hle/kernel/kernel.h" |
|||
#include "core/hle/kernel/shared_memory.h" |
|||
#include "core/hle/service/apt/apt.h" |
|||
|
|||
namespace HLE { |
|||
namespace Applets { |
|||
|
|||
class Applet { |
|||
public: |
|||
virtual ~Applet() {}; |
|||
Applet(Service::APT::AppletId id) : id(id) {}; |
|||
|
|||
/** |
|||
* Creates an instance of the Applet subclass identified by the parameter |
|||
* and stores it in a global map. |
|||
* @param id Id of the applet to create |
|||
* @returns ResultCode Whether the operation was successful or not |
|||
*/ |
|||
static ResultCode Create(Service::APT::AppletId id); |
|||
|
|||
/** |
|||
* Retrieves the Applet instance identified by the specified id |
|||
* @param id Id of the Applet to retrieve |
|||
* @returns Requested Applet or nullptr if not found |
|||
*/ |
|||
static std::shared_ptr<Applet> Get(Service::APT::AppletId id); |
|||
|
|||
/** |
|||
* Handles a parameter from the application |
|||
* @param parameter Parameter data to handle |
|||
* @returns ResultCode Whether the operation was successful or not |
|||
*/ |
|||
virtual ResultCode ReceiveParameter(Service::APT::MessageParameter const& parameter) = 0; |
|||
|
|||
/** |
|||
* Handles the Applet start event, triggered from the application |
|||
* @param parameter Parameter data to handle |
|||
* @returns ResultCode Whether the operation was successful or not |
|||
*/ |
|||
virtual ResultCode Start(Service::APT::AppletStartupParameter const& parameter) = 0; |
|||
|
|||
Service::APT::AppletId id; ///< Id of this Applet |
|||
}; |
|||
|
|||
} |
|||
} // namespace |
|||
@ -0,0 +1,73 @@ |
|||
// 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/swkbd.h"
|
|||
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|||
|
|||
namespace HLE { |
|||
namespace Applets { |
|||
|
|||
SoftwareKeyboard::SoftwareKeyboard(Service::APT::AppletId id) : Applet(id) { |
|||
// Create the SharedMemory that will hold the framebuffer data
|
|||
// TODO(Subv): What size should we use here?
|
|||
using Kernel::MemoryPermission; |
|||
framebuffer_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "SoftwareKeyboard Memory"); |
|||
} |
|||
|
|||
ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) { |
|||
if (parameter.signal != static_cast<u32>(Service::APT::SignalType::LibAppJustStarted)) { |
|||
LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal); |
|||
UNIMPLEMENTED(); |
|||
// TODO(Subv): Find the right error code
|
|||
return ResultCode(-1); |
|||
} |
|||
|
|||
Service::APT::MessageParameter result; |
|||
// The buffer passed in parameter contains the data returned by GSPGPU::ImportDisplayCaptureInfo
|
|||
result.signal = static_cast<u32>(Service::APT::SignalType::LibAppFinished); |
|||
result.data = nullptr; |
|||
result.buffer_size = 0; |
|||
result.destination_id = static_cast<u32>(Service::APT::AppletId::Application); |
|||
result.sender_id = static_cast<u32>(id); |
|||
result.object = framebuffer_memory; |
|||
|
|||
Service::APT::SendParameter(result); |
|||
return RESULT_SUCCESS; |
|||
} |
|||
|
|||
ResultCode SoftwareKeyboard::Start(Service::APT::AppletStartupParameter const& parameter) { |
|||
memcpy(&config, parameter.data, parameter.buffer_size); |
|||
text_memory = boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object); |
|||
|
|||
// TODO(Subv): Verify if this is the correct behavior
|
|||
memset(text_memory->GetPointer(), 0, text_memory->size); |
|||
|
|||
// TODO(Subv): Remove this hardcoded text
|
|||
const wchar_t str[] = L"Subv"; |
|||
memcpy(text_memory->GetPointer(), str, 4 * sizeof(wchar_t)); |
|||
|
|||
// TODO(Subv): Ask for input and write it to the shared memory
|
|||
// TODO(Subv): Find out what are the possible values for the return code,
|
|||
// some games seem to check for a hardcoded 2
|
|||
config.return_code = 2; |
|||
config.text_length = 5; |
|||
config.text_offset = 0; |
|||
|
|||
Service::APT::MessageParameter message; |
|||
message.buffer_size = sizeof(SoftwareKeyboardConfig); |
|||
message.data = reinterpret_cast<u8*>(&config); |
|||
message.signal = static_cast<u32>(Service::APT::SignalType::LibAppClosed); |
|||
message.destination_id = static_cast<u32>(Service::APT::AppletId::Application); |
|||
message.sender_id = static_cast<u32>(id); |
|||
Service::APT::SendParameter(message); |
|||
|
|||
return RESULT_SUCCESS; |
|||
} |
|||
|
|||
} |
|||
} // namespace
|
|||
@ -0,0 +1,67 @@ |
|||
// Copyright 2015 Citra Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include "common/common_types.h" |
|||
#include "core/hle/applets/applet.h" |
|||
#include "core/hle/kernel/kernel.h" |
|||
#include "core/hle/kernel/shared_memory.h" |
|||
#include "core/hle/service/apt/apt.h" |
|||
|
|||
namespace HLE { |
|||
namespace Applets { |
|||
|
|||
struct SoftwareKeyboardConfig { |
|||
INSERT_PADDING_WORDS(0x8); |
|||
|
|||
u16 max_text_length; ///< Maximum length of the input text |
|||
|
|||
INSERT_PADDING_BYTES(0x6E); |
|||
|
|||
char16_t display_text[65]; ///< Text to display when asking the user for input |
|||
|
|||
INSERT_PADDING_BYTES(0xE); |
|||
|
|||
u32 default_text_offset; ///< Offset of the default text in the output SharedMemory |
|||
|
|||
INSERT_PADDING_WORDS(0x3); |
|||
|
|||
u32 shared_memory_size; ///< Size of the SharedMemory |
|||
|
|||
INSERT_PADDING_WORDS(0x1); |
|||
|
|||
u32 return_code; ///< Return code of the SoftwareKeyboard, usually 2, other values are unknown |
|||
|
|||
INSERT_PADDING_WORDS(0x2); |
|||
|
|||
u32 text_offset; ///< Offset in the SharedMemory where the output text starts |
|||
u16 text_length; ///< Length in characters of the output text |
|||
|
|||
INSERT_PADDING_BYTES(0x2B6); |
|||
}; |
|||
|
|||
static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config size is wrong"); |
|||
|
|||
class SoftwareKeyboard : public Applet { |
|||
public: |
|||
SoftwareKeyboard(Service::APT::AppletId id); |
|||
~SoftwareKeyboard() {} |
|||
|
|||
ResultCode ReceiveParameter(Service::APT::MessageParameter const& parameter) override; |
|||
ResultCode Start(Service::APT::AppletStartupParameter const& parameter) override; |
|||
|
|||
/// TODO(Subv): Find out what this is actually used for. |
|||
// It is believed that the application stores the current screen image here. |
|||
Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory; |
|||
|
|||
/// SharedMemory where the output text will be stored |
|||
Kernel::SharedPtr<Kernel::SharedMemory> text_memory; |
|||
|
|||
/// Configuration of this instance of the SoftwareKeyboard, as received from the application |
|||
SoftwareKeyboardConfig config; |
|||
}; |
|||
|
|||
} |
|||
} // namespace |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue