@daugasauron/dolly-host-touch 0.1.4 → 0.1.5-rc.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 +1 -1
- package/abi.mjs +8 -1
- package/module.json +2 -2
- package/package.json +3 -3
- package/touch.mjs +60 -11
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
# @daugasauron/dolly-host-touch
|
|
2
2
|
|
|
3
|
-
Dolly's `touch@0` host module: fingers on a touchscreen
|
|
3
|
+
Dolly's `touch@0` host module: fingers on a touchscreen, every one that is down with its id, and a program's buttons. Give the URL of its
|
|
4
4
|
`module.json` to `boot()`'s `modules`; @daugasauron/dolly's README says how.
|
package/abi.mjs
CHANGED
|
@@ -10,10 +10,17 @@ export const DOLLY_TOUCH_DOWN = 1;
|
|
|
10
10
|
export const DOLLY_TOUCH_MOVE = 2;
|
|
11
11
|
export const DOLLY_TOUCH_UP = 3;
|
|
12
12
|
export const DOLLY_TOUCH_CANCEL = 4;
|
|
13
|
+
export const DOLLY_TOUCH_PRESS = 5;
|
|
13
14
|
export const DOLLY_TOUCH_FINGERS = 10;
|
|
15
|
+
export const DOLLY_TOUCH_BUTTONS_OFFSET = 16400;
|
|
16
|
+
export const DOLLY_TOUCH_LABEL_COUNT_OFFSET = 16404;
|
|
17
|
+
export const DOLLY_TOUCH_LABELS_OFFSET = 16408;
|
|
18
|
+
export const DOLLY_TOUCH_BUTTON_COUNT = 12;
|
|
19
|
+
export const DOLLY_TOUCH_LABEL_SIZE = 32;
|
|
14
20
|
export const DOLLY_TOUCH_ACQUIRE = 92;
|
|
15
21
|
export const DOLLY_TOUCH_READ = 93;
|
|
16
22
|
export const DOLLY_TOUCH_RELEASE = 94;
|
|
23
|
+
export const DOLLY_TOUCH_BUTTONS = 95;
|
|
17
24
|
export const DOLLY_TOUCH_READ_RECORDS = 64;
|
|
18
25
|
export const DOLLY_ERRNO = Object.freeze({ E2BIG: 1, EACCES: 2, EADDRINUSE: 3, EADDRNOTAVAIL: 4, EAFNOSUPPORT: 5, EAGAIN: 6, EALREADY: 7, EBADF: 8, EBADMSG: 9, EBUSY: 10, ECANCELED: 11, ECHILD: 12, ECONNABORTED: 13, ECONNREFUSED: 14, ECONNRESET: 15, EDEADLK: 16, EDESTADDRREQ: 17, EDOM: 18, EDQUOT: 19, EEXIST: 20, EFAULT: 21, EFBIG: 22, EHOSTUNREACH: 23, EIDRM: 24, EILSEQ: 25, EINPROGRESS: 26, EINTR: 27, EINVAL: 28, EIO: 29, EISCONN: 30, EISDIR: 31, ELOOP: 32, EMFILE: 33, EMLINK: 34, EMSGSIZE: 35, EMULTIHOP: 36, ENAMETOOLONG: 37, ENETDOWN: 38, ENETRESET: 39, ENETUNREACH: 40, ENFILE: 41, ENOBUFS: 42, ENODEV: 43, ENOENT: 44, ENOEXEC: 45, ENOLCK: 46, ENOLINK: 47, ENOMEM: 48, ENOMSG: 49, ENOPROTOOPT: 50, ENOSPC: 51, ENOSYS: 52, ENOTCONN: 53, ENOTDIR: 54, ENOTEMPTY: 55, ENOTRECOVERABLE: 56, ENOTSOCK: 57, ENOTTY: 59, ENXIO: 60, EOVERFLOW: 61, EOWNERDEAD: 62, EPERM: 63, EPIPE: 64, EPROTO: 65, EPROTONOSUPPORT: 66, EPROTOTYPE: 67, ERANGE: 68, EROFS: 69, ESPIPE: 70, ESRCH: 71, ESTALE: 72, ETIMEDOUT: 73, ETXTBSY: 74, EXDEV: 75, ENODATA: 116, ENOTSUP: 138 });
|
|
19
|
-
export const DOLLY_TOUCH_ABI_DIGEST = "
|
|
26
|
+
export const DOLLY_TOUCH_ABI_DIGEST = "a666fc4a91ca78e6a7f42e9357d4e3aa8586d6aa662049f7a590794408caa67d";
|
package/module.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "touch",
|
|
3
3
|
"version": 0,
|
|
4
|
-
"gives": "fingers on a touchscreen
|
|
5
|
-
"dependencies": ["runtime@0"],
|
|
4
|
+
"gives": "fingers on a touchscreen, every one that is down with its id, and a program's buttons",
|
|
5
|
+
"dependencies": ["runtime@0", "input@0"],
|
|
6
6
|
"phase": "image",
|
|
7
7
|
"imports": [],
|
|
8
8
|
"host": "touch.mjs",
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.1.
|
|
2
|
+
"version": "0.1.5-rc.0",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"name": "@daugasauron/dolly-host-touch",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@daugasauron/dolly": "0.1.
|
|
7
|
+
"@daugasauron/dolly": "0.1.5-rc.0"
|
|
8
8
|
},
|
|
9
|
-
"description": "Dolly's touch@0 host module: fingers on a touchscreen
|
|
9
|
+
"description": "Dolly's touch@0 host module: fingers on a touchscreen, every one that is down with its id, and a program's buttons.",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
12
12
|
"url": "git+https://github.com/daugasauron/dolly.git"
|
package/touch.mjs
CHANGED
|
@@ -5,6 +5,7 @@ const word = { read: T.DOLLY_TOUCH_WORD_READ, write: T.DOLLY_TOUCH_WORD_WRITE,
|
|
|
5
5
|
lease: T.DOLLY_TOUCH_WORD_LEASE, enabled: T.DOLLY_TOUCH_WORD_ENABLED };
|
|
6
6
|
// Moves leave room for every finger's down and its end.
|
|
7
7
|
const moveReserve = 2 * T.DOLLY_TOUCH_FINGERS;
|
|
8
|
+
const buttonsEnd = T.DOLLY_TOUCH_LABELS_OFFSET + T.DOLLY_TOUCH_BUTTON_COUNT * T.DOLLY_TOUCH_LABEL_SIZE;
|
|
8
9
|
|
|
9
10
|
// The Worker's end of the touch mailbox, the one producer of its records: the
|
|
10
11
|
// page sends it the fingers it took. A finger is delivered under the lease its
|
|
@@ -16,7 +17,8 @@ export class TouchTransport {
|
|
|
16
17
|
if (!(buffer instanceof SharedArrayBuffer)) throw new Error("Dolly touch transport requires shared Wasm memory");
|
|
17
18
|
if (!Number.isSafeInteger(address) || address <= 0 || address % 4 !== 0 || !Number.isSafeInteger(capacity) ||
|
|
18
19
|
capacity <= moveReserve || (capacity & (capacity - 1)) !== 0 ||
|
|
19
|
-
|
|
20
|
+
T.DOLLY_TOUCH_HEADER_SIZE + capacity * T.DOLLY_TOUCH_RECORD_SIZE > T.DOLLY_TOUCH_BUTTONS_OFFSET ||
|
|
21
|
+
address > buffer.byteLength - buttonsEnd) {
|
|
20
22
|
throw new Error("Dolly supplied an invalid touch mailbox");
|
|
21
23
|
}
|
|
22
24
|
this.view = new DataView(buffer);
|
|
@@ -46,16 +48,23 @@ export class TouchTransport {
|
|
|
46
48
|
Atomics.store(this.words, this.address / 4 + word.write, (write + 1) | 0);
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
finger(phase, pointerId, samples) {
|
|
51
|
+
// The lease records are written under. A new one ends the fingers of the
|
|
52
|
+
// one before: they are nobody's until they end.
|
|
53
|
+
follow() {
|
|
53
54
|
const lease = this.lease();
|
|
54
55
|
if (lease !== this.heldLease) {
|
|
55
56
|
for (const pointer of this.fingers.keys()) this.ignored.add(pointer);
|
|
56
57
|
this.fingers.clear();
|
|
57
58
|
this.heldLease = lease;
|
|
58
59
|
}
|
|
60
|
+
return lease;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// One Pointer Event of a finger as samples ({ x, y, pressure, time }, the
|
|
64
|
+
// coalesced moves of a pointermove). Returns whether the finger is this
|
|
65
|
+
// module's, so that it is not also the pointer.
|
|
66
|
+
finger(phase, pointerId, samples) {
|
|
67
|
+
const lease = this.follow();
|
|
59
68
|
const id = this.fingers.get(pointerId), ends = phase === T.DOLLY_TOUCH_UP || phase === T.DOLLY_TOUCH_CANCEL;
|
|
60
69
|
if (id === undefined) {
|
|
61
70
|
if (this.ignored.has(pointerId)) {
|
|
@@ -86,6 +95,33 @@ export class TouchTransport {
|
|
|
86
95
|
return true;
|
|
87
96
|
}
|
|
88
97
|
|
|
98
|
+
// The holder's labels and the labels word they were read under, or null
|
|
99
|
+
// while the kernel is changing them.
|
|
100
|
+
buttons() {
|
|
101
|
+
const word = (this.address + T.DOLLY_TOUCH_BUTTONS_OFFSET) / 4;
|
|
102
|
+
const labels = Atomics.load(this.words, word) >>> 0;
|
|
103
|
+
const count = Math.min(this.view.getUint32(this.address + T.DOLLY_TOUCH_LABEL_COUNT_OFFSET, true),
|
|
104
|
+
T.DOLLY_TOUCH_BUTTON_COUNT);
|
|
105
|
+
const texts = Array.from({ length: count }, (_, index) => {
|
|
106
|
+
const at = this.address + T.DOLLY_TOUCH_LABELS_OFFSET + index * T.DOLLY_TOUCH_LABEL_SIZE;
|
|
107
|
+
const bytes = new Uint8Array(this.view.buffer, at, T.DOLLY_TOUCH_LABEL_SIZE).slice();
|
|
108
|
+
return new TextDecoder().decode(bytes.subarray(0, bytes.indexOf(0) >>> 0));
|
|
109
|
+
});
|
|
110
|
+
return Atomics.load(this.words, word) >>> 0 === labels ? { labels, texts } : null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// A press of the holder's button index, of the labels read under the word
|
|
114
|
+
// labels, while the ring keeps room for it and every finger's end.
|
|
115
|
+
press(index, labels, time) {
|
|
116
|
+
if (!this.follow()) return;
|
|
117
|
+
if (this.free() < this.fingers.size + 1) {
|
|
118
|
+
this.dropped++;
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
this.write(index, T.DOLLY_TOUCH_PRESS, { x: labels, y: 0, pressure: 0, time });
|
|
122
|
+
Atomics.notify(this.words, this.address / 4 + word.write);
|
|
123
|
+
}
|
|
124
|
+
|
|
89
125
|
// Tells the kernel whether this page listens: without it no lease is given.
|
|
90
126
|
enable(enabled) {
|
|
91
127
|
Atomics.store(this.words, this.address / 4 + word.enabled, enabled ? 1 : 0);
|
|
@@ -98,8 +134,9 @@ const phases = { pointerdown: T.DOLLY_TOUCH_DOWN, pointermove: T.DOLLY_TOUCH_MOV
|
|
|
98
134
|
// The page's fingers on the canvas. They are taken before input@0's listeners
|
|
99
135
|
// on the canvas see them, and only while a program holds the lease, as the
|
|
100
136
|
// Worker last reported it: without one the terminal's scroll and pinch are
|
|
101
|
-
// input@0's. A finger taken stays this module's until it ends.
|
|
102
|
-
|
|
137
|
+
// input@0's. A finger taken stays this module's until it ends. The holder's
|
|
138
|
+
// buttons are input@0's bar's, before its Paste.
|
|
139
|
+
export function browser({ canvas, surfaceSize, send, get }) {
|
|
103
140
|
let started = false, lease = 0;
|
|
104
141
|
const taken = new Set();
|
|
105
142
|
// Positions are pixels of the frame the canvas shows, as input@0's pointer records are.
|
|
@@ -130,24 +167,36 @@ export function browser({ canvas, surfaceSize, send }) {
|
|
|
130
167
|
canvas.addEventListener("contextmenu", menu);
|
|
131
168
|
return {
|
|
132
169
|
page: { get touchTransport() { return started ? { lease: () => lease } : undefined; } },
|
|
133
|
-
messages: {
|
|
170
|
+
messages: {
|
|
171
|
+
"touch-lease"(message) { lease = message.lease; },
|
|
172
|
+
"touch-buttons"({ labels, texts }) {
|
|
173
|
+
get("input").buttons(texts, (index, event) =>
|
|
174
|
+
send({ type: "touch-press", index, labels, time: Math.floor(event.timeStamp) }));
|
|
175
|
+
},
|
|
176
|
+
},
|
|
134
177
|
start() { started = true; },
|
|
135
178
|
dispose() {
|
|
136
179
|
for (const type of Object.keys(phases)) window.removeEventListener(type, listen, { capture: true });
|
|
137
180
|
canvas.removeEventListener("contextmenu", menu);
|
|
181
|
+
get("input")?.buttons([]);
|
|
138
182
|
started = false;
|
|
139
183
|
},
|
|
140
184
|
};
|
|
141
185
|
}
|
|
142
186
|
|
|
143
|
-
// The holder's lease
|
|
187
|
+
// The holder's lease and labels are read at each service tick and reported when they change.
|
|
144
188
|
export function worker({ get, send }) {
|
|
145
|
-
let transport, stop, reported = 0;
|
|
189
|
+
let transport, stop, reported = 0, shown = 0;
|
|
146
190
|
return {
|
|
147
|
-
messages: {
|
|
191
|
+
messages: {
|
|
192
|
+
"touch-finger"({ phase, pointerId, samples }) { transport?.finger(phase, pointerId, samples); },
|
|
193
|
+
"touch-press"({ index, labels, time }) { transport?.press(index, labels, time); },
|
|
194
|
+
},
|
|
148
195
|
service() {
|
|
149
196
|
const lease = transport?.lease() ?? 0;
|
|
150
197
|
if (transport && lease !== reported) send({ type: "touch-lease", lease: reported = lease });
|
|
198
|
+
const buttons = transport?.buttons();
|
|
199
|
+
if (buttons && buttons.labels !== shown) send({ type: "touch-buttons", ...buttons, labels: shown = buttons.labels });
|
|
151
200
|
},
|
|
152
201
|
start({ kernel, memory }) {
|
|
153
202
|
const address = Number(kernel.dolly_touch_mailbox_address());
|