tecs.platform.gamepadbackend
The observation contract between Tecs input policy and a gamepad source.
Tecs owns the policy: the layer stack, frame and fixed-step edges, deadzones, and the positional vocabulary a game names a control by. A backend owns device enumeration, hot plug and the platform's own event stream, and reports what it saw as one array of plain observations per poll. Nothing crosses the seam except that array, the capability and identity answers a device is asked for directly, and the one outbound command, which is rumble.
Every field is a plain function rather than a method, so a test double is a record of closures. That is what makes the whole of tecs.input testable with no gamepad attached: none is the device-free backend a headless build gets, and a test that wants to drive a device supplies its own.
local backend <const> = tecs.platform.gamepadbackend.none()
local buffer <const> = {tecs.platform.gamepadbackend.newEvent()}
print(backend.drain(buffer))Module contents
Constructors
| Constructor | Description |
|---|---|
newEvent | Returns one zeroed observation record. |
Types
| Type | Kind | Description |
|---|---|---|
Backend | record | Reads one platform's gamepads. |
Event | record | One observation a backend produces. |
Info | record | What one device reports about itself. |
PowerState | type | Names what a device says about its power source. |
Functions
| Function | Kind | Description |
|---|---|---|
missing | function | Returns the info a device that is not there reports. |
none | function | Returns a backend with no devices and no platform source. |
Values
| Value | Kind | Description |
|---|---|---|
KIND_ADDED | variable | Reports that a device appeared. |
KIND_AXIS | variable | Reports one axis's new value. |
KIND_BUTTON_DOWN | variable | Reports a button transition to held. |
KIND_BUTTON_UP | variable | Reports a button transition to released. |
KIND_REMOVED | variable | Reports that a device went away. |
Constructors#
newEventconstructor#
function newEvent(): EventReturns one zeroed observation record.
A caller preallocates a drain buffer of these once and reuses it, because the seam is crossed every frame and allocating per observation on a path that exists to avoid per-device calls gives the saving straight back.
Returns
| Type | Description |
|---|---|
Event | a fresh caller-owned observation record |
Types#
Backendrecord#
record Backend
available: boolean
poll: function(): integer
drain: function(out: {Event}): integer
attached: function(): {integer}
info: function(device: integer): Info
hasButton: function(device: integer, code: integer): boolean
hasAxis: function(device: integer, code: integer): boolean
name: function(device: integer): string
guid: function(device: integer): string
rumble: function(device: integer, low: number, high: number, seconds: number): boolean
close: function(): nil
endReads one platform's gamepads.
Methods
poll#
poll: function(): integerRead-only. Reads everything the platform produced since the previous call and returns how many observations are waiting. Runs on the frame thread, because that is the only thread allowed to move platform work into Tecs.
Returns
| Type | Description |
|---|---|
integer |
drain#
Read-only. Fills out with waiting observations in order and returns how many it wrote. Writes at most #out, and the rest wait for the next call rather than being lost.
Arguments
| Name | Type | Description |
|---|---|---|
out | {Event} |
Returns
| Type | Description |
|---|---|
integer |
attached#
attached: function(): {integer}Read-only. Returns a fresh list of every attached device's identifier.
Returns
| Type | Description |
|---|---|
{integer} |
info#
info: function(device: integer): InfoRead-only. Returns what one device says about itself. A device that is gone answers with connected false.
Arguments
| Name | Type | Description |
|---|---|---|
device | integer |
Returns
| Type | Description |
|---|---|
Info |
hasButton#
hasButton: function(device: integer, code: integer): booleanRead-only. Reports whether one device has the button a code names.
Arguments
| Name | Type | Description |
|---|---|---|
device | integer | |
code | integer |
Returns
| Type | Description |
|---|---|
boolean |
hasAxis#
hasAxis: function(device: integer, code: integer): booleanRead-only. Reports whether one device has the axis a code names.
Arguments
| Name | Type | Description |
|---|---|---|
device | integer | |
code | integer |
Returns
| Type | Description |
|---|---|
boolean |
name#
name: function(device: integer): stringRead-only. Returns the device's display name, and an empty string when the platform reports none.
Arguments
| Name | Type | Description |
|---|---|---|
device | integer |
Returns
| Type | Description |
|---|---|
string |
guid#
guid: function(device: integer): stringRead-only. Returns the stable identity a saved binding matches on, and an empty string when the platform reports none.
Arguments
| Name | Type | Description |
|---|---|---|
device | integer |
Returns
| Type | Description |
|---|---|
string |
rumble#
rumble: function(device: integer, low: number, high: number, seconds: number): booleanRead-only. Plays one rumble effect for seconds, replacing whatever the device was playing, and reports whether it started. A zero or negative duration stops the device instead.
Arguments
| Name | Type | Description |
|---|---|---|
device | integer | |
low | number | |
high | number | |
seconds | number |
Returns
| Type | Description |
|---|---|
boolean |
close#
close: function(): nilRead-only. Releases the platform source. Calling anything afterwards is a mistake in the caller.
Returns
| Type | Description |
|---|---|
nil |
Fields
available#
available: booleanRead-only. Reports whether a real device source opened. A false here still answers every call; no device ever appears.
Eventrecord#
One observation a backend produces.
One record covers every kind, because the array crossing the seam has to be one contiguous run of identical elements. A field a kind does not name carries whatever the previous use of that record left behind, so a reader reads only the fields its kind claims.
Fields
code#
code: integerRead-only. Carries the button or axis code, and zero for a device appearing or going away.
Inforecord#
record Info
connected: boolean
forceFeedback: boolean
power: PowerState
percent: integer
endWhat one device reports about itself.
Fields
forceFeedback#
forceFeedback: booleanRead-only. Reports whether the device accepts rumble on this platform.
percent#
percent: integerRead-only. Reports the battery percentage, and -1 when the device will not say.
PowerStatetype#
type PowerState = "unknown" | "noBattery" | "onBattery" | "charging" | "charged"Names what a device says about its power source.
Compatibility surface: these strings are stable for saved bindings and game branches. "error" is not among them because no source distinguishes a failed read from an unknown one.
Functions#
missingfunction#
function missing(): InfoReturns the info a device that is not there reports.
Returns
| Type | Description |
|---|---|
Info | a fresh caller-owned info record describing nothing |
nonefunction#
function none(): BackendReturns a backend with no devices and no platform source.
This is what a headless build and a device-free test get. Every call answers, nothing is ever attached, and rumble reports that it did not run.
Returns
| Type | Description |
|---|---|
Backend | a fresh backend that observes nothing |
Values#
KIND_ADDEDvariable#
const KIND_ADDED: integerReports that a device appeared.
KIND_AXISvariable#
const KIND_AXIS: integerReports one axis's new value.
KIND_BUTTON_DOWNvariable#
const KIND_BUTTON_DOWN: integerReports a button transition to held.
KIND_BUTTON_UPvariable#
const KIND_BUTTON_UP: integerReports a button transition to released.
KIND_REMOVEDvariable#
const KIND_REMOVED: integerReports that a device went away.