@debuffjp/input 0.0.0-stage → 0.2.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,3 +1,38 @@
1
- # Temporary Holding Version
1
+ # @debuffjp/input
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Action-based input across keyboard, mouse/touch/pen (Pointer Events) and gamepads (standard mapping). No dependencies.
4
+
5
+ ```ts
6
+ import { Input } from "@debuffjp/input";
7
+
8
+ const input = new Input(game, {
9
+ bindings: {
10
+ left: ["ArrowLeft", "KeyA", "PadLeft", "PadStickLeft"],
11
+ right: ["ArrowRight", "KeyD", "PadRight", "PadStickRight"],
12
+ jump: ["Space", "PadA", "Pointer"],
13
+ },
14
+ });
15
+
16
+ // inside Scene.update
17
+ const dx = input.axis("left", "right");
18
+ if (input.pressed("jump")) jump();
19
+ ```
20
+
21
+ Edges clear automatically after each simulation step, so a tap shorter than a frame is never missed.
22
+
23
+ ## Binding names
24
+
25
+ | Source | Names |
26
+ | --- | --- |
27
+ | Keyboard | [`KeyboardEvent.code`](https://developer.mozilla.org/docs/Web/API/KeyboardEvent/code): `Space`, `KeyZ`, `ArrowUp`, … |
28
+ | Pointer | `Pointer` (primary mouse button, touch or pen) |
29
+ | Gamepad | `PadA` `PadB` `PadX` `PadY` `PadL1` `PadR1` `PadL2` `PadR2` `PadSelect` `PadStart` `PadL3` `PadR3` `PadUp` `PadDown` `PadLeft` `PadRight` |
30
+ | Left stick | `PadStickUp` `PadStickDown` `PadStickLeft` `PadStickRight` |
31
+
32
+ ## API
33
+
34
+ - `input.down(action)`, `input.pressed(action)`, `input.released(action)`, `input.axis(neg, pos)`
35
+ - `input.pointer`: `x`, `y` (logical), `down`, `pressed`, `released`, `touches`
36
+ - `input.keys`: `down(code)`, `pressed(code)`, `released(code)`
37
+ - `input.pads`: `stickX`, `stickY`, `connected`, `deadzone`
38
+ - Programmatic control for tests and on-screen buttons: `keys.press/release`, `pointer.press/move/release`
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Button names for the W3C "standard" gamepad mapping, used in bindings as `"Pad<Name>"`,
3
+ * e.g. `"PadA"`, `"PadUp"`. Stick directions (`PadStickLeft` …) treat the left stick as a d-pad.
4
+ * https://w3c.github.io/gamepad/#remapping
5
+ */
6
+ export declare const PAD_BUTTONS: {
7
+ readonly PadA: 0;
8
+ readonly PadB: 1;
9
+ readonly PadX: 2;
10
+ readonly PadY: 3;
11
+ readonly PadL1: 4;
12
+ readonly PadR1: 5;
13
+ readonly PadL2: 6;
14
+ readonly PadR2: 7;
15
+ readonly PadSelect: 8;
16
+ readonly PadStart: 9;
17
+ readonly PadL3: 10;
18
+ readonly PadR3: 11;
19
+ readonly PadUp: 12;
20
+ readonly PadDown: 13;
21
+ readonly PadLeft: 14;
22
+ readonly PadRight: 15;
23
+ };
24
+ export type PadButton = keyof typeof PAD_BUTTONS;
25
+ export type PadStick = "PadStickUp" | "PadStickDown" | "PadStickLeft" | "PadStickRight";
26
+ /** Polls the first connected standard gamepad. The Gamepad API is poll-based, so call `poll()` once per step. */
27
+ export declare class Gamepads {
28
+ /** Stick deflection needed to count as a direction. */
29
+ deadzone: number;
30
+ private current;
31
+ private previous;
32
+ /** Left stick, -1..1, after the deadzone. */
33
+ stickX: number;
34
+ stickY: number;
35
+ connected: boolean;
36
+ poll(): void;
37
+ down(name: string): boolean;
38
+ pressed(name: string): boolean;
39
+ released(name: string): boolean;
40
+ }
41
+ //# sourceMappingURL=gamepad.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gamepad.d.ts","sourceRoot":"","sources":["../src/gamepad.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,WAAW;aACtB,IAAI,EAAE,CAAC;aACP,IAAI,EAAE,CAAC;aACP,IAAI,EAAE,CAAC;aACP,IAAI,EAAE,CAAC;aACP,KAAK,EAAE,CAAC;aACR,KAAK,EAAE,CAAC;aACR,KAAK,EAAE,CAAC;aACR,KAAK,EAAE,CAAC;aACR,SAAS,EAAE,CAAC;aACZ,QAAQ,EAAE,CAAC;aACX,KAAK,EAAE,EAAE;aACT,KAAK,EAAE,EAAE;aACT,KAAK,EAAE,EAAE;aACT,OAAO,EAAE,EAAE;aACX,OAAO,EAAE,EAAE;aACX,QAAQ,EAAE,EAAE;CACJ,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,WAAW,CAAC;AACjD,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,cAAc,GAAG,cAAc,GAAG,eAAe,CAAC;AAExF,iHAAiH;AACjH,qBAAa,QAAQ;IACnB,uDAAuD;IACvD,QAAQ,SAAO;IACf,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,QAAQ,CAAqB;IACrC,6CAA6C;IAC7C,MAAM,SAAK;IACX,MAAM,SAAK;IACX,SAAS,UAAS;IAElB,IAAI,IAAI,IAAI,CAiBX;IAED,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1B;IAED,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7B;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9B;CACF"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Button names for the W3C "standard" gamepad mapping, used in bindings as `"Pad<Name>"`,
3
+ * e.g. `"PadA"`, `"PadUp"`. Stick directions (`PadStickLeft` …) treat the left stick as a d-pad.
4
+ * https://w3c.github.io/gamepad/#remapping
5
+ */
6
+ export const PAD_BUTTONS = {
7
+ PadA: 0,
8
+ PadB: 1,
9
+ PadX: 2,
10
+ PadY: 3,
11
+ PadL1: 4,
12
+ PadR1: 5,
13
+ PadL2: 6,
14
+ PadR2: 7,
15
+ PadSelect: 8,
16
+ PadStart: 9,
17
+ PadL3: 10,
18
+ PadR3: 11,
19
+ PadUp: 12,
20
+ PadDown: 13,
21
+ PadLeft: 14,
22
+ PadRight: 15,
23
+ };
24
+ /** Polls the first connected standard gamepad. The Gamepad API is poll-based, so call `poll()` once per step. */
25
+ export class Gamepads {
26
+ /** Stick deflection needed to count as a direction. */
27
+ deadzone = 0.4;
28
+ current = new Set();
29
+ previous = new Set();
30
+ /** Left stick, -1..1, after the deadzone. */
31
+ stickX = 0;
32
+ stickY = 0;
33
+ connected = false;
34
+ poll() {
35
+ [this.previous, this.current] = [this.current, this.previous];
36
+ this.current.clear();
37
+ const pad = typeof navigator !== "undefined" && navigator.getGamepads ? navigator.getGamepads().find((p) => p?.connected) : undefined;
38
+ this.connected = Boolean(pad);
39
+ this.stickX = 0;
40
+ this.stickY = 0;
41
+ if (!pad)
42
+ return;
43
+ for (const [name, index] of Object.entries(PAD_BUTTONS))
44
+ if (pad.buttons[index]?.pressed)
45
+ this.current.add(name);
46
+ const ax = pad.axes[0] ?? 0;
47
+ const ay = pad.axes[1] ?? 0;
48
+ this.stickX = Math.abs(ax) > this.deadzone ? ax : 0;
49
+ this.stickY = Math.abs(ay) > this.deadzone ? ay : 0;
50
+ if (this.stickX < 0)
51
+ this.current.add("PadStickLeft");
52
+ if (this.stickX > 0)
53
+ this.current.add("PadStickRight");
54
+ if (this.stickY < 0)
55
+ this.current.add("PadStickUp");
56
+ if (this.stickY > 0)
57
+ this.current.add("PadStickDown");
58
+ }
59
+ down(name) {
60
+ return this.current.has(name);
61
+ }
62
+ pressed(name) {
63
+ return this.current.has(name) && !this.previous.has(name);
64
+ }
65
+ released(name) {
66
+ return !this.current.has(name) && this.previous.has(name);
67
+ }
68
+ }
69
+ //# sourceMappingURL=gamepad.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gamepad.js","sourceRoot":"","sources":["../src/gamepad.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { Gamepads, PAD_BUTTONS, type PadButton, type PadStick } from "./gamepad.js";
2
+ export { type Binding, type Bindings, Input, type InputHost, type InputOptions } from "./input.js";
3
+ export { Keyboard } from "./keyboard.js";
4
+ export { Pointer, type ToLogical, type TouchPoint } from "./pointer.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,EAAE,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACnG,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { Gamepads, PAD_BUTTONS } from "./gamepad.js";
2
+ export { Input } from "./input.js";
3
+ export { Keyboard } from "./keyboard.js";
4
+ export { Pointer } from "./pointer.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAiC,MAAM,cAAc,CAAC;AACpF,OAAO,EAA+B,KAAK,EAAqC,MAAM,YAAY,CAAC;AACnG,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAmC,MAAM,cAAc,CAAC"}
@@ -0,0 +1,62 @@
1
+ import { Gamepads } from "./gamepad.js";
2
+ import { Keyboard } from "./keyboard.js";
3
+ import { Pointer, type ToLogical } from "./pointer.js";
4
+ /**
5
+ * A binding is a source name:
6
+ * - a `KeyboardEvent.code`: `"Space"`, `"KeyZ"`, `"ArrowLeft"`
7
+ * - `"Pointer"`: primary mouse button / touch / pen
8
+ * - a gamepad button or stick direction: `"PadA"`, `"PadLeft"`, `"PadStickLeft"`
9
+ */
10
+ export type Binding = string;
11
+ export type Bindings<A extends string> = Record<A, readonly Binding[]>;
12
+ /** The parts of `Game` that `Input` uses. */
13
+ export interface InputHost {
14
+ canvas: HTMLElement;
15
+ toLogical: ToLogical;
16
+ hooks: {
17
+ afterUpdate(fn: (dt: number) => void): () => void;
18
+ };
19
+ }
20
+ export interface InputOptions<A extends string> {
21
+ /** Named actions and the sources that trigger them. */
22
+ bindings: Bindings<A>;
23
+ /** Element receiving keyboard events. Default `window`. */
24
+ keyboardTarget?: Window | HTMLElement;
25
+ /** Block the browser default for bound keys (page scrolling in embeds). Default true. */
26
+ captureKeys?: boolean;
27
+ }
28
+ /**
29
+ * Action-based input across keyboard, pointer and gamepad.
30
+ *
31
+ * ```ts
32
+ * const input = new Input(game, {
33
+ * bindings: { left: ["ArrowLeft", "KeyA", "PadLeft"], jump: ["Space", "PadA", "Pointer"] },
34
+ * });
35
+ * if (input.pressed("jump")) jump();
36
+ * const dx = input.axis("left", "right");
37
+ * ```
38
+ *
39
+ * Edges are cleared automatically after each simulation step.
40
+ */
41
+ export declare class Input<A extends string> {
42
+ readonly keys: Keyboard;
43
+ readonly pointer: Pointer;
44
+ readonly pads: Gamepads;
45
+ readonly bindings: Bindings<A>;
46
+ private readonly unhook;
47
+ constructor(host: InputHost, options: InputOptions<A>);
48
+ /** Any binding for the action is held. */
49
+ down(action: A): boolean;
50
+ /** The action started this step. */
51
+ pressed(action: A): boolean;
52
+ /** The action ended this step. */
53
+ released(action: A): boolean;
54
+ /** -1, 0 or 1 from two opposing actions, e.g. `axis("left", "right")`. */
55
+ axis(negative: A, positive: A): number;
56
+ dispose(): void;
57
+ private some;
58
+ private isPad;
59
+ /** Clear edges, then sample gamepads for the next step (the Gamepad API is poll-based). */
60
+ private endStep;
61
+ }
62
+ //# sourceMappingURL=input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAE7B,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,MAAM,IAAI,MAAM,CAAC,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC,CAAC;AAEvE,6CAA6C;AAC7C,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE;QAAE,WAAW,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CAAA;KAAE,CAAC;CAC9D;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,MAAM;IAC5C,uDAAuD;IACvD,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtB,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IACtC,yFAAyF;IACzF,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,KAAK,CAAC,CAAC,SAAS,MAAM;IACjC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,IAAI,WAAkB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IAEpC,YAAY,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAWpD;IAED,0CAA0C;IAC1C,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,OAAO,CAEvB;IAED,oCAAoC;IACpC,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,OAAO,CAE1B;IAED,kCAAkC;IAClC,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,OAAO,CAI3B;IAED,0EAA0E;IAC1E,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,MAAM,CAErC;IAED,OAAO,IAAI,IAAI,CAId;IAED,OAAO,CAAC,IAAI;IAMZ,OAAO,CAAC,KAAK;IAIb,2FAA2F;IAC3F,OAAO,CAAC,OAAO;CAKhB"}
package/dist/input.js ADDED
@@ -0,0 +1,74 @@
1
+ import { Gamepads } from "./gamepad.js";
2
+ import { Keyboard } from "./keyboard.js";
3
+ import { Pointer } from "./pointer.js";
4
+ /**
5
+ * Action-based input across keyboard, pointer and gamepad.
6
+ *
7
+ * ```ts
8
+ * const input = new Input(game, {
9
+ * bindings: { left: ["ArrowLeft", "KeyA", "PadLeft"], jump: ["Space", "PadA", "Pointer"] },
10
+ * });
11
+ * if (input.pressed("jump")) jump();
12
+ * const dx = input.axis("left", "right");
13
+ * ```
14
+ *
15
+ * Edges are cleared automatically after each simulation step.
16
+ */
17
+ export class Input {
18
+ keys;
19
+ pointer;
20
+ pads = new Gamepads();
21
+ bindings;
22
+ unhook;
23
+ constructor(host, options) {
24
+ this.bindings = options.bindings;
25
+ this.keys = new Keyboard(options.keyboardTarget ?? window);
26
+ if (options.captureKeys ?? true) {
27
+ for (const list of Object.values(options.bindings)) {
28
+ for (const b of list)
29
+ if (b !== "Pointer" && !b.startsWith("Pad"))
30
+ this.keys.captured.add(b);
31
+ }
32
+ }
33
+ // Call through the host so a class method keeps its `this`.
34
+ this.pointer = new Pointer(host.canvas, (x, y) => host.toLogical(x, y));
35
+ this.unhook = host.hooks.afterUpdate(() => this.endStep());
36
+ }
37
+ /** Any binding for the action is held. */
38
+ down(action) {
39
+ return this.some(action, (b) => (b === "Pointer" ? this.pointer.down : this.isPad(b) ? this.pads.down(b) : this.keys.down(b)));
40
+ }
41
+ /** The action started this step. */
42
+ pressed(action) {
43
+ return this.some(action, (b) => (b === "Pointer" ? this.pointer.pressed : this.isPad(b) ? this.pads.pressed(b) : this.keys.pressed(b)));
44
+ }
45
+ /** The action ended this step. */
46
+ released(action) {
47
+ return this.some(action, (b) => b === "Pointer" ? this.pointer.released : this.isPad(b) ? this.pads.released(b) : this.keys.released(b));
48
+ }
49
+ /** -1, 0 or 1 from two opposing actions, e.g. `axis("left", "right")`. */
50
+ axis(negative, positive) {
51
+ return (this.down(positive) ? 1 : 0) - (this.down(negative) ? 1 : 0);
52
+ }
53
+ dispose() {
54
+ this.unhook();
55
+ this.keys.dispose();
56
+ this.pointer.dispose();
57
+ }
58
+ some(action, test) {
59
+ const list = this.bindings[action];
60
+ if (!list)
61
+ throw new Error(`Unknown input action "${action}". Known: ${Object.keys(this.bindings).join(", ")}`);
62
+ return list.some(test);
63
+ }
64
+ isPad(b) {
65
+ return b.startsWith("Pad");
66
+ }
67
+ /** Clear edges, then sample gamepads for the next step (the Gamepad API is poll-based). */
68
+ endStep() {
69
+ this.keys.endStep();
70
+ this.pointer.endStep();
71
+ this.pads.poll();
72
+ }
73
+ }
74
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Keyboard state by `KeyboardEvent.code` (layout-independent, e.g. `"KeyW"`, `"ArrowLeft"`, `"Space"`).
3
+ *
4
+ * Edges (`pressed`/`released`) are latched until `endStep()`, so a tap shorter than a
5
+ * simulation step is never missed. `Input` calls `endStep()` for you.
6
+ */
7
+ export declare class Keyboard {
8
+ private readonly held;
9
+ private readonly pressedEdge;
10
+ private readonly releasedEdge;
11
+ private readonly target;
12
+ /**
13
+ * Keys whose browser default (scrolling with arrows/Space, find-as-you-type…) is blocked so an
14
+ * embedded game doesn't move the page. Never applied while the user types in a form field.
15
+ */
16
+ readonly captured: Set<string>;
17
+ private readonly onDown;
18
+ private readonly onUp;
19
+ private readonly onBlur;
20
+ constructor(target?: Window | HTMLElement);
21
+ /** Key is currently held. */
22
+ down(code: string): boolean;
23
+ /** Key went down since the last step. */
24
+ pressed(code: string): boolean;
25
+ /** Key went up since the last step. */
26
+ released(code: string): boolean;
27
+ /** Simulate a key press (scenarios, tests, on-screen buttons). */
28
+ press(code: string): void;
29
+ /** Simulate a key release. */
30
+ release(code: string): void;
31
+ releaseAll(): void;
32
+ /** Clear edges. Call once after each simulation step. */
33
+ endStep(): void;
34
+ private shouldCapture;
35
+ dispose(): void;
36
+ }
37
+ //# sourceMappingURL=keyboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../src/keyboard.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqB;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAE9C;;;OAGG;IACH,QAAQ,CAAC,QAAQ,cAAqB;IAEtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAIrB;IACF,OAAO,CAAC,QAAQ,CAAC,IAAI,CAInB;IACF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2B;IAElD,YAAY,MAAM,GAAE,MAAM,GAAG,WAAoB,EAKhD;IAED,6BAA6B;IAC7B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1B;IAED,yCAAyC;IACzC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7B;IAED,uCAAuC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9B;IAED,kEAAkE;IAClE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAIxB;IAED,8BAA8B;IAC9B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAG1B;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,yDAAyD;IACzD,OAAO,IAAI,IAAI,CAGd;IAED,OAAO,CAAC,aAAa;IAOrB,OAAO,IAAI,IAAI,CAId;CACF"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Keyboard state by `KeyboardEvent.code` (layout-independent, e.g. `"KeyW"`, `"ArrowLeft"`, `"Space"`).
3
+ *
4
+ * Edges (`pressed`/`released`) are latched until `endStep()`, so a tap shorter than a
5
+ * simulation step is never missed. `Input` calls `endStep()` for you.
6
+ */
7
+ export class Keyboard {
8
+ held = new Set();
9
+ pressedEdge = new Set();
10
+ releasedEdge = new Set();
11
+ target;
12
+ /**
13
+ * Keys whose browser default (scrolling with arrows/Space, find-as-you-type…) is blocked so an
14
+ * embedded game doesn't move the page. Never applied while the user types in a form field.
15
+ */
16
+ captured = new Set();
17
+ onDown = (e) => {
18
+ const k = e;
19
+ if (this.shouldCapture(k))
20
+ k.preventDefault();
21
+ if (!k.repeat)
22
+ this.press(k.code);
23
+ };
24
+ onUp = (e) => {
25
+ const k = e;
26
+ if (this.shouldCapture(k))
27
+ k.preventDefault();
28
+ this.release(k.code);
29
+ };
30
+ onBlur = () => this.releaseAll();
31
+ constructor(target = window) {
32
+ this.target = target;
33
+ target.addEventListener("keydown", this.onDown);
34
+ target.addEventListener("keyup", this.onUp);
35
+ window.addEventListener("blur", this.onBlur);
36
+ }
37
+ /** Key is currently held. */
38
+ down(code) {
39
+ return this.held.has(code);
40
+ }
41
+ /** Key went down since the last step. */
42
+ pressed(code) {
43
+ return this.pressedEdge.has(code);
44
+ }
45
+ /** Key went up since the last step. */
46
+ released(code) {
47
+ return this.releasedEdge.has(code);
48
+ }
49
+ /** Simulate a key press (scenarios, tests, on-screen buttons). */
50
+ press(code) {
51
+ if (this.held.has(code))
52
+ return;
53
+ this.held.add(code);
54
+ this.pressedEdge.add(code);
55
+ }
56
+ /** Simulate a key release. */
57
+ release(code) {
58
+ if (!this.held.delete(code))
59
+ return;
60
+ this.releasedEdge.add(code);
61
+ }
62
+ releaseAll() {
63
+ for (const code of [...this.held])
64
+ this.release(code);
65
+ }
66
+ /** Clear edges. Call once after each simulation step. */
67
+ endStep() {
68
+ this.pressedEdge.clear();
69
+ this.releasedEdge.clear();
70
+ }
71
+ shouldCapture(e) {
72
+ if (!this.captured.has(e.code) || e.ctrlKey || e.metaKey || e.altKey)
73
+ return false;
74
+ const t = e.target;
75
+ const editable = t && (t.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(t.tagName));
76
+ return !editable;
77
+ }
78
+ dispose() {
79
+ this.target.removeEventListener("keydown", this.onDown);
80
+ this.target.removeEventListener("keyup", this.onUp);
81
+ window.removeEventListener("blur", this.onBlur);
82
+ }
83
+ }
84
+ //# sourceMappingURL=keyboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboard.js","sourceRoot":"","sources":["../src/keyboard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /** Maps client (event) coordinates to the game's logical coordinates. `Game.toLogical` fits. */
2
+ export type ToLogical = (clientX: number, clientY: number) => {
3
+ x: number;
4
+ y: number;
5
+ };
6
+ export interface TouchPoint {
7
+ readonly id: number;
8
+ x: number;
9
+ y: number;
10
+ }
11
+ /**
12
+ * Unified mouse, touch and pen input via Pointer Events, in logical game coordinates.
13
+ *
14
+ * `x`, `y`, `down`, `pressed` and `released` describe the primary pointer. Edges are
15
+ * latched until `endStep()`. All active contacts are in `touches` for multi-touch.
16
+ */
17
+ export declare class Pointer {
18
+ x: number;
19
+ y: number;
20
+ down: boolean;
21
+ pressed: boolean;
22
+ released: boolean;
23
+ /** Active contacts keyed by pointerId. */
24
+ readonly touches: Map<number, TouchPoint>;
25
+ private readonly element;
26
+ private readonly toLogical;
27
+ private readonly onDown;
28
+ private readonly onMove;
29
+ private readonly onContextMenu;
30
+ private readonly onUp;
31
+ constructor(element: HTMLElement, toLogical: ToLogical);
32
+ /** Simulate pressing the primary pointer at logical coordinates. */
33
+ press(x: number, y: number): void;
34
+ /** Simulate moving the primary pointer. */
35
+ move(x: number, y: number): void;
36
+ /** Simulate releasing the primary pointer. */
37
+ release(): void;
38
+ /** Clear edges. Call once after each simulation step. */
39
+ endStep(): void;
40
+ dispose(): void;
41
+ private track;
42
+ }
43
+ //# sourceMappingURL=pointer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pointer.d.ts","sourceRoot":"","sources":["../src/pointer.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;;;GAKG;AACH,qBAAa,OAAO;IAClB,CAAC,SAAK;IACN,CAAC,SAAK;IACN,IAAI,UAAS;IACb,OAAO,UAAS;IAChB,QAAQ,UAAS;IACjB,0CAA0C;IAC1C,QAAQ,CAAC,OAAO,0BAAiC;IAEjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IAEtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAKrB;IACF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAErB;IAEF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoC;IAClE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAGnB;IAEF,YAAY,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EASrD;IAED,oEAAoE;IACpE,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAMhC;IAED,2CAA2C;IAC3C,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAG/B;IAED,8CAA8C;IAC9C,OAAO,IAAI,IAAI,CAId;IAED,yDAAyD;IACzD,OAAO,IAAI,IAAI,CAGd;IAED,OAAO,IAAI,IAAI,CAMd;IAED,OAAO,CAAC,KAAK;CAOd"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Unified mouse, touch and pen input via Pointer Events, in logical game coordinates.
3
+ *
4
+ * `x`, `y`, `down`, `pressed` and `released` describe the primary pointer. Edges are
5
+ * latched until `endStep()`. All active contacts are in `touches` for multi-touch.
6
+ */
7
+ export class Pointer {
8
+ x = 0;
9
+ y = 0;
10
+ down = false;
11
+ pressed = false;
12
+ released = false;
13
+ /** Active contacts keyed by pointerId. */
14
+ touches = new Map();
15
+ element;
16
+ toLogical;
17
+ onDown = (e) => {
18
+ this.element.setPointerCapture?.(e.pointerId);
19
+ const p = this.track(e);
20
+ if (e.isPrimary)
21
+ this.press(p.x, p.y);
22
+ e.preventDefault();
23
+ };
24
+ onMove = (e) => {
25
+ if (this.touches.has(e.pointerId) || e.isPrimary)
26
+ this.track(e);
27
+ };
28
+ // Right-click shouldn't open the browser menu over a game.
29
+ onContextMenu = (e) => e.preventDefault();
30
+ onUp = (e) => {
31
+ this.touches.delete(e.pointerId);
32
+ if (e.isPrimary)
33
+ this.release();
34
+ };
35
+ constructor(element, toLogical) {
36
+ this.element = element;
37
+ this.toLogical = toLogical;
38
+ element.style.touchAction = "none";
39
+ element.addEventListener("pointerdown", this.onDown);
40
+ element.addEventListener("pointermove", this.onMove);
41
+ element.addEventListener("pointerup", this.onUp);
42
+ element.addEventListener("pointercancel", this.onUp);
43
+ element.addEventListener("contextmenu", this.onContextMenu);
44
+ }
45
+ /** Simulate pressing the primary pointer at logical coordinates. */
46
+ press(x, y) {
47
+ this.x = x;
48
+ this.y = y;
49
+ if (this.down)
50
+ return;
51
+ this.down = true;
52
+ this.pressed = true;
53
+ }
54
+ /** Simulate moving the primary pointer. */
55
+ move(x, y) {
56
+ this.x = x;
57
+ this.y = y;
58
+ }
59
+ /** Simulate releasing the primary pointer. */
60
+ release() {
61
+ if (!this.down)
62
+ return;
63
+ this.down = false;
64
+ this.released = true;
65
+ }
66
+ /** Clear edges. Call once after each simulation step. */
67
+ endStep() {
68
+ this.pressed = false;
69
+ this.released = false;
70
+ }
71
+ dispose() {
72
+ this.element.removeEventListener("pointerdown", this.onDown);
73
+ this.element.removeEventListener("pointermove", this.onMove);
74
+ this.element.removeEventListener("pointerup", this.onUp);
75
+ this.element.removeEventListener("pointercancel", this.onUp);
76
+ this.element.removeEventListener("contextmenu", this.onContextMenu);
77
+ }
78
+ track(e) {
79
+ const { x, y } = this.toLogical(e.clientX, e.clientY);
80
+ const point = { id: e.pointerId, x, y };
81
+ if (e.buttons || e.type === "pointerdown")
82
+ this.touches.set(e.pointerId, point);
83
+ if (e.isPrimary)
84
+ this.move(x, y);
85
+ return point;
86
+ }
87
+ }
88
+ //# sourceMappingURL=pointer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pointer.js","sourceRoot":"","sources":["../src/pointer.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,48 @@
1
1
  {
2
2
  "name": "@debuffjp/input",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "description": "Action-based keyboard, pointer and gamepad input for debuff",
5
+ "keywords": [
6
+ "game",
7
+ "gamedev",
8
+ "game-engine",
9
+ "2d",
10
+ "html5-game",
11
+ "browser-game",
12
+ "debuff",
13
+ "input",
14
+ "keyboard",
15
+ "gamepad",
16
+ "touch",
17
+ "pointer-events"
18
+ ],
19
+ "license": "MIT",
20
+ "homepage": "https://debuff.jp",
21
+ "bugs": "https://github.com/debuffjp/debuff/issues",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/debuffjp/debuff.git",
25
+ "directory": "packages/input"
26
+ },
27
+ "type": "module",
28
+ "sideEffects": false,
29
+ "main": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "default": "./dist/index.js"
35
+ }
36
+ },
37
+ "files": [
38
+ "dist",
39
+ "README.md"
40
+ ],
41
+ "scripts": {
42
+ "build": "tsc -b"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public",
46
+ "provenance": false
47
+ }
48
+ }