Controller: vibration, light, and sensors
Check capabilities, request short vibration, and prepare sensors.
Vibration, lights, and sensors are optional capabilities of a particular device and driver. Check each separately and keep a primary control method without it. A connected controller need not support every Input feature.
Check before issuing commands
| Capability | Check | Command / reading |
|---|---|---|
| Vibration | Input.HasJoyVibration(device) | StartJoyVibration() / StopJoyVibration(). |
| Light | Input.HasJoyLight(device) | SetJoyLight(). |
| Motion sensors | Input.HasJoyMotionSensors(device) | Sensor enabling, calibration, and readings. |
Take IDs from GetConnectedJoypads() and assign players explicitly. A nonzero vector or stored command parameters do not replace connection checks. Recheck when switching devices; unsubscribe from JoyConnectionChanged when an object stops servicing input.
Short vibration with a missing-device fallback
This helper checks intensity bounds, positive duration, and the selected controller's capabilities. Its second method reads the gyroscope only after enabling and calibrating sensors.
using System;
using Reckfell;
public static class ControllerFeedback
{
public static bool TryPulse(int device, float strength, float seconds)
{
if (!float.IsFinite(strength) || strength < 0 || strength > 1 ||
!float.IsFinite(seconds) || seconds <= 0) return false;
if (!Input.GetConnectedJoypads().Contains(device) || !Input.HasJoyVibration(device)) return false;
Input.StartJoyVibration(device, strength, strength, seconds);
return true; // Request submitted, not proof that the motors moved.
}
public static bool TryReadGyroscope(int device, out Vector3 radiansPerSecond)
{
radiansPerSecond = Vector3.Zero;
if (!Input.GetConnectedJoypads().Contains(device) ||
!Input.HasJoyMotionSensors(device) || !Input.IsJoyMotionSensorsEnabled(device) ||
!Input.IsJoyMotionSensorsCalibrated(device)) return false;
radiansPerSecond = Input.GetJoyGyroscope(device);
return radiansPerSecond.IsFinite();
}
}Call TryPulse once per gameplay event. A true return means the request was submitted, not that motors physically moved. false means no request was sent. Do not issue a pulse every frame instead of one command with a duration.
StartJoyVibration() accepts two intensities, for weak and strong motors, each 0–1. Duration is in seconds. Do not treat 0 as a guarantee of infinite operation: the current SDL backend converts it to 65,535 ms. The example deliberately requires a finite positive duration. Provide vibration strength/disable settings and stop it when game context changes.
Light
Check HasJoyLight before SetJoyLight(device, color). Send a new color when state changes rather than needlessly every frame. Do not make a light the sole danger indicator: display the same state on screen. The API does not promise a specific LED count, brightness, or matching color reproduction across devices.
Sensors and calibration
- Check connection and
HasJoyMotionSensors. - Enable with
SetJoyMotionSensorsEnabled(device, true)and checkIsJoyMotionSensorsEnabled. - Ask the player to keep the device still. Call
StartJoyMotionSensorsCalibration, allow a collection period you select, then callStopJoyMotionSensorsCalibration. - Check calibration state before using readings. A fixed one-second wait is not a universal accuracy guarantee.
- Disable sensors when finished if your code owns their use; do not disable them while another system still needs readings.
In 1.0.0, StopJoyMotionSensorsCalibration() sets the calibrated flag. This indicates procedure completion, not a measurement of stillness quality. Check drift on the target device and allow recalibration.
GetJoyGyroscope() returns angular velocity in radians per second. Account for time and your control-axis mapping when accumulating angles. GetJoyAccelerometer() and GetJoyGravity() use m/s²; their difference can estimate acceleration without gravity. Integrating these readings alone does not provide reliable controller position in a room.
A zero reading can mean missing data or ignored input, not only a stationary device. Check capabilities and state first. Missing an optional feature must not block play.
Executed checks cover missing devices, zero readings, and wrapper refusal paths. Commands do not create sensor support for an unknown ID. Real motors, lights, sensor accuracy, on-device calibration, hot disconnection, and exports were not tested; an API list is not a compatibility matrix.