@gd-kirie/ipc 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -0
- package/dist/pointer-input/auto.d.ts +1 -0
- package/dist/pointer-input/auto.js +11 -0
- package/dist/pointer-input/auto.js.map +1 -0
- package/dist/pointer-input/index.d.ts +14 -0
- package/dist/pointer-input/index.d.ts.map +1 -0
- package/dist/pointer-input/index.js +105 -0
- package/dist/pointer-input/index.js.map +1 -0
- package/package.json +12 -2
package/README.md
CHANGED
|
@@ -36,3 +36,45 @@ message:
|
|
|
36
36
|
The structured data subset is limited to `null`, booleans, numbers, strings,
|
|
37
37
|
arrays, and objects with string keys. JSON message shapes are a caller or
|
|
38
38
|
adapter convention and should be sent with `sendText()` when needed.
|
|
39
|
+
|
|
40
|
+
## Pointer input forwarding
|
|
41
|
+
|
|
42
|
+
> [!IMPORTANT]
|
|
43
|
+
> Kirie WebViews normally fill their native host above Godot. CSS transparency
|
|
44
|
+
> does not pass native hit tests through to Godot, so visible Godot controls
|
|
45
|
+
> behind the WebView cannot be clicked without pointer forwarding. Most Kirie
|
|
46
|
+
> pages should import `@gd-kirie/ipc/pointer-input/auto`.
|
|
47
|
+
|
|
48
|
+
Enable both sides; the browser entry registers on import:
|
|
49
|
+
|
|
50
|
+
```gdscript
|
|
51
|
+
$KirieNode.pointer_input_forwarding_enabled = true
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import "@gd-kirie/ipc/pointer-input/auto";
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Custom event orchestration
|
|
59
|
+
|
|
60
|
+
For custom targets or lifetimes, use the explicit entry instead:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import {
|
|
64
|
+
createPointerEventsHandler,
|
|
65
|
+
phaseFromPointerEvent,
|
|
66
|
+
sendPointerEvent,
|
|
67
|
+
} from "@gd-kirie/ipc/pointer-input";
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`createPointerEventsHandler()` returns `capture`, `bubble`, and `cancel` handlers;
|
|
71
|
+
the caller owns their registration and removal.
|
|
72
|
+
|
|
73
|
+
`pointerdown` bubbling decides ownership: `event.stopPropagation()` keeps the
|
|
74
|
+
sequence in the WebView; otherwise its move, up, and cancel events are forwarded
|
|
75
|
+
to Godot.
|
|
76
|
+
|
|
77
|
+
Forwarding uses Godot's
|
|
78
|
+
[`Input.parse_input_event()`](https://docs.godotengine.org/en/stable/classes/class_input.html#class-input-method-parse-input-event)
|
|
79
|
+
API; forwarded mouse and touch events retain their destination
|
|
80
|
+
[`window_id`](https://docs.godotengine.org/en/stable/classes/class_inputeventfromwindow.html#class-inputeventfromwindow-property-window-id).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createPointerEventsHandler } from "./index.js";
|
|
2
|
+
//#region src/pointer-input/auto.ts
|
|
3
|
+
const pointerEventsHandler = createPointerEventsHandler();
|
|
4
|
+
document.addEventListener("pointerdown", pointerEventsHandler.bubble);
|
|
5
|
+
document.addEventListener("pointermove", pointerEventsHandler.capture, true);
|
|
6
|
+
document.addEventListener("pointerup", pointerEventsHandler.capture, true);
|
|
7
|
+
document.addEventListener("pointercancel", pointerEventsHandler.capture, true);
|
|
8
|
+
document.addEventListener("pointermove", pointerEventsHandler.bubble);
|
|
9
|
+
//#endregion
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=auto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto.js","names":[],"sources":["../../src/pointer-input/auto.ts"],"sourcesContent":["import { createPointerEventsHandler } from \"./index\";\n\nconst pointerEventsHandler = createPointerEventsHandler();\n\ndocument.addEventListener(\"pointerdown\", pointerEventsHandler.bubble);\ndocument.addEventListener(\"pointermove\", pointerEventsHandler.capture, true);\ndocument.addEventListener(\"pointerup\", pointerEventsHandler.capture, true);\ndocument.addEventListener(\"pointercancel\", pointerEventsHandler.capture, true);\ndocument.addEventListener(\"pointermove\", pointerEventsHandler.bubble);\n"],"mappings":";;AAEA,MAAM,uBAAuB,2BAA2B;AAExD,SAAS,iBAAiB,eAAe,qBAAqB,MAAM;AACpE,SAAS,iBAAiB,eAAe,qBAAqB,SAAS,IAAI;AAC3E,SAAS,iBAAiB,aAAa,qBAAqB,SAAS,IAAI;AACzE,SAAS,iBAAiB,iBAAiB,qBAAqB,SAAS,IAAI;AAC7E,SAAS,iBAAiB,eAAe,qBAAqB,MAAM"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/pointer-input/index.d.ts
|
|
2
|
+
type PointerPhase = "down" | "move" | "up" | "cancel";
|
|
3
|
+
type PointerEventSender = (event: PointerEvent, phase?: PointerPhase) => void;
|
|
4
|
+
interface PointerEventsHandler {
|
|
5
|
+
capture(event: PointerEvent): void;
|
|
6
|
+
bubble(event: PointerEvent): void;
|
|
7
|
+
cancel(): void;
|
|
8
|
+
}
|
|
9
|
+
declare function sendPointerEvent(event: PointerEvent, phase?: PointerPhase): void;
|
|
10
|
+
declare function createPointerEventsHandler(sendPointer?: PointerEventSender): PointerEventsHandler;
|
|
11
|
+
declare function phaseFromPointerEvent(event: PointerEvent): PointerPhase;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { PointerEventSender, PointerEventsHandler, PointerPhase, createPointerEventsHandler, phaseFromPointerEvent, sendPointerEvent };
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/pointer-input/index.ts"],"mappings":";KAGY,YAAA;AAAA,KAmBA,kBAAA,IAAsB,KAAA,EAAO,YAAA,EAAc,KAAA,GAAQ,YAAA;AAAA,UAE9C,oBAAA;EACf,OAAA,CAAQ,KAAA,EAAO,YAAA;EACf,MAAA,CAAO,KAAA,EAAO,YAAA;EACd,MAAA;AAAA;AAAA,iBAGc,gBAAA,CACd,KAAA,EAAO,YAAA,EACP,KAAA,GAAO,YAAA;AAAA,iBAwBO,0BAAA,CACd,WAAA,GAAa,kBAAA,GACZ,oBAAA;AAAA,iBA8Fa,qBAAA,CAAsB,KAAA,EAAO,YAAA,GAAe,YAAA"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { sendData } from "../index.js";
|
|
2
|
+
//#region src/pointer-input/index.ts
|
|
3
|
+
function sendPointerEvent(event, phase = phaseFromPointerEvent(event)) {
|
|
4
|
+
const view = event.view ?? window;
|
|
5
|
+
const pointerType = event.pointerType;
|
|
6
|
+
if (pointerType !== "mouse" && pointerType !== "pen" && pointerType !== "touch") throw new TypeError(`Kirie cannot forward pointer type: ${pointerType}`);
|
|
7
|
+
sendData({ __gd_kirie_control: {
|
|
8
|
+
kind: "pointer",
|
|
9
|
+
phase,
|
|
10
|
+
pointer_id: event.pointerId,
|
|
11
|
+
pointer_type: pointerType,
|
|
12
|
+
normalized_x: event.clientX / view.innerWidth,
|
|
13
|
+
normalized_y: event.clientY / view.innerHeight,
|
|
14
|
+
button: event.button,
|
|
15
|
+
buttons: event.buttons,
|
|
16
|
+
pressure: event.pressure
|
|
17
|
+
} });
|
|
18
|
+
}
|
|
19
|
+
function createPointerEventsHandler(sendPointer = sendPointerEvent) {
|
|
20
|
+
const claimedPointers = /* @__PURE__ */ new Map();
|
|
21
|
+
/**
|
|
22
|
+
* Completes events for pointer sequences previously claimed during bubbling.
|
|
23
|
+
*
|
|
24
|
+
* Triggering workflow:
|
|
25
|
+
*
|
|
26
|
+
* {@link EventTarget.addEventListener}
|
|
27
|
+
* -> `pointermove|pointerup|pointercancel`
|
|
28
|
+
* -> {@link capture}
|
|
29
|
+
*
|
|
30
|
+
* Upstream:
|
|
31
|
+
* - {@link EventTarget.addEventListener}
|
|
32
|
+
*
|
|
33
|
+
* Downstream:
|
|
34
|
+
* - {@link sendPointerEvent}
|
|
35
|
+
*/
|
|
36
|
+
const capture = (event) => {
|
|
37
|
+
if (!claimedPointers.has(event.pointerId) || event.type !== "pointermove" && event.type !== "pointerup" && event.type !== "pointercancel") return;
|
|
38
|
+
sendPointer(event);
|
|
39
|
+
if (event.type === "pointerup" || event.type === "pointercancel") {
|
|
40
|
+
claimedPointers.delete(event.pointerId);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
claimedPointers.set(event.pointerId, event);
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Claims bubbled pointer downs and forwards unpressed mouse hover.
|
|
47
|
+
*
|
|
48
|
+
* Triggering workflow:
|
|
49
|
+
*
|
|
50
|
+
* {@link EventTarget.addEventListener}
|
|
51
|
+
* -> `pointerdown|pointermove`
|
|
52
|
+
* -> {@link bubble}
|
|
53
|
+
*
|
|
54
|
+
* Upstream:
|
|
55
|
+
* - {@link EventTarget.addEventListener}
|
|
56
|
+
*
|
|
57
|
+
* Downstream:
|
|
58
|
+
* - {@link sendPointerEvent}
|
|
59
|
+
*/
|
|
60
|
+
const bubble = (event) => {
|
|
61
|
+
if (event.type === "pointerdown") {
|
|
62
|
+
sendPointer(event);
|
|
63
|
+
claimedPointers.set(event.pointerId, event);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (event.type !== "pointermove" || claimedPointers.has(event.pointerId) || event.pointerType !== "mouse" || event.buttons !== 0) return;
|
|
67
|
+
sendPointer(event);
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Cancels every pointer sequence currently claimed by this handler.
|
|
71
|
+
*
|
|
72
|
+
* Triggering workflow:
|
|
73
|
+
*
|
|
74
|
+
* {@link createPointerEventsHandler}
|
|
75
|
+
* -> {@link PointerEventsHandler.cancel}
|
|
76
|
+
*
|
|
77
|
+
* Upstream:
|
|
78
|
+
* - caller of {@link PointerEventsHandler.cancel}
|
|
79
|
+
*
|
|
80
|
+
* Downstream:
|
|
81
|
+
* - {@link sendPointerEvent}
|
|
82
|
+
*/
|
|
83
|
+
const cancel = () => {
|
|
84
|
+
for (const pointerEvent of claimedPointers.values()) sendPointer(pointerEvent, "cancel");
|
|
85
|
+
claimedPointers.clear();
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
capture,
|
|
89
|
+
bubble,
|
|
90
|
+
cancel
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function phaseFromPointerEvent(event) {
|
|
94
|
+
switch (event.type) {
|
|
95
|
+
case "pointerdown": return "down";
|
|
96
|
+
case "pointermove": return "move";
|
|
97
|
+
case "pointerup": return "up";
|
|
98
|
+
case "pointercancel": return "cancel";
|
|
99
|
+
default: throw new TypeError(`Kirie cannot forward pointer event type: ${event.type}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
export { createPointerEventsHandler, phaseFromPointerEvent, sendPointerEvent };
|
|
104
|
+
|
|
105
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/pointer-input/index.ts"],"sourcesContent":["import type { KirieData } from \"../index\";\nimport { sendData } from \"../index\";\n\nexport type PointerPhase = \"down\" | \"move\" | \"up\" | \"cancel\";\ntype PointerType = \"mouse\" | \"pen\" | \"touch\";\n\ninterface PointerInputRecord extends Record<string, KirieData> {\n kind: \"pointer\";\n phase: PointerPhase;\n pointer_id: number;\n pointer_type: PointerType;\n normalized_x: number;\n normalized_y: number;\n button: number;\n buttons: number;\n pressure: number;\n}\n\ninterface PointerControlRecord extends Record<string, KirieData> {\n __gd_kirie_control: PointerInputRecord;\n}\n\nexport type PointerEventSender = (event: PointerEvent, phase?: PointerPhase) => void;\n\nexport interface PointerEventsHandler {\n capture(event: PointerEvent): void;\n bubble(event: PointerEvent): void;\n cancel(): void;\n}\n\nexport function sendPointerEvent(\n event: PointerEvent,\n phase: PointerPhase = phaseFromPointerEvent(event),\n): void {\n const view = event.view ?? window;\n\n const pointerType = event.pointerType;\n if (pointerType !== \"mouse\" && pointerType !== \"pen\" && pointerType !== \"touch\") {\n throw new TypeError(`Kirie cannot forward pointer type: ${pointerType}`);\n }\n\n sendData({\n __gd_kirie_control: {\n kind: \"pointer\",\n phase,\n pointer_id: event.pointerId,\n pointer_type: pointerType,\n normalized_x: event.clientX / view.innerWidth,\n normalized_y: event.clientY / view.innerHeight,\n button: event.button,\n buttons: event.buttons,\n pressure: event.pressure,\n },\n } satisfies PointerControlRecord);\n}\n\nexport function createPointerEventsHandler(\n sendPointer: PointerEventSender = sendPointerEvent,\n): PointerEventsHandler {\n // A sequence is claimed only when its down event reaches the document bubble phase.\n const claimedPointers = new Map<number, PointerEvent>();\n\n /**\n * Completes events for pointer sequences previously claimed during bubbling.\n *\n * Triggering workflow:\n *\n * {@link EventTarget.addEventListener}\n * -> `pointermove|pointerup|pointercancel`\n * -> {@link capture}\n *\n * Upstream:\n * - {@link EventTarget.addEventListener}\n *\n * Downstream:\n * - {@link sendPointerEvent}\n */\n const capture = (event: PointerEvent): void => {\n if (\n !claimedPointers.has(event.pointerId) ||\n (event.type !== \"pointermove\" && event.type !== \"pointerup\" && event.type !== \"pointercancel\")\n ) {\n return;\n }\n\n sendPointer(event);\n if (event.type === \"pointerup\" || event.type === \"pointercancel\") {\n claimedPointers.delete(event.pointerId);\n return;\n }\n\n claimedPointers.set(event.pointerId, event);\n };\n\n /**\n * Claims bubbled pointer downs and forwards unpressed mouse hover.\n *\n * Triggering workflow:\n *\n * {@link EventTarget.addEventListener}\n * -> `pointerdown|pointermove`\n * -> {@link bubble}\n *\n * Upstream:\n * - {@link EventTarget.addEventListener}\n *\n * Downstream:\n * - {@link sendPointerEvent}\n */\n const bubble = (event: PointerEvent): void => {\n if (event.type === \"pointerdown\") {\n sendPointer(event);\n claimedPointers.set(event.pointerId, event);\n return;\n }\n\n if (\n event.type !== \"pointermove\" ||\n claimedPointers.has(event.pointerId) ||\n event.pointerType !== \"mouse\" ||\n event.buttons !== 0\n ) {\n return;\n }\n\n sendPointer(event);\n };\n\n /**\n * Cancels every pointer sequence currently claimed by this handler.\n *\n * Triggering workflow:\n *\n * {@link createPointerEventsHandler}\n * -> {@link PointerEventsHandler.cancel}\n *\n * Upstream:\n * - caller of {@link PointerEventsHandler.cancel}\n *\n * Downstream:\n * - {@link sendPointerEvent}\n */\n const cancel = (): void => {\n for (const pointerEvent of claimedPointers.values()) {\n sendPointer(pointerEvent, \"cancel\");\n }\n claimedPointers.clear();\n };\n\n return { capture, bubble, cancel };\n}\n\nexport function phaseFromPointerEvent(event: PointerEvent): PointerPhase {\n switch (event.type) {\n case \"pointerdown\":\n return \"down\";\n case \"pointermove\":\n return \"move\";\n case \"pointerup\":\n return \"up\";\n case \"pointercancel\":\n return \"cancel\";\n default:\n throw new TypeError(`Kirie cannot forward pointer event type: ${event.type}`);\n }\n}\n"],"mappings":";;AA8BA,SAAgB,iBACd,OACA,QAAsB,sBAAsB,KAAK,GAC3C;CACN,MAAM,OAAO,MAAM,QAAQ;CAE3B,MAAM,cAAc,MAAM;CAC1B,IAAI,gBAAgB,WAAW,gBAAgB,SAAS,gBAAgB,SACtE,MAAM,IAAI,UAAU,sCAAsC,aAAa;CAGzE,SAAS,EACP,oBAAoB;EAClB,MAAM;EACN;EACA,YAAY,MAAM;EAClB,cAAc;EACd,cAAc,MAAM,UAAU,KAAK;EACnC,cAAc,MAAM,UAAU,KAAK;EACnC,QAAQ,MAAM;EACd,SAAS,MAAM;EACf,UAAU,MAAM;CAClB,EACF,CAAgC;AAClC;AAEA,SAAgB,2BACd,cAAkC,kBACZ;CAEtB,MAAM,kCAAkB,IAAI,IAA0B;;;;;;;;;;;;;;;;CAiBtD,MAAM,WAAW,UAA8B;EAC7C,IACE,CAAC,gBAAgB,IAAI,MAAM,SAAS,KACnC,MAAM,SAAS,iBAAiB,MAAM,SAAS,eAAe,MAAM,SAAS,iBAE9E;EAGF,YAAY,KAAK;EACjB,IAAI,MAAM,SAAS,eAAe,MAAM,SAAS,iBAAiB;GAChE,gBAAgB,OAAO,MAAM,SAAS;GACtC;EACF;EAEA,gBAAgB,IAAI,MAAM,WAAW,KAAK;CAC5C;;;;;;;;;;;;;;;;CAiBA,MAAM,UAAU,UAA8B;EAC5C,IAAI,MAAM,SAAS,eAAe;GAChC,YAAY,KAAK;GACjB,gBAAgB,IAAI,MAAM,WAAW,KAAK;GAC1C;EACF;EAEA,IACE,MAAM,SAAS,iBACf,gBAAgB,IAAI,MAAM,SAAS,KACnC,MAAM,gBAAgB,WACtB,MAAM,YAAY,GAElB;EAGF,YAAY,KAAK;CACnB;;;;;;;;;;;;;;;CAgBA,MAAM,eAAqB;EACzB,KAAK,MAAM,gBAAgB,gBAAgB,OAAO,GAChD,YAAY,cAAc,QAAQ;EAEpC,gBAAgB,MAAM;CACxB;CAEA,OAAO;EAAE;EAAS;EAAQ;CAAO;AACnC;AAEA,SAAgB,sBAAsB,OAAmC;CACvE,QAAQ,MAAM,MAAd;EACE,KAAK,eACH,OAAO;EACT,KAAK,eACH,OAAO;EACT,KAAK,aACH,OAAO;EACT,KAAK,iBACH,OAAO;EACT,SACE,MAAM,IAAI,UAAU,4CAA4C,MAAM,MAAM;CAChF;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gd-kirie/ipc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -13,6 +13,14 @@
|
|
|
13
13
|
".": {
|
|
14
14
|
"types": "./dist/index.d.ts",
|
|
15
15
|
"import": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./pointer-input": {
|
|
18
|
+
"types": "./dist/pointer-input/index.d.ts",
|
|
19
|
+
"import": "./dist/pointer-input/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./pointer-input/auto": {
|
|
22
|
+
"types": "./dist/pointer-input/auto.d.ts",
|
|
23
|
+
"import": "./dist/pointer-input/auto.js"
|
|
16
24
|
}
|
|
17
25
|
},
|
|
18
26
|
"files": [
|
|
@@ -23,7 +31,8 @@
|
|
|
23
31
|
},
|
|
24
32
|
"devDependencies": {
|
|
25
33
|
"tsdown": "^0.22.2",
|
|
26
|
-
"typescript": "^6.0.3"
|
|
34
|
+
"typescript": "^6.0.3",
|
|
35
|
+
"vitest": "^4.0.15"
|
|
27
36
|
},
|
|
28
37
|
"publishConfig": {
|
|
29
38
|
"access": "public",
|
|
@@ -31,6 +40,7 @@
|
|
|
31
40
|
},
|
|
32
41
|
"scripts": {
|
|
33
42
|
"build": "tsdown",
|
|
43
|
+
"test:run": "vitest run",
|
|
34
44
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
35
45
|
}
|
|
36
46
|
}
|