Repository navigation
Expand file tree
/
Copy pathinput-native.ts
More file actions
276 lines (251 loc) · 7.48 KB
/
Copy pathinput-native.ts
File metadata and controls
276 lines (251 loc) · 7.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
export const EVENT_KEY = 1;
export const EVENT_MOUSE = 2;
export const EVENT_RESIZE = 3;
export const EVENT_CURSOR = 4;
export const EVENT_CAPABILITY = 5;
export const MOD_ALT = 1;
export const MOD_CTRL = 2;
export const MOD_SHIFT = 4;
export const MOD_MOTION = 8;
export const MOD_RELEASE = 16;
/* Capability key constants — must match CAP_* in src/input.h */
export const CAP_FOREGROUND_COLOR = 1;
export const CAP_BACKGROUND_COLOR = 2;
export const CAP_CURSOR_COLOR = 3;
export const CAP_COLORDEPTH = 4;
export const CAP_SYNC_OUTPUT = 5;
export const CAP_KITTY_KEYBOARD = 6;
export const CAP_KITTY_GRAPHICS = 7;
export const CAP_POINTER_SHAPE = 8;
/* CAP_COLORDEPTH ch values — must match COLORDEPTH_* in src/input.c */
export const COLORDEPTH_16 = 0;
export const COLORDEPTH_256 = 1;
export const COLORDEPTH_TRUECOLOR = 2;
export const KEY_F1 = 0xFFFF;
export const KEY_F2 = 0xFFFE;
export const KEY_F3 = 0xFFFD;
export const KEY_F4 = 0xFFFC;
export const KEY_F5 = 0xFFFB;
export const KEY_F6 = 0xFFFA;
export const KEY_F7 = 0xFFF9;
export const KEY_F8 = 0xFFF8;
export const KEY_F9 = 0xFFF7;
export const KEY_F10 = 0xFFF6;
export const KEY_F11 = 0xFFF5;
export const KEY_F12 = 0xFFF4;
export const KEY_ARROW_UP = 0xFFF3;
export const KEY_ARROW_DOWN = 0xFFF2;
export const KEY_ARROW_LEFT = 0xFFF1;
export const KEY_ARROW_RIGHT = 0xFFF0;
export const KEY_HOME = 0xFFEF;
export const KEY_END = 0xFFEE;
export const KEY_INSERT = 0xFFED;
export const KEY_DELETE = 0xFFEC;
export const KEY_PGUP = 0xFFEB;
export const KEY_PGDN = 0xFFEA;
export const KEY_BACKTAB = 0xFFE9;
export const KEY_NUMPAD_0 = 0xFFE2;
export const KEY_NUMPAD_1 = 0xFFE1;
export const KEY_NUMPAD_2 = 0xFFE0;
export const KEY_NUMPAD_3 = 0xFFDF;
export const KEY_NUMPAD_4 = 0xFFDE;
export const KEY_NUMPAD_5 = 0xFFDD;
export const KEY_NUMPAD_6 = 0xFFDC;
export const KEY_NUMPAD_7 = 0xFFDB;
export const KEY_NUMPAD_8 = 0xFFDA;
export const KEY_NUMPAD_9 = 0xFFD9;
export const KEY_NUMPAD_DECIMAL = 0xFFD8;
export const KEY_NUMPAD_DIVIDE = 0xFFD7;
export const KEY_NUMPAD_MULTIPLY = 0xFFD6;
export const KEY_NUMPAD_SUBTRACT = 0xFFD5;
export const KEY_NUMPAD_ADD = 0xFFD4;
export const KEY_NUMPAD_ENTER = 0xFFD3;
export const KEY_NUMPAD_EQUAL = 0xFFD2;
export const KEY_SHIFT_LEFT = 0xFFD1;
export const KEY_SHIFT_RIGHT = 0xFFD0;
export const KEY_CONTROL_LEFT = 0xFFCF;
export const KEY_CONTROL_RIGHT = 0xFFCE;
export const KEY_ALT_LEFT = 0xFFCD;
export const KEY_ALT_RIGHT = 0xFFCC;
export const KEY_SUPER_LEFT = 0xFFCB;
export const KEY_SUPER_RIGHT = 0xFFCA;
export const KEY_HYPER_LEFT = 0xFFC9;
export const KEY_HYPER_RIGHT = 0xFFC8;
export const KEY_META_LEFT = 0xFFC7;
export const KEY_META_RIGHT = 0xFFC6;
export const KEY_CAPS_LOCK = 0xFFC5;
export const KEY_NUM_LOCK = 0xFFC4;
export const KEY_SCROLL_LOCK = 0xFFC3;
export const KEY_MOUSE_LEFT = 0xFFE8;
export const KEY_MOUSE_RIGHT = 0xFFE7;
export const KEY_MOUSE_MIDDLE = 0xFFE6;
export const KEY_MOUSE_RELEASE = 0xFFE5;
export const KEY_MOUSE_WHEEL_UP = 0xFFE4;
export const KEY_MOUSE_WHEEL_DOWN = 0xFFE3;
export const KEY_ESC = 0x1B;
export const KEY_ENTER = 0x0D;
export const KEY_TAB = 0x09;
export const KEY_BACKSPACE = 0x7F;
export const KEY_SPACE = 0x20;
import {
array,
int32,
offsets,
struct,
uint16,
uint32,
uint8,
} from "./typedef.ts";
const MAX_TEXT_CODEPOINTS = 8;
const InputEventLayout = struct({
type: uint8(),
mod: uint8(),
key: uint16(),
ch: uint32(),
x: int32(),
y: int32(),
w: int32(),
h: int32(),
action: uint8(),
shifted: uint32(),
base: uint32(),
text: array(uint32(), MAX_TEXT_CODEPOINTS),
text_len: uint8(),
});
const {
type: OFFSET_TYPE,
mod: OFFSET_MOD,
key: OFFSET_KEY,
ch: OFFSET_CH,
x: OFFSET_X,
y: OFFSET_Y,
w: OFFSET_W,
h: OFFSET_H,
action: OFFSET_ACTION,
text_len: OFFSET_TEXT_LEN,
shifted: OFFSET_SHIFTED,
base: OFFSET_BASE,
text: OFFSET_TEXT,
} = offsets(InputEventLayout);
export interface NativeInputEvent {
type: number;
mod: number;
key: number;
ch: number;
x: number;
y: number;
w: number;
h: number;
action: number;
shifted: number;
base: number;
text: number[];
}
export function readEvent(view: DataView, ptr: number): NativeInputEvent {
let len = view.getUint8(ptr + OFFSET_TEXT_LEN);
let text: number[] = [];
for (let i = 0; i < len && i < MAX_TEXT_CODEPOINTS; i++) {
text.push(view.getUint32(ptr + OFFSET_TEXT + i * 4, true));
}
return {
type: view.getUint8(ptr + OFFSET_TYPE),
mod: view.getUint8(ptr + OFFSET_MOD),
key: view.getUint16(ptr + OFFSET_KEY, true),
ch: view.getUint32(ptr + OFFSET_CH, true),
x: view.getInt32(ptr + OFFSET_X, true),
y: view.getInt32(ptr + OFFSET_Y, true),
w: view.getInt32(ptr + OFFSET_W, true),
h: view.getInt32(ptr + OFFSET_H, true),
action: view.getUint8(ptr + OFFSET_ACTION),
shifted: view.getUint32(ptr + OFFSET_SHIFTED, true),
base: view.getUint32(ptr + OFFSET_BASE, true),
text,
};
}
export interface InputNative {
memory: WebAssembly.Memory;
state: number;
buffer: number;
scan(st: number, buf: number, len: number, now: number): number;
count(st: number): number;
event(st: number, index: number): number;
delay(st: number): number;
}
// Must match SCAN_BUFFER_SIZE in input.c — the maximum bytes input_scan()
// can accept in a single call.
export const SCAN_BUFFER_SIZE = 4096;
function align8(n: number): number {
return (n + 7) & ~7;
}
import { compiled } from "./wasm.ts";
export async function createInputNative(
escLatency: number,
keys?: Uint8Array,
initialColors?: number,
): Promise<InputNative> {
let memory = new WebAssembly.Memory({ initial: 4 });
let instance = await WebAssembly.instantiate(compiled, {
env: { memory },
clay: {
measureTextFunction() {},
queryScrollOffsetFunction(ret: number) {
let v = new DataView(memory.buffer);
v.setFloat32(ret, 0, true);
v.setFloat32(ret + 4, 0, true);
},
},
});
let exports = instance.exports as unknown as {
__heap_base: WebAssembly.Global;
input_size(): number;
input_init(
mem: number,
escLatency: number,
terminfo: number,
terminfoLen: number,
initialColors: number,
): number;
input_scan(st: number, buf: number, len: number, now: number): number;
input_count(st: number): number;
input_event(st: number, index: number): number;
input_delay(st: number): number;
};
// Linear memory layout, each region 8-byte aligned:
//
// [0, __heap_base) wasm data and stack
// keys terminfo key table (keys.byteLength, may be empty)
// InputState parser state (input_size())
// scan buffer input_scan() transfer buffer (SCAN_BUFFER_SIZE)
//
// Memory is grown once to cover the end of the scan buffer.
let keysLen = keys?.byteLength ?? 0;
let top = align8(exports.__heap_base.value as number);
let keysPtr = keysLen > 0 ? top : 0;
top = align8(top + keysLen);
let statePtr = top;
top = align8(top + exports.input_size());
let buffer = top;
top += SCAN_BUFFER_SIZE;
let pages = Math.ceil(top / 65536);
let current = memory.buffer.byteLength / 65536;
if (pages > current) memory.grow(pages - current);
if (keys && keysLen > 0) {
new Uint8Array(memory.buffer).set(keys, keysPtr);
}
let state = exports.input_init(
statePtr,
escLatency,
keysPtr,
keysLen,
initialColors ?? 256,
);
return {
memory,
state,
buffer,
scan: exports.input_scan,
count: exports.input_count,
event: exports.input_event,
delay: exports.input_delay,
};
}