# `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.