@valyrianjs/terminal 0.1.2 → 0.2.1
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/dist/ansi.d.ts +2 -0
- package/dist/ansi.d.ts.map +1 -1
- package/dist/ansi.js +12 -0
- package/dist/ansi.js.map +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +6 -2
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/keymap.d.ts.map +1 -1
- package/dist/keymap.js +4 -2
- package/dist/keymap.js.map +1 -1
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js +2 -1
- package/dist/layout.js.map +1 -1
- package/dist/mouse.d.ts +6 -0
- package/dist/mouse.d.ts.map +1 -1
- package/dist/mouse.js +30 -16
- package/dist/mouse.js.map +1 -1
- package/dist/primitives.d.ts +8 -3
- package/dist/primitives.d.ts.map +1 -1
- package/dist/primitives.js +8 -1
- package/dist/primitives.js.map +1 -1
- package/dist/render.d.ts +1 -1
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +290 -51
- package/dist/render.js.map +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +13 -11
- package/dist/runtime.js.map +1 -1
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +434 -65
- package/dist/session.js.map +1 -1
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +3 -0
- package/dist/theme.js.map +1 -1
- package/dist/tree.d.ts.map +1 -1
- package/dist/tree.js +18 -4
- package/dist/tree.js.map +1 -1
- package/dist/types.d.ts +61 -13
- package/dist/types.d.ts.map +1 -1
- package/docs/api-reference.md +40 -28
- package/docs/cookbook.md +2 -2
- package/docs/core-concepts.md +1 -1
- package/docs/interaction-model.md +18 -6
- package/docs/primitive-gallery.md +19 -10
- package/llms-full.txt +80 -47
- package/package.json +1 -1
- package/src/ansi.ts +12 -0
- package/src/events.ts +4 -2
- package/src/index.ts +3 -0
- package/src/keymap.ts +4 -2
- package/src/layout.ts +2 -1
- package/src/mouse.ts +31 -15
- package/src/primitives.ts +15 -5
- package/src/render.ts +320 -52
- package/src/runtime.ts +13 -11
- package/src/session.ts +469 -59
- package/src/theme.ts +3 -0
- package/src/tree.ts +19 -4
- package/src/types.ts +72 -12
package/dist/session.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { ANSI_ENTER_ALTERNATE_SCREEN, ANSI_EXIT_ALTERNATE_SCREEN, ANSI_HIDE_CURSOR, ANSI_SHOW_CURSOR, createAnsiDiffWriter, formatPlainFrame, toAnsiFrame } from "./ansi.js";
|
|
1
|
+
import { ANSI_DISABLE_MOUSE_REPORTING, ANSI_ENABLE_MOUSE_REPORTING, ANSI_ENTER_ALTERNATE_SCREEN, ANSI_EXIT_ALTERNATE_SCREEN, ANSI_HIDE_CURSOR, ANSI_SHOW_CURSOR, createAnsiDiffWriter, formatPlainFrame, toAnsiFrame } from "./ansi.js";
|
|
2
2
|
import { createSystemClipboardAdapter } from "./clipboard.js";
|
|
3
3
|
import { createEditorState, insertEditorText, moveEditorCursor, removeEditorBackward, removeEditorForward } from "./editor-state.js";
|
|
4
4
|
import { copySelection, hasSelection, insertText, moveCursorEnd, moveCursorHome, moveCursorLeft, moveCursorRight, moveCursorWordLeft, moveCursorWordRight, normalizeInputState, parseTerminalKey, removeBackward, removeForward, selectAll } from "./events.js";
|
|
5
5
|
import { createResolvedTerminalKeymap, resolveTerminalKeyBinding } from "./keymap.js";
|
|
6
6
|
import { mergeVertical } from "./layout.js";
|
|
7
|
-
import { cursorFromHitbox, parseTerminalInput, resolvePointerTarget } from "./mouse.js";
|
|
7
|
+
import { cursorFromHitbox, parseTerminalInput, parseTerminalMousePrefix, resolvePointerTarget } from "./mouse.js";
|
|
8
8
|
import { createOutputWriter } from "./output-writer.js";
|
|
9
9
|
import { parseBracketedPaste } from "./paste.js";
|
|
10
10
|
import { renderTerminalFrame } from "./render.js";
|
|
@@ -25,6 +25,10 @@ const KNOWN_TERMINAL_KEY_SEQUENCES = [
|
|
|
25
25
|
"\u001b[1;3C",
|
|
26
26
|
"\u001b[1;3D",
|
|
27
27
|
"\u001b[3~",
|
|
28
|
+
"\u001b[5~",
|
|
29
|
+
"\u001b[6~",
|
|
30
|
+
"\u001b[1~",
|
|
31
|
+
"\u001b[4~",
|
|
28
32
|
"\u001b[Z",
|
|
29
33
|
"\u001b[A",
|
|
30
34
|
"\u001b[B",
|
|
@@ -37,6 +41,7 @@ const KNOWN_TERMINAL_KEY_SEQUENCES = [
|
|
|
37
41
|
];
|
|
38
42
|
const ESCAPE = "\u001b";
|
|
39
43
|
const CSI_PREFIX = "\u001b[";
|
|
44
|
+
const DOUBLE_PRESS_INTERVAL_MS = 500;
|
|
40
45
|
function isBracketedPasteStartPrefix(value) {
|
|
41
46
|
return value.length > 0 && value.length < BRACKETED_PASTE_START.length && BRACKETED_PASTE_START.startsWith(value);
|
|
42
47
|
}
|
|
@@ -83,6 +88,7 @@ function resolveRuntimeOptions(options) {
|
|
|
83
88
|
stdout,
|
|
84
89
|
alternateScreen: options.alternateScreen ?? ownsInteractiveTTY,
|
|
85
90
|
hideCursor: options.hideCursor ?? ownsInteractiveTTY,
|
|
91
|
+
mouseReporting: ownsInteractiveTTY,
|
|
86
92
|
writesAnsi: runtime === "app" && Boolean(stdout)
|
|
87
93
|
};
|
|
88
94
|
}
|
|
@@ -94,7 +100,7 @@ function resolveTerminalSize(options, stdout) {
|
|
|
94
100
|
rows: validateTerminalDimension("rows", rows)
|
|
95
101
|
};
|
|
96
102
|
}
|
|
97
|
-
function applyInteractiveState(nodes, focusedId, inputStateById, editorStateById, listIndexById, scrollOffsetById, listHoverById, scrollHoverRowById) {
|
|
103
|
+
function applyInteractiveState(nodes, focusedId, inputStateById, editorStateById, listIndexById, listSelectedIndexById, listViewportOffsetById, scrollOffsetById, listHoverById, scrollHoverRowById) {
|
|
98
104
|
for (let i = 0; i < nodes.length; i += 1) {
|
|
99
105
|
const node = nodes[i];
|
|
100
106
|
if (node.type !== "element") {
|
|
@@ -116,7 +122,23 @@ function applyInteractiveState(nodes, focusedId, inputStateById, editorStateById
|
|
|
116
122
|
node.props.__editorState = current;
|
|
117
123
|
}
|
|
118
124
|
if (node.tag === "terminal-list" && id) {
|
|
119
|
-
node.props.
|
|
125
|
+
const items = Array.isArray(node.props.items) ? node.props.items : [];
|
|
126
|
+
const activeIndex = listIndexById.get(id) || 0;
|
|
127
|
+
const clampedActiveIndex = Math.max(0, Math.min(Math.max(0, items.length - 1), activeIndex));
|
|
128
|
+
if (!listIndexById.has(id)) {
|
|
129
|
+
listIndexById.set(id, clampedActiveIndex);
|
|
130
|
+
}
|
|
131
|
+
const selectedIndex = node.props.showActive === false
|
|
132
|
+
? null
|
|
133
|
+
: listSelectedIndexById.has(id)
|
|
134
|
+
? listSelectedIndexById.get(id)
|
|
135
|
+
: clampedActiveIndex;
|
|
136
|
+
if (!listSelectedIndexById.has(id)) {
|
|
137
|
+
listSelectedIndexById.set(id, selectedIndex === null ? null : Math.max(0, Math.min(Math.max(0, items.length - 1), selectedIndex)));
|
|
138
|
+
}
|
|
139
|
+
node.props.__activeIndex = clampedActiveIndex;
|
|
140
|
+
node.props.__selectedIndex = selectedIndex === null ? null : Math.max(0, Math.min(Math.max(0, items.length - 1), selectedIndex));
|
|
141
|
+
node.props.__scrollOffset = listViewportOffsetById.get(id) || 0;
|
|
120
142
|
if (listHoverById.has(id)) {
|
|
121
143
|
node.props.__hoveredIndex = listHoverById.get(id);
|
|
122
144
|
}
|
|
@@ -127,7 +149,7 @@ function applyInteractiveState(nodes, focusedId, inputStateById, editorStateById
|
|
|
127
149
|
node.props.__hoveredRow = scrollHoverRowById.get(id);
|
|
128
150
|
}
|
|
129
151
|
}
|
|
130
|
-
applyInteractiveState(node.children, focusedId, inputStateById, editorStateById, listIndexById, scrollOffsetById, listHoverById, scrollHoverRowById);
|
|
152
|
+
applyInteractiveState(node.children, focusedId, inputStateById, editorStateById, listIndexById, listSelectedIndexById, listViewportOffsetById, scrollOffsetById, listHoverById, scrollHoverRowById);
|
|
131
153
|
}
|
|
132
154
|
}
|
|
133
155
|
export function mountTerminal(input, options = {}) {
|
|
@@ -139,6 +161,7 @@ export function mountTerminal(input, options = {}) {
|
|
|
139
161
|
let pendingPasteChunk = "";
|
|
140
162
|
let pendingKeyChunk = "";
|
|
141
163
|
let pendingEscapeFlush = null;
|
|
164
|
+
let lastPrimaryPress = null;
|
|
142
165
|
let destroyed = false;
|
|
143
166
|
let autoProjectionEnabled = false;
|
|
144
167
|
let suppressAutoProjection = false;
|
|
@@ -146,6 +169,8 @@ export function mountTerminal(input, options = {}) {
|
|
|
146
169
|
const inputStateById = new Map();
|
|
147
170
|
const editorStateById = new Map();
|
|
148
171
|
const listIndexById = new Map();
|
|
172
|
+
const listSelectedIndexById = new Map();
|
|
173
|
+
const listViewportOffsetById = new Map();
|
|
149
174
|
const scrollOffsetById = new Map();
|
|
150
175
|
const listHoverById = new Map();
|
|
151
176
|
const scrollHoverRowById = new Map();
|
|
@@ -159,7 +184,7 @@ export function mountTerminal(input, options = {}) {
|
|
|
159
184
|
renderNow();
|
|
160
185
|
});
|
|
161
186
|
let currentTree = terminalRuntime.project();
|
|
162
|
-
applyInteractiveState(currentTree, focusedId, inputStateById, editorStateById, listIndexById, scrollOffsetById, listHoverById, scrollHoverRowById);
|
|
187
|
+
applyInteractiveState(currentTree, focusedId, inputStateById, editorStateById, listIndexById, listSelectedIndexById, listViewportOffsetById, scrollOffsetById, listHoverById, scrollHoverRowById);
|
|
163
188
|
let currentFrame = renderTreeFrame(currentTree);
|
|
164
189
|
let currentOutput = formatPlainFrame(currentFrame, { theme: options.theme }).trimEnd();
|
|
165
190
|
let currentHitboxes = currentFrame.hitboxes;
|
|
@@ -184,6 +209,9 @@ export function mountTerminal(input, options = {}) {
|
|
|
184
209
|
if (runtimeOptions.hideCursor) {
|
|
185
210
|
writes.push(ANSI_HIDE_CURSOR);
|
|
186
211
|
}
|
|
212
|
+
if (runtimeOptions.mouseReporting) {
|
|
213
|
+
writes.push(ANSI_ENABLE_MOUSE_REPORTING);
|
|
214
|
+
}
|
|
187
215
|
if (writes.length > 0) {
|
|
188
216
|
outputWriter.write(writes.join(""), { force: true });
|
|
189
217
|
}
|
|
@@ -193,6 +221,9 @@ export function mountTerminal(input, options = {}) {
|
|
|
193
221
|
return;
|
|
194
222
|
}
|
|
195
223
|
const writes = [];
|
|
224
|
+
if (runtimeOptions.mouseReporting) {
|
|
225
|
+
writes.push(ANSI_DISABLE_MOUSE_REPORTING);
|
|
226
|
+
}
|
|
196
227
|
if (runtimeOptions.hideCursor) {
|
|
197
228
|
writes.push(ANSI_SHOW_CURSOR);
|
|
198
229
|
}
|
|
@@ -221,7 +252,7 @@ export function mountTerminal(input, options = {}) {
|
|
|
221
252
|
focusedId = activeFocusables[0]?.props.id || null;
|
|
222
253
|
}
|
|
223
254
|
skipFocusContainmentOnce = false;
|
|
224
|
-
applyInteractiveState(currentTree, focusedId, inputStateById, editorStateById, listIndexById, scrollOffsetById, listHoverById, scrollHoverRowById);
|
|
255
|
+
applyInteractiveState(currentTree, focusedId, inputStateById, editorStateById, listIndexById, listSelectedIndexById, listViewportOffsetById, scrollOffsetById, listHoverById, scrollHoverRowById);
|
|
225
256
|
currentFrame = renderTreeFrame(currentTree);
|
|
226
257
|
currentOutput = formatPlainFrame(currentFrame, { theme: options.theme }).trimEnd();
|
|
227
258
|
currentHitboxes = currentFrame.hitboxes;
|
|
@@ -360,10 +391,18 @@ export function mountTerminal(input, options = {}) {
|
|
|
360
391
|
return 1;
|
|
361
392
|
}
|
|
362
393
|
function sourceRowFromHitbox(node, hitbox, y) {
|
|
363
|
-
|
|
394
|
+
if (node.tag === "terminal-list" && typeof hitbox.__listItemIndex === "number" && y >= hitbox.y1 && y <= hitbox.y2) {
|
|
395
|
+
return Math.max(1, Math.min(rowCountForNode(node), hitbox.__listItemIndex + 1));
|
|
396
|
+
}
|
|
397
|
+
const sourceY = hitbox.contentY ?? hitbox.y1;
|
|
398
|
+
const visibleRow = Math.max(1, y - sourceY + 1);
|
|
364
399
|
if (node.tag !== "terminal-list") {
|
|
365
400
|
return Math.max(1, Math.min(rowCountForNode(node), visibleRow));
|
|
366
401
|
}
|
|
402
|
+
const mappedIndex = hitbox.itemIndexes?.[visibleRow - 1];
|
|
403
|
+
if (typeof mappedIndex === "number") {
|
|
404
|
+
return Math.max(1, Math.min(rowCountForNode(node), mappedIndex + 1));
|
|
405
|
+
}
|
|
367
406
|
return Math.max(1, Math.min(rowCountForNode(node), visibleRow + (hitbox.itemOffset || 0)));
|
|
368
407
|
}
|
|
369
408
|
function shouldPointerCapture(node) {
|
|
@@ -404,6 +443,155 @@ export function mountTerminal(input, options = {}) {
|
|
|
404
443
|
emitCaptureEvent(next, "capturestart", source, row ?? hoveredRowForNode(next), x, y);
|
|
405
444
|
}
|
|
406
445
|
}
|
|
446
|
+
function listItemKey(node, index) {
|
|
447
|
+
const items = Array.isArray(node.props.items) ? node.props.items : [];
|
|
448
|
+
const item = items[index];
|
|
449
|
+
if (typeof node.props.itemKey === "function" && typeof item !== "undefined") {
|
|
450
|
+
const key = node.props.itemKey(item, index);
|
|
451
|
+
if (typeof key === "string" || typeof key === "number") {
|
|
452
|
+
return String(key);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return undefined;
|
|
456
|
+
}
|
|
457
|
+
function listViewportRows(node) {
|
|
458
|
+
const context = renderContext();
|
|
459
|
+
const items = Array.isArray(node.props.items) ? node.props.items : [];
|
|
460
|
+
const hitbox = node.props.id ? currentHitboxes.find((box) => box.id === node.props.id) : null;
|
|
461
|
+
const overscan = typeof node.props.overscan === "number" ? Math.max(0, Math.floor(node.props.overscan)) : 0;
|
|
462
|
+
const renderedRows = hitbox ? Math.max(1, hitbox.y2 - hitbox.y1 + 1 - overscan * 2) : null;
|
|
463
|
+
const sourceRows = Number(node.props.height || renderedRows || context.rows || items.length || 1);
|
|
464
|
+
if (!Number.isFinite(sourceRows) || !Number.isInteger(sourceRows) || sourceRows <= 0) {
|
|
465
|
+
return Math.max(1, items.length || 1);
|
|
466
|
+
}
|
|
467
|
+
return Math.max(1, Math.min(items.length || 1, sourceRows));
|
|
468
|
+
}
|
|
469
|
+
function clampListIndex(node, index) {
|
|
470
|
+
const items = Array.isArray(node.props.items) ? node.props.items : [];
|
|
471
|
+
if (items.length === 0) {
|
|
472
|
+
return 0;
|
|
473
|
+
}
|
|
474
|
+
return Math.max(0, Math.min(items.length - 1, index));
|
|
475
|
+
}
|
|
476
|
+
function currentListActiveIndex(node) {
|
|
477
|
+
return clampListIndex(node, listIndexById.get(node.props.id || "") || 0);
|
|
478
|
+
}
|
|
479
|
+
function currentListSelectedIndex(node) {
|
|
480
|
+
const id = node.props.id || "";
|
|
481
|
+
if (node.props.showActive === false) {
|
|
482
|
+
return null;
|
|
483
|
+
}
|
|
484
|
+
if (listSelectedIndexById.has(id)) {
|
|
485
|
+
const selectedIndex = listSelectedIndexById.get(id);
|
|
486
|
+
return typeof selectedIndex === "number" ? clampListIndex(node, selectedIndex) : null;
|
|
487
|
+
}
|
|
488
|
+
return currentListActiveIndex(node);
|
|
489
|
+
}
|
|
490
|
+
function currentListViewportOffset(node) {
|
|
491
|
+
const id = node.props.id || "";
|
|
492
|
+
return Math.max(0, Math.min(listMaxViewportOffset(node), listViewportOffsetById.get(id) || 0));
|
|
493
|
+
}
|
|
494
|
+
function listStatePayload(node) {
|
|
495
|
+
return {
|
|
496
|
+
activeIndex: currentListActiveIndex(node),
|
|
497
|
+
selectedIndex: currentListSelectedIndex(node),
|
|
498
|
+
viewportOffset: currentListViewportOffset(node),
|
|
499
|
+
viewportRows: listViewportRows(node)
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
function listMaxViewportOffset(node) {
|
|
503
|
+
const items = Array.isArray(node.props.items) ? node.props.items : [];
|
|
504
|
+
return Math.max(0, items.length - listViewportRows(node));
|
|
505
|
+
}
|
|
506
|
+
function setListViewportOffset(node, offset, emit = true) {
|
|
507
|
+
const id = node.props.id;
|
|
508
|
+
if (!id) {
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
const nextOffset = Math.max(0, Math.min(listMaxViewportOffset(node), offset));
|
|
512
|
+
const previous = listViewportOffsetById.get(id) || 0;
|
|
513
|
+
listViewportOffsetById.set(id, nextOffset);
|
|
514
|
+
if (emit && nextOffset !== previous) {
|
|
515
|
+
const payload = {
|
|
516
|
+
type: "viewportchange",
|
|
517
|
+
id,
|
|
518
|
+
offset: nextOffset,
|
|
519
|
+
rows: listViewportRows(node),
|
|
520
|
+
...listStatePayload(node)
|
|
521
|
+
};
|
|
522
|
+
dispatchNodeEvent(node, "viewportchange", payload);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
function ensureListActiveVisible(node, activeIndex) {
|
|
526
|
+
const id = node.props.id;
|
|
527
|
+
if (!id || !node.props.virtualized) {
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
const currentOffset = listViewportOffsetById.get(id) || 0;
|
|
531
|
+
const rows = listViewportRows(node);
|
|
532
|
+
if (activeIndex < currentOffset) {
|
|
533
|
+
setListViewportOffset(node, activeIndex);
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
if (activeIndex >= currentOffset + rows) {
|
|
537
|
+
setListViewportOffset(node, activeIndex - rows + 1);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
function dispatchListPressEvent(node, type, index) {
|
|
541
|
+
const id = node.props.id;
|
|
542
|
+
if (!id) {
|
|
543
|
+
return false;
|
|
544
|
+
}
|
|
545
|
+
const items = Array.isArray(node.props.items) ? node.props.items : [];
|
|
546
|
+
if (typeof items[index] === "undefined") {
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
const key = listItemKey(node, index);
|
|
550
|
+
const payload = typeof key === "undefined"
|
|
551
|
+
? { type, id, index, value: items[index], ...listStatePayload(node) }
|
|
552
|
+
: { type, id, index, key, value: items[index], ...listStatePayload(node) };
|
|
553
|
+
return dispatchNodeEvent(node, type, payload);
|
|
554
|
+
}
|
|
555
|
+
function dispatchButtonPressEvent(node, type) {
|
|
556
|
+
const id = String(node.props.id || "");
|
|
557
|
+
if (!id) {
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
560
|
+
return dispatchNodeEvent(node, type, { type, id });
|
|
561
|
+
}
|
|
562
|
+
function dispatchHitboxButtonPressEvent(hitbox, type) {
|
|
563
|
+
if (type !== "press" || typeof hitbox.__pressHandler !== "function") {
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
hitbox.__pressHandler({ type, id: hitbox.id });
|
|
567
|
+
return true;
|
|
568
|
+
}
|
|
569
|
+
function dispatchListPointerPressEvent(node, type, row) {
|
|
570
|
+
const items = Array.isArray(node.props.items) ? node.props.items : [];
|
|
571
|
+
const index = Math.max(0, Math.min(items.length - 1, row - 1));
|
|
572
|
+
return dispatchListPressEvent(node, type, index);
|
|
573
|
+
}
|
|
574
|
+
function dispatchInputContextPressEvent(node, hitbox, x, y) {
|
|
575
|
+
const id = String(node.props.id || "");
|
|
576
|
+
if (!id) {
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
579
|
+
const value = stripTerminalControls(node.props.value ?? "");
|
|
580
|
+
const current = normalizeInputState(inputStateById.get(id), value.length);
|
|
581
|
+
const cursor = typeof x === "number" ? cursorFromHitbox(hitbox, x) : current.cursor;
|
|
582
|
+
return dispatchNodeEvent(node, "contextpress", { type: "contextpress", id, value, cursor, x, y });
|
|
583
|
+
}
|
|
584
|
+
function dispatchScrollContextPressEvent(node, row, x, y) {
|
|
585
|
+
if (!node.props.id) {
|
|
586
|
+
return false;
|
|
587
|
+
}
|
|
588
|
+
const lines = visibleScrollLines(node);
|
|
589
|
+
const index = Math.max(0, Math.min(lines.length - 1, row - 1));
|
|
590
|
+
if (typeof lines[index] === "undefined") {
|
|
591
|
+
return false;
|
|
592
|
+
}
|
|
593
|
+
return dispatchNodeEvent(node, "contextpress", { type: "contextpress", id: node.props.id, row: index + 1, value: lines[index], x, y });
|
|
594
|
+
}
|
|
407
595
|
function emitMouseRowEvent(node, type, row, x = null, y = null) {
|
|
408
596
|
if (!node.props.id) {
|
|
409
597
|
return;
|
|
@@ -414,7 +602,10 @@ export function mountTerminal(input, options = {}) {
|
|
|
414
602
|
if (typeof items[index] === "undefined") {
|
|
415
603
|
return;
|
|
416
604
|
}
|
|
417
|
-
const
|
|
605
|
+
const key = listItemKey(node, index);
|
|
606
|
+
const payload = typeof key === "undefined"
|
|
607
|
+
? { type, id: node.props.id, row: index + 1, index, value: items[index], x, y }
|
|
608
|
+
: { type, id: node.props.id, row: index + 1, index, key, value: items[index], x, y };
|
|
418
609
|
dispatchNodeEvent(node, type, payload);
|
|
419
610
|
return;
|
|
420
611
|
}
|
|
@@ -504,28 +695,72 @@ export function mountTerminal(input, options = {}) {
|
|
|
504
695
|
setSemanticHoverFromHitbox(hitbox.id, x, y);
|
|
505
696
|
return rerender();
|
|
506
697
|
}
|
|
507
|
-
function
|
|
698
|
+
function moveListActiveTo(node, nextIndex) {
|
|
508
699
|
const id = node.props.id;
|
|
509
700
|
if (!id) {
|
|
510
701
|
return currentOutput;
|
|
511
702
|
}
|
|
512
703
|
const items = Array.isArray(node.props.items) ? node.props.items : [];
|
|
513
|
-
const
|
|
514
|
-
|
|
704
|
+
const clampedIndex = clampListIndex(node, nextIndex);
|
|
705
|
+
listIndexById.set(id, clampedIndex);
|
|
706
|
+
ensureListActiveVisible(node, clampedIndex);
|
|
707
|
+
const key = listItemKey(node, clampedIndex);
|
|
708
|
+
const payload = typeof key === "undefined"
|
|
709
|
+
? { type: "change", id, index: clampedIndex, value: items[clampedIndex], ...listStatePayload(node) }
|
|
710
|
+
: { type: "change", id, index: clampedIndex, key, value: items[clampedIndex], ...listStatePayload(node) };
|
|
711
|
+
dispatchNodeEvent(node, "change", payload);
|
|
712
|
+
return rerender();
|
|
713
|
+
}
|
|
714
|
+
function changeListSelection(node, direction) {
|
|
715
|
+
return moveListActiveTo(node, currentListActiveIndex(node) + direction);
|
|
716
|
+
}
|
|
717
|
+
function pageListSelection(node, direction) {
|
|
718
|
+
const id = node.props.id;
|
|
719
|
+
if (!id) {
|
|
720
|
+
return currentOutput;
|
|
721
|
+
}
|
|
722
|
+
const nextIndex = clampListIndex(node, currentListActiveIndex(node) + direction * listViewportRows(node));
|
|
515
723
|
listIndexById.set(id, nextIndex);
|
|
516
|
-
|
|
724
|
+
setListViewportOffset(node, nextIndex);
|
|
725
|
+
const items = Array.isArray(node.props.items) ? node.props.items : [];
|
|
726
|
+
const key = listItemKey(node, nextIndex);
|
|
727
|
+
const payload = typeof key === "undefined"
|
|
728
|
+
? { type: "change", id, index: nextIndex, value: items[nextIndex], ...listStatePayload(node) }
|
|
729
|
+
: { type: "change", id, index: nextIndex, key, value: items[nextIndex], ...listStatePayload(node) };
|
|
517
730
|
dispatchNodeEvent(node, "change", payload);
|
|
518
731
|
return rerender();
|
|
519
732
|
}
|
|
733
|
+
function moveListSelectionToBoundary(node, boundary) {
|
|
734
|
+
const items = Array.isArray(node.props.items) ? node.props.items : [];
|
|
735
|
+
return moveListActiveTo(node, boundary === "start" ? 0 : Math.max(0, items.length - 1));
|
|
736
|
+
}
|
|
520
737
|
function pressListSelection(node) {
|
|
738
|
+
const id = node.props.id;
|
|
739
|
+
if (!id) {
|
|
740
|
+
return currentOutput;
|
|
741
|
+
}
|
|
742
|
+
const currentIndex = currentListActiveIndex(node);
|
|
743
|
+
if (node.props.showActive !== false) {
|
|
744
|
+
listSelectedIndexById.set(id, currentIndex);
|
|
745
|
+
}
|
|
746
|
+
dispatchListPressEvent(node, "press", currentIndex);
|
|
747
|
+
return rerender();
|
|
748
|
+
}
|
|
749
|
+
function pressListPointerSelection(node, row) {
|
|
521
750
|
const id = node.props.id;
|
|
522
751
|
if (!id) {
|
|
523
752
|
return currentOutput;
|
|
524
753
|
}
|
|
525
754
|
const items = Array.isArray(node.props.items) ? node.props.items : [];
|
|
526
|
-
const
|
|
527
|
-
|
|
528
|
-
|
|
755
|
+
const index = Math.max(0, Math.min(items.length - 1, row - 1));
|
|
756
|
+
if (typeof items[index] === "undefined") {
|
|
757
|
+
return currentOutput;
|
|
758
|
+
}
|
|
759
|
+
listIndexById.set(id, index);
|
|
760
|
+
if (node.props.showActive !== false) {
|
|
761
|
+
listSelectedIndexById.set(id, index);
|
|
762
|
+
}
|
|
763
|
+
dispatchListPressEvent(node, "press", index);
|
|
529
764
|
return rerender();
|
|
530
765
|
}
|
|
531
766
|
function scrollFocusedNode(node, direction) {
|
|
@@ -552,7 +787,9 @@ export function mountTerminal(input, options = {}) {
|
|
|
552
787
|
return scrollFocusedNode(node, direction);
|
|
553
788
|
}
|
|
554
789
|
if (node?.tag === "terminal-list" && node.props.virtualized) {
|
|
555
|
-
|
|
790
|
+
const currentOffset = listViewportOffsetById.get(node.props.id || "") || 0;
|
|
791
|
+
setListViewportOffset(node, currentOffset + direction);
|
|
792
|
+
return rerender();
|
|
556
793
|
}
|
|
557
794
|
return rerender();
|
|
558
795
|
}
|
|
@@ -710,8 +947,7 @@ export function mountTerminal(input, options = {}) {
|
|
|
710
947
|
return currentOutput;
|
|
711
948
|
case "button.press":
|
|
712
949
|
if (node?.tag === "terminal-button") {
|
|
713
|
-
|
|
714
|
-
dispatchNodeEvent(node, "press", { type: "press", id });
|
|
950
|
+
dispatchButtonPressEvent(node, "press");
|
|
715
951
|
return rerender();
|
|
716
952
|
}
|
|
717
953
|
return currentOutput;
|
|
@@ -719,6 +955,14 @@ export function mountTerminal(input, options = {}) {
|
|
|
719
955
|
return node?.tag === "terminal-list" ? changeListSelection(node, -1) : currentOutput;
|
|
720
956
|
case "list.next":
|
|
721
957
|
return node?.tag === "terminal-list" ? changeListSelection(node, 1) : currentOutput;
|
|
958
|
+
case "list.pageUp":
|
|
959
|
+
return node?.tag === "terminal-list" ? pageListSelection(node, -1) : currentOutput;
|
|
960
|
+
case "list.pageDown":
|
|
961
|
+
return node?.tag === "terminal-list" ? pageListSelection(node, 1) : currentOutput;
|
|
962
|
+
case "list.home":
|
|
963
|
+
return node?.tag === "terminal-list" ? moveListSelectionToBoundary(node, "start") : currentOutput;
|
|
964
|
+
case "list.end":
|
|
965
|
+
return node?.tag === "terminal-list" ? moveListSelectionToBoundary(node, "end") : currentOutput;
|
|
722
966
|
case "list.press":
|
|
723
967
|
return node?.tag === "terminal-list" ? pressListSelection(node) : currentOutput;
|
|
724
968
|
case "scroll.up":
|
|
@@ -754,6 +998,19 @@ export function mountTerminal(input, options = {}) {
|
|
|
754
998
|
return;
|
|
755
999
|
}
|
|
756
1000
|
terminalSize = nextSize;
|
|
1001
|
+
const focusedNode = findFocused(currentTree, focusedId);
|
|
1002
|
+
if (focusedNode?.tag === "terminal-list" && focusedNode.props.id && focusedNode.props.virtualized) {
|
|
1003
|
+
const items = Array.isArray(focusedNode.props.items) ? focusedNode.props.items : [];
|
|
1004
|
+
const rows = Math.max(1, Math.min(items.length || 1, Number(focusedNode.props.height || terminalSize.rows || items.length || 1)));
|
|
1005
|
+
const activeIndex = currentListActiveIndex(focusedNode);
|
|
1006
|
+
const currentOffset = listViewportOffsetById.get(focusedNode.props.id) || 0;
|
|
1007
|
+
if (activeIndex < currentOffset) {
|
|
1008
|
+
listViewportOffsetById.set(focusedNode.props.id, activeIndex);
|
|
1009
|
+
}
|
|
1010
|
+
else if (activeIndex >= currentOffset + rows) {
|
|
1011
|
+
listViewportOffsetById.set(focusedNode.props.id, Math.max(0, activeIndex - rows + 1));
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
757
1014
|
rerender();
|
|
758
1015
|
},
|
|
759
1016
|
update() {
|
|
@@ -834,7 +1091,7 @@ export function mountTerminal(input, options = {}) {
|
|
|
834
1091
|
if (id) {
|
|
835
1092
|
focusedId = node.props.id || focusedId;
|
|
836
1093
|
}
|
|
837
|
-
|
|
1094
|
+
dispatchButtonPressEvent(node, "press");
|
|
838
1095
|
return rerender();
|
|
839
1096
|
},
|
|
840
1097
|
clickAt(x, y) {
|
|
@@ -844,7 +1101,14 @@ export function mountTerminal(input, options = {}) {
|
|
|
844
1101
|
return currentOutput;
|
|
845
1102
|
}
|
|
846
1103
|
if (hitbox.tag === "terminal-button") {
|
|
847
|
-
|
|
1104
|
+
const node = findFocusableById(currentTree, hitbox.id);
|
|
1105
|
+
if (node?.tag === "terminal-button") {
|
|
1106
|
+
return this.click(hitbox.id);
|
|
1107
|
+
}
|
|
1108
|
+
if (dispatchHitboxButtonPressEvent(hitbox, "press")) {
|
|
1109
|
+
return rerender();
|
|
1110
|
+
}
|
|
1111
|
+
return currentOutput;
|
|
848
1112
|
}
|
|
849
1113
|
setSemanticHoverFromHitbox(hitbox.id, x, y);
|
|
850
1114
|
focusedId = hitbox.id;
|
|
@@ -852,6 +1116,12 @@ export function mountTerminal(input, options = {}) {
|
|
|
852
1116
|
mouseSelectionId = hitbox.id;
|
|
853
1117
|
return setCursorFromHitbox(hitbox.id, x, false);
|
|
854
1118
|
}
|
|
1119
|
+
if (hitbox.tag === "terminal-list") {
|
|
1120
|
+
const node = findFocusableById(currentTree, hitbox.id);
|
|
1121
|
+
if (node?.tag === "terminal-list") {
|
|
1122
|
+
return pressListPointerSelection(node, sourceRowFromHitbox(node, hitbox, y));
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
855
1125
|
rerender();
|
|
856
1126
|
return currentOutput;
|
|
857
1127
|
},
|
|
@@ -975,6 +1245,142 @@ export function mountTerminal(input, options = {}) {
|
|
|
975
1245
|
session.dispatchKey(parseTerminalKey(char));
|
|
976
1246
|
}
|
|
977
1247
|
}
|
|
1248
|
+
function isPrimaryMouseButton(button) {
|
|
1249
|
+
return button < 64 && (button & 3) === 0;
|
|
1250
|
+
}
|
|
1251
|
+
function isContextMouseButton(button) {
|
|
1252
|
+
return button < 64 && (button & 3) === 2;
|
|
1253
|
+
}
|
|
1254
|
+
function isDoublePrimaryPress(hitbox, row) {
|
|
1255
|
+
const now = Date.now();
|
|
1256
|
+
const isDouble = Boolean(lastPrimaryPress
|
|
1257
|
+
&& lastPrimaryPress.id === hitbox.id
|
|
1258
|
+
&& lastPrimaryPress.tag === hitbox.tag
|
|
1259
|
+
&& lastPrimaryPress.row === row
|
|
1260
|
+
&& now - lastPrimaryPress.at <= DOUBLE_PRESS_INTERVAL_MS);
|
|
1261
|
+
lastPrimaryPress = { id: hitbox.id, tag: hitbox.tag, row, at: now };
|
|
1262
|
+
return isDouble;
|
|
1263
|
+
}
|
|
1264
|
+
function doublePressAt(hitbox, x, y) {
|
|
1265
|
+
const node = findFocusableById(currentTree, hitbox.id);
|
|
1266
|
+
if (!node) {
|
|
1267
|
+
return currentOutput;
|
|
1268
|
+
}
|
|
1269
|
+
focusedId = hitbox.id;
|
|
1270
|
+
setSemanticHoverFromHitbox(hitbox.id, x, y);
|
|
1271
|
+
if (node.tag === "terminal-button") {
|
|
1272
|
+
dispatchButtonPressEvent(node, "doublepress");
|
|
1273
|
+
return rerender();
|
|
1274
|
+
}
|
|
1275
|
+
if (node.tag === "terminal-list") {
|
|
1276
|
+
dispatchListPointerPressEvent(node, "doublepress", sourceRowFromHitbox(node, hitbox, y));
|
|
1277
|
+
return rerender();
|
|
1278
|
+
}
|
|
1279
|
+
return currentOutput;
|
|
1280
|
+
}
|
|
1281
|
+
function contextPressAt(x, y) {
|
|
1282
|
+
const hitbox = resolvePointerTarget(currentHitboxes, x, y);
|
|
1283
|
+
if (!hitbox) {
|
|
1284
|
+
clearSemanticHover(undefined, x, y);
|
|
1285
|
+
return currentOutput;
|
|
1286
|
+
}
|
|
1287
|
+
const node = findFocusableById(currentTree, hitbox.id);
|
|
1288
|
+
if (!node) {
|
|
1289
|
+
return currentOutput;
|
|
1290
|
+
}
|
|
1291
|
+
focusedId = hitbox.id;
|
|
1292
|
+
setSemanticHoverFromHitbox(hitbox.id, x, y);
|
|
1293
|
+
if (node.tag === "terminal-button") {
|
|
1294
|
+
dispatchButtonPressEvent(node, "contextpress");
|
|
1295
|
+
return rerender();
|
|
1296
|
+
}
|
|
1297
|
+
if (node.tag === "terminal-list") {
|
|
1298
|
+
dispatchListPointerPressEvent(node, "contextpress", sourceRowFromHitbox(node, hitbox, y));
|
|
1299
|
+
return rerender();
|
|
1300
|
+
}
|
|
1301
|
+
if (node.tag === "terminal-input") {
|
|
1302
|
+
dispatchInputContextPressEvent(node, hitbox, x, y);
|
|
1303
|
+
return rerender();
|
|
1304
|
+
}
|
|
1305
|
+
if (node.tag === "terminal-scroll") {
|
|
1306
|
+
dispatchScrollContextPressEvent(node, sourceRowFromHitbox(node, hitbox, y), x, y);
|
|
1307
|
+
return rerender();
|
|
1308
|
+
}
|
|
1309
|
+
return currentOutput;
|
|
1310
|
+
}
|
|
1311
|
+
function processParsedMouseInput(parsed) {
|
|
1312
|
+
if (parsed.action === "press") {
|
|
1313
|
+
const hitbox = resolvePointerTarget(currentHitboxes, parsed.x, parsed.y);
|
|
1314
|
+
if (isContextMouseButton(parsed.button)) {
|
|
1315
|
+
lastPrimaryPress = null;
|
|
1316
|
+
contextPressAt(parsed.x, parsed.y);
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
if (hitbox?.tag === "terminal-input") {
|
|
1320
|
+
mouseSelectionId = hitbox.id;
|
|
1321
|
+
}
|
|
1322
|
+
const node = hitbox ? findFocusableById(currentTree, hitbox.id) : null;
|
|
1323
|
+
if (hitbox && node && shouldPointerCapture(node)) {
|
|
1324
|
+
setPointerCapture(hitbox.id, "press", sourceRowFromHitbox(node, hitbox, parsed.y), parsed.x, parsed.y);
|
|
1325
|
+
}
|
|
1326
|
+
const isPrimaryPress = isPrimaryMouseButton(parsed.button);
|
|
1327
|
+
const isDoublePressEligible = Boolean(hitbox
|
|
1328
|
+
&& node
|
|
1329
|
+
&& (hitbox.tag === "terminal-button" || hitbox.tag === "terminal-list"));
|
|
1330
|
+
const primaryPressRow = hitbox && node && hitbox.tag === "terminal-list"
|
|
1331
|
+
? sourceRowFromHitbox(node, hitbox, parsed.y)
|
|
1332
|
+
: null;
|
|
1333
|
+
const shouldDispatchDoublePress = Boolean(isPrimaryPress
|
|
1334
|
+
&& isDoublePressEligible
|
|
1335
|
+
&& hitbox
|
|
1336
|
+
&& isDoublePrimaryPress(hitbox, primaryPressRow));
|
|
1337
|
+
if (isPrimaryPress && !isDoublePressEligible) {
|
|
1338
|
+
lastPrimaryPress = null;
|
|
1339
|
+
}
|
|
1340
|
+
if (hitbox && shouldDispatchDoublePress && hitbox.tag === "terminal-list") {
|
|
1341
|
+
doublePressAt(hitbox, parsed.x, parsed.y);
|
|
1342
|
+
}
|
|
1343
|
+
else {
|
|
1344
|
+
session.clickAt(parsed.x, parsed.y);
|
|
1345
|
+
if (hitbox && shouldDispatchDoublePress) {
|
|
1346
|
+
doublePressAt(hitbox, parsed.x, parsed.y);
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
else if (parsed.action === "drag") {
|
|
1351
|
+
if (mouseSelectionId) {
|
|
1352
|
+
setCursorFromHitbox(mouseSelectionId, parsed.x, true);
|
|
1353
|
+
}
|
|
1354
|
+
else {
|
|
1355
|
+
hoverAt(parsed.x, parsed.y);
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
else if (parsed.action === "release") {
|
|
1359
|
+
mouseSelectionId = null;
|
|
1360
|
+
const capturedId = pointerCaptureId;
|
|
1361
|
+
const releaseHitbox = resolvePointerTarget(currentHitboxes, parsed.x, parsed.y);
|
|
1362
|
+
const releaseNode = releaseHitbox ? findFocusableById(currentTree, releaseHitbox.id) : null;
|
|
1363
|
+
const releaseRow = releaseHitbox && releaseNode
|
|
1364
|
+
? sourceRowFromHitbox(releaseNode, releaseHitbox, parsed.y)
|
|
1365
|
+
: null;
|
|
1366
|
+
setPointerCapture(null, "release", capturedId && releaseHitbox?.id === capturedId ? releaseRow : null, parsed.x, parsed.y);
|
|
1367
|
+
const hitbox = resolvePointerTarget(currentHitboxes, parsed.x, parsed.y);
|
|
1368
|
+
if (capturedId && hitbox && hitbox.id === capturedId && (hitbox.tag === "terminal-list" || hitbox.tag === "terminal-scroll")) {
|
|
1369
|
+
setSemanticHoverFromHitbox(hitbox.id, parsed.x, parsed.y);
|
|
1370
|
+
rerender();
|
|
1371
|
+
}
|
|
1372
|
+
else {
|
|
1373
|
+
clearSemanticHover(undefined, parsed.x, parsed.y);
|
|
1374
|
+
rerender();
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
else if (parsed.action === "wheel-up") {
|
|
1378
|
+
wheelAt(parsed.x, parsed.y, -1);
|
|
1379
|
+
}
|
|
1380
|
+
else if (parsed.action === "wheel-down") {
|
|
1381
|
+
wheelAt(parsed.x, parsed.y, 1);
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
978
1384
|
function processInputStream(value) {
|
|
979
1385
|
if (!value) {
|
|
980
1386
|
return;
|
|
@@ -1026,52 +1432,15 @@ export function mountTerminal(input, options = {}) {
|
|
|
1026
1432
|
processInputStream(paste.rest);
|
|
1027
1433
|
return;
|
|
1028
1434
|
}
|
|
1435
|
+
const parsedMouse = parseTerminalMousePrefix(value);
|
|
1436
|
+
if (parsedMouse) {
|
|
1437
|
+
processParsedMouseInput(parsedMouse.input);
|
|
1438
|
+
processInputStream(parsedMouse.rest);
|
|
1439
|
+
return;
|
|
1440
|
+
}
|
|
1029
1441
|
const parsed = parseTerminalInput(value);
|
|
1030
1442
|
if (parsed.type === "mouse") {
|
|
1031
|
-
|
|
1032
|
-
const hitbox = resolvePointerTarget(currentHitboxes, parsed.x, parsed.y);
|
|
1033
|
-
if (hitbox?.tag === "terminal-input") {
|
|
1034
|
-
mouseSelectionId = hitbox.id;
|
|
1035
|
-
}
|
|
1036
|
-
const node = hitbox ? findFocusableById(currentTree, hitbox.id) : null;
|
|
1037
|
-
if (hitbox && node && shouldPointerCapture(node)) {
|
|
1038
|
-
setPointerCapture(hitbox.id, "press", sourceRowFromHitbox(node, hitbox, parsed.y), parsed.x, parsed.y);
|
|
1039
|
-
}
|
|
1040
|
-
session.clickAt(parsed.x, parsed.y);
|
|
1041
|
-
}
|
|
1042
|
-
else if (parsed.action === "drag") {
|
|
1043
|
-
if (mouseSelectionId) {
|
|
1044
|
-
setCursorFromHitbox(mouseSelectionId, parsed.x, true);
|
|
1045
|
-
}
|
|
1046
|
-
else {
|
|
1047
|
-
hoverAt(parsed.x, parsed.y);
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
else if (parsed.action === "release") {
|
|
1051
|
-
mouseSelectionId = null;
|
|
1052
|
-
const capturedId = pointerCaptureId;
|
|
1053
|
-
const releaseHitbox = resolvePointerTarget(currentHitboxes, parsed.x, parsed.y);
|
|
1054
|
-
const releaseNode = releaseHitbox ? findFocusableById(currentTree, releaseHitbox.id) : null;
|
|
1055
|
-
const releaseRow = releaseHitbox && releaseNode
|
|
1056
|
-
? sourceRowFromHitbox(releaseNode, releaseHitbox, parsed.y)
|
|
1057
|
-
: null;
|
|
1058
|
-
setPointerCapture(null, "release", capturedId && releaseHitbox?.id === capturedId ? releaseRow : null, parsed.x, parsed.y);
|
|
1059
|
-
const hitbox = resolvePointerTarget(currentHitboxes, parsed.x, parsed.y);
|
|
1060
|
-
if (capturedId && hitbox && hitbox.id === capturedId && (hitbox.tag === "terminal-list" || hitbox.tag === "terminal-scroll")) {
|
|
1061
|
-
setSemanticHoverFromHitbox(hitbox.id, parsed.x, parsed.y);
|
|
1062
|
-
rerender();
|
|
1063
|
-
}
|
|
1064
|
-
else {
|
|
1065
|
-
clearSemanticHover(undefined, parsed.x, parsed.y);
|
|
1066
|
-
rerender();
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
else if (parsed.action === "wheel-up") {
|
|
1070
|
-
wheelAt(parsed.x, parsed.y, -1);
|
|
1071
|
-
}
|
|
1072
|
-
else if (parsed.action === "wheel-down") {
|
|
1073
|
-
wheelAt(parsed.x, parsed.y, 1);
|
|
1074
|
-
}
|
|
1443
|
+
processParsedMouseInput(parsed);
|
|
1075
1444
|
return;
|
|
1076
1445
|
}
|
|
1077
1446
|
processKeyStream(value);
|