@al8b/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.
Files changed (56) hide show
  1. package/README.md +25 -0
  2. package/dist/core/input-manager.d.mts +25 -0
  3. package/dist/core/input-manager.d.ts +25 -0
  4. package/dist/core/input-manager.js +724 -0
  5. package/dist/core/input-manager.js.map +1 -0
  6. package/dist/core/input-manager.mjs +701 -0
  7. package/dist/core/input-manager.mjs.map +1 -0
  8. package/dist/devices/gamepad.d.mts +24 -0
  9. package/dist/devices/gamepad.d.ts +24 -0
  10. package/dist/devices/gamepad.js +244 -0
  11. package/dist/devices/gamepad.js.map +1 -0
  12. package/dist/devices/gamepad.mjs +221 -0
  13. package/dist/devices/gamepad.mjs.map +1 -0
  14. package/dist/devices/keyboard.d.mts +16 -0
  15. package/dist/devices/keyboard.d.ts +16 -0
  16. package/dist/devices/keyboard.js +131 -0
  17. package/dist/devices/keyboard.js.map +1 -0
  18. package/dist/devices/keyboard.mjs +106 -0
  19. package/dist/devices/keyboard.mjs.map +1 -0
  20. package/dist/devices/mouse.d.mts +21 -0
  21. package/dist/devices/mouse.d.ts +21 -0
  22. package/dist/devices/mouse.js +207 -0
  23. package/dist/devices/mouse.js.map +1 -0
  24. package/dist/devices/mouse.mjs +182 -0
  25. package/dist/devices/mouse.mjs.map +1 -0
  26. package/dist/devices/touch.d.mts +22 -0
  27. package/dist/devices/touch.d.ts +22 -0
  28. package/dist/devices/touch.js +186 -0
  29. package/dist/devices/touch.js.map +1 -0
  30. package/dist/devices/touch.mjs +161 -0
  31. package/dist/devices/touch.mjs.map +1 -0
  32. package/dist/index.d.mts +6 -0
  33. package/dist/index.d.ts +6 -0
  34. package/dist/index.js +735 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/index.mjs +706 -0
  37. package/dist/index.mjs.map +1 -0
  38. package/dist/shared/constants.d.mts +6 -0
  39. package/dist/shared/constants.d.ts +6 -0
  40. package/dist/shared/constants.js +40 -0
  41. package/dist/shared/constants.js.map +1 -0
  42. package/dist/shared/constants.mjs +12 -0
  43. package/dist/shared/constants.mjs.map +1 -0
  44. package/dist/shared/utils.d.mts +9 -0
  45. package/dist/shared/utils.d.ts +9 -0
  46. package/dist/shared/utils.js +56 -0
  47. package/dist/shared/utils.js.map +1 -0
  48. package/dist/shared/utils.mjs +29 -0
  49. package/dist/shared/utils.mjs.map +1 -0
  50. package/dist/types/index.d.mts +41 -0
  51. package/dist/types/index.d.ts +41 -0
  52. package/dist/types/index.js +19 -0
  53. package/dist/types/index.js.map +1 -0
  54. package/dist/types/index.mjs +1 -0
  55. package/dist/types/index.mjs.map +1 -0
  56. package/package.json +34 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/devices/gamepad.ts"],"sourcesContent":["/**\n * Gamepad - Game controller input handling\n *\n * Provides gamepad polling and state management.\n */\n\ntype ButtonMap = Record<number, string>;\ntype BrowserGamepad = globalThis.Gamepad;\n\ninterface StateMap extends Record<string, any> {\n\tpress: Record<string, number>;\n\trelease: Record<string, number>;\n}\n\nconst createState = (): StateMap => ({\n\tpress: {},\n\trelease: {},\n});\n\nconst BUTTONS_MAP: ButtonMap = {\n\t0: \"A\",\n\t1: \"B\",\n\t2: \"X\",\n\t3: \"Y\",\n\t4: \"LB\",\n\t5: \"RB\",\n\t8: \"VIEW\",\n\t9: \"MENU\",\n\t10: \"LS\",\n\t11: \"RS\",\n\t12: \"DPAD_UP\",\n\t13: \"DPAD_DOWN\",\n\t14: \"DPAD_LEFT\",\n\t15: \"DPAD_RIGHT\",\n};\n\nconst TRIGGERS_MAP: ButtonMap = {\n\t6: \"LT\",\n\t7: \"RT\",\n};\n\nconst ensureState = (state?: StateMap): StateMap => {\n\tif (!state) {\n\t\treturn createState();\n\t}\n\tstate.press ??= {};\n\tstate.release ??= {};\n\treturn state;\n};\n\nexport class GamepadInput {\n\tpublic status: StateMap & Record<number, StateMap>;\n\tpublic previous: {\n\t\tglobal: StateMap;\n\t} & Record<number, StateMap>;\n\tpublic count = 0;\n\n\tconstructor() {\n\t\tthis.status = createState();\n\t\tthis.previous = {\n\t\t\tglobal: createState(),\n\t\t};\n\t}\n\n\tupdate(): void {\n\t\tconst pads = this.getGamepads();\n\t\tif (!pads) {\n\t\t\tthis.count = 0;\n\t\t\treturn;\n\t\t}\n\n\t\tlet padCount = 0;\n\t\tfor (let i = 0; i < pads.length; i++) {\n\t\t\tconst pad = pads[i];\n\t\t\tif (!pad) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tpadCount++;\n\t\t\tthis.status[i] = ensureState(this.status[i]);\n\t\t\tthis.previous[i] = ensureState(this.previous[i]);\n\n\t\t\tfor (const [index, name] of Object.entries(BUTTONS_MAP)) {\n\t\t\t\tconst idx = Number(index);\n\t\t\t\tconst button = pad.buttons[idx];\n\t\t\t\tif (button) {\n\t\t\t\t\tthis.status[i][name] = button.pressed ? 1 : 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const [index, name] of Object.entries(TRIGGERS_MAP)) {\n\t\t\t\tconst idx = Number(index);\n\t\t\t\tconst trigger = pad.buttons[idx];\n\t\t\t\tif (trigger) {\n\t\t\t\t\tthis.status[i][name] = trigger.value ?? 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (pad.axes.length >= 2) {\n\t\t\t\tthis.updateStick(pad.axes[0], -pad.axes[1], this.status[i], \"LEFT\");\n\t\t\t}\n\t\t\tif (pad.axes.length >= 4) {\n\t\t\t\tthis.updateStick(pad.axes[2], -pad.axes[3], this.status[i], \"RIGHT\");\n\t\t\t}\n\t\t}\n\n\t\tthis.aggregateStatus(pads, padCount);\n\t\tthis.count = padCount;\n\t\tthis.updateChanges(this.status, this.previous.global);\n\t\tfor (let i = 0; i < padCount; i++) {\n\t\t\tthis.updateChanges(this.status[i], this.previous[i]);\n\t\t}\n\n\t\tfor (let i = padCount; i < 4; i++) {\n\t\t\tdelete this.status[i];\n\t\t\tdelete this.previous[i];\n\t\t}\n\t}\n\n\tprivate getGamepads(): (BrowserGamepad | null)[] | null {\n\t\tif (typeof navigator === \"undefined\" || !navigator.getGamepads) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\treturn navigator.getGamepads();\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate updateStick(x: number, y: number, target: StateMap, prefix: \"LEFT\" | \"RIGHT\"): void {\n\t\tconst radius = Math.sqrt(x * x + y * y);\n\t\tconst angle = Math.floor((((Math.atan2(y, x) + Math.PI * 2) % (Math.PI * 2)) / (Math.PI * 2)) * 360);\n\t\ttarget[`${prefix}_STICK_ANGLE`] = angle;\n\t\ttarget[`${prefix}_STICK_AMOUNT`] = radius;\n\t\ttarget[`${prefix}_STICK_UP`] = y > 0.5 ? 1 : 0;\n\t\ttarget[`${prefix}_STICK_DOWN`] = y < -0.5 ? 1 : 0;\n\t\ttarget[`${prefix}_STICK_LEFT`] = x < -0.5 ? 1 : 0;\n\t\ttarget[`${prefix}_STICK_RIGHT`] = x > 0.5 ? 1 : 0;\n\t}\n\n\tprivate aggregateStatus(pads: (BrowserGamepad | null)[], padCount: number): void {\n\t\tfor (const [index, name] of Object.entries(BUTTONS_MAP)) {\n\t\t\tthis.status[name] = 0;\n\t\t\tconst idx = Number(index);\n\t\t\tfor (const pad of pads) {\n\t\t\t\tif (!pad) break;\n\t\t\t\tif (pad.buttons[idx]?.pressed) {\n\t\t\t\t\tthis.status[name] = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const [index, name] of Object.entries(TRIGGERS_MAP)) {\n\t\t\tthis.status[name] = 0;\n\t\t\tconst idx = Number(index);\n\t\t\tfor (const pad of pads) {\n\t\t\t\tif (!pad) break;\n\t\t\t\tconst button = pad.buttons[idx];\n\t\t\t\tif (button) {\n\t\t\t\t\tthis.status[name] = button.value ?? 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.status.UP = 0;\n\t\tthis.status.DOWN = 0;\n\t\tthis.status.LEFT = 0;\n\t\tthis.status.RIGHT = 0;\n\t\tthis.status.LEFT_STICK_UP = 0;\n\t\tthis.status.LEFT_STICK_DOWN = 0;\n\t\tthis.status.LEFT_STICK_LEFT = 0;\n\t\tthis.status.LEFT_STICK_RIGHT = 0;\n\t\tthis.status.RIGHT_STICK_UP = 0;\n\t\tthis.status.RIGHT_STICK_DOWN = 0;\n\t\tthis.status.RIGHT_STICK_LEFT = 0;\n\t\tthis.status.RIGHT_STICK_RIGHT = 0;\n\t\tthis.status.LEFT_STICK_ANGLE = 0;\n\t\tthis.status.LEFT_STICK_AMOUNT = 0;\n\t\tthis.status.RIGHT_STICK_ANGLE = 0;\n\t\tthis.status.RIGHT_STICK_AMOUNT = 0;\n\t\tthis.status.RT = 0;\n\t\tthis.status.LT = 0;\n\n\t\tfor (let i = 0; i < padCount; i++) {\n\t\t\tconst padState = this.status[i];\n\t\t\tif (!padState) continue;\n\n\t\t\tpadState.UP = padState.DPAD_UP || padState.LEFT_STICK_UP || padState.RIGHT_STICK_UP || 0 ? 1 : 0;\n\t\t\tpadState.DOWN = padState.DPAD_DOWN || padState.LEFT_STICK_DOWN || padState.RIGHT_STICK_DOWN || 0 ? 1 : 0;\n\t\t\tpadState.LEFT = padState.DPAD_LEFT || padState.LEFT_STICK_LEFT || padState.RIGHT_STICK_LEFT || 0 ? 1 : 0;\n\t\t\tpadState.RIGHT = padState.DPAD_RIGHT || padState.LEFT_STICK_RIGHT || padState.RIGHT_STICK_RIGHT || 0 ? 1 : 0;\n\n\t\t\tif (padState.UP) this.status.UP = 1;\n\t\t\tif (padState.DOWN) this.status.DOWN = 1;\n\t\t\tif (padState.LEFT) this.status.LEFT = 1;\n\t\t\tif (padState.RIGHT) this.status.RIGHT = 1;\n\n\t\t\tif (padState.LEFT_STICK_UP) this.status.LEFT_STICK_UP = 1;\n\t\t\tif (padState.LEFT_STICK_DOWN) this.status.LEFT_STICK_DOWN = 1;\n\t\t\tif (padState.LEFT_STICK_LEFT) this.status.LEFT_STICK_LEFT = 1;\n\t\t\tif (padState.LEFT_STICK_RIGHT) this.status.LEFT_STICK_RIGHT = 1;\n\t\t\tif (padState.RIGHT_STICK_UP) this.status.RIGHT_STICK_UP = 1;\n\t\t\tif (padState.RIGHT_STICK_DOWN) this.status.RIGHT_STICK_DOWN = 1;\n\t\t\tif (padState.RIGHT_STICK_LEFT) this.status.RIGHT_STICK_LEFT = 1;\n\t\t\tif (padState.RIGHT_STICK_RIGHT) this.status.RIGHT_STICK_RIGHT = 1;\n\t\t\tif (padState.LT) this.status.LT = padState.LT;\n\t\t\tif (padState.RT) this.status.RT = padState.RT;\n\n\t\t\tif ((padState.LEFT_STICK_AMOUNT ?? 0) > (this.status.LEFT_STICK_AMOUNT ?? 0)) {\n\t\t\t\tthis.status.LEFT_STICK_AMOUNT = padState.LEFT_STICK_AMOUNT;\n\t\t\t\tthis.status.LEFT_STICK_ANGLE = padState.LEFT_STICK_ANGLE;\n\t\t\t}\n\t\t\tif ((padState.RIGHT_STICK_AMOUNT ?? 0) > (this.status.RIGHT_STICK_AMOUNT ?? 0)) {\n\t\t\t\tthis.status.RIGHT_STICK_AMOUNT = padState.RIGHT_STICK_AMOUNT;\n\t\t\t\tthis.status.RIGHT_STICK_ANGLE = padState.RIGHT_STICK_ANGLE;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate updateChanges(current: StateMap, previous: StateMap): void {\n\t\tfor (const key in current.press) {\n\t\t\tcurrent.press[key] = 0;\n\t\t}\n\t\tfor (const key in current.release) {\n\t\t\tcurrent.release[key] = 0;\n\t\t}\n\t\tfor (const key in previous) {\n\t\t\tif (key === \"press\" || key === \"release\") continue;\n\t\t\tif (previous[key] && !current[key]) {\n\t\t\t\tcurrent.release[key] = 1;\n\t\t\t}\n\t\t}\n\t\tfor (const key in current) {\n\t\t\tif (key === \"press\" || key === \"release\") continue;\n\t\t\tif (current[key] && !previous[key]) {\n\t\t\t\tcurrent.press[key] = 1;\n\t\t\t}\n\t\t}\n\t\tfor (const key in previous) {\n\t\t\tif (key === \"press\" || key === \"release\") continue;\n\t\t\tprevious[key] = 0;\n\t\t}\n\t\tfor (const key in current) {\n\t\t\tif (key === \"press\" || key === \"release\") continue;\n\t\t\tprevious[key] = current[key];\n\t\t}\n\t}\n}\n"],"mappings":"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","names":["createState","press","release","BUTTONS_MAP","TRIGGERS_MAP","ensureState","state","GamepadInput","status","previous","count","global","update","pads","getGamepads","padCount","i","length","pad","index","name","Object","entries","idx","Number","button","buttons","pressed","trigger","value","axes","updateStick","aggregateStatus","updateChanges","navigator","x","y","target","prefix","radius","Math","sqrt","angle","floor","atan2","PI","UP","DOWN","LEFT","RIGHT","LEFT_STICK_UP","LEFT_STICK_DOWN","LEFT_STICK_LEFT","LEFT_STICK_RIGHT","RIGHT_STICK_UP","RIGHT_STICK_DOWN","RIGHT_STICK_LEFT","RIGHT_STICK_RIGHT","LEFT_STICK_ANGLE","LEFT_STICK_AMOUNT","RIGHT_STICK_ANGLE","RIGHT_STICK_AMOUNT","RT","LT","padState","DPAD_UP","DPAD_DOWN","DPAD_LEFT","DPAD_RIGHT","current","key"]}
@@ -0,0 +1,16 @@
1
+ import { KeyboardState } from '../types/index.mjs';
2
+
3
+ declare class KeyboardInput {
4
+ readonly state: KeyboardState;
5
+ private previous;
6
+ private dirtyKeys;
7
+ constructor(target?: Document);
8
+ private convertCode;
9
+ private handleKeyDown;
10
+ private handleKeyUp;
11
+ private updateDirectional;
12
+ update(): void;
13
+ reset(): void;
14
+ }
15
+
16
+ export { KeyboardInput };
@@ -0,0 +1,16 @@
1
+ import { KeyboardState } from '../types/index.js';
2
+
3
+ declare class KeyboardInput {
4
+ readonly state: KeyboardState;
5
+ private previous;
6
+ private dirtyKeys;
7
+ constructor(target?: Document);
8
+ private convertCode;
9
+ private handleKeyDown;
10
+ private handleKeyUp;
11
+ private updateDirectional;
12
+ update(): void;
13
+ reset(): void;
14
+ }
15
+
16
+ export { KeyboardInput };
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/devices/keyboard.ts
22
+ var keyboard_exports = {};
23
+ __export(keyboard_exports, {
24
+ KeyboardInput: () => KeyboardInput
25
+ });
26
+ module.exports = __toCommonJS(keyboard_exports);
27
+
28
+ // src/shared/constants.ts
29
+ var PREVENT_DEFAULT_REGEX = /Escape|(F\d+)/;
30
+
31
+ // src/shared/utils.ts
32
+ var hasDocument = typeof document !== "undefined";
33
+
34
+ // src/devices/keyboard.ts
35
+ var KeyboardInput = class {
36
+ static {
37
+ __name(this, "KeyboardInput");
38
+ }
39
+ state = {
40
+ press: {},
41
+ release: {},
42
+ UP: 0,
43
+ DOWN: 0,
44
+ LEFT: 0,
45
+ RIGHT: 0
46
+ };
47
+ previous = {};
48
+ // Track only keys that changed since last update() — avoids O(n) iteration of all keys
49
+ dirtyKeys = /* @__PURE__ */ new Set();
50
+ constructor(target = hasDocument ? document : void 0) {
51
+ if (!target) {
52
+ return;
53
+ }
54
+ target.addEventListener("keydown", (event) => this.handleKeyDown(event));
55
+ target.addEventListener("keyup", (event) => this.handleKeyUp(event));
56
+ }
57
+ convertCode(code) {
58
+ let res = "";
59
+ let low = false;
60
+ for (let i = 0; i < code.length; i++) {
61
+ const c = code.charAt(i);
62
+ if (c === c.toUpperCase() && low) {
63
+ res += "_";
64
+ low = false;
65
+ } else {
66
+ low = true;
67
+ }
68
+ res += c.toUpperCase();
69
+ }
70
+ return res;
71
+ }
72
+ handleKeyDown(event) {
73
+ if (!(event.altKey || event.ctrlKey || event.metaKey || PREVENT_DEFAULT_REGEX.test(event.key))) {
74
+ event.preventDefault();
75
+ }
76
+ const codeKey = this.convertCode(event.code);
77
+ const upperKey = event.key.toUpperCase();
78
+ this.state[codeKey] = 1;
79
+ this.state[upperKey] = 1;
80
+ this.dirtyKeys.add(codeKey);
81
+ this.dirtyKeys.add(upperKey);
82
+ this.updateDirectional();
83
+ }
84
+ handleKeyUp(event) {
85
+ const codeKey = this.convertCode(event.code);
86
+ const upperKey = event.key.toUpperCase();
87
+ this.state[codeKey] = 0;
88
+ this.state[upperKey] = 0;
89
+ this.dirtyKeys.add(codeKey);
90
+ this.dirtyKeys.add(upperKey);
91
+ this.updateDirectional();
92
+ }
93
+ updateDirectional() {
94
+ this.state.UP = this.state.KEY_W || this.state.ARROW_UP || 0;
95
+ this.state.DOWN = this.state.KEY_S || this.state.ARROW_DOWN || 0;
96
+ this.state.LEFT = this.state.KEY_A || this.state.ARROW_LEFT || 0;
97
+ this.state.RIGHT = this.state.KEY_D || this.state.ARROW_RIGHT || 0;
98
+ }
99
+ update() {
100
+ for (const key of this.dirtyKeys) {
101
+ if (this.state.press[key]) this.state.press[key] = 0;
102
+ if (this.state.release[key]) this.state.release[key] = 0;
103
+ }
104
+ for (const key of this.dirtyKeys) {
105
+ const current = this.state[key];
106
+ const prev = this.previous[key] || 0;
107
+ if (current && !prev) {
108
+ this.state.press[key] = 1;
109
+ } else if (!current && prev) {
110
+ this.state.release[key] = 1;
111
+ }
112
+ this.previous[key] = current;
113
+ }
114
+ this.dirtyKeys.clear();
115
+ }
116
+ reset() {
117
+ for (const key in this.state) {
118
+ if (key === "press" || key === "release") continue;
119
+ this.state[key] = 0;
120
+ }
121
+ for (const key in this.previous) {
122
+ this.previous[key] = 0;
123
+ }
124
+ this.dirtyKeys.clear();
125
+ }
126
+ };
127
+ // Annotate the CommonJS export names for ESM import in node:
128
+ 0 && (module.exports = {
129
+ KeyboardInput
130
+ });
131
+ //# sourceMappingURL=keyboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/devices/keyboard.ts","../../src/shared/constants.ts","../../src/shared/utils.ts"],"sourcesContent":["import { PREVENT_DEFAULT_REGEX } from \"../shared/constants\";\nimport { hasDocument } from \"../shared/utils\";\nimport type { KeyboardState } from \"../types\";\n\nexport class KeyboardInput {\n\tpublic readonly state: KeyboardState = {\n\t\tpress: {},\n\t\trelease: {},\n\t\tUP: 0,\n\t\tDOWN: 0,\n\t\tLEFT: 0,\n\t\tRIGHT: 0,\n\t};\n\n\tprivate previous: Record<string, number> = {};\n\n\t// Track only keys that changed since last update() — avoids O(n) iteration of all keys\n\tprivate dirtyKeys: Set<string> = new Set();\n\n\tconstructor(target: Document = hasDocument ? document : (undefined as any)) {\n\t\tif (!target) {\n\t\t\treturn;\n\t\t}\n\t\ttarget.addEventListener(\"keydown\", (event) => this.handleKeyDown(event));\n\t\ttarget.addEventListener(\"keyup\", (event) => this.handleKeyUp(event));\n\t}\n\n\tprivate convertCode(code: string): string {\n\t\tlet res = \"\";\n\t\tlet low = false;\n\t\tfor (let i = 0; i < code.length; i++) {\n\t\t\tconst c = code.charAt(i);\n\t\t\tif (c === c.toUpperCase() && low) {\n\t\t\t\tres += \"_\";\n\t\t\t\tlow = false;\n\t\t\t} else {\n\t\t\t\tlow = true;\n\t\t\t}\n\t\t\tres += c.toUpperCase();\n\t\t}\n\t\treturn res;\n\t}\n\n\tprivate handleKeyDown(event: KeyboardEvent): void {\n\t\tif (!(event.altKey || event.ctrlKey || event.metaKey || PREVENT_DEFAULT_REGEX.test(event.key))) {\n\t\t\tevent.preventDefault();\n\t\t}\n\t\tconst codeKey = this.convertCode(event.code);\n\t\tconst upperKey = event.key.toUpperCase();\n\t\tthis.state[codeKey] = 1;\n\t\tthis.state[upperKey] = 1;\n\t\tthis.dirtyKeys.add(codeKey);\n\t\tthis.dirtyKeys.add(upperKey);\n\t\tthis.updateDirectional();\n\t}\n\n\tprivate handleKeyUp(event: KeyboardEvent): void {\n\t\tconst codeKey = this.convertCode(event.code);\n\t\tconst upperKey = event.key.toUpperCase();\n\t\tthis.state[codeKey] = 0;\n\t\tthis.state[upperKey] = 0;\n\t\tthis.dirtyKeys.add(codeKey);\n\t\tthis.dirtyKeys.add(upperKey);\n\t\tthis.updateDirectional();\n\t}\n\n\tprivate updateDirectional(): void {\n\t\tthis.state.UP = (this.state.KEY_W as number) || (this.state.ARROW_UP as number) || 0;\n\t\tthis.state.DOWN = (this.state.KEY_S as number) || (this.state.ARROW_DOWN as number) || 0;\n\t\tthis.state.LEFT = (this.state.KEY_A as number) || (this.state.ARROW_LEFT as number) || 0;\n\t\tthis.state.RIGHT = (this.state.KEY_D as number) || (this.state.ARROW_RIGHT as number) || 0;\n\t}\n\n\tpublic update(): void {\n\t\t// Clear previous press/release state only for dirty keys\n\t\tfor (const key of this.dirtyKeys) {\n\t\t\tif (this.state.press[key]) this.state.press[key] = 0;\n\t\t\tif (this.state.release[key]) this.state.release[key] = 0;\n\t\t}\n\n\t\t// Detect press/release transitions only for dirty keys\n\t\tfor (const key of this.dirtyKeys) {\n\t\t\tconst current = this.state[key] as number;\n\t\t\tconst prev = this.previous[key] || 0;\n\n\t\t\tif (current && !prev) {\n\t\t\t\tthis.state.press[key] = 1;\n\t\t\t} else if (!current && prev) {\n\t\t\t\tthis.state.release[key] = 1;\n\t\t\t}\n\n\t\t\tthis.previous[key] = current;\n\t\t}\n\n\t\tthis.dirtyKeys.clear();\n\t}\n\n\tpublic reset(): void {\n\t\tfor (const key in this.state) {\n\t\t\tif (key === \"press\" || key === \"release\") continue;\n\t\t\tthis.state[key] = 0;\n\t\t}\n\t\tfor (const key in this.previous) {\n\t\t\tthis.previous[key] = 0;\n\t\t}\n\t\tthis.dirtyKeys.clear();\n\t}\n}\n","export const NORMALIZED_SCALE = 200;\nexport const OUT_OF_BOUNDS = -10000;\nexport const PREVENT_DEFAULT_REGEX = /Escape|(F\\d+)/;\nexport const TOUCH_MOUSE_ID = \"mouse\";\n","import { NORMALIZED_SCALE } from \"./constants\";\n\ninterface RelativePosition {\n\tx: number;\n\ty: number;\n}\n\nexport const hasDocument = typeof document !== \"undefined\";\n\nexport const computeRelativePosition = (\n\tcanvas: HTMLCanvasElement,\n\tclientX: number,\n\tclientY: number,\n): RelativePosition => {\n\tconst rect = canvas.getBoundingClientRect();\n\tconst min = Math.min(canvas.clientWidth, canvas.clientHeight) || 1;\n\tconst x = ((clientX - rect.left - canvas.clientWidth / 2) / min) * NORMALIZED_SCALE;\n\tconst y = ((canvas.clientHeight / 2 - (clientY - rect.top)) / min) * NORMALIZED_SCALE;\n\treturn {\n\t\tx,\n\t\ty,\n\t};\n};\n\nexport const addEventListener = <K extends keyof DocumentEventMap>(\n\ttarget: Document | HTMLElement,\n\ttype: K,\n\tlistener: (this: Document | HTMLElement, ev: DocumentEventMap[K]) => any,\n): void => {\n\ttarget.addEventListener(type, listener as EventListener, {\n\t\tpassive: false,\n\t});\n};\n"],"mappings":"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","names":["PREVENT_DEFAULT_REGEX","hasDocument","document","KeyboardInput","state","press","release","UP","DOWN","LEFT","RIGHT","previous","dirtyKeys","Set","target","hasDocument","document","undefined","addEventListener","event","handleKeyDown","handleKeyUp","convertCode","code","res","low","i","length","c","charAt","toUpperCase","altKey","ctrlKey","metaKey","PREVENT_DEFAULT_REGEX","test","key","preventDefault","codeKey","upperKey","add","updateDirectional","KEY_W","ARROW_UP","KEY_S","ARROW_DOWN","KEY_A","ARROW_LEFT","KEY_D","ARROW_RIGHT","update","current","prev","clear","reset"]}
@@ -0,0 +1,106 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // src/shared/constants.ts
5
+ var PREVENT_DEFAULT_REGEX = /Escape|(F\d+)/;
6
+
7
+ // src/shared/utils.ts
8
+ var hasDocument = typeof document !== "undefined";
9
+
10
+ // src/devices/keyboard.ts
11
+ var KeyboardInput = class {
12
+ static {
13
+ __name(this, "KeyboardInput");
14
+ }
15
+ state = {
16
+ press: {},
17
+ release: {},
18
+ UP: 0,
19
+ DOWN: 0,
20
+ LEFT: 0,
21
+ RIGHT: 0
22
+ };
23
+ previous = {};
24
+ // Track only keys that changed since last update() — avoids O(n) iteration of all keys
25
+ dirtyKeys = /* @__PURE__ */ new Set();
26
+ constructor(target = hasDocument ? document : void 0) {
27
+ if (!target) {
28
+ return;
29
+ }
30
+ target.addEventListener("keydown", (event) => this.handleKeyDown(event));
31
+ target.addEventListener("keyup", (event) => this.handleKeyUp(event));
32
+ }
33
+ convertCode(code) {
34
+ let res = "";
35
+ let low = false;
36
+ for (let i = 0; i < code.length; i++) {
37
+ const c = code.charAt(i);
38
+ if (c === c.toUpperCase() && low) {
39
+ res += "_";
40
+ low = false;
41
+ } else {
42
+ low = true;
43
+ }
44
+ res += c.toUpperCase();
45
+ }
46
+ return res;
47
+ }
48
+ handleKeyDown(event) {
49
+ if (!(event.altKey || event.ctrlKey || event.metaKey || PREVENT_DEFAULT_REGEX.test(event.key))) {
50
+ event.preventDefault();
51
+ }
52
+ const codeKey = this.convertCode(event.code);
53
+ const upperKey = event.key.toUpperCase();
54
+ this.state[codeKey] = 1;
55
+ this.state[upperKey] = 1;
56
+ this.dirtyKeys.add(codeKey);
57
+ this.dirtyKeys.add(upperKey);
58
+ this.updateDirectional();
59
+ }
60
+ handleKeyUp(event) {
61
+ const codeKey = this.convertCode(event.code);
62
+ const upperKey = event.key.toUpperCase();
63
+ this.state[codeKey] = 0;
64
+ this.state[upperKey] = 0;
65
+ this.dirtyKeys.add(codeKey);
66
+ this.dirtyKeys.add(upperKey);
67
+ this.updateDirectional();
68
+ }
69
+ updateDirectional() {
70
+ this.state.UP = this.state.KEY_W || this.state.ARROW_UP || 0;
71
+ this.state.DOWN = this.state.KEY_S || this.state.ARROW_DOWN || 0;
72
+ this.state.LEFT = this.state.KEY_A || this.state.ARROW_LEFT || 0;
73
+ this.state.RIGHT = this.state.KEY_D || this.state.ARROW_RIGHT || 0;
74
+ }
75
+ update() {
76
+ for (const key of this.dirtyKeys) {
77
+ if (this.state.press[key]) this.state.press[key] = 0;
78
+ if (this.state.release[key]) this.state.release[key] = 0;
79
+ }
80
+ for (const key of this.dirtyKeys) {
81
+ const current = this.state[key];
82
+ const prev = this.previous[key] || 0;
83
+ if (current && !prev) {
84
+ this.state.press[key] = 1;
85
+ } else if (!current && prev) {
86
+ this.state.release[key] = 1;
87
+ }
88
+ this.previous[key] = current;
89
+ }
90
+ this.dirtyKeys.clear();
91
+ }
92
+ reset() {
93
+ for (const key in this.state) {
94
+ if (key === "press" || key === "release") continue;
95
+ this.state[key] = 0;
96
+ }
97
+ for (const key in this.previous) {
98
+ this.previous[key] = 0;
99
+ }
100
+ this.dirtyKeys.clear();
101
+ }
102
+ };
103
+ export {
104
+ KeyboardInput
105
+ };
106
+ //# sourceMappingURL=keyboard.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/shared/constants.ts","../../src/shared/utils.ts","../../src/devices/keyboard.ts"],"sourcesContent":["export const NORMALIZED_SCALE = 200;\nexport const OUT_OF_BOUNDS = -10000;\nexport const PREVENT_DEFAULT_REGEX = /Escape|(F\\d+)/;\nexport const TOUCH_MOUSE_ID = \"mouse\";\n","import { NORMALIZED_SCALE } from \"./constants\";\n\ninterface RelativePosition {\n\tx: number;\n\ty: number;\n}\n\nexport const hasDocument = typeof document !== \"undefined\";\n\nexport const computeRelativePosition = (\n\tcanvas: HTMLCanvasElement,\n\tclientX: number,\n\tclientY: number,\n): RelativePosition => {\n\tconst rect = canvas.getBoundingClientRect();\n\tconst min = Math.min(canvas.clientWidth, canvas.clientHeight) || 1;\n\tconst x = ((clientX - rect.left - canvas.clientWidth / 2) / min) * NORMALIZED_SCALE;\n\tconst y = ((canvas.clientHeight / 2 - (clientY - rect.top)) / min) * NORMALIZED_SCALE;\n\treturn {\n\t\tx,\n\t\ty,\n\t};\n};\n\nexport const addEventListener = <K extends keyof DocumentEventMap>(\n\ttarget: Document | HTMLElement,\n\ttype: K,\n\tlistener: (this: Document | HTMLElement, ev: DocumentEventMap[K]) => any,\n): void => {\n\ttarget.addEventListener(type, listener as EventListener, {\n\t\tpassive: false,\n\t});\n};\n","import { PREVENT_DEFAULT_REGEX } from \"../shared/constants\";\nimport { hasDocument } from \"../shared/utils\";\nimport type { KeyboardState } from \"../types\";\n\nexport class KeyboardInput {\n\tpublic readonly state: KeyboardState = {\n\t\tpress: {},\n\t\trelease: {},\n\t\tUP: 0,\n\t\tDOWN: 0,\n\t\tLEFT: 0,\n\t\tRIGHT: 0,\n\t};\n\n\tprivate previous: Record<string, number> = {};\n\n\t// Track only keys that changed since last update() — avoids O(n) iteration of all keys\n\tprivate dirtyKeys: Set<string> = new Set();\n\n\tconstructor(target: Document = hasDocument ? document : (undefined as any)) {\n\t\tif (!target) {\n\t\t\treturn;\n\t\t}\n\t\ttarget.addEventListener(\"keydown\", (event) => this.handleKeyDown(event));\n\t\ttarget.addEventListener(\"keyup\", (event) => this.handleKeyUp(event));\n\t}\n\n\tprivate convertCode(code: string): string {\n\t\tlet res = \"\";\n\t\tlet low = false;\n\t\tfor (let i = 0; i < code.length; i++) {\n\t\t\tconst c = code.charAt(i);\n\t\t\tif (c === c.toUpperCase() && low) {\n\t\t\t\tres += \"_\";\n\t\t\t\tlow = false;\n\t\t\t} else {\n\t\t\t\tlow = true;\n\t\t\t}\n\t\t\tres += c.toUpperCase();\n\t\t}\n\t\treturn res;\n\t}\n\n\tprivate handleKeyDown(event: KeyboardEvent): void {\n\t\tif (!(event.altKey || event.ctrlKey || event.metaKey || PREVENT_DEFAULT_REGEX.test(event.key))) {\n\t\t\tevent.preventDefault();\n\t\t}\n\t\tconst codeKey = this.convertCode(event.code);\n\t\tconst upperKey = event.key.toUpperCase();\n\t\tthis.state[codeKey] = 1;\n\t\tthis.state[upperKey] = 1;\n\t\tthis.dirtyKeys.add(codeKey);\n\t\tthis.dirtyKeys.add(upperKey);\n\t\tthis.updateDirectional();\n\t}\n\n\tprivate handleKeyUp(event: KeyboardEvent): void {\n\t\tconst codeKey = this.convertCode(event.code);\n\t\tconst upperKey = event.key.toUpperCase();\n\t\tthis.state[codeKey] = 0;\n\t\tthis.state[upperKey] = 0;\n\t\tthis.dirtyKeys.add(codeKey);\n\t\tthis.dirtyKeys.add(upperKey);\n\t\tthis.updateDirectional();\n\t}\n\n\tprivate updateDirectional(): void {\n\t\tthis.state.UP = (this.state.KEY_W as number) || (this.state.ARROW_UP as number) || 0;\n\t\tthis.state.DOWN = (this.state.KEY_S as number) || (this.state.ARROW_DOWN as number) || 0;\n\t\tthis.state.LEFT = (this.state.KEY_A as number) || (this.state.ARROW_LEFT as number) || 0;\n\t\tthis.state.RIGHT = (this.state.KEY_D as number) || (this.state.ARROW_RIGHT as number) || 0;\n\t}\n\n\tpublic update(): void {\n\t\t// Clear previous press/release state only for dirty keys\n\t\tfor (const key of this.dirtyKeys) {\n\t\t\tif (this.state.press[key]) this.state.press[key] = 0;\n\t\t\tif (this.state.release[key]) this.state.release[key] = 0;\n\t\t}\n\n\t\t// Detect press/release transitions only for dirty keys\n\t\tfor (const key of this.dirtyKeys) {\n\t\t\tconst current = this.state[key] as number;\n\t\t\tconst prev = this.previous[key] || 0;\n\n\t\t\tif (current && !prev) {\n\t\t\t\tthis.state.press[key] = 1;\n\t\t\t} else if (!current && prev) {\n\t\t\t\tthis.state.release[key] = 1;\n\t\t\t}\n\n\t\t\tthis.previous[key] = current;\n\t\t}\n\n\t\tthis.dirtyKeys.clear();\n\t}\n\n\tpublic reset(): void {\n\t\tfor (const key in this.state) {\n\t\t\tif (key === \"press\" || key === \"release\") continue;\n\t\t\tthis.state[key] = 0;\n\t\t}\n\t\tfor (const key in this.previous) {\n\t\t\tthis.previous[key] = 0;\n\t\t}\n\t\tthis.dirtyKeys.clear();\n\t}\n}\n"],"mappings":"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","names":["PREVENT_DEFAULT_REGEX","hasDocument","document","KeyboardInput","state","press","release","UP","DOWN","LEFT","RIGHT","previous","dirtyKeys","Set","target","hasDocument","document","undefined","addEventListener","event","handleKeyDown","handleKeyUp","convertCode","code","res","low","i","length","c","charAt","toUpperCase","altKey","ctrlKey","metaKey","PREVENT_DEFAULT_REGEX","test","key","preventDefault","codeKey","upperKey","add","updateDirectional","KEY_W","ARROW_UP","KEY_S","ARROW_DOWN","KEY_A","ARROW_LEFT","KEY_D","ARROW_RIGHT","update","current","prev","clear","reset"]}
@@ -0,0 +1,21 @@
1
+ import { MouseState } from '../types/index.mjs';
2
+
3
+ declare class MouseInput {
4
+ readonly state: MouseState;
5
+ private previousPressed;
6
+ private wheel;
7
+ private canvas?;
8
+ private removeListeners?;
9
+ constructor(canvas?: HTMLCanvasElement);
10
+ setCanvas(canvas: HTMLCanvasElement): void;
11
+ syncFromTouch(x: number, y: number, touching: boolean): void;
12
+ update(): void;
13
+ private attach;
14
+ private detach;
15
+ private handleMouseDown;
16
+ private handleMouseMove;
17
+ private handleMouseUp;
18
+ private handleWheel;
19
+ }
20
+
21
+ export { MouseInput };
@@ -0,0 +1,21 @@
1
+ import { MouseState } from '../types/index.js';
2
+
3
+ declare class MouseInput {
4
+ readonly state: MouseState;
5
+ private previousPressed;
6
+ private wheel;
7
+ private canvas?;
8
+ private removeListeners?;
9
+ constructor(canvas?: HTMLCanvasElement);
10
+ setCanvas(canvas: HTMLCanvasElement): void;
11
+ syncFromTouch(x: number, y: number, touching: boolean): void;
12
+ update(): void;
13
+ private attach;
14
+ private detach;
15
+ private handleMouseDown;
16
+ private handleMouseMove;
17
+ private handleMouseUp;
18
+ private handleWheel;
19
+ }
20
+
21
+ export { MouseInput };
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/devices/mouse.ts
22
+ var mouse_exports = {};
23
+ __export(mouse_exports, {
24
+ MouseInput: () => MouseInput
25
+ });
26
+ module.exports = __toCommonJS(mouse_exports);
27
+
28
+ // src/shared/constants.ts
29
+ var NORMALIZED_SCALE = 200;
30
+ var OUT_OF_BOUNDS = -1e4;
31
+
32
+ // src/shared/utils.ts
33
+ var hasDocument = typeof document !== "undefined";
34
+ var computeRelativePosition = /* @__PURE__ */ __name((canvas, clientX, clientY) => {
35
+ const rect = canvas.getBoundingClientRect();
36
+ const min = Math.min(canvas.clientWidth, canvas.clientHeight) || 1;
37
+ const x = (clientX - rect.left - canvas.clientWidth / 2) / min * NORMALIZED_SCALE;
38
+ const y = (canvas.clientHeight / 2 - (clientY - rect.top)) / min * NORMALIZED_SCALE;
39
+ return {
40
+ x,
41
+ y
42
+ };
43
+ }, "computeRelativePosition");
44
+
45
+ // src/devices/mouse.ts
46
+ var MouseInput = class {
47
+ static {
48
+ __name(this, "MouseInput");
49
+ }
50
+ state = {
51
+ x: OUT_OF_BOUNDS,
52
+ y: OUT_OF_BOUNDS,
53
+ pressed: 0,
54
+ left: 0,
55
+ middle: 0,
56
+ right: 0,
57
+ press: 0,
58
+ release: 0,
59
+ wheel: 0
60
+ };
61
+ previousPressed = false;
62
+ wheel = 0;
63
+ canvas;
64
+ removeListeners;
65
+ constructor(canvas) {
66
+ if (canvas) {
67
+ this.setCanvas(canvas);
68
+ }
69
+ }
70
+ setCanvas(canvas) {
71
+ this.detach();
72
+ this.canvas = canvas;
73
+ this.attach();
74
+ }
75
+ syncFromTouch(x, y, touching) {
76
+ this.state.x = x;
77
+ this.state.y = y;
78
+ if (touching) {
79
+ this.state.left = 1;
80
+ this.state.middle = 0;
81
+ this.state.right = 0;
82
+ this.state.pressed = 1;
83
+ } else {
84
+ this.state.left = 0;
85
+ this.state.middle = 0;
86
+ this.state.right = 0;
87
+ this.state.pressed = 0;
88
+ }
89
+ }
90
+ update() {
91
+ if (this.state.pressed && !this.previousPressed) {
92
+ this.previousPressed = true;
93
+ this.state.press = 1;
94
+ } else {
95
+ this.state.press = 0;
96
+ }
97
+ if (!this.state.pressed && this.previousPressed) {
98
+ this.previousPressed = false;
99
+ this.state.release = 1;
100
+ } else {
101
+ this.state.release = 0;
102
+ }
103
+ this.state.wheel = this.wheel;
104
+ this.wheel = 0;
105
+ }
106
+ attach() {
107
+ if (!hasDocument) {
108
+ return;
109
+ }
110
+ const target = document;
111
+ const onDown = /* @__PURE__ */ __name((event) => this.handleMouseDown(event), "onDown");
112
+ const onMove = /* @__PURE__ */ __name((event) => this.handleMouseMove(event), "onMove");
113
+ const onUp = /* @__PURE__ */ __name((event) => this.handleMouseUp(event), "onUp");
114
+ const onWheel = /* @__PURE__ */ __name((event) => this.handleWheel(event), "onWheel");
115
+ const onDomWheel = /* @__PURE__ */ __name((event) => this.handleWheel(event), "onDomWheel");
116
+ target.addEventListener("mousedown", onDown, {
117
+ passive: false
118
+ });
119
+ target.addEventListener("mousemove", onMove, {
120
+ passive: false
121
+ });
122
+ target.addEventListener("mouseup", onUp, {
123
+ passive: false
124
+ });
125
+ target.addEventListener("mousewheel", onWheel, {
126
+ passive: false
127
+ });
128
+ target.addEventListener("DOMMouseScroll", onDomWheel, {
129
+ passive: false
130
+ });
131
+ this.removeListeners = () => {
132
+ target.removeEventListener("mousedown", onDown);
133
+ target.removeEventListener("mousemove", onMove);
134
+ target.removeEventListener("mouseup", onUp);
135
+ target.removeEventListener("mousewheel", onWheel);
136
+ target.removeEventListener("DOMMouseScroll", onDomWheel);
137
+ };
138
+ }
139
+ detach() {
140
+ this.removeListeners?.();
141
+ this.removeListeners = void 0;
142
+ this.canvas = void 0;
143
+ }
144
+ handleMouseDown(event) {
145
+ if (!this.canvas) return;
146
+ event.preventDefault();
147
+ const { x, y } = computeRelativePosition(this.canvas, event.clientX, event.clientY);
148
+ this.state.x = x;
149
+ this.state.y = y;
150
+ switch (event.button) {
151
+ case 0:
152
+ this.state.left = 1;
153
+ break;
154
+ case 1:
155
+ this.state.middle = 1;
156
+ break;
157
+ case 2:
158
+ this.state.right = 1;
159
+ break;
160
+ }
161
+ this.state.pressed = Math.min(1, this.state.left + this.state.right + this.state.middle);
162
+ }
163
+ handleMouseMove(event) {
164
+ if (!this.canvas) return;
165
+ event.preventDefault();
166
+ const { x, y } = computeRelativePosition(this.canvas, event.clientX, event.clientY);
167
+ this.state.x = x;
168
+ this.state.y = y;
169
+ }
170
+ handleMouseUp(event) {
171
+ if (!this.canvas) return;
172
+ event.preventDefault();
173
+ const { x, y } = computeRelativePosition(this.canvas, event.clientX, event.clientY);
174
+ this.state.x = x;
175
+ this.state.y = y;
176
+ switch (event.button) {
177
+ case 0:
178
+ this.state.left = 0;
179
+ break;
180
+ case 1:
181
+ this.state.middle = 0;
182
+ break;
183
+ case 2:
184
+ this.state.right = 0;
185
+ break;
186
+ }
187
+ this.state.pressed = Math.min(1, this.state.left + this.state.right + this.state.middle);
188
+ }
189
+ handleWheel(event) {
190
+ const wheelEvent = event;
191
+ if (typeof wheelEvent.deltaY === "number" && wheelEvent.deltaY !== 0) {
192
+ this.wheel = wheelEvent.deltaY > 0 ? -1 : 1;
193
+ } else if (typeof wheelEvent.wheelDelta === "number" && wheelEvent.wheelDelta !== 0) {
194
+ this.wheel = wheelEvent.wheelDelta < 0 ? -1 : 1;
195
+ } else if (typeof wheelEvent.detail === "number" && wheelEvent.detail !== 0) {
196
+ this.wheel = wheelEvent.detail > 0 ? -1 : 1;
197
+ } else {
198
+ this.wheel = 0;
199
+ }
200
+ event.preventDefault();
201
+ }
202
+ };
203
+ // Annotate the CommonJS export names for ESM import in node:
204
+ 0 && (module.exports = {
205
+ MouseInput
206
+ });
207
+ //# sourceMappingURL=mouse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/devices/mouse.ts","../../src/shared/constants.ts","../../src/shared/utils.ts"],"sourcesContent":["import { OUT_OF_BOUNDS } from \"../shared/constants\";\nimport { computeRelativePosition, hasDocument } from \"../shared/utils\";\nimport type { MouseState } from \"../types\";\n\ntype MouseListener = (event: MouseEvent) => void;\ntype WheelListener = (event: WheelEvent | Event) => void;\n\nexport class MouseInput {\n\tpublic readonly state: MouseState = {\n\t\tx: OUT_OF_BOUNDS,\n\t\ty: OUT_OF_BOUNDS,\n\t\tpressed: 0,\n\t\tleft: 0,\n\t\tmiddle: 0,\n\t\tright: 0,\n\t\tpress: 0,\n\t\trelease: 0,\n\t\twheel: 0,\n\t};\n\n\tprivate previousPressed = false;\n\tprivate wheel = 0;\n\tprivate canvas?: HTMLCanvasElement;\n\tprivate removeListeners?: () => void;\n\n\tconstructor(canvas?: HTMLCanvasElement) {\n\t\tif (canvas) {\n\t\t\tthis.setCanvas(canvas);\n\t\t}\n\t}\n\n\tpublic setCanvas(canvas: HTMLCanvasElement): void {\n\t\tthis.detach();\n\t\tthis.canvas = canvas;\n\t\tthis.attach();\n\t}\n\n\tpublic syncFromTouch(x: number, y: number, touching: boolean): void {\n\t\tthis.state.x = x;\n\t\tthis.state.y = y;\n\t\tif (touching) {\n\t\t\tthis.state.left = 1;\n\t\t\tthis.state.middle = 0;\n\t\t\tthis.state.right = 0;\n\t\t\tthis.state.pressed = 1;\n\t\t} else {\n\t\t\tthis.state.left = 0;\n\t\t\tthis.state.middle = 0;\n\t\t\tthis.state.right = 0;\n\t\t\tthis.state.pressed = 0;\n\t\t}\n\t}\n\n\tpublic update(): void {\n\t\tif (this.state.pressed && !this.previousPressed) {\n\t\t\tthis.previousPressed = true;\n\t\t\tthis.state.press = 1;\n\t\t} else {\n\t\t\tthis.state.press = 0;\n\t\t}\n\n\t\tif (!this.state.pressed && this.previousPressed) {\n\t\t\tthis.previousPressed = false;\n\t\t\tthis.state.release = 1;\n\t\t} else {\n\t\t\tthis.state.release = 0;\n\t\t}\n\n\t\tthis.state.wheel = this.wheel;\n\t\tthis.wheel = 0;\n\t}\n\n\tprivate attach(): void {\n\t\tif (!hasDocument) {\n\t\t\treturn;\n\t\t}\n\t\tconst target = document;\n\t\tconst onDown: MouseListener = (event) => this.handleMouseDown(event);\n\t\tconst onMove: MouseListener = (event) => this.handleMouseMove(event);\n\t\tconst onUp: MouseListener = (event) => this.handleMouseUp(event);\n\t\tconst onWheel: WheelListener = (event) => this.handleWheel(event as WheelEvent);\n\t\tconst onDomWheel: WheelListener = (event) => this.handleWheel(event as WheelEvent);\n\n\t\ttarget.addEventListener(\"mousedown\", onDown, {\n\t\t\tpassive: false,\n\t\t});\n\t\ttarget.addEventListener(\"mousemove\", onMove, {\n\t\t\tpassive: false,\n\t\t});\n\t\ttarget.addEventListener(\"mouseup\", onUp, {\n\t\t\tpassive: false,\n\t\t});\n\t\ttarget.addEventListener(\"mousewheel\", onWheel as EventListener, {\n\t\t\tpassive: false,\n\t\t});\n\t\ttarget.addEventListener(\"DOMMouseScroll\", onDomWheel as EventListener, {\n\t\t\tpassive: false,\n\t\t});\n\n\t\tthis.removeListeners = () => {\n\t\t\ttarget.removeEventListener(\"mousedown\", onDown);\n\t\t\ttarget.removeEventListener(\"mousemove\", onMove);\n\t\t\ttarget.removeEventListener(\"mouseup\", onUp);\n\t\t\ttarget.removeEventListener(\"mousewheel\", onWheel as EventListener);\n\t\t\ttarget.removeEventListener(\"DOMMouseScroll\", onDomWheel as EventListener);\n\t\t};\n\t}\n\n\tprivate detach(): void {\n\t\tthis.removeListeners?.();\n\t\tthis.removeListeners = undefined;\n\t\tthis.canvas = undefined;\n\t}\n\n\tprivate handleMouseDown(event: MouseEvent): void {\n\t\tif (!this.canvas) return;\n\t\tevent.preventDefault();\n\t\tconst { x, y } = computeRelativePosition(this.canvas, event.clientX, event.clientY);\n\t\tthis.state.x = x;\n\t\tthis.state.y = y;\n\t\tswitch (event.button) {\n\t\t\tcase 0:\n\t\t\t\tthis.state.left = 1;\n\t\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\tthis.state.middle = 1;\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\tthis.state.right = 1;\n\t\t\t\tbreak;\n\t\t}\n\t\tthis.state.pressed = Math.min(1, this.state.left + this.state.right + this.state.middle);\n\t}\n\n\tprivate handleMouseMove(event: MouseEvent): void {\n\t\tif (!this.canvas) return;\n\t\tevent.preventDefault();\n\t\tconst { x, y } = computeRelativePosition(this.canvas, event.clientX, event.clientY);\n\t\tthis.state.x = x;\n\t\tthis.state.y = y;\n\t}\n\n\tprivate handleMouseUp(event: MouseEvent): void {\n\t\tif (!this.canvas) return;\n\t\tevent.preventDefault();\n\t\tconst { x, y } = computeRelativePosition(this.canvas, event.clientX, event.clientY);\n\t\tthis.state.x = x;\n\t\tthis.state.y = y;\n\t\tswitch (event.button) {\n\t\t\tcase 0:\n\t\t\t\tthis.state.left = 0;\n\t\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\tthis.state.middle = 0;\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\tthis.state.right = 0;\n\t\t\t\tbreak;\n\t\t}\n\t\tthis.state.pressed = Math.min(1, this.state.left + this.state.right + this.state.middle);\n\t}\n\n\tprivate handleWheel(event: WheelEvent | Event): void {\n\t\tconst wheelEvent = event as WheelEvent & {\n\t\t\twheelDelta?: number;\n\t\t\tdetail?: number;\n\t\t};\n\t\tif (typeof wheelEvent.deltaY === \"number\" && wheelEvent.deltaY !== 0) {\n\t\t\tthis.wheel = wheelEvent.deltaY > 0 ? -1 : 1;\n\t\t} else if (typeof wheelEvent.wheelDelta === \"number\" && wheelEvent.wheelDelta !== 0) {\n\t\t\tthis.wheel = wheelEvent.wheelDelta < 0 ? -1 : 1;\n\t\t} else if (typeof wheelEvent.detail === \"number\" && wheelEvent.detail !== 0) {\n\t\t\tthis.wheel = wheelEvent.detail > 0 ? -1 : 1;\n\t\t} else {\n\t\t\tthis.wheel = 0;\n\t\t}\n\t\tevent.preventDefault();\n\t}\n}\n","export const NORMALIZED_SCALE = 200;\nexport const OUT_OF_BOUNDS = -10000;\nexport const PREVENT_DEFAULT_REGEX = /Escape|(F\\d+)/;\nexport const TOUCH_MOUSE_ID = \"mouse\";\n","import { NORMALIZED_SCALE } from \"./constants\";\n\ninterface RelativePosition {\n\tx: number;\n\ty: number;\n}\n\nexport const hasDocument = typeof document !== \"undefined\";\n\nexport const computeRelativePosition = (\n\tcanvas: HTMLCanvasElement,\n\tclientX: number,\n\tclientY: number,\n): RelativePosition => {\n\tconst rect = canvas.getBoundingClientRect();\n\tconst min = Math.min(canvas.clientWidth, canvas.clientHeight) || 1;\n\tconst x = ((clientX - rect.left - canvas.clientWidth / 2) / min) * NORMALIZED_SCALE;\n\tconst y = ((canvas.clientHeight / 2 - (clientY - rect.top)) / min) * NORMALIZED_SCALE;\n\treturn {\n\t\tx,\n\t\ty,\n\t};\n};\n\nexport const addEventListener = <K extends keyof DocumentEventMap>(\n\ttarget: Document | HTMLElement,\n\ttype: K,\n\tlistener: (this: Document | HTMLElement, ev: DocumentEventMap[K]) => any,\n): void => {\n\ttarget.addEventListener(type, listener as EventListener, {\n\t\tpassive: false,\n\t});\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;ACAO,IAAMA,mBAAmB;AACzB,IAAMC,gBAAgB;;;ACMtB,IAAMC,cAAc,OAAOC,aAAa;AAExC,IAAMC,0BAA0B,wBACtCC,QACAC,SACAC,YAAAA;AAEA,QAAMC,OAAOH,OAAOI,sBAAqB;AACzC,QAAMC,MAAMC,KAAKD,IAAIL,OAAOO,aAAaP,OAAOQ,YAAY,KAAK;AACjE,QAAMC,KAAMR,UAAUE,KAAKO,OAAOV,OAAOO,cAAc,KAAKF,MAAOM;AACnE,QAAMC,KAAMZ,OAAOQ,eAAe,KAAKN,UAAUC,KAAKU,QAAQR,MAAOM;AACrE,SAAO;IACNF;IACAG;EACD;AACD,GAbuC;;;AFFhC,IAAME,aAAN,MAAMA;EAPb,OAOaA;;;EACIC,QAAoB;IACnCC,GAAGC;IACHC,GAAGD;IACHE,SAAS;IACTC,MAAM;IACNC,QAAQ;IACRC,OAAO;IACPC,OAAO;IACPC,SAAS;IACTC,OAAO;EACR;EAEQC,kBAAkB;EAClBD,QAAQ;EACRE;EACAC;EAER,YAAYD,QAA4B;AACvC,QAAIA,QAAQ;AACX,WAAKE,UAAUF,MAAAA;IAChB;EACD;EAEOE,UAAUF,QAAiC;AACjD,SAAKG,OAAM;AACX,SAAKH,SAASA;AACd,SAAKI,OAAM;EACZ;EAEOC,cAAchB,GAAWE,GAAWe,UAAyB;AACnE,SAAKlB,MAAMC,IAAIA;AACf,SAAKD,MAAMG,IAAIA;AACf,QAAIe,UAAU;AACb,WAAKlB,MAAMK,OAAO;AAClB,WAAKL,MAAMM,SAAS;AACpB,WAAKN,MAAMO,QAAQ;AACnB,WAAKP,MAAMI,UAAU;IACtB,OAAO;AACN,WAAKJ,MAAMK,OAAO;AAClB,WAAKL,MAAMM,SAAS;AACpB,WAAKN,MAAMO,QAAQ;AACnB,WAAKP,MAAMI,UAAU;IACtB;EACD;EAEOe,SAAe;AACrB,QAAI,KAAKnB,MAAMI,WAAW,CAAC,KAAKO,iBAAiB;AAChD,WAAKA,kBAAkB;AACvB,WAAKX,MAAMQ,QAAQ;IACpB,OAAO;AACN,WAAKR,MAAMQ,QAAQ;IACpB;AAEA,QAAI,CAAC,KAAKR,MAAMI,WAAW,KAAKO,iBAAiB;AAChD,WAAKA,kBAAkB;AACvB,WAAKX,MAAMS,UAAU;IACtB,OAAO;AACN,WAAKT,MAAMS,UAAU;IACtB;AAEA,SAAKT,MAAMU,QAAQ,KAAKA;AACxB,SAAKA,QAAQ;EACd;EAEQM,SAAe;AACtB,QAAI,CAACI,aAAa;AACjB;IACD;AACA,UAAMC,SAASC;AACf,UAAMC,SAAwB,wBAACC,UAAU,KAAKC,gBAAgBD,KAAAA,GAAhC;AAC9B,UAAME,SAAwB,wBAACF,UAAU,KAAKG,gBAAgBH,KAAAA,GAAhC;AAC9B,UAAMI,OAAsB,wBAACJ,UAAU,KAAKK,cAAcL,KAAAA,GAA9B;AAC5B,UAAMM,UAAyB,wBAACN,UAAU,KAAKO,YAAYP,KAAAA,GAA5B;AAC/B,UAAMQ,aAA4B,wBAACR,UAAU,KAAKO,YAAYP,KAAAA,GAA5B;AAElCH,WAAOY,iBAAiB,aAAaV,QAAQ;MAC5CW,SAAS;IACV,CAAA;AACAb,WAAOY,iBAAiB,aAAaP,QAAQ;MAC5CQ,SAAS;IACV,CAAA;AACAb,WAAOY,iBAAiB,WAAWL,MAAM;MACxCM,SAAS;IACV,CAAA;AACAb,WAAOY,iBAAiB,cAAcH,SAA0B;MAC/DI,SAAS;IACV,CAAA;AACAb,WAAOY,iBAAiB,kBAAkBD,YAA6B;MACtEE,SAAS;IACV,CAAA;AAEA,SAAKrB,kBAAkB,MAAA;AACtBQ,aAAOc,oBAAoB,aAAaZ,MAAAA;AACxCF,aAAOc,oBAAoB,aAAaT,MAAAA;AACxCL,aAAOc,oBAAoB,WAAWP,IAAAA;AACtCP,aAAOc,oBAAoB,cAAcL,OAAAA;AACzCT,aAAOc,oBAAoB,kBAAkBH,UAAAA;IAC9C;EACD;EAEQjB,SAAe;AACtB,SAAKF,kBAAe;AACpB,SAAKA,kBAAkBuB;AACvB,SAAKxB,SAASwB;EACf;EAEQX,gBAAgBD,OAAyB;AAChD,QAAI,CAAC,KAAKZ,OAAQ;AAClBY,UAAMa,eAAc;AACpB,UAAM,EAAEpC,GAAGE,EAAC,IAAKmC,wBAAwB,KAAK1B,QAAQY,MAAMe,SAASf,MAAMgB,OAAO;AAClF,SAAKxC,MAAMC,IAAIA;AACf,SAAKD,MAAMG,IAAIA;AACf,YAAQqB,MAAMiB,QAAM;MACnB,KAAK;AACJ,aAAKzC,MAAMK,OAAO;AAClB;MACD,KAAK;AACJ,aAAKL,MAAMM,SAAS;AACpB;MACD,KAAK;AACJ,aAAKN,MAAMO,QAAQ;AACnB;IACF;AACA,SAAKP,MAAMI,UAAUsC,KAAKC,IAAI,GAAG,KAAK3C,MAAMK,OAAO,KAAKL,MAAMO,QAAQ,KAAKP,MAAMM,MAAM;EACxF;EAEQqB,gBAAgBH,OAAyB;AAChD,QAAI,CAAC,KAAKZ,OAAQ;AAClBY,UAAMa,eAAc;AACpB,UAAM,EAAEpC,GAAGE,EAAC,IAAKmC,wBAAwB,KAAK1B,QAAQY,MAAMe,SAASf,MAAMgB,OAAO;AAClF,SAAKxC,MAAMC,IAAIA;AACf,SAAKD,MAAMG,IAAIA;EAChB;EAEQ0B,cAAcL,OAAyB;AAC9C,QAAI,CAAC,KAAKZ,OAAQ;AAClBY,UAAMa,eAAc;AACpB,UAAM,EAAEpC,GAAGE,EAAC,IAAKmC,wBAAwB,KAAK1B,QAAQY,MAAMe,SAASf,MAAMgB,OAAO;AAClF,SAAKxC,MAAMC,IAAIA;AACf,SAAKD,MAAMG,IAAIA;AACf,YAAQqB,MAAMiB,QAAM;MACnB,KAAK;AACJ,aAAKzC,MAAMK,OAAO;AAClB;MACD,KAAK;AACJ,aAAKL,MAAMM,SAAS;AACpB;MACD,KAAK;AACJ,aAAKN,MAAMO,QAAQ;AACnB;IACF;AACA,SAAKP,MAAMI,UAAUsC,KAAKC,IAAI,GAAG,KAAK3C,MAAMK,OAAO,KAAKL,MAAMO,QAAQ,KAAKP,MAAMM,MAAM;EACxF;EAEQyB,YAAYP,OAAiC;AACpD,UAAMoB,aAAapB;AAInB,QAAI,OAAOoB,WAAWC,WAAW,YAAYD,WAAWC,WAAW,GAAG;AACrE,WAAKnC,QAAQkC,WAAWC,SAAS,IAAI,KAAK;IAC3C,WAAW,OAAOD,WAAWE,eAAe,YAAYF,WAAWE,eAAe,GAAG;AACpF,WAAKpC,QAAQkC,WAAWE,aAAa,IAAI,KAAK;IAC/C,WAAW,OAAOF,WAAWG,WAAW,YAAYH,WAAWG,WAAW,GAAG;AAC5E,WAAKrC,QAAQkC,WAAWG,SAAS,IAAI,KAAK;IAC3C,OAAO;AACN,WAAKrC,QAAQ;IACd;AACAc,UAAMa,eAAc;EACrB;AACD;","names":["NORMALIZED_SCALE","OUT_OF_BOUNDS","hasDocument","document","computeRelativePosition","canvas","clientX","clientY","rect","getBoundingClientRect","min","Math","clientWidth","clientHeight","x","left","NORMALIZED_SCALE","y","top","MouseInput","state","x","OUT_OF_BOUNDS","y","pressed","left","middle","right","press","release","wheel","previousPressed","canvas","removeListeners","setCanvas","detach","attach","syncFromTouch","touching","update","hasDocument","target","document","onDown","event","handleMouseDown","onMove","handleMouseMove","onUp","handleMouseUp","onWheel","handleWheel","onDomWheel","addEventListener","passive","removeEventListener","undefined","preventDefault","computeRelativePosition","clientX","clientY","button","Math","min","wheelEvent","deltaY","wheelDelta","detail"]}