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.
This commit is contained in:
Subv 2015-05-25 23:30:20 -05:00
parent b0d72e3de1
commit 2a6ebadf66
9 changed files with 410 additions and 50 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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