pixijs-input-devices 0.5.7 → 0.6.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 +207 -180
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +110 -87
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -12
package/README.md
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
| | |
|
|
6
6
|
| ------ | ------ |
|
|
7
|
-
| 🎮
|
|
8
|
-
| ⚡
|
|
9
|
-
| 🔮 Highly configurable |
|
|
10
|
-
| ✅ Cross-platform & mobile-friendly <sup>[[1]](https://caniuse.com/mdn-api_keyboardlayoutmap) [[2]](https://caniuse.com/mdn-api_gamepad_vibrationactuator) [[3]](https://chromestatus.com/feature/5989275208253440)</sup> |
|
|
7
|
+
| 🎮 Handle [keyboard](#keyboarddevice), [gamepads](#gamepaddevice), and [more](#custom-devices)! | 🚀 [Real-time](#real-time) & [event-driven](#keyboarddevice-events) APIs |
|
|
8
|
+
| ⚡ Highly-optimized for [performance](https://web.dev/articles/inp) | 🧭 Built-in [UI navigation](#uinavigation-api) |
|
|
9
|
+
| 🔮 Highly configurable (with sensible defaults) | 🪄 Supports [input binding](#named-binds) |
|
|
10
|
+
| ✅ Cross-platform & mobile-friendly <sup>[[1]](https://caniuse.com/mdn-api_keyboardlayoutmap) [[2]](https://caniuse.com/mdn-api_gamepad_vibrationactuator) [[3]](https://chromestatus.com/feature/5989275208253440)</sup> | 🌐 Automatic [Intl layouts](#keyboard-layout---detection) detection |
|
|
11
11
|
| 🍃 Zero dependencies & tree-shakeable | ✨ Supports PixiJS v8, v7, v6.3+ |
|
|
12
12
|
|
|
13
13
|
|
|
@@ -16,37 +16,43 @@
|
|
|
16
16
|
*Handle device inputs with ease.*
|
|
17
17
|
|
|
18
18
|
```ts
|
|
19
|
-
import { InputDevice, GamepadDevice } from "pixijs-input-devices"
|
|
19
|
+
import { InputDevice, GamepadDevice } from "pixijs-input-devices"
|
|
20
|
+
|
|
20
21
|
|
|
21
22
|
// Set named binds
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
GamepadDevice.configureDefaultBinds({
|
|
24
|
+
jump: [ "Face1" ]
|
|
25
|
+
})
|
|
26
|
+
InputDevice.keyboard.configureBinds({
|
|
27
|
+
jump: [ "ArrowUp", "Space" ]
|
|
28
|
+
})
|
|
24
29
|
|
|
25
30
|
// Use binds
|
|
26
|
-
for (
|
|
27
|
-
if (
|
|
31
|
+
for (const device of InputDevice.devices) {
|
|
32
|
+
if (device.bindDown("jump")) // ...
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
// Event-driven
|
|
31
|
-
InputDevice.
|
|
32
|
-
if (
|
|
33
|
-
|
|
36
|
+
InputDevice.onBindDown("jump", ({ device }) => {
|
|
37
|
+
if (device.type === "gamepad") {
|
|
38
|
+
device.playVibration({ duration: 50 })
|
|
34
39
|
}
|
|
35
|
-
)
|
|
40
|
+
})
|
|
36
41
|
```
|
|
37
42
|
|
|
38
43
|
## Getting Started with PixiJS Input Devices
|
|
39
44
|
|
|
40
|
-
*Everything you need to quickly integrate
|
|
45
|
+
*Everything you need to quickly integrate device management.*
|
|
41
46
|
|
|
42
|
-
**PixiJS Input Devices** adds first-class support for input
|
|
43
|
-
that can enable
|
|
47
|
+
**PixiJS Input Devices** adds first-class support for input devices, and
|
|
48
|
+
provides a simple, but powerful navigation manager that can enable devices to
|
|
49
|
+
navigate existing pointer-based UIs.
|
|
44
50
|
|
|
45
|
-
The
|
|
51
|
+
The key concepts are:
|
|
46
52
|
|
|
47
53
|
1. **Devices:** _Any human interface device_
|
|
48
54
|
2. **Binds:** _Custom, named input actions that can be triggered by assigned keys or buttons_
|
|
49
|
-
3. **UINavigation:**
|
|
55
|
+
3. **UINavigation:** _Navigation manager for non-pointer devices to navigate UIs_
|
|
50
56
|
|
|
51
57
|
> [!NOTE]
|
|
52
58
|
> _See [UINavigation API](#uinavigation-api) for more information._
|
|
@@ -69,10 +75,11 @@ yarn add pixijs-input-devices --dev
|
|
|
69
75
|
**2.** Register the update loop:
|
|
70
76
|
|
|
71
77
|
```ts
|
|
72
|
-
import { Ticker } from 'pixi.js'
|
|
73
|
-
import { InputDevice } from 'pixijs-input-devices'
|
|
78
|
+
import { Ticker } from 'pixi.js'
|
|
79
|
+
import { InputDevice } from 'pixijs-input-devices'
|
|
80
|
+
|
|
74
81
|
|
|
75
|
-
Ticker.shared.add(
|
|
82
|
+
Ticker.shared.add(() => InputDevice.update())
|
|
76
83
|
```
|
|
77
84
|
|
|
78
85
|
> [!TIP]
|
|
@@ -81,14 +88,15 @@ Ticker.shared.add(ticker => InputDevice.update());
|
|
|
81
88
|
**3.** (Optional) enable the UINavigation API
|
|
82
89
|
|
|
83
90
|
```ts
|
|
84
|
-
import * as PIXI from 'pixi.js'
|
|
85
|
-
import { UINavigation, registerPixiJSNavigationMixin } from 'pixijs-input-devices'
|
|
91
|
+
import * as PIXI from 'pixi.js'
|
|
92
|
+
import { UINavigation, registerPixiJSNavigationMixin } from 'pixijs-input-devices'
|
|
93
|
+
|
|
86
94
|
|
|
87
95
|
const app = new PIXI.Application(/*…*/)
|
|
88
96
|
|
|
89
97
|
// enable the navigation API
|
|
90
|
-
UINavigation.configureWithRoot(
|
|
91
|
-
registerPixiJSNavigationMixin(
|
|
98
|
+
UINavigation.configureWithRoot(app.stage)
|
|
99
|
+
registerPixiJSNavigationMixin(PIXI.Container)
|
|
92
100
|
```
|
|
93
101
|
|
|
94
102
|
✨ You are now ready to use inputs!
|
|
@@ -101,46 +109,65 @@ The `InputDevice` singleton controls all device discovery.
|
|
|
101
109
|
|
|
102
110
|
```ts
|
|
103
111
|
InputDevice.keyboard // KeyboardDevice
|
|
104
|
-
InputDevice.gamepads //
|
|
105
|
-
InputDevice.custom //
|
|
112
|
+
InputDevice.gamepads // GamepadDevice[]
|
|
113
|
+
InputDevice.custom // Device[]
|
|
106
114
|
```
|
|
107
115
|
|
|
108
116
|
You can access all **active/connected** devices using `.devices`:
|
|
109
117
|
|
|
110
118
|
```ts
|
|
111
|
-
for (
|
|
119
|
+
for (const device of InputDevice.devices) { // …
|
|
112
120
|
```
|
|
113
121
|
|
|
114
122
|
#### InputDevice - properties
|
|
115
123
|
|
|
124
|
+
The `InputDevice` manager provides the following **context capability** properties:
|
|
125
|
+
|
|
116
126
|
| Property | Type | Description |
|
|
117
127
|
|---|---|---|
|
|
118
|
-
| `InputDevice.
|
|
119
|
-
| `InputDevice.
|
|
128
|
+
| `InputDevice.hasMouseLikePointer` | `boolean` | Whether the context has a mouse/trackpad. |
|
|
129
|
+
| `InputDevice.isMobile` | `boolean` | Whether the context is mobile capable. |
|
|
130
|
+
| `InputDevice.isTouchCapable` | `boolean` | Whether the context is touchscreen capable. |
|
|
131
|
+
|
|
132
|
+
As well as shortcuts to **connected devices**:
|
|
133
|
+
|
|
134
|
+
| Accessor | Type | Description |
|
|
135
|
+
|---|---|---|
|
|
120
136
|
| `InputDevice.lastInteractedDevice` | `Device?` | The most recently interacted device (or first if multiple). |
|
|
121
137
|
| `InputDevice.devices` | `Device[]` | All active, connected devices. |
|
|
122
138
|
| `InputDevice.keyboard` | `KeyboardDevice` | The global keyboard. |
|
|
123
139
|
| `InputDevice.gamepads` | `GamepadDevice[]` | Connected gamepads. |
|
|
124
|
-
| `InputDevice.custom` | `CustomDevice[]` |
|
|
140
|
+
| `InputDevice.custom` | `CustomDevice[]` | Any custom devices. |
|
|
125
141
|
|
|
126
142
|
#### InputDevice - on() Events
|
|
127
143
|
|
|
128
144
|
Access global events directly through the manager:
|
|
129
145
|
|
|
130
146
|
```ts
|
|
131
|
-
InputDevice.on(
|
|
132
|
-
//
|
|
147
|
+
InputDevice.on("deviceadded", ({ device }) => {
|
|
148
|
+
// new device was connected or became available
|
|
133
149
|
// do additional setup here, show a dialog, etc.
|
|
134
150
|
})
|
|
135
151
|
|
|
136
|
-
InputDevice.off(
|
|
152
|
+
InputDevice.off("deviceadded") // stop listening
|
|
137
153
|
```
|
|
138
154
|
|
|
139
155
|
| Event | Description | Payload |
|
|
140
156
|
|---|---|---|
|
|
141
157
|
| `"deviceadded"` | `{device}` | A device has been added. |
|
|
142
158
|
| `"deviceremoved"` | `{device}` | A device has been removed. |
|
|
159
|
+
| `"lastdevicechanged"` | `{device}` | The _last interacted device_ has changed. |
|
|
160
|
+
|
|
143
161
|
|
|
162
|
+
#### InputDevice - onBindDown() Events
|
|
163
|
+
|
|
164
|
+
You may also subscribe globally to **named bind** events:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
InputDevice.onBindDown("my_custom_bind", (event) => {
|
|
168
|
+
// a bound input waas triggered
|
|
169
|
+
})
|
|
170
|
+
```
|
|
144
171
|
|
|
145
172
|
### KeyboardDevice
|
|
146
173
|
|
|
@@ -149,7 +176,7 @@ Unlike gamepads & custom devices, there is a single global keyboard device.
|
|
|
149
176
|
```ts
|
|
150
177
|
let keyboard = InputDevice.keyboard
|
|
151
178
|
|
|
152
|
-
if (
|
|
179
|
+
if (keyboard.key.ControlLeft) { // …
|
|
153
180
|
```
|
|
154
181
|
|
|
155
182
|
> [!NOTE]
|
|
@@ -161,7 +188,7 @@ if ( keyboard.key.ControlLeft ) { // …
|
|
|
161
188
|
```ts
|
|
162
189
|
keyboard.layout // "AZERTY" | "JCUKEN" | "QWERTY" | "QWERTZ"
|
|
163
190
|
|
|
164
|
-
keyboard.getKeyLabel(
|
|
191
|
+
keyboard.getKeyLabel("KeyZ") // Я
|
|
165
192
|
```
|
|
166
193
|
|
|
167
194
|
> [!NOTE]
|
|
@@ -169,7 +196,7 @@ keyboard.getKeyLabel( "KeyZ" ) // Я
|
|
|
169
196
|
> Almost every keyboard is one of these four (or a regional derivative – e.g. Hangeul,
|
|
170
197
|
> Kana). There is no built-in detection for specialist or esoteric layouts (e.g. Dvorak, Colemak, BÉPO).
|
|
171
198
|
>
|
|
172
|
-
> The `keyboard.getKeyLabel(
|
|
199
|
+
> The `keyboard.getKeyLabel(key)` uses the [KeyboardLayoutMap API](https://caniuse.com/mdn-api_keyboardlayoutmap)
|
|
173
200
|
> when available, before falling back to default AZERTY, JCUKEN, QWERTY or QWERTZ key values.
|
|
174
201
|
|
|
175
202
|
The keyboard layout is automatically detected from (in order):
|
|
@@ -184,7 +211,7 @@ You can also manually force the layout:
|
|
|
184
211
|
// force layout
|
|
185
212
|
InputDevice.keyboard.layout = "JCUKEN"
|
|
186
213
|
|
|
187
|
-
InputDevice.keyboard.getKeyLabel(
|
|
214
|
+
InputDevice.keyboard.getKeyLabel("KeyW") // "Ц"
|
|
188
215
|
InputDevice.keyboard.layoutSource // "manual"
|
|
189
216
|
```
|
|
190
217
|
|
|
@@ -193,7 +220,7 @@ InputDevice.keyboard.layoutSource // "manual"
|
|
|
193
220
|
| Event | Description | Payload |
|
|
194
221
|
|---|---|---|
|
|
195
222
|
| `"layoutdetected"` | `{layout,layoutSource,device}` | The keyboard layout (`"QWERTY"`, `"QWERTZ"`, `"AZERTY"`, or `"JCUKEN"`) has been detected, either from the native API or from keypresses. |
|
|
196
|
-
| `"
|
|
223
|
+
| `"binddown"` | `{name,event,keyCode,keyLabel,device}` | A **named bind** key was pressed. |
|
|
197
224
|
| **Key presses:** | | |
|
|
198
225
|
| `"KeyA"` | `{event,keyCode,keyLabel,device}` | The `"KeyA"` was pressed. |
|
|
199
226
|
| `"KeyB"` | `{event,keyCode,keyLabel,device}` | The `"KeyB"` was pressed. |
|
|
@@ -208,11 +235,22 @@ Gamepads are automatically detected via the browser API when first interacted wi
|
|
|
208
235
|
Gamepad accessors are modelled around the "Standard Controller Layout":
|
|
209
236
|
|
|
210
237
|
```ts
|
|
211
|
-
|
|
238
|
+
const gamepad = InputDevice.gamepads[0];
|
|
239
|
+
|
|
240
|
+
if (gamepad.button.DpadDown)
|
|
241
|
+
{
|
|
242
|
+
// button pressed
|
|
243
|
+
}
|
|
212
244
|
|
|
213
|
-
if (
|
|
214
|
-
|
|
215
|
-
|
|
245
|
+
if (gamepad.leftTrigger > 0.25)
|
|
246
|
+
{
|
|
247
|
+
// trigger pulled
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (gamepad.leftJoystick.x < -0.33)
|
|
251
|
+
{
|
|
252
|
+
// joystick moved
|
|
253
|
+
}
|
|
216
254
|
```
|
|
217
255
|
|
|
218
256
|
> [!TIP]
|
|
@@ -236,24 +274,24 @@ gamepad.playVibration({
|
|
|
236
274
|
|
|
237
275
|
The gamepad buttons reference **Standard Controller Layout**:
|
|
238
276
|
|
|
239
|
-
| Button
|
|
277
|
+
| Button # | GamepadCode | Description | Xbox Series X | Playstation 5 DualSense® | Nintendo Switch™ Pro |
|
|
240
278
|
|:---:|:---|:---|:---:|:---:|:---:|
|
|
241
|
-
| `0` | `"
|
|
242
|
-
| `1` | `"
|
|
243
|
-
| `2` | `"
|
|
244
|
-
| `3` | `"
|
|
279
|
+
| `0` | `"Face1"` | **Face Button 1** | A | Cross | B |
|
|
280
|
+
| `1` | `"Face2"` | **Face Button 2** | B | Circle | A |
|
|
281
|
+
| `2` | `"Face3"` | **Face Button 3** | X | Square | Y |
|
|
282
|
+
| `3` | `"Face4"` | **Face Button 4** | Y | Triangle | X |
|
|
245
283
|
| `4` | `"LeftShoulder"` | **Left Shoulder** | LB | L1 | L |
|
|
246
284
|
| `5` | `"RightShoulder"` | **Right Shoulder** | RB | R1 | R |
|
|
247
285
|
| `6` | `"LeftTrigger"` | **Left Trigger** | LT | L2 | ZL |
|
|
248
286
|
| `7` | `"RightTrigger"` | **Right Trigger** | RT | R2 | ZR |
|
|
249
|
-
| `8` | `"Back"` | **Back** |
|
|
250
|
-
| `9` | `"Start"` | **Start** |
|
|
251
|
-
| `10` | `"LeftStickClick"` | **Left Stick Click** | LSB | L3 | L3 |
|
|
252
|
-
| `11` | `"RightStickClick"` | **Right Stick Click** | RSB | R3 | R3 |
|
|
253
|
-
| `12` | `"
|
|
254
|
-
| `13` | `"
|
|
255
|
-
| `14` | `"
|
|
256
|
-
| `15` | `"
|
|
287
|
+
| `8` | `"Back"` | **Back** | View | Options | Minus |
|
|
288
|
+
| `9` | `"Start"` | **Start** | Menu | Select | Plus |
|
|
289
|
+
| `10` | `"LeftStickClick"` | **Left Stick (Click)** | LSB | L3 | L3 |
|
|
290
|
+
| `11` | `"RightStickClick"` | **Right Stick (Click)** | RSB | R3 | R3 |
|
|
291
|
+
| `12` | `"DpadUp"` | **D-Pad Up** | ⬆️ | ⬆️ | ⬆️ |
|
|
292
|
+
| `13` | `"DpadDown"` | **D-Pad Down** | ⬇️ | ⬇️ | ⬇️ |
|
|
293
|
+
| `14` | `"DpadLeft"` | **D-Pad Left** | ⬅️ | ⬅️ | ⬅️ |
|
|
294
|
+
| `15` | `"DpadRight"` | **D-Pad Right** | ➡️ | ➡️ | ➡️ |
|
|
257
295
|
|
|
258
296
|
#### Gamepad Axis Codes
|
|
259
297
|
|
|
@@ -261,71 +299,32 @@ Bindable helpers are available for the joysticks too:
|
|
|
261
299
|
|
|
262
300
|
| Axis # | GamepadCode | Standard | Layout
|
|
263
301
|
|:---:|:---:|:---:|:---:|
|
|
264
|
-
| `0` | `"LeftStickLeft"`<br/>`"LeftStickRight"` | **Left Stick (
|
|
265
|
-
| `1` | `"LeftStickUp"`<br/>`"LeftStickDown"` | **Left Stick (
|
|
266
|
-
| `2` | `"RightStickLeft"`<br/>`"RightStickRight"` | **Right Stick (
|
|
267
|
-
| `3` | `"RightStickUp"`<br/>`"RightStickDown"` | **Right Stick (
|
|
302
|
+
| `0` | `"LeftStickLeft"`<br/>`"LeftStickRight"` | **Left Stick (X-Axis)** | ⬅️➡️ |
|
|
303
|
+
| `1` | `"LeftStickUp"`<br/>`"LeftStickDown"` | **Left Stick (Y-Axis)** | ⬆️⬇️ |
|
|
304
|
+
| `2` | `"RightStickLeft"`<br/>`"RightStickRight"` | **Right Stick (X-Axis)** | ⬅️➡️ |
|
|
305
|
+
| `3` | `"RightStickUp"`<br/>`"RightStickDown"` | **Right Stick (Y-Axis)** | ⬆️⬇️ |
|
|
268
306
|
|
|
269
307
|
> [!TIP]
|
|
270
|
-
> Set the `joystick.
|
|
308
|
+
> Set the `joystick.pressThreshold` option in `GamepadDevice.defaultOptions` to adjust event sensitivity.
|
|
271
309
|
|
|
272
310
|
#### Gamepad Layouts
|
|
273
311
|
|
|
274
312
|
```ts
|
|
275
|
-
gamepad.layout
|
|
313
|
+
gamepad.layout // "xbox_one"
|
|
276
314
|
```
|
|
277
315
|
|
|
278
|
-
|
|
279
|
-
improvements (e.
|
|
280
|
-
|
|
281
|
-
There is some limited layout remapping support built-in for Nintendo controllers, which appear to be the
|
|
282
|
-
only major brand controller that deviates from the standard.
|
|
283
|
-
|
|
284
|
-
##### Gamepad - Nintendo Layout Remapping
|
|
285
|
-
|
|
286
|
-
> [!CAUTION]
|
|
287
|
-
> ***Nintendo:** Both the labels and physical positions of the A,B,X,Y buttons are different
|
|
288
|
-
> on Nintendo controllers.
|
|
289
|
-
>
|
|
290
|
-
> Set `GamepadDevice.defaultOptions.nintendoRemapMode` to apply the remapping as required.
|
|
291
|
-
>
|
|
292
|
-
> - `"physical"` _**(default)**_ – The A,B,X,Y button codes will refer the standard face button positions (Left=X, Top=Y, Bottom=A, Right=B).
|
|
293
|
-
> - `"accurate"` – The A,B,X,Y button codes will refer to the exact Nintendo labels (Left=Y, Top=X, Bottom=B, Right=A).
|
|
294
|
-
> - `"none"` – The A,B,X,Y button codes mapping stay at the default indices (Left=Y, Top=B, Bottom=X, Right=A).
|
|
295
|
-
>
|
|
296
|
-
> ```
|
|
297
|
-
> standard nintendo nintendo nintendo
|
|
298
|
-
> layout "physical" "accurate" "none"
|
|
299
|
-
> reference (default)
|
|
300
|
-
>
|
|
301
|
-
> Y Y X B
|
|
302
|
-
> X B X B Y A Y A
|
|
303
|
-
> A A B X
|
|
304
|
-
>
|
|
305
|
-
> 3 3 2 1
|
|
306
|
-
> 2 1 2 1 3 0 3 0
|
|
307
|
-
> 0 0 1 2
|
|
308
|
-
> ```
|
|
309
|
-
|
|
310
|
-
You can manually override this per-gamepad, or for all gamepads:
|
|
311
|
-
|
|
312
|
-
```ts
|
|
313
|
-
// set default
|
|
314
|
-
GamepadDevice.defaultOptions.nintendoRemapMode = "none"
|
|
315
|
-
|
|
316
|
-
// set for a single gamepad
|
|
317
|
-
gamepad.options.nintendoRemapMode = "accurate"
|
|
318
|
-
```
|
|
316
|
+
Gamepad device layout reporting is a non-standard API, and should only be used for aesthetic
|
|
317
|
+
enhancements improvements (i.e. [display layout-specific icons](https://thoseawesomeguys.com/prompts/)).
|
|
319
318
|
|
|
320
319
|
#### GamepadDevice Events
|
|
321
320
|
|
|
322
321
|
| Event | Description | Payload |
|
|
323
322
|
|---|---|---|
|
|
324
|
-
| `"
|
|
323
|
+
| `"binddown"` | `{name,button,buttonCode,device}` | A **named bind** button was pressed. |
|
|
325
324
|
| **Button presses:** | | |
|
|
326
|
-
| `"
|
|
327
|
-
| `"
|
|
328
|
-
| `"
|
|
325
|
+
| `"Face1"` | `{button,buttonCode,device}` | Standard layout button `"Face1"` was pressed. Equivalent to `0`. |
|
|
326
|
+
| `"Face2"` | `{button,buttonCode,device}` | Standard layout button `"Face2"` was pressed. Equivalent to `1`. |
|
|
327
|
+
| `"Face3"` | `{button,buttonCode,device}` | Standard layout button `"Face3"` was pressed. Equivalent to `2`. |
|
|
329
328
|
| … | … | … |
|
|
330
329
|
| **Button presses (no label):** | | |
|
|
331
330
|
| `0` or `Button.A` | `{button,buttonCode,device}` | Button at offset `0` was pressed. |
|
|
@@ -340,17 +339,16 @@ You can add custom devices to the device manager so it will be polled togehter a
|
|
|
340
339
|
```ts
|
|
341
340
|
import { type CustomDevice, InputDevice } from "pixijs-input-devices"
|
|
342
341
|
|
|
343
|
-
export const
|
|
344
|
-
id: "on-screen-buttons",
|
|
342
|
+
export const onScreenButtonsDevice: CustomDevice = {
|
|
345
343
|
type: "custom",
|
|
344
|
+
id: "OnScreen",
|
|
346
345
|
meta: {},
|
|
347
|
-
|
|
348
|
-
update: ( now: number ) => {
|
|
346
|
+
update: (now: number) => {
|
|
349
347
|
// polling update
|
|
350
348
|
}
|
|
351
|
-
}
|
|
349
|
+
};
|
|
352
350
|
|
|
353
|
-
InputDevice.add(
|
|
351
|
+
InputDevice.add(onScreenButtonsDevice);
|
|
354
352
|
```
|
|
355
353
|
|
|
356
354
|
## Named Binds
|
|
@@ -369,8 +367,8 @@ InputDevice.keyboard.configureBinds({
|
|
|
369
367
|
|
|
370
368
|
// all gamepads:
|
|
371
369
|
GamepadDevice.configureDefaultBinds({
|
|
372
|
-
jump: [ "
|
|
373
|
-
crouch: [ "
|
|
370
|
+
jump: [ "Face1", "LeftStickUp" ],
|
|
371
|
+
crouch: [ "Face2", "Face3", "RightTrigger" ],
|
|
374
372
|
toggleGraphics: [ "RightStickUp", "RightStickDown" ],
|
|
375
373
|
})
|
|
376
374
|
```
|
|
@@ -381,11 +379,11 @@ These can then be used with either the real-time and event-based APIs.
|
|
|
381
379
|
|
|
382
380
|
```ts
|
|
383
381
|
// listen to all devices:
|
|
384
|
-
InputDevice.
|
|
382
|
+
InputDevice.onBindDown("toggleGraphics", (e) => toggleGraphics())
|
|
385
383
|
|
|
386
384
|
// listen to specific devices:
|
|
387
|
-
InputDevice.keyboard.
|
|
388
|
-
InputDevice.gamepads[0].
|
|
385
|
+
InputDevice.keyboard.onBindDown("jump", (e) => doJump())
|
|
386
|
+
InputDevice.gamepads[0].onBindDown("jump", (e) => doJump())
|
|
389
387
|
```
|
|
390
388
|
|
|
391
389
|
#### Real-time:
|
|
@@ -394,19 +392,19 @@ InputDevice.gamepads[0].onBind( "jump", ( e ) => doJump() )
|
|
|
394
392
|
let jump = false, crouch = false, moveX = 0
|
|
395
393
|
|
|
396
394
|
const keyboard = InputDevice.keyboard
|
|
397
|
-
if (
|
|
398
|
-
if (
|
|
399
|
-
if (
|
|
400
|
-
else if (
|
|
395
|
+
if (keyboard.bindDown("jump")) jump = true
|
|
396
|
+
if (keyboard.bindDown("crouch")) crouch = true
|
|
397
|
+
if (keyboard.key.ArrowLeft) moveX = -1
|
|
398
|
+
else if (keyboard.key.ArrowRight) moveX = 1
|
|
401
399
|
|
|
402
|
-
for (
|
|
403
|
-
if (
|
|
404
|
-
if (
|
|
400
|
+
for (const gamepad of InputDevice.gamepads) {
|
|
401
|
+
if (gamepad.bindDown("jump")) jump = true
|
|
402
|
+
if (gamepad.bindDown("crouch")) crouch = true
|
|
405
403
|
|
|
406
404
|
// gamepads have additional analog inputs
|
|
407
405
|
// we're going to apply these only if touched
|
|
408
|
-
if (
|
|
409
|
-
if (
|
|
406
|
+
if (gamepad.leftJoystick.x != 0) moveX = gamepad.leftJoystick.x
|
|
407
|
+
if (gamepad.leftTrigger > 0) moveX *= (1 - gamepad.leftTrigger)
|
|
410
408
|
}
|
|
411
409
|
```
|
|
412
410
|
|
|
@@ -414,19 +412,34 @@ for ( const gamepad of InputDevice.gamepads ) {
|
|
|
414
412
|
|
|
415
413
|
_Traverse a UI using input devices._
|
|
416
414
|
|
|
415
|
+
### Quick setup
|
|
416
|
+
|
|
417
|
+
Set up navigation once using:
|
|
418
|
+
|
|
417
419
|
```ts
|
|
418
|
-
UINavigation.configureWithRoot(
|
|
420
|
+
UINavigation.configureWithRoot(app.stage) // any root container
|
|
421
|
+
registerPixiJSNavigationMixin(PIXI.Container)
|
|
419
422
|
```
|
|
420
423
|
|
|
421
|
-
|
|
424
|
+
Navigation should now work automatically if your buttons handle these events:
|
|
422
425
|
|
|
423
|
-
|
|
424
|
-
// take control
|
|
425
|
-
UINavigation.pushResponder( myModalView )
|
|
426
|
+
- `"pointerdown"` – i.e. Trigger / show press effect
|
|
426
427
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
428
|
+
But in order to really make use, you should also set:
|
|
429
|
+
|
|
430
|
+
- `"pointerover"` – i.e. Select / show hover effect
|
|
431
|
+
- `"pointerout"` – i.e. Deselect / reset
|
|
432
|
+
|
|
433
|
+
> [!TIP]
|
|
434
|
+
> 🖱️ **Seamless navigation:** Manually set `UINavigation.focusTarget = <target>`
|
|
435
|
+
> inside any `"pointerover"` handlers to allow mouse/pointers to update the
|
|
436
|
+
> navigation context for all devices.
|
|
437
|
+
|
|
438
|
+
> [!TIP]
|
|
439
|
+
> **Auto-focus:** Set a container's `navigationPriority` to a value above `0`
|
|
440
|
+
> to become the default selection in a context.
|
|
441
|
+
|
|
442
|
+
### How it works
|
|
430
443
|
|
|
431
444
|
The Navigation API is centered around the **UINavigation** manager, which
|
|
432
445
|
receives navigation intents from devices and forwards it to the UI context.
|
|
@@ -450,21 +463,21 @@ When a navigation intent is **not** handled manually by a responder, it is handl
|
|
|
450
463
|
|`"navigate.left"`, `"navigate.right"`, `"navigate.up"`, `"navigate.down"`|<ul><li>Looks for the nearest `Container` where `container.isNavigatable` in the direction given, and if found, receives a `"deviceover"` event.</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 receives a `"deviceout"` 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>|
|
|
451
464
|
|`"navigate.trigger"`|<ul><li>Checks if we are currently focused on a container, and then issue a `"devicedown"` 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>|
|
|
452
465
|
|
|
453
|
-
Container event | Description | Compatibility
|
|
454
|
-
|
|
455
|
-
`"devicedown"` | Target was triggered. | `"pointerdown"`, `"mousedown"`
|
|
456
|
-
`"deviceover"` | Target became focused. | `"pointerover"`, `"mouseover"`
|
|
457
|
-
`"deviceout"` | Target lost focus. | `"pointerout"`, `"mouseout"`
|
|
466
|
+
| Container event | Description | Compatibility
|
|
467
|
+
|-----------------|-------------|------------------------------------------
|
|
468
|
+
| `"devicedown"` | Target was triggered. | `"pointerdown"`, `"mousedown"`
|
|
469
|
+
| `"deviceover"` | Target became focused. | `"pointerover"`, `"mouseover"`
|
|
470
|
+
| `"deviceout"` | Target lost focus. | `"pointerout"`, `"mouseout"`
|
|
458
471
|
|
|
459
472
|
### Container Navigatability
|
|
460
473
|
|
|
461
474
|
Containers are extended with a few properties/accessors:
|
|
462
475
|
|
|
463
|
-
Container properties | type | default | description
|
|
464
|
-
|
|
465
|
-
`isNavigatable` | `get(): boolean` | `false` | returns `true` if `navigationMode` is set to `"target"`, or is `"auto"` and a `"pointerdown"` or `"mousedown"` event handler is registered.
|
|
466
|
-
`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.
|
|
467
|
-
`navigationPriority` | `number` | `0` | The priority relative to other navigation items in this group.
|
|
476
|
+
| Container properties | type | default | description
|
|
477
|
+
|---------------------|------|---------|--------------
|
|
478
|
+
| `isNavigatable` | `get(): boolean` | `false` | returns `true` if `navigationMode` is set to `"target"`, |or is `"auto"` and a `"pointerdown"` or `"mousedown"` event handler is registered.
|
|
479
|
+
| `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.
|
|
480
|
+
| `navigationPriority` | `number` | `0` | The priority relative to other navigation items in this group.
|
|
468
481
|
|
|
469
482
|
> [!NOTE]
|
|
470
483
|
> **isNavigatable:** By default, any element with `"pointerdown"` or `"mousedown"` handlers is navigatable.
|
|
@@ -472,8 +485,7 @@ Container properties | type | default | description
|
|
|
472
485
|
> [!WARNING]
|
|
473
486
|
> **Fallback Hover Effect:** If there is no `"pointerover"` or `"mouseover"` handler detected on a container, `UINavigation`
|
|
474
487
|
> will apply abasic alpha effect to the selected item to indicate which container is currently the navigation target. This
|
|
475
|
-
> can be disabled by setting `UINavigation.options.
|
|
476
|
-
|
|
488
|
+
> can be disabled by setting `UINavigation.options.enableFallbackOverEffect` to `false`.
|
|
477
489
|
|
|
478
490
|
### Default Binds
|
|
479
491
|
|
|
@@ -481,12 +493,24 @@ The keyboard and gamepad devices are preconfigured with the following binds, fee
|
|
|
481
493
|
|
|
482
494
|
Navigation Intent Bind | Keyboard | Gamepad
|
|
483
495
|
---|---|---
|
|
484
|
-
`"navigate.left"` | "ArrowLeft", "KeyA" | "
|
|
485
|
-
`"navigate.right"` | "ArrowRight", "KeyD" | "
|
|
486
|
-
`"navigate.up"` | "ArrowUp", "KeyW" | "
|
|
487
|
-
`"navigate.down"` | "ArrowDown", "KeyS" | "
|
|
488
|
-
`"navigate.trigger"` | "Enter", "Space" | "
|
|
489
|
-
`"navigate.back"` | "Escape", "Backspace" | "
|
|
496
|
+
`"navigate.left"` | "ArrowLeft", "KeyA" | "DpadLeft", "LeftStickLeft"
|
|
497
|
+
`"navigate.right"` | "ArrowRight", "KeyD" | "DpadRight", "LeftStickRight"
|
|
498
|
+
`"navigate.up"` | "ArrowUp", "KeyW" | "DpadUp", "LeftStickUp"
|
|
499
|
+
`"navigate.down"` | "ArrowDown", "KeyS" | "DpadDown", "LeftStickDown"
|
|
500
|
+
`"navigate.trigger"` | "Enter", "Space" | "Face1"
|
|
501
|
+
`"navigate.back"` | "Escape", "Backspace" | "Face2", "Back"
|
|
502
|
+
|
|
503
|
+
### Manual control for submenus & modal views
|
|
504
|
+
|
|
505
|
+
You can manually take control of navigation using:
|
|
506
|
+
|
|
507
|
+
```ts
|
|
508
|
+
// take control
|
|
509
|
+
UINavigation.pushResponder(myModalView)
|
|
510
|
+
|
|
511
|
+
// relinquish control
|
|
512
|
+
UINavigation.popResponder()
|
|
513
|
+
```
|
|
490
514
|
|
|
491
515
|
## Advanced usage
|
|
492
516
|
|
|
@@ -502,9 +526,9 @@ InputDevice.on("deviceconnected", ({ device }) =>
|
|
|
502
526
|
device.meta.localPlayerId = 123
|
|
503
527
|
)
|
|
504
528
|
|
|
505
|
-
for (
|
|
529
|
+
for (const device of InputDevice.devices)
|
|
506
530
|
{
|
|
507
|
-
if (
|
|
531
|
+
if (device.meta.localPlayerId === 123)
|
|
508
532
|
{
|
|
509
533
|
// use assigned input device!
|
|
510
534
|
}
|
|
@@ -517,26 +541,29 @@ You can easily map an on-screen input device using the `CustomDevice` interface.
|
|
|
517
541
|
|
|
518
542
|
```ts
|
|
519
543
|
export class OnScreenInputContainer extends Container implements CustomDevice {
|
|
520
|
-
id = "onscreen"
|
|
521
|
-
type = "custom" as const
|
|
522
|
-
meta: Record<string, any> = {}
|
|
544
|
+
id = "onscreen"
|
|
545
|
+
type = "custom" as const
|
|
546
|
+
meta: Record<string, any> = {}
|
|
523
547
|
|
|
524
548
|
inputs = {
|
|
525
549
|
moveX: 0.0
|
|
526
550
|
jump: false,
|
|
527
551
|
}
|
|
528
552
|
|
|
529
|
-
update(
|
|
553
|
+
update(now)
|
|
530
554
|
{
|
|
531
|
-
this.moveX = this._virtualJoystick.x
|
|
532
|
-
this.jump = this._jumpButton.isTouching()
|
|
555
|
+
this.inputs.moveX = this._virtualJoystick.x
|
|
556
|
+
this.inputs.jump = this._jumpButton.isTouching()
|
|
533
557
|
}
|
|
558
|
+
|
|
559
|
+
// e.g. disable named binds for onscreen joysticks:
|
|
560
|
+
bindDown(name){ return false }
|
|
534
561
|
}
|
|
535
562
|
|
|
536
|
-
const onscreen = new OnScreenInputContainer()
|
|
563
|
+
const onscreen = new OnScreenInputContainer()
|
|
537
564
|
|
|
538
|
-
InputDevice.add(
|
|
539
|
-
InputDevice.remove(
|
|
565
|
+
InputDevice.add(onscreen)
|
|
566
|
+
InputDevice.remove(onscreen)
|
|
540
567
|
```
|
|
541
568
|
|
|
542
569
|
### Two Users; One Keyboard
|
|
@@ -558,32 +585,32 @@ InputDevice.keyboard.configureBinds({
|
|
|
558
585
|
p2_jump: [ "ArrowUp" ],
|
|
559
586
|
p2_defend: [ "ArrowDown" ],
|
|
560
587
|
p2_left: [ "ArrowLeft" ],
|
|
561
|
-
p2_right: [ "ArrowRight" ]
|
|
588
|
+
p2_right: [ "ArrowRight" ]
|
|
562
589
|
})
|
|
563
590
|
```
|
|
564
591
|
|
|
565
592
|
and then switch groups depending on the mode:
|
|
566
593
|
|
|
567
594
|
```ts
|
|
568
|
-
if (
|
|
595
|
+
if (gameMode === "multiplayer")
|
|
569
596
|
{
|
|
570
|
-
player1.jump = device.
|
|
571
|
-
player1.defend = device.
|
|
572
|
-
player1.moveX += device.
|
|
573
|
-
player1.moveX += device.
|
|
574
|
-
|
|
575
|
-
player2.jump = device.
|
|
576
|
-
player2.defend = device.
|
|
577
|
-
player2.moveX += device.
|
|
578
|
-
player2.moveX += device.
|
|
597
|
+
player1.jump = device.bindDown("p1_jump")
|
|
598
|
+
player1.defend = device.bindDown("p1_defend")
|
|
599
|
+
player1.moveX += device.bindDown("p1_left") ? -1 : 0
|
|
600
|
+
player1.moveX += device.bindDown("p1_right") ? 1 : 0
|
|
601
|
+
|
|
602
|
+
player2.jump = device.bindDown("p2_jump")
|
|
603
|
+
player2.defend = device.bindDown("p2_defend")
|
|
604
|
+
player2.moveX += device.bindDown("p2_left") ? -1 : 0
|
|
605
|
+
player2.moveX += device.bindDown("p2_right") ? 1 : 0
|
|
579
606
|
}
|
|
580
607
|
else
|
|
581
608
|
{
|
|
582
|
-
player1.jump = device.
|
|
583
|
-
player1.defend = device.
|
|
584
|
-
player1.moveX += device.
|
|
585
|
-
player1.moveX += device.
|
|
609
|
+
player1.jump = device.bindDown("jump")
|
|
610
|
+
player1.defend = device.bindDown("defend")
|
|
611
|
+
player1.moveX += device.bindDown("left") ? -1 : 0
|
|
612
|
+
player1.moveX += device.bindDown("right") ? 1 : 0
|
|
586
613
|
|
|
587
|
-
updateComputerPlayerInput(
|
|
614
|
+
updateComputerPlayerInput(player2)
|
|
588
615
|
}
|
|
589
616
|
```
|