diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 00000000..e34606cc
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index 8b1e4852..02edf8ee 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -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
diff --git a/app/src/main/cpp/emu_jni.cpp b/app/src/main/cpp/emu_jni.cpp
index 84b9b07c..7fa83958 100644
--- a/app/src/main/cpp/emu_jni.cpp
+++ b/app/src/main/cpp/emu_jni.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(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(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(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(id)};
+ input->npad[0]->SetButtonState(button, static_cast(state));
+}
+
+extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setAxisValue(JNIEnv *, jobject, jint id, jint value) {
+ input->npad[0]->SetAxisValue(static_cast(id), value);
+}
diff --git a/app/src/main/cpp/skyline/audio.h b/app/src/main/cpp/skyline/audio.h
index 1dfa6dce..711302e7 100644
--- a/app/src/main/cpp/skyline/audio.h
+++ b/app/src/main/cpp/skyline/audio.h
@@ -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 OpenTrack(u8 channelCount, u32 sampleRate, const std::function &releaseCallback);
+ std::shared_ptr OpenTrack(u8 channelCount, u32 sampleRate, const std::function &releaseCallback);
/**
* @brief Closes a track and frees its data
* @param track The track to close
*/
- void CloseTrack(std::shared_ptr &track);
+ void CloseTrack(std::shared_ptr &track);
/**
* @brief The callback oboe uses to get audio sample data
diff --git a/app/src/main/cpp/skyline/common.cpp b/app/src/main/cpp/skyline/common.cpp
index 461cf417..299a31fd 100644
--- a/app/src/main/cpp/skyline/common.cpp
+++ b/app/src/main/cpp/skyline/common.cpp
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
+#include
#include "common.h"
#include "nce.h"
#include "gpu.h"
#include "audio.h"
-#include
-#include
+#include "input.h"
+#include "kernel/types/KThread.h"
namespace skyline {
void Mutex::lock() {
@@ -154,6 +155,7 @@ namespace skyline {
nce = std::make_shared(*this);
gpu = std::make_shared(*this);
audio = std::make_shared(*this);
+ input = std::make_shared(*this);
}
thread_local std::shared_ptr DeviceState::thread = nullptr;
diff --git a/app/src/main/cpp/skyline/common.h b/app/src/main/cpp/skyline/common.h
index b4b7e809..e93881e2 100644
--- a/app/src/main/cpp/skyline/common.h
+++ b/app/src/main/cpp/skyline/common.h
@@ -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; //!< This holds a reference to the NCE class
std::shared_ptr gpu; //!< This holds a reference to the GPU class
std::shared_ptr audio; //!< This holds a reference to the Audio class
+ std::shared_ptr input; //!< This holds a reference to the Input class
std::shared_ptr loader; //!< This holds a reference to the Loader class
std::shared_ptr jvm; //!< This holds a reference to the JvmManager class
std::shared_ptr settings; //!< This holds a reference to the Settings class
diff --git a/app/src/main/cpp/skyline/input.cpp b/app/src/main/cpp/skyline/input.cpp
new file mode 100644
index 00000000..d0d36d21
--- /dev/null
+++ b/app/src/main/cpp/skyline/input.cpp
@@ -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(state)), hidKMem(std::make_shared(state, NULL, sizeof(HidSharedMemory), memory::Permission(true, false, false))) {
+ hidMem = reinterpret_cast(hidKMem->kernel.address);
+
+ for (uint i = 0; i < constant::NpadCount; i++) {
+ npad.at(i) = std::make_shared(hidMem->npad.at(i), npad::IndexToNpadId(i));
+ }
+ }
+}
diff --git a/app/src/main/cpp/skyline/input.h b/app/src/main/cpp/skyline/input.h
new file mode 100644
index 00000000..349c709d
--- /dev/null
+++ b/app/src/main/cpp/skyline/input.h
@@ -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 commonNpad; //!< The common npad device
+ std::array, constant::NpadCount> npad; //!< Array of npad devices
+
+ std::shared_ptr hidKMem; //!< The shared memory reserved for HID input
+ HidSharedMemory *hidMem; //!< A pointer to the root of HID shared memory
+ };
+}
diff --git a/app/src/main/cpp/skyline/input/common.h b/app/src/main/cpp/skyline/input/common.h
new file mode 100644
index 00000000..acc91620
--- /dev/null
+++ b/app/src/main/cpp/skyline/input/common.h
@@ -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 xpad; //!< The xpads section
+ HomeButtonSection homeButton; //!< The home button section
+ SleepButtonSection sleepButton; //!< The sleep button section
+ CaptureButtonSection captureButton; //!< The capture button section
+ std::array inputDetector; //!< The input detectors section
+ u64 _pad0_[0x80 * 0x10]; //!< Unique pad (<5.0.0)
+ std::array npad; //!< The npads section
+ GestureSection gesture; //!< The gesture section
+ ConsoleSixAxisSensorSection consoleSixAxisSensor; //!< The gyro/accel section
+ u64 _pad1_[0x7BC];
+ };
+ static_assert(sizeof(HidSharedMemory) == 0x40000);
+}
diff --git a/app/src/main/cpp/skyline/input/npad.cpp b/app/src/main/cpp/skyline/input/npad.cpp
new file mode 100644
index 00000000..2d69cd74
--- /dev/null
+++ b/app/src/main/cpp/skyline/input/npad.cpp
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: MPL-2.0
+// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
+
+#include
+#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(id);
+ }
+ }
+
+ NpadId IndexToNpadId(u32 index) {
+ switch (index) {
+ case 8:
+ return NpadId::Unknown;
+ case 9:
+ return NpadId::Handheld;
+ default:
+ return static_cast(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(&controller.state.at(stateEntryIndex)), reinterpret_cast(&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);
+ }
+ }
+ }
+}
diff --git a/app/src/main/cpp/skyline/input/npad.h b/app/src/main/cpp/skyline/input/npad.h
new file mode 100644
index 00000000..d98f01e7
--- /dev/null
+++ b/app/src/main/cpp/skyline/input/npad.h
@@ -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 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();
+ };
+ }
+}
diff --git a/app/src/main/cpp/skyline/input/shared_mem.h b/app/src/main/cpp/skyline/input/shared_mem.h
new file mode 100644
index 00000000..ceab690f
--- /dev/null
+++ b/app/src/main/cpp/skyline/input/shared_mem.h
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: MPL-2.0
+// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
+
+#pragma once
+
+#include
+#include
+
+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 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 data;
+ };
+ static_assert(sizeof(TouchScreenState) == 0x298);
+
+ struct TouchScreenSection {
+ CommonHeader header;
+ std::array 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 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 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 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 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 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 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 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 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);
+ }
+}
diff --git a/app/src/main/cpp/skyline/jvm.h b/app/src/main/cpp/skyline/jvm.h
index e4c06ef8..52dcaae1 100644
--- a/app/src/main/cpp/skyline/jvm.h
+++ b/app/src/main/cpp/skyline/jvm.h
@@ -3,7 +3,7 @@
#pragma once
-#include
+#include "common.h"
#include
namespace skyline {
diff --git a/app/src/main/cpp/skyline/os.h b/app/src/main/cpp/skyline/os.h
index 9f937864..6a7ff8d6 100644
--- a/app/src/main/cpp/skyline/os.h
+++ b/app/src/main/cpp/skyline/os.h
@@ -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 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
diff --git a/app/src/main/cpp/skyline/services/hid/IHidServer.cpp b/app/src/main/cpp/skyline/services/hid/IHidServer.cpp
index fcb4d0b9..26b47198 100644
--- a/app/src/main/cpp/skyline/services/hid/IHidServer.cpp
+++ b/app/src/main/cpp/skyline/services/hid/IHidServer.cpp
@@ -1,8 +1,11 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
+#include
#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(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();
+ auto styleSet = request.Pop();
+
state.logger->Debug("Controller Support:\nPro-Controller: {}\nJoy-Con: Handheld: {}, Dual: {}, L: {}, R: {}\nGameCube: {}\nPokeBall: {}\nNES: {}, NES Handheld: {}, SNES: {}", static_cast(styleSet.proController), static_cast(styleSet.joyconHandheld), static_cast(styleSet.joyconDual), static_cast(styleSet.joyconLeft), static_cast
- (styleSet.joyconRight), static_cast(styleSet.gamecube), static_cast(styleSet.pokeball), static_cast(styleSet.nes), static_cast(styleSet.nesHandheld), static_cast(styleSet.snes));
+ (styleSet.joyconRight), static_cast(styleSet.gamecube), static_cast(styleSet.palma), static_cast(styleSet.nes), static_cast(styleSet.nesHandheld), static_cast(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(address);
- deviceMap[id] = JoyConDevice(id);
- address += sizeof(NpadId);
+ auto id = state.process->GetObject(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()].assignment = JoyConAssignment::Single;
+ auto appletResourceUID = request.Pop();
+ state.input->commonNpad->orientation = request.Pop();
}
void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
- orientation = request.Pop();
+ auto id = request.Pop();
+ 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();
- auto appletUserId = request.Pop();
-
- deviceMap[controllerId].assignment = JoyConAssignment::Single;
- deviceMap[controllerId].side = request.Pop();
+ auto id = request.Pop();
+ 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()].assignment = JoyConAssignment::Dual;
+ auto id = request.Pop();
+ state.input->npad.at(npad::NpadIdToIndex(id))->SetAssignment(npad::NpadJoyAssignment::Dual);
}
}
diff --git a/app/src/main/cpp/skyline/services/hid/IHidServer.h b/app/src/main/cpp/skyline/services/hid/IHidServer.h
index 24529cfc..ae326bc8 100644
--- a/app/src/main/cpp/skyline/services/hid/IHidServer.h
+++ b/app/src/main/cpp/skyline/services/hid/IHidServer.h
@@ -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 resource{}; //!< A shared pointer to the applet resource
- std::optional styleSet; //!< The controller styles supported by the application
- std::unordered_map 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);
diff --git a/app/src/main/java/emu/skyline/EmulationActivity.kt b/app/src/main/java/emu/skyline/EmulationActivity.kt
index d4c03f47..bfb133a0 100644
--- a/app/src/main/java/emu/skyline/EmulationActivity.kt
+++ b/app/src/main/java/emu/skyline/EmulationActivity.kt
@@ -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
*