pixijs-input-devices 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,47 +1,104 @@
1
- # đŸ•šī¸ pixijs-input-devices  [![NPM version](https://img.shields.io/npm/v/pixijs-input-devices.svg)](https://www.npmjs.com/package/pixijs-input-devices) [![Minzipped](https://badgen.net/bundlephobia/minzip/pixijs-input-devices@latest)](https://bundlephobia.com/package/pixijs-input-devices) [![Downloads per month](https://img.shields.io/npm/dm/pixijs-input-devices.svg)](https://www.npmjs.com/package/pixijs-input-devices) [![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) [![License](https://badgen.net/npm/license/pixijs-input-devices)](https://github.com/reececomo/pixijs-input-devices/blob/main/LICENSE)
1
+ # đŸ•šī¸ pixijs-input-devices  [![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)
2
2
 
3
- 🚧 WIP - This API is a work in progress, and is subject to change.
3
+ ⚡ Powerful, high-performance input device management for PixiJS
4
4
 
5
- - Adds comprehensive support for âŒ¨ī¸ **Keyboard**, 🎮 **Gamepads**, and other human-interface devices
6
- - High-performance, easy-to-use, sensible defaults
7
- - Supports either real-time or event driven APIs
8
- - Built-in `Navigation` API to navigate pointer/mouse based menus _(optional)_
5
+ | | |
6
+ | ------ | ------ |
7
+ | 🎮 Handles [keyboards](#keyboarddevice), [gamepads](#gamepaddevice), and [more](#custom-devices)! | 🚀 Flexible [low-level](#real-time) and [event-driven](#keyboarddevice-events) APIs |
8
+ | 🔮 Resolves browser API inconsistencies <sup>[[1]](https://caniuse.com/mdn-api_keyboardlayoutmap) [[2]](https://caniuse.com/mdn-api_gamepad_vibrationactuator) [[3]](https://chromestatus.com/feature/5989275208253440)</sup> | 🧭 Seamless [navigation](#navigation-api) for pointer/mouse based UIs |
9
+ | 📱 Powerful configuration options, sensible defaults | 🌐 Automatic i18n (built-in [internationalization](#keyboard-layout---detection)) |
10
+ | ⚡ Optimized for speed (best-in-class [INP performance](https://web.dev/articles/inp)) | 🔀 Named binds (for [user-configurable inputs](#named-binds)) |
11
+ | 🍃 Zero dependencies & tree-shakeable | ✨ Supports PixiJS v8, v7, v6.3+ |
9
12
 
10
- <hr/>
11
13
 
12
- ## đŸ’ŋ Install
14
+ ## Sample Usage
15
+
16
+ *Handle device inputs with ease.*
17
+
18
+ ```ts
19
+ import { InputDevice } from "pixijs-input-devices";
20
+
21
+ // Iterative
22
+ let jump = false
23
+
24
+ for (const device of InputDevice.devices) {
25
+ if (device.type === "keyboard" && device.key.Space) jump = true
26
+ if (device.type === "gamepad" && device.button.A) jump = true
27
+ }
28
+
29
+ // Event-driven
30
+ const gamepad = InputDevice.gamepads[0]
31
+
32
+ gamepad?.on("LeftShoulder", (e) => {
33
+ e.device.playVibration({ duration: 100 })
34
+ });
35
+ ```
36
+
37
+ ## Getting Started with PixiJS Input Devices
38
+
39
+ *Everything you need to quickly integrate powerful device management.*
40
+
41
+ **PixiJS Input Devices** adds first-class support for input device management and input handling. It also provides an optional navigation manager
42
+ that can enable input devices to traverse pointer-based UIs.
43
+
44
+ The core concepts are:
45
+
46
+ 1. **Devices:** _Any human interface device_
47
+ 2. **Binds:** _Custom, named input actions that can be triggered by assigned keys or buttons_
48
+ 3. **Navigation:** _A global controller that allows non-pointer devices to navigate UIs_
49
+
50
+ > [!NOTE]
51
+ > _See [Navigation API](#navigation-api) for more information._
52
+
53
+
54
+ ## Installation
55
+
56
+ *Quick start guide.*
57
+
58
+ **1.** Install the latest `pixijs-input-devices` package:
13
59
 
14
60
  ```sh
15
- npm i pixijs-input-devices
61
+ # npm
62
+ npm install pixijs-input-devices -D
63
+
64
+ # yarn
65
+ yarn add pixijs-input-devices --dev
16
66
  ```
17
67
 
18
- ### Setup
68
+ **2.** Register the update loop:
19
69
 
20
70
  ```ts
21
- import { InputDevice } from "pixijs-input-devices"
71
+ import * as PIXI from 'pixi.js';
72
+ import { InputDevice } from 'pixijs-input-devices';
22
73
 
23
- Ticker.shared.add( () => InputDevice.update() )
74
+ // register `InputDevice.update()` with shared ticker
75
+ Ticker.shared.add(ticker => InputDevice.update());
24
76
  ```
25
77
 
26
- _(Optional)_ Enable the Navigation API:
78
+ > [!TIP]
79
+ > **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 insteaad
80
+
81
+ > [!NOTE]
82
+ > _If not using a PixiJS ticker, then just put `Action.tick(elapsedMs)` in the appropriate equivalent place (i.e. your `requestAnimationFrame()` render loop)._
83
+
84
+ **3.** (Optional) enable the Navigation API
27
85
 
28
86
  ```ts
29
- import { Navigation } from "pixijs-input-devices"
87
+ import * as PIXI from 'pixi.js';
88
+ import { Navigation, registerPixiJSInputDevicesMixin } from 'pixijs-input-devices';
30
89
 
31
- // set root node
32
- Navigation.stage = app.stage
90
+ // register container mixin
91
+ registerPixiJSInputDevicesMixin(PIXI.Container);
33
92
 
34
- // register mixin
35
- registerPixiJSInputDeviceMixin( Container )
36
- ```
93
+ const app = new PIXI.Application(/*â€Ļ*/)
37
94
 
38
- ## Overview
95
+ // set the root view for device navigation
96
+ Navigation.stage = app.stage
97
+ ```
39
98
 
40
- There are a few very simple themes:
99
+ ✨ You are now ready to use inputs!
41
100
 
42
- - All devices are accessed through the `InputDevice` manager
43
- - There are three supported device types: âŒ¨ī¸ `"keyboard"`, 🎮 `"gamepad"` and đŸ‘ģ `"custom"`
44
- - Inputs can be accessed directly, or configured by [Named Groups](#named-input-groups)
101
+ ## Features
45
102
 
46
103
  ### InputDevice Manager
47
104
 
@@ -56,7 +113,7 @@ InputDevice.custom // Array<CustomDevice>
56
113
  You can access all **active/connected** devices using `.devices`:
57
114
 
58
115
  ```ts
59
- for ( const device of InputDevice.devices ) { // ...
116
+ for ( const device of InputDevice.devices ) { // â€Ļ
60
117
  ```
61
118
 
62
119
  #### InputDevice - properties
@@ -76,18 +133,18 @@ for ( const device of InputDevice.devices ) { // ...
76
133
  Access global events directly through the manager:
77
134
 
78
135
  ```ts
79
- InputDevice.on( "deviceconnected", ({ device }) => {
136
+ InputDevice.on( "deviceadded", ({ device }) => {
80
137
  // a device was connected
81
138
  // do additional setup here, show a dialog, etc.
82
139
  })
83
140
 
84
- InputDevice.off( "deviceconnected" ) // stop listening
141
+ InputDevice.off( "deviceadded" ) // stop listening
85
142
  ```
86
143
 
87
144
  | Event | Description | Payload |
88
145
  |---|---|---|
89
- | `"deviceconnected"` | `{device}` | A device has become available. |
90
- | `"devicedisconnected"` | `{device}` | A device has been removed. |
146
+ | `"deviceadded"` | `{device}` | A device has been added. |
147
+ | `"deviceremoved"` | `{device}` | A device has been removed. |
91
148
 
92
149
 
93
150
  ### KeyboardDevice
@@ -97,7 +154,7 @@ Unlike gamepads & custom devices, there is a single global keyboard device.
97
154
  ```ts
98
155
  let keyboard = InputDevice.keyboard
99
156
 
100
- if ( keyboard.key.ControlLeft ) { // ...
157
+ if ( keyboard.key.ControlLeft ) { // â€Ļ
101
158
  ```
102
159
 
103
160
  > [!NOTE]
@@ -141,12 +198,12 @@ InputDevice.keyboard.layoutSource // "manual"
141
198
  | Event | Description | Payload |
142
199
  |---|---|---|
143
200
  | `"layoutdetected"` | `{layout,layoutSource,device}` | The keyboard layout (`"QWERTY"`, `"QWERTZ"`, `"AZERTY"`, or `"JCUKEN"`) has been detected, either from the native API or from keypresses. |
144
- | `"group"` | `{groupName,event,keyCode,keyLabel,device}` | A **named input group** key was pressed. |
201
+ | `"bind"` | `{name,event,keyCode,keyLabel,device}` | A **named bind** key was pressed. |
145
202
  | **Key presses:** | | |
146
203
  | `"KeyA"` | `{event,keyCode,keyLabel,device}` | The `"KeyA"` was pressed. |
147
204
  | `"KeyB"` | `{event,keyCode,keyLabel,device}` | The `"KeyB"` was pressed. |
148
205
  | `"KeyC"` | `{event,keyCode,keyLabel,device}` | The `"KeyC"` was pressed. |
149
- | ... | ... | ... |
206
+ | â€Ļ | â€Ļ | â€Ļ |
150
207
 
151
208
 
152
209
  ### GamepadDevice
@@ -158,9 +215,9 @@ Gamepad accessors are modelled around the "Standard Controller Layout":
158
215
  ```ts
159
216
  let gamepad = InputDevice.gamepads[0]
160
217
 
161
- if ( gamepad.button.Start ) { // ...
162
- if ( gamepad.leftTrigger > 0.25 ) { // ...
163
- if ( gamepad.leftJoystick.x > 0.5 ) { // ...
218
+ if ( gamepad.button.Start ) { // â€Ļ
219
+ if ( gamepad.leftTrigger > 0.25 ) { // â€Ļ
220
+ if ( gamepad.leftJoystick.x > 0.5 ) { // â€Ļ
164
221
  ```
165
222
 
166
223
  > [!TIP]
@@ -172,12 +229,11 @@ if ( gamepad.leftJoystick.x > 0.5 ) { // ...
172
229
  Use the `playVibration()` method to play a haptic vibration, in supported browsers.
173
230
 
174
231
  ```ts
175
- gamepad.playVibration()
176
-
177
232
  gamepad.playVibration({
178
- duration: 150,
179
- weakMagnitude: 0.25,
180
- strongMagnitude: 0.65,
233
+ duration: 150,
234
+ weakMagnitude: 0.75,
235
+ strongMagnitude: 0.25,
236
+ // â€Ļ
181
237
  })
182
238
  ```
183
239
 
@@ -255,17 +311,17 @@ GamepadDevice.defaultOptions.remapNintendoMode = "none"
255
311
 
256
312
  | Event | Description | Payload |
257
313
  |---|---|---|
258
- | `"group"` | `{groupName,button,buttonCode,device}` | A **named input group** button was pressed. |
314
+ | `"bind"` | `{name,button,buttonCode,device}` | A **named bind** button was pressed. |
259
315
  | **Button presses:** | | |
260
316
  | `"A"` | `{button,buttonCode,device}` | Standard layout button `"A"` was pressed. Equivalent to `0`. |
261
317
  | `"B"` | `{button,buttonCode,device}` | Standard layout button `"B"` was pressed. Equivalent to `1`. |
262
318
  | `"X"` | `{button,buttonCode,device}` | Standard layout button `"X"` was pressed. Equivalent to `2`. |
263
- | ... | ... | ... |
319
+ | â€Ļ | â€Ļ | â€Ļ |
264
320
  | **Button presses (no label):** | | |
265
321
  | `0` or `Button.A` | `{button,buttonCode,device}` | Button at offset `0` was pressed. |
266
322
  | `1` or `Button.B` | `{button,buttonCode,device}` | Button at offset `1` was pressed. |
267
323
  | `2` or `Button.X` | `{button,buttonCode,device}` | Button at offset `2` was pressed. |
268
- | ... | ... | ... |
324
+ | â€Ļ | â€Ļ | â€Ļ |
269
325
 
270
326
  ### Custom Devices
271
327
 
@@ -287,22 +343,22 @@ export const myDevice: CustomDevice = {
287
343
  InputDevice.add( myDevice )
288
344
  ```
289
345
 
290
- ## Named Input Groups
346
+ ## Named Binds
291
347
 
292
- Use named "groups" to create named inputs that can be referenced.
348
+ Use _named binds_ to create mappings between abstract inputs and the keys/buttons that trigger those inputs.
293
349
 
294
350
  This allows you to change the keys/buttons later (e.g. allow users to override inputs).
295
351
 
296
352
  ```ts
297
353
  // keyboard:
298
- InputDevice.keyboard.options.namedGroups = {
354
+ InputDevice.keyboard.options.binds = {
299
355
  jump: [ "ArrowUp", "Space", "KeyW" ],
300
356
  crouch: [ "ArrowDown", "KeyS" ],
301
357
  toggleGraphics: [ "KeyB" ],
302
358
  }
303
359
 
304
360
  // all gamepads:
305
- GamepadDevice.defaultOptions.namedGroups = {
361
+ GamepadDevice.defaultOptions.binds = {
306
362
  jump: [ "A" ],
307
363
  crouch: [ "B", "X", "RightTrigger" ],
308
364
  toggleGraphics: [ "RightStick" ],
@@ -315,11 +371,11 @@ These can then be used with either the real-time and event-based APIs.
315
371
 
316
372
  ```ts
317
373
  // listen to all devices:
318
- InputDevice.onGroup( "toggleGraphics", ( e ) => toggleGraphics() )
374
+ InputDevice.onBind( "toggleGraphics", ( e ) => toggleGraphics() )
319
375
 
320
376
  // listen to specific devices:
321
- InputDevice.keyboard.onGroup( "jump", ( e ) => doJump() )
322
- InputDevice.gamepads[0].onGroup( "jump", ( e ) => doJump() )
377
+ InputDevice.keyboard.onBind( "jump", ( e ) => doJump() )
378
+ InputDevice.gamepads[0].onBind( "jump", ( e ) => doJump() )
323
379
  ```
324
380
 
325
381
  #### Real-time:
@@ -328,14 +384,14 @@ InputDevice.gamepads[0].onGroup( "jump", ( e ) => doJump() )
328
384
  let jump = false, crouch = false, moveX = 0
329
385
 
330
386
  const keyboard = InputDevice.keyboard
331
- if ( keyboard.groupPressed( "jump" ) ) jump = true
332
- if ( keyboard.groupPressed( "crouch" ) ) crouch = true
387
+ if ( keyboard.bindPressed( "jump" ) ) jump = true
388
+ if ( keyboard.bindPressed( "crouch" ) ) crouch = true
333
389
  if ( keyboard.key.ArrowLeft ) moveX = -1
334
390
  else if ( keyboard.key.ArrowRight ) moveX = 1
335
391
 
336
392
  for ( const gamepad of InputDevice.gamepads ) {
337
- if ( gamepad.groupPressed( "jump" ) ) jump = true
338
- if ( gamepad.groupPressed( "crouch" ) ) crouch = true
393
+ if ( gamepad.bindPressed( "jump" ) ) jump = true
394
+ if ( gamepad.bindPressed( "crouch" ) ) crouch = true
339
395
 
340
396
  // gamepads have additional analog inputs
341
397
  // we're going to apply these only if touched
@@ -346,122 +402,64 @@ for ( const gamepad of InputDevice.gamepads ) {
346
402
 
347
403
  ## Navigation API
348
404
 
349
- Automatically traverse existing pointer/mouse based menus using the `Navigation` API.
405
+ _Traverse a UI using input devices._
350
406
 
351
- ```ts
352
- // set root container
353
- Navigation.stage = app.stage
354
-
355
- const button = new ButtonSprite()
356
- button.on( "mousedown", () => button.run( clickAnimation ) )
357
- button.on( "mouseout", () => button.run( resetAnimation ) )
358
- button.on( "mouseover", () => button.run( hoverAnimation ) )
407
+ The Navigation API is centered around a central **Navigation** controller, which listens to navigation intents from devices,
408
+ then handles the intent.
359
409
 
360
- app.stage.addChild( button )
361
-
362
- button.isNavigatable // true
363
- ```
410
+ The **Navigation** controller maintains a stack of `NavigationResponder` objects, which represent the **current navigation context**. For
411
+ example, you might add a `NavigationResponder` for a drop-down UI. A normal `Container` can be used as a `NavigationResponder`, and any
412
+ container on the stack will become the **current root container**.
364
413
 
365
414
  > [!NOTE]
366
- > **isNavigatable:** By default, any element with `"mousedown"` or `"pointerdown"` handlers is navigatable.
367
-
368
- > [!WARNING]
369
- > **Fallback Hover Effect:** If there is no `"pointerover"` or `"mouseover"` handler detected on a container, `Navigation`
370
- > will apply abasic alpha effect to the selected item to indicate which container is currently the navigation target. This
371
- > can be disabled by setting `Navigation.options.useFallbackHoverEffect` to `false`.
415
+ > The **current root container** is the top-most `Container` on the navigation responder stack, or otherwise `Navigation.stage`.
372
416
 
373
- ### Disable Navigation
417
+ When a device sends a navigation intent, the **Navigation** controller is responsible for asking each of the responders on the stack
418
+ if it can handle the intent. If it can't, it is propagated up all the way to the **current root container**.
374
419
 
375
- You can **disable** the navigation API - either permanently or temporarily - like so:
420
+ ### Default UI Navigation Behavior
376
421
 
377
- ```ts
378
- Navigation.options.enabled = false
379
- ```
422
+ When a navigation intent is **not** handled manually by a responder, it is handled in one of the following ways:
380
423
 
381
- ### NavigationResponders
424
+ | Intent | Behavior |
425
+ |---|---|
426
+ |`"navigateBack"`|<ul><li>No action.</li></ul>|
427
+ |`"navigateLeft"`, `"navigateRight"`, `"navigateUp"`, `"navigateDown"`|<ul><li>Looks for the nearest `Container` where `container.isNavigatable` in the direction given, and if found, fires a `"focus"` event on it.</li><li>Additionally, if the newly focused container has registered an event handler for either `"pointerover"` or `"mouseover"` (in that order), it will fire that too.</li><li>If we were previously focused on a container, that previous container fires a `"blur"` event.</li><li>If the blurred container has register an event handler for either `"pointerout"` or `"mouseout"` (in that order), that event handler will be fired too.</li></ul>|
428
+ |`"trigger"`|<ul><li>Checks if we are currently focused on a container, and then issue a `"trigger"` event.</li><li>If the focused container has registered an event handler for either `"pointerdown"` or `"mousedown"` (in that order), that event handler will be fired too.</li></ul>|
382
429
 
383
- UIs can be complex! The Navigation API allows you to take over some - or all - of the navigation elements.
430
+ Container event | Description | Equivalent
431
+ -----------------|--------------------------------------------------------
432
+ `trigger` | Target was triggered. | `"pointerdown"`, `"mousedown"`
433
+ `focus` | Target became focused. | `"pointerover"`, `"mouseover"`
434
+ `blur` | Target lost focus. | `"pointerout"`, `"mouseout"`
384
435
 
385
- You can create **NavigationResponder** controllers, which can be a `Container` that becomes the
386
- "root" node for navigation. It can also just be any object (like a custom manager class).
436
+ ### Container Navigation
387
437
 
388
- It has a method called `handledNavigationIntent(): boolean` which can return a boolean saying whether
389
- the navigation event was handled. If you return false here, it is bubbled up to the next parent in the
390
- stack.
438
+ Containers are extended with a few properties/accesors:
391
439
 
392
- To add a responder, just use `Navigation.pushResponder( responder )` - and then remove it with `Navigation.popResponder()`.
440
+ Container properties | type | default | description
441
+ ---------------------|------|---------|--------------
442
+ `isNavigatable` | `get(): boolean` | `false` | returns `true` if `navigationMode` is set to `"target"`, or is `"auto"` and a `"pointerdown"` or `"mousedown"` event handler is registered.
443
+ `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.
444
+ `navigationPriority` | `number` | `0` | The priority relative to other navigation items in this group.
393
445
 
394
- ```ts
395
- class MyVerticalMenu implements NavigationResponder
396
- {
397
- handledNavigationIntent( intent, device ): boolean {
398
- if ( intent === "navigateUp" ) this.moveCursorUp()
399
- else if ( intent === "navigateDown" ) this.moveCursorDown()
400
- else if ( intent === "navigateBack" ) this.loseFocus()
401
- else if ( intent === "trigger" ) this.clickCursorItem()
402
-
403
- // we are going to return false here, which will propagates unhandled
404
- // intents ("navigateLeft", "navigateRight") up to the next responder
405
- // in the stack - which could be a parent view, etc.
406
- return false
407
- }
446
+ > [!NOTE]
447
+ > **isNavigatable:** By default, any element with `"pointerdown"` or `"mousedown"` handlers is navigatable.
408
448
 
409
- becameFirstResponder() {
410
- console.log( "I'm in charge now!" )
411
- }
449
+ > [!WARNING]
450
+ > **Fallback Hover Effect:** If there is no `"pointerover"` or `"mouseover"` handler detected on a container, `Navigation`
451
+ > will apply abasic alpha effect to the selected item to indicate which container is currently the navigation target. This
452
+ > can be disabled by setting `Navigation.options.useFallbackHoverEffect` to `false`.
412
453
 
413
- resignedAsFirstResponder() {
414
- console.log( "Nooo! My power is gone!" )
415
- }
416
- }
417
454
 
418
- const myMenu = new MyVerticalMenu()
419
- Navigation.pushResponder( myMenu )
420
- ```
455
+ ### Disable Navigation
421
456
 
422
- In a game, you might use this to disable navigation outside of menus:
457
+ You can **disable** the navigation API entirely, either permanently or temporaril):
423
458
 
424
459
  ```ts
425
- class GameScene implements NavigationResponder
426
- {
427
- handledNavigationIntent( intent, device ) {
428
- // ignore navigation intents, but allow other navigatable
429
- // views to be pushed on top of me - e.g. a dialog window:
430
- return true
431
- }
432
- }
460
+ Navigation.options.enabled = false
433
461
  ```
434
462
 
435
- ### Default Navigation Binds
436
-
437
- Keyboard and gamepad devices are configured with a few default binds for navigation.
438
-
439
- The default binds are below:
440
-
441
- Navigation Intent | Keyboard | Gamepad
442
- ------------------|------------------------|-----------------------------------
443
- `"navigateLeft"` | `ArrowLeft`, `KeyA` | Left Joystick (Left), `DPadLeft`
444
- `"navigateRight"` | `ArrowRight`, `KeyD` | Left Joystick (Right), `DPadRight`
445
- `"navigateUp"` | `ArrowUp`, `KeyW` | Left Joystick (Up), `DPadDown`
446
- `"navigateDown"` | `ArrowDown`, `KeyS` | Left Joystick (Down), `DPadUp`
447
- `"navigateBack"` | `Escape`, `Backspace` | `B`, `Back`
448
- `"trigger"` | `Enter,` `Space` | `A`
449
-
450
- These can be manually configured in `<device>.options.navigation.binds`.
451
-
452
- #### Container Mixin
453
-
454
- Container properties | type | default | description
455
- ---------------------|------|---------|--------------
456
- `isNavigatable` | `boolean` | `false` | returns `true` if `navigationMode` is set to `"target"`, or is `"auto"` and a `"pointerdown"` or `"mousedown"` event handler is registered.
457
- `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.
458
- `navigationPriority` | `number` | `0` | The priority relative to other navigation items in this group.
459
-
460
- Container events | description
461
- ------------------|--------------------------------------------------------
462
- `focus` | Target became focused.
463
- `blur` | Target lost focus.
464
-
465
463
 
466
464
  ## Advanced usage
467
465
 
@@ -519,7 +517,7 @@ InputDevice.remove( onscreen )
519
517
  You could set up multiple named inputs:
520
518
 
521
519
  ```ts
522
- InputDevice.keyboard.options.namedGroups = {
520
+ InputDevice.keyboard.options.binds = {
523
521
  jump: [ "ArrowUp", "KeyW" ],
524
522
  defend: [ "ArrowDown", "KeyS" ],
525
523
  left: [ "ArrowLeft", "KeyA" ],
@@ -540,25 +538,25 @@ InputDevice.keyboard.options.namedGroups = {
540
538
  and then switch groups depending on the mode:
541
539
 
542
540
  ```ts
543
- if ( gameMode === "2p" )
541
+ if ( gameMode === "multiplayer" )
544
542
  {
545
- // multiplayer
546
- player1.jump = device.pressedGroup( "p1_jump" )
547
- player1.defend = device.pressedGroup( "p1_defend" )
548
- player1.moveX += device.pressedGroup( "p1_left" ) ? -1 : 0
549
- player1.moveX += device.pressedGroup( "p1_right" ) ? 1 : 0
550
- player2.jump = device.pressedGroup( "p2_jump" )
551
- player2.defend = device.pressedGroup( "p2_defend" )
552
- player2.moveX += device.pressedGroup( "p2_left" ) ? -1 : 0
553
- player2.moveX += device.pressedGroup( "p2_right" ) ? 1 : 0
543
+ player1.jump = device.bindPressed( "p1_jump" )
544
+ player1.defend = device.bindPressed( "p1_defend" )
545
+ player1.moveX += device.bindPressed( "p1_left" ) ? -1 : 0
546
+ player1.moveX += device.bindPressed( "p1_right" ) ? 1 : 0
547
+
548
+ player2.jump = device.bindPressed( "p2_jump" )
549
+ player2.defend = device.bindPressed( "p2_defend" )
550
+ player2.moveX += device.bindPressed( "p2_left" ) ? -1 : 0
551
+ player2.moveX += device.bindPressed( "p2_right" ) ? 1 : 0
554
552
  }
555
553
  else
556
554
  {
557
- // single player
558
- player1.jump = device.pressedGroup( "jump" )
559
- player1.defend = device.pressedGroup( "defend" )
560
- player1.moveX += device.pressedGroup( "left" ) ? -1 : 0
561
- player1.moveX += device.pressedGroup( "right" ) ? 1 : 0
562
- player2.updateComputerPlayer()
555
+ player1.jump = device.bindPressed( "jump" )
556
+ player1.defend = device.bindPressed( "defend" )
557
+ player1.moveX += device.bindPressed( "left" ) ? -1 : 0
558
+ player1.moveX += device.bindPressed( "right" ) ? 1 : 0
559
+
560
+ updateComputerPlayerInput( player2 )
563
561
  }
564
562
  ```