mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-22 21:39:15 +01:00
Initial C++ Input Implementation
This commit contains the C++ side of the initial Input implementation, this is based on the work done in the `hid` branch in `bylaws/skyline`. Co-authored-by: ◱ PixelyIon <pixelyion@protonmail.com>
This commit is contained in:
parent
817d37600e
commit
0219eda2db
30
.idea/jarRepositories.xml
Normal file
30
.idea/jarRepositories.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="BintrayJCenter" />
|
||||
<option name="name" value="BintrayJCenter" />
|
||||
<option name="url" value="https://jcenter.bintray.com/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="Google" />
|
||||
<option name="name" value="Google" />
|
||||
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenRepo" />
|
||||
<option name="name" value="MavenRepo" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
@ -45,6 +45,8 @@ add_library(skyline SHARED
|
||||
${source_DIR}/skyline/gpu/syncpoint.cpp
|
||||
${source_DIR}/skyline/gpu/texture.cpp
|
||||
${source_DIR}/skyline/gpu/engines/maxwell_3d.cpp
|
||||
${source_DIR}/skyline/input.cpp
|
||||
${source_DIR}/skyline/input/npad.cpp
|
||||
${source_DIR}/skyline/os.cpp
|
||||
${source_DIR}/skyline/loader/loader.cpp
|
||||
${source_DIR}/skyline/loader/nro.cpp
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "skyline/common.h"
|
||||
#include "skyline/os.h"
|
||||
#include "skyline/jvm.h"
|
||||
#include "skyline/input.h"
|
||||
|
||||
bool Halt;
|
||||
jobject Surface;
|
||||
@ -14,6 +15,7 @@ uint FaultCount;
|
||||
skyline::GroupMutex JniMtx;
|
||||
skyline::u16 fps;
|
||||
skyline::u32 frametime;
|
||||
skyline::input::Input *input;
|
||||
|
||||
void signalHandler(int signal) {
|
||||
syslog(LOG_ERR, "Halting program due to signal: %s", strsignal(signal));
|
||||
@ -50,30 +52,33 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
|
||||
|
||||
try {
|
||||
skyline::kernel::OS os(jvmManager, logger, settings, std::string(appFilesPath));
|
||||
input = os.state.input.get();
|
||||
env->ReleaseStringUTFChars(appFilesPathJstring, appFilesPath);
|
||||
|
||||
auto romUri = env->GetStringUTFChars(romUriJstring, nullptr);
|
||||
logger->Info("Launching ROM {}", romUri);
|
||||
env->ReleaseStringUTFChars(romUriJstring, romUri);
|
||||
|
||||
os.Execute(romFd, static_cast<skyline::loader::RomFormat>(romType));
|
||||
} catch (std::exception &e) {
|
||||
logger->Error(e.what());
|
||||
} catch (...) {
|
||||
logger->Error("An unknown exception has occurred");
|
||||
}
|
||||
|
||||
logger->Info("Emulation has ended");
|
||||
|
||||
auto end = std::chrono::steady_clock::now();
|
||||
logger->Info("Done in: {} ms", (std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_setHalt(JNIEnv *env, jobject instance, jboolean halt) {
|
||||
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_setHalt(JNIEnv *, jobject, jboolean halt) {
|
||||
JniMtx.lock(skyline::GroupMutex::Group::Group2);
|
||||
Halt = halt;
|
||||
JniMtx.unlock();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_setSurface(JNIEnv *env, jobject instance, jobject surface) {
|
||||
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_setSurface(JNIEnv *env, jobject, jobject surface) {
|
||||
JniMtx.lock(skyline::GroupMutex::Group::Group2);
|
||||
if (!env->IsSameObject(Surface, nullptr))
|
||||
env->DeleteGlobalRef(Surface);
|
||||
@ -84,10 +89,19 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_setSurface(JNIEnv *
|
||||
JniMtx.unlock();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint Java_emu_skyline_EmulationActivity_getFps(JNIEnv *env, jobject thiz) {
|
||||
extern "C" JNIEXPORT jint Java_emu_skyline_EmulationActivity_getFps(JNIEnv *, jobject ) {
|
||||
return fps;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jfloat Java_emu_skyline_EmulationActivity_getFrametime(JNIEnv *env, jobject thiz) {
|
||||
extern "C" JNIEXPORT jfloat Java_emu_skyline_EmulationActivity_getFrametime(JNIEnv *, jobject ) {
|
||||
return static_cast<float>(frametime) / 100;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setButtonState(JNIEnv *, jobject, jlong id, jint state) {
|
||||
skyline::input::npad::NpadButton button{.raw = static_cast<skyline::u64>(id)};
|
||||
input->npad[0]->SetButtonState(button, static_cast<skyline::input::npad::NpadButtonState>(state));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setAxisValue(JNIEnv *, jobject, jint id, jint value) {
|
||||
input->npad[0]->SetAxisValue(static_cast<skyline::input::npad::NpadAxisId>(id), value);
|
||||
}
|
||||
|
@ -31,13 +31,13 @@ namespace skyline::audio {
|
||||
* @param releaseCallback The callback to call when a buffer has been released
|
||||
* @return A shared pointer to a new AudioTrack object
|
||||
*/
|
||||
std::shared_ptr<AudioTrack> OpenTrack(u8 channelCount, u32 sampleRate, const std::function<void()> &releaseCallback);
|
||||
std::shared_ptr<audio::AudioTrack> OpenTrack(u8 channelCount, u32 sampleRate, const std::function<void()> &releaseCallback);
|
||||
|
||||
/**
|
||||
* @brief Closes a track and frees its data
|
||||
* @param track The track to close
|
||||
*/
|
||||
void CloseTrack(std::shared_ptr<AudioTrack> &track);
|
||||
void CloseTrack(std::shared_ptr<audio::AudioTrack> &track);
|
||||
|
||||
/**
|
||||
* @brief The callback oboe uses to get audio sample data
|
||||
|
@ -1,12 +1,13 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <tinyxml2.h>
|
||||
#include "common.h"
|
||||
#include "nce.h"
|
||||
#include "gpu.h"
|
||||
#include "audio.h"
|
||||
#include <kernel/types/KThread.h>
|
||||
#include <tinyxml2.h>
|
||||
#include "input.h"
|
||||
#include "kernel/types/KThread.h"
|
||||
|
||||
namespace skyline {
|
||||
void Mutex::lock() {
|
||||
@ -154,6 +155,7 @@ namespace skyline {
|
||||
nce = std::make_shared<NCE>(*this);
|
||||
gpu = std::make_shared<gpu::GPU>(*this);
|
||||
audio = std::make_shared<audio::Audio>(*this);
|
||||
input = std::make_shared<input::Input>(*this);
|
||||
}
|
||||
|
||||
thread_local std::shared_ptr<kernel::type::KThread> DeviceState::thread = nullptr;
|
||||
|
@ -364,6 +364,9 @@ namespace skyline {
|
||||
namespace audio {
|
||||
class Audio;
|
||||
}
|
||||
namespace input {
|
||||
class Input;
|
||||
}
|
||||
namespace loader {
|
||||
class Loader;
|
||||
}
|
||||
@ -381,6 +384,7 @@ namespace skyline {
|
||||
std::shared_ptr<NCE> nce; //!< This holds a reference to the NCE class
|
||||
std::shared_ptr<gpu::GPU> gpu; //!< This holds a reference to the GPU class
|
||||
std::shared_ptr<audio::Audio> audio; //!< This holds a reference to the Audio class
|
||||
std::shared_ptr<input::Input> input; //!< This holds a reference to the Input class
|
||||
std::shared_ptr<loader::Loader> loader; //!< This holds a reference to the Loader class
|
||||
std::shared_ptr<JvmManager> jvm; //!< This holds a reference to the JvmManager class
|
||||
std::shared_ptr<Settings> settings; //!< This holds a reference to the Settings class
|
||||
|
14
app/src/main/cpp/skyline/input.cpp
Normal file
14
app/src/main/cpp/skyline/input.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include "input.h"
|
||||
|
||||
namespace skyline::input {
|
||||
Input::Input(const DeviceState &state) : state(state), commonNpad(std::make_shared<npad::CommonNpad>(state)), hidKMem(std::make_shared<kernel::type::KSharedMemory>(state, NULL, sizeof(HidSharedMemory), memory::Permission(true, false, false))) {
|
||||
hidMem = reinterpret_cast<HidSharedMemory *>(hidKMem->kernel.address);
|
||||
|
||||
for (uint i = 0; i < constant::NpadCount; i++) {
|
||||
npad.at(i) = std::make_shared<npad::NpadDevice>(hidMem->npad.at(i), npad::IndexToNpadId(i));
|
||||
}
|
||||
}
|
||||
}
|
27
app/src/main/cpp/skyline/input.h
Normal file
27
app/src/main/cpp/skyline/input.h
Normal file
@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "kernel/types/KSharedMemory.h"
|
||||
#include "input/common.h"
|
||||
|
||||
namespace skyline::input {
|
||||
/**
|
||||
* @brief The Input class manages input devices
|
||||
*/
|
||||
class Input {
|
||||
private:
|
||||
const DeviceState &state; //!< The state of the device
|
||||
|
||||
public:
|
||||
Input(const DeviceState &state);
|
||||
|
||||
std::shared_ptr<npad::CommonNpad> commonNpad; //!< The common npad device
|
||||
std::array<std::shared_ptr<npad::NpadDevice>, constant::NpadCount> npad; //!< Array of npad devices
|
||||
|
||||
std::shared_ptr<kernel::type::KSharedMemory> hidKMem; //!< The shared memory reserved for HID input
|
||||
HidSharedMemory *hidMem; //!< A pointer to the root of HID shared memory
|
||||
};
|
||||
}
|
29
app/src/main/cpp/skyline/input/common.h
Normal file
29
app/src/main/cpp/skyline/input/common.h
Normal file
@ -0,0 +1,29 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "npad.h"
|
||||
|
||||
namespace skyline::input {
|
||||
/**
|
||||
* @brief Encapsulates hid shared memory
|
||||
*/
|
||||
struct HidSharedMemory {
|
||||
DebugPadSection debugPad; //!< The debug pad section
|
||||
TouchScreenSection touchScreen; //!< The touch screen section
|
||||
MouseSection mouse; //!< The mouse section
|
||||
KeyboardSection keyboard; //!< The keyboard section
|
||||
std::array<BasicXpadSection, 4> xpad; //!< The xpads section
|
||||
HomeButtonSection homeButton; //!< The home button section
|
||||
SleepButtonSection sleepButton; //!< The sleep button section
|
||||
CaptureButtonSection captureButton; //!< The capture button section
|
||||
std::array<InputDetectorSection, 16> inputDetector; //!< The input detectors section
|
||||
u64 _pad0_[0x80 * 0x10]; //!< Unique pad (<5.0.0)
|
||||
std::array<npad::NpadSection, constant::NpadCount> npad; //!< The npads section
|
||||
GestureSection gesture; //!< The gesture section
|
||||
ConsoleSixAxisSensorSection consoleSixAxisSensor; //!< The gyro/accel section
|
||||
u64 _pad1_[0x7BC];
|
||||
};
|
||||
static_assert(sizeof(HidSharedMemory) == 0x40000);
|
||||
}
|
177
app/src/main/cpp/skyline/input/npad.cpp
Normal file
177
app/src/main/cpp/skyline/input/npad.cpp
Normal file
@ -0,0 +1,177 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <input.h>
|
||||
#include "npad.h"
|
||||
|
||||
namespace skyline::input::npad {
|
||||
u32 NpadIdToIndex(NpadId id) {
|
||||
switch (id) {
|
||||
case NpadId::Unknown:
|
||||
return 8;
|
||||
case NpadId::Handheld:
|
||||
return 9;
|
||||
default:
|
||||
return static_cast<u32>(id);
|
||||
}
|
||||
}
|
||||
|
||||
NpadId IndexToNpadId(u32 index) {
|
||||
switch (index) {
|
||||
case 8:
|
||||
return NpadId::Unknown;
|
||||
case 9:
|
||||
return NpadId::Handheld;
|
||||
default:
|
||||
return static_cast<NpadId>(index);
|
||||
}
|
||||
}
|
||||
|
||||
NpadDevice::NpadDevice(NpadSection &shmemSection, NpadId id) : shmemSection(shmemSection), id(id) {}
|
||||
|
||||
void NpadDevice::Disconnect() {
|
||||
connectionState.connected = false;
|
||||
}
|
||||
|
||||
void NpadDevice::Connect(NpadControllerType type) {
|
||||
shmemSection.header.styles.raw = 0;
|
||||
shmemSection.deviceType.raw = 0;
|
||||
shmemSection.properties.raw = 0;
|
||||
|
||||
connectionState.raw = 0;
|
||||
connectionState.connected = true;
|
||||
|
||||
switch (type) {
|
||||
case NpadControllerType::Handheld:
|
||||
shmemSection.header.styles.joyconHandheld = true;
|
||||
shmemSection.deviceType.handheld = true;
|
||||
shmemSection.deviceType.handheldLeft = true;
|
||||
shmemSection.deviceType.handheldRight = true;
|
||||
shmemSection.header.assignment = NpadJoyAssignment::Dual;
|
||||
shmemSection.properties.ABXYButtonOriented = true;
|
||||
shmemSection.properties.plusButtonCapability = true;
|
||||
shmemSection.properties.minusButtonCapability = true;
|
||||
|
||||
connectionState.handheld = true;
|
||||
connectionState.leftJoyconConnected = true;
|
||||
connectionState.rightJoyconConnected = true;
|
||||
connectionState.leftJoyconHandheld = true;
|
||||
connectionState.rightJoyconHandheld = true;
|
||||
break;
|
||||
case NpadControllerType::ProController:
|
||||
shmemSection.header.styles.proController = true;
|
||||
shmemSection.deviceType.fullKey = true;
|
||||
shmemSection.deviceType.joyconRight = true;
|
||||
shmemSection.header.assignment = NpadJoyAssignment::Single;
|
||||
shmemSection.properties.ABXYButtonOriented = true;
|
||||
shmemSection.properties.plusButtonCapability = true;
|
||||
shmemSection.properties.minusButtonCapability = true;
|
||||
break;
|
||||
default:
|
||||
throw exception("Unsupported controller type: {}", type);
|
||||
}
|
||||
|
||||
controllerType = type;
|
||||
|
||||
shmemSection.header.singleColourStatus = NpadColourReadStatus::Success;
|
||||
shmemSection.header.singleColour = {0, 0};
|
||||
|
||||
shmemSection.header.dualColourStatus = NpadColourReadStatus::Success;
|
||||
shmemSection.header.leftColour = {0, 0}; //TODO: make these configurable
|
||||
shmemSection.header.rightColour = {0, 0};
|
||||
|
||||
shmemSection.batteryLevel[0] = constant::NpadBatteryFull;
|
||||
shmemSection.batteryLevel[1] = constant::NpadBatteryFull;
|
||||
shmemSection.batteryLevel[2] = constant::NpadBatteryFull;
|
||||
|
||||
// Set controllers initial state
|
||||
SetButtonState(NpadButton{}, NpadButtonState::Released);
|
||||
|
||||
//TODO: signal npad event
|
||||
}
|
||||
|
||||
NpadControllerInfo &NpadDevice::GetControllerDeviceInfo() {
|
||||
switch (controllerType) {
|
||||
case NpadControllerType::Handheld:
|
||||
return shmemSection.handheldController;
|
||||
case NpadControllerType::ProController:
|
||||
default:
|
||||
return shmemSection.fullKeyController;
|
||||
}
|
||||
}
|
||||
|
||||
void NpadDevice::UpdateHeaders(NpadControllerInfo &controller, uint lastStateEntryIndex) {
|
||||
controller.header.entryCount = constant::HidEntryCount;
|
||||
controller.header.maxEntry = constant::HidEntryCount - 1;
|
||||
controller.header.currentEntry = stateEntryIndex;
|
||||
controller.header.timestamp = util::GetTimeNs();
|
||||
|
||||
memcpy(reinterpret_cast<void *>(&controller.state.at(stateEntryIndex)), reinterpret_cast<void *>(&controller.state.at(lastStateEntryIndex)), sizeof(NpadControllerState));
|
||||
|
||||
controller.state.at(stateEntryIndex).globalTimestamp++;
|
||||
controller.state.at(stateEntryIndex).localTimestamp++;
|
||||
controller.state.at(stateEntryIndex).status.raw = connectionState.raw;
|
||||
}
|
||||
|
||||
void NpadDevice::SetButtonState(NpadButton button, NpadButtonState state) {
|
||||
NpadControllerInfo &controllerDeviceInfo = GetControllerDeviceInfo();
|
||||
uint lastStateEntryIndex = stateEntryIndex;
|
||||
stateEntryIndex = (stateEntryIndex + 1) % constant::HidEntryCount;
|
||||
|
||||
for (NpadControllerInfo &controllerInfo : {std::ref(controllerDeviceInfo), std::ref(shmemSection.systemExtController)}) {
|
||||
UpdateHeaders(controllerInfo, lastStateEntryIndex);
|
||||
|
||||
if (state == NpadButtonState::Pressed)
|
||||
controllerInfo.state.at(stateEntryIndex).controller.buttons.raw |= button.raw;
|
||||
else
|
||||
controllerInfo.state.at(stateEntryIndex).controller.buttons.raw &= ~(button.raw);
|
||||
}
|
||||
}
|
||||
|
||||
void NpadDevice::SetAxisValue(NpadAxisId axis, int value) {
|
||||
NpadControllerInfo controllerDeviceInfo = GetControllerDeviceInfo();
|
||||
uint lastStateEntryIndex = stateEntryIndex;
|
||||
stateEntryIndex = (stateEntryIndex + 1) % constant::HidEntryCount;
|
||||
|
||||
for (NpadControllerInfo &controllerInfo : {std::ref(controllerDeviceInfo), std::ref(shmemSection.systemExtController)}) {
|
||||
UpdateHeaders(controllerInfo, lastStateEntryIndex);
|
||||
|
||||
switch (axis) {
|
||||
case NpadAxisId::LX:
|
||||
controllerInfo.state.at(stateEntryIndex).controller.leftX = value;
|
||||
break;
|
||||
case NpadAxisId::LY:
|
||||
controllerInfo.state.at(stateEntryIndex).controller.leftY = -value; // Invert Y axis
|
||||
break;
|
||||
case NpadAxisId::RX:
|
||||
controllerInfo.state.at(stateEntryIndex).controller.rightX = value;
|
||||
break;
|
||||
case NpadAxisId::RY:
|
||||
controllerInfo.state.at(stateEntryIndex).controller.rightY = -value; // Invert Y axis
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CommonNpad::CommonNpad(const DeviceState &state) : state(state) {}
|
||||
|
||||
void CommonNpad::Activate() {
|
||||
// Always mark controllers we support as supported
|
||||
if (supportedStyles.raw == 0) {
|
||||
supportedStyles.proController = true;
|
||||
supportedStyles.joyconHandheld = true;
|
||||
}
|
||||
|
||||
for (uint i = 0; i < constant::NpadCount; i++) {
|
||||
bool shouldConnect = (i == 0); // P1
|
||||
|
||||
//TODO: Read this as well as controller type from settings based off of NpadID
|
||||
if (shouldConnect) {
|
||||
if (state.settings->GetBool("operation_mode"))
|
||||
state.input->npad.at(i)->Connect(NpadControllerType::Handheld);
|
||||
else
|
||||
state.input->npad.at(i)->Connect(NpadControllerType::ProController);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
397
app/src/main/cpp/skyline/input/npad.h
Normal file
397
app/src/main/cpp/skyline/input/npad.h
Normal file
@ -0,0 +1,397 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared_mem.h"
|
||||
|
||||
namespace skyline {
|
||||
namespace constant {
|
||||
constexpr u32 NpadBatteryFull = 2; //!< The full battery state of an npad
|
||||
constexpr u8 NpadCount = 10; //!< The number of npads in shared memory
|
||||
}
|
||||
|
||||
namespace input::npad {
|
||||
union NpadButton {
|
||||
struct {
|
||||
bool a : 1; //!< The A button
|
||||
bool b : 1; //!< The B button
|
||||
bool x : 1; //!< The X button
|
||||
bool y : 1; //!< The Y button
|
||||
bool l3 : 1; //!< The L3 button
|
||||
bool r3 : 1; //!< The R3 button
|
||||
bool l : 1; //!< The L trigger
|
||||
bool r : 1; //!< The R button
|
||||
bool zl : 1; //!< The ZL trigger
|
||||
bool zr : 1; //!< The ZR trigger
|
||||
bool plus : 1; //!< The + button
|
||||
bool minus : 1; //!< The - button
|
||||
bool dpadLeft : 1; //!< D-Pad left
|
||||
bool dpadUp : 1; //!< D-Pad up
|
||||
bool dpadRight : 1; //!< D-Pad right
|
||||
bool dpadDown : 1; //!< D-Pad down
|
||||
bool leftStickLeft : 1; //!< Left stick left
|
||||
bool leftStickUp : 1; //!< Left stick up
|
||||
bool leftStickRight : 1; //!< Left stick right
|
||||
bool leftStickDown : 1; //!< Left stick down
|
||||
bool rightStickLeft : 1; //!< Right stick left
|
||||
bool rightStickUp : 1; //!< Right stick up
|
||||
bool rightStickRight : 1; //!< Right stick right
|
||||
bool rightStickDown : 1; //!< Right stick down
|
||||
bool leftSL : 1; //!< Left Joy-Con SL button
|
||||
bool leftSr : 1; //!< Left Joy-Con SR button
|
||||
bool rightSl : 1; //!< Right Joy-Con SL button
|
||||
bool rightSr : 1; //!< Right Joy-Con SR button
|
||||
bool touch : 1; //!< The touch button
|
||||
};
|
||||
u64 raw;
|
||||
};
|
||||
static_assert(sizeof(NpadButton) == 0x8);
|
||||
|
||||
enum class NpadAxisId {
|
||||
RX, //!< Right stick X
|
||||
RY, //!< Right stick Y
|
||||
LX, //!< Left stick X
|
||||
LY //!< Left stick Y
|
||||
};
|
||||
|
||||
enum class NpadButtonState : bool {
|
||||
Released = false, //!< Released button
|
||||
Pressed = true //!< Pressed button
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This holds the controller styles supported
|
||||
*/
|
||||
union NpadStyleSet {
|
||||
struct {
|
||||
bool proController : 1; //!< The Pro Controller
|
||||
bool joyconHandheld : 1; //!< Joy-Cons in handheld mode
|
||||
bool joyconDual : 1; //!< Joy-Cons in a pair
|
||||
bool joyconLeft : 1; //!< Left Joy-Con only
|
||||
bool joyconRight : 1; //!< Right Joy-Con only
|
||||
bool gamecube : 1; //!< GameCube controller
|
||||
bool palma : 1; //!< Poké Ball Plus controller
|
||||
bool nes : 1; //!< NES controller
|
||||
bool nesHandheld : 1; //!< NES controller in handheld mode
|
||||
bool snes : 1; //!< SNES controller
|
||||
};
|
||||
u32 raw;
|
||||
};
|
||||
static_assert(sizeof(NpadStyleSet) == 0x4);
|
||||
|
||||
/**
|
||||
* @brief This holds a Controller's ID (https://switchbrew.org/wiki/HID_services#NpadIdType)
|
||||
*/
|
||||
enum class NpadId : u32 {
|
||||
Player1 = 0x0, //!< 1st Player
|
||||
Player2 = 0x1, //!< 2nd Player
|
||||
Player3 = 0x2, //!< 3rd Player
|
||||
Player4 = 0x3, //!< 4th Player
|
||||
Player5 = 0x4, //!< 5th Player
|
||||
Player6 = 0x5, //!< 6th Player
|
||||
Player7 = 0x6, //!< 7th Player
|
||||
Player8 = 0x7, //!< 8th Player
|
||||
Unknown = 0x10, //!< Unknown
|
||||
Handheld = 0x20 //!< Handheld mode
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This denotes the orientation of the Joy-Con(s)
|
||||
*/
|
||||
enum class NpadJoyOrientation : u64 {
|
||||
Vertical = 0, //!< The Joy-Con is held vertically
|
||||
Horizontal = 1, //!< The Joy-Con is held horizontally
|
||||
Unset = 2 //!< Not set
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This denotes the assignment of the Joy-Con(s)
|
||||
*/
|
||||
enum class NpadJoyAssignment : u32 {
|
||||
Dual = 0, //!< Dual Joy-Cons
|
||||
Single = 1, //!< Single Joy-Con
|
||||
Unset = 2 //!< Not set
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This denotes the colour read status of an npad
|
||||
*/
|
||||
enum class NpadColourReadStatus : u32 {
|
||||
Success = 0, //!< Success
|
||||
Invalid = 1, //!< Invalid color
|
||||
Disconnected = 2 //!< Controller not connected
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This denotes the type of an npad
|
||||
*/
|
||||
enum class NpadControllerType {
|
||||
None, //!< Nothing
|
||||
ProController, //!< A Pro Controller
|
||||
Handheld, //!< Handheld mode
|
||||
JoyconDual, //!< Dual Joy-Cons
|
||||
JoyconLeft, //!< Left Joy-Con
|
||||
JoyconRight, //!< Right Joy-Con
|
||||
Palma, //!< Poké Ball Plus
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This denotes the connection state of an npad
|
||||
*/
|
||||
union NpadConnectionState {
|
||||
struct {
|
||||
bool connected : 1; //!< Is connected
|
||||
bool handheld : 1; //!< Is in handheld mode
|
||||
bool leftJoyconConnected : 1; //!< Is the left Joy-Con connected
|
||||
bool leftJoyconHandheld : 1; //!< Is the left Joy-Con handheld
|
||||
bool rightJoyconConnected : 1; //!< Is the right Joy-Con connected
|
||||
bool rightJoyconHandheld : 1; //!< Is the right Joy-Con handheld
|
||||
};
|
||||
u64 raw;
|
||||
};
|
||||
static_assert(sizeof(NpadConnectionState) == 0x8);
|
||||
|
||||
/**
|
||||
* @brief This denotes the device type of an npad
|
||||
*/
|
||||
union NpadDeviceType {
|
||||
struct {
|
||||
bool fullKey : 1; //!< Pro/GC controller
|
||||
bool handheld : 1; //!< Handheld mode
|
||||
bool handheldLeft : 1; //!< Joy-Con/Famicom/NES left controller
|
||||
bool handheldRight : 1; //!< Joy-Con/Famicom/NES right controller
|
||||
bool joyconLeft : 1; //!< Left Joy-Con
|
||||
bool joyconRight : 1; //!< Right Joy-Con
|
||||
bool palma : 1; //!< Pokeball Plus controller
|
||||
bool larkLeftFamicom : 1; //!< Famicom left Joy-Con
|
||||
bool larkRightFamicom : 1;//!< Famicom right Joy-Con
|
||||
bool larkLeftNES : 1; //!< NES left Joy-Con
|
||||
bool larkRightNES : 1; //!< NES right Joy-Con
|
||||
u32 _unk1_ : 4;
|
||||
bool systemExt : 1; //!< Generic external controller
|
||||
u32 _unk2_ : 14;
|
||||
bool system : 1; //!< Generic controller
|
||||
};
|
||||
u32 raw;
|
||||
};
|
||||
static_assert(sizeof(NpadDeviceType) == 0x4);
|
||||
|
||||
/**
|
||||
* @brief This denotes the system properties of the npad
|
||||
*/
|
||||
union NpadSystemProperties {
|
||||
struct {
|
||||
bool powerInfo0Charging : 1; //!< Info 0 Charging
|
||||
bool powerInfo1Charging : 1; //!< Info 1 Charging
|
||||
bool powerInfo2Charging : 1; //!< Info 2 Charging
|
||||
bool powerInfo0PowerConnected : 1; //!< Info 0 Connected
|
||||
bool powerInfo1PowerConnected : 1; //!< Info 1 Connected
|
||||
bool powerInfo2PowerConnected : 1; //!< Info 2 Connected
|
||||
u64 _unk_ : 3;
|
||||
bool unsupportedButtonPressedSystem : 1; //!< Unsupported buttons are pressed on system controller
|
||||
bool unsupportedButtonPressedSystemExt : 1; //!< Unsupported buttons are pressed on system external controller
|
||||
bool ABXYButtonOriented : 1; //!< Are the ABXY Buttons oriented
|
||||
bool SLSRuttonOriented : 1; //!< Are the SLSR Buttons oriented
|
||||
bool plusButtonCapability : 1; //!< Does the + button exist
|
||||
bool minusButtonCapability : 1; //!< Does the - button exist
|
||||
bool directionalButtonsSupported : 1; //!< Does the controller have a D-Pad
|
||||
};
|
||||
u64 raw;
|
||||
};
|
||||
static_assert(sizeof(NpadSystemProperties) == 0x8);
|
||||
|
||||
/**
|
||||
* @brief This denotes the system button properties of the npad
|
||||
*/
|
||||
union NpadSystemButtonProperties {
|
||||
struct {
|
||||
bool unintendedHomeButtonInputProtectionEnabled : 1; //!< Is unintended home button input protection enabled
|
||||
};
|
||||
u32 raw;
|
||||
};
|
||||
static_assert(sizeof(NpadSystemButtonProperties) == 0x4);
|
||||
|
||||
/**
|
||||
* @brief This denotes the colour of an npad
|
||||
*/
|
||||
struct NpadColour {
|
||||
u32 bodyColour; //!< The body colour
|
||||
u32 buttonColour; //!< The button colour
|
||||
};
|
||||
static_assert(sizeof(NpadColour) == 0x8);
|
||||
|
||||
/**
|
||||
* @brief This is the header of an npad entry
|
||||
*/
|
||||
struct NpadHeader {
|
||||
NpadStyleSet styles; //!< The style set
|
||||
NpadJoyAssignment assignment; //!< The pad assignment
|
||||
|
||||
NpadColourReadStatus singleColourStatus; //!< The single colour status
|
||||
NpadColour singleColour; //!< The colours
|
||||
|
||||
NpadColourReadStatus dualColourStatus; //!< The dual colour status
|
||||
NpadColour rightColour; //!< The right colours
|
||||
NpadColour leftColour; //!< The left colours
|
||||
};
|
||||
static_assert(sizeof(NpadHeader) == 0x28);
|
||||
|
||||
/**
|
||||
* @brief This contains controller input data
|
||||
*/
|
||||
struct NpadController {
|
||||
NpadButton buttons; //!< The pressed buttons
|
||||
|
||||
u32 leftX; //!< The left stick X
|
||||
u32 leftY; //!< The left stick Y
|
||||
|
||||
u32 rightX; //!< The right stick X
|
||||
u32 rightY; //!< The right stick Y
|
||||
};
|
||||
static_assert(sizeof(NpadController) == 0x18);
|
||||
|
||||
/**
|
||||
* @brief This contains info about controller input data
|
||||
*/
|
||||
struct NpadControllerState {
|
||||
u64 globalTimestamp; //!< The global timestamp
|
||||
u64 localTimestamp; //!< The local timestamp
|
||||
NpadController controller; //!< The npad controller
|
||||
NpadConnectionState status; //!< The npad connection status
|
||||
};
|
||||
static_assert(sizeof(NpadControllerState) == 0x30);
|
||||
|
||||
/**
|
||||
* @brief This contains all the input states
|
||||
*/
|
||||
struct NpadControllerInfo {
|
||||
CommonHeader header; //!< The common data header
|
||||
std::array<NpadControllerState, 17> state; //!< The npad state
|
||||
};
|
||||
static_assert(sizeof(NpadControllerInfo) == 0x350);
|
||||
|
||||
/**
|
||||
* @brief An npad section in shared memory
|
||||
*/
|
||||
struct NpadSection {
|
||||
NpadHeader header; //!< The npad header
|
||||
|
||||
NpadControllerInfo fullKeyController; //!< The full key controller
|
||||
NpadControllerInfo handheldController; //!< The handheld controller
|
||||
NpadControllerInfo dualController; //!< The dual Joy-Con controller
|
||||
NpadControllerInfo leftController; //!< The left Joy-Con controller
|
||||
NpadControllerInfo rightController; //!< The right Joy-Con controller
|
||||
NpadControllerInfo pokeballController; //!< The Pokeball Plus controller
|
||||
NpadControllerInfo systemExtController; //!< The system external controller
|
||||
|
||||
u64 _unk_[0xE1 * 6]; //!< Unused sixaxis data
|
||||
|
||||
NpadDeviceType deviceType; //!< The device type
|
||||
|
||||
u32 _pad0_;
|
||||
|
||||
NpadSystemProperties properties; //!< The system properties
|
||||
NpadSystemButtonProperties buttonProperties; //!< The button properties
|
||||
|
||||
u32 batteryLevel[3]; //!< The battery level reported
|
||||
|
||||
u32 _pad1_[0x395];
|
||||
};
|
||||
static_assert(sizeof(NpadSection) == 0x5000);
|
||||
|
||||
/**
|
||||
* @brief Converts the ID of an npad to the index in shared memory
|
||||
* @param id The ID of an npad
|
||||
* @return The index in shared memory
|
||||
*/
|
||||
u32 NpadIdToIndex(NpadId id);
|
||||
|
||||
/**
|
||||
* @brief Converts the index in shared memory to the ID of an npad
|
||||
* @param id The index in shared memory
|
||||
* @return The ID of the npad
|
||||
*/
|
||||
NpadId IndexToNpadId(u32 index);
|
||||
|
||||
class NpadDevice {
|
||||
private:
|
||||
NpadId id; //!< The ID of the npad
|
||||
NpadControllerType controllerType{NpadControllerType::None}; //!< The type of controller
|
||||
uint stateEntryIndex{}; //!< The index of the current state entry
|
||||
|
||||
NpadConnectionState connectionState{}; //!< The state of the connection
|
||||
NpadSection &shmemSection; //!< The section in HID shared memory for this controller
|
||||
|
||||
/**
|
||||
* @brief Updates headers for a new shared memory entry
|
||||
* @param controller The controller to operate on
|
||||
* @param lastStateEntryIndex The index of the previous state entry
|
||||
*/
|
||||
void UpdateHeaders(NpadControllerInfo &controller, uint lastStateEntryIndex);
|
||||
|
||||
/**
|
||||
* @return The controller device info appropriate for the controllers type
|
||||
*/
|
||||
NpadControllerInfo &GetControllerDeviceInfo();
|
||||
|
||||
public:
|
||||
bool supported{false}; //!< If the npad marked as supported
|
||||
|
||||
/**
|
||||
* @param shmemSection A reference to the controllers shared memory region
|
||||
* @param id The ID of the npad
|
||||
*/
|
||||
NpadDevice(NpadSection &shmemSection, NpadId id);
|
||||
|
||||
/**
|
||||
* @brief Sets the joycon assignment in shared memory
|
||||
* @param assignment The assignment to set
|
||||
*/
|
||||
inline void SetAssignment(NpadJoyAssignment assignment) {
|
||||
shmemSection.header.assignment = assignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connects a controller to the guest
|
||||
* @param type The type of controller to connect
|
||||
*/
|
||||
void Connect(NpadControllerType type);
|
||||
|
||||
/**
|
||||
* @brief Disconnects the controller from the guest
|
||||
*/
|
||||
void Disconnect();
|
||||
|
||||
/**
|
||||
* @brief Changes a button's state on the virtual controller
|
||||
* @param button The button work on
|
||||
* @param state Whether to release or press the button
|
||||
*/
|
||||
void SetButtonState(NpadButton button, NpadButtonState state);
|
||||
|
||||
/**
|
||||
* @brief Sets an axis to a value on the virtual controller
|
||||
* @param axis The axis to change
|
||||
* @param value The value to use
|
||||
*/
|
||||
void SetAxisValue(NpadAxisId axis, int value);
|
||||
};
|
||||
|
||||
class CommonNpad {
|
||||
private:
|
||||
const DeviceState &state; //!< The state of the device
|
||||
|
||||
public:
|
||||
NpadStyleSet supportedStyles{}; //!< The supported style sets
|
||||
NpadJoyOrientation orientation{NpadJoyOrientation::Unset}; //!< The Joy-Con orientation to use
|
||||
|
||||
CommonNpad(const DeviceState &state);
|
||||
|
||||
/**
|
||||
* @brief Activates npad support
|
||||
*/
|
||||
void Activate();
|
||||
};
|
||||
}
|
||||
}
|
216
app/src/main/cpp/skyline/input/shared_mem.h
Normal file
216
app/src/main/cpp/skyline/input/shared_mem.h
Normal file
@ -0,0 +1,216 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <common.h>
|
||||
|
||||
namespace skyline {
|
||||
namespace constant {
|
||||
constexpr u8 HidEntryCount = 17; //!< The amount of state entries in each hid device
|
||||
}
|
||||
|
||||
namespace input {
|
||||
struct CommonHeader {
|
||||
u64 timestamp;
|
||||
u64 entryCount;
|
||||
u64 currentEntry;
|
||||
u64 maxEntry;
|
||||
};
|
||||
static_assert(sizeof(CommonHeader) == 0x20);
|
||||
|
||||
|
||||
|
||||
struct DebugPadState {
|
||||
u64 timestamp;
|
||||
u8 _unk_[0x20];
|
||||
};
|
||||
static_assert(sizeof(DebugPadState) == 0x28);
|
||||
|
||||
struct DebugPadSection {
|
||||
CommonHeader header;
|
||||
std::array<DebugPadState, constant::HidEntryCount> state;
|
||||
u64 _pad_[0x27];
|
||||
};
|
||||
static_assert(sizeof(DebugPadSection) == 0x400);
|
||||
|
||||
|
||||
|
||||
struct TouchScreenStateData {
|
||||
u64 timestamp;
|
||||
u32 _pad0_;
|
||||
|
||||
u32 index;
|
||||
|
||||
u32 positionX;
|
||||
u32 positionY;
|
||||
|
||||
u32 diameterX;
|
||||
u32 diameterY;
|
||||
|
||||
u32 angle;
|
||||
u32 _pad1_;
|
||||
};
|
||||
static_assert(sizeof(TouchScreenStateData) == 0x28);
|
||||
|
||||
struct TouchScreenState {
|
||||
u64 globalTimestamp;
|
||||
u64 localTimestamp;
|
||||
|
||||
u64 touchCount;
|
||||
std::array<TouchScreenStateData, 16> data;
|
||||
};
|
||||
static_assert(sizeof(TouchScreenState) == 0x298);
|
||||
|
||||
struct TouchScreenSection {
|
||||
CommonHeader header;
|
||||
std::array<TouchScreenState, constant::HidEntryCount> state;
|
||||
u64 _pad_[0x79];
|
||||
|
||||
};
|
||||
static_assert(sizeof(TouchScreenSection) == 0x3000);
|
||||
|
||||
|
||||
|
||||
struct MouseState {
|
||||
u64 globalTimestamp;
|
||||
u64 localTimestamp;
|
||||
|
||||
u32 positionX;
|
||||
u32 positionY;
|
||||
|
||||
u32 changeX;
|
||||
u32 changeY;
|
||||
|
||||
u32 scrollChangeY;
|
||||
u32 scrollChangeX;
|
||||
|
||||
u64 buttons;
|
||||
};
|
||||
static_assert(sizeof(MouseState) == 0x30);
|
||||
|
||||
struct MouseSection {
|
||||
CommonHeader header;
|
||||
std::array<MouseState, constant::HidEntryCount> state;
|
||||
u64 _pad_[22];
|
||||
};
|
||||
static_assert(sizeof(MouseSection) == 0x400);
|
||||
|
||||
|
||||
|
||||
struct KeyboardState {
|
||||
u64 globalTimestamp;
|
||||
u64 localTimestamp;
|
||||
|
||||
u64 modifers;
|
||||
u64 keysDown[4];
|
||||
};
|
||||
static_assert(sizeof(KeyboardState) == 0x38);
|
||||
|
||||
struct KeyboardSection {
|
||||
CommonHeader header;
|
||||
std::array<KeyboardState, constant::HidEntryCount> state;
|
||||
u64 _pad_[5];
|
||||
};
|
||||
static_assert(sizeof(KeyboardSection) == 0x400);
|
||||
|
||||
|
||||
|
||||
struct BasicXpadState {
|
||||
u64 globalTimestamp;
|
||||
u64 _unk_[4];
|
||||
};
|
||||
static_assert(sizeof(BasicXpadState) == 0x28);
|
||||
|
||||
struct BasicXpadSection {
|
||||
CommonHeader header;
|
||||
std::array<BasicXpadState, constant::HidEntryCount> state;
|
||||
u64 _pad_[39];
|
||||
};
|
||||
static_assert(sizeof(BasicXpadSection) == 0x400);
|
||||
|
||||
|
||||
|
||||
struct HomeButtonState {
|
||||
u64 globalTimestamp;
|
||||
u64 _unk_[2];
|
||||
};
|
||||
static_assert(sizeof(HomeButtonState) == 0x18);
|
||||
|
||||
struct HomeButtonSection {
|
||||
CommonHeader header;
|
||||
std::array<HomeButtonState, constant::HidEntryCount> state;
|
||||
u64 _pad_[9];
|
||||
};
|
||||
static_assert(sizeof(HomeButtonSection) == 0x200);
|
||||
|
||||
|
||||
|
||||
struct SleepButtonState {
|
||||
u64 globalTimestamp;
|
||||
u64 _unk_[2];
|
||||
};
|
||||
static_assert(sizeof(SleepButtonState) == 0x18);
|
||||
|
||||
struct SleepButtonSection {
|
||||
CommonHeader header;
|
||||
std::array<SleepButtonState, constant::HidEntryCount> state;
|
||||
u64 _pad_[9];
|
||||
};
|
||||
static_assert(sizeof(SleepButtonSection) == 0x200);
|
||||
|
||||
|
||||
|
||||
struct CaptureButtonState {
|
||||
u64 globalTimestamp;
|
||||
u64 _unk_[2];
|
||||
};
|
||||
static_assert(sizeof(CaptureButtonState) == 0x18);
|
||||
|
||||
struct CaptureButtonSection {
|
||||
CommonHeader header;
|
||||
std::array<CaptureButtonState, constant::HidEntryCount> state;
|
||||
u64 _pad_[9];
|
||||
};
|
||||
static_assert(sizeof(CaptureButtonSection) == 0x200);
|
||||
|
||||
|
||||
struct InputDetectorState {
|
||||
u64 globalTimestamp;
|
||||
u64 _unk_[2];
|
||||
};
|
||||
static_assert(sizeof(InputDetectorState) == 0x18);
|
||||
|
||||
struct InputDetectorSection {
|
||||
CommonHeader header;
|
||||
std::array<InputDetectorState, 2> state;
|
||||
u64 _pad_[6];
|
||||
};
|
||||
static_assert(sizeof(InputDetectorSection) == 0x80);
|
||||
|
||||
|
||||
struct GestureState {
|
||||
u64 globalTimestamp;
|
||||
u64 _unk_[12];
|
||||
};
|
||||
static_assert(sizeof(GestureState) == 0x68);
|
||||
|
||||
struct GestureSection {
|
||||
CommonHeader header;
|
||||
std::array<GestureState, constant::HidEntryCount> state;
|
||||
u64 _pad_[31];
|
||||
};
|
||||
static_assert(sizeof(GestureSection) == 0x800);
|
||||
|
||||
struct ConsoleSixAxisSensorSection {
|
||||
u64 timestamp;
|
||||
bool resting : 1;
|
||||
u32 _pad0_ : 3;
|
||||
u32 verticalizationError;
|
||||
u32 gyroBias[3];
|
||||
u32 _pad1_;
|
||||
};
|
||||
static_assert(sizeof(ConsoleSixAxisSensorSection) == 0x20);
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common.h>
|
||||
#include "common.h"
|
||||
#include <jni.h>
|
||||
|
||||
namespace skyline {
|
||||
|
@ -18,10 +18,8 @@ namespace skyline::kernel {
|
||||
* @brief The OS class manages the interaction between Skyline components and the underlying OS in NCE
|
||||
*/
|
||||
class OS {
|
||||
private:
|
||||
DeviceState state; //!< The state of the device
|
||||
|
||||
public:
|
||||
DeviceState state; //!< The state of the device
|
||||
std::shared_ptr<type::KProcess> process; //!< The KProcess object for the emulator, representing the guest process
|
||||
service::ServiceManager serviceManager; //!< This manages all of the service functions
|
||||
MemoryManager memory; //!< The MemoryManager object for this process
|
||||
|
@ -1,8 +1,11 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <input.h>
|
||||
#include "IHidServer.h"
|
||||
|
||||
using namespace skyline::input;
|
||||
|
||||
namespace skyline::service::hid {
|
||||
IHidServer::IHidServer(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, Service::hid_IHidServer, "hid:IHidServer", {
|
||||
{0x0, SFUNC(IHidServer::CreateAppletResource)},
|
||||
@ -13,50 +16,53 @@ namespace skyline::service::hid {
|
||||
{0x7A, SFUNC(IHidServer::SetNpadJoyAssignmentModeSingleByDefault)},
|
||||
{0x7B, SFUNC(IHidServer::SetNpadJoyAssignmentModeSingle)},
|
||||
{0x7C, SFUNC(IHidServer::SetNpadJoyAssignmentModeDual)}
|
||||
}) {}
|
||||
}) {
|
||||
state.input->commonNpad->Activate();
|
||||
}
|
||||
|
||||
void IHidServer::CreateAppletResource(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
resource = std::make_shared<IAppletResource>(state, manager);
|
||||
manager.RegisterService(resource, session, response);
|
||||
manager.RegisterService(SRVREG(IAppletResource), session, response);
|
||||
}
|
||||
|
||||
void IHidServer::SetSupportedNpadStyleSet(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto styleSet = request.Pop<StyleSet>();
|
||||
auto styleSet = request.Pop<npad::NpadStyleSet>();
|
||||
|
||||
state.logger->Debug("Controller Support:\nPro-Controller: {}\nJoy-Con: Handheld: {}, Dual: {}, L: {}, R: {}\nGameCube: {}\nPokeBall: {}\nNES: {}, NES Handheld: {}, SNES: {}", static_cast<bool>(styleSet.proController), static_cast<bool>(styleSet.joyconHandheld), static_cast<bool>(styleSet.joyconDual), static_cast<bool>(styleSet.joyconLeft), static_cast<bool>
|
||||
(styleSet.joyconRight), static_cast<bool>(styleSet.gamecube), static_cast<bool>(styleSet.pokeball), static_cast<bool>(styleSet.nes), static_cast<bool>(styleSet.nesHandheld), static_cast<bool>(styleSet.snes));
|
||||
(styleSet.joyconRight), static_cast<bool>(styleSet.gamecube), static_cast<bool>(styleSet.palma), static_cast<bool>(styleSet.nes), static_cast<bool>(styleSet.nesHandheld), static_cast<bool>(styleSet.snes));
|
||||
}
|
||||
|
||||
void IHidServer::SetSupportedNpadIdType(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
const auto &buffer = request.inputBuf.at(0);
|
||||
size_t numId = buffer.size / sizeof(NpadId);
|
||||
size_t numId = buffer.size / sizeof(npad::NpadId);
|
||||
u64 address = buffer.address;
|
||||
|
||||
for (size_t i = 0; i < numId; i++) {
|
||||
auto id = state.process->GetObject<NpadId>(address);
|
||||
deviceMap[id] = JoyConDevice(id);
|
||||
address += sizeof(NpadId);
|
||||
auto id = state.process->GetObject<npad::NpadId>(address);
|
||||
state.input->npad.at(NpadIdToIndex(id))->supported = true;
|
||||
|
||||
address += sizeof(npad::NpadId);
|
||||
}
|
||||
}
|
||||
|
||||
void IHidServer::ActivateNpad(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {}
|
||||
|
||||
void IHidServer::SetNpadJoyHoldType(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
deviceMap[request.Pop<NpadId>()].assignment = JoyConAssignment::Single;
|
||||
auto appletResourceUID = request.Pop<u64>();
|
||||
state.input->commonNpad->orientation = request.Pop<npad::NpadJoyOrientation>();
|
||||
}
|
||||
|
||||
void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
orientation = request.Pop<JoyConOrientation>();
|
||||
auto id = request.Pop<npad::NpadId>();
|
||||
state.input->npad.at(npad::NpadIdToIndex(id))->SetAssignment(npad::NpadJoyAssignment::Single);
|
||||
}
|
||||
|
||||
void IHidServer::SetNpadJoyAssignmentModeSingle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
auto controllerId = request.Pop<NpadId>();
|
||||
auto appletUserId = request.Pop<u64>();
|
||||
|
||||
deviceMap[controllerId].assignment = JoyConAssignment::Single;
|
||||
deviceMap[controllerId].side = request.Pop<JoyConSide>();
|
||||
auto id = request.Pop<npad::NpadId>();
|
||||
state.input->npad.at(npad::NpadIdToIndex(id))->SetAssignment(npad::NpadJoyAssignment::Single);
|
||||
}
|
||||
|
||||
void IHidServer::SetNpadJoyAssignmentModeDual(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||
deviceMap[request.Pop<NpadId>()].assignment = JoyConAssignment::Dual;
|
||||
auto id = request.Pop<npad::NpadId>();
|
||||
state.input->npad.at(npad::NpadIdToIndex(id))->SetAssignment(npad::NpadJoyAssignment::Dual);
|
||||
}
|
||||
}
|
||||
|
@ -12,88 +12,6 @@ namespace skyline::service::hid {
|
||||
* @brief IHidServer or hid service is used to access input devices (https://switchbrew.org/wiki/HID_services#hid)
|
||||
*/
|
||||
class IHidServer : public BaseService {
|
||||
private:
|
||||
/**
|
||||
* @brief This holds the controller styles supported by an application
|
||||
*/
|
||||
struct StyleSet {
|
||||
bool proController : 1; //!< The Pro Controller
|
||||
bool joyconHandheld : 1; //!< Joy-Cons in handheld mode
|
||||
bool joyconDual : 1; //!< Joy-Cons in a pair
|
||||
bool joyconLeft : 1; //!< Left Joy-Con only
|
||||
bool joyconRight : 1; //!< Right Joy-Con only
|
||||
bool gamecube : 1; //!< GameCube controller
|
||||
bool pokeball : 1; //!< Poké Ball Plus controller
|
||||
bool nes : 1; //!< NES controller
|
||||
bool nesHandheld : 1; //!< NES controller in handheld mode
|
||||
bool snes : 1; //!< SNES controller
|
||||
u32 _pad0_ : 22;
|
||||
};
|
||||
static_assert(sizeof(StyleSet) == 4);
|
||||
|
||||
/**
|
||||
* @brief This holds a Controller's ID (https://switchbrew.org/wiki/HID_services#NpadIdType)
|
||||
*/
|
||||
enum class NpadId : u32 {
|
||||
Player1 = 0x0, //!< 1st Player
|
||||
Player2 = 0x1, //!< 2nd Player
|
||||
Player3 = 0x2, //!< 3rd Player
|
||||
Player4 = 0x3, //!< 4th Player
|
||||
Player5 = 0x4, //!< 5th Player
|
||||
Player6 = 0x5, //!< 6th Player
|
||||
Player7 = 0x6, //!< 7th Player
|
||||
Player8 = 0x7, //!< 8th Player
|
||||
Unknown = 0x10, //!< Unknown
|
||||
Handheld = 0x20 //!< Handheld mode
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This holds a Controller's Assignment mode
|
||||
*/
|
||||
enum class JoyConAssignment {
|
||||
Dual, //!< Dual Joy-Cons
|
||||
Single, //!< Single Joy-Con
|
||||
Unset //!< Not set
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This holds which Joy-Con to use Single mode (Not if SetNpadJoyAssignmentModeSingleByDefault is used)
|
||||
*/
|
||||
enum class JoyConSide : i64 {
|
||||
Left, //!< Left Joy-Con
|
||||
Right, //!< Right Joy-Con
|
||||
Unset //!< Not set
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This denotes the orientation of the Joy-Con(s)
|
||||
*/
|
||||
enum class JoyConOrientation : u64 {
|
||||
Vertical, //!< The Joy-Con is held vertically
|
||||
Horizontal, //!< The Joy-Con is held horizontally
|
||||
Unset //!< Not set
|
||||
};
|
||||
|
||||
// TODO: Replace JoyConDevice with base NpadDevice class
|
||||
|
||||
/**
|
||||
* @brief This holds the state of a single Npad device
|
||||
*/
|
||||
struct JoyConDevice {
|
||||
NpadId id; //!< The ID of this device
|
||||
JoyConAssignment assignment{JoyConAssignment::Unset}; //!< The assignment mode of this device
|
||||
JoyConSide side{JoyConSide::Unset}; //!< The type of the device
|
||||
|
||||
JoyConDevice() : id(NpadId::Unknown) {}
|
||||
|
||||
JoyConDevice(const NpadId &id) : id(id) {}
|
||||
};
|
||||
|
||||
std::shared_ptr<IAppletResource> resource{}; //!< A shared pointer to the applet resource
|
||||
std::optional<StyleSet> styleSet; //!< The controller styles supported by the application
|
||||
std::unordered_map<NpadId, JoyConDevice> deviceMap; //!< Mapping from a controller's ID to it's corresponding JoyConDevice
|
||||
JoyConOrientation orientation{JoyConOrientation::Unset}; //!< The Orientation of the Joy-Con(s)
|
||||
|
||||
public:
|
||||
IHidServer(const DeviceState &state, ServiceManager &manager);
|
||||
|
||||
|
@ -84,6 +84,10 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
||||
*/
|
||||
private external fun getFrametime() : Float
|
||||
|
||||
private external fun setButtonState(id : Long, state : Int)
|
||||
|
||||
private external fun setAxisValue(id : Int, value : Int)
|
||||
|
||||
/**
|
||||
* This executes the specified ROM, [preferenceFd] is assumed to be valid beforehand
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user