@yagejs/input 0.1.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 +54 -0
- package/dist/index.cjs +685 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +175 -0
- package/dist/index.d.ts +175 -0
- package/dist/index.js +657 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,657 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
4
|
+
// src/InputPlugin.ts
|
|
5
|
+
import { DebugRegistryKey } from "@yagejs/debug/api";
|
|
6
|
+
|
|
7
|
+
// src/InputManager.ts
|
|
8
|
+
import { Vec2 } from "@yagejs/core";
|
|
9
|
+
var InputManager = class {
|
|
10
|
+
static {
|
|
11
|
+
__name(this, "InputManager");
|
|
12
|
+
}
|
|
13
|
+
pressedKeys = /* @__PURE__ */ new Set();
|
|
14
|
+
justPressedKeys = /* @__PURE__ */ new Set();
|
|
15
|
+
justReleasedKeys = /* @__PURE__ */ new Set();
|
|
16
|
+
holdStart = /* @__PURE__ */ new Map();
|
|
17
|
+
actionMap = /* @__PURE__ */ new Map();
|
|
18
|
+
defaultBindings = /* @__PURE__ */ new Map();
|
|
19
|
+
groups = /* @__PURE__ */ new Map();
|
|
20
|
+
actionGroups = /* @__PURE__ */ new Map();
|
|
21
|
+
disabledGroups = /* @__PURE__ */ new Set();
|
|
22
|
+
pointerScreenPos = Vec2.ZERO;
|
|
23
|
+
pointerDownState = false;
|
|
24
|
+
camera = null;
|
|
25
|
+
elapsedMs = 0;
|
|
26
|
+
listenResolve = null;
|
|
27
|
+
// -- Action-based queries --
|
|
28
|
+
/** Whether any key mapped to this action is currently held. */
|
|
29
|
+
isPressed(action) {
|
|
30
|
+
if (!this.isActionEnabled(action)) return false;
|
|
31
|
+
return this.anyKeyInSet(action, this.pressedKeys);
|
|
32
|
+
}
|
|
33
|
+
/** Whether any key mapped to this action was pressed this frame. */
|
|
34
|
+
isJustPressed(action) {
|
|
35
|
+
if (!this.isActionEnabled(action)) return false;
|
|
36
|
+
return this.anyKeyInSet(action, this.justPressedKeys);
|
|
37
|
+
}
|
|
38
|
+
/** Whether any key mapped to this action was released this frame. */
|
|
39
|
+
isJustReleased(action) {
|
|
40
|
+
if (!this.isActionEnabled(action)) return false;
|
|
41
|
+
return this.anyKeyInSet(action, this.justReleasedKeys);
|
|
42
|
+
}
|
|
43
|
+
/** Returns true if any key bound to the action exists in the given set. */
|
|
44
|
+
anyKeyInSet(action, set) {
|
|
45
|
+
const keys = this.actionMap.get(action);
|
|
46
|
+
if (!keys) return false;
|
|
47
|
+
for (const key of keys) {
|
|
48
|
+
if (set.has(key)) return true;
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
/** Milliseconds the action has been held. Returns 0 if not held. */
|
|
53
|
+
getHoldDuration(action) {
|
|
54
|
+
if (!this.isActionEnabled(action)) return 0;
|
|
55
|
+
const keys = this.actionMap.get(action);
|
|
56
|
+
if (!keys) return 0;
|
|
57
|
+
let maxDuration = 0;
|
|
58
|
+
for (const key of keys) {
|
|
59
|
+
const start = this.holdStart.get(key);
|
|
60
|
+
if (start !== void 0) {
|
|
61
|
+
maxDuration = Math.max(maxDuration, this.elapsedMs - start);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return maxDuration;
|
|
65
|
+
}
|
|
66
|
+
/** Whether the action has been held for at least `minTime` ms. */
|
|
67
|
+
isHeldFor(action, minTime) {
|
|
68
|
+
return this.getHoldDuration(action) >= minTime;
|
|
69
|
+
}
|
|
70
|
+
// -- Axis helpers --
|
|
71
|
+
/** Returns -1, 0, or 1 based on negative/positive action states. */
|
|
72
|
+
getAxis(negative, positive) {
|
|
73
|
+
const neg = this.isPressed(negative) ? 1 : 0;
|
|
74
|
+
const pos = this.isPressed(positive) ? 1 : 0;
|
|
75
|
+
return pos - neg;
|
|
76
|
+
}
|
|
77
|
+
/** Returns a Vec2 from four directional actions. Not normalized. */
|
|
78
|
+
getVector(left, right, up, down) {
|
|
79
|
+
const x = this.getAxis(left, right);
|
|
80
|
+
const y = this.getAxis(up, down);
|
|
81
|
+
return new Vec2(x, y);
|
|
82
|
+
}
|
|
83
|
+
// -- Pointer --
|
|
84
|
+
/** Pointer position in world coordinates (via Camera), or screen coords if no camera. */
|
|
85
|
+
getPointerPosition() {
|
|
86
|
+
if (this.camera) {
|
|
87
|
+
const w = this.camera.screenToWorld(
|
|
88
|
+
this.pointerScreenPos.x,
|
|
89
|
+
this.pointerScreenPos.y
|
|
90
|
+
);
|
|
91
|
+
return new Vec2(w.x, w.y);
|
|
92
|
+
}
|
|
93
|
+
return this.pointerScreenPos;
|
|
94
|
+
}
|
|
95
|
+
/** Raw pointer position in screen coordinates. */
|
|
96
|
+
getPointerScreenPosition() {
|
|
97
|
+
return this.pointerScreenPos;
|
|
98
|
+
}
|
|
99
|
+
/** Whether any pointer button is currently held. */
|
|
100
|
+
isPointerDown() {
|
|
101
|
+
return this.pointerDownState;
|
|
102
|
+
}
|
|
103
|
+
// -- Runtime action map management --
|
|
104
|
+
/** Replace the entire action map and store it as the default for {@link resetBindings}. */
|
|
105
|
+
setActionMap(actions) {
|
|
106
|
+
this.actionMap.clear();
|
|
107
|
+
this.defaultBindings.clear();
|
|
108
|
+
for (const [action, keys] of Object.entries(actions)) {
|
|
109
|
+
this.actionMap.set(action, [...keys]);
|
|
110
|
+
this.defaultBindings.set(action, [...keys]);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** Add a key binding to an action. Creates the action if it doesn't exist. */
|
|
114
|
+
bindKey(action, key) {
|
|
115
|
+
let keys = this.actionMap.get(action);
|
|
116
|
+
if (!keys) {
|
|
117
|
+
keys = [];
|
|
118
|
+
this.actionMap.set(action, keys);
|
|
119
|
+
}
|
|
120
|
+
if (!keys.includes(key)) {
|
|
121
|
+
keys.push(key);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** Remove a key binding from an action. */
|
|
125
|
+
unbindKey(action, key) {
|
|
126
|
+
const keys = this.actionMap.get(action);
|
|
127
|
+
if (!keys) return;
|
|
128
|
+
const idx = keys.indexOf(key);
|
|
129
|
+
if (idx !== -1) keys.splice(idx, 1);
|
|
130
|
+
}
|
|
131
|
+
// -- Binding queries --
|
|
132
|
+
/** Returns the current key bindings for an action, or an empty array if unmapped. */
|
|
133
|
+
getBindings(action) {
|
|
134
|
+
return this.actionMap.get(action) ?? [];
|
|
135
|
+
}
|
|
136
|
+
/** Returns all action names that have the given key bound. */
|
|
137
|
+
getActionsForKey(key) {
|
|
138
|
+
const result = [];
|
|
139
|
+
for (const [action, keys] of this.actionMap) {
|
|
140
|
+
if (keys.includes(key)) result.push(action);
|
|
141
|
+
}
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
// -- Rebinding --
|
|
145
|
+
/**
|
|
146
|
+
* Rebind a key to an action with optional conflict detection.
|
|
147
|
+
* Conflicts are only detected between actions sharing at least one group.
|
|
148
|
+
*/
|
|
149
|
+
rebind(action, key, opts) {
|
|
150
|
+
const conflict = opts?.conflict ?? "reject";
|
|
151
|
+
const slot = opts?.slot;
|
|
152
|
+
const conflictAction = this.findConflictInGroups(action, key);
|
|
153
|
+
if (conflictAction && conflict === "reject") {
|
|
154
|
+
return { ok: false, conflict: { action: conflictAction, key } };
|
|
155
|
+
}
|
|
156
|
+
if (conflictAction && conflict === "replace") {
|
|
157
|
+
this.unbindKey(conflictAction, key);
|
|
158
|
+
}
|
|
159
|
+
let keys = this.actionMap.get(action);
|
|
160
|
+
if (!keys) {
|
|
161
|
+
keys = [];
|
|
162
|
+
this.actionMap.set(action, keys);
|
|
163
|
+
}
|
|
164
|
+
const existingIdx = keys.indexOf(key);
|
|
165
|
+
let targetSlot = slot;
|
|
166
|
+
if (targetSlot !== void 0 && existingIdx !== -1 && existingIdx !== targetSlot) {
|
|
167
|
+
keys.splice(existingIdx, 1);
|
|
168
|
+
if (targetSlot > existingIdx) targetSlot--;
|
|
169
|
+
}
|
|
170
|
+
if (targetSlot !== void 0 && targetSlot < keys.length) {
|
|
171
|
+
keys[targetSlot] = key;
|
|
172
|
+
} else if (!keys.includes(key)) {
|
|
173
|
+
keys.push(key);
|
|
174
|
+
}
|
|
175
|
+
return { ok: true };
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Finds the first action that uses the given key AND shares at least one
|
|
179
|
+
* group with the target action. Ungrouped actions never conflict.
|
|
180
|
+
*/
|
|
181
|
+
findConflictInGroups(action, key) {
|
|
182
|
+
const myGroups = this.actionGroups.get(action);
|
|
183
|
+
if (!myGroups || myGroups.size === 0) return null;
|
|
184
|
+
for (const [otherAction, otherKeys] of this.actionMap) {
|
|
185
|
+
if (otherAction === action) continue;
|
|
186
|
+
if (!otherKeys.includes(key)) continue;
|
|
187
|
+
const otherGroups = this.actionGroups.get(otherAction);
|
|
188
|
+
if (!otherGroups) continue;
|
|
189
|
+
for (const g of myGroups) {
|
|
190
|
+
if (otherGroups.has(g)) return otherAction;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
// -- Binding persistence --
|
|
196
|
+
/** Reset bindings to defaults. If an action name is provided, only reset that action. */
|
|
197
|
+
resetBindings(action) {
|
|
198
|
+
if (action !== void 0) {
|
|
199
|
+
const defaults = this.defaultBindings.get(action);
|
|
200
|
+
if (defaults) {
|
|
201
|
+
this.actionMap.set(action, [...defaults]);
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
this.actionMap.clear();
|
|
205
|
+
for (const [a, keys] of this.defaultBindings) {
|
|
206
|
+
this.actionMap.set(a, [...keys]);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/** Export the current bindings as a plain object for serialization. */
|
|
211
|
+
exportBindings() {
|
|
212
|
+
const result = {};
|
|
213
|
+
for (const [action, keys] of this.actionMap) {
|
|
214
|
+
result[action] = [...keys];
|
|
215
|
+
}
|
|
216
|
+
return result;
|
|
217
|
+
}
|
|
218
|
+
/** Load bindings from a plain object. Resets to defaults first, then overlays the provided map. */
|
|
219
|
+
loadBindings(map) {
|
|
220
|
+
this.resetBindings();
|
|
221
|
+
for (const [action, keys] of Object.entries(map)) {
|
|
222
|
+
this.actionMap.set(action, [...keys]);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// -- Group management --
|
|
226
|
+
/** Configure input groups. Group name -> array of action names. */
|
|
227
|
+
setGroups(groups) {
|
|
228
|
+
this.groups.clear();
|
|
229
|
+
this.actionGroups.clear();
|
|
230
|
+
for (const [name, actions] of Object.entries(groups)) {
|
|
231
|
+
this.groups.set(name, new Set(actions));
|
|
232
|
+
for (const action of actions) {
|
|
233
|
+
let set = this.actionGroups.get(action);
|
|
234
|
+
if (!set) {
|
|
235
|
+
set = /* @__PURE__ */ new Set();
|
|
236
|
+
this.actionGroups.set(action, set);
|
|
237
|
+
}
|
|
238
|
+
set.add(name);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/** Enable a group by name. */
|
|
243
|
+
enableGroup(name) {
|
|
244
|
+
this.disabledGroups.delete(name);
|
|
245
|
+
}
|
|
246
|
+
/** Disable a group by name. Actions only in disabled groups become inactive. */
|
|
247
|
+
disableGroup(name) {
|
|
248
|
+
this.disabledGroups.add(name);
|
|
249
|
+
}
|
|
250
|
+
/** Set exactly these groups as active; all others are disabled. */
|
|
251
|
+
setActiveGroups(names) {
|
|
252
|
+
this.disabledGroups.clear();
|
|
253
|
+
for (const group of this.groups.keys()) {
|
|
254
|
+
if (!names.includes(group)) {
|
|
255
|
+
this.disabledGroups.add(group);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/** Whether a group is currently enabled. Returns true for unknown group names. */
|
|
260
|
+
isGroupEnabled(name) {
|
|
261
|
+
return !this.disabledGroups.has(name);
|
|
262
|
+
}
|
|
263
|
+
/** Get all configured group names. */
|
|
264
|
+
getGroups() {
|
|
265
|
+
return Array.from(this.groups.keys());
|
|
266
|
+
}
|
|
267
|
+
/** Get the action names belonging to a group. Returns empty array for unknown groups. */
|
|
268
|
+
getGroupActions(name) {
|
|
269
|
+
const set = this.groups.get(name);
|
|
270
|
+
return set ? Array.from(set) : [];
|
|
271
|
+
}
|
|
272
|
+
/** Returns true if the action is ungrouped or any of its groups is enabled. */
|
|
273
|
+
isActionEnabled(action) {
|
|
274
|
+
const groupSet = this.actionGroups.get(action);
|
|
275
|
+
if (!groupSet || groupSet.size === 0) return true;
|
|
276
|
+
for (const group of groupSet) {
|
|
277
|
+
if (!this.disabledGroups.has(group)) return true;
|
|
278
|
+
}
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
// -- Key listening --
|
|
282
|
+
/** Returns a promise that resolves with the next key code pressed. Intercepts the key. */
|
|
283
|
+
listenForNextKey() {
|
|
284
|
+
this.cancelListen();
|
|
285
|
+
return new Promise((resolve) => {
|
|
286
|
+
this.listenResolve = resolve;
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
/** Cancel an active {@link listenForNextKey}. Resolves the pending promise with `null`. */
|
|
290
|
+
cancelListen() {
|
|
291
|
+
if (this.listenResolve) {
|
|
292
|
+
const resolve = this.listenResolve;
|
|
293
|
+
this.listenResolve = null;
|
|
294
|
+
resolve(null);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
// -- Internal methods (called by InputPlugin / Systems) --
|
|
298
|
+
/** @internal */
|
|
299
|
+
_onKeyDown(code) {
|
|
300
|
+
if (this.listenResolve) {
|
|
301
|
+
const resolve = this.listenResolve;
|
|
302
|
+
this.listenResolve = null;
|
|
303
|
+
resolve(code);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
if (!this.pressedKeys.has(code)) {
|
|
307
|
+
this.pressedKeys.add(code);
|
|
308
|
+
this.justPressedKeys.add(code);
|
|
309
|
+
this.holdStart.set(code, this.elapsedMs);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
/** @internal */
|
|
313
|
+
_onKeyUp(code) {
|
|
314
|
+
if (this.pressedKeys.has(code)) {
|
|
315
|
+
this.pressedKeys.delete(code);
|
|
316
|
+
this.justReleasedKeys.add(code);
|
|
317
|
+
this.holdStart.delete(code);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
/** @internal */
|
|
321
|
+
_onPointerMove(screenX, screenY) {
|
|
322
|
+
this.pointerScreenPos = new Vec2(screenX, screenY);
|
|
323
|
+
}
|
|
324
|
+
/** @internal */
|
|
325
|
+
_onPointerDown() {
|
|
326
|
+
this.pointerDownState = true;
|
|
327
|
+
}
|
|
328
|
+
/** @internal */
|
|
329
|
+
_onPointerUp() {
|
|
330
|
+
this.pointerDownState = false;
|
|
331
|
+
}
|
|
332
|
+
/** @internal Clear per-frame justPressed/justReleased flags. */
|
|
333
|
+
_clearFrameState() {
|
|
334
|
+
this.justPressedKeys.clear();
|
|
335
|
+
this.justReleasedKeys.clear();
|
|
336
|
+
}
|
|
337
|
+
/** @internal Set camera for pointer world-coord conversion. */
|
|
338
|
+
_setCamera(camera) {
|
|
339
|
+
this.camera = camera;
|
|
340
|
+
}
|
|
341
|
+
/** Get all configured action names. */
|
|
342
|
+
getActionNames() {
|
|
343
|
+
return Array.from(this.actionMap.keys());
|
|
344
|
+
}
|
|
345
|
+
/** @internal Advance the elapsed game-time clock. Called by InputPollSystem. */
|
|
346
|
+
_advanceTime(dtMs) {
|
|
347
|
+
this.elapsedMs += dtMs;
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
// src/types.ts
|
|
352
|
+
import { ServiceKey } from "@yagejs/core";
|
|
353
|
+
var InputManagerKey = new ServiceKey("inputManager");
|
|
354
|
+
|
|
355
|
+
// src/InputPollSystem.ts
|
|
356
|
+
import { System, Phase } from "@yagejs/core";
|
|
357
|
+
var InputPollSystem = class extends System {
|
|
358
|
+
static {
|
|
359
|
+
__name(this, "InputPollSystem");
|
|
360
|
+
}
|
|
361
|
+
phase = Phase.EarlyUpdate;
|
|
362
|
+
priority = -100;
|
|
363
|
+
update(dt) {
|
|
364
|
+
this.use(InputManagerKey)._advanceTime(dt);
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
// src/InputClearSystem.ts
|
|
369
|
+
import { System as System2, Phase as Phase2 } from "@yagejs/core";
|
|
370
|
+
var InputClearSystem = class extends System2 {
|
|
371
|
+
static {
|
|
372
|
+
__name(this, "InputClearSystem");
|
|
373
|
+
}
|
|
374
|
+
phase = Phase2.EndOfFrame;
|
|
375
|
+
priority = 9e3;
|
|
376
|
+
update() {
|
|
377
|
+
this.use(InputManagerKey)._clearFrameState();
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
// src/InputDebugContributor.ts
|
|
382
|
+
var CROSSHAIR_SIZE = 10;
|
|
383
|
+
var CROSSHAIR_COLOR = 16711935;
|
|
384
|
+
var InputDebugContributor = class {
|
|
385
|
+
constructor(manager) {
|
|
386
|
+
this.manager = manager;
|
|
387
|
+
}
|
|
388
|
+
manager;
|
|
389
|
+
static {
|
|
390
|
+
__name(this, "InputDebugContributor");
|
|
391
|
+
}
|
|
392
|
+
name = "input";
|
|
393
|
+
flags = ["actions", "pointer"];
|
|
394
|
+
drawWorld(api) {
|
|
395
|
+
if (!api.isFlagEnabled("pointer")) return;
|
|
396
|
+
const pos = this.manager.getPointerPosition();
|
|
397
|
+
const g = api.acquireGraphics();
|
|
398
|
+
if (!g) return;
|
|
399
|
+
const size = CROSSHAIR_SIZE / api.cameraZoom;
|
|
400
|
+
const lineWidth = 1 / api.cameraZoom;
|
|
401
|
+
g.moveTo(pos.x - size, pos.y).lineTo(pos.x + size, pos.y).moveTo(pos.x, pos.y - size).lineTo(pos.x, pos.y + size).stroke({ width: lineWidth, color: CROSSHAIR_COLOR });
|
|
402
|
+
}
|
|
403
|
+
drawHud(api) {
|
|
404
|
+
if (!api.isFlagEnabled("actions")) return;
|
|
405
|
+
const pressed = this.manager.getActionNames().filter((action) => this.manager.isPressed(action));
|
|
406
|
+
const label = pressed.length > 0 ? pressed.join(", ") : "(none)";
|
|
407
|
+
api.addLine(`Input: ${label}`);
|
|
408
|
+
const groups = this.manager.getGroups();
|
|
409
|
+
if (groups.length > 0) {
|
|
410
|
+
const disabled = groups.filter((g) => !this.manager.isGroupEnabled(g));
|
|
411
|
+
if (disabled.length > 0) {
|
|
412
|
+
api.addLine(`Disabled groups: ${disabled.join(", ")}`);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
// src/InputPlugin.ts
|
|
419
|
+
var MOUSE_BUTTON_MAP = {
|
|
420
|
+
0: "MouseLeft",
|
|
421
|
+
1: "MouseMiddle",
|
|
422
|
+
2: "MouseRight"
|
|
423
|
+
};
|
|
424
|
+
var InputPlugin = class {
|
|
425
|
+
static {
|
|
426
|
+
__name(this, "InputPlugin");
|
|
427
|
+
}
|
|
428
|
+
name = "input";
|
|
429
|
+
version = "2.0.0";
|
|
430
|
+
config;
|
|
431
|
+
manager;
|
|
432
|
+
context;
|
|
433
|
+
cleanupFns = [];
|
|
434
|
+
constructor(config) {
|
|
435
|
+
this.config = config ?? {};
|
|
436
|
+
}
|
|
437
|
+
install(context) {
|
|
438
|
+
this.context = context;
|
|
439
|
+
this.manager = new InputManager();
|
|
440
|
+
if (this.config.actions) {
|
|
441
|
+
this.manager.setActionMap(this.config.actions);
|
|
442
|
+
}
|
|
443
|
+
if (this.config.groups) {
|
|
444
|
+
this.manager.setGroups(this.config.groups);
|
|
445
|
+
}
|
|
446
|
+
if (this.config.cameraKey) {
|
|
447
|
+
const camera = context.tryResolve(this.config.cameraKey);
|
|
448
|
+
if (camera) {
|
|
449
|
+
this.manager._setCamera(camera);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
const renderer = this.config.rendererKey ? context.tryResolve(this.config.rendererKey) : void 0;
|
|
453
|
+
const pointerTarget = this.config.target ?? renderer?.canvas ?? document;
|
|
454
|
+
const pointerElement = this.config.target ?? renderer?.canvas ?? null;
|
|
455
|
+
const preventSet = new Set(this.config.preventDefaultKeys ?? []);
|
|
456
|
+
const onKeyDown = /* @__PURE__ */ __name((e) => {
|
|
457
|
+
const ke = e;
|
|
458
|
+
if (ke.repeat) return;
|
|
459
|
+
if (preventSet.has(ke.code)) ke.preventDefault();
|
|
460
|
+
this.manager._onKeyDown(ke.code);
|
|
461
|
+
}, "onKeyDown");
|
|
462
|
+
const onKeyUp = /* @__PURE__ */ __name((e) => {
|
|
463
|
+
const ke = e;
|
|
464
|
+
if (preventSet.has(ke.code)) ke.preventDefault();
|
|
465
|
+
this.manager._onKeyUp(ke.code);
|
|
466
|
+
}, "onKeyUp");
|
|
467
|
+
window.addEventListener("keydown", onKeyDown);
|
|
468
|
+
window.addEventListener("keyup", onKeyUp);
|
|
469
|
+
this.cleanupFns.push(
|
|
470
|
+
() => window.removeEventListener("keydown", onKeyDown),
|
|
471
|
+
() => window.removeEventListener("keyup", onKeyUp)
|
|
472
|
+
);
|
|
473
|
+
const onPointerMove = /* @__PURE__ */ __name((e) => {
|
|
474
|
+
const pe = e;
|
|
475
|
+
if (pointerElement) {
|
|
476
|
+
const rect = pointerElement.getBoundingClientRect();
|
|
477
|
+
this.manager._onPointerMove(pe.clientX - rect.left, pe.clientY - rect.top);
|
|
478
|
+
} else {
|
|
479
|
+
this.manager._onPointerMove(pe.clientX, pe.clientY);
|
|
480
|
+
}
|
|
481
|
+
}, "onPointerMove");
|
|
482
|
+
const onPointerDown = /* @__PURE__ */ __name((e) => {
|
|
483
|
+
const pe = e;
|
|
484
|
+
this.manager._onPointerDown();
|
|
485
|
+
const mouseKey = MOUSE_BUTTON_MAP[pe.button];
|
|
486
|
+
if (mouseKey) this.manager._onKeyDown(mouseKey);
|
|
487
|
+
}, "onPointerDown");
|
|
488
|
+
const onPointerUp = /* @__PURE__ */ __name((e) => {
|
|
489
|
+
const pe = e;
|
|
490
|
+
this.manager._onPointerUp();
|
|
491
|
+
const mouseKey = MOUSE_BUTTON_MAP[pe.button];
|
|
492
|
+
if (mouseKey) this.manager._onKeyUp(mouseKey);
|
|
493
|
+
}, "onPointerUp");
|
|
494
|
+
const onPointerCancel = /* @__PURE__ */ __name(() => {
|
|
495
|
+
this.manager._onPointerUp();
|
|
496
|
+
this.manager._onKeyUp("MouseLeft");
|
|
497
|
+
this.manager._onKeyUp("MouseMiddle");
|
|
498
|
+
this.manager._onKeyUp("MouseRight");
|
|
499
|
+
}, "onPointerCancel");
|
|
500
|
+
pointerTarget.addEventListener("pointerdown", onPointerDown);
|
|
501
|
+
window.addEventListener("pointermove", onPointerMove);
|
|
502
|
+
window.addEventListener("pointerup", onPointerUp);
|
|
503
|
+
window.addEventListener("pointercancel", onPointerCancel);
|
|
504
|
+
this.cleanupFns.push(
|
|
505
|
+
() => pointerTarget.removeEventListener("pointerdown", onPointerDown),
|
|
506
|
+
() => window.removeEventListener("pointermove", onPointerMove),
|
|
507
|
+
() => window.removeEventListener("pointerup", onPointerUp),
|
|
508
|
+
() => window.removeEventListener("pointercancel", onPointerCancel)
|
|
509
|
+
);
|
|
510
|
+
context.register(InputManagerKey, this.manager);
|
|
511
|
+
}
|
|
512
|
+
registerSystems(scheduler) {
|
|
513
|
+
scheduler.add(new InputPollSystem());
|
|
514
|
+
scheduler.add(new InputClearSystem());
|
|
515
|
+
}
|
|
516
|
+
onStart() {
|
|
517
|
+
const registry = this.context.tryResolve(DebugRegistryKey);
|
|
518
|
+
registry?.register(new InputDebugContributor(this.manager));
|
|
519
|
+
}
|
|
520
|
+
onDestroy() {
|
|
521
|
+
for (const cleanup of this.cleanupFns) {
|
|
522
|
+
cleanup();
|
|
523
|
+
}
|
|
524
|
+
this.cleanupFns.length = 0;
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
// src/keyDisplayNames.ts
|
|
529
|
+
var KEY_DISPLAY_NAMES = {
|
|
530
|
+
// Letters
|
|
531
|
+
KeyA: "A",
|
|
532
|
+
KeyB: "B",
|
|
533
|
+
KeyC: "C",
|
|
534
|
+
KeyD: "D",
|
|
535
|
+
KeyE: "E",
|
|
536
|
+
KeyF: "F",
|
|
537
|
+
KeyG: "G",
|
|
538
|
+
KeyH: "H",
|
|
539
|
+
KeyI: "I",
|
|
540
|
+
KeyJ: "J",
|
|
541
|
+
KeyK: "K",
|
|
542
|
+
KeyL: "L",
|
|
543
|
+
KeyM: "M",
|
|
544
|
+
KeyN: "N",
|
|
545
|
+
KeyO: "O",
|
|
546
|
+
KeyP: "P",
|
|
547
|
+
KeyQ: "Q",
|
|
548
|
+
KeyR: "R",
|
|
549
|
+
KeyS: "S",
|
|
550
|
+
KeyT: "T",
|
|
551
|
+
KeyU: "U",
|
|
552
|
+
KeyV: "V",
|
|
553
|
+
KeyW: "W",
|
|
554
|
+
KeyX: "X",
|
|
555
|
+
KeyY: "Y",
|
|
556
|
+
KeyZ: "Z",
|
|
557
|
+
// Digits
|
|
558
|
+
Digit0: "0",
|
|
559
|
+
Digit1: "1",
|
|
560
|
+
Digit2: "2",
|
|
561
|
+
Digit3: "3",
|
|
562
|
+
Digit4: "4",
|
|
563
|
+
Digit5: "5",
|
|
564
|
+
Digit6: "6",
|
|
565
|
+
Digit7: "7",
|
|
566
|
+
Digit8: "8",
|
|
567
|
+
Digit9: "9",
|
|
568
|
+
// Function keys
|
|
569
|
+
F1: "F1",
|
|
570
|
+
F2: "F2",
|
|
571
|
+
F3: "F3",
|
|
572
|
+
F4: "F4",
|
|
573
|
+
F5: "F5",
|
|
574
|
+
F6: "F6",
|
|
575
|
+
F7: "F7",
|
|
576
|
+
F8: "F8",
|
|
577
|
+
F9: "F9",
|
|
578
|
+
F10: "F10",
|
|
579
|
+
F11: "F11",
|
|
580
|
+
F12: "F12",
|
|
581
|
+
// Modifiers
|
|
582
|
+
ShiftLeft: "Left Shift",
|
|
583
|
+
ShiftRight: "Right Shift",
|
|
584
|
+
ControlLeft: "Left Ctrl",
|
|
585
|
+
ControlRight: "Right Ctrl",
|
|
586
|
+
AltLeft: "Left Alt",
|
|
587
|
+
AltRight: "Right Alt",
|
|
588
|
+
MetaLeft: "Left Meta",
|
|
589
|
+
MetaRight: "Right Meta",
|
|
590
|
+
// Arrows
|
|
591
|
+
ArrowUp: "Up",
|
|
592
|
+
ArrowDown: "Down",
|
|
593
|
+
ArrowLeft: "Left",
|
|
594
|
+
ArrowRight: "Right",
|
|
595
|
+
// Common keys
|
|
596
|
+
Space: "Space",
|
|
597
|
+
Enter: "Enter",
|
|
598
|
+
Escape: "Esc",
|
|
599
|
+
Tab: "Tab",
|
|
600
|
+
Backspace: "Backspace",
|
|
601
|
+
Delete: "Delete",
|
|
602
|
+
Insert: "Insert",
|
|
603
|
+
Home: "Home",
|
|
604
|
+
End: "End",
|
|
605
|
+
PageUp: "Page Up",
|
|
606
|
+
PageDown: "Page Down",
|
|
607
|
+
CapsLock: "Caps Lock",
|
|
608
|
+
NumLock: "Num Lock",
|
|
609
|
+
ScrollLock: "Scroll Lock",
|
|
610
|
+
PrintScreen: "Print Screen",
|
|
611
|
+
Pause: "Pause",
|
|
612
|
+
ContextMenu: "Menu",
|
|
613
|
+
// Punctuation / symbols
|
|
614
|
+
Backquote: "`",
|
|
615
|
+
Minus: "-",
|
|
616
|
+
Equal: "=",
|
|
617
|
+
BracketLeft: "[",
|
|
618
|
+
BracketRight: "]",
|
|
619
|
+
Backslash: "\\",
|
|
620
|
+
Semicolon: ";",
|
|
621
|
+
Quote: "'",
|
|
622
|
+
Comma: ",",
|
|
623
|
+
Period: ".",
|
|
624
|
+
Slash: "/",
|
|
625
|
+
// Numpad
|
|
626
|
+
Numpad0: "Numpad 0",
|
|
627
|
+
Numpad1: "Numpad 1",
|
|
628
|
+
Numpad2: "Numpad 2",
|
|
629
|
+
Numpad3: "Numpad 3",
|
|
630
|
+
Numpad4: "Numpad 4",
|
|
631
|
+
Numpad5: "Numpad 5",
|
|
632
|
+
Numpad6: "Numpad 6",
|
|
633
|
+
Numpad7: "Numpad 7",
|
|
634
|
+
Numpad8: "Numpad 8",
|
|
635
|
+
Numpad9: "Numpad 9",
|
|
636
|
+
NumpadAdd: "Numpad +",
|
|
637
|
+
NumpadSubtract: "Numpad -",
|
|
638
|
+
NumpadMultiply: "Numpad *",
|
|
639
|
+
NumpadDivide: "Numpad /",
|
|
640
|
+
NumpadDecimal: "Numpad .",
|
|
641
|
+
NumpadEnter: "Numpad Enter",
|
|
642
|
+
// Mouse buttons (synthetic codes from InputPlugin)
|
|
643
|
+
MouseLeft: "Left Click",
|
|
644
|
+
MouseMiddle: "Middle Click",
|
|
645
|
+
MouseRight: "Right Click"
|
|
646
|
+
};
|
|
647
|
+
function getKeyDisplayName(code) {
|
|
648
|
+
return KEY_DISPLAY_NAMES[code] ?? code;
|
|
649
|
+
}
|
|
650
|
+
__name(getKeyDisplayName, "getKeyDisplayName");
|
|
651
|
+
export {
|
|
652
|
+
InputManager,
|
|
653
|
+
InputManagerKey,
|
|
654
|
+
InputPlugin,
|
|
655
|
+
getKeyDisplayName
|
|
656
|
+
};
|
|
657
|
+
//# sourceMappingURL=index.js.map
|