{"id":24443559,"url":"https://github.com/reececomo/pixijs-input-devices","last_synced_at":"2025-04-12T21:26:43.500Z","repository":{"id":272740564,"uuid":"912703944","full_name":"reececomo/pixijs-input-devices","owner":"reececomo","description":"🕹️ Powerful, high-performance input handling for PixiJS","archived":false,"fork":false,"pushed_at":"2025-01-31T01:47:57.000Z","size":716,"stargazers_count":6,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-22T21:48:20.920Z","etag":null,"topics":["a11y","accessibility","controller","gamepad","i18n","internationalization","keyboard","pixi","pixijs"],"latest_commit_sha":null,"homepage":"https://npmjs.com/pixijs-input-devices","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/reececomo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-01-06T08:15:43.000Z","updated_at":"2025-02-16T01:14:32.000Z","dependencies_parsed_at":"2025-01-23T11:20:59.863Z","dependency_job_id":null,"html_url":"https://github.com/reececomo/pixijs-input-devices","commit_stats":null,"previous_names":["reececomo/pixijs-input-devices"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reececomo%2Fpixijs-input-devices","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reececomo%2Fpixijs-input-devices/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reececomo%2Fpixijs-input-devices/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reececomo%2Fpixijs-input-devices/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/reececomo","download_url":"https://codeload.github.com/reececomo/pixijs-input-devices/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248633552,"owners_count":21136889,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["a11y","accessibility","controller","gamepad","i18n","internationalization","keyboard","pixi","pixijs"],"created_at":"2025-01-20T22:16:41.734Z","updated_at":"2025-04-12T21:26:43.488Z","avatar_url":"https://github.com/reececomo.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🎮 PixiJS Input Devices \u0026nbsp;[![License](https://badgen.net/npm/license/pixijs-input-devices)](https://github.com/reececomo/pixijs-input-devices/blob/main/LICENSE) [![Tests](https://github.com/reececomo/pixijs-input-devices/actions/workflows/tests.yml/badge.svg)](https://github.com/reececomo/pixijs-input-devices/actions/workflows/tests.yml) [![Downloads per month](https://img.shields.io/npm/dm/pixijs-input-devices.svg)](https://www.npmjs.com/package/pixijs-input-devices) [![NPM version](https://img.shields.io/npm/v/pixijs-input-devices.svg)](https://www.npmjs.com/package/pixijs-input-devices)\n\n⚡ Simple keyboard \u0026 gamepad management for PixiJS\n\n| | |\n| ------ | ------ |\n| 🎮 Handle [keyboard](#keyboarddevice), [gamepads](#gamepaddevice), and [more](#custom-devices)! | 🚀 [Real-time](#real-time) \u0026amp; [event-driven](#keyboarddevice-events) APIs |\n| ⚡ Highly-optimized for [performance](https://web.dev/articles/inp) | 🧭 Built-in [UI navigation](#uinavigation-api) |\n| 🔮 Highly configurable (with sensible defaults) | 🪄 Supports [input binding](#named-binds) |\n| ✅ Cross-platform \u0026amp; mobile-friendly \u003csup\u003e[[1]](https://caniuse.com/mdn-api_keyboardlayoutmap) [[2]](https://caniuse.com/mdn-api_gamepad_vibrationactuator) [[3]](https://chromestatus.com/feature/5989275208253440)\u003c/sup\u003e  | 🌐 Automatic [Intl layouts](#keyboard-layout---detection) detection |\n| 🍃 Zero dependencies \u0026 tree-shakeable | ✨ Supports PixiJS v8, v7, v6.3+ |\n\n\n## Sample Usage\n\n*Handle device inputs with ease.*\n\n```ts\nimport { InputDevice, GamepadDevice } from \"pixijs-input-devices\"\n\n\n// Set named binds\nGamepadDevice.configureDefaultBinds({\n    jump: [ \"A\" ]\n})\nInputDevice.keyboard.configureBinds({\n    jump: [ \"ArrowUp\", \"Space\" ]\n})\n\n// Use binds\nfor ( const device of InputDevice.devices ) {\n    if ( device.pressedBind(\"jump\") ) // ...\n}\n\n// Event-driven\nInputDevice.onBind( \"jump\", ({ device }) =\u003e {\n    if ( device.type === \"gamepad\" ) {\n        device.playVibration({ duration: 50 })\n    }\n})\n```\n\n## Getting Started with PixiJS Input Devices\n\n*Everything you need to quickly integrate device management.*\n\n**PixiJS Input Devices** adds first-class support for input devices, and\nprovides a simple, but powerful navigation manager that can enable devices to\nnavigate existing pointer-based UIs.\n\nThe key concepts are:\n\n1. **Devices:** _Any human interface device_\n2. **Binds:** _Custom, named input actions that can be triggered by assigned keys or buttons_\n3. **UINavigation:** _Navigation manager for non-pointer devices to navigate UIs_\n\n\u003e [!NOTE]\n\u003e _See [UINavigation API](#uinavigation-api) for more information._\n\n\n## Installation\n\n*Quick start guide.*\n\n**1.** Install the latest `pixijs-input-devices` package:\n\n```sh\n# npm\nnpm install pixijs-input-devices -D\n\n# yarn\nyarn add pixijs-input-devices --dev\n```\n\n**2.** Register the update loop:\n\n```ts\nimport { Ticker } from 'pixi.js'\nimport { InputDevice } from 'pixijs-input-devices'\n\n\nTicker.shared.add( () =\u003e InputDevice.update() )\n```\n\n\u003e [!TIP]\n\u003e **Input polling:** In the context of a video game, you may want to put the input update at the start of your game event loop instead.\n\n**3.** (Optional) enable the UINavigation API\n\n```ts\nimport * as PIXI from 'pixi.js'\nimport { UINavigation, registerPixiJSNavigationMixin } from 'pixijs-input-devices'\n\n\nconst app = new PIXI.Application(/*…*/)\n\n// enable the navigation API\nUINavigation.configureWithRoot( app.stage )\nregisterPixiJSNavigationMixin( PIXI.Container )\n```\n\n✨ You are now ready to use inputs!\n\n## Features\n\n### InputDevice Manager\n\nThe `InputDevice` singleton controls all device discovery.\n\n```ts\nInputDevice.keyboard  // KeyboardDevice\nInputDevice.gamepads  // GamepadDevice[]\nInputDevice.custom    // Device[]\n```\n\nYou can access all **active/connected** devices using `.devices`:\n\n```ts\nfor ( const device of InputDevice.devices ) {  // …\n```\n\n#### InputDevice - properties\n\nThe `InputDevice` manager provides the following **context capability** properties:\n\n| Property | Type | Description |\n|---|---|---|\n| `InputDevice.hasMouseLikePointer` | `boolean` | Whether the context has a mouse/trackpad. |\n| `InputDevice.isMobile` | `boolean` | Whether the context is mobile capable. |\n| `InputDevice.isTouchCapable` | `boolean` | Whether the context is touchscreen capable. |\n\nAs well as shortcuts to **connected devices**:\n\n| Accessor | Type | Description |\n|---|---|---|\n| `InputDevice.lastInteractedDevice` | `Device?` | The most recently interacted device (or first if multiple). |\n| `InputDevice.devices` | `Device[]` | All active, connected devices. |\n| `InputDevice.keyboard` | `KeyboardDevice` | The global keyboard. |\n| `InputDevice.gamepads` | `GamepadDevice[]` | Connected gamepads. |\n| `InputDevice.custom` | `CustomDevice[]` | Any custom devices. |\n\n#### InputDevice - on() Events\n\nAccess global events directly through the manager:\n\n```ts\nInputDevice.on( \"deviceadded\", ({ device }) =\u003e {\n    // new device was connected or became available\n    // do additional setup here, show a dialog, etc.\n})\n\nInputDevice.off( \"deviceadded\" ) // stop listening\n```\n\n| Event | Description | Payload |\n|---|---|---|\n| `\"deviceadded\"` | `{device}` | A device has been added. |\n| `\"deviceremoved\"` | `{device}` | A device has been removed. |\n| `\"lastdevicechanged\"` | `{device}` | The _last interacted device_ has changed. |\n\n\n#### InputDevice - onBind() Events\n\nYou may also subscribe globally to **named bind** events:\n\n```ts\nInputDevice.onBind( \"my_custom_bind\", (event) =\u003e {\n    // a bound input waas triggered\n})\n```\n\n### KeyboardDevice\n\nUnlike gamepads \u0026 custom devices, there is a single global keyboard device.\n\n```ts\nlet keyboard = InputDevice.keyboard\n\nif ( keyboard.key.ControlLeft ) {  // …\n```\n\n\u003e [!NOTE]\n\u003e **Detection:** On mobiles/tablets the keyboard will not appear in `InputDevice.devices` until\n\u003e a keyboard is detected. See `keyboard.detected`.\n\n#### Keyboard Layout - detection\n\n```ts\nkeyboard.layout  // \"AZERTY\" | \"JCUKEN\" | \"QWERTY\" | \"QWERTZ\"\n\nkeyboard.getKeyLabel( \"KeyZ\" )  // Я\n```\n\n\u003e [!NOTE]\n\u003e **Layout support:** Detects the **\"big four\"** (AZERTY, JCUKEN, QWERTY and QWERTZ).\n\u003e Almost every keyboard is one of these four (or a regional derivative \u0026ndash; e.g. Hangeul,\n\u003e Kana). There is no built-in detection for specialist or esoteric layouts (e.g. Dvorak, Colemak, BÉPO).\n\u003e\n\u003e The `keyboard.getKeyLabel( key )` uses the [KeyboardLayoutMap API](https://caniuse.com/mdn-api_keyboardlayoutmap)\n\u003e when available, before falling back to default AZERTY, JCUKEN, QWERTY or QWERTZ key values.\n\nThe keyboard layout is automatically detected from (in order):\n\n1. Browser API \u003csup\u003e[(browser support)](https://caniuse.com/mdn-api_keyboardlayoutmap)\u003c/sup\u003e\n2. Keypresses\n3. Browser Language\n\nYou can also manually force the layout:\n\n```ts\n// force layout\nInputDevice.keyboard.layout = \"JCUKEN\"\n\nInputDevice.keyboard.getKeyLabel( \"KeyW\" )  // \"Ц\"\nInputDevice.keyboard.layoutSource  // \"manual\"\n```\n\n#### KeyboardDevice Events\n\n| Event | Description | Payload |\n|---|---|---|\n| `\"layoutdetected\"` | `{layout,layoutSource,device}` | The keyboard layout (`\"QWERTY\"`, `\"QWERTZ\"`, `\"AZERTY\"`, or `\"JCUKEN\"`) has been detected, either from the native API or from keypresses. |\n| `\"bind\"` | `{name,event,keyCode,keyLabel,device}` | A **named bind** key was pressed. |\n| **Key presses:** | | |\n| `\"KeyA\"` | `{event,keyCode,keyLabel,device}` | The `\"KeyA\"` was pressed. |\n| `\"KeyB\"` | `{event,keyCode,keyLabel,device}` | The `\"KeyB\"` was pressed. |\n| `\"KeyC\"` | `{event,keyCode,keyLabel,device}` | The `\"KeyC\"` was pressed. |\n| … | … | … |\n\n\n### GamepadDevice\n\nGamepads are automatically detected via the browser API when first interacted with \u003csup\u003e[(read more)](https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API/Using_the_Gamepad_API)\u003c/sup\u003e.\n\nGamepad accessors are modelled around the \"Standard Controller Layout\":\n\n```ts\nlet gamepad = InputDevice.gamepads[0]\n\nif ( gamepad.button.Start ) {  // …\nif ( gamepad.leftTrigger \u003e 0.25 ) {  // …\nif ( gamepad.leftJoystick.x \u003e 0.5 ) {  // …\n```\n\n\u003e [!TIP]\n\u003e **Special requirements?** You can always access `gamepad.source` and reference the\n\u003e underlying API directly as needed.\n\n#### Vibration \u0026 Haptics\n\nUse the `playVibration()` method to play a haptic vibration, in supported browsers.\n\n```ts\ngamepad.playVibration({\n    duration: 150,\n    weakMagnitude: 0.75,\n    strongMagnitude: 0.25,\n    // …\n})\n```\n\n#### Gamepad Button Codes\n\nThe gamepad buttons reference **Standard Controller Layout**:\n\n| Button Index | GamepadCode | Description | Xbox | Playstation | Nintendo\u003csup\u003e[[?]](#gamepad---nintendo-layout-remapping)\u003c/sup\u003e |\n|:---:|:---|:---|:---:|:---:|:---:|\n| `0` | `\"A\"` | **Face Button 0** | A | Cross | B* |\n| `1` | `\"B\"` | **Face Button 1** | B | Circle | A* |\n| `2` | `\"X\"` | **Face Button 2** | X | Square | Y* |\n| `3` | `\"Y\"` | **Face Button 3** | Y | Triangle | X* |\n| `4` | `\"LeftShoulder\"` | **Left Shoulder** | LB | L1 | L |\n| `5` | `\"RightShoulder\"` | **Right Shoulder** | RB | R1 | R |\n| `6` | `\"LeftTrigger\"` | **Left Trigger** | LT | L2 | ZL |\n| `7` | `\"RightTrigger\"` | **Right Trigger** | RT | R2 | ZR |\n| `8` | `\"Back\"` | **Back** | Back | Options | Minus |\n| `9` | `\"Start\"` | **Start** | Start | Select | Plus |\n| `10` | `\"LeftStickClick\"` | **Left Stick Click** | LSB | L3 | L3 |\n| `11` | `\"RightStickClick\"` | **Right Stick Click** | RSB | R3 | R3 |\n| `12` | `\"DPadUp\"` | **D-Pad Up** | ⬆️ | ⬆️ | ⬆️ |\n| `13` | `\"DPadDown\"` | **D-Pad Down** | ⬇️ | ⬇️ | ⬇️ |\n| `14` | `\"DPadLeft\"` | **D-Pad Left** |  ⬅️ | ⬅️ | ⬅️ |\n| `15` | `\"DPadRight\"` | **D-Pad Right** | ➡️ | ➡️ | ➡️ |\n\n#### Gamepad Axis Codes\n\nBindable helpers are available for the joysticks too:\n\n| Axis # | GamepadCode | Standard | Layout\n|:---:|:---:|:---:|:---:|\n| `0` | `\"LeftStickLeft\"`\u003cbr/\u003e`\"LeftStickRight\"` | **Left Stick (Left/Right)** | ⬅️➡️ |\n| `1` | `\"LeftStickUp\"`\u003cbr/\u003e`\"LeftStickDown\"` | **Left Stick (Up/Down)** | ⬆️⬇️ |\n| `2` | `\"RightStickLeft\"`\u003cbr/\u003e`\"RightStickRight\"` | **Right Stick (Left/Right)** | ⬅️➡️ |\n| `3` | `\"RightStickUp\"`\u003cbr/\u003e`\"RightStickDown\"` | **Right Stick (Up/Down)** | ⬆️⬇️ |\n\n\u003e [!TIP]\n\u003e Set the `joystick.threshold` option in `GamepadDevice.defaultOptions` to control when this is triggered.\n\n#### Gamepad Layouts\n\n```ts\ngamepad.layout  // \"nintendo\" | \"xbox\" | \"playstation\" | \"logitech\" | \"steam\" | \"standard\"\n```\n\nLayout detection is **highly non-standard** across major browsers, it should generally be used for aesthetic\nimprovements (e.g. showing [device-specific icons](https://thoseawesomeguys.com/prompts/)).\n\nThere is some limited layout remapping support built-in for Nintendo controllers, which appear to be the\nonly major brand controller that deviates from the standard.\n\n##### Gamepad - Nintendo Layout Remapping\n\n\u003e [!CAUTION]\n\u003e ***Nintendo:** Both the labels and physical positions of the A,B,X,Y buttons are different\n\u003e on Nintendo controllers.\n\u003e\n\u003e Set `GamepadDevice.defaultOptions.nintendoRemapMode` to apply the remapping as required.\n\u003e\n\u003e - `\"physical\"` _**(default)**_ \u0026ndash; The A,B,X,Y button codes will refer the standard face button positions (Left=X, Top=Y, Bottom=A, Right=B).\n\u003e - `\"accurate\"` \u0026ndash; The A,B,X,Y button codes will refer to the exact Nintendo labels (Left=Y, Top=X, Bottom=B, Right=A).\n\u003e - `\"none\"` \u0026ndash; The A,B,X,Y button codes mapping stay at the default indices (Left=Y, Top=B, Bottom=X, Right=A).\n\u003e\n\u003e ```\n\u003e standard       nintendo        nintendo       nintendo\n\u003e  layout       \"physical\"      \"accurate\"       \"none\"\n\u003e reference      (default)\n\u003e \n\u003e     Y             Y              X               B\n\u003e   X   B         X   B          Y   A           Y   A\n\u003e     A             A              B               X\n\u003e\n\u003e     3             3              2               1\n\u003e   2   1         2   1          3   0           3   0\n\u003e     0             0              1               2\n\u003e ```\n\nYou can manually override this per-gamepad, or for all gamepads:\n\n```ts\n// set default\nGamepadDevice.defaultOptions.nintendoRemapMode = \"none\"\n\n// set for a single gamepad\ngamepad.options.nintendoRemapMode = \"accurate\"\n```\n\n#### GamepadDevice Events\n\n| Event | Description | Payload |\n|---|---|---|\n| `\"bind\"` | `{name,button,buttonCode,device}` | A **named bind** button was pressed. |\n| **Button presses:** | | |\n| `\"A\"` | `{button,buttonCode,device}` | Standard layout button `\"A\"` was pressed. Equivalent to `0`. |\n| `\"B\"` | `{button,buttonCode,device}` | Standard layout button `\"B\"` was pressed. Equivalent to `1`. |\n| `\"X\"` | `{button,buttonCode,device}` | Standard layout button `\"X\"` was pressed. Equivalent to `2`. |\n| … | … | … |\n| **Button presses (no label):** | | |\n| `0` or `Button.A` | `{button,buttonCode,device}` | Button at offset `0` was pressed. |\n| `1` or `Button.B` | `{button,buttonCode,device}` | Button at offset `1` was pressed. |\n| `2` or `Button.X` | `{button,buttonCode,device}` | Button at offset `2` was pressed. |\n| … | … | … |\n\n### Custom Devices\n\nYou can add custom devices to the device manager so it will be polled togehter and included in `InputDevice.devices`.\n\n```ts\nimport { type CustomDevice, InputDevice } from \"pixijs-input-devices\"\n\nexport const myDevice: CustomDevice = {\n    id: \"on-screen-buttons\",\n    type: \"custom\",\n    meta: {},\n    \n    update: ( now: number ) =\u003e {\n        // polling update\n    }\n}\n\nInputDevice.add( myDevice )\n```\n\n## Named Binds\n\nUse _named binds_ to create mappings between abstract inputs and the keys/buttons that trigger those inputs.\n\nThis allows you to change the keys/buttons later (e.g. allow users to override inputs).\n\n```ts\n// keyboard:\nInputDevice.keyboard.configureBinds({\n    jump: [ \"ArrowUp\", \"Space\", \"KeyW\" ],\n    crouch: [ \"ArrowDown\", \"KeyS\" ],\n    toggleGraphics: [ \"KeyB\" ],\n})\n\n// all gamepads:\nGamepadDevice.configureDefaultBinds({\n    jump: [ \"A\", \"LeftStickUp\" ],\n    crouch: [ \"B\", \"X\", \"RightTrigger\" ],\n    toggleGraphics: [ \"RightStickUp\", \"RightStickDown\" ],\n})\n```\n\nThese can then be used with either the real-time and event-based APIs.\n\n#### Event-based:\n\n```ts\n// listen to all devices:\nInputDevice.onBind( \"toggleGraphics\", ( e ) =\u003e toggleGraphics() )\n\n// listen to specific devices:\nInputDevice.keyboard.onBind( \"jump\", ( e ) =\u003e doJump() )\nInputDevice.gamepads[0].onBind( \"jump\", ( e ) =\u003e doJump() )\n```\n\n#### Real-time:\n\n```ts\nlet jump = false, crouch = false, moveX = 0\n\nconst keyboard = InputDevice.keyboard\nif ( keyboard.pressedBind( \"jump\" ) ) jump = true\nif ( keyboard.pressedBind( \"crouch\" ) ) crouch = true\nif ( keyboard.key.ArrowLeft ) moveX = -1\nelse if ( keyboard.key.ArrowRight ) moveX = 1\n\nfor ( const gamepad of InputDevice.gamepads ) {\n    if ( gamepad.pressedBind( \"jump\" ) ) jump = true\n    if ( gamepad.pressedBind( \"crouch\" ) ) crouch = true\n\n    // gamepads have additional analog inputs\n    // we're going to apply these only if touched\n    if ( gamepad.leftJoystick.x != 0 ) moveX = gamepad.leftJoystick.x\n    if ( gamepad.leftTrigger \u003e 0 ) moveX *= ( 1 - gamepad.leftTrigger )\n}\n```\n\n## UINavigation API\n\n_Traverse a UI using input devices._\n\n### Quick setup\n\nSet up navigation once using:\n\n```ts\nUINavigation.configureWithRoot( app.stage )  // any root container\nregisterPixiJSNavigationMixin( PIXI.Container )\n```\n\nNavigation should now work automatically if your buttons handle these events:\n\n- `\"pointerdown\"` \u0026ndash; i.e. Trigger / show press effect\n\nBut in order to really make use, you should also set:\n\n- `\"pointerover\"` \u0026ndash; i.e. Select / show hover effect\n- `\"pointerout\"` \u0026ndash; i.e. Deselect / reset\n\n\u003e [!TIP]\n\u003e 🖱️ **Seamless navigation:** Manually set `UINavigation.focusTarget = \u003ctarget\u003e`\n\u003e inside any `\"pointerover\"` handlers to allow mouse/pointers to update the\n\u003e navigation context for all devices.\n\n\u003e [!TIP]\n\u003e **Auto-focus:** Set a container's `navigationPriority` to a value above `0`\n\u003e to become the default selection in a context.\n\n### How it works\n\nThe Navigation API is centered around the **UINavigation** manager, which\nreceives navigation intents from devices and forwards it to the UI context.\n\nThe **UINavigation** manager maintains a stack of responders, which can be a\n`Container`, or any object that implements the `NavigationResponder` interface.\n\nWhen a device sends a navigation intent, the **UINavigation** manager is\nresponsible for asking the **first responder** whether it can handle the intent.\n\nIf it returns `false`, any other responders are checked (if they exist),\notherwise the default global navigation behavior kicks in.\n\n### Default Global Navigation Behaviors\n\nWhen a navigation intent is **not** handled manually by a responder, it is handled in one of the following ways:\n\n| Intent | Behavior |\n|---|---|\n|`\"navigate.back\"`|\u003cul\u003e\u003cli\u003eNo action.\u003c/li\u003e\u003c/ul\u003e|\n|`\"navigate.left\"`, `\"navigate.right\"`, `\"navigate.up\"`, `\"navigate.down\"`|\u003cul\u003e\u003cli\u003eLooks for the nearest `Container` where `container.isNavigatable` in the direction given, and if found, receives a `\"deviceover\"` event.\u003c/li\u003e\u003cli\u003eAdditionally, if the newly focused container has registered an event handler for either `\"pointerover\"` or `\"mouseover\"` (in that order), it will fire that too.\u003c/li\u003e\u003cli\u003eIf we were previously focused on a container, that previous container receives a `\"deviceout\"` event.\u003c/li\u003e\u003cli\u003eIf the blurred container has register an event handler for either `\"pointerout\"` or `\"mouseout\"` (in that order), that event handler will be fired too.\u003c/li\u003e\u003c/ul\u003e|\n|`\"navigate.trigger\"`|\u003cul\u003e\u003cli\u003eChecks if we are currently focused on a container, and then issue a `\"devicedown\"` event.\u003c/li\u003e\u003cli\u003eIf the focused container has registered an event handler for either `\"pointerdown\"` or `\"mousedown\"` (in that order), that event handler will be fired too.\u003c/li\u003e\u003c/ul\u003e|\n\n| Container event  | Description | Compatibility\n|-----------------|-------------|------------------------------------------\n| `\"devicedown\"`   | Target was triggered. | `\"pointerdown\"`, `\"mousedown\"`\n| `\"deviceover\"`   | Target became focused. | `\"pointerover\"`, `\"mouseover\"`\n| `\"deviceout\"`    | Target lost focus. | `\"pointerout\"`, `\"mouseout\"`\n\n### Container Navigatability\n\nContainers are extended with a few properties/accessors:\n\n| Container properties | type | default | description\n|---------------------|------|---------|--------------\n| `isNavigatable`      | `get(): boolean` | `false` | returns `true` if `navigationMode` is set to `\"target\"`, |or is `\"auto\"` and a `\"pointerdown\"` or `\"mousedown\"` event handler is registered.\n| `navigationMode`     | `\"auto\"` \\| `\"disabled\"` \\| `\"target\"` | `\"auto\"` | When set to `\"auto\"`, a `Container` can be navigated to if it has a `\"pointerdown\"` or `\"mousedown\"` event handler registered.\n| `navigationPriority` | `number` | `0` | The priority relative to other navigation items in this group.\n\n\u003e [!NOTE]\n\u003e **isNavigatable:** By default, any element with `\"pointerdown\"` or `\"mousedown\"` handlers is navigatable.\n\n\u003e [!WARNING]\n\u003e **Fallback Hover Effect:** If there is no `\"pointerover\"` or `\"mouseover\"` handler detected on a container, `UINavigation`\n\u003e  will apply abasic alpha effect to the selected item to indicate which container is currently the navigation target. This\n\u003e can be disabled by setting `UINavigation.options.useFallbackHoverEffect` to `false`.\n\n### Default Binds\n\nThe keyboard and gamepad devices are preconfigured with the following binds, feel free to modify them:\n\nNavigation Intent Bind | Keyboard | Gamepad\n---|---|---\n`\"navigate.left\"` | \"ArrowLeft\", \"KeyA\" | \"DPadLeft\", \"LeftStickLeft\"\n`\"navigate.right\"` | \"ArrowRight\", \"KeyD\" | \"DPadRight\", \"LeftStickRight\"\n`\"navigate.up\"` | \"ArrowUp\", \"KeyW\" | \"DPadUp\", \"LeftStickUp\"\n`\"navigate.down\"` | \"ArrowDown\", \"KeyS\" | \"DPadDown\", \"LeftStickDown\"\n`\"navigate.trigger\"` | \"Enter\", \"Space\" | \"A\"\n`\"navigate.back\"` | \"Escape\", \"Backspace\" | \"B\", \"Back\"\n\n### Manual control for submenus \u0026 modal views\n\nYou can manually take control of navigation using:\n\n```ts\n// take control\nUINavigation.pushResponder( myModalView )\n\n// relinquish control\nUINavigation.popResponder()\n```\n\n## Advanced usage\n\n### Local Player Assignment\n\nUse the `\u003cdevice\u003e.meta` property to set assorted meta data on devices as needed.\n\nYou lose TypeScript's nice strong types, but its very handy for things like user assignment in multiplayer games.\n\n```ts\nInputDevice.on(\"deviceconnected\", ({ device }) =\u003e\n    // assign!\n    device.meta.localPlayerId = 123\n)\n\nfor ( const device of InputDevice.devices )\n{\n    if ( device.meta.localPlayerId === 123 )\n    {\n        // use assigned input device!\n    }\n}\n```\n\n### On-Screen Inputs\n\nYou can easily map an on-screen input device using the `CustomDevice` interface.\n\n```ts\nexport class OnScreenInputContainer extends Container implements CustomDevice {\n    id = \"onscreen\"\n    type = \"custom\" as const\n    meta: Record\u003cstring, any\u003e = {}\n\n    inputs = {\n        moveX: 0.0\n        jump: false,\n    }\n\n    update( now )\n    {\n        this.inputs.moveX = this._virtualJoystick.x\n        this.inputs.jump = this._jumpButton.isTouching()\n    }\n\n    // e.g. disable named binds for onscreen joysticks:\n    pressedBind(name){ return false } \n}\n\nconst onscreen = new OnScreenInputContainer()\n\nInputDevice.add( onscreen )\nInputDevice.remove( onscreen )\n```\n\n### Two Users; One Keyboard\n\nYou could set up multiple named inputs:\n\n```ts\nInputDevice.keyboard.configureBinds({\n    jump: [ \"ArrowUp\", \"KeyW\" ],\n    defend: [ \"ArrowDown\", \"KeyS\" ],\n    left: [ \"ArrowLeft\", \"KeyA\" ],\n    right: [ \"ArrowRight\", \"KeyD\" ],\n\n    p1_jump: [ \"KeyW\" ],\n    p1_defend: [ \"KeyS\" ],\n    p1_left: [ \"KeyA\" ],\n    p1_right: [ \"KeyD\" ],\n\n    p2_jump: [ \"ArrowUp\" ],\n    p2_defend: [ \"ArrowDown\" ],\n    p2_left: [ \"ArrowLeft\" ],\n    p2_right: [ \"ArrowRight\" ]\n})\n```\n\nand then switch groups depending on the mode:\n\n```ts\nif ( gameMode === \"multiplayer\" )\n{\n    player1.jump   = device.pressedBind( \"p1_jump\" )\n    player1.defend = device.pressedBind( \"p1_defend\" )\n    player1.moveX += device.pressedBind( \"p1_left\" ) ? -1 : 0\n    player1.moveX += device.pressedBind( \"p1_right\" ) ? 1 : 0\n\n    player2.jump   = device.pressedBind( \"p2_jump\" )\n    player2.defend = device.pressedBind( \"p2_defend\" )\n    player2.moveX += device.pressedBind( \"p2_left\" ) ? -1 : 0\n    player2.moveX += device.pressedBind( \"p2_right\" ) ? 1 : 0\n}\nelse\n{\n    player1.jump   = device.pressedBind( \"jump\" )\n    player1.defend = device.pressedBind( \"defend\" )\n    player1.moveX += device.pressedBind( \"left\" ) ? -1 : 0\n    player1.moveX += device.pressedBind( \"right\" ) ? 1 : 0\n\n    updateComputerPlayerInput( player2 )\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freececomo%2Fpixijs-input-devices","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freececomo%2Fpixijs-input-devices","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freececomo%2Fpixijs-input-devices/lists"}