coneko-term 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/dist/animation.d.ts +18 -0
- package/dist/animation.js +72 -0
- package/dist/images.d.ts +116 -0
- package/dist/images.js +359 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +21 -0
- package/dist/input.d.ts +130 -0
- package/dist/input.js +313 -0
- package/dist/keyboard.d.ts +46 -0
- package/dist/keyboard.js +278 -0
- package/dist/kitty-keyboard.d.ts +55 -0
- package/dist/kitty-keyboard.js +332 -0
- package/dist/memory.d.ts +4 -0
- package/dist/memory.js +12 -0
- package/dist/renderer.d.ts +261 -0
- package/dist/renderer.js +870 -0
- package/dist/selection.d.ts +67 -0
- package/dist/selection.js +146 -0
- package/dist/terminal.d.ts +1006 -0
- package/dist/terminal.js +2020 -0
- package/dist/wasm/coneko_term_wasm.d.ts +728 -0
- package/dist/wasm/coneko_term_wasm.js +1776 -0
- package/dist/wasm/coneko_term_wasm_bg.wasm +0 -0
- package/dist/wasm/coneko_term_wasm_bg.wasm.d.ts +140 -0
- package/package.json +33 -4
- package/README.md +0 -3
package/dist/keyboard.js
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
// キーを PTY へ送るバイト列にする。xterm.js 6.0.0 の `src/common/input/Keyboard.ts`
|
|
2
|
+
// (`evaluateKeyboardEvent`)と同じ値を返す。xterm.js と同じく `keyCode` で決める。
|
|
3
|
+
import { formatKittyKey, KITTY_DISAMBIGUATE, KITTY_REPORT_ALL_KEYS, KITTY_REPORT_EVENT_TYPES, kittyKeyOf, MOD_ALT, MOD_CTRL, MOD_SHIFT, MOD_SUPER, } from "./kitty-keyboard.js";
|
|
4
|
+
export { KITTY_DISAMBIGUATE, KITTY_REPORT_ALL_KEYS, KITTY_REPORT_ALTERNATE_KEYS, KITTY_REPORT_EVENT_TYPES, KITTY_REPORT_TEXT, } from "./kitty-keyboard.js";
|
|
5
|
+
const ESC = "\x1b";
|
|
6
|
+
// 数字と記号のキーの、そのまま・Shift つきの字
|
|
7
|
+
const KEYCODE_KEY_MAPPINGS = {
|
|
8
|
+
48: ["0", ")"],
|
|
9
|
+
49: ["1", "!"],
|
|
10
|
+
50: ["2", "@"],
|
|
11
|
+
51: ["3", "#"],
|
|
12
|
+
52: ["4", "$"],
|
|
13
|
+
53: ["5", "%"],
|
|
14
|
+
54: ["6", "^"],
|
|
15
|
+
55: ["7", "&"],
|
|
16
|
+
56: ["8", "*"],
|
|
17
|
+
57: ["9", "("],
|
|
18
|
+
186: [";", ":"],
|
|
19
|
+
187: ["=", "+"],
|
|
20
|
+
188: [",", "<"],
|
|
21
|
+
189: ["-", "_"],
|
|
22
|
+
190: [".", ">"],
|
|
23
|
+
191: ["/", "?"],
|
|
24
|
+
192: ["`", "~"],
|
|
25
|
+
219: ["[", "{"],
|
|
26
|
+
220: ["\\", "|"],
|
|
27
|
+
221: ["]", "}"],
|
|
28
|
+
222: ["'", '"'],
|
|
29
|
+
};
|
|
30
|
+
// F1〜F4 は `SS3 P`〜`SS3 S`(修飾キーつきは `CSI 1;m P`〜`S`)、F5〜F12 は `CSI n ~`
|
|
31
|
+
const FUNCTION_KEYS = {
|
|
32
|
+
112: ["P", true],
|
|
33
|
+
113: ["Q", true],
|
|
34
|
+
114: ["R", true],
|
|
35
|
+
115: ["S", true],
|
|
36
|
+
116: [15, false],
|
|
37
|
+
117: [17, false],
|
|
38
|
+
118: [18, false],
|
|
39
|
+
119: [19, false],
|
|
40
|
+
120: [20, false],
|
|
41
|
+
121: [21, false],
|
|
42
|
+
122: [23, false],
|
|
43
|
+
123: [24, false],
|
|
44
|
+
};
|
|
45
|
+
/** 矢印・Home・End。修飾キーが無ければ、アプリケーションカーソルキーで `SS3`、そうでなければ `CSI`。 */
|
|
46
|
+
function cursorKey(letter, modifiers, applicationCursorMode) {
|
|
47
|
+
if (modifiers)
|
|
48
|
+
return `${ESC}[1;${modifiers + 1}${letter}`;
|
|
49
|
+
return applicationCursorMode ? `${ESC}O${letter}` : `${ESC}[${letter}`;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* キーが押された(離された)とき、PTY へ送る文字列を決める。kitty のフラグが 0 なら、
|
|
53
|
+
* xterm.js 6.0.0 の `evaluateKeyboardEvent` と同じ。
|
|
54
|
+
*
|
|
55
|
+
* - `applicationCursorMode`: DECCKM(#5)。矢印・Home・End が `CSI` か `SS3` かを決める。
|
|
56
|
+
* - `kittyFlags`: kitty keyboard protocol のフラグ(`Terminal.keyboardFlags`)。
|
|
57
|
+
* - 1: Esc や、Ctrl・Alt つきの字などを `CSI ... u` で送る。
|
|
58
|
+
* - 2: `eventType` を `CSI` の形で送る(繰り返し・離す)。
|
|
59
|
+
* - 4: `CSI` の形の字のキーに、Shift をかけた字とベースのレイアウトの字を添える。
|
|
60
|
+
* - 8: すべてのキー(字・Enter・Tab・修飾キーだけ…)を `CSI` の形で送る。
|
|
61
|
+
* - 16: フラグ 8 のとき、字を作るキーにその字を添える。
|
|
62
|
+
* - `eventType`: 1 押す、2 繰り返し、3 離す。フラグ 2 が無ければ無視する(繰り返しも押すとして扱う)。
|
|
63
|
+
* 離すときは、`CSI` の形で送るキーだけ `key` が入る。Enter・Tab・Backspace の離すは、フラグ 8 のときだけ。
|
|
64
|
+
* - `isMac`: macOS か。Option は `macOptionIsMeta` が false なら字を打つキーとして扱い、ここでは送らない。
|
|
65
|
+
* - Cmd(`metaKey`)つきのキーをアプリに任せるかどうかは呼ぶ側が決める(`KeyHandler` が送らない)。
|
|
66
|
+
*/
|
|
67
|
+
export function evaluateKeyboardEvent(ev, applicationCursorMode, isMac, macOptionIsMeta, kittyFlags = 0, eventType = 1) {
|
|
68
|
+
const modifiers = (ev.shiftKey ? MOD_SHIFT : 0) |
|
|
69
|
+
(ev.altKey ? MOD_ALT : 0) |
|
|
70
|
+
(ev.ctrlKey ? MOD_CTRL : 0) |
|
|
71
|
+
(ev.metaKey ? MOD_SUPER : 0);
|
|
72
|
+
const legacy = () => legacyKeyboardEvent(ev, applicationCursorMode, isMac, macOptionIsMeta, modifiers);
|
|
73
|
+
const all = (kittyFlags & KITTY_REPORT_ALL_KEYS) !== 0;
|
|
74
|
+
if (!(kittyFlags & (KITTY_DISAMBIGUATE | KITTY_REPORT_EVENT_TYPES | KITTY_REPORT_ALL_KEYS))) {
|
|
75
|
+
return legacy();
|
|
76
|
+
}
|
|
77
|
+
const et = kittyFlags & KITTY_REPORT_EVENT_TYPES ? eventType : 1;
|
|
78
|
+
const nothing = () => ({ type: "send", cancel: false, key: undefined });
|
|
79
|
+
const k = kittyKeyOf(ev, modifiers, kittyFlags, isMac, macOptionIsMeta);
|
|
80
|
+
if (!k)
|
|
81
|
+
return et === 3 ? nothing() : legacy();
|
|
82
|
+
// Enter・Tab・Backspace の離すは、フラグ 8 のときだけ(プログラムが戻さずに終わっても、
|
|
83
|
+
// シェルで reset と打てるように)
|
|
84
|
+
if (et === 3 && !all && k.final === "u" && (k.num === 13 || k.num === 9 || k.num === 127)) {
|
|
85
|
+
return nothing();
|
|
86
|
+
}
|
|
87
|
+
if (k.final !== "u") {
|
|
88
|
+
// 矢印・Home・F5 など。従来は送らないもの(Shift+PageUp のスクロール、Ctrl・Shift+Insert、
|
|
89
|
+
// Cmd+矢印)は、フラグがあっても送らない
|
|
90
|
+
const l = legacy();
|
|
91
|
+
if (l.key === undefined)
|
|
92
|
+
return et === 3 ? nothing() : l;
|
|
93
|
+
if (et === 1 && !all && !k.escapedOnPress)
|
|
94
|
+
return l;
|
|
95
|
+
}
|
|
96
|
+
return { type: "send", cancel: true, key: formatKittyKey(k, modifiers, et) };
|
|
97
|
+
}
|
|
98
|
+
function legacyKeyboardEvent(ev, applicationCursorMode, isMac, macOptionIsMeta, modifiers) {
|
|
99
|
+
const result = { type: "send", cancel: false, key: undefined };
|
|
100
|
+
switch (ev.keyCode) {
|
|
101
|
+
case 0: {
|
|
102
|
+
// iOS の矢印
|
|
103
|
+
const letter = {
|
|
104
|
+
UIKeyInputUpArrow: "A",
|
|
105
|
+
UIKeyInputDownArrow: "B",
|
|
106
|
+
UIKeyInputRightArrow: "C",
|
|
107
|
+
UIKeyInputLeftArrow: "D",
|
|
108
|
+
}[ev.key];
|
|
109
|
+
if (letter)
|
|
110
|
+
result.key = cursorKey(letter, 0, applicationCursorMode);
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
case 8:
|
|
114
|
+
// Backspace: ^H か ^?
|
|
115
|
+
result.key = ev.ctrlKey ? "\b" : "\x7f";
|
|
116
|
+
if (ev.altKey)
|
|
117
|
+
result.key = ESC + result.key;
|
|
118
|
+
break;
|
|
119
|
+
case 9:
|
|
120
|
+
// Tab
|
|
121
|
+
if (ev.shiftKey) {
|
|
122
|
+
result.key = `${ESC}[Z`;
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
result.key = "\t";
|
|
126
|
+
result.cancel = true;
|
|
127
|
+
break;
|
|
128
|
+
case 13:
|
|
129
|
+
// Enter
|
|
130
|
+
result.key = ev.altKey ? `${ESC}\r` : "\r";
|
|
131
|
+
result.cancel = true;
|
|
132
|
+
break;
|
|
133
|
+
case 27:
|
|
134
|
+
// Esc
|
|
135
|
+
result.key = ev.altKey ? ESC + ESC : ESC;
|
|
136
|
+
result.cancel = true;
|
|
137
|
+
break;
|
|
138
|
+
case 37: // 左
|
|
139
|
+
case 38: // 上
|
|
140
|
+
case 39: // 右
|
|
141
|
+
case 40: // 下
|
|
142
|
+
if (ev.metaKey)
|
|
143
|
+
break;
|
|
144
|
+
result.key = cursorKey({ 37: "D", 38: "A", 39: "C", 40: "B" }[ev.keyCode], modifiers, applicationCursorMode);
|
|
145
|
+
break;
|
|
146
|
+
case 45:
|
|
147
|
+
// Insert。Ctrl・Shift つきはコピーと貼り付けに使われることがあるので送らない
|
|
148
|
+
if (!ev.shiftKey && !ev.ctrlKey)
|
|
149
|
+
result.key = `${ESC}[2~`;
|
|
150
|
+
break;
|
|
151
|
+
case 46:
|
|
152
|
+
// Delete
|
|
153
|
+
result.key = modifiers
|
|
154
|
+
? `${ESC}[3;${modifiers + 1}~`
|
|
155
|
+
: `${ESC}[3~`;
|
|
156
|
+
break;
|
|
157
|
+
case 36:
|
|
158
|
+
result.key = cursorKey("H", modifiers, applicationCursorMode);
|
|
159
|
+
break;
|
|
160
|
+
case 35:
|
|
161
|
+
result.key = cursorKey("F", modifiers, applicationCursorMode);
|
|
162
|
+
break;
|
|
163
|
+
case 33:
|
|
164
|
+
if (ev.shiftKey)
|
|
165
|
+
result.type = "pageUp";
|
|
166
|
+
else if (ev.ctrlKey)
|
|
167
|
+
result.key = `${ESC}[5;${modifiers + 1}~`;
|
|
168
|
+
else
|
|
169
|
+
result.key = `${ESC}[5~`;
|
|
170
|
+
break;
|
|
171
|
+
case 34:
|
|
172
|
+
if (ev.shiftKey)
|
|
173
|
+
result.type = "pageDown";
|
|
174
|
+
else if (ev.ctrlKey)
|
|
175
|
+
result.key = `${ESC}[6;${modifiers + 1}~`;
|
|
176
|
+
else
|
|
177
|
+
result.key = `${ESC}[6~`;
|
|
178
|
+
break;
|
|
179
|
+
default: {
|
|
180
|
+
const fn = FUNCTION_KEYS[ev.keyCode];
|
|
181
|
+
if (fn) {
|
|
182
|
+
const [id, ss3] = fn;
|
|
183
|
+
if (ss3) {
|
|
184
|
+
result.key = modifiers
|
|
185
|
+
? `${ESC}[1;${modifiers + 1}${id}`
|
|
186
|
+
: `${ESC}O${id}`;
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
result.key = modifiers
|
|
190
|
+
? `${ESC}[${id};${modifiers + 1}~`
|
|
191
|
+
: `${ESC}[${id}~`;
|
|
192
|
+
}
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
// a-z、空白、記号
|
|
196
|
+
if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
|
197
|
+
if (ev.keyCode >= 65 && ev.keyCode <= 90) {
|
|
198
|
+
result.key = String.fromCharCode(ev.keyCode - 64);
|
|
199
|
+
}
|
|
200
|
+
else if (ev.keyCode === 32) {
|
|
201
|
+
result.key = "\0";
|
|
202
|
+
}
|
|
203
|
+
else if (ev.keyCode >= 51 && ev.keyCode <= 55) {
|
|
204
|
+
// ESC・FS・GS・RS・US
|
|
205
|
+
result.key = String.fromCharCode(ev.keyCode - 51 + 27);
|
|
206
|
+
}
|
|
207
|
+
else if (ev.keyCode === 56) {
|
|
208
|
+
result.key = "\x7f";
|
|
209
|
+
}
|
|
210
|
+
else if (ev.keyCode === 219) {
|
|
211
|
+
result.key = ESC;
|
|
212
|
+
}
|
|
213
|
+
else if (ev.keyCode === 220) {
|
|
214
|
+
result.key = "\x1c";
|
|
215
|
+
}
|
|
216
|
+
else if (ev.keyCode === 221) {
|
|
217
|
+
result.key = "\x1d";
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else if ((!isMac || macOptionIsMeta) && ev.altKey && !ev.metaKey) {
|
|
221
|
+
// macOS で macOptionIsMeta が false のときの Option は、字を打つ 3 段目のシフト。
|
|
222
|
+
// ここでは ESC の前置きにする
|
|
223
|
+
const mapping = KEYCODE_KEY_MAPPINGS[ev.keyCode];
|
|
224
|
+
const key = mapping?.[ev.shiftKey ? 1 : 0];
|
|
225
|
+
if (key) {
|
|
226
|
+
result.key = ESC + key;
|
|
227
|
+
}
|
|
228
|
+
else if (ev.keyCode >= 65 && ev.keyCode <= 90) {
|
|
229
|
+
const code = ev.ctrlKey ? ev.keyCode - 64 : ev.keyCode + 32;
|
|
230
|
+
let s = String.fromCharCode(code);
|
|
231
|
+
if (ev.shiftKey)
|
|
232
|
+
s = s.toUpperCase();
|
|
233
|
+
result.key = ESC + s;
|
|
234
|
+
}
|
|
235
|
+
else if (ev.keyCode === 32) {
|
|
236
|
+
result.key = ESC + (ev.ctrlKey ? "\0" : " ");
|
|
237
|
+
}
|
|
238
|
+
else if (ev.key === "Dead" && ev.code.startsWith("Key")) {
|
|
239
|
+
// US 配列の Alt+N・E・U などは、変換の途中の字(dead key)になる
|
|
240
|
+
// (https://github.com/xtermjs/xterm.js/issues/3725)
|
|
241
|
+
let s = ev.code.slice(3, 4);
|
|
242
|
+
if (!ev.shiftKey)
|
|
243
|
+
s = s.toLowerCase();
|
|
244
|
+
result.key = ESC + s;
|
|
245
|
+
result.cancel = true;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
else if (isMac && !ev.altKey && !ev.ctrlKey && !ev.shiftKey && ev.metaKey) {
|
|
249
|
+
// Cmd+A などは送らない(xterm.js はここで「すべて選択」にする。選択は #10)
|
|
250
|
+
}
|
|
251
|
+
else if (ev.key &&
|
|
252
|
+
!ev.ctrlKey &&
|
|
253
|
+
!ev.altKey &&
|
|
254
|
+
!ev.metaKey &&
|
|
255
|
+
ev.keyCode >= 48 &&
|
|
256
|
+
ev.key.length === 1) {
|
|
257
|
+
// 1 字になるキーだけ(NumLock や音量などは含めない)
|
|
258
|
+
result.key = ev.key;
|
|
259
|
+
}
|
|
260
|
+
else if (ev.key && ev.ctrlKey) {
|
|
261
|
+
if (ev.key === "_")
|
|
262
|
+
result.key = "\x1f"; // ^_
|
|
263
|
+
if (ev.key === "@")
|
|
264
|
+
result.key = "\0"; // Ctrl+Shift+2
|
|
265
|
+
}
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return result;
|
|
270
|
+
}
|
|
271
|
+
/** 貼り付ける文字の改行を `\r` にそろえる(xterm.js の `prepareTextForTerminal`)。 */
|
|
272
|
+
export function prepareTextForTerminal(text) {
|
|
273
|
+
return text.replace(/\r?\n/g, "\r");
|
|
274
|
+
}
|
|
275
|
+
/** bracketed paste(2004)が有効なら、`ESC [200~` と `ESC [201~` で囲む(xterm.js の `bracketTextForPaste`)。 */
|
|
276
|
+
export function bracketTextForPaste(text, bracketedPasteMode) {
|
|
277
|
+
return bracketedPasteMode ? `\x1b[200~${text}\x1b[201~` : text;
|
|
278
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { KeyEventLike } from "./keyboard.js";
|
|
2
|
+
/** フラグ 1。disambiguate escape codes。 */
|
|
3
|
+
export declare const KITTY_DISAMBIGUATE = 1;
|
|
4
|
+
/** フラグ 2。report event types(押す・繰り返し・離す)。 */
|
|
5
|
+
export declare const KITTY_REPORT_EVENT_TYPES = 2;
|
|
6
|
+
/** フラグ 4。report alternate keys(shift を押したときのキーと、ベースのレイアウトのキー)。 */
|
|
7
|
+
export declare const KITTY_REPORT_ALTERNATE_KEYS = 4;
|
|
8
|
+
/** フラグ 8。report all keys as escape codes。 */
|
|
9
|
+
export declare const KITTY_REPORT_ALL_KEYS = 8;
|
|
10
|
+
/** フラグ 16。report associated text。 */
|
|
11
|
+
export declare const KITTY_REPORT_TEXT = 16;
|
|
12
|
+
/** キーの動き。1 押す、2 繰り返し、3 離す(仕様の event-type の値)。 */
|
|
13
|
+
export type KeyEventType = 1 | 2 | 3;
|
|
14
|
+
/** 修飾キーのビット。modifiers の値は 1 + ビットの和。Shift。 */
|
|
15
|
+
export declare const MOD_SHIFT = 1;
|
|
16
|
+
/** 修飾キーのビット。Alt(Option)。 */
|
|
17
|
+
export declare const MOD_ALT = 2;
|
|
18
|
+
/** 修飾キーのビット。Ctrl。 */
|
|
19
|
+
export declare const MOD_CTRL = 4;
|
|
20
|
+
/** 修飾キーのビット。Super(`metaKey`)。 */
|
|
21
|
+
export declare const MOD_SUPER = 8;
|
|
22
|
+
/** エンコードするキー 1 つ。 */
|
|
23
|
+
export interface KittyKey {
|
|
24
|
+
/** `u` ならキーの番号(Unicode か、仕様の私用領域の番号)。ほかの終端なら、パラメーターの数。 */
|
|
25
|
+
num: number;
|
|
26
|
+
/** 終端。`u`・`~`、または `A B C D H F P Q S`。 */
|
|
27
|
+
final: string;
|
|
28
|
+
/**
|
|
29
|
+
* フラグ 8 が無くても、押したときに `CSI` で送るか。送らない(今までの送り方のまま)キーは
|
|
30
|
+
* 繰り返し・離すだけを `CSI` で送る。
|
|
31
|
+
*/
|
|
32
|
+
escapedOnPress: boolean;
|
|
33
|
+
/** `:` で続ける別のキー(フラグ 4)。例: `:65`、`::99`、`:65:99`。 */
|
|
34
|
+
alternates?: string;
|
|
35
|
+
/** 添える字のコードポイント(フラグ 16)。`:` で区切る。 */
|
|
36
|
+
text?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* このキーイベントを、kitty のどのキーにするか。エンコードしないキーは `undefined`
|
|
40
|
+
* (従来の送り方に任せる)。`flags` はいまの kitty のフラグ。
|
|
41
|
+
*
|
|
42
|
+
* - フラグ 8: すべてのキー(修飾キーだけ・テンキー・Enter・Tab・Backspace・字のキーを含む)。
|
|
43
|
+
* - フラグ 8 が無い: Esc(フラグ 1)、修飾キーつきの Enter・Tab・Backspace(フラグ 1)、
|
|
44
|
+
* Ctrl・Alt・Super つきの字(フラグ 1)、F3(フラグ 1)。矢印・Home・F5 などは押すときは従来のまま
|
|
45
|
+
* (`escapedOnPress` が false)で、繰り返し・離すだけがここを通る。
|
|
46
|
+
*/
|
|
47
|
+
export declare function kittyKeyOf(ev: KeyEventLike, modifiers: number, flags: number, isMac: boolean, macOptionIsMeta: boolean): KittyKey | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* `CSI ... final` を作る。`modifiers` は `MOD_*` の和(0 なら無し)。
|
|
50
|
+
*
|
|
51
|
+
* - 修飾キーが無く、押す動きで、字も無ければ、その欄は省く(`CSI 97 u`、`CSI A`)。
|
|
52
|
+
* - 字だけがあるときは、修飾キーの欄を空にする(`CSI 97 ; ; 97 u`)。
|
|
53
|
+
* - `A` `B` `C` `D` `H` `F` `P` `Q` `S` は、欄が要るときだけ番号 `1` を付ける(`CSI 1 ; 1:3 A`)。
|
|
54
|
+
*/
|
|
55
|
+
export declare function formatKittyKey(k: KittyKey, modifiers: number, eventType: KeyEventType): string;
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
// kitty keyboard protocol(https://sw.kovidgoyal.net/kitty/keyboard-protocol/ )のキーのエンコード。
|
|
2
|
+
// 形は `CSI unicode-key-code:alternate-key-codes ; modifiers:event-type ; text-as-codepoints u`。
|
|
3
|
+
// 矢印・Home・F5 などの「機能キー」は、`u` の代わりに今までの終端(`A`・`~` など)を使う。
|
|
4
|
+
//
|
|
5
|
+
// 呼ぶ側は `keyboard.ts` の `evaluateKeyboardEvent`。ここは「どのキーか」と「どう書くか」だけを決め、
|
|
6
|
+
// 従来の(xterm.js と同じ)バイト列には触らない。
|
|
7
|
+
/** フラグ 1。disambiguate escape codes。 */
|
|
8
|
+
export const KITTY_DISAMBIGUATE = 1;
|
|
9
|
+
/** フラグ 2。report event types(押す・繰り返し・離す)。 */
|
|
10
|
+
export const KITTY_REPORT_EVENT_TYPES = 2;
|
|
11
|
+
/** フラグ 4。report alternate keys(shift を押したときのキーと、ベースのレイアウトのキー)。 */
|
|
12
|
+
export const KITTY_REPORT_ALTERNATE_KEYS = 4;
|
|
13
|
+
/** フラグ 8。report all keys as escape codes。 */
|
|
14
|
+
export const KITTY_REPORT_ALL_KEYS = 8;
|
|
15
|
+
/** フラグ 16。report associated text。 */
|
|
16
|
+
export const KITTY_REPORT_TEXT = 16;
|
|
17
|
+
/** 修飾キーのビット。modifiers の値は 1 + ビットの和。Shift。 */
|
|
18
|
+
export const MOD_SHIFT = 1;
|
|
19
|
+
/** 修飾キーのビット。Alt(Option)。 */
|
|
20
|
+
export const MOD_ALT = 2;
|
|
21
|
+
/** 修飾キーのビット。Ctrl。 */
|
|
22
|
+
export const MOD_CTRL = 4;
|
|
23
|
+
/** 修飾キーのビット。Super(`metaKey`)。 */
|
|
24
|
+
export const MOD_SUPER = 8;
|
|
25
|
+
// ---- 字を打つキー ----
|
|
26
|
+
// `KeyboardEvent.code` から、ベースのレイアウト(PC-101 の US 配列)の字。[そのまま, Shift つき]
|
|
27
|
+
const BASE_LAYOUT = {
|
|
28
|
+
Minus: ["-", "_"],
|
|
29
|
+
Equal: ["=", "+"],
|
|
30
|
+
BracketLeft: ["[", "{"],
|
|
31
|
+
BracketRight: ["]", "}"],
|
|
32
|
+
Backslash: ["\\", "|"],
|
|
33
|
+
Semicolon: [";", ":"],
|
|
34
|
+
Quote: ["'", '"'],
|
|
35
|
+
Backquote: ["`", "~"],
|
|
36
|
+
Comma: [",", "<"],
|
|
37
|
+
Period: [".", ">"],
|
|
38
|
+
Slash: ["/", "?"],
|
|
39
|
+
Space: [" ", " "],
|
|
40
|
+
};
|
|
41
|
+
for (let i = 0; i < 26; i++) {
|
|
42
|
+
const c = String.fromCharCode(97 + i);
|
|
43
|
+
BASE_LAYOUT[`Key${c.toUpperCase()}`] = [c, c.toUpperCase()];
|
|
44
|
+
}
|
|
45
|
+
")!@#$%^&*(".split("").forEach((s, i) => {
|
|
46
|
+
BASE_LAYOUT[`Digit${i}`] = [String(i), s];
|
|
47
|
+
});
|
|
48
|
+
// `code` が空のとき(古いブラウザーやテスト)の代わりに、`keyCode` から `code` を決める
|
|
49
|
+
const CODE_BY_KEYCODE = {
|
|
50
|
+
32: "Space",
|
|
51
|
+
186: "Semicolon",
|
|
52
|
+
187: "Equal",
|
|
53
|
+
188: "Comma",
|
|
54
|
+
189: "Minus",
|
|
55
|
+
190: "Period",
|
|
56
|
+
191: "Slash",
|
|
57
|
+
192: "Backquote",
|
|
58
|
+
219: "BracketLeft",
|
|
59
|
+
220: "Backslash",
|
|
60
|
+
221: "BracketRight",
|
|
61
|
+
222: "Quote",
|
|
62
|
+
};
|
|
63
|
+
function baseLayoutOf(ev) {
|
|
64
|
+
let code = ev.code;
|
|
65
|
+
if (!code) {
|
|
66
|
+
const kc = ev.keyCode;
|
|
67
|
+
if (kc >= 65 && kc <= 90)
|
|
68
|
+
code = `Key${String.fromCharCode(kc)}`;
|
|
69
|
+
else if (kc >= 48 && kc <= 57)
|
|
70
|
+
code = `Digit${kc - 48}`;
|
|
71
|
+
else
|
|
72
|
+
code = CODE_BY_KEYCODE[kc] ?? "";
|
|
73
|
+
}
|
|
74
|
+
return BASE_LAYOUT[code];
|
|
75
|
+
}
|
|
76
|
+
/** 印字できる 1 コードポイントならその字。キーの名前("Enter" など)や制御文字は `undefined`。 */
|
|
77
|
+
function singleChar(key) {
|
|
78
|
+
if (!key)
|
|
79
|
+
return undefined;
|
|
80
|
+
const cps = Array.from(key);
|
|
81
|
+
if (cps.length !== 1)
|
|
82
|
+
return undefined;
|
|
83
|
+
const cp = cps[0].codePointAt(0);
|
|
84
|
+
return cp < 0x20 || cp === 0x7f ? undefined : cps[0];
|
|
85
|
+
}
|
|
86
|
+
function lowerSingle(s) {
|
|
87
|
+
const l = s.toLowerCase();
|
|
88
|
+
return Array.from(l).length === 1 ? l : s;
|
|
89
|
+
}
|
|
90
|
+
function upperSingle(s) {
|
|
91
|
+
const u = s.toUpperCase();
|
|
92
|
+
return Array.from(u).length === 1 ? u : s;
|
|
93
|
+
}
|
|
94
|
+
const cp = (s) => s.codePointAt(0);
|
|
95
|
+
/** Shift なしの字。Shift の英字は小文字、記号は US 配列で戻し、戻せなければそのまま。 */
|
|
96
|
+
function unshiftedOf(k, lower, shift, us) {
|
|
97
|
+
if (!shift)
|
|
98
|
+
return lower;
|
|
99
|
+
if (lower !== k)
|
|
100
|
+
return lower;
|
|
101
|
+
if (us && us[1] === k)
|
|
102
|
+
return us[0];
|
|
103
|
+
return k;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 字を打つキーの番号と、別のキー。`undefined` なら字を打つキーではない(テンキーも含む。
|
|
107
|
+
* テンキーは `numpadKey`)。
|
|
108
|
+
*
|
|
109
|
+
* 番号は、いまの配列でそのキーが Shift なしで出す字。ブラウザーは Shift をかけた字を `key` に
|
|
110
|
+
* 入れるので、英字は小文字にし、それ以外は US 配列の対応(`code` から決める)で戻す。US 配列と
|
|
111
|
+
* 違う配列の記号は戻せないので、`key` そのままになる。
|
|
112
|
+
*/
|
|
113
|
+
function textKey(ev) {
|
|
114
|
+
if (ev.code.startsWith("Numpad"))
|
|
115
|
+
return undefined;
|
|
116
|
+
const shift = ev.shiftKey;
|
|
117
|
+
const us = baseLayoutOf(ev);
|
|
118
|
+
// dead key の途中は、合成を止めないように従来の送り方に任せる
|
|
119
|
+
if (ev.key === "Dead")
|
|
120
|
+
return undefined;
|
|
121
|
+
const k = singleChar(ev.key) ?? us?.[shift ? 1 : 0];
|
|
122
|
+
if (k === undefined)
|
|
123
|
+
return undefined;
|
|
124
|
+
const lower = lowerSingle(k);
|
|
125
|
+
const unshifted = unshiftedOf(k, lower, shift, us);
|
|
126
|
+
const out = { code: cp(unshifted) };
|
|
127
|
+
if (shift) {
|
|
128
|
+
const shifted = k !== unshifted ? k : upperSingle(unshifted);
|
|
129
|
+
if (shifted !== unshifted)
|
|
130
|
+
out.shifted = cp(shifted);
|
|
131
|
+
}
|
|
132
|
+
if (us && us[0] !== unshifted)
|
|
133
|
+
out.base = cp(us[0]);
|
|
134
|
+
return out;
|
|
135
|
+
}
|
|
136
|
+
// 従来のバイト列があるキー(`keyboard.ts` の switch と同じ keyCode)
|
|
137
|
+
const LEGACY_FUNCTIONAL = {
|
|
138
|
+
37: { num: 1, final: "D" },
|
|
139
|
+
38: { num: 1, final: "A" },
|
|
140
|
+
39: { num: 1, final: "C" },
|
|
141
|
+
40: { num: 1, final: "B" },
|
|
142
|
+
36: { num: 1, final: "H" },
|
|
143
|
+
35: { num: 1, final: "F" },
|
|
144
|
+
45: { num: 2, final: "~" },
|
|
145
|
+
46: { num: 3, final: "~" },
|
|
146
|
+
33: { num: 5, final: "~" },
|
|
147
|
+
34: { num: 6, final: "~" },
|
|
148
|
+
112: { num: 1, final: "P" },
|
|
149
|
+
113: { num: 1, final: "Q" },
|
|
150
|
+
// F3 の `CSI R` はカーソル位置の報告とぶつかるので `CSI 13 ~`
|
|
151
|
+
114: { num: 13, final: "~" },
|
|
152
|
+
115: { num: 1, final: "S" },
|
|
153
|
+
116: { num: 15, final: "~" },
|
|
154
|
+
117: { num: 17, final: "~" },
|
|
155
|
+
118: { num: 18, final: "~" },
|
|
156
|
+
119: { num: 19, final: "~" },
|
|
157
|
+
120: { num: 20, final: "~" },
|
|
158
|
+
121: { num: 21, final: "~" },
|
|
159
|
+
122: { num: 23, final: "~" },
|
|
160
|
+
123: { num: 24, final: "~" },
|
|
161
|
+
};
|
|
162
|
+
// 従来のバイト列が無いキー(フラグ 8 のときだけ送る)。keyCode から
|
|
163
|
+
const EXTRA_BY_KEYCODE = {
|
|
164
|
+
20: 57358, // Caps Lock
|
|
165
|
+
145: 57359, // Scroll Lock
|
|
166
|
+
144: 57360, // Num Lock
|
|
167
|
+
44: 57361, // Print Screen
|
|
168
|
+
19: 57362, // Pause
|
|
169
|
+
93: 57363, // Menu
|
|
170
|
+
};
|
|
171
|
+
for (let n = 13; n <= 24; n++)
|
|
172
|
+
EXTRA_BY_KEYCODE[124 + n - 13] = 57376 + n - 13; // F13〜F24
|
|
173
|
+
// 修飾キーそのもの。`code` から
|
|
174
|
+
const MODIFIER_BY_CODE = {
|
|
175
|
+
ShiftLeft: 57441,
|
|
176
|
+
ControlLeft: 57442,
|
|
177
|
+
AltLeft: 57443,
|
|
178
|
+
MetaLeft: 57444,
|
|
179
|
+
OSLeft: 57444,
|
|
180
|
+
ShiftRight: 57447,
|
|
181
|
+
ControlRight: 57448,
|
|
182
|
+
AltRight: 57449,
|
|
183
|
+
MetaRight: 57450,
|
|
184
|
+
OSRight: 57450,
|
|
185
|
+
ContextMenu: 57363,
|
|
186
|
+
};
|
|
187
|
+
// `code` が空のときの代わり(左側として扱う)
|
|
188
|
+
const MODIFIER_BY_KEYCODE = {
|
|
189
|
+
16: 57441,
|
|
190
|
+
17: 57442,
|
|
191
|
+
18: 57443,
|
|
192
|
+
91: 57444,
|
|
193
|
+
224: 57444,
|
|
194
|
+
92: 57450,
|
|
195
|
+
};
|
|
196
|
+
// テンキー。`code` から
|
|
197
|
+
const NUMPAD_BY_CODE = {
|
|
198
|
+
NumpadDecimal: 57409,
|
|
199
|
+
NumpadDivide: 57410,
|
|
200
|
+
NumpadMultiply: 57411,
|
|
201
|
+
NumpadSubtract: 57412,
|
|
202
|
+
NumpadAdd: 57413,
|
|
203
|
+
NumpadEnter: 57414,
|
|
204
|
+
NumpadEqual: 57415,
|
|
205
|
+
NumpadComma: 57416,
|
|
206
|
+
};
|
|
207
|
+
// NumLock が切れているとき、テンキーは矢印などの keyCode になる
|
|
208
|
+
const NUMPAD_NAV_BY_KEYCODE = {
|
|
209
|
+
37: 57417,
|
|
210
|
+
39: 57418,
|
|
211
|
+
38: 57419,
|
|
212
|
+
40: 57420,
|
|
213
|
+
33: 57421,
|
|
214
|
+
34: 57422,
|
|
215
|
+
36: 57423,
|
|
216
|
+
35: 57424,
|
|
217
|
+
45: 57425,
|
|
218
|
+
46: 57426,
|
|
219
|
+
12: 57427, // 5(NumLock なし)
|
|
220
|
+
};
|
|
221
|
+
function numpadKey(ev) {
|
|
222
|
+
if (!ev.code.startsWith("Numpad"))
|
|
223
|
+
return undefined;
|
|
224
|
+
if (ev.code === "NumpadEnter")
|
|
225
|
+
return NUMPAD_BY_CODE.NumpadEnter;
|
|
226
|
+
const nav = NUMPAD_NAV_BY_KEYCODE[ev.keyCode];
|
|
227
|
+
if (nav !== undefined)
|
|
228
|
+
return nav;
|
|
229
|
+
const digit = /^Numpad(\d)$/.exec(ev.code);
|
|
230
|
+
if (digit)
|
|
231
|
+
return 57399 + Number(digit[1]);
|
|
232
|
+
return NUMPAD_BY_CODE[ev.code];
|
|
233
|
+
}
|
|
234
|
+
function pressKey(num, final = "u", escapedOnPress = true) {
|
|
235
|
+
return { num, final, escapedOnPress };
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* このキーイベントを、kitty のどのキーにするか。エンコードしないキーは `undefined`
|
|
239
|
+
* (従来の送り方に任せる)。`flags` はいまの kitty のフラグ。
|
|
240
|
+
*
|
|
241
|
+
* - フラグ 8: すべてのキー(修飾キーだけ・テンキー・Enter・Tab・Backspace・字のキーを含む)。
|
|
242
|
+
* - フラグ 8 が無い: Esc(フラグ 1)、修飾キーつきの Enter・Tab・Backspace(フラグ 1)、
|
|
243
|
+
* Ctrl・Alt・Super つきの字(フラグ 1)、F3(フラグ 1)。矢印・Home・F5 などは押すときは従来のまま
|
|
244
|
+
* (`escapedOnPress` が false)で、繰り返し・離すだけがここを通る。
|
|
245
|
+
*/
|
|
246
|
+
export function kittyKeyOf(ev, modifiers, flags, isMac, macOptionIsMeta) {
|
|
247
|
+
const all = (flags & KITTY_REPORT_ALL_KEYS) !== 0;
|
|
248
|
+
const disambiguate = all || (flags & KITTY_DISAMBIGUATE) !== 0;
|
|
249
|
+
const withText = (flags & KITTY_REPORT_TEXT) !== 0;
|
|
250
|
+
const withAlternates = (flags & KITTY_REPORT_ALTERNATE_KEYS) !== 0;
|
|
251
|
+
// 修飾キーそのもの・ロックキーなど(フラグ 8 のときだけ)
|
|
252
|
+
if (all) {
|
|
253
|
+
const mod = MODIFIER_BY_CODE[ev.code] ?? (ev.code ? undefined : MODIFIER_BY_KEYCODE[ev.keyCode]);
|
|
254
|
+
if (mod !== undefined)
|
|
255
|
+
return pressKey(ev.key === "AltGraph" ? 57453 : mod);
|
|
256
|
+
if (ev.key === "AltGraph")
|
|
257
|
+
return pressKey(57453);
|
|
258
|
+
const extra = EXTRA_BY_KEYCODE[ev.keyCode];
|
|
259
|
+
if (extra !== undefined)
|
|
260
|
+
return pressKey(extra);
|
|
261
|
+
const kp = numpadKey(ev);
|
|
262
|
+
if (kp !== undefined) {
|
|
263
|
+
const k = pressKey(kp);
|
|
264
|
+
const ch = singleChar(ev.key);
|
|
265
|
+
if (withText && ch !== undefined && !(modifiers & (MOD_CTRL | MOD_ALT | MOD_SUPER))) {
|
|
266
|
+
k.text = String(cp(ch));
|
|
267
|
+
}
|
|
268
|
+
return k;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
switch (ev.keyCode) {
|
|
272
|
+
case 27:
|
|
273
|
+
return disambiguate ? pressKey(27) : undefined;
|
|
274
|
+
case 8:
|
|
275
|
+
return all || (disambiguate && modifiers) ? pressKey(127) : undefined;
|
|
276
|
+
case 9:
|
|
277
|
+
return all || (disambiguate && modifiers) ? pressKey(9) : undefined;
|
|
278
|
+
case 13:
|
|
279
|
+
return all || (disambiguate && modifiers) ? pressKey(13) : undefined;
|
|
280
|
+
}
|
|
281
|
+
const fn = LEGACY_FUNCTIONAL[ev.keyCode];
|
|
282
|
+
if (fn) {
|
|
283
|
+
// F3 は フラグ 1 以上なら `CSI 13 ~` で送る。ほかは今までのまま
|
|
284
|
+
return pressKey(fn.num, fn.final, all || (disambiguate && ev.keyCode === 114));
|
|
285
|
+
}
|
|
286
|
+
// 字を打つキー
|
|
287
|
+
if (!all && !(disambiguate && modifiers & (MOD_ALT | MOD_CTRL | MOD_SUPER)))
|
|
288
|
+
return undefined;
|
|
289
|
+
// macOS の Option(macOptionIsMeta が false)は字を打つキー。Windows の AltGr は呼ぶ側が除く
|
|
290
|
+
if (isMac && !macOptionIsMeta && ev.altKey && !ev.ctrlKey && !ev.metaKey)
|
|
291
|
+
return undefined;
|
|
292
|
+
const tk = textKey(ev);
|
|
293
|
+
if (!tk)
|
|
294
|
+
return undefined;
|
|
295
|
+
// どのキーか分からない字だけのイベント(keyCode 0 で code が空)は、仕様どおり番号 0
|
|
296
|
+
const k = pressKey(ev.code === "" && ev.keyCode === 0 ? 0 : tk.code);
|
|
297
|
+
if (withAlternates && (tk.shifted !== undefined || tk.base !== undefined)) {
|
|
298
|
+
k.alternates = `:${tk.shifted ?? ""}${tk.base !== undefined ? `:${tk.base}` : ""}`;
|
|
299
|
+
}
|
|
300
|
+
// 字を添えるのは、修飾キーが字を作るのを邪魔していない(Shift だけ)ときの、押す・繰り返し
|
|
301
|
+
if (withText && !(modifiers & (MOD_ALT | MOD_CTRL | MOD_SUPER))) {
|
|
302
|
+
const ch = singleChar(ev.key);
|
|
303
|
+
if (ch !== undefined)
|
|
304
|
+
k.text = String(cp(ch));
|
|
305
|
+
}
|
|
306
|
+
return k;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* `CSI ... final` を作る。`modifiers` は `MOD_*` の和(0 なら無し)。
|
|
310
|
+
*
|
|
311
|
+
* - 修飾キーが無く、押す動きで、字も無ければ、その欄は省く(`CSI 97 u`、`CSI A`)。
|
|
312
|
+
* - 字だけがあるときは、修飾キーの欄を空にする(`CSI 97 ; ; 97 u`)。
|
|
313
|
+
* - `A` `B` `C` `D` `H` `F` `P` `Q` `S` は、欄が要るときだけ番号 `1` を付ける(`CSI 1 ; 1:3 A`)。
|
|
314
|
+
*/
|
|
315
|
+
export function formatKittyKey(k, modifiers, eventType) {
|
|
316
|
+
const text = eventType !== 3 ? k.text : undefined;
|
|
317
|
+
const modField = modifiers || eventType !== 1
|
|
318
|
+
? `${modifiers + 1}${eventType !== 1 ? `:${eventType}` : ""}`
|
|
319
|
+
: "";
|
|
320
|
+
const needsField = modField !== "" || text !== undefined;
|
|
321
|
+
let code;
|
|
322
|
+
if (k.final === "u" || k.final === "~")
|
|
323
|
+
code = `${k.num}${k.alternates ?? ""}`;
|
|
324
|
+
else
|
|
325
|
+
code = needsField ? String(k.num) : "";
|
|
326
|
+
let params = code;
|
|
327
|
+
if (needsField)
|
|
328
|
+
params += `;${modField}`;
|
|
329
|
+
if (text !== undefined)
|
|
330
|
+
params += `;${text}`;
|
|
331
|
+
return `\x1b[${params}${k.final}`;
|
|
332
|
+
}
|
package/dist/memory.d.ts
ADDED
package/dist/memory.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
let memory;
|
|
2
|
+
/** `init()` が WASM のメモリを渡す。 */
|
|
3
|
+
export function setMemory(m) {
|
|
4
|
+
memory = m;
|
|
5
|
+
}
|
|
6
|
+
/** WASM のメモリ。`init()` の前は例外。 */
|
|
7
|
+
export function getMemory() {
|
|
8
|
+
if (memory === undefined) {
|
|
9
|
+
throw new Error("coneko-term: call init() before using Terminal");
|
|
10
|
+
}
|
|
11
|
+
return memory;
|
|
12
|
+
}
|