@omnipad/core 0.2.0-alpha.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,1439 +1 @@
1
- var __defProp = Object.defineProperty;
2
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
-
5
- // src/types/keys.ts
6
- var STANDARD_KEYS = {
7
- // --- System Controls (8-27) ---
8
- Backspace: { key: "Backspace", code: "Backspace", keyCode: 8 },
9
- Tab: { key: "Tab", code: "Tab", keyCode: 9 },
10
- Enter: { key: "Enter", code: "Enter", keyCode: 13 },
11
- ShiftLeft: { key: "Shift", code: "ShiftLeft", keyCode: 16 },
12
- ControlLeft: { key: "Control", code: "ControlLeft", keyCode: 17 },
13
- AltLeft: { key: "Alt", code: "AltLeft", keyCode: 18 },
14
- Pause: { key: "Pause", code: "Pause", keyCode: 19 },
15
- CapsLock: { key: "CapsLock", code: "CapsLock", keyCode: 20 },
16
- Escape: { key: "Escape", code: "Escape", keyCode: 27 },
17
- // --- Navigation & Editing (32-46) ---
18
- Space: { key: " ", code: "Space", keyCode: 32 },
19
- PageUp: { key: "PageUp", code: "PageUp", keyCode: 33 },
20
- PageDown: { key: "PageDown", code: "PageDown", keyCode: 34 },
21
- End: { key: "End", code: "End", keyCode: 35 },
22
- Home: { key: "Home", code: "Home", keyCode: 36 },
23
- ArrowLeft: { key: "ArrowLeft", code: "ArrowLeft", keyCode: 37 },
24
- ArrowUp: { key: "ArrowUp", code: "ArrowUp", keyCode: 38 },
25
- ArrowRight: { key: "ArrowRight", code: "ArrowRight", keyCode: 39 },
26
- ArrowDown: { key: "ArrowDown", code: "ArrowDown", keyCode: 40 },
27
- PrintScreen: { key: "PrintScreen", code: "PrintScreen", keyCode: 44 },
28
- Insert: { key: "Insert", code: "Insert", keyCode: 45 },
29
- Delete: { key: "Delete", code: "Delete", keyCode: 46 },
30
- // --- Digit Keys 0-9 (48-57) ---
31
- Digit0: { key: "0", code: "Digit0", keyCode: 48 },
32
- Digit1: { key: "1", code: "Digit1", keyCode: 49 },
33
- Digit2: { key: "2", code: "Digit2", keyCode: 50 },
34
- Digit3: { key: "3", code: "Digit3", keyCode: 51 },
35
- Digit4: { key: "4", code: "Digit4", keyCode: 52 },
36
- Digit5: { key: "5", code: "Digit5", keyCode: 53 },
37
- Digit6: { key: "6", code: "Digit6", keyCode: 54 },
38
- Digit7: { key: "7", code: "Digit7", keyCode: 55 },
39
- Digit8: { key: "8", code: "Digit8", keyCode: 56 },
40
- Digit9: { key: "9", code: "Digit9", keyCode: 57 },
41
- // --- Alpha Keys A-Z (65-90) ---
42
- KeyA: { key: "a", code: "KeyA", keyCode: 65 },
43
- KeyB: { key: "b", code: "KeyB", keyCode: 66 },
44
- KeyC: { key: "c", code: "KeyC", keyCode: 67 },
45
- KeyD: { key: "d", code: "KeyD", keyCode: 68 },
46
- KeyE: { key: "e", code: "KeyE", keyCode: 69 },
47
- KeyF: { key: "f", code: "KeyF", keyCode: 70 },
48
- KeyG: { key: "g", code: "KeyG", keyCode: 71 },
49
- KeyH: { key: "h", code: "KeyH", keyCode: 72 },
50
- KeyI: { key: "i", code: "KeyI", keyCode: 73 },
51
- KeyJ: { key: "j", code: "KeyJ", keyCode: 74 },
52
- KeyK: { key: "k", code: "KeyK", keyCode: 75 },
53
- KeyL: { key: "l", code: "KeyL", keyCode: 76 },
54
- KeyM: { key: "m", code: "KeyM", keyCode: 77 },
55
- KeyN: { key: "n", code: "KeyN", keyCode: 78 },
56
- KeyO: { key: "o", code: "KeyO", keyCode: 79 },
57
- KeyP: { key: "p", code: "KeyP", keyCode: 80 },
58
- KeyQ: { key: "q", code: "KeyQ", keyCode: 81 },
59
- KeyR: { key: "r", code: "KeyR", keyCode: 82 },
60
- KeyS: { key: "s", code: "KeyS", keyCode: 83 },
61
- KeyT: { key: "t", code: "KeyT", keyCode: 84 },
62
- KeyU: { key: "u", code: "KeyU", keyCode: 85 },
63
- KeyV: { key: "v", code: "KeyV", keyCode: 86 },
64
- KeyW: { key: "w", code: "KeyW", keyCode: 87 },
65
- KeyX: { key: "x", code: "KeyX", keyCode: 88 },
66
- KeyY: { key: "y", code: "KeyY", keyCode: 89 },
67
- KeyZ: { key: "z", code: "KeyZ", keyCode: 90 },
68
- // --- Meta & Menu (91-93) ---
69
- MetaLeft: { key: "Meta", code: "MetaLeft", keyCode: 91 },
70
- ContextMenu: { key: "ContextMenu", code: "ContextMenu", keyCode: 93 },
71
- // --- Numpad Digits (96-105) ---
72
- Numpad0: { key: "0", code: "Numpad0", keyCode: 96 },
73
- Numpad1: { key: "1", code: "Numpad1", keyCode: 97 },
74
- Numpad2: { key: "2", code: "Numpad2", keyCode: 98 },
75
- Numpad3: { key: "3", code: "Numpad3", keyCode: 99 },
76
- Numpad4: { key: "4", code: "Numpad4", keyCode: 100 },
77
- Numpad5: { key: "5", code: "Numpad5", keyCode: 101 },
78
- Numpad6: { key: "6", code: "Numpad6", keyCode: 102 },
79
- Numpad7: { key: "7", code: "Numpad7", keyCode: 103 },
80
- Numpad8: { key: "8", code: "Numpad8", keyCode: 104 },
81
- Numpad9: { key: "9", code: "Numpad9", keyCode: 105 },
82
- // --- Numpad Symbols (106-111) ---
83
- NumpadMultiply: { key: "*", code: "NumpadMultiply", keyCode: 106 },
84
- NumpadAdd: { key: "+", code: "NumpadAdd", keyCode: 107 },
85
- NumpadSubtract: { key: "-", code: "NumpadSubtract", keyCode: 109 },
86
- NumpadDecimal: { key: ".", code: "NumpadDecimal", keyCode: 110 },
87
- NumpadDivide: { key: "/", code: "NumpadDivide", keyCode: 111 },
88
- // --- Function Keys (112-123) ---
89
- F1: { key: "F1", code: "F1", keyCode: 112 },
90
- F2: { key: "F2", code: "F2", keyCode: 113 },
91
- F3: { key: "F3", code: "F3", keyCode: 114 },
92
- F4: { key: "F4", code: "F4", keyCode: 115 },
93
- F5: { key: "F5", code: "F5", keyCode: 116 },
94
- F6: { key: "F6", code: "F6", keyCode: 117 },
95
- F7: { key: "F7", code: "F7", keyCode: 118 },
96
- F8: { key: "F8", code: "F8", keyCode: 119 },
97
- F9: { key: "F9", code: "F9", keyCode: 120 },
98
- F10: { key: "F10", code: "F10", keyCode: 121 },
99
- F11: { key: "F11", code: "F11", keyCode: 122 },
100
- F12: { key: "F12", code: "F12", keyCode: 123 },
101
- // --- State Locks (144-145) ---
102
- NumLock: { key: "NumLock", code: "NumLock", keyCode: 144 },
103
- ScrollLock: { key: "ScrollLock", code: "ScrollLock", keyCode: 145 },
104
- // --- Punctuation (186-222) ---
105
- Semicolon: { key: ";", code: "Semicolon", keyCode: 186 },
106
- Equal: { key: "=", code: "Equal", keyCode: 187 },
107
- Comma: { key: ",", code: "Comma", keyCode: 188 },
108
- Minus: { key: "-", code: "Minus", keyCode: 189 },
109
- Period: { key: ".", code: "Period", keyCode: 190 },
110
- Slash: { key: "/", code: "Slash", keyCode: 191 },
111
- Backquote: { key: "`", code: "Backquote", keyCode: 192 },
112
- BracketLeft: { key: "[", code: "BracketLeft", keyCode: 219 },
113
- Backslash: { key: "\\", code: "Backslash", keyCode: 220 },
114
- BracketRight: { key: "]", code: "BracketRight", keyCode: 221 },
115
- Quote: { key: "'", code: "Quote", keyCode: 222 }
116
- };
117
- var KEYS = STANDARD_KEYS;
118
-
119
- // src/types/index.ts
120
- var CMP_TYPES = {
121
- // --- Zones ---
122
- /** Area responsible for capturing touches and spawning dynamic widgets */
123
- INPUT_ZONE: "input-zone",
124
- /** Area responsible for receiving signals and simulating DOM events */
125
- TARGET_ZONE: "target-zone",
126
- // --- Widgets ---
127
- /** Simulates a physical keyboard key press */
128
- KEYBOARD_BUTTON: "keyboard-button",
129
- /** Simulates a mouse button click/hold */
130
- MOUSE_BUTTON: "mouse-button",
131
- /** A joystick that outputs 360-degree or locked direction vectors */
132
- ANALOG_STICK: "analog-stick",
133
- /** Classic 4/8-way directional pad */
134
- D_PAD: "d-pad",
135
- /** Trackpad-style relative movement area */
136
- TRACKPAD: "trackpad",
137
- // --- Virtual Helpers ---
138
- /** Logic for the on-screen visual cursor */
139
- VIRTUAL_CURSOR: "virtual-cursor",
140
- /** The top-level managed container */
141
- ROOT_LAYER: "root-layer"
142
- };
143
- var ACTION_TYPES = {
144
- KEYDOWN: "keydown",
145
- KEYUP: "keyup",
146
- POINTER: "pointer",
147
- POINTERMOVE: "pointermove",
148
- POINTERDOWN: "pointerdown",
149
- POINTERUP: "pointerup",
150
- MOUSE: "mouse",
151
- MOUSEMOVE: "mousemove",
152
- MOUSEDOWN: "mousedown",
153
- MOUSEUP: "mouseup",
154
- CLICK: "click"
155
- };
156
- var CONTEXT = {
157
- /** The key used to propagate Parent IDs through the component tree */
158
- PARENT_ID_KEY: "omnipad-parent-id-link"
159
- };
160
-
161
- // src/utils/math.ts
162
- var subVec = (v1, v2) => {
163
- return { x: v1.x - v2.x, y: v1.y - v2.y };
164
- };
165
- var addVec = (v1, v2) => {
166
- return { x: v1.x + v2.x, y: v1.y + v2.y };
167
- };
168
- var scaleVec = (v, s) => {
169
- return { x: v.x * s, y: v.y * s };
170
- };
171
- var clamp = (val, min, max) => {
172
- return Math.max(min, Math.min(max, val));
173
- };
174
- var lerp = (start, end, t) => {
175
- return start + (end - start) * t;
176
- };
177
- var roundTo = (val, precision = 2) => {
178
- const m = Math.pow(10, precision);
179
- return Math.round(val * m) / m;
180
- };
181
- var getDistance = (p1, p2) => {
182
- return Math.hypot(p2.x - p1.x, p2.y - p1.y);
183
- };
184
- var getAngle = (p1, p2) => {
185
- return Math.atan2(p2.y - p1.y, p2.x - p1.x);
186
- };
187
- var radToDeg = (rad) => {
188
- return rad * 180 / Math.PI;
189
- };
190
- var degToRad = (deg) => {
191
- return deg * Math.PI / 180;
192
- };
193
- var clampVector = (origin, target, radius) => {
194
- const dx = target.x - origin.x;
195
- const dy = target.y - origin.y;
196
- const dist = Math.hypot(dx, dy);
197
- if (dist <= radius) return target;
198
- const angle = Math.atan2(dy, dx);
199
- return {
200
- x: origin.x + Math.cos(angle) * radius,
201
- y: origin.y + Math.sin(angle) * radius
202
- };
203
- };
204
- var lockTo8Directions = (rad) => {
205
- const step = Math.PI / 4;
206
- return Math.round(rad / step) * step;
207
- };
208
- var lockTo4Directions = (rad) => {
209
- const step = Math.PI / 2;
210
- return Math.round(rad / step) * step;
211
- };
212
- var percentToPx = (percent, totalPx) => {
213
- return roundTo(percent * totalPx / 100);
214
- };
215
- var pxToPercent = (px, totalPx) => {
216
- if (totalPx === 0) return 0;
217
- return roundTo(px * 100 / totalPx);
218
- };
219
- var normalizeVec = (v) => {
220
- const magnitude = Math.hypot(v.x, v.y);
221
- return magnitude === 0 ? { x: 0, y: 0 } : { x: v.x / magnitude, y: v.y / magnitude };
222
- };
223
- var radToVec = (rad) => ({
224
- x: Math.cos(rad),
225
- y: Math.sin(rad)
226
- });
227
- var remap = (val, inMin, inMax, outMin, outMax) => {
228
- const t = (val - inMin) / (inMax - inMin);
229
- return lerp(outMin, outMax, clamp(t, 0, 1));
230
- };
231
- var isVec2Equal = (v1, v2, epsilon = 1e-4) => {
232
- return Math.abs(v1.x - v2.x) < epsilon && Math.abs(v1.y - v2.y) < epsilon;
233
- };
234
- var getDeadzoneScalar = (magnitude, threshold, max) => {
235
- if (magnitude < threshold) return 0;
236
- const scalar = (magnitude - threshold) / (max - threshold);
237
- return clamp(scalar, 0, 1);
238
- };
239
- var applyRadialDeadzone = (v, radius, deadzonePercent) => {
240
- const magnitude = Math.hypot(v.x, v.y);
241
- const threshold = radius * deadzonePercent;
242
- const scalar = getDeadzoneScalar(magnitude, threshold, radius);
243
- if (scalar === 0) return { x: 0, y: 0 };
244
- const direction = { x: v.x / magnitude, y: v.y / magnitude };
245
- return scaleVec(direction, scalar);
246
- };
247
- var applyAxialDeadzone = (v, threshold, max) => {
248
- return {
249
- x: getDeadzoneScalar(Math.abs(v.x), threshold, max) * Math.sign(v.x),
250
- y: getDeadzoneScalar(Math.abs(v.y), threshold, max) * Math.sign(v.y)
251
- };
252
- };
253
-
254
- // src/utils/dom.ts
255
- var getDeepElement = (x, y, ignoreClass = "omnipad-target-zone") => {
256
- const elements = document.elementsFromPoint(x, y);
257
- let target = elements.find((el) => !el.classList.contains(ignoreClass));
258
- if (!target) return null;
259
- while (target && target.shadowRoot) {
260
- const nestedElements = target.shadowRoot.elementsFromPoint(x, y);
261
- const nestedTarget = nestedElements.find((el) => !el.classList.contains(ignoreClass));
262
- if (!nestedTarget || nestedTarget === target) break;
263
- target = nestedTarget;
264
- }
265
- return target;
266
- };
267
- var getDeepActiveElement = () => {
268
- let el = document.activeElement;
269
- while (el && el.shadowRoot && el.shadowRoot.activeElement) {
270
- el = el.shadowRoot.activeElement;
271
- }
272
- return el;
273
- };
274
- var focusElement = (el) => {
275
- if (getDeepActiveElement() === el) return;
276
- if (!el.hasAttribute("tabindex")) {
277
- el.setAttribute("tabindex", "-1");
278
- }
279
- el.focus();
280
- };
281
- var dispatchKeyboardEvent = (type, payload) => {
282
- const ev = new KeyboardEvent(type, {
283
- ...payload,
284
- which: payload.keyCode,
285
- // Support for legacy Flash engines
286
- bubbles: true,
287
- cancelable: true,
288
- view: window
289
- });
290
- window.dispatchEvent(ev);
291
- };
292
- var dispatchPointerEventAtPos = (type, x, y, opts = {}) => {
293
- const target = getDeepElement(x, y);
294
- if (!target) return;
295
- const commonProps = {
296
- bubbles: true,
297
- cancelable: true,
298
- composed: true,
299
- // Crucial for piercing Shadow DOM boundaries
300
- clientX: x,
301
- clientY: y,
302
- view: window,
303
- ...opts
304
- };
305
- if (type.startsWith("pointer")) {
306
- target.dispatchEvent(
307
- new PointerEvent(type, {
308
- isPrimary: true,
309
- pointerId: 9999,
310
- pointerType: "mouse",
311
- // Emulate mouse behavior for Flash MouseOver/Down logic
312
- ...commonProps
313
- })
314
- );
315
- const mouseType = type.replace("pointer", "mouse");
316
- target.dispatchEvent(new MouseEvent(mouseType, commonProps));
317
- } else {
318
- target.dispatchEvent(new MouseEvent(type, commonProps));
319
- }
320
- };
321
- var getAnchorPosition = (rect, anchor) => {
322
- const { left: l, top: t, width: w, height: h } = rect;
323
- const map = {
324
- "top-left": { x: l, y: t },
325
- "top-center": { x: l + w / 2, y: t },
326
- "top-right": { x: l + w, y: t },
327
- "center-left": { x: l, y: t + h / 2 },
328
- center: { x: l + w / 2, y: t + h / 2 },
329
- "center-right": { x: l + w, y: t + h / 2 },
330
- "bottom-left": { x: l, y: t + h },
331
- "bottom-center": { x: l + w / 2, y: t + h },
332
- "bottom-right": { x: l + w, y: t + h }
333
- };
334
- return map[anchor] || map["center"];
335
- };
336
-
337
- // src/utils/id.ts
338
- var generateUID = (prefix = "omnipad") => {
339
- const stamp = Date.now().toString(36);
340
- const random = Math.random().toString(36).substring(2, 6);
341
- return `${prefix}-${stamp}-${random}`;
342
- };
343
- function isGlobalID(id) {
344
- return id.startsWith("$");
345
- }
346
-
347
- // src/utils/layout.ts
348
- var resolveLayoutStyle = (layout) => {
349
- if (!layout) return {};
350
- const style = {};
351
- style.position = "absolute";
352
- const fields = ["left", "top", "right", "bottom", "width", "height"];
353
- fields.forEach((field) => {
354
- const val = layout[field];
355
- if (val !== void 0) {
356
- style[field] = typeof val === "number" ? `${val}px` : val;
357
- }
358
- });
359
- if (layout.zIndex !== void 0) style.zIndex = layout.zIndex;
360
- const anchorMap = {
361
- "top-left": "translate(0, 0)",
362
- "top-center": "translate(-50%, 0)",
363
- "top-right": "translate(-100%, 0)",
364
- "center-left": "translate(0, -50%)",
365
- center: "translate(-50%, -50%)",
366
- "center-right": "translate(-100%, -50%)",
367
- "bottom-left": "translate(0, -100%)",
368
- "bottom-center": "translate(-50%, -100%)",
369
- "bottom-right": "translate(-100%, -100%)"
370
- };
371
- if (layout.anchor) {
372
- style.transform = anchorMap[layout.anchor];
373
- }
374
- return style;
375
- };
376
-
377
- // src/registry/index.ts
378
- var GLOBAL_REGISTRY_KEY = /* @__PURE__ */ Symbol.for("omnipad.registry.instance");
379
- var Registry = class _Registry {
380
- /**
381
- * Private constructor to enforce singleton pattern.
382
- */
383
- constructor() {
384
- /** Internal storage: Mapping of Entity UID to Entity Instance */
385
- __publicField(this, "entities", /* @__PURE__ */ new Map());
386
- if (import.meta.env?.DEV) {
387
- console.log("[OmniPad-Core] Registry initialized.");
388
- }
389
- }
390
- /**
391
- * Retrieves the global instance of the Registry.
392
- * Uses globalThis to ensure the instance is unique even if the library is loaded multiple times.
393
- */
394
- static getInstance() {
395
- const globalObj = globalThis;
396
- if (!globalObj[GLOBAL_REGISTRY_KEY]) {
397
- globalObj[GLOBAL_REGISTRY_KEY] = new _Registry();
398
- }
399
- return globalObj[GLOBAL_REGISTRY_KEY];
400
- }
401
- register(entity) {
402
- if (!entity.uid) {
403
- console.warn("[OmniPad-Core] Registry: Attempted to register entity without UID.", entity);
404
- return;
405
- }
406
- if (this.entities.has(entity.uid)) {
407
- }
408
- this.entities.set(entity.uid, entity);
409
- }
410
- unregister(uid) {
411
- if (this.entities.has(uid)) {
412
- this.entities.delete(uid);
413
- }
414
- }
415
- getEntity(uid) {
416
- return this.entities.get(uid);
417
- }
418
- getAllEntities() {
419
- return Array.from(this.entities.values());
420
- }
421
- getEntitiesByRoot(rootUid) {
422
- const all = this.getAllEntities();
423
- if (!rootUid) return all;
424
- const rootEntity = this.entities.get(rootUid);
425
- if (!rootEntity) {
426
- console.warn(`[OmniPad-Core] Registry: Root entity ${rootUid} not found.`);
427
- return [];
428
- }
429
- const parentMap = /* @__PURE__ */ new Map();
430
- all.forEach((entity) => {
431
- const e = entity;
432
- if (typeof e.getConfig === "function") {
433
- const config = e.getConfig();
434
- if (config.parentId) {
435
- if (!parentMap.has(config.parentId)) {
436
- parentMap.set(config.parentId, []);
437
- }
438
- parentMap.get(config.parentId).push(entity);
439
- }
440
- }
441
- });
442
- const result = [];
443
- const queue = [rootUid];
444
- const visited = /* @__PURE__ */ new Set();
445
- while (queue.length > 0) {
446
- const currentId = queue.shift();
447
- if (visited.has(currentId)) continue;
448
- visited.add(currentId);
449
- const entity = this.entities.get(currentId);
450
- if (entity) {
451
- result.push(entity);
452
- const children = parentMap.get(currentId);
453
- if (children) {
454
- children.forEach((child) => queue.push(child.uid));
455
- }
456
- }
457
- }
458
- return result;
459
- }
460
- destroyByRoot(rootUid) {
461
- const entities = this.getEntitiesByRoot(rootUid);
462
- for (let i = entities.length - 1; i >= 0; i--) {
463
- const entity = entities[i];
464
- try {
465
- entity.destroy();
466
- } catch (error) {
467
- console.error(`[OmniPad-Core] Error during destroyByRoot at ${entity.uid}:`, error);
468
- }
469
- }
470
- }
471
- clear() {
472
- this.entities.clear();
473
- }
474
- resetAll() {
475
- this.entities.forEach((entity) => {
476
- if ("reset" in entity) {
477
- entity.reset();
478
- }
479
- });
480
- }
481
- debugGetSnapshot() {
482
- return new Map(this.entities);
483
- }
484
- };
485
-
486
- // src/utils/profile.ts
487
- function parseProfileJson(raw) {
488
- if (!raw || typeof raw !== "object") {
489
- throw new Error("[OmniPad-Validation] Profile must be a valid JSON object.");
490
- }
491
- if (!raw.rootId) {
492
- throw new Error('[OmniPad-Validation] Missing "rootId" in profile.');
493
- }
494
- if (!Array.isArray(raw.items)) {
495
- throw new Error('[OmniPad-Validation] "items" must be an array.');
496
- }
497
- const meta = {
498
- name: raw.meta?.name || "Untitled Profile",
499
- version: raw.meta?.version || "1.0.0",
500
- author: raw.meta?.author || "Unknown"
501
- };
502
- const items = raw.items.map((item, index) => {
503
- if (!item.id || !item.type) {
504
- throw new Error(`[OmniPad-Validation] Item at index ${index} is missing "id" or "type".`);
505
- }
506
- return {
507
- id: String(item.id),
508
- type: String(item.type),
509
- parentId: item.parentId ? String(item.parentId) : void 0,
510
- // 确保 config 存在,业务参数平铺于此
511
- config: item.config || {}
512
- };
513
- });
514
- return {
515
- meta,
516
- rootId: String(raw.rootId),
517
- items
518
- };
519
- }
520
- function parseProfileTree(profile) {
521
- const { items, rootId } = profile;
522
- const cidToUidMap = /* @__PURE__ */ new Map();
523
- const getUid = (cid, type = "node") => {
524
- if (isGlobalID(cid)) return cid;
525
- if (!cidToUidMap.has(cid)) {
526
- cidToUidMap.set(cid, generateUID(type));
527
- }
528
- return cidToUidMap.get(cid);
529
- };
530
- items.forEach((item) => getUid(item.id, item.type));
531
- const childrenMap = /* @__PURE__ */ new Map();
532
- items.forEach((item) => {
533
- if (item.parentId) {
534
- if (!childrenMap.has(item.parentId)) {
535
- childrenMap.set(item.parentId, []);
536
- }
537
- childrenMap.get(item.parentId).push(item);
538
- }
539
- });
540
- const buildNode = (item) => {
541
- const runtimeConfig = { ...item.config };
542
- if (runtimeConfig?.targetStageId) {
543
- runtimeConfig.targetStageId = getUid(runtimeConfig.targetStageId);
544
- }
545
- if (runtimeConfig?.dynamicWidgetId) {
546
- runtimeConfig.dynamicWidgetId = getUid(runtimeConfig.dynamicWidgetId);
547
- }
548
- const rawChildren = childrenMap.get(item.id) || [];
549
- const children = rawChildren.map((child) => buildNode(child));
550
- return {
551
- uid: getUid(item.id),
552
- type: item.type,
553
- config: runtimeConfig,
554
- children
555
- };
556
- };
557
- const rootItem = items.find((i) => i.id === rootId);
558
- if (!rootItem) {
559
- throw new Error(`[OmniPad-Core] Root item with ID "${rootId}" not found in profile.`);
560
- }
561
- return buildNode(rootItem);
562
- }
563
- function exportProfile(meta, rootUid) {
564
- const registry = Registry.getInstance();
565
- const allEntities = registry.getEntitiesByRoot(rootUid);
566
- const eidToCidMap = /* @__PURE__ */ new Map();
567
- let cidCounter = 0;
568
- const getNewCid = (eid) => {
569
- if (isGlobalID(eid)) return eid;
570
- if (!eidToCidMap.has(eid)) {
571
- eidToCidMap.set(eid, `node_${++cidCounter}`);
572
- }
573
- return eidToCidMap.get(eid);
574
- };
575
- const items = allEntities.map((entity) => {
576
- const config = entity.getConfig();
577
- const currentEid = entity.uid;
578
- const processedConfig = { ...config };
579
- if (processedConfig.targetStageId) {
580
- processedConfig.targetStageId = getNewCid(processedConfig.targetStageId);
581
- }
582
- if (processedConfig.dynamicWidgetId) {
583
- processedConfig.dynamicWidgetId = getNewCid(processedConfig.dynamicWidgetId);
584
- }
585
- const { id, type, parentId, ...cleanConfig } = processedConfig;
586
- return {
587
- id: getNewCid(currentEid),
588
- type: entity.type,
589
- // 如果存在父级,将其 UID 转换回本次导出的新 CID
590
- parentId: config.parentId ? getNewCid(config.parentId) : void 0,
591
- config: cleanConfig
592
- };
593
- });
594
- return {
595
- meta,
596
- rootId: getNewCid(rootUid),
597
- items
598
- };
599
- }
600
-
601
- // src/utils/emitter.ts
602
- var SimpleEmitter = class {
603
- constructor() {
604
- __publicField(this, "listeners", /* @__PURE__ */ new Set());
605
- }
606
- /**
607
- * Registers a callback function to be executed whenever data is emitted.
608
- *
609
- * @param fn - The callback function.
610
- * @returns A function that, when called, unsubscribes the listener.
611
- */
612
- subscribe(fn) {
613
- this.listeners.add(fn);
614
- return () => this.listeners.delete(fn);
615
- }
616
- /**
617
- * Broadcasts the provided data to all registered listeners.
618
- * Each listener is executed within a try-catch block to ensure that
619
- * an error in one subscriber doesn't prevent others from receiving the signal.
620
- *
621
- * @param data - The payload to be sent to all subscribers.
622
- */
623
- emit(data) {
624
- this.listeners.forEach((fn) => {
625
- try {
626
- fn(data);
627
- } catch (error) {
628
- console.error("[OmniPad-Core] Emitter callback error:", error);
629
- }
630
- });
631
- }
632
- /**
633
- * Removes all listeners and clears the subscription set.
634
- * Essential for preventing memory leaks when an Entity is destroyed.
635
- */
636
- clear() {
637
- this.listeners.clear();
638
- }
639
- };
640
-
641
- // src/utils/performance.ts
642
- function createRafThrottler(callback) {
643
- let ticking = false;
644
- let latestPayload = null;
645
- return function(payload) {
646
- latestPayload = payload;
647
- if (!ticking) {
648
- ticking = true;
649
- window.requestAnimationFrame(() => {
650
- if (latestPayload !== null) {
651
- callback(latestPayload);
652
- }
653
- ticking = false;
654
- });
655
- }
656
- };
657
- }
658
-
659
- // src/imputManager/index.ts
660
- var INPUT_MANAGER_KEY = /* @__PURE__ */ Symbol.for("omnipad.input_manager.instance");
661
- var InputManager = class _InputManager {
662
- constructor() {
663
- /** Internal flag to prevent multiple event registrations */
664
- __publicField(this, "_isListening", false);
665
- /** A throttled version of the reset logic */
666
- __publicField(this, "throttledReset");
667
- /**
668
- * Manually triggers a system-wide input reset via Registry.
669
- */
670
- __publicField(this, "handleGlobalReset", () => {
671
- if (import.meta.env?.DEV) {
672
- console.debug("[OmniPad-Core] Safety reset triggered by environment change.");
673
- }
674
- Registry.getInstance().resetAll();
675
- });
676
- __publicField(this, "handleResizeReset", () => {
677
- this.throttledReset(null);
678
- });
679
- __publicField(this, "handleBlurReset", () => {
680
- this.handleGlobalReset();
681
- });
682
- __publicField(this, "handleVisibilityChangeReset", () => {
683
- if (document.visibilityState === "hidden") {
684
- this.handleGlobalReset();
685
- }
686
- });
687
- this.throttledReset = createRafThrottler(() => {
688
- this.handleGlobalReset();
689
- });
690
- }
691
- /**
692
- * Retrieves the global instance of the InputManager.
693
- * Ensures uniqueness across multiple bundles or modules.
694
- */
695
- static getInstance() {
696
- const globalObj = globalThis;
697
- if (!globalObj[INPUT_MANAGER_KEY]) {
698
- globalObj[INPUT_MANAGER_KEY] = new _InputManager();
699
- }
700
- return globalObj[INPUT_MANAGER_KEY];
701
- }
702
- /**
703
- * Initializes global safety listeners.
704
- * Should be called once at the root component lifecycle (e.g., VirtualLayer).
705
- */
706
- init() {
707
- if (this._isListening) return;
708
- window.addEventListener("resize", this.handleResizeReset);
709
- window.addEventListener("blur", this.handleBlurReset);
710
- document.addEventListener("visibilitychange", this.handleVisibilityChangeReset);
711
- this._isListening = true;
712
- if (import.meta.env?.DEV) {
713
- console.log("[OmniPad-Core] Global InputManager monitoring started.");
714
- }
715
- }
716
- /**
717
- * Toggle full-screen state of the page.
718
- * @param element Target HTMLElement
719
- */
720
- async toggleFullscreen(element) {
721
- const target = element || document.documentElement;
722
- try {
723
- if (!document.fullscreenElement) {
724
- Registry.getInstance().resetAll();
725
- await target.requestFullscreen();
726
- } else {
727
- Registry.getInstance().resetAll();
728
- await document.exitFullscreen();
729
- }
730
- } catch (err) {
731
- console.error(`[OmniPad-Core] Fullscreen toggle failed:`, err);
732
- }
733
- }
734
- /**
735
- * Full-screen status query provided to the UI layer.
736
- */
737
- isFullscreen() {
738
- return !!document.fullscreenElement;
739
- }
740
- /**
741
- * Detaches all global listeners.
742
- */
743
- destroy() {
744
- window.removeEventListener("resize", this.handleResizeReset);
745
- window.removeEventListener("blur", this.handleBlurReset);
746
- window.removeEventListener("visibilitychange", this.handleVisibilityChangeReset);
747
- this._isListening = false;
748
- }
749
- };
750
-
751
- // src/entities/BaseEntity.ts
752
- var BaseEntity = class {
753
- constructor(uid, type, initialConfig, initialState) {
754
- __publicField(this, "uid");
755
- __publicField(this, "type");
756
- __publicField(this, "config");
757
- __publicField(this, "state");
758
- __publicField(this, "rectProvider", null);
759
- // 内部状态发射器,负责处理状态订阅逻辑 / Internal emitter for state subscription logic
760
- __publicField(this, "stateEmitter", new SimpleEmitter());
761
- this.uid = uid;
762
- this.type = type;
763
- this.config = initialConfig;
764
- this.state = initialState;
765
- }
766
- // --- IObservable Implementation ---
767
- subscribe(cb) {
768
- cb(this.state);
769
- return this.stateEmitter.subscribe(cb);
770
- }
771
- // --- State Management ---
772
- /**
773
- * Updates the internal state and notifies all subscribers.
774
- *
775
- * @param partialState - Partial object containing updated state values.
776
- */
777
- setState(partialState) {
778
- this.state = { ...this.state, ...partialState };
779
- this.stateEmitter.emit(this.state);
780
- }
781
- // --- Lifecycle ---
782
- destroy() {
783
- this.reset();
784
- this.stateEmitter.clear();
785
- Registry.getInstance().unregister(this.uid);
786
- }
787
- bindRectProvider(provider) {
788
- this.rectProvider = provider;
789
- }
790
- /**
791
- * Called when triggering interactions, this subclass fetches the latest boundaries in real time.
792
- */
793
- getRect() {
794
- return this.rectProvider ? this.rectProvider() : null;
795
- }
796
- updateConfig(newConfig) {
797
- this.config = { ...this.config, ...newConfig };
798
- this.stateEmitter.emit(this.state);
799
- }
800
- getState() {
801
- return this.state;
802
- }
803
- getConfig() {
804
- return this.config;
805
- }
806
- };
807
-
808
- // src/entities/InputZoneCore.ts
809
- var INITIAL_STATE = {
810
- isDynamicActive: false,
811
- dynamicPointerId: null,
812
- dynamicPosition: { x: 0, y: 0 }
813
- };
814
- var InputZoneCore = class extends BaseEntity {
815
- constructor(uid, config) {
816
- super(uid, CMP_TYPES.INPUT_ZONE, config, INITIAL_STATE);
817
- }
818
- onPointerDown(e) {
819
- if (this.state.isDynamicActive) return;
820
- if (e.target !== e.currentTarget) return;
821
- if (e.cancelable) e.preventDefault();
822
- e.stopPropagation();
823
- const pos = this.calculateRelativePosition(e.clientX, e.clientY);
824
- this.setState({
825
- isDynamicActive: true,
826
- dynamicPointerId: e.pointerId,
827
- dynamicPosition: pos
828
- });
829
- }
830
- onPointerMove(e) {
831
- if (!this.state.isDynamicActive || e.pointerId !== this.state.dynamicPointerId) return;
832
- }
833
- onPointerUp(e) {
834
- if (e.cancelable) e.preventDefault();
835
- this.handleRelease(e);
836
- }
837
- onPointerCancel(e) {
838
- this.handleRelease(e);
839
- }
840
- /**
841
- * Internal helper to handle pointer release and cleanup.
842
- */
843
- handleRelease(e) {
844
- if (e.pointerId === this.state.dynamicPointerId) {
845
- try {
846
- e.currentTarget.releasePointerCapture(e.pointerId);
847
- } catch (err) {
848
- }
849
- this.setState({
850
- isDynamicActive: false,
851
- dynamicPointerId: null
852
- });
853
- }
854
- }
855
- // --- Helper Calculations ---
856
- /**
857
- * Converts viewport pixels to percentage coordinates relative to the zone.
858
- */
859
- calculateRelativePosition(clientX, clientY) {
860
- const rect = this.getRect();
861
- if (!rect) return { x: 0, y: 0 };
862
- return {
863
- x: pxToPercent(clientX - rect.left, rect.width),
864
- y: pxToPercent(clientY - rect.top, rect.height)
865
- };
866
- }
867
- /**
868
- * Whether the interceptor layer should be enabled.
869
- */
870
- get isInterceptorRequired() {
871
- return !!(this.config.dynamicWidgetId || this.config.preventFocusLoss);
872
- }
873
- reset() {
874
- this.setState({
875
- isDynamicActive: false,
876
- dynamicPointerId: null
877
- });
878
- }
879
- };
880
-
881
- // src/entities/KeyboardButtonCore.ts
882
- var INITIAL_STATE2 = {
883
- isActive: false,
884
- isPressed: false,
885
- pointerId: null,
886
- value: 0
887
- };
888
- var KeyboardButtonCore = class extends BaseEntity {
889
- /**
890
- * Creates an instance of KeyboardButtonCore.
891
- *
892
- * @param uid - The unique entity ID.
893
- * @param config - The flat configuration object for the button.
894
- */
895
- constructor(uid, config) {
896
- super(uid, CMP_TYPES.KEYBOARD_BUTTON, config, INITIAL_STATE2);
897
- }
898
- // --- IPointerHandler Implementation ---
899
- onPointerDown(e) {
900
- if (e.cancelable) e.preventDefault();
901
- e.stopPropagation();
902
- e.target.setPointerCapture(e.pointerId);
903
- this.setState({
904
- isActive: true,
905
- isPressed: true,
906
- pointerId: e.pointerId
907
- });
908
- this.sendInputSignal(ACTION_TYPES.KEYDOWN);
909
- }
910
- onPointerUp(e) {
911
- if (e.cancelable) e.preventDefault();
912
- this.handleRelease(e);
913
- }
914
- onPointerCancel(e) {
915
- this.handleRelease(e);
916
- }
917
- onPointerMove(e) {
918
- if (e.cancelable) e.preventDefault();
919
- }
920
- // --- Internal Logic ---
921
- /**
922
- * Common logic for releasing the button state.
923
- *
924
- * @param e - The pointer event that triggered the release.
925
- */
926
- handleRelease(e) {
927
- if (this.state.pointerId !== e.pointerId) return;
928
- if (e.target.hasPointerCapture(e.pointerId)) {
929
- e.target.releasePointerCapture(e.pointerId);
930
- }
931
- this.setState(INITIAL_STATE2);
932
- this.sendInputSignal(ACTION_TYPES.KEYUP);
933
- }
934
- /**
935
- * Dispatches input signals to the registered target stage.
936
- *
937
- * @param type - The action type (keydown or keyup).
938
- */
939
- sendInputSignal(type) {
940
- const targetId = this.config.targetStageId;
941
- if (!targetId) return;
942
- const target = Registry.getInstance().getEntity(targetId);
943
- if (target && typeof target.handleSignal === "function") {
944
- const signal = {
945
- targetStageId: targetId,
946
- type,
947
- payload: {
948
- key: this.config.mapping.key,
949
- code: this.config.mapping.code,
950
- keyCode: this.config.mapping.keyCode
951
- }
952
- };
953
- target.handleSignal(signal);
954
- } else {
955
- if (import.meta.env?.DEV) {
956
- console.warn(`[OmniPad-Core] KeyboardButton ${this.uid} target not found: ${targetId}`);
957
- }
958
- }
959
- }
960
- // --- IResettable Implementation ---
961
- reset() {
962
- if (this.state.isPressed) {
963
- this.sendInputSignal(ACTION_TYPES.KEYUP);
964
- }
965
- this.setState(INITIAL_STATE2);
966
- }
967
- };
968
-
969
- // src/entities/MouseButtonCore.ts
970
- var INITIAL_STATE3 = {
971
- isActive: false,
972
- isPressed: false,
973
- pointerId: null,
974
- value: 0
975
- };
976
- var MouseButtonCore = class extends BaseEntity {
977
- constructor(uid, config) {
978
- super(uid, CMP_TYPES.MOUSE_BUTTON, config, INITIAL_STATE3);
979
- }
980
- // --- IPointerHandler Implementation ---
981
- onPointerDown(e) {
982
- if (e.cancelable) e.preventDefault();
983
- e.stopPropagation();
984
- e.target.setPointerCapture(e.pointerId);
985
- this.setState({
986
- isActive: true,
987
- isPressed: true,
988
- pointerId: e.pointerId
989
- });
990
- this.sendInputSignal(ACTION_TYPES.MOUSEDOWN);
991
- }
992
- onPointerUp(e) {
993
- if (e.cancelable) e.preventDefault();
994
- this.handleRelease(e, true);
995
- }
996
- onPointerCancel(e) {
997
- this.handleRelease(e, false);
998
- }
999
- onPointerMove(e) {
1000
- if (e.cancelable) e.preventDefault();
1001
- }
1002
- // --- Internal Logic ---
1003
- /**
1004
- * Handles the release of the button.
1005
- *
1006
- * @param e - The pointer event.
1007
- * @param isNormalRelease - If true, a 'click' event will also be dispatched.
1008
- */
1009
- handleRelease(e, isNormalRelease) {
1010
- const isCancelEvent = e.type === "pointercancel" || e.type === "lostpointercapture";
1011
- if (!isCancelEvent && this.state.pointerId !== e.pointerId) return;
1012
- if (e.target.hasPointerCapture(e.pointerId)) {
1013
- e.target.releasePointerCapture(e.pointerId);
1014
- }
1015
- this.setState(INITIAL_STATE3);
1016
- this.sendInputSignal(ACTION_TYPES.MOUSEUP);
1017
- if (isNormalRelease) {
1018
- this.sendInputSignal(ACTION_TYPES.CLICK);
1019
- }
1020
- }
1021
- /**
1022
- * Dispatches input signals to the registered target stage.
1023
- *
1024
- * @param type - The action type (mousedown, mouseup, or click).
1025
- */
1026
- sendInputSignal(type) {
1027
- const targetId = this.config.targetStageId;
1028
- if (!targetId) return;
1029
- const target = Registry.getInstance().getEntity(targetId);
1030
- if (target && typeof target.handleSignal === "function") {
1031
- const signal = {
1032
- targetStageId: targetId,
1033
- type,
1034
- payload: {
1035
- // 传递配置中的鼠标按键索引 (0:左键, 1:中键, 2:右键)
1036
- button: this.config.button ?? 0,
1037
- // 如果配置了固定坐标,一并传递给 TargetZone
1038
- point: this.config.fixedPoint
1039
- }
1040
- };
1041
- target.handleSignal(signal);
1042
- } else {
1043
- if (import.meta.env?.DEV) {
1044
- console.warn(`[OmniPad-Core] MouseButton ${this.uid} target not found: ${targetId}`);
1045
- }
1046
- }
1047
- }
1048
- // --- IResettable Implementation ---
1049
- reset() {
1050
- if (this.state.isPressed) {
1051
- this.sendInputSignal(ACTION_TYPES.MOUSEUP);
1052
- }
1053
- this.setState(INITIAL_STATE3);
1054
- }
1055
- };
1056
-
1057
- // src/entities/RootLayerCore.ts
1058
- var INITIAL_STATE4 = {
1059
- isHighlighted: false
1060
- };
1061
- var RootLayerCore = class extends BaseEntity {
1062
- constructor(uid, config) {
1063
- super(uid, CMP_TYPES.ROOT_LAYER, config, INITIAL_STATE4);
1064
- }
1065
- reset() {
1066
- }
1067
- };
1068
-
1069
- // src/entities/TargetZoneCore.ts
1070
- var INITIAL_STATE5 = {
1071
- position: { x: 50, y: 50 },
1072
- isVisible: false,
1073
- isPointerDown: false,
1074
- isFocusReturning: false
1075
- };
1076
- var TargetZoneCore = class extends BaseEntity {
1077
- constructor(uid, config) {
1078
- super(uid, CMP_TYPES.TARGET_ZONE, config, INITIAL_STATE5);
1079
- __publicField(this, "hideTimer", null);
1080
- __publicField(this, "focusFeedbackTimer", null);
1081
- __publicField(this, "throttledPointerMove");
1082
- this.throttledPointerMove = createRafThrottler((e) => {
1083
- this.processPhysicalEvent(e, ACTION_TYPES.MOUSEMOVE);
1084
- });
1085
- }
1086
- // --- IPointerHandler Implementation ---
1087
- onPointerDown(e) {
1088
- if (e.cancelable) e.preventDefault();
1089
- e.stopPropagation();
1090
- this.processPhysicalEvent(e, ACTION_TYPES.MOUSEDOWN);
1091
- }
1092
- onPointerMove(e) {
1093
- if (e.cancelable) e.preventDefault();
1094
- e.stopPropagation();
1095
- this.throttledPointerMove(e);
1096
- }
1097
- onPointerUp(e) {
1098
- if (e.cancelable) e.preventDefault();
1099
- this.processPhysicalEvent(e, ACTION_TYPES.MOUSEUP);
1100
- this.processPhysicalEvent(e, ACTION_TYPES.CLICK);
1101
- }
1102
- onPointerCancel(e) {
1103
- this.processPhysicalEvent(e, ACTION_TYPES.MOUSEUP);
1104
- }
1105
- /**
1106
- * Convert physical DOM events into internal signals
1107
- */
1108
- processPhysicalEvent(e, type) {
1109
- const rect = this.getRect();
1110
- if (!rect) return;
1111
- const point = {
1112
- x: pxToPercent(e.clientX - rect.left, rect.width),
1113
- y: pxToPercent(e.clientY - rect.top, rect.height)
1114
- };
1115
- this.handleSignal({
1116
- targetStageId: this.uid,
1117
- type,
1118
- payload: { point, button: e.button }
1119
- });
1120
- }
1121
- // --- ISignalReceiver Implementation ---
1122
- handleSignal(signal) {
1123
- const { type, payload } = signal;
1124
- this.ensureFocus();
1125
- switch (type) {
1126
- case ACTION_TYPES.KEYDOWN:
1127
- case ACTION_TYPES.KEYUP:
1128
- dispatchKeyboardEvent(type, payload);
1129
- break;
1130
- case ACTION_TYPES.MOUSEMOVE:
1131
- if (payload.point) {
1132
- this.updateCursorPosition(payload.point);
1133
- } else if (payload.delta) {
1134
- this.updateCursorPositionByDelta(payload.delta);
1135
- }
1136
- if (this.config.cursorEnabled) this.showCursor();
1137
- this.executeMouseAction(ACTION_TYPES.POINTERMOVE, payload);
1138
- break;
1139
- case ACTION_TYPES.MOUSEDOWN:
1140
- case ACTION_TYPES.MOUSEUP:
1141
- case ACTION_TYPES.CLICK:
1142
- if (payload.point) {
1143
- this.updateCursorPosition(payload.point);
1144
- }
1145
- if (this.config.cursorEnabled) this.showCursor();
1146
- this.executeMouseAction(
1147
- type.startsWith(ACTION_TYPES.MOUSE) ? type.replace(ACTION_TYPES.MOUSE, ACTION_TYPES.POINTER) : type,
1148
- payload
1149
- );
1150
- break;
1151
- }
1152
- }
1153
- // --- Mouse & Pointer Simulation ---
1154
- /**
1155
- * Calculates pixel coordinates and dispatches simulated pointer events to the deepest element.
1156
- *
1157
- * @param pointerType - The specific pointer event type (e.g., pointermove, pointerdown).
1158
- * @param payload - Data containing point coordinates or button info.
1159
- */
1160
- executeMouseAction(pointerType, payload) {
1161
- const rect = this.getRect();
1162
- if (!rect) return;
1163
- if (pointerType === ACTION_TYPES.POINTERDOWN) this.setState({ isPointerDown: true });
1164
- if (pointerType === ACTION_TYPES.POINTERUP) this.setState({ isPointerDown: false });
1165
- const target = payload.point || this.state.position;
1166
- const px = rect.left + percentToPx(target.x, rect.width);
1167
- const py = rect.top + percentToPx(target.y, rect.height);
1168
- dispatchPointerEventAtPos(pointerType, px, py, {
1169
- button: payload.button ?? 0,
1170
- buttons: this.state.isPointerDown ? 1 : 0
1171
- });
1172
- }
1173
- // --- Focus Management ---
1174
- /**
1175
- * Checks if the target element under the virtual cursor has focus, and reclaims it if lost.
1176
- */
1177
- ensureFocus() {
1178
- const rect = this.getRect();
1179
- if (!rect) return;
1180
- const px = rect.left + percentToPx(this.state.position.x, rect.width);
1181
- const py = rect.top + percentToPx(this.state.position.y, rect.height);
1182
- const target = getDeepElement(px, py);
1183
- if (!target) return;
1184
- if (getDeepActiveElement() !== target) {
1185
- focusElement(target);
1186
- this.triggerFocusFeedback();
1187
- }
1188
- }
1189
- /**
1190
- * Activates a temporary visual feedback state to indicate a focus-reclaim event.
1191
- */
1192
- triggerFocusFeedback() {
1193
- this.setState({ isFocusReturning: true });
1194
- if (this.focusFeedbackTimer) clearTimeout(this.focusFeedbackTimer);
1195
- this.focusFeedbackTimer = setTimeout(() => this.setState({ isFocusReturning: false }), 500);
1196
- }
1197
- // --- Cursor State Helpers ---
1198
- /**
1199
- * Updates the internal virtual cursor coordinates.
1200
- */
1201
- updateCursorPosition(point) {
1202
- if (isVec2Equal(point, this.state.position)) return;
1203
- this.setState({ position: { ...point } });
1204
- }
1205
- /**
1206
- * Updates the internal virtual cursor coordinates by delta.
1207
- */
1208
- updateCursorPositionByDelta(delta) {
1209
- if (isVec2Equal(delta, { x: 0, y: 0 })) return;
1210
- const rect = this.getRect();
1211
- if (!rect) return;
1212
- const dxPercent = pxToPercent(delta.x, rect.width);
1213
- const dyPercent = pxToPercent(delta.y, rect.height);
1214
- this.updateCursorPosition({
1215
- x: clamp(this.state.position.x + dxPercent, 0, 100),
1216
- y: clamp(this.state.position.y + dyPercent, 0, 100)
1217
- });
1218
- }
1219
- /**
1220
- * Makes the virtual cursor visible and sets a timeout for auto-hiding.
1221
- */
1222
- showCursor() {
1223
- this.setState({ isVisible: true });
1224
- if (this.hideTimer) clearTimeout(this.hideTimer);
1225
- if (this.config.cursorAutoDelay && this.config.cursorAutoDelay > 0) {
1226
- this.hideTimer = setTimeout(
1227
- () => this.setState({ isVisible: false }),
1228
- this.config.cursorAutoDelay
1229
- );
1230
- }
1231
- }
1232
- // --- IResettable Implementation ---
1233
- reset() {
1234
- if (this.state.isPointerDown) {
1235
- this.executeMouseAction(ACTION_TYPES.POINTERUP, {});
1236
- }
1237
- if (this.hideTimer) clearTimeout(this.hideTimer);
1238
- if (this.focusFeedbackTimer) clearTimeout(this.focusFeedbackTimer);
1239
- this.setState({
1240
- isVisible: false,
1241
- isPointerDown: false,
1242
- isFocusReturning: false
1243
- });
1244
- }
1245
- };
1246
-
1247
- // src/entities/TrackpadCore.ts
1248
- var GESTURE = {
1249
- TAP_TIME: 200,
1250
- // 200ms 以内抬起视为轻点 / Release within 200ms counts as a tap
1251
- TAP_DISTANCE: 10,
1252
- // 位移小于 10px 视为点击判定 / Movement within 10px counts as a tap
1253
- DOUBLE_TAP_GAP: 300
1254
- // 两次点击间隔小于 300ms 视为双击触发 / Interval within 300ms counts as double-tap
1255
- };
1256
- var INITIAL_STATE6 = {
1257
- isActive: false,
1258
- isPressed: false,
1259
- pointerId: null,
1260
- value: 0
1261
- };
1262
- var TrackpadCore = class extends BaseEntity {
1263
- /**
1264
- * Creates an instance of TrackpadCore.
1265
- *
1266
- * @param uid - Unique entity ID.
1267
- * @param config - Configuration for the trackpad.
1268
- */
1269
- constructor(uid, config) {
1270
- super(uid, CMP_TYPES.TRACKPAD, config, INITIAL_STATE6);
1271
- __publicField(this, "lastPointerPos", { x: 0, y: 0 });
1272
- __publicField(this, "startTime", 0);
1273
- __publicField(this, "startPos", { x: 0, y: 0 });
1274
- // 连击状态追踪 / State tracking for consecutive taps
1275
- __publicField(this, "lastClickTime", 0);
1276
- __publicField(this, "isDragMode", false);
1277
- __publicField(this, "throttledPointerMove");
1278
- this.throttledPointerMove = createRafThrottler((e) => {
1279
- this.processPointerMove(e);
1280
- });
1281
- }
1282
- // --- IPointerHandler Implementation ---
1283
- onPointerDown(e) {
1284
- if (e.cancelable) e.preventDefault();
1285
- e.stopPropagation();
1286
- e.target.setPointerCapture(e.pointerId);
1287
- const now = Date.now();
1288
- this.startTime = now;
1289
- this.startPos = { x: e.clientX, y: e.clientY };
1290
- this.lastPointerPos = { x: e.clientX, y: e.clientY };
1291
- if (now - this.lastClickTime < GESTURE.DOUBLE_TAP_GAP) {
1292
- this.isDragMode = true;
1293
- this.sendSignal(ACTION_TYPES.MOUSEDOWN);
1294
- this.setState({ isPressed: true });
1295
- }
1296
- this.setState({ isActive: true, pointerId: e.pointerId });
1297
- }
1298
- onPointerMove(e) {
1299
- if (e.cancelable) e.preventDefault();
1300
- e.stopPropagation();
1301
- if (this.state.pointerId !== e.pointerId) return;
1302
- this.throttledPointerMove(e);
1303
- }
1304
- /**
1305
- * Internal logic for processing pointer movement.
1306
- * Calculates displacement and emits relative move signals.
1307
- *
1308
- * @param e - The pointer event.
1309
- */
1310
- processPointerMove(e) {
1311
- const dx = e.clientX - this.lastPointerPos.x;
1312
- const dy = e.clientY - this.lastPointerPos.y;
1313
- const rect = this.getRect();
1314
- if (!rect) return;
1315
- const deltaX = dx / rect.width * 100 * this.config.sensitivity;
1316
- const deltaY = dy / rect.height * 100 * this.config.sensitivity;
1317
- if (Math.abs(dx) > 0 || Math.abs(dy) > 0) {
1318
- this.sendSignal(ACTION_TYPES.MOUSEMOVE, { delta: { x: deltaX, y: deltaY } });
1319
- }
1320
- this.lastPointerPos = { x: e.clientX, y: e.clientY };
1321
- }
1322
- onPointerUp(e) {
1323
- if (this.state.pointerId !== e.pointerId) return;
1324
- if (e.cancelable) e.preventDefault();
1325
- const duration = Date.now() - this.startTime;
1326
- const dist = Math.hypot(e.clientX - this.startPos.x, e.clientY - this.startPos.y);
1327
- if (this.isDragMode) {
1328
- this.sendSignal(ACTION_TYPES.MOUSEUP);
1329
- this.isDragMode = false;
1330
- } else if (duration < GESTURE.TAP_TIME && dist < GESTURE.TAP_DISTANCE) {
1331
- this.sendSignal(ACTION_TYPES.CLICK);
1332
- this.lastClickTime = Date.now();
1333
- }
1334
- this.handleRelease(e);
1335
- }
1336
- onPointerCancel(e) {
1337
- this.handleRelease(e);
1338
- }
1339
- // --- IResettable Implementation ---
1340
- reset() {
1341
- if (this.isDragMode) this.sendSignal(ACTION_TYPES.MOUSEUP);
1342
- this.isDragMode = false;
1343
- this.setState(INITIAL_STATE6);
1344
- }
1345
- // --- Internal Helpers ---
1346
- /**
1347
- * Clean up pointer capture and reset interaction state.
1348
- */
1349
- handleRelease(e) {
1350
- if (e.target.hasPointerCapture(e.pointerId)) {
1351
- try {
1352
- e.target.releasePointerCapture(e.pointerId);
1353
- } catch (err) {
1354
- }
1355
- }
1356
- this.setState(INITIAL_STATE6);
1357
- }
1358
- /**
1359
- * Helper to send signals to the target stage via Registry.
1360
- *
1361
- * @param type - Signal action type.
1362
- * @param extraPayload - Additional data like delta or point.
1363
- */
1364
- sendSignal(type, extraPayload = {}) {
1365
- const targetId = this.config.targetStageId;
1366
- if (!targetId) return;
1367
- const target = Registry.getInstance().getEntity(targetId);
1368
- if (target && typeof target.handleSignal === "function") {
1369
- target.handleSignal({
1370
- targetStageId: targetId,
1371
- type,
1372
- payload: {
1373
- button: 0,
1374
- // 触摸板操作默认模拟左键 / Trackpad defaults to left button
1375
- ...extraPayload
1376
- }
1377
- });
1378
- }
1379
- }
1380
- };
1381
-
1382
- // src/index.ts
1383
- var OmniPad = {
1384
- ActionTypes: ACTION_TYPES,
1385
- Context: CONTEXT,
1386
- Keys: KEYS,
1387
- Types: CMP_TYPES
1388
- };
1389
- export {
1390
- ACTION_TYPES,
1391
- BaseEntity,
1392
- CMP_TYPES,
1393
- CONTEXT,
1394
- InputManager,
1395
- InputZoneCore,
1396
- KEYS,
1397
- KeyboardButtonCore,
1398
- MouseButtonCore,
1399
- OmniPad,
1400
- Registry,
1401
- RootLayerCore,
1402
- SimpleEmitter,
1403
- TargetZoneCore,
1404
- TrackpadCore,
1405
- addVec,
1406
- applyAxialDeadzone,
1407
- applyRadialDeadzone,
1408
- clamp,
1409
- clampVector,
1410
- degToRad,
1411
- dispatchKeyboardEvent,
1412
- dispatchPointerEventAtPos,
1413
- exportProfile,
1414
- focusElement,
1415
- generateUID,
1416
- getAnchorPosition,
1417
- getAngle,
1418
- getDeadzoneScalar,
1419
- getDeepActiveElement,
1420
- getDeepElement,
1421
- getDistance,
1422
- isGlobalID,
1423
- isVec2Equal,
1424
- lerp,
1425
- lockTo4Directions,
1426
- lockTo8Directions,
1427
- normalizeVec,
1428
- parseProfileJson,
1429
- parseProfileTree,
1430
- percentToPx,
1431
- pxToPercent,
1432
- radToDeg,
1433
- radToVec,
1434
- remap,
1435
- resolveLayoutStyle,
1436
- roundTo,
1437
- scaleVec,
1438
- subVec
1439
- };
1
+ import {a,b,f,q as q$1,w as w$1,p,u as u$1}from'./chunk-K6RXCH3Q.mjs';export{b as Registry}from'./chunk-K6RXCH3Q.mjs';var X={Backspace:{key:"Backspace",code:"Backspace",keyCode:8},Tab:{key:"Tab",code:"Tab",keyCode:9},Enter:{key:"Enter",code:"Enter",keyCode:13},ShiftLeft:{key:"Shift",code:"ShiftLeft",keyCode:16},ControlLeft:{key:"Control",code:"ControlLeft",keyCode:17},AltLeft:{key:"Alt",code:"AltLeft",keyCode:18},Pause:{key:"Pause",code:"Pause",keyCode:19},CapsLock:{key:"CapsLock",code:"CapsLock",keyCode:20},Escape:{key:"Escape",code:"Escape",keyCode:27},Space:{key:" ",code:"Space",keyCode:32},PageUp:{key:"PageUp",code:"PageUp",keyCode:33},PageDown:{key:"PageDown",code:"PageDown",keyCode:34},End:{key:"End",code:"End",keyCode:35},Home:{key:"Home",code:"Home",keyCode:36},ArrowLeft:{key:"ArrowLeft",code:"ArrowLeft",keyCode:37},ArrowUp:{key:"ArrowUp",code:"ArrowUp",keyCode:38},ArrowRight:{key:"ArrowRight",code:"ArrowRight",keyCode:39},ArrowDown:{key:"ArrowDown",code:"ArrowDown",keyCode:40},PrintScreen:{key:"PrintScreen",code:"PrintScreen",keyCode:44},Insert:{key:"Insert",code:"Insert",keyCode:45},Delete:{key:"Delete",code:"Delete",keyCode:46},Digit0:{key:"0",code:"Digit0",keyCode:48},Digit1:{key:"1",code:"Digit1",keyCode:49},Digit2:{key:"2",code:"Digit2",keyCode:50},Digit3:{key:"3",code:"Digit3",keyCode:51},Digit4:{key:"4",code:"Digit4",keyCode:52},Digit5:{key:"5",code:"Digit5",keyCode:53},Digit6:{key:"6",code:"Digit6",keyCode:54},Digit7:{key:"7",code:"Digit7",keyCode:55},Digit8:{key:"8",code:"Digit8",keyCode:56},Digit9:{key:"9",code:"Digit9",keyCode:57},KeyA:{key:"a",code:"KeyA",keyCode:65},KeyB:{key:"b",code:"KeyB",keyCode:66},KeyC:{key:"c",code:"KeyC",keyCode:67},KeyD:{key:"d",code:"KeyD",keyCode:68},KeyE:{key:"e",code:"KeyE",keyCode:69},KeyF:{key:"f",code:"KeyF",keyCode:70},KeyG:{key:"g",code:"KeyG",keyCode:71},KeyH:{key:"h",code:"KeyH",keyCode:72},KeyI:{key:"i",code:"KeyI",keyCode:73},KeyJ:{key:"j",code:"KeyJ",keyCode:74},KeyK:{key:"k",code:"KeyK",keyCode:75},KeyL:{key:"l",code:"KeyL",keyCode:76},KeyM:{key:"m",code:"KeyM",keyCode:77},KeyN:{key:"n",code:"KeyN",keyCode:78},KeyO:{key:"o",code:"KeyO",keyCode:79},KeyP:{key:"p",code:"KeyP",keyCode:80},KeyQ:{key:"q",code:"KeyQ",keyCode:81},KeyR:{key:"r",code:"KeyR",keyCode:82},KeyS:{key:"s",code:"KeyS",keyCode:83},KeyT:{key:"t",code:"KeyT",keyCode:84},KeyU:{key:"u",code:"KeyU",keyCode:85},KeyV:{key:"v",code:"KeyV",keyCode:86},KeyW:{key:"w",code:"KeyW",keyCode:87},KeyX:{key:"x",code:"KeyX",keyCode:88},KeyY:{key:"y",code:"KeyY",keyCode:89},KeyZ:{key:"z",code:"KeyZ",keyCode:90},MetaLeft:{key:"Meta",code:"MetaLeft",keyCode:91},ContextMenu:{key:"ContextMenu",code:"ContextMenu",keyCode:93},Numpad0:{key:"0",code:"Numpad0",keyCode:96},Numpad1:{key:"1",code:"Numpad1",keyCode:97},Numpad2:{key:"2",code:"Numpad2",keyCode:98},Numpad3:{key:"3",code:"Numpad3",keyCode:99},Numpad4:{key:"4",code:"Numpad4",keyCode:100},Numpad5:{key:"5",code:"Numpad5",keyCode:101},Numpad6:{key:"6",code:"Numpad6",keyCode:102},Numpad7:{key:"7",code:"Numpad7",keyCode:103},Numpad8:{key:"8",code:"Numpad8",keyCode:104},Numpad9:{key:"9",code:"Numpad9",keyCode:105},NumpadMultiply:{key:"*",code:"NumpadMultiply",keyCode:106},NumpadAdd:{key:"+",code:"NumpadAdd",keyCode:107},NumpadSubtract:{key:"-",code:"NumpadSubtract",keyCode:109},NumpadDecimal:{key:".",code:"NumpadDecimal",keyCode:110},NumpadDivide:{key:"/",code:"NumpadDivide",keyCode:111},F1:{key:"F1",code:"F1",keyCode:112},F2:{key:"F2",code:"F2",keyCode:113},F3:{key:"F3",code:"F3",keyCode:114},F4:{key:"F4",code:"F4",keyCode:115},F5:{key:"F5",code:"F5",keyCode:116},F6:{key:"F6",code:"F6",keyCode:117},F7:{key:"F7",code:"F7",keyCode:118},F8:{key:"F8",code:"F8",keyCode:119},F9:{key:"F9",code:"F9",keyCode:120},F10:{key:"F10",code:"F10",keyCode:121},F11:{key:"F11",code:"F11",keyCode:122},F12:{key:"F12",code:"F12",keyCode:123},NumLock:{key:"NumLock",code:"NumLock",keyCode:144},ScrollLock:{key:"ScrollLock",code:"ScrollLock",keyCode:145},Semicolon:{key:";",code:"Semicolon",keyCode:186},Equal:{key:"=",code:"Equal",keyCode:187},Comma:{key:",",code:"Comma",keyCode:188},Minus:{key:"-",code:"Minus",keyCode:189},Period:{key:".",code:"Period",keyCode:190},Slash:{key:"/",code:"Slash",keyCode:191},Backquote:{key:"`",code:"Backquote",keyCode:192},BracketLeft:{key:"[",code:"BracketLeft",keyCode:219},Backslash:{key:"\\",code:"Backslash",keyCode:220},BracketRight:{key:"]",code:"BracketRight",keyCode:221},Quote:{key:"'",code:"Quote",keyCode:222}},E=X;var u={INPUT_ZONE:"input-zone",TARGET_ZONE:"target-zone",BUTTON:"button",KEYBOARD_BUTTON:"keyboard-button",MOUSE_BUTTON:"mouse-button",JOYSTICK:"joystick",D_PAD:"d-pad",TRACKPAD:"trackpad",VIRTUAL_CURSOR:"virtual-cursor",ROOT_LAYER:"root-layer"},n={KEYDOWN:"keydown",KEYUP:"keyup",POINTER:"pointer",POINTERMOVE:"pointermove",POINTERDOWN:"pointerdown",POINTERUP:"pointerup",MOUSE:"mouse",MOUSEMOVE:"mousemove",MOUSEDOWN:"mousedown",MOUSEUP:"mouseup",CLICK:"click"},_={PARENT_ID_KEY:"omnipad-parent-id-link"};var I=Symbol.for("omnipad.gamepad_manager.instance"),z={A:0,B:1,X:2,Y:3,LB:4,RB:5,LT:6,RT:7,Select:8,Start:9,L3:10,R3:11,Up:12,Down:13,Left:14,Right:15},D=class a$1{constructor(){a(this,"isRunning",false);a(this,"config",null);a(this,"lastButtonStates",[]);a(this,"loop",()=>{if(!this.isRunning)return;let o=navigator.getGamepads();this.config?.forEach((e,t)=>{let i=o[t];i&&i.connected&&e&&(this.lastButtonStates[t]||(this.lastButtonStates[t]=[]),this.processButtons(i,e,t),this.processDPad(i,e),this.processAxes(i,e));}),requestAnimationFrame(this.loop);});}static getInstance(){let o=globalThis;return o[I]||(o[I]=new a$1),o[I]}setConfig(o){this.config=o;}getConfig(){return this.config}start(){this.isRunning||(this.isRunning=true,window.addEventListener("gamepadconnected",o=>{import.meta.env?.DEV&&console.log("[Omnipad-Core] Gamepad Connected:",o.gamepad.id);}),window.addEventListener("gamepaddisconnected",()=>{import.meta.env?.DEV&&console.log("[Omnipad-Core] Gamepad disconnected.");}),this.loop());}stop(){this.isRunning=false;}processButtons(o,e,t){e.buttons&&Object.entries(e.buttons).forEach(([i,r])=>{let c=z[i];if(c===void 0||!o.buttons[c])return;let p=o.buttons[c].pressed,h=this.lastButtonStates[t][c]||false;p&&!h?this.triggerVirtualEntity(r,"down"):!p&&h&&this.triggerVirtualEntity(r,"up"),this.lastButtonStates[t][c]=p;});}processDPad(o,e){let t=e?.dpad;if(!t)return;let i=o.buttons[12]?.pressed?-1:0,r=o.buttons[13]?.pressed?1:0,c=o.buttons[14]?.pressed?-1:0,p=o.buttons[15]?.pressed?1:0,h=c+p,f=i+r;this.triggerVirtualEntity(t,"vector",{x:h,y:f});}processAxes(o,e){let t=e?.deadzone??.1;if(e?.leftStick){let i=Math.abs(o.axes[0])>t?o.axes[0]:0,r=Math.abs(o.axes[1])>t?o.axes[1]:0;this.triggerVirtualEntity(e.leftStick,"vector",{x:i,y:r});}if(e?.rightStick){let i=Math.abs(o.axes[2])>t?o.axes[2]:0,r=Math.abs(o.axes[3])>t?o.axes[3]:0;this.triggerVirtualEntity(e.rightStick,"vector",{x:i,y:r});}}triggerVirtualEntity(o,e,t){let i=b.getInstance().getEntity(o);!i||i.activePointerId!=null||(e==="down"&&i.triggerDown&&i.triggerDown(),e==="up"&&i.triggerUp&&i.triggerUp(),e==="vector"&&i.triggerVector&&t&&i.triggerVector(t.x,t.y));}};var C=typeof globalThis<"u"&&globalThis.requestAnimationFrame?globalThis.requestAnimationFrame.bind(globalThis):a=>setTimeout(a,16),q=typeof globalThis<"u"&&globalThis.cancelAnimationFrame?globalThis.cancelAnimationFrame.bind(globalThis):a=>clearTimeout(a);function g(a){let o=false,e=null;return function(t){e=t,o||(o=true,C(()=>{e!==null&&a(e),o=false;}));}}function V(a){let o=null,e=()=>{a(),o=C(e);};return {start:()=>{o===null&&e();},stop:()=>{o!==null&&(q(o),o=null);}}}var H=(a=2)=>new Promise(o=>{let e=0,t=()=>{++e>=a?o():C(t);};C(t);});var x=Symbol.for("omnipad.input_manager.instance"),w=class a$1{constructor(){a(this,"_isListening",false);a(this,"throttledReset");a(this,"handleGlobalReset",()=>{import.meta.env?.DEV&&console.debug("[OmniPad-Core] Safety reset triggered by environment change."),b.getInstance().resetAll();});a(this,"handleResizeReset",()=>{this.throttledReset(null);});a(this,"handleBlurReset",()=>{this.handleGlobalReset();});a(this,"handleVisibilityChangeReset",()=>{document.visibilityState==="hidden"&&this.handleGlobalReset();});this.throttledReset=g(()=>{this.handleGlobalReset();});}static getInstance(){let o=globalThis;return o[x]||(o[x]=new a$1),o[x]}init(){this._isListening||(window.addEventListener("resize",this.handleResizeReset),window.addEventListener("blur",this.handleBlurReset),document.addEventListener("visibilitychange",this.handleVisibilityChangeReset),this._isListening=true,import.meta.env?.DEV&&console.log("[OmniPad-Core] Global InputManager monitoring started."));}async toggleFullscreen(o){let e=o||document.documentElement;try{document.fullscreenElement?(b.getInstance().resetAll(),await document.exitFullscreen()):(b.getInstance().resetAll(),await e.requestFullscreen());}catch(t){console.error("[OmniPad-Core] Fullscreen toggle failed:",t);}}isFullscreen(){return !!document.fullscreenElement}destroy(){window.removeEventListener("resize",this.handleResizeReset),window.removeEventListener("blur",this.handleBlurReset),window.removeEventListener("visibilitychange",this.handleVisibilityChangeReset),this._isListening=false;}};var A=class{constructor(){a(this,"listeners",new Set);}subscribe(o){return this.listeners.add(o),()=>this.listeners.delete(o)}emit(o){this.listeners.forEach(e=>{try{e(o);}catch(t){console.error("[OmniPad-Core] Emitter callback error:",t);}});}clear(){this.listeners.clear();}};var l=class{constructor(o,e,t,i){a(this,"uid");a(this,"type");a(this,"config");a(this,"state");a(this,"rectProvider",null);a(this,"stateEmitter",new A);this.uid=o,this.type=e,this.config=t,this.state=i;}subscribe(o){return o(this.state),this.stateEmitter.subscribe(o)}setState(o){this.state={...this.state,...o},this.stateEmitter.emit(this.state);}destroy(){this.reset(),this.stateEmitter.clear(),b.getInstance().unregister(this.uid);}get rect(){return this.rectProvider?this.rectProvider():null}bindRectProvider(o){this.rectProvider=o;}updateConfig(o){this.config={...this.config,...o},this.stateEmitter.emit(this.state);}getState(){return this.state}getConfig(){return this.config}};var d=class{constructor(o,e){a(this,"isPressed",false);a(this,"mapping");a(this,"targetId");this.update(o,e);}update(o,e){this.isPressed&&this.reset(),this.targetId=o,this.mapping=this.hydrate(e);}hydrate(o){if(!o)return;let e={...o};if(e.type==="mouse")return e.button=e.button??0,e;let{key:t,code:i,keyCode:r}=e;if(t||i||r){e.type="keyboard";let c=Object.values(E).find(p=>p.code===i||p.key===t||p.keyCode===r);c&&(e.key=t??c.key,e.code=i??c.code,e.keyCode=r??c.keyCode);}return e}press(){if(!this.mapping||this.isPressed)return;this.isPressed=true;let o=this.mapping.type==="keyboard"?n.KEYDOWN:n.MOUSEDOWN;this.emitSignal(o);}release(o=true){if(!this.mapping||!this.isPressed)return;this.isPressed=false;let e=this.mapping.type==="keyboard"?n.KEYUP:n.MOUSEUP;this.emitSignal(e),this.mapping.type==="mouse"&&o&&this.emitSignal(n.CLICK);}move(o){this.mapping?.type==="mouse"&&this.emitSignal(n.MOUSEMOVE,o);}reset(){this.isPressed&&this.release(false);}async tap(o=true){this.isPressed||(this.press(),await H(2),this.isPressed&&this.release(o));}emitSignal(o,e={}){if(!this.targetId||!this.mapping)return;let t=b.getInstance().getEntity(this.targetId);t&&t.handleSignal({targetStageId:this.targetId,type:o,payload:{key:this.mapping.key,code:this.mapping.code,keyCode:this.mapping.keyCode,button:this.mapping.button,point:this.mapping.fixedPoint,...e}});}};var M={isActive:false,isPressed:false,pointerId:null,value:0},R=class extends l{constructor(e,t){super(e,u.BUTTON,t,M);a(this,"emitter");this.emitter=new d(t.targetStageId,t.mapping);}get activePointerId(){return this.state.pointerId}onPointerDown(e){this.setState({isActive:true,isPressed:true,pointerId:e.pointerId}),this.emitter.press();}onPointerUp(e){!this.state.isActive||e.pointerId!==this.state.pointerId||this.handleRelease(true);}onPointerCancel(){this.handleRelease(false);}onPointerMove(){}reset(){this.setState(M),this.emitter.reset();}updateConfig(e){super.updateConfig(e),this.emitter.update(this.config.targetStageId,this.config.mapping);}handleRelease(e){this.setState(M),this.emitter.release(e);}triggerDown(){this.state.isPressed||(this.setState({isActive:true,isPressed:true}),this.emitter.press());}triggerUp(){this.state.isPressed&&(this.setState({isActive:false,isPressed:false}),this.emitter.release(true));}};var G={isActive:false,pointerId:null,vector:{x:0,y:0}},O=class extends l{constructor(e,t){super(e,u.D_PAD,t,G);a(this,"emitters");a(this,"throttledPointerMove");let i=t.targetStageId;this.emitters={up:new d(i,t.mapping?.up),down:new d(i,t.mapping?.down),left:new d(i,t.mapping?.left),right:new d(i,t.mapping?.right)},this.throttledPointerMove=g(r=>{this.processInput(r);});}get activePointerId(){return this.state.pointerId}onPointerDown(e){this.setState({isActive:true,pointerId:e.pointerId,vector:{x:0,y:0}});}onPointerMove(e){!this.state.isActive||e.pointerId!==this.state.pointerId||this.throttledPointerMove(e);}onPointerUp(e){!this.state.isActive||e.pointerId!==this.state.pointerId||this.reset();}onPointerCancel(){this.reset();}processInput(e,t=false){if(!this.state.isActive)return;let i=this.rect;if(!i)return;let r=i.left+i.width/2,c=i.top+i.height/2,p=i.width/2,h=i.height/2,f$1=(e.clientX-r)/p,b=(e.clientY-c)/h;if(t&&(f$1!=f(f$1,-1,1)||b!=f(b,-1,1))){this.setState({vector:{x:0,y:0}});return}let S={x:f(f$1,-1,1),y:f(b,-1,1)};this.setState({vector:S}),this.handleDigitalKeys(S);}handleDigitalKeys(e){let t=this.config.threshold??.3;e.y<-t?(this.emitters.up.press(),this.emitters.down.release()):e.y>t?(this.emitters.down.press(),this.emitters.up.release()):(this.emitters.up.release(),this.emitters.down.release()),e.x<-t?(this.emitters.left.press(),this.emitters.right.release()):e.x>t?(this.emitters.right.press(),this.emitters.left.release()):(this.emitters.left.release(),this.emitters.right.release());}reset(){this.emitters.up.reset(),this.emitters.down.reset(),this.emitters.left.reset(),this.emitters.right.reset(),this.setState(G);}updateConfig(e){super.updateConfig(e),this.emitters.up.update(this.config.targetStageId,this.config.mapping?.up),this.emitters.down.update(this.config.targetStageId,this.config.mapping?.down),this.emitters.left.update(this.config.targetStageId,this.config.mapping?.left),this.emitters.right.update(this.config.targetStageId,this.config.mapping?.right);}triggerVector(e,t){let i={x:e,y:t},r=this.config.threshold??.3;Math.abs(e)>=r||Math.abs(t)>=r?(this.setState({isActive:true,vector:i}),this.handleDigitalKeys(i)):this.reset();}};var J={isDynamicActive:false,dynamicPointerId:null,dynamicPosition:{x:0,y:0}},K=class extends l{constructor(e,t){super(e,u.INPUT_ZONE,t,J);a(this,"delegates",{dynamicWidgetPointerDown:()=>{},dynamicWidgetPointerMove:()=>{},dynamicWidgetPointerUp:()=>{},dynamicWidgetPointerCancel:()=>{}});}bindDelegate(e,t){Object.prototype.hasOwnProperty.call(this.delegates,e)?this.delegates[e]=t:import.meta.env?.DEV&&console.warn(`[Omnipad-Core] TargetZone attempted to bind unknown delegate: ${e}`);}get activePointerId(){return this.state.dynamicPointerId}onPointerDown(e){if(this.state.isDynamicActive)return;let t=this.calculateRelativePosition(e.clientX,e.clientY);this.setState({isDynamicActive:true,dynamicPointerId:e.pointerId,dynamicPosition:t}),this.delegates.dynamicWidgetPointerDown?.(e);}onPointerMove(e){this.state.isDynamicActive&&this.delegates.dynamicWidgetPointerMove?.(e);}onPointerUp(e){this.delegates.dynamicWidgetPointerUp?.(e),this.reset();}onPointerCancel(e){this.delegates.dynamicWidgetPointerCancel?.(e),this.reset();}calculateRelativePosition(e,t){let i=this.rect;return i?{x:q$1(e-i.left,i.width),y:q$1(t-i.top,i.height)}:{x:0,y:0}}get isInterceptorRequired(){return !!(this.config.dynamicWidgetId||this.config.preventFocusLoss)}reset(){this.setState({isDynamicActive:false,dynamicPointerId:null});}};var P=class{constructor(o={}){a(this,"options");a(this,"startTime",0);a(this,"startPos",{x:0,y:0});a(this,"lastTapTime",0);a(this,"hasMoved",false);a(this,"isDoubleTapHolding",false);this.options={tapTime:250,tapDistance:10,doubleTapGap:300,...o};}onPointerDown(o,e){let t=Date.now();this.startTime=t,this.startPos={x:o,y:e},this.hasMoved=false,t-this.lastTapTime<this.options.doubleTapGap?(this.isDoubleTapHolding=true,this.options.onDoubleTapHoldStart?.()):this.isDoubleTapHolding=false;}onPointerMove(o,e){this.hasMoved||Math.hypot(o-this.startPos.x,e-this.startPos.y)>this.options.tapDistance&&(this.hasMoved=true);}onPointerUp(){let o=Date.now(),e=o-this.startTime;this.isDoubleTapHolding?(this.isDoubleTapHolding=false,this.options.onDoubleTapHoldEnd?.(),this.lastTapTime=0):e<=this.options.tapTime&&!this.hasMoved&&(this.options.onTap?.(),o-this.lastTapTime<this.options.doubleTapGap?(this.options.onDoubleTap?.(),this.lastTapTime=0):this.lastTapTime=o);}reset(){this.isDoubleTapHolding&&this.options.onDoubleTapHoldEnd?.(),this.isDoubleTapHolding=false,this.hasMoved=false,this.startTime=0,this.lastTapTime=0;}};var W={isActive:false,isPressed:false,pointerId:null,value:0,vector:{x:0,y:0}},N=class extends l{constructor(e,t){super(e,u.JOYSTICK,t,W);a(this,"emitters");a(this,"stickEmitter");a(this,"cursorEmitter");a(this,"gesture");a(this,"ticker");a(this,"throttledUpdate");let i=t.targetStageId,r=t.mapping||{};this.emitters={up:new d(i,r.up),down:new d(i,r.down),left:new d(i,r.left),right:new d(i,r.right)},this.stickEmitter=new d(i,r.stick),this.cursorEmitter=new d(i,{type:"mouse"}),this.gesture=new P({onTap:async()=>{this.setState({isPressed:true}),await this.stickEmitter.tap(),this.setState({isPressed:false});},onDoubleTapHoldStart:()=>{this.setState({isPressed:true}),this.stickEmitter.press();},onDoubleTapHoldEnd:()=>{this.setState({isPressed:false}),this.stickEmitter.release(false);}}),this.ticker=V(()=>{this.handleCursorTick();}),this.throttledUpdate=g(c=>{this.processInput(c);});}get activePointerId(){return this.state.pointerId}onPointerDown(e){this.setState({isActive:true,pointerId:e.pointerId,vector:{x:0,y:0}}),this.gesture.onPointerDown(e.clientX,e.clientY);}onPointerMove(e){!this.state.isActive||e.pointerId!==this.state.pointerId||(this.gesture.onPointerMove(e.clientX,e.clientY),this.config.cursorMode&&this.ticker.start(),this.throttledUpdate(e));}onPointerUp(e){!this.state.isActive||e.pointerId!==this.state.pointerId||(this.gesture.onPointerUp(),this.handleRelease());}onPointerCancel(){this.handleRelease();}handleRelease(){this.setState({isActive:false,pointerId:null,vector:{x:0,y:0}}),this.ticker.stop(),Object.values(this.emitters).forEach(e=>e?.reset());}processInput(e,t=false){if(!this.state.isActive)return;let i=this.rect;if(!i)return;let r=i.left+i.width/2,c=i.top+i.height/2,p=i.width/2,h=i.height/2,f$1=(e.clientX-r)/p,b=(e.clientY-c)/h;if(t&&(f$1!=f(f$1,-1,1)||b!=f(b,-1,1))){this.setState({vector:{x:0,y:0}});return}let B=w$1({x:f$1,y:b},1,this.config.threshold||.15);this.setState({vector:B}),this.handleDigitalKeys(B);}handleCursorTick(){let{vector:e,isActive:t}=this.state;if(!t||!this.config.cursorMode)return;let i=this.config.cursorSensitivity??1,r={x:e.x*i,y:e.y*i};(Math.abs(r.x)>0||Math.abs(r.y)>0)&&this.cursorEmitter.move({delta:r});}handleDigitalKeys(e){let t=this.config.threshold??.3;e.y<-t?(this.emitters.up.press(),this.emitters.down.release()):e.y>t?(this.emitters.down.press(),this.emitters.up.release()):(this.emitters.up.release(),this.emitters.down.release()),e.x<-t?(this.emitters.left.press(),this.emitters.right.release()):e.x>t?(this.emitters.right.press(),this.emitters.left.release()):(this.emitters.left.release(),this.emitters.right.release());}reset(){this.setState(W),this.gesture.reset(),this.handleRelease(),this.stickEmitter.reset(),this.cursorEmitter.reset();}updateConfig(e){super.updateConfig(e);let t=this.config.targetStageId,i=this.config.mapping||{};this.emitters.up.update(t,i.up),this.emitters.down.update(t,i.down),this.emitters.left.update(t,i.left),this.emitters.right.update(t,i.right),this.stickEmitter.update(t,i.stick),this.cursorEmitter.update(t);}triggerDown(){this.state.isPressed||(this.setState({isActive:true,isPressed:true}),this.stickEmitter.press());}triggerUp(){this.state.isPressed&&(this.setState({isActive:false,isPressed:false}),this.stickEmitter.release(true));}triggerVector(e,t){let i={x:e,y:t},r=this.config.threshold??.3;Math.abs(e)>=r||Math.abs(t)>=r?(this.setState({isActive:true,vector:i}),this.handleDigitalKeys(i),this.config.cursorMode&&this.ticker.start()):this.handleRelease();}};var j={isHighlighted:false},F=class extends l{constructor(o,e){super(o,u.ROOT_LAYER,e,j);}reset(){}};var Q={position:{x:50,y:50},isVisible:false,isPointerDown:false,isFocusReturning:false},U=class extends l{constructor(e,t){super(e,u.TARGET_ZONE,t,Q);a(this,"hideTimer",null);a(this,"focusFeedbackTimer",null);a(this,"throttledPointerMove");a(this,"delegates",{dispatchKeyboardEvent:()=>{},dispatchPointerEventAtPos:()=>{},reclaimFocusAtPos:()=>{}});this.throttledPointerMove=g(i=>{this.processPhysicalEvent(i,n.MOUSEMOVE);});}bindDelegate(e,t){Object.prototype.hasOwnProperty.call(this.delegates,e)?this.delegates[e]=t:import.meta.env?.DEV&&console.warn(`[Omnipad-Core] TargetZone attempted to bind unknown delegate: ${e}`);}get activePointerId(){return null}onPointerDown(e){this.processPhysicalEvent(e,n.MOUSEDOWN);}onPointerMove(e){this.throttledPointerMove(e);}onPointerUp(e){this.processPhysicalEvent(e,n.MOUSEUP),this.processPhysicalEvent(e,n.CLICK);}onPointerCancel(e){this.processPhysicalEvent(e,n.MOUSEUP);}processPhysicalEvent(e,t){let i=this.rect;if(!i)return;let r={x:q$1(e.clientX-i.left,i.width),y:q$1(e.clientY-i.top,i.height)};this.handleSignal({targetStageId:this.uid,type:t,payload:{point:r,button:e.button}});}handleSignal(e){let{type:t,payload:i}=e;switch(this.ensureFocus(),t){case n.KEYDOWN:case n.KEYUP:this.delegates.dispatchKeyboardEvent?.(t,i);break;case n.MOUSEMOVE:i.point?this.updateCursorPosition(i.point):i.delta&&this.updateCursorPositionByDelta(i.delta),this.config.cursorEnabled&&this.showCursor(),this.executeMouseAction(n.POINTERMOVE,i);break;case n.MOUSEDOWN:case n.MOUSEUP:case n.CLICK:i.point&&this.updateCursorPosition(i.point),this.config.cursorEnabled&&this.showCursor(),this.executeMouseAction(t.startsWith(n.MOUSE)?t.replace(n.MOUSE,n.POINTER):t,i);break}}executeMouseAction(e,t){let i=this.rect;if(!i)return;e===n.POINTERDOWN&&this.setState({isPointerDown:true}),e===n.POINTERUP&&this.setState({isPointerDown:false});let r=t.point||this.state.position,c=i.left+p(r.x,i.width),p$1=i.top+p(r.y,i.height);this.delegates.dispatchPointerEventAtPos?.(e,c,p$1,{button:t.button??0,buttons:this.state.isPointerDown?1:0,pressure:this.state.isPointerDown?.5:0});}ensureFocus(){let e=this.rect;if(!e)return;let t=e.left+p(this.state.position.x,e.width),i=e.top+p(this.state.position.y,e.height);this.delegates.reclaimFocusAtPos?.(t,i,()=>this.triggerFocusFeedback());}triggerFocusFeedback(){this.setState({isFocusReturning:true}),this.focusFeedbackTimer&&clearTimeout(this.focusFeedbackTimer),this.focusFeedbackTimer=setTimeout(()=>this.setState({isFocusReturning:false}),500);}updateCursorPosition(e){u$1(e,this.state.position)||this.setState({position:{...e}});}updateCursorPositionByDelta(e){if(u$1(e,{x:0,y:0}))return;let t=this.rect;if(!t)return;let i=q$1(e.x,t.width),r=q$1(e.y,t.height);this.updateCursorPosition({x:f(this.state.position.x+i,0,100),y:f(this.state.position.y+r,0,100)});}showCursor(){this.setState({isVisible:true}),this.hideTimer&&clearTimeout(this.hideTimer),this.config.cursorAutoDelay&&this.config.cursorAutoDelay>0&&(this.hideTimer=setTimeout(()=>this.setState({isVisible:false}),this.config.cursorAutoDelay));}reset(){this.state.isPointerDown&&this.executeMouseAction(n.POINTERUP,{}),this.hideTimer&&clearTimeout(this.hideTimer),this.focusFeedbackTimer&&clearTimeout(this.focusFeedbackTimer),this.setState({isVisible:false,isPointerDown:false,isFocusReturning:false});}};var Z={isActive:false,isPressed:false,pointerId:null,value:0},Y=class extends l{constructor(e,t){super(e,u.TRACKPAD,t,Z);a(this,"lastPointerPos",{x:0,y:0});a(this,"throttledPointerMove");a(this,"gesture");a(this,"emitter");let i=t.mapping||{type:"mouse"};this.emitter=new d(t.targetStageId,i),this.throttledPointerMove=g(r=>{this.processPointerMove(r);}),this.gesture=new P({onTap:()=>{this.setState({isPressed:true}),this.emitter.tap();},onDoubleTapHoldStart:()=>{this.setState({isPressed:true}),this.emitter.press();},onDoubleTapHoldEnd:()=>{this.setState({isPressed:false}),this.emitter.release(false);}});}get activePointerId(){return this.state.pointerId}onPointerDown(e){this.lastPointerPos={x:e.clientX,y:e.clientY},this.gesture.onPointerDown(e.clientX,e.clientY),this.setState({isActive:true,pointerId:e.pointerId});}onPointerMove(e){!this.state.isActive||e.pointerId!==this.state.pointerId||(this.gesture.onPointerMove(e.clientX,e.clientY),this.throttledPointerMove(e));}processPointerMove(e){if(!this.state.isActive)return;let t=e.clientX-this.lastPointerPos.x,i=e.clientY-this.lastPointerPos.y,r=this.rect;if(!r)return;let c=t/r.width*100*(this.config.sensitivity??1),p=i/r.height*100*(this.config.sensitivity??1),h={x:c,y:p};u$1(h,{x:0,y:0})||this.emitter.move({delta:h}),this.lastPointerPos={x:e.clientX,y:e.clientY};}onPointerUp(e){!this.state.isActive||e.pointerId!==this.state.pointerId||(this.gesture.onPointerUp(),this.handleRelease());}onPointerCancel(){this.handleRelease();}reset(){this.gesture.reset(),this.emitter.reset(),this.handleRelease();}updateConfig(e){super.updateConfig(e),this.emitter.update(this.config.targetStageId,this.config.mapping);}handleRelease(){this.setState(Z);}};var Mt={ActionTypes:n,Context:_,Keys:E,Types:u};export{n as ACTION_TYPES,l as BaseEntity,R as ButtonCore,u as CMP_TYPES,_ as CONTEXT,O as DPadCore,D as GamepadManager,w as InputManager,K as InputZoneCore,N as JoystickCore,E as KEYS,Mt as OmniPad,F as RootLayerCore,U as TargetZoneCore,Y as TrackpadCore};