Source code for libretro.api.sensor
"""
Types for providing sensor input to cores.
.. seealso::
:class:`.SensorDriver`
The :class:`.Protocol` that uses these types to implement sensor support in libretro.py.
:mod:`libretro.drivers.sensor`
libretro.py's included :class:`.SensorDriver` implementations.
"""
from ctypes import Structure, c_bool, c_float, c_int, c_uint
from dataclasses import dataclass
from enum import IntEnum
from libretro.ctypes import CIntArg, TypedFunctionPointer
retro_sensor_action = c_int
"""Corresponds to :c:type:`retro_sensor_action` in ``libretro.h``."""
RETRO_SENSOR_ACCELEROMETER_ENABLE = 0
RETRO_SENSOR_ACCELEROMETER_DISABLE = RETRO_SENSOR_ACCELEROMETER_ENABLE + 1
RETRO_SENSOR_GYROSCOPE_ENABLE = RETRO_SENSOR_ACCELEROMETER_DISABLE + 1
RETRO_SENSOR_GYROSCOPE_DISABLE = RETRO_SENSOR_GYROSCOPE_ENABLE + 1
RETRO_SENSOR_ILLUMINANCE_ENABLE = RETRO_SENSOR_GYROSCOPE_DISABLE + 1
RETRO_SENSOR_ILLUMINANCE_DISABLE = RETRO_SENSOR_ILLUMINANCE_ENABLE + 1
RETRO_SENSOR_DUMMY = 0x7FFFFFFF
RETRO_SENSOR_ACCELEROMETER_X = 0
RETRO_SENSOR_ACCELEROMETER_Y = 1
RETRO_SENSOR_ACCELEROMETER_Z = 2
RETRO_SENSOR_GYROSCOPE_X = 3
RETRO_SENSOR_GYROSCOPE_Y = 4
RETRO_SENSOR_GYROSCOPE_Z = 5
RETRO_SENSOR_ILLUMINANCE = 6
retro_set_sensor_state_t = TypedFunctionPointer[
c_bool, [CIntArg[c_uint], CIntArg[retro_sensor_action], CIntArg[c_uint]]
]
"""
Adjust the state of a sensor on a controller.
Registered by the :term:`frontend` and called by the :term:`core`
to enable or disable a particular sensor and request an update rate.
Cores should only enable sensors while they are actively in use,
since sensors can drain the host device's battery.
:param port: Index of the controller :term:`port` whose sensor will be addressed.
:param action: A :class:`SensorAction` describing which sensor to enable or disable.
:param rate: Desired sensor update rate, in Hz.
Treated as a hint; the actual rate may differ depending on the device.
:return: :obj:`True` if the sensor state was successfully adjusted,
:obj:`False` otherwise (most commonly because the sensor is unavailable).
Corresponds to :c:type:`retro_set_sensor_state_t` in ``libretro.h``.
"""
retro_sensor_get_input_t = TypedFunctionPointer[c_float, [CIntArg[c_uint], CIntArg[c_uint]]]
"""
Return the current value reported by a sensor.
Registered by the :term:`frontend` and called by the :term:`core`.
:param port: Index of the controller :term:`port` whose sensor will be queried.
:param id: A :class:`Sensor` value that selects the sensor reading
(e.g. an accelerometer axis or the illuminance sensor).
:return: The current sensor value;
semantics depend on ``id``,
and ``0.0`` is returned for invalid arguments.
Corresponds to :c:type:`retro_sensor_get_input_t` in ``libretro.h``.
"""
[docs]
@dataclass(init=False, slots=True)
class retro_sensor_interface(Structure):
"""
Provides functions for managing sensor input.
Corresponds to :c:type:`retro_sensor_interface` in ``libretro.h``.
>>> from libretro.api import retro_sensor_interface
>>> s = retro_sensor_interface()
>>> s.set_sensor_state is None
True
"""
set_sensor_state: retro_set_sensor_state_t | None
"""Enables or disables a sensor for a given port."""
get_sensor_input: retro_sensor_get_input_t | None
"""Reads a sensor value for a given port and sensor ID."""
_fields_ = (
("set_sensor_state", retro_set_sensor_state_t),
("get_sensor_input", retro_sensor_get_input_t),
)
[docs]
def __deepcopy__(self, _):
"""
Return a copy of this object.
Intended for use with :func:`copy.deepcopy`.
>>> import copy
>>> from libretro.api import retro_sensor_interface
>>> copy.deepcopy(retro_sensor_interface()).set_sensor_state is None
True
"""
return retro_sensor_interface(self.set_sensor_state, self.get_sensor_input)
[docs]
class SensorType(IntEnum):
"""
Type of sensor hardware.
>>> from libretro.api import SensorType
>>> SensorType.ACCELEROMETER
<SensorType.ACCELEROMETER: 0>
"""
ACCELEROMETER = 0
GYROSCOPE = 3
ILLUMINANCE = 6
[docs]
class SensorAction(IntEnum):
"""
Action to enable or disable a sensor.
>>> from libretro.api import SensorAction
>>> SensorAction.GYROSCOPE_ENABLE.enabled
True
"""
ACCELEROMETER_ENABLE = RETRO_SENSOR_ACCELEROMETER_ENABLE
ACCELEROMETER_DISABLE = RETRO_SENSOR_ACCELEROMETER_DISABLE
GYROSCOPE_ENABLE = RETRO_SENSOR_GYROSCOPE_ENABLE
GYROSCOPE_DISABLE = RETRO_SENSOR_GYROSCOPE_DISABLE
ILLUMINANCE_ENABLE = RETRO_SENSOR_ILLUMINANCE_ENABLE
ILLUMINANCE_DISABLE = RETRO_SENSOR_ILLUMINANCE_DISABLE
@property
def sensor_type(self) -> SensorType:
"""
Returns the :class:`SensorType` this action applies to.
>>> from libretro.api import SensorAction, SensorType
>>> SensorAction.ACCELEROMETER_ENABLE.sensor_type == SensorType.ACCELEROMETER
True
"""
match self:
case SensorAction.ACCELEROMETER_ENABLE | SensorAction.ACCELEROMETER_DISABLE:
return SensorType.ACCELEROMETER
case SensorAction.GYROSCOPE_ENABLE | SensorAction.GYROSCOPE_DISABLE:
return SensorType.GYROSCOPE
case SensorAction.ILLUMINANCE_ENABLE | SensorAction.ILLUMINANCE_DISABLE:
return SensorType.ILLUMINANCE
case _:
raise ValueError(f"Invalid action: {self}")
@property
def enabled(self) -> bool:
"""
Returns ``True`` if this action enables the sensor.
>>> from libretro.api import SensorAction
>>> SensorAction.GYROSCOPE_DISABLE.enabled
False
"""
match self:
case (
SensorAction.ACCELEROMETER_ENABLE
| SensorAction.GYROSCOPE_ENABLE
| SensorAction.ILLUMINANCE_ENABLE
):
return True
case (
SensorAction.ACCELEROMETER_DISABLE
| SensorAction.GYROSCOPE_DISABLE
| SensorAction.ILLUMINANCE_DISABLE
):
return False
case _:
raise ValueError(f"Invalid action: {self}")
[docs]
class Sensor(IntEnum):
"""
Individual sensor axis or value identifiers.
>>> from libretro.api import Sensor, SensorType
>>> Sensor.GYROSCOPE_X.type == SensorType.GYROSCOPE
True
"""
ACCELEROMETER_X = RETRO_SENSOR_ACCELEROMETER_X
ACCELEROMETER_Y = RETRO_SENSOR_ACCELEROMETER_Y
ACCELEROMETER_Z = RETRO_SENSOR_ACCELEROMETER_Z
GYROSCOPE_X = RETRO_SENSOR_GYROSCOPE_X
GYROSCOPE_Y = RETRO_SENSOR_GYROSCOPE_Y
GYROSCOPE_Z = RETRO_SENSOR_GYROSCOPE_Z
ILLUMINANCE = RETRO_SENSOR_ILLUMINANCE
@property
def type(self) -> SensorType:
"""
Returns the :class:`SensorType` for this sensor reading.
>>> from libretro.api import Sensor, SensorType
>>> Sensor.ILLUMINANCE.type == SensorType.ILLUMINANCE
True
"""
match self:
case Sensor.ACCELEROMETER_X | Sensor.ACCELEROMETER_Y | Sensor.ACCELEROMETER_Z:
return SensorType.ACCELEROMETER
case Sensor.GYROSCOPE_X | Sensor.GYROSCOPE_Y | Sensor.GYROSCOPE_Z:
return SensorType.GYROSCOPE
case Sensor.ILLUMINANCE:
return SensorType.ILLUMINANCE
case _:
raise ValueError(f"Invalid sensor: {self}")
__all__ = [
"retro_set_sensor_state_t",
"retro_sensor_get_input_t",
"retro_sensor_interface",
"SensorAction",
"SensorType",
"Sensor",
"retro_sensor_action",
]