mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-07-05 06:42:57 +12:00
More CirclePad Pro improvements
This commit is contained in:
parent
935e088ca1
commit
0ab8a6d956
14 changed files with 155 additions and 81 deletions
|
@ -27,6 +27,12 @@ namespace HID::Keys {
|
||||||
GPIO0Inv = 1 << 12, // Inverted value of GPIO bit 0
|
GPIO0Inv = 1 << 12, // Inverted value of GPIO bit 0
|
||||||
GPIO14Inv = 1 << 13, // Inverted value of GPIO bit 14
|
GPIO14Inv = 1 << 13, // Inverted value of GPIO bit 14
|
||||||
|
|
||||||
|
// CirclePad Pro buttons. We store them in the HID service for ease, even though they're only used by the IR service
|
||||||
|
// Whenever the HID service writes to shared memory, we remember to mask them out
|
||||||
|
ZL = 1 << 14,
|
||||||
|
ZR = 1 << 15,
|
||||||
|
CirclePadProButtons = ZL | ZR,
|
||||||
|
|
||||||
CirclePadRight = 1 << 28, // X >= 41
|
CirclePadRight = 1 << 28, // X >= 41
|
||||||
CirclePadLeft = 1 << 29, // X <= -41
|
CirclePadLeft = 1 << 29, // X <= -41
|
||||||
CirclePadUp = 1 << 30, // Y >= 41
|
CirclePadUp = 1 << 30, // Y >= 41
|
||||||
|
@ -58,6 +64,9 @@ class HIDService {
|
||||||
s16 roll, pitch, yaw; // Gyroscope state
|
s16 roll, pitch, yaw; // Gyroscope state
|
||||||
s16 accelX, accelY, accelZ; // Accelerometer state
|
s16 accelX, accelY, accelZ; // Accelerometer state
|
||||||
|
|
||||||
|
// New 3DS/CirclePad Pro C-stick state
|
||||||
|
s16 cStickX, cStickY;
|
||||||
|
|
||||||
bool accelerometerEnabled;
|
bool accelerometerEnabled;
|
||||||
bool eventsInitialized;
|
bool eventsInitialized;
|
||||||
bool gyroEnabled;
|
bool gyroEnabled;
|
||||||
|
@ -113,7 +122,7 @@ class HIDService {
|
||||||
|
|
||||||
// Turn bits 28 and 29 off in the new button state, which indicate whether the circlepad is steering left or right
|
// Turn bits 28 and 29 off in the new button state, which indicate whether the circlepad is steering left or right
|
||||||
// Then, set them according to the new value of x
|
// Then, set them according to the new value of x
|
||||||
newButtons &= ~0x3000'0000;
|
newButtons &= ~(HID::Keys::CirclePadLeft | HID::Keys::CirclePadRight);
|
||||||
if (x >= 41) // Pressing right
|
if (x >= 41) // Pressing right
|
||||||
newButtons |= 1 << 28;
|
newButtons |= 1 << 28;
|
||||||
else if (x <= -41) // Pressing left
|
else if (x <= -41) // Pressing left
|
||||||
|
@ -125,13 +134,19 @@ class HIDService {
|
||||||
|
|
||||||
// Turn bits 30 and 31 off in the new button state, which indicate whether the circlepad is steering up or down
|
// Turn bits 30 and 31 off in the new button state, which indicate whether the circlepad is steering up or down
|
||||||
// Then, set them according to the new value of y
|
// Then, set them according to the new value of y
|
||||||
newButtons &= ~0xC000'0000;
|
newButtons &= ~(HID::Keys::CirclePadUp | HID::Keys::CirclePadDown);
|
||||||
if (y >= 41) // Pressing up
|
if (y >= 41) // Pressing up
|
||||||
newButtons |= 1 << 30;
|
newButtons |= 1 << 30;
|
||||||
else if (y <= -41) // Pressing down
|
else if (y <= -41) // Pressing down
|
||||||
newButtons |= 1 << 31;
|
newButtons |= 1 << 31;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setCStickX(s16 x) { cStickX = x; }
|
||||||
|
void setCStickY(s16 y) { cStickY = y; }
|
||||||
|
|
||||||
|
s16 getCStickX() { return cStickX; }
|
||||||
|
s16 getCStickY() { return cStickY; }
|
||||||
|
|
||||||
void setRoll(s16 value) { roll = value; }
|
void setRoll(s16 value) { roll = value; }
|
||||||
void setPitch(s16 value) { pitch = value; }
|
void setPitch(s16 value) { pitch = value; }
|
||||||
void setYaw(s16 value) { yaw = value; }
|
void setYaw(s16 value) { yaw = value; }
|
||||||
|
@ -157,9 +172,6 @@ class HIDService {
|
||||||
touchScreenPressed = true;
|
touchScreenPressed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void releaseTouchScreen() {
|
void releaseTouchScreen() { touchScreenPressed = false; }
|
||||||
touchScreenPressed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isTouchScreenPressed() { return touchScreenPressed; }
|
bool isTouchScreenPressed() { return touchScreenPressed; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,7 +8,6 @@ namespace IR {
|
||||||
public:
|
public:
|
||||||
struct ButtonState {
|
struct ButtonState {
|
||||||
static constexpr int C_STICK_CENTER = 0x800;
|
static constexpr int C_STICK_CENTER = 0x800;
|
||||||
static constexpr int C_STICK_RADIUS = 0x7FF;
|
|
||||||
|
|
||||||
union {
|
union {
|
||||||
BitField<0, 8, u32> header;
|
BitField<0, 8, u32> header;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
#include "result/result.hpp"
|
#include "result/result.hpp"
|
||||||
|
#include "services/hid.hpp"
|
||||||
#include "services/ir/circlepad_pro.hpp"
|
#include "services/ir/circlepad_pro.hpp"
|
||||||
|
|
||||||
// Circular dependencies in this project? Never
|
// Circular dependencies in this project? Never
|
||||||
|
@ -23,6 +24,8 @@ class IRUserService {
|
||||||
Handle handle = KernelHandles::IR_USER;
|
Handle handle = KernelHandles::IR_USER;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
Kernel& kernel;
|
Kernel& kernel;
|
||||||
|
// The IR service has a reference to the HID service as that's where the frontends store CirclePad Pro button state in
|
||||||
|
HIDService& hid;
|
||||||
const EmulatorConfig& config;
|
const EmulatorConfig& config;
|
||||||
|
|
||||||
MAKE_LOG_FUNCTION(log, irUserLogger)
|
MAKE_LOG_FUNCTION(log, irUserLogger)
|
||||||
|
@ -76,11 +79,9 @@ class IRUserService {
|
||||||
void sendPayload(std::span<const u8> payload);
|
void sendPayload(std::span<const u8> payload);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IRUserService(Memory& mem, const EmulatorConfig& config, Kernel& kernel)
|
IRUserService(Memory& mem, HIDService& hid, const EmulatorConfig& config, Kernel& kernel)
|
||||||
: mem(mem), config(config), kernel(kernel), cpp([&](IR::Device::Payload payload) { sendPayload(payload); }) {}
|
: mem(mem), hid(hid), config(config), kernel(kernel), cpp([&](IR::Device::Payload payload) { sendPayload(payload); }) {}
|
||||||
|
|
||||||
void setZRPressed(bool pressed) { cpp.state.buttons.zrNotPressed = pressed ? 0 : 1; }
|
|
||||||
void setZLPressed(bool pressed) { cpp.state.buttons.zrNotPressed = pressed ? 0 : 1; }
|
|
||||||
void setCStickX(s16 value) { cpp.state.cStick.x = value; }
|
void setCStickX(s16 value) { cpp.state.cStick.x = value; }
|
||||||
void setCStickY(s16 value) { cpp.state.cStick.y = value; }
|
void setCStickY(s16 value) { cpp.state.cStick.y = value; }
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#include "services/hid.hpp"
|
#include "services/hid.hpp"
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
|
|
||||||
#include "ipc.hpp"
|
#include "ipc.hpp"
|
||||||
#include "kernel.hpp"
|
#include "kernel.hpp"
|
||||||
#include <bit>
|
|
||||||
|
|
||||||
namespace HIDCommands {
|
namespace HIDCommands {
|
||||||
enum : u32 {
|
enum : u32 {
|
||||||
|
@ -36,6 +38,8 @@ void HIDService::reset() {
|
||||||
touchScreenX = touchScreenY = 0;
|
touchScreenX = touchScreenY = 0;
|
||||||
roll = pitch = yaw = 0;
|
roll = pitch = yaw = 0;
|
||||||
accelX = accelY = accelZ = 0;
|
accelX = accelY = accelZ = 0;
|
||||||
|
|
||||||
|
cStickX = cStickY = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HIDService::handleSyncRequest(u32 messagePointer) {
|
void HIDService::handleSyncRequest(u32 messagePointer) {
|
||||||
|
@ -87,17 +91,17 @@ void HIDService::disableGyroscopeLow(u32 messagePointer) {
|
||||||
|
|
||||||
void HIDService::getGyroscopeLowCalibrateParam(u32 messagePointer) {
|
void HIDService::getGyroscopeLowCalibrateParam(u32 messagePointer) {
|
||||||
log("HID::GetGyroscopeLowCalibrateParam\n");
|
log("HID::GetGyroscopeLowCalibrateParam\n");
|
||||||
constexpr s16 unit = 6700; // Approximately from Citra which took it from hardware
|
constexpr s16 unit = 6700; // Approximately from Citra which took it from hardware
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x16, 6, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x16, 6, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
// Fill calibration data (for x/y/z depending on i)
|
// Fill calibration data (for x/y/z depending on i)
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
const u32 pointer = messagePointer + 8 + i * 3 * sizeof(u16); // Pointer to write the calibration info for the current coordinate
|
const u32 pointer = messagePointer + 8 + i * 3 * sizeof(u16); // Pointer to write the calibration info for the current coordinate
|
||||||
|
|
||||||
mem.write16(pointer, 0); // Zero point
|
mem.write16(pointer, 0); // Zero point
|
||||||
mem.write16(pointer + 1 * sizeof(u16), unit); // Positive unit point
|
mem.write16(pointer + 1 * sizeof(u16), unit); // Positive unit point
|
||||||
mem.write16(pointer + 2 * sizeof(u16), -unit); // Negative unit point
|
mem.write16(pointer + 2 * sizeof(u16), -unit); // Negative unit point
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,9 +138,9 @@ void HIDService::getIPCHandles(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0xA, 1, 7));
|
mem.write32(messagePointer, IPC::responseHeader(0xA, 1, 7));
|
||||||
mem.write32(messagePointer + 4, Result::Success); // Result code
|
mem.write32(messagePointer + 4, Result::Success); // Result code
|
||||||
mem.write32(messagePointer + 8, 0x14000000); // Translation descriptor
|
mem.write32(messagePointer + 8, 0x14000000); // Translation descriptor
|
||||||
mem.write32(messagePointer + 12, KernelHandles::HIDSharedMemHandle); // Shared memory handle
|
mem.write32(messagePointer + 12, KernelHandles::HIDSharedMemHandle); // Shared memory handle
|
||||||
|
|
||||||
// Write HID event handles
|
// Write HID event handles
|
||||||
for (int i = 0; i < events.size(); i++) {
|
for (int i = 0; i < events.size(); i++) {
|
||||||
|
@ -149,23 +153,27 @@ void HIDService::updateInputs(u64 currentTick) {
|
||||||
if (sharedMem) {
|
if (sharedMem) {
|
||||||
// First, update the pad state
|
// First, update the pad state
|
||||||
if (nextPadIndex == 0) {
|
if (nextPadIndex == 0) {
|
||||||
writeSharedMem<u64>(0x8, readSharedMem<u64>(0x0)); // Copy previous tick count
|
writeSharedMem<u64>(0x8, readSharedMem<u64>(0x0)); // Copy previous tick count
|
||||||
writeSharedMem<u64>(0x0, currentTick); // Write new tick count
|
writeSharedMem<u64>(0x0, currentTick); // Write new tick count
|
||||||
}
|
}
|
||||||
|
|
||||||
writeSharedMem<u32>(0x10, nextPadIndex); // Index last updated by the HID module
|
// Mask out the CirclePadPro buttons when writing to HID shared memory, since the actual OS doesn't store anything in those bits
|
||||||
writeSharedMem<u32>(0x1C, newButtons); // Current PAD state
|
const u32 currentButtons = newButtons & ~HID::Keys::CirclePadProButtons;
|
||||||
writeSharedMem<s16>(0x20, circlePadX); // Current circle pad state
|
const u32 previousButtons = oldButtons & ~HID::Keys::CirclePadProButtons;
|
||||||
writeSharedMem<s16>(0x22, circlePadY);
|
|
||||||
|
|
||||||
const size_t padEntryOffset = 0x28 + (nextPadIndex * 0x10); // Offset in the array of 8 pad entries
|
|
||||||
nextPadIndex = (nextPadIndex + 1) % 8; // Move to next entry
|
|
||||||
|
|
||||||
const u32 pressed = (newButtons ^ oldButtons) & newButtons; // Pressed buttons
|
|
||||||
const u32 released = (newButtons ^ oldButtons) & oldButtons; // Released buttons
|
|
||||||
oldButtons = newButtons;
|
oldButtons = newButtons;
|
||||||
|
|
||||||
writeSharedMem<u32>(padEntryOffset, newButtons);
|
writeSharedMem<u32>(0x10, nextPadIndex); // Index last updated by the HID module
|
||||||
|
writeSharedMem<u32>(0x1C, currentButtons); // Current PAD state
|
||||||
|
writeSharedMem<s16>(0x20, circlePadX); // Current circle pad state
|
||||||
|
writeSharedMem<s16>(0x22, circlePadY);
|
||||||
|
|
||||||
|
const size_t padEntryOffset = 0x28 + (nextPadIndex * 0x10); // Offset in the array of 8 pad entries
|
||||||
|
nextPadIndex = (nextPadIndex + 1) % 8; // Move to next entry
|
||||||
|
|
||||||
|
const u32 pressed = (currentButtons ^ previousButtons) & currentButtons; // Pressed buttons
|
||||||
|
const u32 released = (currentButtons ^ previousButtons) & previousButtons; // Released buttons
|
||||||
|
|
||||||
|
writeSharedMem<u32>(padEntryOffset, currentButtons);
|
||||||
writeSharedMem<u32>(padEntryOffset + 4, pressed);
|
writeSharedMem<u32>(padEntryOffset + 4, pressed);
|
||||||
writeSharedMem<u32>(padEntryOffset + 8, released);
|
writeSharedMem<u32>(padEntryOffset + 8, released);
|
||||||
writeSharedMem<s16>(padEntryOffset + 12, circlePadX);
|
writeSharedMem<s16>(padEntryOffset + 12, circlePadX);
|
||||||
|
@ -173,12 +181,12 @@ void HIDService::updateInputs(u64 currentTick) {
|
||||||
|
|
||||||
// Next, update touchscreen state
|
// Next, update touchscreen state
|
||||||
if (nextTouchscreenIndex == 0) {
|
if (nextTouchscreenIndex == 0) {
|
||||||
writeSharedMem<u64>(0xB0, readSharedMem<u64>(0xA8)); // Copy previous tick count
|
writeSharedMem<u64>(0xB0, readSharedMem<u64>(0xA8)); // Copy previous tick count
|
||||||
writeSharedMem<u64>(0xA8, currentTick); // Write new tick count
|
writeSharedMem<u64>(0xA8, currentTick); // Write new tick count
|
||||||
}
|
}
|
||||||
writeSharedMem<u32>(0xB8, nextTouchscreenIndex); // Index last updated by the HID module
|
writeSharedMem<u32>(0xB8, nextTouchscreenIndex); // Index last updated by the HID module
|
||||||
const size_t touchEntryOffset = 0xC8 + (nextTouchscreenIndex * 8); // Offset in the array of 8 touchscreen entries
|
const size_t touchEntryOffset = 0xC8 + (nextTouchscreenIndex * 8); // Offset in the array of 8 touchscreen entries
|
||||||
nextTouchscreenIndex = (nextTouchscreenIndex + 1) % 8; // Move to next entry
|
nextTouchscreenIndex = (nextTouchscreenIndex + 1) % 8; // Move to next entry
|
||||||
|
|
||||||
writeSharedMem<u16>(touchEntryOffset, touchScreenX);
|
writeSharedMem<u16>(touchEntryOffset, touchScreenX);
|
||||||
writeSharedMem<u16>(touchEntryOffset + 2, touchScreenY);
|
writeSharedMem<u16>(touchEntryOffset + 2, touchScreenY);
|
||||||
|
@ -186,10 +194,10 @@ void HIDService::updateInputs(u64 currentTick) {
|
||||||
|
|
||||||
// Next, update accelerometer state
|
// Next, update accelerometer state
|
||||||
if (nextAccelerometerIndex == 0) {
|
if (nextAccelerometerIndex == 0) {
|
||||||
writeSharedMem<u64>(0x110, readSharedMem<u64>(0x108)); // Copy previous tick count
|
writeSharedMem<u64>(0x110, readSharedMem<u64>(0x108)); // Copy previous tick count
|
||||||
writeSharedMem<u64>(0x108, currentTick); // Write new tick count
|
writeSharedMem<u64>(0x108, currentTick); // Write new tick count
|
||||||
}
|
}
|
||||||
writeSharedMem<u32>(0x118, nextAccelerometerIndex); // Index last updated by the HID module
|
writeSharedMem<u32>(0x118, nextAccelerometerIndex); // Index last updated by the HID module
|
||||||
const size_t accelEntryOffset = 0x128 + (nextAccelerometerIndex * 6); // Offset in the array of 8 accelerometer entries
|
const size_t accelEntryOffset = 0x128 + (nextAccelerometerIndex * 6); // Offset in the array of 8 accelerometer entries
|
||||||
|
|
||||||
// Raw data of current accelerometer entry
|
// Raw data of current accelerometer entry
|
||||||
|
@ -204,12 +212,12 @@ void HIDService::updateInputs(u64 currentTick) {
|
||||||
accelerometerData[0] = accelX;
|
accelerometerData[0] = accelX;
|
||||||
accelerometerData[1] = accelY;
|
accelerometerData[1] = accelY;
|
||||||
accelerometerData[2] = accelZ;
|
accelerometerData[2] = accelZ;
|
||||||
nextAccelerometerIndex = (nextAccelerometerIndex + 1) % 8; // Move to next entry
|
nextAccelerometerIndex = (nextAccelerometerIndex + 1) % 8; // Move to next entry
|
||||||
|
|
||||||
// Next, update gyro state
|
// Next, update gyro state
|
||||||
if (nextGyroIndex == 0) {
|
if (nextGyroIndex == 0) {
|
||||||
writeSharedMem<u64>(0x160, readSharedMem<u64>(0x158)); // Copy previous tick count
|
writeSharedMem<u64>(0x160, readSharedMem<u64>(0x158)); // Copy previous tick count
|
||||||
writeSharedMem<u64>(0x158, currentTick); // Write new tick count
|
writeSharedMem<u64>(0x158, currentTick); // Write new tick count
|
||||||
}
|
}
|
||||||
const size_t gyroEntryOffset = 0x178 + (nextGyroIndex * 6); // Offset in the array of 8 touchscreen entries
|
const size_t gyroEntryOffset = 0x178 + (nextGyroIndex * 6); // Offset in the array of 8 touchscreen entries
|
||||||
s16* gyroData = getSharedMemPointer<s16>(gyroEntryOffset);
|
s16* gyroData = getSharedMemPointer<s16>(gyroEntryOffset);
|
||||||
|
@ -220,8 +228,8 @@ void HIDService::updateInputs(u64 currentTick) {
|
||||||
// Since gyroscope euler angles are relative, we zero them out here and the frontend will update them again when we receive a new rotation
|
// Since gyroscope euler angles are relative, we zero them out here and the frontend will update them again when we receive a new rotation
|
||||||
roll = pitch = yaw = 0;
|
roll = pitch = yaw = 0;
|
||||||
|
|
||||||
writeSharedMem<u32>(0x168, nextGyroIndex); // Index last updated by the HID module
|
writeSharedMem<u32>(0x168, nextGyroIndex); // Index last updated by the HID module
|
||||||
nextGyroIndex = (nextGyroIndex + 1) % 32; // Move to next entry
|
nextGyroIndex = (nextGyroIndex + 1) % 32; // Move to next entry
|
||||||
}
|
}
|
||||||
|
|
||||||
// For some reason, the original developers decided to signal the HID events each time the OS rescanned inputs
|
// For some reason, the original developers decided to signal the HID events each time the OS rescanned inputs
|
||||||
|
|
|
@ -333,7 +333,17 @@ void IRUserService::updateCirclePadPro() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> response(sizeof(cpp.state));
|
// The button state for the CirclePad Pro is stored in the HID service to make the frontend logic simpler
|
||||||
std::memcpy(response.data(), &cpp.state, sizeof(cpp.state));
|
// We take the button state, format it nicely into the CirclePad Pro struct, and return it
|
||||||
|
auto& cppState = cpp.state;
|
||||||
|
u32 buttons = hid.getOldButtons();
|
||||||
|
|
||||||
|
cppState.buttons.zlNotPressed = (buttons & HID::Keys::ZL) ? 0 : 1;
|
||||||
|
cppState.buttons.zrNotPressed = (buttons & HID::Keys::ZR) ? 0 : 1;
|
||||||
|
cppState.cStick.x = hid.getCStickX();
|
||||||
|
cppState.cStick.y = hid.getCStickY();
|
||||||
|
|
||||||
|
std::vector<u8> response(sizeof(cppState));
|
||||||
|
std::memcpy(response.data(), &cppState, sizeof(cppState));
|
||||||
sendPayload(response);
|
sendPayload(response);
|
||||||
}
|
}
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
ServiceManager::ServiceManager(std::span<u32, 16> regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel, const EmulatorConfig& config)
|
ServiceManager::ServiceManager(std::span<u32, 16> regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel, const EmulatorConfig& config)
|
||||||
: regs(regs), mem(mem), kernel(kernel), ac(mem), am(mem), boss(mem), act(mem), apt(mem, kernel), cam(mem, kernel), cecd(mem, kernel),
|
: regs(regs), mem(mem), kernel(kernel), ac(mem), am(mem), boss(mem), act(mem), apt(mem, kernel), cam(mem, kernel), cecd(mem, kernel),
|
||||||
cfg(mem, config), csnd(mem, kernel), dlp_srvr(mem), dsp(mem, kernel, config), hid(mem, kernel), http(mem), ir_user(mem, config, kernel),
|
cfg(mem, config), csnd(mem, kernel), dlp_srvr(mem), dsp(mem, kernel, config), hid(mem, kernel), http(mem), ir_user(mem, hid, config, kernel),
|
||||||
frd(mem), fs(mem, kernel, config), gsp_gpu(mem, gpu, kernel, currentPID), gsp_lcd(mem), ldr(mem, kernel), mcu_hwc(mem, config),
|
frd(mem), fs(mem, kernel, config), gsp_gpu(mem, gpu, kernel, currentPID), gsp_lcd(mem), ldr(mem, kernel), mcu_hwc(mem, config),
|
||||||
mic(mem, kernel), nfc(mem, kernel), nim(mem), ndm(mem), news_u(mem), ns(mem), nwm_uds(mem, kernel), ptm(mem, config), soc(mem), ssl(mem),
|
mic(mem, kernel), nfc(mem, kernel), nim(mem), ndm(mem), news_u(mem), ns(mem), nwm_uds(mem, kernel), ptm(mem, config), soc(mem), ssl(mem),
|
||||||
y2r(mem, kernel) {}
|
y2r(mem, kernel) {}
|
||||||
|
|
|
@ -93,8 +93,10 @@ HttpServer::HttpServer(Emulator* emulator)
|
||||||
{"Left", {HID::Keys::Left}},
|
{"Left", {HID::Keys::Left}},
|
||||||
{"Up", {HID::Keys::Up}},
|
{"Up", {HID::Keys::Up}},
|
||||||
{"Down", {HID::Keys::Down}},
|
{"Down", {HID::Keys::Down}},
|
||||||
{"R", {HID::Keys::R}},
|
|
||||||
{"L", {HID::Keys::L}},
|
{"L", {HID::Keys::L}},
|
||||||
|
{"R", {HID::Keys::R}},
|
||||||
|
{"ZL", {HID::Keys::ZL}},
|
||||||
|
{"ZR", {HID::Keys::ZR}},
|
||||||
{"X", {HID::Keys::X}},
|
{"X", {HID::Keys::X}},
|
||||||
{"Y", {HID::Keys::Y}},
|
{"Y", {HID::Keys::Y}},
|
||||||
}) {
|
}) {
|
||||||
|
|
|
@ -82,6 +82,7 @@ void HydraCore::runFrame() {
|
||||||
hid.setKey(HID::Keys::Down, checkButtonCallback(0, hydra::ButtonType::Keypad1Down));
|
hid.setKey(HID::Keys::Down, checkButtonCallback(0, hydra::ButtonType::Keypad1Down));
|
||||||
hid.setKey(HID::Keys::Left, checkButtonCallback(0, hydra::ButtonType::Keypad1Left));
|
hid.setKey(HID::Keys::Left, checkButtonCallback(0, hydra::ButtonType::Keypad1Left));
|
||||||
hid.setKey(HID::Keys::Right, checkButtonCallback(0, hydra::ButtonType::Keypad1Right));
|
hid.setKey(HID::Keys::Right, checkButtonCallback(0, hydra::ButtonType::Keypad1Right));
|
||||||
|
// TODO: N3DS buttons
|
||||||
|
|
||||||
int x = !!checkButtonCallback(0, hydra::ButtonType::Analog1Right) - !!checkButtonCallback(0, hydra::ButtonType::Analog1Left);
|
int x = !!checkButtonCallback(0, hydra::ButtonType::Analog1Right) - !!checkButtonCallback(0, hydra::ButtonType::Analog1Left);
|
||||||
int y = !!checkButtonCallback(0, hydra::ButtonType::Analog1Up) - !!checkButtonCallback(0, hydra::ButtonType::Analog1Down);
|
int y = !!checkButtonCallback(0, hydra::ButtonType::Analog1Up) - !!checkButtonCallback(0, hydra::ButtonType::Analog1Down);
|
||||||
|
|
|
@ -351,6 +351,7 @@ void retro_run() {
|
||||||
hid.setKey(HID::Keys::Down, getButtonState(RETRO_DEVICE_ID_JOYPAD_DOWN));
|
hid.setKey(HID::Keys::Down, getButtonState(RETRO_DEVICE_ID_JOYPAD_DOWN));
|
||||||
hid.setKey(HID::Keys::Left, getButtonState(RETRO_DEVICE_ID_JOYPAD_LEFT));
|
hid.setKey(HID::Keys::Left, getButtonState(RETRO_DEVICE_ID_JOYPAD_LEFT));
|
||||||
hid.setKey(HID::Keys::Right, getButtonState(RETRO_DEVICE_ID_JOYPAD_RIGHT));
|
hid.setKey(HID::Keys::Right, getButtonState(RETRO_DEVICE_ID_JOYPAD_RIGHT));
|
||||||
|
// TODO: N3DS buttons
|
||||||
|
|
||||||
// Get analog values for the left analog stick (Right analog stick is N3DS-only and unimplemented)
|
// Get analog values for the left analog stick (Right analog stick is N3DS-only and unimplemented)
|
||||||
float xLeft = getAxisState(RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X);
|
float xLeft = getAxisState(RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X);
|
||||||
|
|
|
@ -367,6 +367,8 @@ void LuaManager::initializeThunks() {
|
||||||
addIntConstant(HID::Keys::Right, "__ButtonRight");
|
addIntConstant(HID::Keys::Right, "__ButtonRight");
|
||||||
addIntConstant(HID::Keys::L, "__ButtonL");
|
addIntConstant(HID::Keys::L, "__ButtonL");
|
||||||
addIntConstant(HID::Keys::R, "__ButtonR");
|
addIntConstant(HID::Keys::R, "__ButtonR");
|
||||||
|
addIntConstant(HID::Keys::ZL, "__ButtonZL");
|
||||||
|
addIntConstant(HID::Keys::ZR, "__ButtonZR");
|
||||||
|
|
||||||
// Call our Lua runtime initialization before any Lua script runs
|
// Call our Lua runtime initialization before any Lua script runs
|
||||||
luaL_loadstring(L, runtimeInit);
|
luaL_loadstring(L, runtimeInit);
|
||||||
|
|
|
@ -592,47 +592,53 @@ void MainWindow::initControllers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::pollControllers() {
|
void MainWindow::pollControllers() {
|
||||||
// Update circlepad if a controller is plugged in
|
// Update circlepad/c-stick/ZL/ZR if a controller is plugged in
|
||||||
if (gameController != nullptr) {
|
if (gameController != nullptr) {
|
||||||
HIDService& hid = emu->getServiceManager().getHID();
|
HIDService& hid = emu->getServiceManager().getHID();
|
||||||
const s16 stickX = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_LEFTX);
|
const s16 stickX = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_LEFTX);
|
||||||
const s16 stickY = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_LEFTY);
|
const s16 stickY = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_LEFTY);
|
||||||
constexpr s16 deadzone = 3276;
|
constexpr s16 deadzone = 3276;
|
||||||
constexpr s16 maxValue = 0x9C;
|
constexpr s16 triggerThreshold = SDL_JOYSTICK_AXIS_MAX / 2;
|
||||||
constexpr s16 div = 0x8000 / maxValue;
|
|
||||||
|
|
||||||
// Avoid overriding the keyboard's circlepad input
|
{
|
||||||
if (std::abs(stickX) < deadzone && !keyboardAnalogX) {
|
// Update circlepad
|
||||||
hid.setCirclepadX(0);
|
constexpr s16 circlepadMax = 0x9C;
|
||||||
} else {
|
constexpr s16 div = 0x8000 / circlepadMax;
|
||||||
hid.setCirclepadX(stickX / div);
|
|
||||||
|
// Avoid overriding the keyboard's circlepad input
|
||||||
|
if (std::abs(stickX) < deadzone && !keyboardAnalogX) {
|
||||||
|
hid.setCirclepadX(0);
|
||||||
|
} else {
|
||||||
|
hid.setCirclepadX(stickX / div);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::abs(stickY) < deadzone && !keyboardAnalogY) {
|
||||||
|
hid.setCirclepadY(0);
|
||||||
|
} else {
|
||||||
|
hid.setCirclepadY(-(stickY / div));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::abs(stickY) < deadzone && !keyboardAnalogY) {
|
|
||||||
hid.setCirclepadY(0);
|
|
||||||
} else {
|
|
||||||
hid.setCirclepadY(-(stickY / div));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& ir = emu->getServiceManager().getIRUser();
|
|
||||||
const s16 l2 = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_TRIGGERLEFT);
|
const s16 l2 = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_TRIGGERLEFT);
|
||||||
const s16 r2 = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
|
const s16 r2 = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
|
||||||
const s16 cstickX = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_RIGHTX);
|
const s16 cstickX = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_RIGHTX);
|
||||||
const s16 cstickY = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_RIGHTY);
|
const s16 cstickY = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_RIGHTY);
|
||||||
|
|
||||||
ir.setZLPressed(l2 > 16000);
|
hid.setKey(HID::Keys::ZL, l2 > triggerThreshold);
|
||||||
ir.setZRPressed(r2 > 16000);
|
hid.setKey(HID::Keys::ZR, r2 > triggerThreshold);
|
||||||
|
|
||||||
|
// Update C-Stick
|
||||||
|
// To convert from SDL coordinates, ie [-32768, 32767] to [-2048, 2047] we just divide by 8
|
||||||
if (std::abs(cstickX) < deadzone) {
|
if (std::abs(cstickX) < deadzone) {
|
||||||
ir.setCStickX(IR::CirclePadPro::ButtonState::C_STICK_CENTER);
|
hid.setCStickX(IR::CirclePadPro::ButtonState::C_STICK_CENTER);
|
||||||
} else {
|
} else {
|
||||||
ir.setCStickX(cstickX / 8);
|
hid.setCStickX(cstickX / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::abs(cstickY) < deadzone) {
|
if (std::abs(cstickY) < deadzone) {
|
||||||
ir.setCStickY(IR::CirclePadPro::ButtonState::C_STICK_CENTER);
|
hid.setCStickY(IR::CirclePadPro::ButtonState::C_STICK_CENTER);
|
||||||
} else {
|
} else {
|
||||||
ir.setCStickY(-(cstickY / 8));
|
hid.setCStickY(-(cstickY / 8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ InputMappings InputMappings::defaultKeyboardMappings() {
|
||||||
mappings.setMapping(Qt::Key_I, HID::Keys::Y);
|
mappings.setMapping(Qt::Key_I, HID::Keys::Y);
|
||||||
mappings.setMapping(Qt::Key_Q, HID::Keys::L);
|
mappings.setMapping(Qt::Key_Q, HID::Keys::L);
|
||||||
mappings.setMapping(Qt::Key_P, HID::Keys::R);
|
mappings.setMapping(Qt::Key_P, HID::Keys::R);
|
||||||
|
mappings.setMapping(Qt::Key_1, HID::Keys::ZL);
|
||||||
|
mappings.setMapping(Qt::Key_0, HID::Keys::ZR);
|
||||||
mappings.setMapping(Qt::Key_Up, HID::Keys::Up);
|
mappings.setMapping(Qt::Key_Up, HID::Keys::Up);
|
||||||
mappings.setMapping(Qt::Key_Down, HID::Keys::Down);
|
mappings.setMapping(Qt::Key_Down, HID::Keys::Down);
|
||||||
mappings.setMapping(Qt::Key_Right, HID::Keys::Right);
|
mappings.setMapping(Qt::Key_Right, HID::Keys::Right);
|
||||||
|
|
|
@ -401,24 +401,52 @@ void FrontendSDL::run() {
|
||||||
|
|
||||||
// Update controller analog sticks and HID service
|
// Update controller analog sticks and HID service
|
||||||
if (emu.romType != ROMType::None) {
|
if (emu.romType != ROMType::None) {
|
||||||
|
// Update circlepad/c-stick/ZL/ZR if a controller is plugged in
|
||||||
if (gameController != nullptr) {
|
if (gameController != nullptr) {
|
||||||
const s16 stickX = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_LEFTX);
|
const s16 stickX = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_LEFTX);
|
||||||
const s16 stickY = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_LEFTY);
|
const s16 stickY = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_LEFTY);
|
||||||
constexpr s16 deadzone = 3276;
|
constexpr s16 deadzone = 3276;
|
||||||
constexpr s16 maxValue = 0x9C;
|
constexpr s16 triggerThreshold = SDL_JOYSTICK_AXIS_MAX / 2;
|
||||||
constexpr s16 div = 0x8000 / maxValue;
|
|
||||||
|
|
||||||
// Avoid overriding the keyboard's circlepad input
|
{
|
||||||
if (abs(stickX) < deadzone && !keyboardAnalogX) {
|
// Update circlepad
|
||||||
hid.setCirclepadX(0);
|
constexpr s16 circlepadMax = 0x9C;
|
||||||
} else {
|
constexpr s16 div = 0x8000 / circlepadMax;
|
||||||
hid.setCirclepadX(stickX / div);
|
|
||||||
|
// Avoid overriding the keyboard's circlepad input
|
||||||
|
if (std::abs(stickX) < deadzone && !keyboardAnalogX) {
|
||||||
|
hid.setCirclepadX(0);
|
||||||
|
} else {
|
||||||
|
hid.setCirclepadX(stickX / div);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::abs(stickY) < deadzone && !keyboardAnalogY) {
|
||||||
|
hid.setCirclepadY(0);
|
||||||
|
} else {
|
||||||
|
hid.setCirclepadY(-(stickY / div));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (abs(stickY) < deadzone && !keyboardAnalogY) {
|
const s16 l2 = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_TRIGGERLEFT);
|
||||||
hid.setCirclepadY(0);
|
const s16 r2 = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
|
||||||
|
const s16 cstickX = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_RIGHTX);
|
||||||
|
const s16 cstickY = SDL_GameControllerGetAxis(gameController, SDL_CONTROLLER_AXIS_RIGHTY);
|
||||||
|
|
||||||
|
hid.setKey(HID::Keys::ZL, l2 > triggerThreshold);
|
||||||
|
hid.setKey(HID::Keys::ZR, r2 > triggerThreshold);
|
||||||
|
|
||||||
|
// Update C-Stick
|
||||||
|
// To convert from SDL coordinates, ie [-32768, 32767] to [-2048, 2047] we just divide by 8
|
||||||
|
if (std::abs(cstickX) < deadzone) {
|
||||||
|
hid.setCStickX(IR::CirclePadPro::ButtonState::C_STICK_CENTER);
|
||||||
} else {
|
} else {
|
||||||
hid.setCirclepadY(-(stickY / div));
|
hid.setCStickX(cstickX / 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::abs(cstickY) < deadzone) {
|
||||||
|
hid.setCStickY(IR::CirclePadPro::ButtonState::C_STICK_CENTER);
|
||||||
|
} else {
|
||||||
|
hid.setCStickY(-(cstickY / 8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ InputMappings InputMappings::defaultKeyboardMappings() {
|
||||||
mappings.setMapping(SDLK_i, HID::Keys::Y);
|
mappings.setMapping(SDLK_i, HID::Keys::Y);
|
||||||
mappings.setMapping(SDLK_q, HID::Keys::L);
|
mappings.setMapping(SDLK_q, HID::Keys::L);
|
||||||
mappings.setMapping(SDLK_p, HID::Keys::R);
|
mappings.setMapping(SDLK_p, HID::Keys::R);
|
||||||
|
mappings.setMapping(SDLK_1, HID::Keys::ZL);
|
||||||
|
mappings.setMapping(SDLK_0, HID::Keys::ZR);
|
||||||
mappings.setMapping(SDLK_UP, HID::Keys::Up);
|
mappings.setMapping(SDLK_UP, HID::Keys::Up);
|
||||||
mappings.setMapping(SDLK_DOWN, HID::Keys::Down);
|
mappings.setMapping(SDLK_DOWN, HID::Keys::Down);
|
||||||
mappings.setMapping(SDLK_RIGHT, HID::Keys::Right);
|
mappings.setMapping(SDLK_RIGHT, HID::Keys::Right);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue