diff --git a/include/emulator.hpp b/include/emulator.hpp index 33f1ae6e..e1684085 100644 --- a/include/emulator.hpp +++ b/include/emulator.hpp @@ -37,6 +37,10 @@ class Emulator { bool keyboardAnalogX = false; bool keyboardAnalogY = false; + // For tracking whether to update gyroscope + // We bind gyro to right click + mouse movement + bool holdingRightClick = false; + static constexpr u32 width = 400; static constexpr u32 height = 240 * 2; // * 2 because 2 screens ROMType romType = ROMType::None; diff --git a/include/services/hid.hpp b/include/services/hid.hpp index 70bae750..6a3aab95 100644 --- a/include/services/hid.hpp +++ b/include/services/hid.hpp @@ -52,6 +52,7 @@ class HIDService { s16 circlePadX, circlePadY; // Circlepad state s16 touchScreenX, touchScreenY; // Touchscreen state + s16 roll, pitch, yaw; // Gyroscope state bool accelerometerEnabled; bool eventsInitialized; @@ -117,6 +118,10 @@ class HIDService { newButtons |= 1 << 31; } + void setRoll(s16 value) { roll = value; } + void setPitch(s16 value) { pitch = value; } + void setYaw(s16 value) { yaw = value; } + void updateInputs(u64 currentTimestamp); void setSharedMem(u8* ptr) { diff --git a/include/services/service_manager.hpp b/include/services/service_manager.hpp index 3136408f..1d93641c 100644 --- a/include/services/service_manager.hpp +++ b/include/services/service_manager.hpp @@ -99,4 +99,8 @@ class ServiceManager { void updateInputs(u64 currentTimestamp) { hid.updateInputs(currentTimestamp); } void setTouchScreenPress(u16 x, u16 y) { hid.setTouchScreenPress(x, y); } void releaseTouchScreen() { hid.releaseTouchScreen(); } + + void setRoll(s16 roll) { hid.setRoll(roll); } + void setPitch(s16 pitch) { hid.setPitch(pitch); } + void setYaw(s16 yaw) { hid.setYaw(yaw); } }; diff --git a/readme.md b/readme.md index 964b8e56..507ddc37 100644 --- a/readme.md +++ b/readme.md @@ -59,7 +59,8 @@ Keyboard & Mouse - R button P - Start button Enter - Select button Backspace -- Touch Screen Left click +- Touch Screen Left click +- Gyroscope Hold right click and swipe your mouse left and right (support is kind of shaky atm, but games that require gyro here and there like Kirby should work) Panda3DS also supports controller input using the SDL2 GameController API. diff --git a/src/core/services/hid.cpp b/src/core/services/hid.cpp index 27a078f2..0c83487c 100644 --- a/src/core/services/hid.cpp +++ b/src/core/services/hid.cpp @@ -33,6 +33,7 @@ void HIDService::reset() { newButtons = oldButtons = 0; circlePadX = circlePadY = 0; touchScreenX = touchScreenY = 0; + roll = pitch = yaw = 0; } void HIDService::handleSyncRequest(u32 messagePointer) { @@ -182,6 +183,14 @@ void HIDService::updateInputs(u64 currentTick) { writeSharedMem(0x160, readSharedMem(0x158)); // Copy previous tick count writeSharedMem(0x158, currentTick); // Write new tick count } + const size_t gyroEntryOffset = 0x178 + (nextGyroIndex * 6); // Offset in the array of 8 touchscreen entries + writeSharedMem(gyroEntryOffset, pitch); + writeSharedMem(gyroEntryOffset + 2, yaw); + writeSharedMem(gyroEntryOffset + 4, roll); + + // 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; + writeSharedMem(0x168, nextGyroIndex); // Index last updated by the HID module nextGyroIndex = (nextGyroIndex + 1) % 32; // Move to next entry } diff --git a/src/emulator.cpp b/src/emulator.cpp index 7ca9e26d..198c573d 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -192,6 +192,8 @@ void Emulator::run() { } else { srv.releaseTouchScreen(); } + } else if (event.button.button == SDL_BUTTON_RIGHT) { + holdingRightClick = true; } break; } @@ -199,6 +201,8 @@ void Emulator::run() { case SDL_MOUSEBUTTONUP: if (event.button.button == SDL_BUTTON_LEFT) { srv.releaseTouchScreen(); + } else if (event.button.button == SDL_BUTTON_RIGHT) { + holdingRightClick = false; } break; @@ -244,6 +248,24 @@ void Emulator::run() { } } } + + // Detect mouse motion events for gyroscope emulation + case SDL_MOUSEMOTION: { + // We use right click to indicate we want to rotate the console. If right click is not held, then this is not a gyroscope rotation + if (!holdingRightClick) break; + + // Relative motion since last mouse motion event + const s32 motionX = event.motion.xrel; + const s32 motionY = event.motion.yrel; + + // The gyroscope involves lots of weird math I don't want to bother with atm + // So up until then, we will set the gyroscope euler angles to fixed values based on the direction of the relative motion + const s32 roll = motionX > 0 ? 0x7f : -0x7f; + const s32 pitch = motionY > 0 ? 0x7f : -0x7f; + srv.setRoll(roll); + srv.setPitch(pitch); + break; + } } }