mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 13:01:50 +01:00
Stub the controller applet
Mostly based off of yuzu's implementation, this will need to be extended in the future to open up a UI for configuring controllers according to the applications requirements.
This commit is contained in:
parent
9a8e39cba1
commit
d115ce3c05
@ -248,6 +248,7 @@ add_library(skyline SHARED
|
|||||||
${source_DIR}/skyline/services/am/applet/ILibraryAppletAccessor.cpp
|
${source_DIR}/skyline/services/am/applet/ILibraryAppletAccessor.cpp
|
||||||
${source_DIR}/skyline/services/am/applet/IApplet.cpp
|
${source_DIR}/skyline/services/am/applet/IApplet.cpp
|
||||||
${source_DIR}/skyline/applet/applet_creator.cpp
|
${source_DIR}/skyline/applet/applet_creator.cpp
|
||||||
|
${source_DIR}/skyline/applet/controller_applet.cpp
|
||||||
${source_DIR}/skyline/services/codec/IHardwareOpusDecoder.cpp
|
${source_DIR}/skyline/services/codec/IHardwareOpusDecoder.cpp
|
||||||
${source_DIR}/skyline/services/codec/IHardwareOpusDecoderManager.cpp
|
${source_DIR}/skyline/services/codec/IHardwareOpusDecoderManager.cpp
|
||||||
${source_DIR}/skyline/services/hid/IHidServer.cpp
|
${source_DIR}/skyline/services/hid/IHidServer.cpp
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#include "controller_applet.h"
|
||||||
#include "applet_creator.h"
|
#include "applet_creator.h"
|
||||||
|
|
||||||
namespace skyline::applet {
|
namespace skyline::applet {
|
||||||
@ -11,6 +12,8 @@ namespace skyline::applet {
|
|||||||
std::shared_ptr<kernel::type::KEvent> onInteractiveDataPushFromApplet,
|
std::shared_ptr<kernel::type::KEvent> onInteractiveDataPushFromApplet,
|
||||||
service::applet::LibraryAppletMode appletMode) {
|
service::applet::LibraryAppletMode appletMode) {
|
||||||
switch (appletId) {
|
switch (appletId) {
|
||||||
|
case AppletId::LibraryAppletController:
|
||||||
|
return std::make_shared<ControllerApplet>(state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode);
|
||||||
default:
|
default:
|
||||||
throw exception("Unimplemented Applet: 0x{:X} ({})", static_cast<u32>(appletId), ToString(appletId));
|
throw exception("Unimplemented Applet: 0x{:X} ({})", static_cast<u32>(appletId), ToString(appletId));
|
||||||
}
|
}
|
||||||
|
111
app/src/main/cpp/skyline/applet/controller_applet.cpp
Normal file
111
app/src/main/cpp/skyline/applet/controller_applet.cpp
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
|
||||||
|
#include <input.h>
|
||||||
|
#include <input/npad.h>
|
||||||
|
#include <services/applet/common_arguments.h>
|
||||||
|
#include <services/am/storage/ObjIStorage.h>
|
||||||
|
#include "controller_applet.h"
|
||||||
|
|
||||||
|
namespace skyline::applet {
|
||||||
|
ControllerApplet::ControllerApplet(const DeviceState &state,
|
||||||
|
service::ServiceManager &manager,
|
||||||
|
std::shared_ptr<kernel::type::KEvent> onAppletStateChanged,
|
||||||
|
std::shared_ptr<kernel::type::KEvent> onNormalDataPushFromApplet,
|
||||||
|
std::shared_ptr<kernel::type::KEvent> onInteractiveDataPushFromApplet,
|
||||||
|
service::applet::LibraryAppletMode appletMode)
|
||||||
|
: IApplet(state, manager, std::move(onAppletStateChanged), std::move(onNormalDataPushFromApplet), std::move(onInteractiveDataPushFromApplet), appletMode) {}
|
||||||
|
|
||||||
|
void ControllerApplet::HandleShowControllerSupport(input::NpadStyleSet styleSet, ControllerAppletVersion version, span<u8> arg) {
|
||||||
|
// Generic macro due to both versions of arguments sharing the same fields but having different layouts
|
||||||
|
auto handle{[&](auto controllerSupportModeArg) {
|
||||||
|
Logger::Info("playerCountMin: {}, playerCountMax: {}, "
|
||||||
|
"enableTakeOverConnection: {}, enableLeftJustify: {}, enablePermitJoyDual: {}, enableSingleMode: {}, "
|
||||||
|
"enableIdentificationColor: {}, enableExplainText: {}",
|
||||||
|
controllerSupportModeArg.playerCountMin, controllerSupportModeArg.playerCountMax,
|
||||||
|
controllerSupportModeArg.enableTakeOverConnection, controllerSupportModeArg.enableLeftJustify, controllerSupportModeArg.enablePermitJoyDual, controllerSupportModeArg.enableSingleMode,
|
||||||
|
controllerSupportModeArg.enableIdentificationColor, controllerSupportModeArg.enableExplainText);
|
||||||
|
|
||||||
|
// Here is where we would trigger the applet UI
|
||||||
|
|
||||||
|
auto &npad{state.input->npad};
|
||||||
|
std::scoped_lock lock{npad.mutex};
|
||||||
|
|
||||||
|
PushNormalDataAndSignal(std::make_shared<service::am::ObjIStorage<ControllerSupportResultInfo>>(state, manager, ControllerSupportResultInfo{
|
||||||
|
.playerCount = static_cast<i8>(controllerSupportModeArg.enableSingleMode ? 1 : npad.GetConnectedControllerCount()),
|
||||||
|
.selectedId = [&npad]() {
|
||||||
|
if (npad.controllers[0].device) {
|
||||||
|
return npad.controllers[0].device->id;
|
||||||
|
} else {
|
||||||
|
Logger::Warn("Controller requested but none connected!");
|
||||||
|
return input::NpadId::Player1; // Fallback to player 1
|
||||||
|
}
|
||||||
|
}(),
|
||||||
|
.result = {}
|
||||||
|
}));
|
||||||
|
}};
|
||||||
|
|
||||||
|
switch (version) {
|
||||||
|
case ControllerAppletVersion::Version3:
|
||||||
|
case ControllerAppletVersion::Version4:
|
||||||
|
case ControllerAppletVersion::Version5:
|
||||||
|
handle(arg.as<ControllerSupportArgOld>());
|
||||||
|
break;
|
||||||
|
case ControllerAppletVersion::Version7:
|
||||||
|
case ControllerAppletVersion::Version8:
|
||||||
|
handle(arg.as<ControllerSupportArgNew>());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Logger::Warn("Unsupported controller applet version {}", static_cast<u32>(version));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Result ControllerApplet::Start() {
|
||||||
|
auto commonArg{PopNormalInput<service::applet::CommonArguments>()};
|
||||||
|
ControllerAppletVersion appletVersion{commonArg.apiVersion};
|
||||||
|
|
||||||
|
auto argPrivate{PopNormalInput<ControllerSupportArgPrivate>()};
|
||||||
|
|
||||||
|
// Some games such as Cave Story+ set invalid values for the ControllerSupportMode so use argSize to derive it if necessary (from yuzu)
|
||||||
|
if (argPrivate.mode >= ControllerSupportMode::MaxControllerSupportMode) {
|
||||||
|
switch (argPrivate.argSize) {
|
||||||
|
case sizeof(ControllerSupportArgOld):
|
||||||
|
case sizeof(ControllerSupportArgNew):
|
||||||
|
argPrivate.mode = ControllerSupportMode::ShowControllerSupport;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// TODO: when we support other modes make sure to add them here too
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (argPrivate.mode) {
|
||||||
|
case ControllerSupportMode::ShowControllerSupport:
|
||||||
|
HandleShowControllerSupport(argPrivate.styleSet, appletVersion, normalInputData.front()->GetSpan());
|
||||||
|
normalInputData.pop();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Logger::Warn("Controller applet mode {} is unimplemented", static_cast<u32>(argPrivate.mode));
|
||||||
|
normalInputData.pop();
|
||||||
|
|
||||||
|
// Return empty result
|
||||||
|
PushNormalDataAndSignal(std::make_shared<service::am::ObjIStorage<Result>>(state, manager, Result{}));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify the guest that we've finished running
|
||||||
|
onAppletStateChanged->Signal();
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
Result ControllerApplet::GetResult() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerApplet::PushNormalDataToApplet(std::shared_ptr<service::am::IStorage> data) {
|
||||||
|
normalInputData.emplace(std::move(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerApplet::PushInteractiveDataToApplet(std::shared_ptr<service::am::IStorage> data) {}
|
||||||
|
}
|
126
app/src/main/cpp/skyline/applet/controller_applet.h
Normal file
126
app/src/main/cpp/skyline/applet/controller_applet.h
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <services/am/applet/IApplet.h>
|
||||||
|
#include <services/applet/common_arguments.h>
|
||||||
|
#include <input/npad_device.h>
|
||||||
|
|
||||||
|
namespace skyline::applet {
|
||||||
|
/**
|
||||||
|
* @brief The Controller applet is responsible for notifiying the user of a games controller requirements and for allowing user management og controllers
|
||||||
|
*/
|
||||||
|
class ControllerApplet : public service::am::IApplet {
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief The version of the controller applet interface that an application supports
|
||||||
|
*/
|
||||||
|
enum class ControllerAppletVersion : u32 {
|
||||||
|
Version3 = 0x3, // 1.0.0 - 2.3.0
|
||||||
|
Version4 = 0x4, // 3.0.0 - 5.1.0
|
||||||
|
Version5 = 0x5, // 6.0.0 - 7.0.1
|
||||||
|
// No version 6
|
||||||
|
Version7 = 0x7, // 8.0.0 - 10.2.0
|
||||||
|
Version8 = 0x8, // 11.0.0+
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The requested mode of the controller applet, determines the specific UI that should be shown to the user
|
||||||
|
*/
|
||||||
|
enum class ControllerSupportMode : u8 {
|
||||||
|
ShowControllerSupport = 0,
|
||||||
|
ShowControllerStrapGuide = 1,
|
||||||
|
ShowControllerFirmwareUpdate = 2,
|
||||||
|
ShowControllerKeyRemappingForSystem = 3,
|
||||||
|
|
||||||
|
MaxControllerSupportMode
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The caller that is requesting the controller applet
|
||||||
|
*/
|
||||||
|
enum class ControllerSupportCaller : u8 {
|
||||||
|
Application = 1,
|
||||||
|
System = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Common set of arguments supplied for all controller applet invocations
|
||||||
|
*/
|
||||||
|
struct ControllerSupportArgPrivate {
|
||||||
|
u32 argPrivateSize;
|
||||||
|
u32 argSize;
|
||||||
|
bool flag0;
|
||||||
|
bool flag1;
|
||||||
|
ControllerSupportMode mode;
|
||||||
|
ControllerSupportCaller caller;
|
||||||
|
input::NpadStyleSet styleSet;
|
||||||
|
u32 joyHoldType;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ControllerSupportArgPrivate) == 0x14);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set of arguments required for the ShowControllerSupport mode, templated since the number of controller supported varies based on applet version
|
||||||
|
*/
|
||||||
|
template<u8 NumControllersSupported>
|
||||||
|
struct ControllerSupportArg {
|
||||||
|
using IdentificationColor = std::array<u8, 4>; // RGBA colour code
|
||||||
|
using ExplainText = std::array<char, 128 + 1>; // 128 chars + null terminator
|
||||||
|
|
||||||
|
i8 playerCountMin{};
|
||||||
|
i8 playerCountMax{};
|
||||||
|
bool enableTakeOverConnection{};
|
||||||
|
bool enableLeftJustify{};
|
||||||
|
bool enablePermitJoyDual{};
|
||||||
|
bool enableSingleMode{};
|
||||||
|
bool enableIdentificationColor{};
|
||||||
|
std::array<IdentificationColor, NumControllersSupported> identification_colors{};
|
||||||
|
bool enableExplainText{};
|
||||||
|
std::array<ExplainText, NumControllersSupported> explain_text{};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Applet versions 3-5 inclusive allow 4 controllers maximum
|
||||||
|
using ControllerSupportArgOld = ControllerSupportArg<4>;
|
||||||
|
static_assert(sizeof(ControllerSupportArgOld) == 0x21C);
|
||||||
|
|
||||||
|
// Applet versions 6-8 allow 8 controllers maximum
|
||||||
|
using ControllerSupportArgNew = ControllerSupportArg<8>;
|
||||||
|
static_assert(sizeof(ControllerSupportArgNew) == 0x430);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The result type of the controller applet controller support mode
|
||||||
|
*/
|
||||||
|
struct ControllerSupportResultInfo {
|
||||||
|
i8 playerCount;
|
||||||
|
u8 _pad_[3];
|
||||||
|
input::NpadId selectedId;
|
||||||
|
Result result;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ControllerSupportResultInfo) == 0xC);
|
||||||
|
|
||||||
|
std::queue<std::shared_ptr<service::am::IStorage>> normalInputData;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T PopNormalInput() {
|
||||||
|
auto data{normalInputData.front()->GetSpan().as<T>()};
|
||||||
|
normalInputData.pop();
|
||||||
|
return static_cast<T>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handles the 'ShowControllerSupport' mode of the controller applet
|
||||||
|
*/
|
||||||
|
void HandleShowControllerSupport(input::NpadStyleSet styleSet, ControllerAppletVersion version, span<u8> arg);
|
||||||
|
|
||||||
|
public:
|
||||||
|
ControllerApplet(const DeviceState &state, service::ServiceManager &manager, std::shared_ptr<kernel::type::KEvent> onAppletStateChanged, std::shared_ptr<kernel::type::KEvent> onNormalDataPushFromApplet, std::shared_ptr<kernel::type::KEvent> onInteractiveDataPushFromApplet, service::applet::LibraryAppletMode appletMode);
|
||||||
|
|
||||||
|
Result Start() override;
|
||||||
|
|
||||||
|
Result GetResult() override;
|
||||||
|
|
||||||
|
void PushNormalDataToApplet(std::shared_ptr<service::am::IStorage> data) override;
|
||||||
|
|
||||||
|
void PushInteractiveDataToApplet(std::shared_ptr<service::am::IStorage> data) override;
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user