mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 17:51:52 +01:00
Significantly Improve Accuracy of HID
This commit significantly increases the accuracy of the prior HID code due to testing on the Switch. It is now fully accurate in all supported scenarios, them being assignment mode, orientation, color writes and system properties. In addition, review comments were addressed and fixed in the PR.
This commit is contained in:
parent
ee2fdbdf6a
commit
07c2f2d891
@ -59,7 +59,6 @@
|
|||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:launchMode="singleInstance"
|
android:launchMode="singleInstance"
|
||||||
android:screenOrientation="landscape"
|
android:screenOrientation="landscape"
|
||||||
android:theme="@style/EmuTheme"
|
|
||||||
tools:ignore="LockedOrientationActivity">
|
tools:ignore="LockedOrientationActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
@ -15,7 +15,7 @@ uint FaultCount;
|
|||||||
skyline::GroupMutex JniMtx;
|
skyline::GroupMutex JniMtx;
|
||||||
skyline::u16 fps;
|
skyline::u16 fps;
|
||||||
skyline::u32 frametime;
|
skyline::u32 frametime;
|
||||||
skyline::input::Input *input;
|
std::weak_ptr<skyline::input::Input> inputWeak;
|
||||||
|
|
||||||
void signalHandler(int signal) {
|
void signalHandler(int signal) {
|
||||||
syslog(LOG_ERR, "Halting program due to signal: %s", strsignal(signal));
|
syslog(LOG_ERR, "Halting program due to signal: %s", strsignal(signal));
|
||||||
@ -52,7 +52,7 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
skyline::kernel::OS os(jvmManager, logger, settings, std::string(appFilesPath));
|
skyline::kernel::OS os(jvmManager, logger, settings, std::string(appFilesPath));
|
||||||
input = os.state.input.get();
|
inputWeak = os.state.input;
|
||||||
env->ReleaseStringUTFChars(appFilesPathJstring, appFilesPath);
|
env->ReleaseStringUTFChars(appFilesPathJstring, appFilesPath);
|
||||||
|
|
||||||
auto romUri = env->GetStringUTFChars(romUriJstring, nullptr);
|
auto romUri = env->GetStringUTFChars(romUriJstring, nullptr);
|
||||||
@ -66,6 +66,8 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
|
|||||||
logger->Error("An unknown exception has occurred");
|
logger->Error("An unknown exception has occurred");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inputWeak.reset();
|
||||||
|
|
||||||
logger->Info("Emulation has ended");
|
logger->Info("Emulation has ended");
|
||||||
|
|
||||||
auto end = std::chrono::steady_clock::now();
|
auto end = std::chrono::steady_clock::now();
|
||||||
@ -98,30 +100,38 @@ extern "C" JNIEXPORT jfloat Java_emu_skyline_EmulationActivity_getFrametime(JNIE
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setController(JNIEnv *, jobject, jint index, jint type, jint partnerIndex) {
|
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setController(JNIEnv *, jobject, jint index, jint type, jint partnerIndex) {
|
||||||
while (input == nullptr)
|
while (inputWeak.expired()); // If this isn't called then the guest won't know that the following host controller exists
|
||||||
asm("yield");
|
auto input = inputWeak.lock();
|
||||||
|
std::lock_guard guard(input->npad.mutex);
|
||||||
input->npad.controllers[index] = skyline::input::GuestController{static_cast<skyline::input::NpadControllerType>(type), static_cast<skyline::i8>(partnerIndex)};
|
input->npad.controllers[index] = skyline::input::GuestController{static_cast<skyline::input::NpadControllerType>(type), static_cast<skyline::i8>(partnerIndex)};
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_updateControllers(JNIEnv *, jobject) {
|
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_updateControllers(JNIEnv *, jobject) {
|
||||||
while (input == nullptr)
|
while (inputWeak.expired()); // If this isn't called then the mappings will not update unless the guest initiates an update itself
|
||||||
asm("yield");
|
auto input = inputWeak.lock();
|
||||||
input->npad.Update(true);
|
std::unique_lock lock(input->npad.mutex);
|
||||||
|
input->npad.Update(lock, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setButtonState(JNIEnv *, jobject, jint index, jlong mask, jint state) {
|
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setButtonState(JNIEnv *, jobject, jint index, jlong mask, jint state) {
|
||||||
if (input) {
|
try {
|
||||||
|
auto input = inputWeak.lock();
|
||||||
auto device = input->npad.controllers[index].device;
|
auto device = input->npad.controllers[index].device;
|
||||||
skyline::input::NpadButton button{.raw = static_cast<skyline::u64>(mask)};
|
skyline::input::NpadButton button{.raw = static_cast<skyline::u64>(mask)};
|
||||||
if (device)
|
if (device)
|
||||||
device->SetButtonState(button, static_cast<skyline::input::NpadButtonState>(state));
|
device->SetButtonState(button, state);
|
||||||
|
} catch (const std::bad_weak_ptr) {
|
||||||
|
// We don't mind if we miss button updates while input hasn't been initialized
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setAxisValue(JNIEnv *, jobject, jint index, jint axis, jint value) {
|
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setAxisValue(JNIEnv *, jobject, jint index, jint axis, jint value) {
|
||||||
if (input) {
|
try {
|
||||||
|
auto input = inputWeak.lock();
|
||||||
auto device = input->npad.controllers[index].device;
|
auto device = input->npad.controllers[index].device;
|
||||||
if (device)
|
if (device)
|
||||||
device->SetAxisValue(static_cast<skyline::input::NpadAxisId>(axis), value);
|
device->SetAxisValue(static_cast<skyline::input::NpadAxisId>(axis), value);
|
||||||
|
} catch (const std::bad_weak_ptr) {
|
||||||
|
// We don't mind if we miss axis updates while input hasn't been initialized
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ namespace skyline::audio {
|
|||||||
private:
|
private:
|
||||||
oboe::AudioStreamBuilder builder; //!< The audio stream builder, used to open
|
oboe::AudioStreamBuilder builder; //!< The audio stream builder, used to open
|
||||||
oboe::ManagedStream outputStream; //!< The output oboe audio stream
|
oboe::ManagedStream outputStream; //!< The output oboe audio stream
|
||||||
std::vector<std::shared_ptr<audio::AudioTrack>> audioTracks; //!< A vector of shared_ptr to every open audio track
|
std::vector<std::shared_ptr<AudioTrack>> audioTracks; //!< A vector of shared_ptr to every open audio track
|
||||||
Mutex trackLock; //!< This mutex is used to ensure that audioTracks isn't modified while it is being used
|
Mutex trackLock; //!< This mutex is used to ensure that audioTracks isn't modified while it is being used
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -31,13 +31,13 @@ namespace skyline::audio {
|
|||||||
* @param releaseCallback The callback to call when a buffer has been released
|
* @param releaseCallback The callback to call when a buffer has been released
|
||||||
* @return A shared pointer to a new AudioTrack object
|
* @return A shared pointer to a new AudioTrack object
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<audio::AudioTrack> OpenTrack(u8 channelCount, u32 sampleRate, const std::function<void()> &releaseCallback);
|
std::shared_ptr<AudioTrack> OpenTrack(u8 channelCount, u32 sampleRate, const std::function<void()> &releaseCallback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Closes a track and frees its data
|
* @brief Closes a track and frees its data
|
||||||
* @param track The track to close
|
* @param track The track to close
|
||||||
*/
|
*/
|
||||||
void CloseTrack(std::shared_ptr<audio::AudioTrack> &track);
|
void CloseTrack(std::shared_ptr<AudioTrack> &track);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The callback oboe uses to get audio sample data
|
* @brief The callback oboe uses to get audio sample data
|
||||||
|
@ -14,13 +14,13 @@ namespace skyline::input {
|
|||||||
*/
|
*/
|
||||||
class Input {
|
class Input {
|
||||||
private:
|
private:
|
||||||
const DeviceState &state; //!< The state of the device
|
const DeviceState &state;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<kernel::type::KSharedMemory> kHid; //!< The kernel shared memory object for HID Shared Memory
|
std::shared_ptr<kernel::type::KSharedMemory> kHid; //!< The kernel shared memory object for HID Shared Memory
|
||||||
input::HidSharedMemory *hid; //!< A pointer to HID Shared Memory on the host
|
HidSharedMemory *hid; //!< A pointer to HID Shared Memory on the host
|
||||||
|
|
||||||
input::NpadManager npad; //!< This manages all the NPad controllers
|
NpadManager npad; //!< This manages all the NPad controllers
|
||||||
|
|
||||||
Input(const DeviceState &state);
|
Input(const DeviceState &state);
|
||||||
};
|
};
|
||||||
|
@ -13,12 +13,15 @@ namespace skyline::input {
|
|||||||
{*this, hid->npad[8], NpadId::Unknown}, {*this, hid->npad[9], NpadId::Handheld},
|
{*this, hid->npad[8], NpadId::Unknown}, {*this, hid->npad[9], NpadId::Handheld},
|
||||||
} {}
|
} {}
|
||||||
|
|
||||||
void NpadManager::Update(bool host) {
|
void NpadManager::Update(std::unique_lock<std::mutex> &lock, bool host) {
|
||||||
if (host)
|
if (host) {
|
||||||
updated = true;
|
updated = true;
|
||||||
else
|
} else if (!updated) {
|
||||||
while (!updated)
|
lock.unlock();
|
||||||
asm("yield");
|
while (!updated);
|
||||||
|
lock.lock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!activated)
|
if (!activated)
|
||||||
return;
|
return;
|
||||||
@ -52,19 +55,13 @@ namespace skyline::input {
|
|||||||
style = NpadStyleSet{.raw = style.raw & styles.raw};
|
style = NpadStyleSet{.raw = style.raw & styles.raw};
|
||||||
|
|
||||||
if (style.raw) {
|
if (style.raw) {
|
||||||
if (style.proController) {
|
if (style.proController || style.joyconHandheld || style.joyconLeft || style.joyconRight) {
|
||||||
device.Connect(NpadControllerType::ProController);
|
device.Connect(controller.type);
|
||||||
controller.device = &device;
|
controller.device = &device;
|
||||||
} else if (style.joyconHandheld) {
|
} else if (style.joyconDual && orientation == NpadJoyOrientation::Vertical && device.GetAssignment() == NpadJoyAssignment::Dual) {
|
||||||
device.Connect(NpadControllerType::Handheld);
|
|
||||||
controller.device = &device;
|
|
||||||
} else if (style.joyconDual && device.GetAssignment() == NpadJoyAssignment::Dual) {
|
|
||||||
device.Connect(NpadControllerType::JoyconDual);
|
device.Connect(NpadControllerType::JoyconDual);
|
||||||
controller.device = &device;
|
controller.device = &device;
|
||||||
controllers.at(controller.partnerIndex).device = &device;
|
controllers.at(controller.partnerIndex).device = &device;
|
||||||
} else if (style.joyconLeft || style.joyconRight) {
|
|
||||||
device.Connect(controller.type);
|
|
||||||
controller.device = &device;
|
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -75,8 +72,8 @@ namespace skyline::input {
|
|||||||
|
|
||||||
// We do this to prevent triggering the event unless there's a real change in a device's style, which would be caused if we disconnected all controllers then reconnected them
|
// We do this to prevent triggering the event unless there's a real change in a device's style, which would be caused if we disconnected all controllers then reconnected them
|
||||||
for (auto &device : npads) {
|
for (auto &device : npads) {
|
||||||
bool connected = false;
|
bool connected{};
|
||||||
for (auto &controller : controllers) {
|
for (const auto &controller : controllers) {
|
||||||
if (controller.device == &device) {
|
if (controller.device == &device) {
|
||||||
connected = true;
|
connected = true;
|
||||||
break;
|
break;
|
||||||
@ -88,14 +85,18 @@ namespace skyline::input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void NpadManager::Activate() {
|
void NpadManager::Activate() {
|
||||||
|
std::unique_lock lock(mutex);
|
||||||
|
|
||||||
supportedIds = {NpadId::Handheld, NpadId::Player1, NpadId::Player2, NpadId::Player3, NpadId::Player4, NpadId::Player5, NpadId::Player6, NpadId::Player7, NpadId::Player8};
|
supportedIds = {NpadId::Handheld, NpadId::Player1, NpadId::Player2, NpadId::Player3, NpadId::Player4, NpadId::Player5, NpadId::Player6, NpadId::Player7, NpadId::Player8};
|
||||||
styles = {.proController = true, .joyconHandheld = true, .joyconDual = true, .joyconLeft = true, .joyconRight = true};
|
styles = {.proController = true, .joyconHandheld = true, .joyconDual = true, .joyconLeft = true, .joyconRight = true};
|
||||||
activated = true;
|
activated = true;
|
||||||
|
|
||||||
Update();
|
Update(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NpadManager::Deactivate() {
|
void NpadManager::Deactivate() {
|
||||||
|
std::unique_lock lock(mutex);
|
||||||
|
|
||||||
supportedIds = {};
|
supportedIds = {};
|
||||||
styles = {};
|
styles = {};
|
||||||
activated = false;
|
activated = false;
|
||||||
|
@ -6,8 +6,11 @@
|
|||||||
#include "npad_device.h"
|
#include "npad_device.h"
|
||||||
|
|
||||||
namespace skyline::input {
|
namespace skyline::input {
|
||||||
|
/**
|
||||||
|
* @brief A controller equivalent to a physical one connected to the Switch, it's translation into a Player (NpadDevice) is also encapsulated here
|
||||||
|
*/
|
||||||
struct GuestController {
|
struct GuestController {
|
||||||
NpadControllerType type{}; //!< The type of the controller
|
NpadControllerType type{};
|
||||||
i8 partnerIndex{-1}; //!< The index of a Joy-Con partner, if this has one
|
i8 partnerIndex{-1}; //!< The index of a Joy-Con partner, if this has one
|
||||||
NpadDevice *device{nullptr}; //!< A pointer to the NpadDevice that all events from this are redirected to
|
NpadDevice *device{nullptr}; //!< A pointer to the NpadDevice that all events from this are redirected to
|
||||||
};
|
};
|
||||||
@ -17,8 +20,7 @@ namespace skyline::input {
|
|||||||
*/
|
*/
|
||||||
class NpadManager {
|
class NpadManager {
|
||||||
private:
|
private:
|
||||||
const DeviceState &state; //!< The state of the device
|
const DeviceState &state;
|
||||||
std::array<NpadDevice, constant::NpadCount> npads; //!< An array of all the NPad devices
|
|
||||||
bool activated{false}; //!< If this NpadManager is activated or not
|
bool activated{false}; //!< If this NpadManager is activated or not
|
||||||
std::atomic<bool> updated{false}; //!< If this NpadManager has been updated by the guest
|
std::atomic<bool> updated{false}; //!< If this NpadManager has been updated by the guest
|
||||||
|
|
||||||
@ -41,10 +43,12 @@ namespace skyline::input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::array<GuestController, constant::ControllerCount> controllers; //!< An array of all the available guest controllers
|
std::mutex mutex; //!< This mutex must be locked before any modifications to class members
|
||||||
|
std::array<NpadDevice, constant::NpadCount> npads;
|
||||||
|
std::array<GuestController, constant::ControllerCount> controllers;
|
||||||
std::vector<NpadId> supportedIds; //!< The NpadId(s) that are supported by the application
|
std::vector<NpadId> supportedIds; //!< The NpadId(s) that are supported by the application
|
||||||
NpadStyleSet styles; //!< The styles that are supported by the application
|
NpadStyleSet styles; //!< The styles that are supported by the application
|
||||||
NpadJoyOrientation orientation{}; //!< The Joy-Con orientation to use
|
NpadJoyOrientation orientation{}; //!< The orientation all of Joy-Cons are in (This affects stick transformation for them)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param hid A pointer to HID Shared Memory on the host
|
* @param hid A pointer to HID Shared Memory on the host
|
||||||
@ -52,7 +56,6 @@ namespace skyline::input {
|
|||||||
NpadManager(const DeviceState &state, input::HidSharedMemory *hid);
|
NpadManager(const DeviceState &state, input::HidSharedMemory *hid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param id The ID of the NPad to return
|
|
||||||
* @return A reference to the NPad with the specified ID
|
* @return A reference to the NPad with the specified ID
|
||||||
*/
|
*/
|
||||||
constexpr inline NpadDevice &at(NpadId id) {
|
constexpr inline NpadDevice &at(NpadId id) {
|
||||||
@ -60,7 +63,6 @@ namespace skyline::input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param id The ID of the NPad to return
|
|
||||||
* @return A reference to the NPad with the specified ID
|
* @return A reference to the NPad with the specified ID
|
||||||
*/
|
*/
|
||||||
constexpr inline NpadDevice &operator[](NpadId id) noexcept {
|
constexpr inline NpadDevice &operator[](NpadId id) noexcept {
|
||||||
@ -69,9 +71,10 @@ namespace skyline::input {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This deduces all the mappings from guest controllers -> players based on the configuration supplied by HID services and available controllers
|
* @brief This deduces all the mappings from guest controllers -> players based on the configuration supplied by HID services and available controllers
|
||||||
|
* @param lock A unique_lock which locks the mutex in the class, it should be locked before modifications to any members and must not be passed in an unlocked state
|
||||||
* @param host If the update is host-initiated rather than the guest
|
* @param host If the update is host-initiated rather than the guest
|
||||||
*/
|
*/
|
||||||
void Update(bool host = false);
|
void Update(std::unique_lock<std::mutex> &lock, bool host = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This activates the mapping between guest controllers -> players, a call to this is required for function
|
* @brief This activates the mapping between guest controllers -> players, a call to this is required for function
|
||||||
|
@ -8,27 +8,37 @@ namespace skyline::input {
|
|||||||
NpadDevice::NpadDevice(NpadManager &manager, NpadSection §ion, NpadId id) : manager(manager), section(section), id(id), updateEvent(std::make_shared<kernel::type::KEvent>(manager.state)) {}
|
NpadDevice::NpadDevice(NpadManager &manager, NpadSection §ion, NpadId id) : manager(manager), section(section), id(id), updateEvent(std::make_shared<kernel::type::KEvent>(manager.state)) {}
|
||||||
|
|
||||||
void NpadDevice::Connect(NpadControllerType newType) {
|
void NpadDevice::Connect(NpadControllerType newType) {
|
||||||
if (type == newType)
|
if (type == newType) {
|
||||||
|
if (type == NpadControllerType::JoyconLeft || type == NpadControllerType::JoyconRight) {
|
||||||
|
switch (manager.orientation) {
|
||||||
|
case NpadJoyOrientation::Vertical:
|
||||||
|
section.systemProperties.abxyButtonsOriented = true;
|
||||||
|
section.systemProperties.slSrButtonOriented = false;
|
||||||
|
break;
|
||||||
|
case NpadJoyOrientation::Horizontal:
|
||||||
|
section.systemProperties.abxyButtonsOriented = false;
|
||||||
|
section.systemProperties.slSrButtonOriented = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
section.header.type = NpadControllerType::None;
|
section = {};
|
||||||
section.deviceType.raw = 0;
|
controllerInfo = nullptr;
|
||||||
section.buttonProperties.raw = 0;
|
|
||||||
|
|
||||||
connectionState.raw = 0;
|
connectionState = {.connected = true};
|
||||||
connectionState.connected = true;
|
|
||||||
|
|
||||||
switch (newType) {
|
switch (newType) {
|
||||||
case NpadControllerType::ProController:
|
case NpadControllerType::ProController:
|
||||||
section.header.type = NpadControllerType::ProController;
|
section.header.type = NpadControllerType::ProController;
|
||||||
section.deviceType.fullKey = true;
|
section.deviceType.fullKey = true;
|
||||||
|
|
||||||
section.systemProperties.directionalButtonsSupported = true;
|
|
||||||
section.systemProperties.abxyButtonsOriented = true;
|
section.systemProperties.abxyButtonsOriented = true;
|
||||||
section.systemProperties.plusButtonCapability = true;
|
section.systemProperties.plusButtonCapability = true;
|
||||||
section.systemProperties.minusButtonCapability = true;
|
section.systemProperties.minusButtonCapability = true;
|
||||||
|
|
||||||
connectionState.connected = true;
|
connectionState.handheld = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NpadControllerType::Handheld:
|
case NpadControllerType::Handheld:
|
||||||
@ -36,13 +46,15 @@ namespace skyline::input {
|
|||||||
section.deviceType.handheldLeft = true;
|
section.deviceType.handheldLeft = true;
|
||||||
section.deviceType.handheldRight = true;
|
section.deviceType.handheldRight = true;
|
||||||
|
|
||||||
section.systemProperties.directionalButtonsSupported = true;
|
|
||||||
section.systemProperties.abxyButtonsOriented = true;
|
section.systemProperties.abxyButtonsOriented = true;
|
||||||
section.systemProperties.plusButtonCapability = true;
|
section.systemProperties.plusButtonCapability = true;
|
||||||
section.systemProperties.minusButtonCapability = true;
|
section.systemProperties.minusButtonCapability = true;
|
||||||
|
section.systemProperties.directionalButtonsSupported = true;
|
||||||
|
|
||||||
connectionState.handheld = true;
|
connectionState.handheld = true;
|
||||||
|
connectionState.leftJoyconConnected = true;
|
||||||
connectionState.leftJoyconHandheld = true;
|
connectionState.leftJoyconHandheld = true;
|
||||||
|
connectionState.rightJoyconConnected = true;
|
||||||
connectionState.rightJoyconHandheld = true;
|
connectionState.rightJoyconHandheld = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -52,12 +64,11 @@ namespace skyline::input {
|
|||||||
section.deviceType.joyconRight = true;
|
section.deviceType.joyconRight = true;
|
||||||
section.header.assignment = NpadJoyAssignment::Dual;
|
section.header.assignment = NpadJoyAssignment::Dual;
|
||||||
|
|
||||||
section.systemProperties.directionalButtonsSupported = true;
|
|
||||||
section.systemProperties.abxyButtonsOriented = true;
|
section.systemProperties.abxyButtonsOriented = true;
|
||||||
section.systemProperties.plusButtonCapability = true;
|
section.systemProperties.plusButtonCapability = true;
|
||||||
section.systemProperties.minusButtonCapability = true;
|
section.systemProperties.minusButtonCapability = true;
|
||||||
|
section.systemProperties.directionalButtonsSupported = true;
|
||||||
|
|
||||||
connectionState.connected = true;
|
|
||||||
connectionState.leftJoyconConnected = true;
|
connectionState.leftJoyconConnected = true;
|
||||||
connectionState.rightJoyconConnected = true;
|
connectionState.rightJoyconConnected = true;
|
||||||
break;
|
break;
|
||||||
@ -67,11 +78,14 @@ namespace skyline::input {
|
|||||||
section.deviceType.joyconLeft = true;
|
section.deviceType.joyconLeft = true;
|
||||||
section.header.assignment = NpadJoyAssignment::Single;
|
section.header.assignment = NpadJoyAssignment::Single;
|
||||||
|
|
||||||
section.systemProperties.directionalButtonsSupported = true;
|
if (manager.orientation == NpadJoyOrientation::Vertical)
|
||||||
|
section.systemProperties.abxyButtonsOriented = true;
|
||||||
|
else if (manager.orientation == NpadJoyOrientation::Horizontal)
|
||||||
section.systemProperties.slSrButtonOriented = true;
|
section.systemProperties.slSrButtonOriented = true;
|
||||||
section.systemProperties.minusButtonCapability = true;
|
|
||||||
|
|
||||||
connectionState.connected = true;
|
section.systemProperties.minusButtonCapability = true;
|
||||||
|
section.systemProperties.directionalButtonsSupported = true;
|
||||||
|
|
||||||
connectionState.leftJoyconConnected = true;
|
connectionState.leftJoyconConnected = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -80,11 +94,14 @@ namespace skyline::input {
|
|||||||
section.deviceType.joyconRight = true;
|
section.deviceType.joyconRight = true;
|
||||||
section.header.assignment = NpadJoyAssignment::Single;
|
section.header.assignment = NpadJoyAssignment::Single;
|
||||||
|
|
||||||
|
if (manager.orientation == NpadJoyOrientation::Vertical)
|
||||||
section.systemProperties.abxyButtonsOriented = true;
|
section.systemProperties.abxyButtonsOriented = true;
|
||||||
|
else if (manager.orientation == NpadJoyOrientation::Horizontal)
|
||||||
|
section.systemProperties.slSrButtonOriented = true;
|
||||||
|
|
||||||
section.systemProperties.slSrButtonOriented = true;
|
section.systemProperties.slSrButtonOriented = true;
|
||||||
section.systemProperties.plusButtonCapability = true;
|
section.systemProperties.plusButtonCapability = true;
|
||||||
|
|
||||||
connectionState.connected = true;
|
|
||||||
connectionState.rightJoyconConnected = true;
|
connectionState.rightJoyconConnected = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -97,16 +114,20 @@ namespace skyline::input {
|
|||||||
case NpadControllerType::JoyconLeft:
|
case NpadControllerType::JoyconLeft:
|
||||||
case NpadControllerType::JoyconRight:
|
case NpadControllerType::JoyconRight:
|
||||||
section.header.singleColorStatus = NpadColorReadStatus::Success;
|
section.header.singleColorStatus = NpadColorReadStatus::Success;
|
||||||
section.header.dualColorStatus = NpadColorReadStatus::Disconnected;
|
if (newType == NpadControllerType::ProController)
|
||||||
section.header.singleColor = {0, 0};
|
section.header.singleColor = {0xFF2D2D2D, 0xFFE6E6E6}; // Normal Pro-Controller
|
||||||
|
else
|
||||||
|
section.header.singleColor = {0x4655F5, 0x00000A}; // Blue Joy-Con (https://switchbrew.org/wiki/Joy-Con#Colors)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NpadControllerType::Handheld:
|
case NpadControllerType::Handheld:
|
||||||
case NpadControllerType::JoyconDual:
|
case NpadControllerType::JoyconDual:
|
||||||
section.header.singleColorStatus = NpadColorReadStatus::Disconnected;
|
|
||||||
section.header.dualColorStatus = NpadColorReadStatus::Success;
|
section.header.dualColorStatus = NpadColorReadStatus::Success;
|
||||||
section.header.leftColor = {0, 0};
|
section.header.leftColor = {0x4655F5, 0x00000A};
|
||||||
section.header.rightColor = {0, 0};
|
section.header.rightColor = {0x4655F5, 0x00000A};
|
||||||
|
|
||||||
|
section.header.singleColorStatus = NpadColorReadStatus::Success; // Single color is also written for dual controllers
|
||||||
|
section.header.singleColor = section.header.leftColor; // and is set to the color of the left JC
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NpadControllerType::None:
|
case NpadControllerType::None:
|
||||||
@ -120,6 +141,10 @@ namespace skyline::input {
|
|||||||
type = newType;
|
type = newType;
|
||||||
controllerInfo = &GetControllerInfo();
|
controllerInfo = &GetControllerInfo();
|
||||||
|
|
||||||
|
GetNextEntry(*controllerInfo);
|
||||||
|
GetNextEntry(section.defaultController);
|
||||||
|
globalTimestamp++;
|
||||||
|
|
||||||
updateEvent->Signal();
|
updateEvent->Signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +153,6 @@ namespace skyline::input {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
section = {};
|
section = {};
|
||||||
explicitAssignment = false;
|
|
||||||
globalTimestamp = 0;
|
globalTimestamp = 0;
|
||||||
|
|
||||||
type = NpadControllerType::None;
|
type = NpadControllerType::None;
|
||||||
@ -175,18 +199,18 @@ namespace skyline::input {
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NpadDevice::SetButtonState(NpadButton mask, NpadButtonState state) {
|
void NpadDevice::SetButtonState(NpadButton mask, bool pressed) {
|
||||||
if (!connectionState.connected || !controllerInfo)
|
if (!connectionState.connected)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto &entry = GetNextEntry(*controllerInfo);
|
auto &entry = GetNextEntry(*controllerInfo);
|
||||||
|
|
||||||
if (state == NpadButtonState::Pressed)
|
if (pressed)
|
||||||
entry.buttons.raw |= mask.raw;
|
entry.buttons.raw |= mask.raw;
|
||||||
else
|
else
|
||||||
entry.buttons.raw &= ~mask.raw;
|
entry.buttons.raw &= ~mask.raw;
|
||||||
|
|
||||||
if ((type == NpadControllerType::JoyconLeft || type == NpadControllerType::JoyconRight) && manager.orientation == NpadJoyOrientation::Horizontal) {
|
if (manager.orientation == NpadJoyOrientation::Horizontal && (type == NpadControllerType::JoyconLeft || type == NpadControllerType::JoyconRight)) {
|
||||||
NpadButton orientedMask{};
|
NpadButton orientedMask{};
|
||||||
|
|
||||||
if (mask.dpadUp)
|
if (mask.dpadUp)
|
||||||
@ -219,75 +243,108 @@ namespace skyline::input {
|
|||||||
mask = orientedMask;
|
mask = orientedMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (NpadControllerState &controllerEntry : {std::ref(GetNextEntry(section.defaultController)), std::ref(GetNextEntry(section.digitalController))})
|
auto &defaultEntry = GetNextEntry(section.defaultController);
|
||||||
if (state == NpadButtonState::Pressed)
|
if (pressed)
|
||||||
controllerEntry.buttons.raw |= mask.raw;
|
defaultEntry.buttons.raw |= mask.raw;
|
||||||
else
|
else
|
||||||
controllerEntry.buttons.raw &= ~mask.raw;
|
defaultEntry.buttons.raw &= ~mask.raw;
|
||||||
|
|
||||||
globalTimestamp++;
|
globalTimestamp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NpadDevice::SetAxisValue(NpadAxisId axis, i32 value) {
|
void NpadDevice::SetAxisValue(NpadAxisId axis, i32 value) {
|
||||||
if (!connectionState.connected || !controllerInfo)
|
if (!connectionState.connected)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto &controllerEntry = GetNextEntry(*controllerInfo);
|
auto &controllerEntry = GetNextEntry(*controllerInfo);
|
||||||
auto &defaultEntry = GetNextEntry(section.defaultController);
|
auto &defaultEntry = GetNextEntry(section.defaultController);
|
||||||
|
|
||||||
if (manager.orientation == NpadJoyOrientation::Vertical && (type != NpadControllerType::JoyconLeft && type != NpadControllerType::JoyconRight)) {
|
constexpr i16 threshold = std::numeric_limits<i16>::max() / 2; // A 50% deadzone for the stick buttons
|
||||||
|
|
||||||
|
if (manager.orientation == NpadJoyOrientation::Vertical || (type != NpadControllerType::JoyconLeft && type != NpadControllerType::JoyconRight)) {
|
||||||
switch (axis) {
|
switch (axis) {
|
||||||
case NpadAxisId::LX:
|
case NpadAxisId::LX:
|
||||||
controllerEntry.leftX = value;
|
controllerEntry.leftX = value;
|
||||||
defaultEntry.leftX = value;
|
defaultEntry.leftX = value;
|
||||||
|
|
||||||
|
controllerEntry.buttons.leftStickLeft = controllerEntry.leftX <= -threshold;
|
||||||
|
defaultEntry.buttons.leftStickLeft = controllerEntry.buttons.leftStickLeft;
|
||||||
|
|
||||||
|
controllerEntry.buttons.leftStickRight = controllerEntry.leftX >= threshold;
|
||||||
|
defaultEntry.buttons.leftStickRight = controllerEntry.buttons.leftStickRight;
|
||||||
break;
|
break;
|
||||||
case NpadAxisId::LY:
|
case NpadAxisId::LY:
|
||||||
controllerEntry.leftY = value;
|
controllerEntry.leftY = value;
|
||||||
defaultEntry.leftY = value;
|
defaultEntry.leftY = value;
|
||||||
|
|
||||||
|
defaultEntry.buttons.leftStickUp = controllerEntry.buttons.leftStickUp;
|
||||||
|
controllerEntry.buttons.leftStickUp = controllerEntry.leftY >= threshold;
|
||||||
|
|
||||||
|
controllerEntry.buttons.leftStickDown = controllerEntry.leftY <= -threshold;
|
||||||
|
defaultEntry.buttons.leftStickDown = controllerEntry.buttons.leftStickDown;
|
||||||
break;
|
break;
|
||||||
case NpadAxisId::RX:
|
case NpadAxisId::RX:
|
||||||
controllerEntry.rightX = value;
|
controllerEntry.rightX = value;
|
||||||
defaultEntry.rightX = value;
|
defaultEntry.rightX = value;
|
||||||
|
|
||||||
|
controllerEntry.buttons.rightStickLeft = controllerEntry.rightX <= -threshold;
|
||||||
|
defaultEntry.buttons.rightStickLeft = controllerEntry.buttons.rightStickLeft;
|
||||||
|
|
||||||
|
controllerEntry.buttons.rightStickRight = controllerEntry.rightX >= threshold;
|
||||||
|
defaultEntry.buttons.rightStickRight = controllerEntry.buttons.rightStickRight;
|
||||||
break;
|
break;
|
||||||
case NpadAxisId::RY:
|
case NpadAxisId::RY:
|
||||||
controllerEntry.rightY = value;
|
controllerEntry.rightY = value;
|
||||||
defaultEntry.rightY = value;
|
defaultEntry.rightY = value;
|
||||||
|
|
||||||
|
controllerEntry.buttons.rightStickUp = controllerEntry.rightY >= threshold;
|
||||||
|
defaultEntry.buttons.rightStickUp = controllerEntry.buttons.rightStickUp;
|
||||||
|
|
||||||
|
controllerEntry.buttons.rightStickDown = controllerEntry.rightY <= -threshold;
|
||||||
|
defaultEntry.buttons.rightStickDown = controllerEntry.buttons.rightStickDown;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (axis) {
|
switch (axis) {
|
||||||
case NpadAxisId::LX:
|
case NpadAxisId::LX:
|
||||||
controllerEntry.leftX = value;
|
controllerEntry.leftY = value;
|
||||||
defaultEntry.leftY = value;
|
controllerEntry.buttons.leftStickUp = controllerEntry.leftY >= threshold;
|
||||||
|
controllerEntry.buttons.leftStickDown = controllerEntry.leftY <= -threshold;
|
||||||
|
|
||||||
|
defaultEntry.leftX = value;
|
||||||
|
defaultEntry.buttons.leftStickLeft = defaultEntry.leftX <= -threshold;
|
||||||
|
defaultEntry.buttons.leftStickRight = defaultEntry.leftX >= threshold;
|
||||||
break;
|
break;
|
||||||
case NpadAxisId::LY:
|
case NpadAxisId::LY:
|
||||||
controllerEntry.leftY = value;
|
controllerEntry.leftX = -value;
|
||||||
defaultEntry.leftX = -value;
|
controllerEntry.buttons.leftStickLeft = controllerEntry.leftX <= -threshold;
|
||||||
|
controllerEntry.buttons.leftStickRight = controllerEntry.leftX >= threshold;
|
||||||
|
|
||||||
|
defaultEntry.leftY = value;
|
||||||
|
defaultEntry.buttons.leftStickUp = defaultEntry.leftY >= threshold;
|
||||||
|
defaultEntry.buttons.leftStickDown = defaultEntry.leftY <= -threshold;
|
||||||
break;
|
break;
|
||||||
case NpadAxisId::RX:
|
case NpadAxisId::RX:
|
||||||
controllerEntry.rightX = value;
|
controllerEntry.rightY = value;
|
||||||
defaultEntry.rightY = value;
|
controllerEntry.buttons.rightStickUp = controllerEntry.rightY >= threshold;
|
||||||
|
controllerEntry.buttons.rightStickDown = controllerEntry.rightY <= -threshold;
|
||||||
|
|
||||||
|
defaultEntry.rightX = value;
|
||||||
|
defaultEntry.buttons.rightStickLeft = defaultEntry.rightX <= -threshold;
|
||||||
|
defaultEntry.buttons.rightStickRight = defaultEntry.rightX >= threshold;
|
||||||
break;
|
break;
|
||||||
case NpadAxisId::RY:
|
case NpadAxisId::RY:
|
||||||
controllerEntry.rightY = value;
|
controllerEntry.rightX = -value;
|
||||||
defaultEntry.rightX = -value;
|
controllerEntry.buttons.rightStickLeft = controllerEntry.rightX <= -threshold;
|
||||||
|
controllerEntry.buttons.rightStickRight = controllerEntry.rightX >= threshold;
|
||||||
|
|
||||||
|
defaultEntry.rightY = value;
|
||||||
|
defaultEntry.buttons.rightStickUp = defaultEntry.rightY >= threshold;
|
||||||
|
defaultEntry.buttons.rightStickDown = defaultEntry.rightY <= -threshold;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &digitalEntry = GetNextEntry(section.digitalController);
|
|
||||||
constexpr i16 threshold = 3276; // A 10% deadzone for the stick
|
|
||||||
|
|
||||||
digitalEntry.buttons.leftStickUp = defaultEntry.leftY >= threshold;
|
|
||||||
digitalEntry.buttons.leftStickDown = defaultEntry.leftY <= -threshold;
|
|
||||||
digitalEntry.buttons.leftStickLeft = defaultEntry.leftX <= -threshold;
|
|
||||||
digitalEntry.buttons.leftStickRight = defaultEntry.leftX >= threshold;
|
|
||||||
|
|
||||||
digitalEntry.buttons.rightStickUp = defaultEntry.rightY >= threshold;
|
|
||||||
digitalEntry.buttons.rightStickDown = defaultEntry.rightY <= -threshold;
|
|
||||||
digitalEntry.buttons.rightStickLeft = defaultEntry.rightX <= -threshold;
|
|
||||||
digitalEntry.buttons.rightStickRight = defaultEntry.rightX >= threshold;
|
|
||||||
|
|
||||||
globalTimestamp++;
|
globalTimestamp++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,20 +8,20 @@
|
|||||||
|
|
||||||
namespace skyline::input {
|
namespace skyline::input {
|
||||||
/**
|
/**
|
||||||
* @brief This enumerates all the orientations of the Joy-Con(s)
|
* @brief This enumerates the orientations the Joy-Con(s) can be held in
|
||||||
*/
|
*/
|
||||||
enum class NpadJoyOrientation : i64 {
|
enum class NpadJoyOrientation : i64 {
|
||||||
Vertical = 0, //!< The Joy-Con is held vertically (Default)
|
Vertical = 0,
|
||||||
Horizontal = 1, //!< The Joy-Con is held horizontally
|
Horizontal = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This holds all the NPad styles (https://switchbrew.org/wiki/HID_services#NpadStyleTag)
|
* @brief A union of all the NPad styles (https://switchbrew.org/wiki/HID_services#NpadStyleTag)
|
||||||
*/
|
*/
|
||||||
union NpadStyleSet {
|
union NpadStyleSet {
|
||||||
u32 raw;
|
u32 raw;
|
||||||
struct {
|
struct {
|
||||||
bool proController : 1; //!< The Pro Controller
|
bool proController : 1; //!< Pro Controller
|
||||||
bool joyconHandheld : 1; //!< Joy-Cons in handheld mode
|
bool joyconHandheld : 1; //!< Joy-Cons in handheld mode
|
||||||
bool joyconDual : 1; //!< Joy-Cons in a pair
|
bool joyconDual : 1; //!< Joy-Cons in a pair
|
||||||
bool joyconLeft : 1; //!< Left Joy-Con only
|
bool joyconLeft : 1; //!< Left Joy-Con only
|
||||||
@ -36,15 +36,7 @@ namespace skyline::input {
|
|||||||
static_assert(sizeof(NpadStyleSet) == 0x4);
|
static_assert(sizeof(NpadStyleSet) == 0x4);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This enumerates the states that a button can be in
|
* @brief This enumerates all of the axis on NPads
|
||||||
*/
|
|
||||||
enum class NpadButtonState : bool {
|
|
||||||
Released = false, //!< The button isn't being pressed
|
|
||||||
Pressed = true //!< The button is being pressed
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This enumerates all of the axis on NPad controllers
|
|
||||||
*/
|
*/
|
||||||
enum class NpadAxisId {
|
enum class NpadAxisId {
|
||||||
LX, //!< Left Stick X
|
LX, //!< Left Stick X
|
||||||
@ -57,16 +49,16 @@ namespace skyline::input {
|
|||||||
* @brief This enumerates all the possible IDs for an NPad (https://switchbrew.org/wiki/HID_services#NpadIdType)
|
* @brief This enumerates all the possible IDs for an NPad (https://switchbrew.org/wiki/HID_services#NpadIdType)
|
||||||
*/
|
*/
|
||||||
enum class NpadId : u32 {
|
enum class NpadId : u32 {
|
||||||
Player1 = 0x0, //!< 1st Player
|
Player1 = 0x0,
|
||||||
Player2 = 0x1, //!< 2nd Player
|
Player2 = 0x1,
|
||||||
Player3 = 0x2, //!< 3rd Player
|
Player3 = 0x2,
|
||||||
Player4 = 0x3, //!< 4th Player
|
Player4 = 0x3,
|
||||||
Player5 = 0x4, //!< 5th Player
|
Player5 = 0x4,
|
||||||
Player6 = 0x5, //!< 6th Player
|
Player6 = 0x5,
|
||||||
Player7 = 0x6, //!< 7th Player
|
Player7 = 0x6,
|
||||||
Player8 = 0x7, //!< 8th Player
|
Player8 = 0x7,
|
||||||
Unknown = 0x10, //!< Unknown
|
Unknown = 0x10,
|
||||||
Handheld = 0x20 //!< Handheld mode
|
Handheld = 0x20,
|
||||||
};
|
};
|
||||||
|
|
||||||
class NpadManager;
|
class NpadManager;
|
||||||
@ -78,8 +70,8 @@ namespace skyline::input {
|
|||||||
private:
|
private:
|
||||||
NpadManager &manager; //!< The manager responsible for managing this NpadDevice
|
NpadManager &manager; //!< The manager responsible for managing this NpadDevice
|
||||||
NpadSection §ion; //!< The section in HID shared memory for this controller
|
NpadSection §ion; //!< The section in HID shared memory for this controller
|
||||||
NpadControllerInfo *controllerInfo; //!< The controller info for this controller's type
|
NpadControllerInfo *controllerInfo; //!< The NpadControllerInfo for this controller's type
|
||||||
u64 globalTimestamp{}; //!< The global timestamp of the state entries
|
u64 globalTimestamp{}; //!< An incrementing timestamp that's common across all sections
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This updates the headers and creates a new entry in HID Shared Memory
|
* @brief This updates the headers and creates a new entry in HID Shared Memory
|
||||||
@ -94,26 +86,19 @@ namespace skyline::input {
|
|||||||
NpadControllerInfo &GetControllerInfo();
|
NpadControllerInfo &GetControllerInfo();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NpadId id; //!< The ID of this controller
|
NpadId id;
|
||||||
NpadControllerType type{}; //!< The type of this controller
|
NpadControllerType type{};
|
||||||
NpadConnectionState connectionState{}; //!< The state of the connection
|
NpadConnectionState connectionState{};
|
||||||
std::shared_ptr<kernel::type::KEvent> updateEvent; //!< This event is triggered on the controller's style changing
|
std::shared_ptr<kernel::type::KEvent> updateEvent; //!< This event is triggered on the controller's style changing
|
||||||
bool explicitAssignment{false}; //!< If an assignment has explicitly been set or is the default for this controller
|
|
||||||
|
|
||||||
NpadDevice(NpadManager &manager, NpadSection §ion, NpadId id);
|
NpadDevice(NpadManager &manager, NpadSection §ion, NpadId id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This sets a Joy-Con's Assignment Mode
|
* @brief This sets a Joy-Con's Assignment Mode
|
||||||
* @param assignment The assignment mode to set this controller to
|
* @param assignment The assignment mode to set this controller to
|
||||||
* @param isDefault If this is setting the default assignment mode of the controller
|
|
||||||
*/
|
*/
|
||||||
inline void SetAssignment(NpadJoyAssignment assignment, bool isDefault) {
|
inline void SetAssignment(NpadJoyAssignment assignment) {
|
||||||
if (!isDefault) {
|
|
||||||
section.header.assignment = assignment;
|
section.header.assignment = assignment;
|
||||||
explicitAssignment = true;
|
|
||||||
} else if (!explicitAssignment) {
|
|
||||||
section.header.assignment = assignment;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,9 +122,9 @@ namespace skyline::input {
|
|||||||
/**
|
/**
|
||||||
* @brief This changes the state of buttons to the specified state
|
* @brief This changes the state of buttons to the specified state
|
||||||
* @param mask A bit-field mask of all the buttons to change
|
* @param mask A bit-field mask of all the buttons to change
|
||||||
* @param state The state to change the buttons to
|
* @param pressed If the buttons were pressed or released
|
||||||
*/
|
*/
|
||||||
void SetButtonState(NpadButton mask, NpadButtonState state);
|
void SetButtonState(NpadButton mask, bool pressed);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This sets the value of an axis to the specified value
|
* @brief This sets the value of an axis to the specified value
|
||||||
|
@ -19,8 +19,8 @@ namespace skyline::input {
|
|||||||
* @brief The structure of the BasicXpad section (https://switchbrew.org/wiki/HID_Shared_Memory#BasicXpad)
|
* @brief The structure of the BasicXpad section (https://switchbrew.org/wiki/HID_Shared_Memory#BasicXpad)
|
||||||
*/
|
*/
|
||||||
struct BasicXpadSection {
|
struct BasicXpadSection {
|
||||||
CommonHeader header; //!< The header for this section
|
CommonHeader header;
|
||||||
std::array<BasicXpadState, constant::HidEntryCount> entries; //!< An array of all of the entries
|
std::array<BasicXpadState, constant::HidEntryCount> entries;
|
||||||
u64 _pad_[0x27];
|
u64 _pad_[0x27];
|
||||||
};
|
};
|
||||||
static_assert(sizeof(BasicXpadSection) == 0x400);
|
static_assert(sizeof(BasicXpadSection) == 0x400);
|
||||||
|
@ -19,8 +19,8 @@ namespace skyline::input {
|
|||||||
* @brief The section structure for all Button sections (HomeButton, SleepButton, CaptureButton)
|
* @brief The section structure for all Button sections (HomeButton, SleepButton, CaptureButton)
|
||||||
*/
|
*/
|
||||||
struct ButtonSection {
|
struct ButtonSection {
|
||||||
CommonHeader header; //!< The header for this section
|
CommonHeader header;
|
||||||
std::array<ButtonState, constant::HidEntryCount> entries; //!< An array of all of the entries
|
std::array<ButtonState, constant::HidEntryCount> entries;
|
||||||
u64 _pad_[0x9];
|
u64 _pad_[0x9];
|
||||||
};
|
};
|
||||||
static_assert(sizeof(ButtonSection) == 0x200);
|
static_assert(sizeof(ButtonSection) == 0x200);
|
||||||
|
@ -7,15 +7,15 @@
|
|||||||
|
|
||||||
namespace skyline::input {
|
namespace skyline::input {
|
||||||
/**
|
/**
|
||||||
* @brief The structure of the ConsoleSixAxisSensor section (https://switchbrew.org/wiki/HID_Shared_Memory#ConsoleSixAxisSensor)
|
* @brief The structure of the ConsoleSixAxisSensor (SevenSixAxisSensor) section (https://switchbrew.org/wiki/HID_Shared_Memory#ConsoleSixAxisSensor)
|
||||||
* @note This is seemingly used to calibrate the gyroscope bias values over time
|
* @note This is seemingly used to calibrate the gyroscope bias values over time
|
||||||
*/
|
*/
|
||||||
struct ConsoleSixAxisSensorSection {
|
struct ConsoleSixAxisSensorSection {
|
||||||
u64 timestamp; //!< The timestamp in samples
|
u64 timestamp; //!< The timestamp in samples
|
||||||
bool resting; //!< If the sensors are at rest or not (The calibration is performed when the devices are at rest)
|
bool resting; //!< If the sensors are at rest or not (Calibration is performed when the sensors are at rest)
|
||||||
u8 _pad0_[0x3];
|
u8 _pad0_[0x3];
|
||||||
u32 verticalizationError; //!< The error in verticalization ?
|
u32 verticalizationError; //!< The error in sensor fusion
|
||||||
u32 gyroBias[3]; //!< The gyroscope's sensor bias in all axis
|
std::array<u32, 3> gyroBias; //!< The gyroscope's sensor bias in all axis
|
||||||
u32 _pad1_;
|
u32 _pad1_;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(ConsoleSixAxisSensorSection) == 0x20);
|
static_assert(sizeof(ConsoleSixAxisSensorSection) == 0x20);
|
||||||
|
@ -19,8 +19,8 @@ namespace skyline::input {
|
|||||||
* @brief The structure of the DebugPad section (https://switchbrew.org/wiki/HID_Shared_Memory#DebugPad)
|
* @brief The structure of the DebugPad section (https://switchbrew.org/wiki/HID_Shared_Memory#DebugPad)
|
||||||
*/
|
*/
|
||||||
struct DebugPadSection {
|
struct DebugPadSection {
|
||||||
CommonHeader header; //!< The header for this section
|
CommonHeader header;
|
||||||
std::array<DebugPadState, constant::HidEntryCount> entries; //!< An array of all of the entries
|
std::array<DebugPadState, constant::HidEntryCount> entries;
|
||||||
u64 _pad_[0x27];
|
u64 _pad_[0x27];
|
||||||
};
|
};
|
||||||
static_assert(sizeof(DebugPadSection) == 0x400);
|
static_assert(sizeof(DebugPadSection) == 0x400);
|
||||||
|
@ -19,8 +19,8 @@ namespace skyline::input {
|
|||||||
* @brief The structure of the Gesture section (https://switchbrew.org/wiki/HID_Shared_Memory#Gesture)
|
* @brief The structure of the Gesture section (https://switchbrew.org/wiki/HID_Shared_Memory#Gesture)
|
||||||
*/
|
*/
|
||||||
struct GestureSection {
|
struct GestureSection {
|
||||||
CommonHeader header; //!< The header for this section
|
CommonHeader header;
|
||||||
std::array<GestureState, constant::HidEntryCount> entries; //!< An array of all of the entries
|
std::array<GestureState, constant::HidEntryCount> entries;
|
||||||
u64 _pad_[0x1F];
|
u64 _pad_[0x1F];
|
||||||
};
|
};
|
||||||
static_assert(sizeof(GestureSection) == 0x800);
|
static_assert(sizeof(GestureSection) == 0x800);
|
||||||
|
@ -19,8 +19,8 @@ namespace skyline::input {
|
|||||||
* @brief The structure of the InputDetector section (https://switchbrew.org/wiki/HID_Shared_Memory#InputDetector)
|
* @brief The structure of the InputDetector section (https://switchbrew.org/wiki/HID_Shared_Memory#InputDetector)
|
||||||
*/
|
*/
|
||||||
struct InputDetectorSection {
|
struct InputDetectorSection {
|
||||||
CommonHeader header; //!< The header for this section
|
CommonHeader header;
|
||||||
std::array<InputDetectorState, 2> entries; //!< An array of all of the entries
|
std::array<InputDetectorState, 2> entries;
|
||||||
u64 _pad_[0x6];
|
u64 _pad_[0x6];
|
||||||
};
|
};
|
||||||
static_assert(sizeof(InputDetectorSection) == 0x80);
|
static_assert(sizeof(InputDetectorSection) == 0x80);
|
||||||
|
@ -12,17 +12,17 @@ namespace skyline::input {
|
|||||||
union ModifierKey {
|
union ModifierKey {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
struct {
|
struct {
|
||||||
bool LControl : 1; //!< Left Control Key
|
bool lControl : 1; //!< Left Control Key
|
||||||
bool LShift : 1; //!< Left Shift Key
|
bool lShift : 1; //!< Left Shift Key
|
||||||
bool LAlt : 1; //!< Left Alt Key
|
bool lAlt : 1; //!< Left Alt Key
|
||||||
bool LWindows : 1; //!< Left Windows Key
|
bool lWindows : 1; //!< Left Windows Key
|
||||||
bool RControl : 1; //!< Right Control Key
|
bool rControl : 1; //!< Right Control Key
|
||||||
bool RShift : 1; //!< Right Shift Key
|
bool rShift : 1; //!< Right Shift Key
|
||||||
bool RAlt : 1; //!< Right Alt Key
|
bool rAlt : 1; //!< Right Alt Key
|
||||||
bool RWindows : 1; //!< Right Windows Key
|
bool rWindows : 1; //!< Right Windows Key
|
||||||
bool CapsLock : 1; //!< Caps-Lock Key
|
bool capsLock : 1; //!< Caps-Lock Key
|
||||||
bool ScrLock : 1; //!< Scroll-Lock Key
|
bool scrLock : 1; //!< Scroll-Lock Key
|
||||||
bool NumLock : 1; //!< Num-Lock Key
|
bool numLock : 1; //!< Num-Lock Key
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ namespace skyline::input {
|
|||||||
* @brief The structure of the Mouse section (https://switchbrew.org/wiki/HID_Shared_Memory#Mouse)
|
* @brief The structure of the Mouse section (https://switchbrew.org/wiki/HID_Shared_Memory#Mouse)
|
||||||
*/
|
*/
|
||||||
struct MouseSection {
|
struct MouseSection {
|
||||||
CommonHeader header; //!< The header for this section
|
CommonHeader header;
|
||||||
std::array<MouseState, constant::HidEntryCount> entries; //!< An array of all of the entries
|
std::array<MouseState, constant::HidEntryCount> entries;
|
||||||
u64 _pad_[0x16];
|
u64 _pad_[0x16];
|
||||||
};
|
};
|
||||||
static_assert(sizeof(MouseSection) == 0x400);
|
static_assert(sizeof(MouseSection) == 0x400);
|
||||||
|
@ -11,12 +11,12 @@ namespace skyline::input {
|
|||||||
* @brief This enumerates all of the types of an NPad controller
|
* @brief This enumerates all of the types of an NPad controller
|
||||||
*/
|
*/
|
||||||
enum class NpadControllerType : u32 {
|
enum class NpadControllerType : u32 {
|
||||||
None = 0, //!< No Controller
|
None = 0,
|
||||||
ProController = 0b1, //!< Pro Controller
|
ProController = 0b1,
|
||||||
Handheld = 0b10, //!< Handheld Controllers
|
Handheld = 0b10,
|
||||||
JoyconDual = 0b100, //!< Dual Joy-Cons Controller
|
JoyconDual = 0b100,
|
||||||
JoyconLeft = 0b1000, //!< Left Joy-Con Controller
|
JoyconLeft = 0b1000,
|
||||||
JoyconRight = 0b10000, //!< Right Joy-Con Controller
|
JoyconRight = 0b10000,
|
||||||
};
|
};
|
||||||
// @fmt:on
|
// @fmt:on
|
||||||
|
|
||||||
@ -24,8 +24,8 @@ namespace skyline::input {
|
|||||||
* @brief This enumerates all the possible assignments of the Joy-Con(s)
|
* @brief This enumerates all the possible assignments of the Joy-Con(s)
|
||||||
*/
|
*/
|
||||||
enum class NpadJoyAssignment : u32 {
|
enum class NpadJoyAssignment : u32 {
|
||||||
Dual = 0, //!< Dual Joy-Cons (Default)
|
Dual = 0, //!< Dual Joy-Cons (A pair of Joy-Cons are combined into a single player, if possible)
|
||||||
Single = 1, //!< Single Joy-Con
|
Single = 1, //!< Single Joy-Con (A single Joy-Con translates into a single player)
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,8 +41,8 @@ namespace skyline::input {
|
|||||||
* @brief This structure stores the color of a controller
|
* @brief This structure stores the color of a controller
|
||||||
*/
|
*/
|
||||||
struct NpadColor {
|
struct NpadColor {
|
||||||
u32 bodyColor; //!< The color of the controller's body
|
u32 bodyColor; //!< The color of the controller's body (This isn't always accurate and sometimes has magic values, especially with the Pro Controller)
|
||||||
u32 buttonColor; //!< The color of the controller's buttons
|
u32 buttonColor; //!< The color of the controller's buttons (Same as above)
|
||||||
};
|
};
|
||||||
static_assert(sizeof(NpadColor) == 0x8);
|
static_assert(sizeof(NpadColor) == 0x8);
|
||||||
|
|
||||||
@ -50,13 +50,13 @@ namespace skyline::input {
|
|||||||
* @brief The structure of the NPad headers (https://switchbrew.org/wiki/HID_Shared_Memory#NpadStateHeader)
|
* @brief The structure of the NPad headers (https://switchbrew.org/wiki/HID_Shared_Memory#NpadStateHeader)
|
||||||
*/
|
*/
|
||||||
struct NpadHeader {
|
struct NpadHeader {
|
||||||
NpadControllerType type; //!< The type of this controller
|
NpadControllerType type;
|
||||||
NpadJoyAssignment assignment; //!< The Joy-Con assignment of this controller
|
NpadJoyAssignment assignment;
|
||||||
|
|
||||||
NpadColorReadStatus singleColorStatus; //!< The status of reading color from a single controller (Single Joy-Con or Pro Controller)
|
NpadColorReadStatus singleColorStatus{NpadColorReadStatus::Disconnected}; //!< The status of reading color from a single controller (Single Joy-Con or Pro Controller)
|
||||||
NpadColor singleColor; //!< The color of the single controller
|
NpadColor singleColor; //!< The color of the single controller
|
||||||
|
|
||||||
NpadColorReadStatus dualColorStatus; //!< The status of reading color from dual controllers (Dual Joy-Cons)
|
NpadColorReadStatus dualColorStatus{NpadColorReadStatus::Disconnected}; //!< The status of reading color from dual controllers (Dual Joy-Cons)
|
||||||
NpadColor rightColor; //!< The color of the right Joy-Con
|
NpadColor rightColor; //!< The color of the right Joy-Con
|
||||||
NpadColor leftColor; //!< The color of the left Joy-Con
|
NpadColor leftColor; //!< The color of the left Joy-Con
|
||||||
};
|
};
|
||||||
@ -106,11 +106,11 @@ namespace skyline::input {
|
|||||||
union NpadConnectionState {
|
union NpadConnectionState {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
struct {
|
struct {
|
||||||
bool connected : 1; //!< If the controller is connected (Not in handheld mode)
|
bool connected : 1; //!< If the controller is connected
|
||||||
bool handheld : 1; //!< If the controller is in handheld mode
|
bool handheld : 1; //!< If both Joy-Cons are in handheld mode (or a Pro Controller)
|
||||||
bool leftJoyconConnected : 1; //!< If the left Joy-Con is connected (Not in handheld mode)
|
bool leftJoyconConnected : 1; //!< If the left Joy-Con is connected
|
||||||
bool leftJoyconHandheld : 1; //!< If the left Joy-Con is handheld
|
bool leftJoyconHandheld : 1; //!< If the left Joy-Con is handheld
|
||||||
bool rightJoyconConnected : 1; //!< If the right Joy-Con is connected (Not in handheld mode)
|
bool rightJoyconConnected : 1; //!< If the right Joy-Con is connected
|
||||||
bool rightJoyconHandheld : 1; //!< If the right Joy-Con is handheld
|
bool rightJoyconHandheld : 1; //!< If the right Joy-Con is handheld
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -131,7 +131,7 @@ namespace skyline::input {
|
|||||||
i32 rightX; //!< The right stick X (32768 to -32768)
|
i32 rightX; //!< The right stick X (32768 to -32768)
|
||||||
i32 rightY; //!< The right stick Y (32768 to -32768)
|
i32 rightY; //!< The right stick Y (32768 to -32768)
|
||||||
|
|
||||||
NpadConnectionState status; //!< The connection status of the controller
|
NpadConnectionState status;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(NpadControllerState) == 0x30);
|
static_assert(sizeof(NpadControllerState) == 0x30);
|
||||||
|
|
||||||
@ -139,8 +139,8 @@ namespace skyline::input {
|
|||||||
* @brief This structure contains the header and entries for the controller input
|
* @brief This structure contains the header and entries for the controller input
|
||||||
*/
|
*/
|
||||||
struct NpadControllerInfo {
|
struct NpadControllerInfo {
|
||||||
CommonHeader header; //!< The header for this controller
|
CommonHeader header;
|
||||||
std::array<NpadControllerState, constant::HidEntryCount> state; //!< An array of all of the entries
|
std::array<NpadControllerState, constant::HidEntryCount> state;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(NpadControllerInfo) == 0x350);
|
static_assert(sizeof(NpadControllerInfo) == 0x350);
|
||||||
|
|
||||||
@ -162,9 +162,9 @@ namespace skyline::input {
|
|||||||
u64 _unk0_;
|
u64 _unk0_;
|
||||||
u64 localTimestamp; //!< The local timestamp in samples
|
u64 localTimestamp; //!< The local timestamp in samples
|
||||||
|
|
||||||
SixaxisVector accelerometer; //!< The data from the accelerometer
|
SixaxisVector accelerometer;
|
||||||
SixaxisVector gyroscope; //!< The data from the gyroscope
|
SixaxisVector gyroscope;
|
||||||
SixaxisVector _unk1_; //!< The data from an unknown sensor
|
SixaxisVector rotation;
|
||||||
std::array<SixaxisVector, 3> orientation; //!< The orientation basis data as a matrix
|
std::array<SixaxisVector, 3> orientation; //!< The orientation basis data as a matrix
|
||||||
|
|
||||||
u64 _unk2_; //!< This is always 1
|
u64 _unk2_; //!< This is always 1
|
||||||
@ -175,8 +175,8 @@ namespace skyline::input {
|
|||||||
* @brief This structure contains header and entries for the IMU (Sixaxis) data
|
* @brief This structure contains header and entries for the IMU (Sixaxis) data
|
||||||
*/
|
*/
|
||||||
struct NpadSixaxisInfo {
|
struct NpadSixaxisInfo {
|
||||||
CommonHeader header; //!< The header for the controller's IMU data
|
CommonHeader header;
|
||||||
std::array<NpadSixaxisState, constant::HidEntryCount> state; //!< An array of all of the entries
|
std::array<NpadSixaxisState, constant::HidEntryCount> state;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(NpadSixaxisInfo) == 0x708);
|
static_assert(sizeof(NpadSixaxisInfo) == 0x708);
|
||||||
|
|
||||||
@ -220,25 +220,25 @@ namespace skyline::input {
|
|||||||
bool singlePowerConnected : 1; //!< If a single unit is connected to a power source (Handheld, Pro-Con)
|
bool singlePowerConnected : 1; //!< If a single unit is connected to a power source (Handheld, Pro-Con)
|
||||||
bool leftPowerConnected : 1; //!< If the left Joy-Con is connected to a power source
|
bool leftPowerConnected : 1; //!< If the left Joy-Con is connected to a power source
|
||||||
bool rightPowerConnected : 1; //!< If the right Joy-Con is connected to a power source
|
bool rightPowerConnected : 1; //!< If the right Joy-Con is connected to a power source
|
||||||
u64 _unk_ : 3;
|
u8 _unk_ : 3;
|
||||||
bool unsupportedButtonPressedSystem : 1; //!< If an unsupported buttons was pressed on system controller
|
bool unsupportedButtonPressedSystem : 1; //!< If an unsupported buttons was pressed on system controller
|
||||||
bool unsupportedButtonPressedSystemExt : 1; //!< If an unsupported buttons was pressed on system external controller
|
bool unsupportedButtonPressedSystemExt : 1; //!< If an unsupported buttons was pressed on system external controller
|
||||||
bool abxyButtonsOriented : 1; //!< If the ABXY Buttons oriented
|
bool abxyButtonsOriented : 1; //!< If the controller is oriented so that ABXY buttons are oriented correctly (Vertical for Joy-Cons)
|
||||||
bool slSrButtonOriented : 1; //!< If the SL/SR Buttons oriented
|
bool slSrButtonOriented : 1; //!< If the Joy-Con is oriented so that the SL/SR Buttons are accessible (Horizontal)
|
||||||
bool plusButtonCapability : 1; //!< If the + button exists
|
bool plusButtonCapability : 1; //!< If the + button exists
|
||||||
bool minusButtonCapability : 1; //!< If the - button exists
|
bool minusButtonCapability : 1; //!< If the - button exists
|
||||||
bool directionalButtonsSupported : 1; //!< If the controller has a D-Pad
|
bool directionalButtonsSupported : 1; //!< If the controller has explicit directional buttons (Not a HAT like on the Pro Controller)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(NpadSystemProperties) == 0x8);
|
static_assert(sizeof(NpadSystemProperties) == 0x8);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This structure holds data about the System Buttons (Home, Sleep and Capture) on an NPad (https://switchbrew.org/wiki/HID_Shared_Memory#NpadSystemButtonProperties)
|
* @brief This structure holds properties regarding the System Buttons (Home, Sleep and Capture) on an NPad (https://switchbrew.org/wiki/HID_Shared_Memory#NpadSystemButtonProperties)
|
||||||
*/
|
*/
|
||||||
union NpadSystemButtonProperties {
|
union NpadSystemButtonProperties {
|
||||||
u32 raw;
|
u32 raw;
|
||||||
struct {
|
struct {
|
||||||
bool unintendedHomeButtonInputProtectionEnabled : 1; //!< If the Unintended Home Button Input Protection is enabled or not
|
bool unintendedHomeButtonInputProtectionEnabled : 1;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(NpadSystemButtonProperties) == 0x4);
|
static_assert(sizeof(NpadSystemButtonProperties) == 0x4);
|
||||||
@ -247,40 +247,40 @@ namespace skyline::input {
|
|||||||
* @brief This enumerates all the possible values for the NPad's battery level
|
* @brief This enumerates all the possible values for the NPad's battery level
|
||||||
*/
|
*/
|
||||||
enum class NpadBatteryLevel : u32 {
|
enum class NpadBatteryLevel : u32 {
|
||||||
Empty = 0, //!< The battery is empty
|
Empty = 0,
|
||||||
Low = 1, //!< The battery is nearly empty
|
Low = 1,
|
||||||
Medium = 2, //!< The battery is fairly full
|
Medium = 2,
|
||||||
High = 3, //!< The battery is almost full
|
High = 3,
|
||||||
Full = 4, //!< The battery is 100% full
|
Full = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The structure of the Npad section (https://switchbrew.org/wiki/HID_Shared_Memory#NpadState)
|
* @brief The structure of the Npad section (https://switchbrew.org/wiki/HID_Shared_Memory#NpadState)
|
||||||
*/
|
*/
|
||||||
struct NpadSection {
|
struct NpadSection {
|
||||||
NpadHeader header; //!< The header for this section
|
NpadHeader header;
|
||||||
|
|
||||||
NpadControllerInfo fullKeyController; //!< The Pro/GC controller data
|
NpadControllerInfo fullKeyController; //!< The Pro/GC controller data
|
||||||
NpadControllerInfo handheldController; //!< The Handheld controller data
|
NpadControllerInfo handheldController; //!< The Handheld controller data
|
||||||
NpadControllerInfo dualController; //!< The Dual Joy-Con controller data (Only in Dual Mode, no input rotation based on rotation)
|
NpadControllerInfo dualController; //!< The Dual Joy-Con controller data (Only in Dual Mode, no input rotation based on rotation)
|
||||||
NpadControllerInfo leftController; //!< The Left Joy-Con controller data (Only in Single Mode, no input rotation based on rotation)
|
NpadControllerInfo leftController; //!< The Left Joy-Con controller data (Only in Single Mode, no input rotation based on rotation)
|
||||||
NpadControllerInfo rightController; //!< The Right Joy-Con controller data (Only in Single Mode, no input rotation based on rotation)
|
NpadControllerInfo rightController; //!< The Right Joy-Con controller data (Only in Single Mode, no input rotation based on rotation)
|
||||||
NpadControllerInfo digitalController; //!< The Default Digital controller data (Same as Default but Analog Sticks are converted into 8-directional Digital Sticks)
|
NpadControllerInfo palmaController; //!< The Poké Ball Plus controller data
|
||||||
NpadControllerInfo defaultController; //!< The Default controller data (Inputs are rotated based on orientation and SL/SR are mapped to L/R incase it is a single JC)
|
NpadControllerInfo defaultController; //!< The Default controller data (Inputs are rotated based on orientation and SL/SR are mapped to L/R incase it is a single JC)
|
||||||
|
|
||||||
NpadSixaxisInfo fullKeySixaxis; //!< The Pro/GC IMU data
|
NpadSixaxisInfo fullKeySixaxis; //!< The Pro/GC IMU data
|
||||||
NpadSixaxisInfo handheldSixaxis; //!< The Handheld IMU data
|
NpadSixaxisInfo handheldSixaxis; //!< The Handheld IMU data
|
||||||
NpadSixaxisInfo dualLeftSixaxis; //!< The Left Joy-Con in dual mode IMU data
|
NpadSixaxisInfo dualLeftSixaxis; //!< The Left Joy-Con in dual mode's IMU data
|
||||||
NpadSixaxisInfo dualRightSixaxis; //!< The Left Joy-Con in dual mode IMU data
|
NpadSixaxisInfo dualRightSixaxis; //!< The Left Joy-Con in dual mode's IMU data
|
||||||
NpadSixaxisInfo leftSixaxis; //!< The Left Joy-Con IMU data
|
NpadSixaxisInfo leftSixaxis; //!< The Left Joy-Con IMU data
|
||||||
NpadSixaxisInfo rightSixaxis; //!< The Right Joy-Con IMU data
|
NpadSixaxisInfo rightSixaxis; //!< The Right Joy-Con IMU data
|
||||||
|
|
||||||
NpadDeviceType deviceType; //!< The device type of this controller
|
NpadDeviceType deviceType;
|
||||||
|
|
||||||
u32 _pad0_;
|
u32 _pad0_;
|
||||||
|
|
||||||
NpadSystemProperties systemProperties; //!< The system properties of this controller
|
NpadSystemProperties systemProperties;
|
||||||
NpadSystemButtonProperties buttonProperties; //!< The system button properties of this controller
|
NpadSystemButtonProperties buttonProperties;
|
||||||
NpadBatteryLevel singleBatteryLevel; //!< The battery level of a single unit (Handheld, Pro-Con)
|
NpadBatteryLevel singleBatteryLevel; //!< The battery level of a single unit (Handheld, Pro-Con)
|
||||||
NpadBatteryLevel leftBatteryLevel; //!< The battery level of the left Joy-Con
|
NpadBatteryLevel leftBatteryLevel; //!< The battery level of the left Joy-Con
|
||||||
NpadBatteryLevel rightBatteryLevel; //!< The battery level of the right Joy-Con
|
NpadBatteryLevel rightBatteryLevel; //!< The battery level of the right Joy-Con
|
||||||
|
@ -42,8 +42,8 @@ namespace skyline::input {
|
|||||||
* @brief The structure of the TouchScreen section (https://switchbrew.org/wiki/HID_Shared_Memory#TouchScreen)
|
* @brief The structure of the TouchScreen section (https://switchbrew.org/wiki/HID_Shared_Memory#TouchScreen)
|
||||||
*/
|
*/
|
||||||
struct TouchScreenSection {
|
struct TouchScreenSection {
|
||||||
CommonHeader header; //!< The header for this section
|
CommonHeader header;
|
||||||
std::array<TouchScreenState, constant::HidEntryCount> entries; //!< An array of all of the entries
|
std::array<TouchScreenState, constant::HidEntryCount> entries;
|
||||||
u64 _pad_[0x79];
|
u64 _pad_[0x79];
|
||||||
};
|
};
|
||||||
static_assert(sizeof(TouchScreenSection) == 0x3000);
|
static_assert(sizeof(TouchScreenSection) == 0x3000);
|
||||||
|
@ -10,7 +10,7 @@ namespace skyline {
|
|||||||
namespace constant {
|
namespace constant {
|
||||||
constexpr u8 HidEntryCount = 17; //!< The amount of entries in each HID device
|
constexpr u8 HidEntryCount = 17; //!< The amount of entries in each HID device
|
||||||
constexpr u8 NpadCount = 10; //!< The amount of NPads in shared memory
|
constexpr u8 NpadCount = 10; //!< The amount of NPads in shared memory
|
||||||
constexpr u8 ControllerCount = 8; //!< The maximum amount of host controllers
|
constexpr u8 ControllerCount = 8; //!< The maximum amount of guest controllers
|
||||||
constexpr u32 NpadBatteryFull = 2; //!< The full battery state of an npad
|
constexpr u32 NpadBatteryFull = 2; //!< The full battery state of an npad
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,10 +89,10 @@ namespace skyline {
|
|||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
std::lock_guard guard(JniMtx);
|
std::lock_guard guard(JniMtx);
|
||||||
if (!Halt) {
|
if (Halt)
|
||||||
|
break;
|
||||||
state.gpu->Loop();
|
state.gpu->Loop();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
state.logger->Error(e.what());
|
state.logger->Error(e.what());
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
@ -27,7 +27,7 @@ namespace skyline::kernel {
|
|||||||
throw exception("Unsupported ROM extension.");
|
throw exception("Unsupported ROM extension.");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto process = CreateProcess(constant::BaseAddress, 0, constant::DefStackSize);
|
process = CreateProcess(constant::BaseAddress, 0, constant::DefStackSize);
|
||||||
state.loader->LoadProcessData(process, state);
|
state.loader->LoadProcessData(process, state);
|
||||||
process->InitializeMemory();
|
process->InitializeMemory();
|
||||||
process->threads.at(process->pid)->Start(); // The kernel itself is responsible for starting the main thread
|
process->threads.at(process->pid)->Start(); // The kernel itself is responsible for starting the main thread
|
||||||
@ -50,9 +50,7 @@ namespace skyline::kernel {
|
|||||||
throw exception("Call to clone() has failed: {}", strerror(errno));
|
throw exception("Call to clone() has failed: {}", strerror(errno));
|
||||||
|
|
||||||
state.logger->Debug("Successfully created process with PID: {}", pid);
|
state.logger->Debug("Successfully created process with PID: {}", pid);
|
||||||
process = std::make_shared<kernel::type::KProcess>(state, pid, argument, stack, tlsMem);
|
return std::make_shared<kernel::type::KProcess>(state, pid, argument, stack, tlsMem);
|
||||||
|
|
||||||
return process;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OS::KillThread(pid_t pid) {
|
void OS::KillThread(pid_t pid) {
|
||||||
|
@ -29,8 +29,9 @@ namespace skyline::service::hid {
|
|||||||
|
|
||||||
void IHidServer::SetSupportedNpadStyleSet(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
void IHidServer::SetSupportedNpadStyleSet(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
auto styleSet = request.Pop<NpadStyleSet>();
|
auto styleSet = request.Pop<NpadStyleSet>();
|
||||||
|
std::unique_lock lock(state.input->npad.mutex);
|
||||||
state.input->npad.styles = styleSet;
|
state.input->npad.styles = styleSet;
|
||||||
state.input->npad.Update();
|
state.input->npad.Update(lock);
|
||||||
|
|
||||||
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>
|
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.palma), 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));
|
||||||
@ -51,8 +52,9 @@ namespace skyline::service::hid {
|
|||||||
address += sizeof(NpadId);
|
address += sizeof(NpadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_lock lock(state.input->npad.mutex);
|
||||||
state.input->npad.supportedIds = supportedIds;
|
state.input->npad.supportedIds = supportedIds;
|
||||||
state.input->npad.Update();
|
state.input->npad.Update(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IHidServer::ActivateNpad(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
void IHidServer::ActivateNpad(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
@ -73,7 +75,10 @@ namespace skyline::service::hid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IHidServer::SetNpadJoyHoldType(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
void IHidServer::SetNpadJoyHoldType(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
|
std::unique_lock lock(state.input->npad.mutex);
|
||||||
|
request.Skip<u64>();
|
||||||
state.input->npad.orientation = request.Pop<NpadJoyOrientation>();
|
state.input->npad.orientation = request.Pop<NpadJoyOrientation>();
|
||||||
|
state.input->npad.Update(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IHidServer::GetNpadJoyHoldType(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
void IHidServer::GetNpadJoyHoldType(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
@ -82,17 +87,22 @@ namespace skyline::service::hid {
|
|||||||
|
|
||||||
void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
auto id = request.Pop<NpadId>();
|
auto id = request.Pop<NpadId>();
|
||||||
state.input->npad.at(id).SetAssignment(NpadJoyAssignment::Single, true);
|
std::unique_lock lock(state.input->npad.mutex);
|
||||||
state.input->npad.Update();
|
state.input->npad.at(id).SetAssignment(NpadJoyAssignment::Single);
|
||||||
|
state.input->npad.Update(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IHidServer::SetNpadJoyAssignmentModeSingle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
void IHidServer::SetNpadJoyAssignmentModeSingle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
auto id = request.Pop<NpadId>();
|
auto id = request.Pop<NpadId>();
|
||||||
state.input->npad.at(id).SetAssignment(NpadJoyAssignment::Single, false);
|
std::unique_lock lock(state.input->npad.mutex);
|
||||||
|
state.input->npad.at(id).SetAssignment(NpadJoyAssignment::Single);
|
||||||
|
state.input->npad.Update(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IHidServer::SetNpadJoyAssignmentModeDual(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
void IHidServer::SetNpadJoyAssignmentModeDual(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
auto id = request.Pop<NpadId>();
|
auto id = request.Pop<NpadId>();
|
||||||
state.input->npad.at(id).SetAssignment(NpadJoyAssignment::Dual, false);
|
std::unique_lock lock(state.input->npad.mutex);
|
||||||
|
state.input->npad.at(id).SetAssignment(NpadJoyAssignment::Dual);
|
||||||
|
state.input->npad.Update(lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ namespace skyline::service::settings {
|
|||||||
{0x3, SFUNC(ISystemSettingsServer::GetFirmwareVersion)}}) {}
|
{0x3, SFUNC(ISystemSettingsServer::GetFirmwareVersion)}}) {}
|
||||||
|
|
||||||
void ISystemSettingsServer::GetFirmwareVersion(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
void ISystemSettingsServer::GetFirmwareVersion(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
SysVerTitle title{.major=9, .minor=0, .micro=0, .revMajor=4, .revMinor=0, .platform="NX", .verHash="4de65c071fd0869695b7629f75eb97b2551dbf2f", .dispVer="9.0.0", .dispTitle="NintendoSDK Firmware for NX 9.0.0-4.0"};
|
SysVerTitle title{.major=5, .minor=0, .micro=0, .revMajor=4, .revMinor=0, .platform="NX", .verHash="4de65c071fd0869695b7629f75eb97b2551dbf2f", .dispVer="9.0.0", .dispTitle="NintendoSDK Firmware for NX 9.0.0-4.0"};
|
||||||
state.process->WriteMemory(title, request.outputBuf.at(0).address);
|
state.process->WriteMemory(title, request.outputBuf.at(0).address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
|||||||
/**
|
/**
|
||||||
* The [InputManager] class handles loading/saving the input data
|
* The [InputManager] class handles loading/saving the input data
|
||||||
*/
|
*/
|
||||||
lateinit var input : InputManager
|
private lateinit var input : InputManager
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A boolean flag denoting the current operation mode of the emulator (Docked = true/Handheld = false)
|
* A boolean flag denoting the current operation mode of the emulator (Docked = true/Handheld = false)
|
||||||
@ -104,11 +104,14 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
|||||||
* @param index The arbitrary index of the controller, this is to handle matching with a partner Joy-Con
|
* @param index The arbitrary index of the controller, this is to handle matching with a partner Joy-Con
|
||||||
* @param type The type of the host controller
|
* @param type The type of the host controller
|
||||||
* @param partnerIndex The index of a partner Joy-Con if there is one
|
* @param partnerIndex The index of a partner Joy-Con if there is one
|
||||||
|
* @note This is blocking and will stall till input has been initialized on the guest
|
||||||
*/
|
*/
|
||||||
private external fun setController(index : Int, type : Int, partnerIndex : Int = -1)
|
private external fun setController(index : Int, type : Int, partnerIndex : Int = -1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This flushes the controller updates on the guest
|
* This flushes the controller updates on the guest
|
||||||
|
*
|
||||||
|
* @note This is blocking and will stall till input has been initialized on the guest
|
||||||
*/
|
*/
|
||||||
private external fun updateControllers()
|
private external fun updateControllers()
|
||||||
|
|
||||||
@ -172,7 +175,7 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
|||||||
|
|
||||||
runOnUiThread { initializeControllers() }
|
runOnUiThread { initializeControllers() }
|
||||||
|
|
||||||
executeApplication(Uri.decode(rom.toString()), romType, romFd.fd, preferenceFd.fd, applicationContext.filesDir.canonicalPath + "/")
|
executeApplication(rom.toString(), romType, romFd.fd, preferenceFd.fd, applicationContext.filesDir.canonicalPath + "/")
|
||||||
|
|
||||||
if (shouldFinish)
|
if (shouldFinish)
|
||||||
runOnUiThread { finish() }
|
runOnUiThread { finish() }
|
||||||
@ -195,7 +198,7 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
|||||||
window.insetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
window.insetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||||
} else {
|
} else {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE
|
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||||
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||||
@ -225,7 +228,8 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
|||||||
|
|
||||||
operationMode = sharedPreferences.getBoolean("operation_mode", operationMode)
|
operationMode = sharedPreferences.getBoolean("operation_mode", operationMode)
|
||||||
|
|
||||||
windowManager.defaultDisplay.supportedModes.maxBy { it.refreshRate + (it.physicalHeight * it.physicalWidth) }?.let { window.attributes.preferredDisplayModeId = it.modeId }
|
@Suppress("DEPRECATION") val display = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) display!! else windowManager.defaultDisplay
|
||||||
|
display?.supportedModes?.maxBy { it.refreshRate + (it.physicalHeight * it.physicalWidth) }?.let { window.attributes.preferredDisplayModeId = it.modeId }
|
||||||
|
|
||||||
executeApplication(intent.data!!)
|
executeApplication(intent.data!!)
|
||||||
}
|
}
|
||||||
|
@ -184,9 +184,8 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
|
|||||||
override fun onScrolled(recyclerView : RecyclerView, dx : Int, dy : Int) {
|
override fun onScrolled(recyclerView : RecyclerView, dx : Int, dy : Int) {
|
||||||
y += dy
|
y += dy
|
||||||
|
|
||||||
if (!app_list.isInTouchMode) {
|
if (!app_list.isInTouchMode)
|
||||||
toolbar_layout.setExpanded(y == 0)
|
toolbar_layout.setExpanded(y == 0)
|
||||||
}
|
|
||||||
|
|
||||||
super.onScrolled(recyclerView, dx, dy)
|
super.onScrolled(recyclerView, dx, dy)
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
public override fun onActivityResult(requestCode : Int, resultCode : Int, data : Intent?) {
|
public override fun onActivityResult(requestCode : Int, resultCode : Int, data : Intent?) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
|
||||||
if (refreshKey != null) {
|
refreshKey?.let {
|
||||||
inputManager.syncObjects()
|
inputManager.syncObjects()
|
||||||
preferenceFragment.refreshPreference(refreshKey!!)
|
preferenceFragment.refreshPreference(refreshKey!!)
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout
|
|||||||
import com.google.android.material.snackbar.Snackbar.SnackbarLayout
|
import com.google.android.material.snackbar.Snackbar.SnackbarLayout
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom linear layout with support for [CoordinatorLayout] to move children, when [com.google.android.material.snackbar.Snackbar] shows up.
|
* Custom linear layout with support for [CoordinatorLayout] to move children, when [com.google.android.material.snackbar.Snackbar] shows up
|
||||||
*/
|
*/
|
||||||
class CustomLinearLayout : LinearLayout, CoordinatorLayout.AttachedBehavior {
|
class CustomLinearLayout : LinearLayout, CoordinatorLayout.AttachedBehavior {
|
||||||
constructor(context : Context) : this(context, null)
|
constructor(context : Context) : this(context, null)
|
||||||
@ -26,16 +26,9 @@ class CustomLinearLayout : LinearLayout, CoordinatorLayout.AttachedBehavior {
|
|||||||
|
|
||||||
override fun requestFocus(direction: Int, previouslyFocusedRect: Rect): Boolean = getChildAt(if (direction == View.FOCUS_UP) childCount - 1 else 0 )?.requestFocus() ?: false
|
override fun requestFocus(direction: Int, previouslyFocusedRect: Rect): Boolean = getChildAt(if (direction == View.FOCUS_UP) childCount - 1 else 0 )?.requestFocus() ?: false
|
||||||
|
|
||||||
/*
|
|
||||||
override fun onRequestFocusInDescendants(dir : Int, rect : Rect?) : Boolean {
|
|
||||||
Log.i("DESC", "$dir and $rect")
|
|
||||||
return getChildAt(0).requestFocus()
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines behaviour when [com.google.android.material.snackbar.Snackbar] is shown.
|
* Defines behaviour when [com.google.android.material.snackbar.Snackbar] is shown
|
||||||
* Simply sets an offset to y translation to move children out of the way.
|
* Simply sets an offset to y translation to move children out of the way
|
||||||
*/
|
*/
|
||||||
class MoveUpwardBehavior : CoordinatorLayout.Behavior<CustomLinearLayout>() {
|
class MoveUpwardBehavior : CoordinatorLayout.Behavior<CustomLinearLayout>() {
|
||||||
override fun layoutDependsOn(parent : CoordinatorLayout, child : CustomLinearLayout, dependency : View) : Boolean = dependency is SnackbarLayout
|
override fun layoutDependsOn(parent : CoordinatorLayout, child : CustomLinearLayout, dependency : View) : Boolean = dependency is SnackbarLayout
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
@ -9,11 +9,6 @@
|
|||||||
<item name="colorOnSecondary">@color/colorOnSecondary</item>
|
<item name="colorOnSecondary">@color/colorOnSecondary</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="EmuTheme" parent="AppTheme">
|
|
||||||
<item name="android:windowTranslucentStatus">true</item>
|
|
||||||
<item name="android:windowTranslucentNavigation">true</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="AppTheme.ActionBar" parent="">
|
<style name="AppTheme.ActionBar" parent="">
|
||||||
<item name="android:textColorPrimary">@color/colorOnPrimary</item>
|
<item name="android:textColorPrimary">@color/colorOnPrimary</item>
|
||||||
<item name="android:textColorSecondary">@color/colorOnPrimary</item>
|
<item name="android:textColorSecondary">@color/colorOnPrimary</item>
|
||||||
|
Loading…
Reference in New Issue
Block a user