# `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.
```nupp
local backend = tecs.platform.gamepadbackend.none()
local buffer = {tecs.platform.gamepadbackend.newEvent()}
print(backend.drain(buffer))
```
## Constructors
### `newEvent` _constructor_
```nupp
function newEvent(): Event
```
Returns 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
### `Backend` _record_
```nupp
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
end
```
Reads one platform's gamepads.
#### Methods
##### `poll`
```nupp
poll: function(): integer
```
Read-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`
```nupp
drain: function(out: {Event}): integer
```
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`
```nupp
attached: function(): {integer}
```
Read-only. Returns a fresh list of every attached device's identifier.
###### Returns
| Type | Description |
| --- | --- |
| `{integer}` | |
##### `info`
```nupp
info: function(device: integer): Info
```
Read-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`
```nupp
hasButton: function(device: integer, code: integer): boolean
```
Read-only. Reports whether one device has the button a code names.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `device` | `integer` | |
| `code` | `integer` | |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | |
##### `hasAxis`
```nupp
hasAxis: function(device: integer, code: integer): boolean
```
Read-only. Reports whether one device has the axis a code names.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `device` | `integer` | |
| `code` | `integer` | |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | |
##### `name`
```nupp
name: function(device: integer): string
```
Read-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`
```nupp
guid: function(device: integer): string
```
Read-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`
```nupp
rumble: function(device: integer, low: number, high: number, seconds: number): boolean
```
Read-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`
```nupp
close: function(): nil
```
Read-only. Releases the platform source. Calling anything afterwards is
a mistake in the caller.
###### Returns
| Type | Description |
| --- | --- |
| `nil` | |
#### Fields
##### `available`
```nupp
available: boolean
```
Read-only. Reports whether a real device source opened. A false here
still answers every call; no device ever appears.
### `Event` _record_
```nupp
record Event
kind: integer
device: integer
code: integer
value: number
end
```
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
##### `kind`
```nupp
kind: integer
```
Read-only. Selects the observation from this module's kind constants.
##### `device`
```nupp
device: integer
```
Read-only. Names the device the observation is about.
##### `code`
```nupp
code: integer
```
Read-only. Carries the button or axis code, and zero for a device
appearing or going away.
##### `value`
```nupp
value: number
```
Read-only. Carries the axis value from -1 to 1, and zero for every
other kind.
### `Info` _record_
```nupp
record Info
connected: boolean
forceFeedback: boolean
power: PowerState
percent: integer
end
```
What one device reports about itself.
#### Fields
##### `connected`
```nupp
connected: boolean
```
Read-only. Reports whether the device is still attached.
##### `forceFeedback`
```nupp
forceFeedback: boolean
```
Read-only. Reports whether the device accepts rumble on this platform.
##### `power`
```nupp
power: PowerState
```
Read-only. Reports what the device says about its power source.
##### `percent`
```nupp
percent: integer
```
Read-only. Reports the battery percentage, and -1 when the device will
not say.
### `PowerState` _type_
```nupp
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
### `missing` _function_
```nupp
function missing(): Info
```
Returns the info a device that is not there reports.
#### Returns
| Type | Description |
| --- | --- |
| `Info` | a fresh caller-owned info record describing nothing |
### `none` _function_
```nupp
function none(): Backend
```
Returns 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_ADDED` _variable_
```nupp
const KIND_ADDED: integer
```
Reports that a device appeared.
### `KIND_AXIS` _variable_
```nupp
const KIND_AXIS: integer
```
Reports one axis's new value.
### `KIND_BUTTON_DOWN` _variable_
```nupp
const KIND_BUTTON_DOWN: integer
```
Reports a button transition to held.
### `KIND_BUTTON_UP` _variable_
```nupp
const KIND_BUTTON_UP: integer
```
Reports a button transition to released.
### `KIND_REMOVED` _variable_
```nupp
const KIND_REMOVED: integer
```
Reports that a device went away.