pixijs-input-devices 0.2.9 → 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,112 +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
- Navigation.stage = app.stage
353
-
354
- const button = new ButtonSprite()
355
- button.on( "mousedown", () => button.run( clickAnimation ) )
356
- button.on( "mouseout", () => button.run( resetAnimation ) )
357
- 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.
358
409
 
359
- app.stage.addChild( button )
360
-
361
- button.isNavigatable // true
362
- ```
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**.
363
413
 
364
414
  > [!NOTE]
365
- > **isNavigatable:** By default, any element with `"mousedown"` or `"pointerdown"` handlers is navigatable.
415
+ > The **current root container** is the top-most `Container` on the navigation responder stack, or otherwise `Navigation.stage`.
366
416
 
367
- > [!WARNING]
368
- > **Fallback Hover Effect:** If there is no `"pointerover"` or `"mouseover"` handler detected on a container, `Navigation`
369
- > will apply abasic alpha effect to the selected item to indicate which container is currently the navigation target. This
370
- > can be disabled by setting `Navigation.options.useFallbackHoverEffect` to `false`.
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**.
371
419
 
372
- ### Disable Navigation
420
+ ### Default UI Navigation Behavior
373
421
 
374
- You can **disable** the navigation API - either permanently or temporarily - like so:
422
+ When a navigation intent is **not** handled manually by a responder, it is handled in one of the following ways:
375
423
 
376
- ```ts
377
- Navigation.options.enabled = false
378
- ```
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>|
379
429
 
380
- ### Navigation Hierarchy
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"`
381
435
 
382
- UIs can be complex! The Navigation API allows you to take over some - or all - of the navigation elements.
436
+ ### Container Navigation
383
437
 
384
- ```ts
385
- class MyVerticalMenu implements NavigationResponder
386
- {
387
- becameFirstResponder() {
388
- console.log( "I'm in charge now!" )
389
- }
438
+ Containers are extended with a few properties/accesors:
390
439
 
391
- resignedAsFirstResponder() {
392
- console.log( "Nooo! My power is gone!" )
393
- }
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.
394
445
 
395
- handledNavigationIntent( intent, device ): boolean {
396
- if ( intent === "navigateUp" ) this.moveCursorUp()
397
- else if ( intent === "navigateDown" ) this.moveCursorDown()
398
- else if ( intent === "navigateBack" ) this.loseFocus()
399
- else if ( intent === "trigger" ) this.clickCursorItem()
446
+ > [!NOTE]
447
+ > **isNavigatable:** By default, any element with `"pointerdown"` or `"mousedown"` handlers is navigatable.
400
448
 
401
- // we are going to return false here, which will propagates unhandled
402
- // intents ("navigateLeft", "navigateRight") up to the next responder
403
- // in the stack - which could be a parent view, etc.
404
- return false
405
- }
406
- }
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`.
407
453
 
408
- const myMenu = new MyVerticalMenu()
409
- Navigation.pushResponder( myMenu )
410
- ```
411
454
 
412
- In a game, you might use this to disable navigation outside of menus:
455
+ ### Disable Navigation
456
+
457
+ You can **disable** the navigation API entirely, either permanently or temporaril):
413
458
 
414
459
  ```ts
415
- class GameScene implements NavigationResponder
416
- {
417
- handledNavigationIntent( intent, device ) {
418
- // ignore navigation intents, but allow other navigatable
419
- // views to be pushed on top of me - e.g. a dialog window:
420
- return true
421
- }
422
- }
460
+ Navigation.options.enabled = false
423
461
  ```
424
462
 
425
- ### Default Navigation Binds
426
-
427
- Keyboard and gamepad devices are configured with a few default binds for navigation.
428
-
429
- The default binds are below:
430
-
431
- Navigation Intent | Keyboard | Gamepad
432
- ------------------|------------------------|-----------------------------------
433
- `"navigateLeft"` | `ArrowLeft`, `KeyA` | Left Joystick (Left), `DPadLeft`
434
- `"navigateRight"` | `ArrowRight`, `KeyD` | Left Joystick (Right), `DPadRight`
435
- `"navigateUp"` | `ArrowUp`, `KeyW` | Left Joystick (Up), `DPadDown`
436
- `"navigateDown"` | `ArrowDown`, `KeyS` | Left Joystick (Down), `DPadUp`
437
- `"navigateBack"` | `Escape`, `Backspace` | `B`, `Back`
438
- `"trigger"` | `Enter,` `Space` | `A`
439
-
440
- These can be manually configured in `<device>.options.navigation.binds`.
441
-
442
- #### Container Mixin
443
-
444
- Container properties | type | default | description
445
- ---------------------|------|---------|--------------
446
- `isNavigatable` | `boolean` | `false` | returns `true` if `navigationMode` is set to `"target"`, or is `"auto"` and a `"pointerdown"` or `"mousedown"` event handler is registered.
447
- `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.
448
- `navigationPriority` | `number` | `0` | The priority relative to other navigation items in this group.
449
-
450
- Container events | description
451
- ------------------|--------------------------------------------------------
452
- `focus` | Target became focused.
453
- `blur` | Target lost focus.
454
-
455
463
 
456
464
  ## Advanced usage
457
465
 
@@ -509,7 +517,7 @@ InputDevice.remove( onscreen )
509
517
  You could set up multiple named inputs:
510
518
 
511
519
  ```ts
512
- InputDevice.keyboard.options.namedGroups = {
520
+ InputDevice.keyboard.options.binds = {
513
521
  jump: [ "ArrowUp", "KeyW" ],
514
522
  defend: [ "ArrowDown", "KeyS" ],
515
523
  left: [ "ArrowLeft", "KeyA" ],
@@ -530,25 +538,25 @@ InputDevice.keyboard.options.namedGroups = {
530
538
  and then switch groups depending on the mode:
531
539
 
532
540
  ```ts
533
- if ( gameMode === "2p" )
541
+ if ( gameMode === "multiplayer" )
534
542
  {
535
- // multiplayer
536
- player1.jump = device.pressedGroup( "p1_jump" )
537
- player1.defend = device.pressedGroup( "p1_defend" )
538
- player1.moveX += device.pressedGroup( "p1_left" ) ? -1 : 0
539
- player1.moveX += device.pressedGroup( "p1_right" ) ? 1 : 0
540
- player2.jump = device.pressedGroup( "p2_jump" )
541
- player2.defend = device.pressedGroup( "p2_defend" )
542
- player2.moveX += device.pressedGroup( "p2_left" ) ? -1 : 0
543
- 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
544
552
  }
545
553
  else
546
554
  {
547
- // single player
548
- player1.jump = device.pressedGroup( "jump" )
549
- player1.defend = device.pressedGroup( "defend" )
550
- player1.moveX += device.pressedGroup( "left" ) ? -1 : 0
551
- player1.moveX += device.pressedGroup( "right" ) ? 1 : 0
552
- 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 )
553
561
  }
554
562
  ```