iOS: Feed the gyroscope into tilt input

Same as Android: rotation rates go to NativeGyroscope, and SYSPROP_HAS_GYRO shows the "Use gyroscope" option.

Accelerometer data is now scaled from g to m/s^2, like Android's. Tilt normalizes it, but the gyro fusion only trusts the accelerometer when it reads about 9.81, so in g it would never correct drift.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-10-21 14:00:33 +02:00
1 parent 3647b9e8a4
commit cdf9d38dca
5 files changed
+42 -1

No files matched your search

+1
View File
@@ -66,6 +66,7 @@ void NativeResized();
void NativeTouch(const TouchInput &touch);
bool NativeKey(const KeyInput &key);
void NativeAxis(const AxisInput *axis, size_t count);
// In m/s^2, the way Android reports it: about +9.81 on z with the device lying screen up.
void NativeAccelerometer(float tiltX, float tiltY, float tiltZ);
// Angular rates in rad/s around the NativeAccelerometer axes. The timestamp is in seconds, on any clock (only deltas are used).
void NativeGyroscope(float x, float y, float z, double timestamp);
+1
View File
@@ -34,6 +34,7 @@ private:
#if !PPSSPP_PLATFORM(TVOS)
void ProcessAccelerometerData(CMAccelerometerData *accData);
void ProcessGyroData(CMGyroData *gyroData);
#endif
InputKeyCode HIDUsageToInputKeyCode(UIKeyboardHIDUsage usage);
+9 -1
View File
@@ -385,8 +385,16 @@ void ProcessAccelerometerData(CMAccelerometerData *accData) {
CMAcceleration acc = accData.acceleration;
// INFO_LOG(SYSTEM, "%f %f %f", acc.x, acc.y, acc.z);
// Core Motion reports acceleration in g, with the opposite sign of Android's m/s^2.
// Might need to change these for portrait or inverse landscape
NativeAccelerometer(-acc.x, -acc.y, -acc.z);
const float standardGravity = 9.81f;
NativeAccelerometer(-acc.x * standardGravity, -acc.y * standardGravity, -acc.z * standardGravity);
}
void ProcessGyroData(CMGyroData *gyroData) {
// Same axes and units (rad/s, right-handed) as Android.
CMRotationRate rate = gyroData.rotationRate;
NativeGyroscope(rate.x, rate.y, rate.z, gyroData.timestamp);
}
#endif
+19
View File
@@ -312,6 +312,21 @@ static int GetPickerRequestId(id picker) {
} else {
INFO_LOG(Log::G3D, "No accelerometer available, not starting updates.");
}
if (self.motionManager.gyroAvailable) {
self.motionManager.gyroUpdateInterval = 1.0 / 60.0;
INFO_LOG(Log::G3D, "Starting gyro updates.");
// Same serial queue as the accelerometer, so the two don't race in the tilt fusion.
[self.motionManager startGyroUpdatesToQueue:self.accelerometerQueue
withHandler:^(CMGyroData *gyroData, NSError *error) {
if (error) {
NSLog(@"Gyro error: %@", error);
return;
}
ProcessGyroData(gyroData);
}];
}
#endif
// Spin up the render thread, which in turn starts the emu thread.
@@ -328,6 +343,10 @@ static int GetPickerRequestId(id picker) {
INFO_LOG(Log::G3D, "Stopping accelerometer updates");
[self.motionManager stopAccelerometerUpdates];
}
if (self.motionManager.gyroActive) {
INFO_LOG(Log::G3D, "Stopping gyro updates");
[self.motionManager stopGyroUpdates];
}
#endif
}
+12
View File
@@ -41,6 +41,10 @@
#include "Common/Log/LogManager.h"
#include "Core/Util/DarwinFileSystemServices.h"
#if !PPSSPP_PLATFORM(TVOS)
#import <CoreMotion/CoreMotion.h>
#endif
// Compile out all the hackery in app store builds. tvOS doesn't have posix_spawn, and there's no
// jailbreak scene to speak of.
#if !PPSSPP_PLATFORM(IOS_APP_STORE) && !PPSSPP_PLATFORM(TVOS)
@@ -324,6 +328,7 @@ bool System_GetPropertyBool(SystemProperty prop) {
case SYSPROP_HAS_FOLDER_BROWSER:
case SYSPROP_HAS_IMAGE_BROWSER:
case SYSPROP_HAS_ACCELEROMETER:
case SYSPROP_HAS_GYRO:
case SYSPROP_HAS_KEYBOARD:
case SYSPROP_KEYBOARD_IS_SOFT:
case SYSPROP_SUPPORTS_SHARE_TEXT:
@@ -363,6 +368,13 @@ bool System_GetPropertyBool(SystemProperty prop) {
return false;
case SYSPROP_HAS_ACCELEROMETER:
return true;
#if !PPSSPP_PLATFORM(TVOS)
case SYSPROP_HAS_GYRO:
{
static const bool hasGyro = [[CMMotionManager alloc] init].gyroAvailable;
return hasGyro;
}
#endif
case SYSPROP_HAS_KEYBOARD:
return true;
case SYSPROP_SUPPORTS_SHARE_TEXT: