ink-native 0.1.0 → 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 +59 -3
- package/dist/{chunk-3NCUBVFY.js → chunk-5O6OVITA.js} +377 -17
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +31 -1
- package/dist/index.js +5 -1
- package/native/fenster.dylib +0 -0
- package/native/fenster.h +31 -3
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -286,8 +286,9 @@ Event emitter for window lifecycle and input events.
|
|
|
286
286
|
|
|
287
287
|
#### Events
|
|
288
288
|
|
|
289
|
+
- `keydown` -- Emitted when a key is pressed (with `NativeKeyboardEvent` payload)
|
|
290
|
+
- `keyup` -- Emitted when a key is released (with `NativeKeyboardEvent` payload)
|
|
289
291
|
- `close` -- Emitted when the window is closed
|
|
290
|
-
- `key` -- Emitted on keyboard events
|
|
291
292
|
- `resize` -- Emitted when the window is resized (with `{ columns, rows }`)
|
|
292
293
|
- `sigint` -- Emitted on Ctrl+C (if a listener is registered; otherwise sends SIGINT to the process)
|
|
293
294
|
|
|
@@ -303,9 +304,59 @@ Event emitter for window lifecycle and input events.
|
|
|
303
304
|
- `resume()` -- Resume the Ink event loop
|
|
304
305
|
- `isPaused()` -- Check if the event loop is paused
|
|
305
306
|
|
|
306
|
-
## Keyboard
|
|
307
|
+
## Keyboard Events
|
|
307
308
|
|
|
308
|
-
The
|
|
309
|
+
The `window` emits `keydown` and `keyup` events with a `NativeKeyboardEvent` payload:
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
import { createStreams, type NativeKeyboardEvent } from "ink-native";
|
|
313
|
+
|
|
314
|
+
const { window } = createStreams({ title: "My Game" });
|
|
315
|
+
|
|
316
|
+
window.on("keydown", (event: NativeKeyboardEvent) => {
|
|
317
|
+
console.log(event.key); // "a", "A", "Enter", "ArrowUp", "Shift"
|
|
318
|
+
console.log(event.code); // "KeyA", "Enter", "ArrowUp", "ShiftLeft"
|
|
319
|
+
console.log(event.ctrlKey); // true if Ctrl is held
|
|
320
|
+
console.log(event.type); // "keydown"
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
window.on("keyup", (event: NativeKeyboardEvent) => {
|
|
324
|
+
console.log(event.key, "released");
|
|
325
|
+
});
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
#### `NativeKeyboardEvent`
|
|
329
|
+
|
|
330
|
+
| Property | Type | Description |
|
|
331
|
+
| ---------- | ------------------------ | ------------------------------------------------------- |
|
|
332
|
+
| `key` | `string` | The key value: `"a"`, `"A"`, `"Enter"`, `"Shift"` |
|
|
333
|
+
| `code` | `string` | Physical key code: `"KeyA"`, `"Enter"`, `"ShiftLeft"` |
|
|
334
|
+
| `ctrlKey` | `boolean` | Whether Ctrl is held |
|
|
335
|
+
| `shiftKey` | `boolean` | Whether Shift is held |
|
|
336
|
+
| `altKey` | `boolean` | Whether Alt is held |
|
|
337
|
+
| `metaKey` | `boolean` | Whether Meta/Command is held |
|
|
338
|
+
| `repeat` | `false` | Always `false` (fenster only reports transitions) |
|
|
339
|
+
| `type` | `"keydown" \| "keyup"` | Whether the key was pressed or released |
|
|
340
|
+
|
|
341
|
+
Modifier keys fire their own events with left/right distinction — `event.code` will be `"ShiftLeft"` or `"ShiftRight"`, while `event.key` gives the generic name `"Shift"`.
|
|
342
|
+
|
|
343
|
+
#### `isNativeKeyboardEvent(value)`
|
|
344
|
+
|
|
345
|
+
Type guard to check if a value is a `NativeKeyboardEvent`:
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
import { isNativeKeyboardEvent } from "ink-native";
|
|
349
|
+
|
|
350
|
+
window.on("keydown", (event) => {
|
|
351
|
+
if (isNativeKeyboardEvent(event)) {
|
|
352
|
+
// event is typed as NativeKeyboardEvent
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Terminal Sequences
|
|
358
|
+
|
|
359
|
+
In addition to `keydown`/`keyup` events, key presses are also mapped to terminal escape sequences and pushed to `stdin` for Ink's built-in key handling:
|
|
309
360
|
|
|
310
361
|
- Arrow keys (Up, Down, Left, Right)
|
|
311
362
|
- Enter, Escape, Backspace, Tab, Delete
|
|
@@ -327,6 +378,11 @@ import {
|
|
|
327
378
|
InputStream,
|
|
328
379
|
OutputStream,
|
|
329
380
|
|
|
381
|
+
// Keyboard events
|
|
382
|
+
createKeyboardEvent,
|
|
383
|
+
isNativeKeyboardEvent,
|
|
384
|
+
type NativeKeyboardEvent,
|
|
385
|
+
|
|
330
386
|
// Renderer
|
|
331
387
|
UiRenderer,
|
|
332
388
|
packColor,
|
|
@@ -123867,13 +123867,66 @@ var FENSTER_KEY_HOME = 2;
|
|
|
123867
123867
|
var FENSTER_KEY_PAGEUP = 3;
|
|
123868
123868
|
var FENSTER_KEY_PAGEDOWN = 4;
|
|
123869
123869
|
var FENSTER_KEY_END = 5;
|
|
123870
|
+
var FENSTER_KEY_INSERT = 26;
|
|
123870
123871
|
var FENSTER_KEY_A = 65;
|
|
123872
|
+
var FENSTER_KEY_B = 66;
|
|
123873
|
+
var FENSTER_KEY_C = 67;
|
|
123874
|
+
var FENSTER_KEY_D = 68;
|
|
123875
|
+
var FENSTER_KEY_E = 69;
|
|
123876
|
+
var FENSTER_KEY_F = 70;
|
|
123877
|
+
var FENSTER_KEY_G = 71;
|
|
123878
|
+
var FENSTER_KEY_H = 72;
|
|
123879
|
+
var FENSTER_KEY_I = 73;
|
|
123880
|
+
var FENSTER_KEY_J = 74;
|
|
123881
|
+
var FENSTER_KEY_K = 75;
|
|
123882
|
+
var FENSTER_KEY_L = 76;
|
|
123883
|
+
var FENSTER_KEY_M = 77;
|
|
123884
|
+
var FENSTER_KEY_N = 78;
|
|
123885
|
+
var FENSTER_KEY_O = 79;
|
|
123886
|
+
var FENSTER_KEY_P = 80;
|
|
123887
|
+
var FENSTER_KEY_Q = 81;
|
|
123888
|
+
var FENSTER_KEY_R = 82;
|
|
123889
|
+
var FENSTER_KEY_S = 83;
|
|
123890
|
+
var FENSTER_KEY_T = 84;
|
|
123891
|
+
var FENSTER_KEY_U = 85;
|
|
123892
|
+
var FENSTER_KEY_V = 86;
|
|
123893
|
+
var FENSTER_KEY_W = 87;
|
|
123894
|
+
var FENSTER_KEY_X = 88;
|
|
123895
|
+
var FENSTER_KEY_Y = 89;
|
|
123871
123896
|
var FENSTER_KEY_Z = 90;
|
|
123897
|
+
var FENSTER_KEY_0 = 48;
|
|
123898
|
+
var FENSTER_KEY_1 = 49;
|
|
123899
|
+
var FENSTER_KEY_2 = 50;
|
|
123900
|
+
var FENSTER_KEY_3 = 51;
|
|
123901
|
+
var FENSTER_KEY_4 = 52;
|
|
123902
|
+
var FENSTER_KEY_5 = 53;
|
|
123903
|
+
var FENSTER_KEY_6 = 54;
|
|
123904
|
+
var FENSTER_KEY_7 = 55;
|
|
123905
|
+
var FENSTER_KEY_8 = 56;
|
|
123906
|
+
var FENSTER_KEY_9 = 57;
|
|
123907
|
+
var FENSTER_KEY_APOSTROPHE = 39;
|
|
123908
|
+
var FENSTER_KEY_COMMA = 44;
|
|
123909
|
+
var FENSTER_KEY_MINUS = 45;
|
|
123910
|
+
var FENSTER_KEY_PERIOD = 46;
|
|
123911
|
+
var FENSTER_KEY_SLASH = 47;
|
|
123912
|
+
var FENSTER_KEY_SEMICOLON = 59;
|
|
123913
|
+
var FENSTER_KEY_EQUAL = 61;
|
|
123872
123914
|
var FENSTER_KEY_BRACKET_LEFT = 91;
|
|
123873
123915
|
var FENSTER_KEY_BACKSLASH = 92;
|
|
123874
123916
|
var FENSTER_KEY_BRACKET_RIGHT = 93;
|
|
123917
|
+
var FENSTER_KEY_GRAVE = 96;
|
|
123918
|
+
var FENSTER_KEY_SHIFT_LEFT = 128;
|
|
123919
|
+
var FENSTER_KEY_SHIFT_RIGHT = 129;
|
|
123920
|
+
var FENSTER_KEY_CONTROL_LEFT = 130;
|
|
123921
|
+
var FENSTER_KEY_CONTROL_RIGHT = 131;
|
|
123922
|
+
var FENSTER_KEY_ALT_LEFT = 132;
|
|
123923
|
+
var FENSTER_KEY_ALT_RIGHT = 133;
|
|
123924
|
+
var FENSTER_KEY_META_LEFT = 134;
|
|
123925
|
+
var FENSTER_KEY_META_RIGHT = 135;
|
|
123875
123926
|
var FENSTER_MOD_CTRL = 1;
|
|
123876
123927
|
var FENSTER_MOD_SHIFT = 2;
|
|
123928
|
+
var FENSTER_MOD_ALT = 4;
|
|
123929
|
+
var FENSTER_MOD_META = 8;
|
|
123877
123930
|
var KEYS_ARRAY_SIZE = 256;
|
|
123878
123931
|
var INT32_BYTES = 4;
|
|
123879
123932
|
var FENSTER_LIB_PATHS = {
|
|
@@ -123888,6 +123941,10 @@ var findFensterLibrary = () => {
|
|
|
123888
123941
|
if (!libName) {
|
|
123889
123942
|
return null;
|
|
123890
123943
|
}
|
|
123944
|
+
try {
|
|
123945
|
+
return fileURLToPath(import.meta.resolve(`ink-native/${libName}`));
|
|
123946
|
+
} catch {
|
|
123947
|
+
}
|
|
123891
123948
|
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
123892
123949
|
const projectRoot = resolve(currentDir, "../..");
|
|
123893
123950
|
return resolve(projectRoot, libName);
|
|
@@ -124134,9 +124191,249 @@ var InputStream = class extends Readable {
|
|
|
124134
124191
|
}
|
|
124135
124192
|
};
|
|
124136
124193
|
|
|
124194
|
+
// src/KeyboardEvent/consts.ts
|
|
124195
|
+
var FENSTER_TO_CODE = {
|
|
124196
|
+
// Navigation / control
|
|
124197
|
+
[FENSTER_KEY_BACKSPACE]: "Backspace",
|
|
124198
|
+
[FENSTER_KEY_TAB]: "Tab",
|
|
124199
|
+
[FENSTER_KEY_RETURN]: "Enter",
|
|
124200
|
+
[FENSTER_KEY_UP]: "ArrowUp",
|
|
124201
|
+
[FENSTER_KEY_DOWN]: "ArrowDown",
|
|
124202
|
+
[FENSTER_KEY_RIGHT]: "ArrowRight",
|
|
124203
|
+
[FENSTER_KEY_LEFT]: "ArrowLeft",
|
|
124204
|
+
[FENSTER_KEY_ESCAPE]: "Escape",
|
|
124205
|
+
[FENSTER_KEY_SPACE]: "Space",
|
|
124206
|
+
[FENSTER_KEY_DELETE]: "Delete",
|
|
124207
|
+
[FENSTER_KEY_HOME]: "Home",
|
|
124208
|
+
[FENSTER_KEY_PAGEUP]: "PageUp",
|
|
124209
|
+
[FENSTER_KEY_PAGEDOWN]: "PageDown",
|
|
124210
|
+
[FENSTER_KEY_END]: "End",
|
|
124211
|
+
[FENSTER_KEY_INSERT]: "Insert",
|
|
124212
|
+
// Letters (A-Z → KeyA-KeyZ)
|
|
124213
|
+
[FENSTER_KEY_A]: "KeyA",
|
|
124214
|
+
[FENSTER_KEY_B]: "KeyB",
|
|
124215
|
+
[FENSTER_KEY_C]: "KeyC",
|
|
124216
|
+
[FENSTER_KEY_D]: "KeyD",
|
|
124217
|
+
[FENSTER_KEY_E]: "KeyE",
|
|
124218
|
+
[FENSTER_KEY_F]: "KeyF",
|
|
124219
|
+
[FENSTER_KEY_G]: "KeyG",
|
|
124220
|
+
[FENSTER_KEY_H]: "KeyH",
|
|
124221
|
+
[FENSTER_KEY_I]: "KeyI",
|
|
124222
|
+
[FENSTER_KEY_J]: "KeyJ",
|
|
124223
|
+
[FENSTER_KEY_K]: "KeyK",
|
|
124224
|
+
[FENSTER_KEY_L]: "KeyL",
|
|
124225
|
+
[FENSTER_KEY_M]: "KeyM",
|
|
124226
|
+
[FENSTER_KEY_N]: "KeyN",
|
|
124227
|
+
[FENSTER_KEY_O]: "KeyO",
|
|
124228
|
+
[FENSTER_KEY_P]: "KeyP",
|
|
124229
|
+
[FENSTER_KEY_Q]: "KeyQ",
|
|
124230
|
+
[FENSTER_KEY_R]: "KeyR",
|
|
124231
|
+
[FENSTER_KEY_S]: "KeyS",
|
|
124232
|
+
[FENSTER_KEY_T]: "KeyT",
|
|
124233
|
+
[FENSTER_KEY_U]: "KeyU",
|
|
124234
|
+
[FENSTER_KEY_V]: "KeyV",
|
|
124235
|
+
[FENSTER_KEY_W]: "KeyW",
|
|
124236
|
+
[FENSTER_KEY_X]: "KeyX",
|
|
124237
|
+
[FENSTER_KEY_Y]: "KeyY",
|
|
124238
|
+
[FENSTER_KEY_Z]: "KeyZ",
|
|
124239
|
+
// Digits (0-9 → Digit0-Digit9)
|
|
124240
|
+
[FENSTER_KEY_0]: "Digit0",
|
|
124241
|
+
[FENSTER_KEY_1]: "Digit1",
|
|
124242
|
+
[FENSTER_KEY_2]: "Digit2",
|
|
124243
|
+
[FENSTER_KEY_3]: "Digit3",
|
|
124244
|
+
[FENSTER_KEY_4]: "Digit4",
|
|
124245
|
+
[FENSTER_KEY_5]: "Digit5",
|
|
124246
|
+
[FENSTER_KEY_6]: "Digit6",
|
|
124247
|
+
[FENSTER_KEY_7]: "Digit7",
|
|
124248
|
+
[FENSTER_KEY_8]: "Digit8",
|
|
124249
|
+
[FENSTER_KEY_9]: "Digit9",
|
|
124250
|
+
// Symbols
|
|
124251
|
+
[FENSTER_KEY_APOSTROPHE]: "Quote",
|
|
124252
|
+
[FENSTER_KEY_COMMA]: "Comma",
|
|
124253
|
+
[FENSTER_KEY_MINUS]: "Minus",
|
|
124254
|
+
[FENSTER_KEY_PERIOD]: "Period",
|
|
124255
|
+
[FENSTER_KEY_SLASH]: "Slash",
|
|
124256
|
+
[FENSTER_KEY_SEMICOLON]: "Semicolon",
|
|
124257
|
+
[FENSTER_KEY_EQUAL]: "Equal",
|
|
124258
|
+
[FENSTER_KEY_BRACKET_LEFT]: "BracketLeft",
|
|
124259
|
+
[FENSTER_KEY_BACKSLASH]: "Backslash",
|
|
124260
|
+
[FENSTER_KEY_BRACKET_RIGHT]: "BracketRight",
|
|
124261
|
+
[FENSTER_KEY_GRAVE]: "Backquote",
|
|
124262
|
+
// Modifier keys (left/right)
|
|
124263
|
+
[FENSTER_KEY_SHIFT_LEFT]: "ShiftLeft",
|
|
124264
|
+
[FENSTER_KEY_SHIFT_RIGHT]: "ShiftRight",
|
|
124265
|
+
[FENSTER_KEY_CONTROL_LEFT]: "ControlLeft",
|
|
124266
|
+
[FENSTER_KEY_CONTROL_RIGHT]: "ControlRight",
|
|
124267
|
+
[FENSTER_KEY_ALT_LEFT]: "AltLeft",
|
|
124268
|
+
[FENSTER_KEY_ALT_RIGHT]: "AltRight",
|
|
124269
|
+
[FENSTER_KEY_META_LEFT]: "MetaLeft",
|
|
124270
|
+
[FENSTER_KEY_META_RIGHT]: "MetaRight"
|
|
124271
|
+
};
|
|
124272
|
+
var FENSTER_TO_KEY = {
|
|
124273
|
+
// Navigation / control
|
|
124274
|
+
[FENSTER_KEY_BACKSPACE]: "Backspace",
|
|
124275
|
+
[FENSTER_KEY_TAB]: "Tab",
|
|
124276
|
+
[FENSTER_KEY_RETURN]: "Enter",
|
|
124277
|
+
[FENSTER_KEY_UP]: "ArrowUp",
|
|
124278
|
+
[FENSTER_KEY_DOWN]: "ArrowDown",
|
|
124279
|
+
[FENSTER_KEY_RIGHT]: "ArrowRight",
|
|
124280
|
+
[FENSTER_KEY_LEFT]: "ArrowLeft",
|
|
124281
|
+
[FENSTER_KEY_ESCAPE]: "Escape",
|
|
124282
|
+
[FENSTER_KEY_SPACE]: " ",
|
|
124283
|
+
[FENSTER_KEY_DELETE]: "Delete",
|
|
124284
|
+
[FENSTER_KEY_HOME]: "Home",
|
|
124285
|
+
[FENSTER_KEY_PAGEUP]: "PageUp",
|
|
124286
|
+
[FENSTER_KEY_PAGEDOWN]: "PageDown",
|
|
124287
|
+
[FENSTER_KEY_END]: "End",
|
|
124288
|
+
[FENSTER_KEY_INSERT]: "Insert",
|
|
124289
|
+
// Letters (A-Z → a-z lowercase)
|
|
124290
|
+
[FENSTER_KEY_A]: "a",
|
|
124291
|
+
[FENSTER_KEY_B]: "b",
|
|
124292
|
+
[FENSTER_KEY_C]: "c",
|
|
124293
|
+
[FENSTER_KEY_D]: "d",
|
|
124294
|
+
[FENSTER_KEY_E]: "e",
|
|
124295
|
+
[FENSTER_KEY_F]: "f",
|
|
124296
|
+
[FENSTER_KEY_G]: "g",
|
|
124297
|
+
[FENSTER_KEY_H]: "h",
|
|
124298
|
+
[FENSTER_KEY_I]: "i",
|
|
124299
|
+
[FENSTER_KEY_J]: "j",
|
|
124300
|
+
[FENSTER_KEY_K]: "k",
|
|
124301
|
+
[FENSTER_KEY_L]: "l",
|
|
124302
|
+
[FENSTER_KEY_M]: "m",
|
|
124303
|
+
[FENSTER_KEY_N]: "n",
|
|
124304
|
+
[FENSTER_KEY_O]: "o",
|
|
124305
|
+
[FENSTER_KEY_P]: "p",
|
|
124306
|
+
[FENSTER_KEY_Q]: "q",
|
|
124307
|
+
[FENSTER_KEY_R]: "r",
|
|
124308
|
+
[FENSTER_KEY_S]: "s",
|
|
124309
|
+
[FENSTER_KEY_T]: "t",
|
|
124310
|
+
[FENSTER_KEY_U]: "u",
|
|
124311
|
+
[FENSTER_KEY_V]: "v",
|
|
124312
|
+
[FENSTER_KEY_W]: "w",
|
|
124313
|
+
[FENSTER_KEY_X]: "x",
|
|
124314
|
+
[FENSTER_KEY_Y]: "y",
|
|
124315
|
+
[FENSTER_KEY_Z]: "z",
|
|
124316
|
+
// Digits (0-9)
|
|
124317
|
+
[FENSTER_KEY_0]: "0",
|
|
124318
|
+
[FENSTER_KEY_1]: "1",
|
|
124319
|
+
[FENSTER_KEY_2]: "2",
|
|
124320
|
+
[FENSTER_KEY_3]: "3",
|
|
124321
|
+
[FENSTER_KEY_4]: "4",
|
|
124322
|
+
[FENSTER_KEY_5]: "5",
|
|
124323
|
+
[FENSTER_KEY_6]: "6",
|
|
124324
|
+
[FENSTER_KEY_7]: "7",
|
|
124325
|
+
[FENSTER_KEY_8]: "8",
|
|
124326
|
+
[FENSTER_KEY_9]: "9",
|
|
124327
|
+
// Symbols (unshifted)
|
|
124328
|
+
[FENSTER_KEY_APOSTROPHE]: "'",
|
|
124329
|
+
[FENSTER_KEY_COMMA]: ",",
|
|
124330
|
+
[FENSTER_KEY_MINUS]: "-",
|
|
124331
|
+
[FENSTER_KEY_PERIOD]: ".",
|
|
124332
|
+
[FENSTER_KEY_SLASH]: "/",
|
|
124333
|
+
[FENSTER_KEY_SEMICOLON]: ";",
|
|
124334
|
+
[FENSTER_KEY_EQUAL]: "=",
|
|
124335
|
+
[FENSTER_KEY_BRACKET_LEFT]: "[",
|
|
124336
|
+
[FENSTER_KEY_BACKSLASH]: "\\",
|
|
124337
|
+
[FENSTER_KEY_BRACKET_RIGHT]: "]",
|
|
124338
|
+
[FENSTER_KEY_GRAVE]: "`",
|
|
124339
|
+
// Modifier keys (left/right)
|
|
124340
|
+
[FENSTER_KEY_SHIFT_LEFT]: "Shift",
|
|
124341
|
+
[FENSTER_KEY_SHIFT_RIGHT]: "Shift",
|
|
124342
|
+
[FENSTER_KEY_CONTROL_LEFT]: "Control",
|
|
124343
|
+
[FENSTER_KEY_CONTROL_RIGHT]: "Control",
|
|
124344
|
+
[FENSTER_KEY_ALT_LEFT]: "Alt",
|
|
124345
|
+
[FENSTER_KEY_ALT_RIGHT]: "Alt",
|
|
124346
|
+
[FENSTER_KEY_META_LEFT]: "Meta",
|
|
124347
|
+
[FENSTER_KEY_META_RIGHT]: "Meta"
|
|
124348
|
+
};
|
|
124349
|
+
var SHIFTED_KEY = {
|
|
124350
|
+
// Letters (a-z → A-Z)
|
|
124351
|
+
[FENSTER_KEY_A]: "A",
|
|
124352
|
+
[FENSTER_KEY_B]: "B",
|
|
124353
|
+
[FENSTER_KEY_C]: "C",
|
|
124354
|
+
[FENSTER_KEY_D]: "D",
|
|
124355
|
+
[FENSTER_KEY_E]: "E",
|
|
124356
|
+
[FENSTER_KEY_F]: "F",
|
|
124357
|
+
[FENSTER_KEY_G]: "G",
|
|
124358
|
+
[FENSTER_KEY_H]: "H",
|
|
124359
|
+
[FENSTER_KEY_I]: "I",
|
|
124360
|
+
[FENSTER_KEY_J]: "J",
|
|
124361
|
+
[FENSTER_KEY_K]: "K",
|
|
124362
|
+
[FENSTER_KEY_L]: "L",
|
|
124363
|
+
[FENSTER_KEY_M]: "M",
|
|
124364
|
+
[FENSTER_KEY_N]: "N",
|
|
124365
|
+
[FENSTER_KEY_O]: "O",
|
|
124366
|
+
[FENSTER_KEY_P]: "P",
|
|
124367
|
+
[FENSTER_KEY_Q]: "Q",
|
|
124368
|
+
[FENSTER_KEY_R]: "R",
|
|
124369
|
+
[FENSTER_KEY_S]: "S",
|
|
124370
|
+
[FENSTER_KEY_T]: "T",
|
|
124371
|
+
[FENSTER_KEY_U]: "U",
|
|
124372
|
+
[FENSTER_KEY_V]: "V",
|
|
124373
|
+
[FENSTER_KEY_W]: "W",
|
|
124374
|
+
[FENSTER_KEY_X]: "X",
|
|
124375
|
+
[FENSTER_KEY_Y]: "Y",
|
|
124376
|
+
[FENSTER_KEY_Z]: "Z",
|
|
124377
|
+
// Digits (0-9 → shifted symbols)
|
|
124378
|
+
[FENSTER_KEY_0]: ")",
|
|
124379
|
+
[FENSTER_KEY_1]: "!",
|
|
124380
|
+
[FENSTER_KEY_2]: "@",
|
|
124381
|
+
[FENSTER_KEY_3]: "#",
|
|
124382
|
+
[FENSTER_KEY_4]: "$",
|
|
124383
|
+
[FENSTER_KEY_5]: "%",
|
|
124384
|
+
[FENSTER_KEY_6]: "^",
|
|
124385
|
+
[FENSTER_KEY_7]: "&",
|
|
124386
|
+
[FENSTER_KEY_8]: "*",
|
|
124387
|
+
[FENSTER_KEY_9]: "(",
|
|
124388
|
+
// Symbols (shifted)
|
|
124389
|
+
[FENSTER_KEY_APOSTROPHE]: '"',
|
|
124390
|
+
[FENSTER_KEY_COMMA]: "<",
|
|
124391
|
+
[FENSTER_KEY_MINUS]: "_",
|
|
124392
|
+
[FENSTER_KEY_PERIOD]: ">",
|
|
124393
|
+
[FENSTER_KEY_SLASH]: "?",
|
|
124394
|
+
[FENSTER_KEY_SEMICOLON]: ":",
|
|
124395
|
+
[FENSTER_KEY_EQUAL]: "+",
|
|
124396
|
+
[FENSTER_KEY_BRACKET_LEFT]: "{",
|
|
124397
|
+
[FENSTER_KEY_BACKSLASH]: "|",
|
|
124398
|
+
[FENSTER_KEY_BRACKET_RIGHT]: "}",
|
|
124399
|
+
[FENSTER_KEY_GRAVE]: "~"
|
|
124400
|
+
};
|
|
124401
|
+
|
|
124402
|
+
// src/KeyboardEvent/types.ts
|
|
124403
|
+
import { isBoolean, isPlainObject, isString } from "remeda";
|
|
124404
|
+
var isNativeKeyboardEvent = (value) => {
|
|
124405
|
+
if (!isPlainObject(value)) {
|
|
124406
|
+
return false;
|
|
124407
|
+
}
|
|
124408
|
+
return isString(value["key"]) && isString(value["code"]) && isBoolean(value["ctrlKey"]) && isBoolean(value["shiftKey"]) && isBoolean(value["altKey"]) && isBoolean(value["metaKey"]) && value["repeat"] === false && (value["type"] === "keydown" || value["type"] === "keyup");
|
|
124409
|
+
};
|
|
124410
|
+
|
|
124411
|
+
// src/KeyboardEvent/index.ts
|
|
124412
|
+
var createKeyboardEvent = (event, mod) => {
|
|
124413
|
+
const code = FENSTER_TO_CODE[event.keyIndex];
|
|
124414
|
+
if (code === void 0) {
|
|
124415
|
+
return null;
|
|
124416
|
+
}
|
|
124417
|
+
const shiftKey = (mod & FENSTER_MOD_SHIFT) !== 0;
|
|
124418
|
+
const key = (shiftKey ? SHIFTED_KEY[event.keyIndex] : void 0) ?? FENSTER_TO_KEY[event.keyIndex];
|
|
124419
|
+
if (key === void 0) {
|
|
124420
|
+
return null;
|
|
124421
|
+
}
|
|
124422
|
+
return {
|
|
124423
|
+
key,
|
|
124424
|
+
code,
|
|
124425
|
+
ctrlKey: (mod & FENSTER_MOD_CTRL) !== 0,
|
|
124426
|
+
shiftKey,
|
|
124427
|
+
altKey: (mod & FENSTER_MOD_ALT) !== 0,
|
|
124428
|
+
metaKey: (mod & FENSTER_MOD_META) !== 0,
|
|
124429
|
+
repeat: false,
|
|
124430
|
+
type: event.pressed ? "keydown" : "keyup"
|
|
124431
|
+
};
|
|
124432
|
+
};
|
|
124433
|
+
|
|
124137
124434
|
// src/OutputStream/index.ts
|
|
124138
124435
|
import { Writable } from "stream";
|
|
124139
|
-
import { isString } from "remeda";
|
|
124436
|
+
import { isString as isString2 } from "remeda";
|
|
124140
124437
|
|
|
124141
124438
|
// src/OutputStream/consts.ts
|
|
124142
124439
|
var DEFAULT_COLUMNS = 80;
|
|
@@ -124178,7 +124475,7 @@ var OutputStream = class extends Writable {
|
|
|
124178
124475
|
*/
|
|
124179
124476
|
_write(chunk, _encoding, callback) {
|
|
124180
124477
|
try {
|
|
124181
|
-
const text =
|
|
124478
|
+
const text = isString2(chunk) ? chunk : chunk.toString("utf8");
|
|
124182
124479
|
this.uiRenderer.processAnsi(text);
|
|
124183
124480
|
this.uiRenderer.present();
|
|
124184
124481
|
callback(null);
|
|
@@ -124233,9 +124530,53 @@ var FENSTER_REFRESH_RATE = 60;
|
|
|
124233
124530
|
var ALPHA_MASK = 4278190080;
|
|
124234
124531
|
var RED_SHIFT = 16;
|
|
124235
124532
|
var GREEN_SHIFT = 8;
|
|
124236
|
-
var CTRL_KEY_OFFSET =
|
|
124533
|
+
var CTRL_KEY_OFFSET = 64;
|
|
124237
124534
|
var ASCII_PRINTABLE_START = 32;
|
|
124238
124535
|
var ASCII_PRINTABLE_END = 126;
|
|
124536
|
+
var SHIFTED_SYMBOLS = {
|
|
124537
|
+
48: ")",
|
|
124538
|
+
// 0 → )
|
|
124539
|
+
49: "!",
|
|
124540
|
+
// 1 → !
|
|
124541
|
+
50: "@",
|
|
124542
|
+
// 2 → @
|
|
124543
|
+
51: "#",
|
|
124544
|
+
// 3 → #
|
|
124545
|
+
52: "$",
|
|
124546
|
+
// 4 → $
|
|
124547
|
+
53: "%",
|
|
124548
|
+
// 5 → %
|
|
124549
|
+
54: "^",
|
|
124550
|
+
// 6 → ^
|
|
124551
|
+
55: "&",
|
|
124552
|
+
// 7 → &
|
|
124553
|
+
56: "*",
|
|
124554
|
+
// 8 → *
|
|
124555
|
+
57: "(",
|
|
124556
|
+
// 9 → (
|
|
124557
|
+
45: "_",
|
|
124558
|
+
// - → _
|
|
124559
|
+
61: "+",
|
|
124560
|
+
// = → +
|
|
124561
|
+
91: "{",
|
|
124562
|
+
// [ → {
|
|
124563
|
+
93: "}",
|
|
124564
|
+
// ] → }
|
|
124565
|
+
92: "|",
|
|
124566
|
+
// \ → |
|
|
124567
|
+
59: ":",
|
|
124568
|
+
// ; → :
|
|
124569
|
+
39: '"',
|
|
124570
|
+
// ' → "
|
|
124571
|
+
96: "~",
|
|
124572
|
+
// ` → ~
|
|
124573
|
+
44: "<",
|
|
124574
|
+
// , → <
|
|
124575
|
+
46: ">",
|
|
124576
|
+
// . → >
|
|
124577
|
+
47: "?"
|
|
124578
|
+
// / → ?
|
|
124579
|
+
};
|
|
124239
124580
|
|
|
124240
124581
|
// src/UiRenderer/index.ts
|
|
124241
124582
|
var packColor = (r, g, b) => (ALPHA_MASK | r << RED_SHIFT | g << GREEN_SHIFT | b) >>> 0;
|
|
@@ -124471,6 +124812,8 @@ var UiRenderer = class {
|
|
|
124471
124812
|
return shift ? "\x1B[Z" : " ";
|
|
124472
124813
|
case FENSTER_KEY_DELETE:
|
|
124473
124814
|
return "\x1B[3~";
|
|
124815
|
+
case FENSTER_KEY_INSERT:
|
|
124816
|
+
return "\x1B[2~";
|
|
124474
124817
|
case FENSTER_KEY_SPACE:
|
|
124475
124818
|
return ctrl ? "\0" : " ";
|
|
124476
124819
|
}
|
|
@@ -124489,11 +124832,16 @@ var UiRenderer = class {
|
|
|
124489
124832
|
}
|
|
124490
124833
|
}
|
|
124491
124834
|
if (key >= ASCII_PRINTABLE_START && key <= ASCII_PRINTABLE_END) {
|
|
124492
|
-
|
|
124493
|
-
|
|
124494
|
-
char = char.toUpperCase();
|
|
124835
|
+
if (key >= FENSTER_KEY_A && key <= FENSTER_KEY_Z) {
|
|
124836
|
+
return shift ? String.fromCharCode(key) : String.fromCharCode(key).toLowerCase();
|
|
124495
124837
|
}
|
|
124496
|
-
|
|
124838
|
+
if (shift) {
|
|
124839
|
+
const shifted = SHIFTED_SYMBOLS[key];
|
|
124840
|
+
if (shifted) {
|
|
124841
|
+
return shifted;
|
|
124842
|
+
}
|
|
124843
|
+
}
|
|
124844
|
+
return String.fromCharCode(key);
|
|
124497
124845
|
}
|
|
124498
124846
|
return null;
|
|
124499
124847
|
}
|
|
@@ -124771,18 +125119,28 @@ var Window = class extends EventEmitter {
|
|
|
124771
125119
|
}
|
|
124772
125120
|
const { keyEvents, mod, resized } = this.renderer.processEventsAndPresent();
|
|
124773
125121
|
for (const event of keyEvents) {
|
|
124774
|
-
const
|
|
124775
|
-
if (
|
|
124776
|
-
|
|
124777
|
-
|
|
124778
|
-
|
|
124779
|
-
|
|
124780
|
-
|
|
125122
|
+
const kbEvent = createKeyboardEvent(event, mod);
|
|
125123
|
+
if (event.pressed) {
|
|
125124
|
+
const sequence = this.renderer.keyEventToSequence(event, mod);
|
|
125125
|
+
if (sequence) {
|
|
125126
|
+
if (sequence === "") {
|
|
125127
|
+
if (this.listenerCount("sigint") > 0) {
|
|
125128
|
+
this.emit("sigint");
|
|
125129
|
+
} else {
|
|
125130
|
+
process.kill(process.pid, "SIGINT");
|
|
125131
|
+
}
|
|
125132
|
+
if (kbEvent) {
|
|
125133
|
+
this.emit("keydown", kbEvent);
|
|
125134
|
+
}
|
|
125135
|
+
continue;
|
|
124781
125136
|
}
|
|
124782
|
-
|
|
125137
|
+
this.inputStream.pushKey(sequence);
|
|
125138
|
+
}
|
|
125139
|
+
if (kbEvent) {
|
|
125140
|
+
this.emit("keydown", kbEvent);
|
|
124783
125141
|
}
|
|
124784
|
-
|
|
124785
|
-
this.emit("
|
|
125142
|
+
} else if (kbEvent) {
|
|
125143
|
+
this.emit("keyup", kbEvent);
|
|
124786
125144
|
}
|
|
124787
125145
|
}
|
|
124788
125146
|
if (resized) {
|
|
@@ -124907,6 +125265,8 @@ export {
|
|
|
124907
125265
|
getFenster,
|
|
124908
125266
|
isFensterAvailable,
|
|
124909
125267
|
InputStream,
|
|
125268
|
+
isNativeKeyboardEvent,
|
|
125269
|
+
createKeyboardEvent,
|
|
124910
125270
|
OutputStream,
|
|
124911
125271
|
packColor,
|
|
124912
125272
|
UiRenderer,
|
package/dist/cli.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -324,6 +324,36 @@ declare class InputStream extends Readable {
|
|
|
324
324
|
unref(): this;
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
+
/** Keyboard event from the native window */
|
|
328
|
+
interface NativeKeyboardEvent {
|
|
329
|
+
/** Key value: "a", "A", "Enter", "ArrowUp", "!" */
|
|
330
|
+
readonly key: string;
|
|
331
|
+
/** Physical key code: "KeyA", "Digit1", "ArrowUp" */
|
|
332
|
+
readonly code: string;
|
|
333
|
+
readonly ctrlKey: boolean;
|
|
334
|
+
readonly shiftKey: boolean;
|
|
335
|
+
readonly altKey: boolean;
|
|
336
|
+
readonly metaKey: boolean;
|
|
337
|
+
/** Always false — fenster only reports transitions, not held state */
|
|
338
|
+
readonly repeat: false;
|
|
339
|
+
readonly type: "keydown" | "keyup";
|
|
340
|
+
}
|
|
341
|
+
declare const isNativeKeyboardEvent: (value: unknown) => value is NativeKeyboardEvent;
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* KeyboardEvent
|
|
345
|
+
*
|
|
346
|
+
* Converts fenster key events into NativeKeyboardEvent objects,
|
|
347
|
+
* providing keydown/keyup events for games and interactive apps.
|
|
348
|
+
*/
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Create a NativeKeyboardEvent from a fenster key event and modifier bitmask.
|
|
352
|
+
*
|
|
353
|
+
* Returns null for unmapped key indices.
|
|
354
|
+
*/
|
|
355
|
+
declare const createKeyboardEvent: (event: FensterKeyEvent, mod: number) => NativeKeyboardEvent | null;
|
|
356
|
+
|
|
327
357
|
/**
|
|
328
358
|
* OutputStream Types
|
|
329
359
|
*/
|
|
@@ -711,4 +741,4 @@ declare class Window extends EventEmitter {
|
|
|
711
741
|
*/
|
|
712
742
|
declare const createStreams: (options?: StreamsOptions) => Streams;
|
|
713
743
|
|
|
714
|
-
export { AnsiParser, BitmapFontRenderer, type Color, type DrawCommand, Fenster, type FensterKeyEvent, type FensterPointer, type Framebuffer, InputStream, OutputStream, type ProcessEventsResult, type Streams, type StreamsOptions, UiRenderer, type UiRendererOptions, Window, createStreams, getFenster, isFensterAvailable, packColor };
|
|
744
|
+
export { AnsiParser, BitmapFontRenderer, type Color, type DrawCommand, Fenster, type FensterKeyEvent, type FensterPointer, type Framebuffer, InputStream, type NativeKeyboardEvent, OutputStream, type ProcessEventsResult, type Streams, type StreamsOptions, UiRenderer, type UiRendererOptions, Window, createKeyboardEvent, createStreams, getFenster, isFensterAvailable, isNativeKeyboardEvent, packColor };
|
package/dist/index.js
CHANGED
|
@@ -6,11 +6,13 @@ import {
|
|
|
6
6
|
OutputStream,
|
|
7
7
|
UiRenderer,
|
|
8
8
|
Window,
|
|
9
|
+
createKeyboardEvent,
|
|
9
10
|
createStreams,
|
|
10
11
|
getFenster,
|
|
11
12
|
isFensterAvailable,
|
|
13
|
+
isNativeKeyboardEvent,
|
|
12
14
|
packColor
|
|
13
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-5O6OVITA.js";
|
|
14
16
|
export {
|
|
15
17
|
AnsiParser,
|
|
16
18
|
BitmapFontRenderer,
|
|
@@ -19,8 +21,10 @@ export {
|
|
|
19
21
|
OutputStream,
|
|
20
22
|
UiRenderer,
|
|
21
23
|
Window,
|
|
24
|
+
createKeyboardEvent,
|
|
22
25
|
createStreams,
|
|
23
26
|
getFenster,
|
|
24
27
|
isFensterAvailable,
|
|
28
|
+
isNativeKeyboardEvent,
|
|
25
29
|
packColor
|
|
26
30
|
};
|
package/native/fenster.dylib
CHANGED
|
Binary file
|
package/native/fenster.h
CHANGED
|
@@ -172,6 +172,24 @@ FENSTER_API int fenster_loop(struct fenster *f) {
|
|
|
172
172
|
f->mod = (mod & 0xc) | ((mod & 1) << 1) | ((mod >> 1) & 1);
|
|
173
173
|
return 0;
|
|
174
174
|
}
|
|
175
|
+
case 12: { /* NSEventTypeFlagsChanged — modifier key press/release */
|
|
176
|
+
NSUInteger k = msg(NSUInteger, ev, "keyCode");
|
|
177
|
+
NSUInteger flags = msg(NSUInteger, ev, "modifierFlags");
|
|
178
|
+
NSUInteger mod = flags >> 17;
|
|
179
|
+
f->mod = (mod & 0xc) | ((mod & 1) << 1) | ((mod >> 1) & 1);
|
|
180
|
+
/* Device-dependent flags distinguish left/right modifiers */
|
|
181
|
+
switch (k) {
|
|
182
|
+
case 56: f->keys[128] = !!(flags & 0x00000002); break; /* Left Shift */
|
|
183
|
+
case 60: f->keys[129] = !!(flags & 0x00000004); break; /* Right Shift */
|
|
184
|
+
case 59: f->keys[130] = !!(flags & 0x00000001); break; /* Left Control */
|
|
185
|
+
case 62: f->keys[131] = !!(flags & 0x00002000); break; /* Right Control */
|
|
186
|
+
case 58: f->keys[132] = !!(flags & 0x00000020); break; /* Left Alt */
|
|
187
|
+
case 61: f->keys[133] = !!(flags & 0x00000040); break; /* Right Alt */
|
|
188
|
+
case 55: f->keys[134] = !!(flags & 0x00000008); break; /* Left Meta */
|
|
189
|
+
case 54: f->keys[135] = !!(flags & 0x00000010); break; /* Right Meta */
|
|
190
|
+
}
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
175
193
|
}
|
|
176
194
|
msg1(void, NSApp, "sendEvent:", id, ev);
|
|
177
195
|
/* Poll content view frame for resize */
|
|
@@ -240,7 +258,17 @@ static LRESULT CALLBACK fenster_wndproc(HWND hwnd, UINT msg, WPARAM wParam,
|
|
|
240
258
|
((GetKeyState(VK_SHIFT) & 0x8000) >> 14) |
|
|
241
259
|
((GetKeyState(VK_MENU) & 0x8000) >> 13) |
|
|
242
260
|
(((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000) >> 12);
|
|
243
|
-
|
|
261
|
+
int pressed = !((lParam >> 31) & 1);
|
|
262
|
+
f->keys[FENSTER_KEYCODES[HIWORD(lParam) & 0x1ff]] = pressed;
|
|
263
|
+
/* Left/right modifier key tracking */
|
|
264
|
+
f->keys[128] = !!(GetKeyState(VK_LSHIFT) & 0x8000);
|
|
265
|
+
f->keys[129] = !!(GetKeyState(VK_RSHIFT) & 0x8000);
|
|
266
|
+
f->keys[130] = !!(GetKeyState(VK_LCONTROL) & 0x8000);
|
|
267
|
+
f->keys[131] = !!(GetKeyState(VK_RCONTROL) & 0x8000);
|
|
268
|
+
f->keys[132] = !!(GetKeyState(VK_LMENU) & 0x8000);
|
|
269
|
+
f->keys[133] = !!(GetKeyState(VK_RMENU) & 0x8000);
|
|
270
|
+
f->keys[134] = !!(GetKeyState(VK_LWIN) & 0x8000);
|
|
271
|
+
f->keys[135] = !!(GetKeyState(VK_RWIN) & 0x8000);
|
|
244
272
|
} break;
|
|
245
273
|
case WM_SIZE:
|
|
246
274
|
f->width = LOWORD(lParam);
|
|
@@ -320,7 +348,7 @@ FENSTER_API int fenster_loop(struct fenster *f) {
|
|
|
320
348
|
}
|
|
321
349
|
#else
|
|
322
350
|
// clang-format off
|
|
323
|
-
static int FENSTER_KEYCODES[
|
|
351
|
+
static int FENSTER_KEYCODES[140] = {XK_BackSpace,8,XK_Delete,127,XK_Down,18,XK_End,5,XK_Escape,27,XK_Home,2,XK_Insert,26,XK_Left,20,XK_Page_Down,4,XK_Page_Up,3,XK_Return,10,XK_Right,19,XK_Tab,9,XK_Up,17,XK_apostrophe,39,XK_backslash,92,XK_bracketleft,91,XK_bracketright,93,XK_comma,44,XK_equal,61,XK_grave,96,XK_minus,45,XK_period,46,XK_semicolon,59,XK_slash,47,XK_space,32,XK_a,65,XK_b,66,XK_c,67,XK_d,68,XK_e,69,XK_f,70,XK_g,71,XK_h,72,XK_i,73,XK_j,74,XK_k,75,XK_l,76,XK_m,77,XK_n,78,XK_o,79,XK_p,80,XK_q,81,XK_r,82,XK_s,83,XK_t,84,XK_u,85,XK_v,86,XK_w,87,XK_x,88,XK_y,89,XK_z,90,XK_0,48,XK_1,49,XK_2,50,XK_3,51,XK_4,52,XK_5,53,XK_6,54,XK_7,55,XK_8,56,XK_9,57,XK_Shift_L,128,XK_Shift_R,129,XK_Control_L,130,XK_Control_R,131,XK_Alt_L,132,XK_Alt_R,133,XK_Super_L,134,XK_Super_R,135};
|
|
324
352
|
// clang-format on
|
|
325
353
|
FENSTER_API int fenster_open(struct fenster *f) {
|
|
326
354
|
f->dpy = XOpenDisplay(NULL);
|
|
@@ -363,7 +391,7 @@ FENSTER_API int fenster_loop(struct fenster *f) {
|
|
|
363
391
|
case KeyRelease: {
|
|
364
392
|
int m = ev.xkey.state;
|
|
365
393
|
int k = XkbKeycodeToKeysym(f->dpy, ev.xkey.keycode, 0, 0);
|
|
366
|
-
for (unsigned int i = 0; i <
|
|
394
|
+
for (unsigned int i = 0; i < 140; i += 2) {
|
|
367
395
|
if (FENSTER_KEYCODES[i] == k) {
|
|
368
396
|
f->keys[FENSTER_KEYCODES[i + 1]] = (ev.type == KeyPress);
|
|
369
397
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ink-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Render Ink terminal apps in a native window",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
".": {
|
|
10
10
|
"import": "./dist/index.js",
|
|
11
11
|
"types": "./dist/index.d.ts"
|
|
12
|
-
}
|
|
12
|
+
},
|
|
13
|
+
"./native/*": "./native/*"
|
|
13
14
|
},
|
|
14
15
|
"bin": {
|
|
15
16
|
"ink-native": "./dist/cli.js"
|