SYSPROP_HAS_ACCELEROMETER was true for every phone and tablet, whether or
not it had the sensor. The activity now tells the native side what the
sensor manager found, which also answers the new SYSPROP_HAS_GYRO. VR
headsets still report neither. Every other platform returns false for the
gyro for now.
The "Use gyroscope" checkbox uses the new property instead of waiting for
gyro data to show up.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Appended to the end of the tilt types, so stored values keep their meaning.
It shares the left stick's deadzone settings and preview, and like other
right-stick input it goes to CTRL_STICK_RIGHT.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Tilt used the raw accelerometer as the gravity vector, which jitters with
sensor noise and jumps when the device is shaken. Now, when gyro data is
coming in, a complementary filter integrates the gyro rates and only pulls
the result toward the accelerometer with a 0.5 s time constant, trusting
the accelerometer less the further it reads from 1g. The fused vector goes
through the same ProcessTilt path, so calibration and sensitivity work as
before. Without a gyro, nothing changes.
The fusion lives in TiltEventProcessor behind NativeGyroscope(), so other
sources (DualSense) can feed it too. Android registers TYPE_GYROSCOPE next
to the accelerometer. A "Use gyroscope" checkbox (on by default, per game)
appears in tilt setup once gyro data has been seen.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Buffer::PeekAll resized the destination and then appended, so it returned twice the
data with zeros in front. No callers today.
The assert dialog's caption was a function-local static, so it froze at whichever
kind of assert fired first in the session - a later Critical Assert would still be
titled 'Debug Assert'. Made it a plain const char *.
containsNoCase passed a possibly-negative char to std::toupper, which is UB for
anything but EOF; non-ASCII bytes get here from ELF symbol names.
ApplyDeadzoneXY's circular path lacked the deadzone >= 0.99f guard its own sibling
ApplyDeadzoneAxis has one function above, so it divided by ~0.