tinky-mouse 1.0.0 → 1.0.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/lib/contexts/MouseContext.js +33 -83
- package/lib/hooks/use-mouse-context.d.ts +1 -1
- package/lib/hooks/use-mouse-context.js +4 -7
- package/lib/hooks/use-mouse.js +6 -10
- package/lib/index.js +3 -11
- package/lib/utils/mouse.js +54 -61
- package/lib/utils/sequences.js +16 -22
- package/package.json +1 -1
|
@@ -1,34 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
if (o && i >= o.length) o = void 0;
|
|
8
|
-
return { value: o && o[i++], done: !o };
|
|
9
|
-
}
|
|
10
|
-
};
|
|
11
|
-
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
12
|
-
};
|
|
13
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.MouseContext = void 0;
|
|
15
|
-
exports.enableMouseEvents = enableMouseEvents;
|
|
16
|
-
exports.disableMouseEvents = disableMouseEvents;
|
|
17
|
-
exports.MouseProvider = MouseProvider;
|
|
18
|
-
var jsx_runtime_1 = require("react/jsx-runtime");
|
|
19
|
-
var tinky_1 = require("tinky");
|
|
20
|
-
var react_1 = require("react");
|
|
21
|
-
var sequences_js_1 = require("../utils/sequences.js");
|
|
22
|
-
var mouse_js_1 = require("../utils/mouse.js");
|
|
23
|
-
var MAX_MOUSE_BUFFER_SIZE = 4096;
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useStdin } from "tinky";
|
|
3
|
+
import { createContext, useCallback, useEffect, useRef } from "react";
|
|
4
|
+
import { ESC } from "../utils/sequences.js";
|
|
5
|
+
import { isIncompleteMouseSequence, parseMouseEvent, } from "../utils/mouse.js";
|
|
6
|
+
const MAX_MOUSE_BUFFER_SIZE = 4096;
|
|
24
7
|
// ANSI escape sequences for mouse event control
|
|
25
|
-
|
|
8
|
+
const ENABLE_MOUSE_SEQUENCES = [
|
|
26
9
|
"\x1b[?1000h", // Enable basic mouse mode (button press/release)
|
|
27
10
|
"\x1b[?1002h", // Enable button event tracking (motion while button down)
|
|
28
11
|
"\x1b[?1003h", // Enable any event tracking (all motion) - optional
|
|
29
12
|
"\x1b[?1006h", // Enable SGR extended mode (better coordinate reporting)
|
|
30
13
|
];
|
|
31
|
-
|
|
14
|
+
const DISABLE_MOUSE_SEQUENCES = [
|
|
32
15
|
"\x1b[?1006l", // Disable SGR extended mode
|
|
33
16
|
"\x1b[?1003l", // Disable any event tracking
|
|
34
17
|
"\x1b[?1002l", // Disable button event tracking
|
|
@@ -37,39 +20,17 @@ var DISABLE_MOUSE_SEQUENCES = [
|
|
|
37
20
|
/**
|
|
38
21
|
* Enable mouse event reporting in the terminal.
|
|
39
22
|
*/
|
|
40
|
-
function enableMouseEvents() {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
for (var ENABLE_MOUSE_SEQUENCES_1 = __values(ENABLE_MOUSE_SEQUENCES), ENABLE_MOUSE_SEQUENCES_1_1 = ENABLE_MOUSE_SEQUENCES_1.next(); !ENABLE_MOUSE_SEQUENCES_1_1.done; ENABLE_MOUSE_SEQUENCES_1_1 = ENABLE_MOUSE_SEQUENCES_1.next()) {
|
|
44
|
-
var seq = ENABLE_MOUSE_SEQUENCES_1_1.value;
|
|
45
|
-
process.stdout.write(seq);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
49
|
-
finally {
|
|
50
|
-
try {
|
|
51
|
-
if (ENABLE_MOUSE_SEQUENCES_1_1 && !ENABLE_MOUSE_SEQUENCES_1_1.done && (_a = ENABLE_MOUSE_SEQUENCES_1.return)) _a.call(ENABLE_MOUSE_SEQUENCES_1);
|
|
52
|
-
}
|
|
53
|
-
finally { if (e_1) throw e_1.error; }
|
|
23
|
+
export function enableMouseEvents() {
|
|
24
|
+
for (const seq of ENABLE_MOUSE_SEQUENCES) {
|
|
25
|
+
process.stdout.write(seq);
|
|
54
26
|
}
|
|
55
27
|
}
|
|
56
28
|
/**
|
|
57
29
|
* Disable mouse event reporting in the terminal.
|
|
58
30
|
*/
|
|
59
|
-
function disableMouseEvents() {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
for (var DISABLE_MOUSE_SEQUENCES_1 = __values(DISABLE_MOUSE_SEQUENCES), DISABLE_MOUSE_SEQUENCES_1_1 = DISABLE_MOUSE_SEQUENCES_1.next(); !DISABLE_MOUSE_SEQUENCES_1_1.done; DISABLE_MOUSE_SEQUENCES_1_1 = DISABLE_MOUSE_SEQUENCES_1.next()) {
|
|
63
|
-
var seq = DISABLE_MOUSE_SEQUENCES_1_1.value;
|
|
64
|
-
process.stdout.write(seq);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
68
|
-
finally {
|
|
69
|
-
try {
|
|
70
|
-
if (DISABLE_MOUSE_SEQUENCES_1_1 && !DISABLE_MOUSE_SEQUENCES_1_1.done && (_a = DISABLE_MOUSE_SEQUENCES_1.return)) _a.call(DISABLE_MOUSE_SEQUENCES_1);
|
|
71
|
-
}
|
|
72
|
-
finally { if (e_2) throw e_2.error; }
|
|
31
|
+
export function disableMouseEvents() {
|
|
32
|
+
for (const seq of DISABLE_MOUSE_SEQUENCES) {
|
|
33
|
+
process.stdout.write(seq);
|
|
73
34
|
}
|
|
74
35
|
}
|
|
75
36
|
/**
|
|
@@ -78,7 +39,7 @@ function disableMouseEvents() {
|
|
|
78
39
|
/**
|
|
79
40
|
* Context for managing mouse events.
|
|
80
41
|
*/
|
|
81
|
-
|
|
42
|
+
export const MouseContext = createContext(undefined);
|
|
82
43
|
/**
|
|
83
44
|
* Provider component that sets up mouse event listening and distribution.
|
|
84
45
|
*
|
|
@@ -94,58 +55,47 @@ exports.MouseContext = (0, react_1.createContext)(undefined);
|
|
|
94
55
|
*
|
|
95
56
|
* @param props - The component props.
|
|
96
57
|
*/
|
|
97
|
-
function MouseProvider(props) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
58
|
+
export function MouseProvider(props) {
|
|
59
|
+
const { children, mouseEventsEnabled } = props;
|
|
60
|
+
const { stdin } = useStdin();
|
|
61
|
+
const subscribers = useRef(new Set()).current;
|
|
62
|
+
const subscribe = useCallback((handler) => {
|
|
102
63
|
subscribers.add(handler);
|
|
103
64
|
}, [subscribers]);
|
|
104
|
-
|
|
65
|
+
const unsubscribe = useCallback((handler) => {
|
|
105
66
|
subscribers.delete(handler);
|
|
106
67
|
}, [subscribers]);
|
|
107
|
-
|
|
68
|
+
useEffect(() => {
|
|
108
69
|
if (!mouseEventsEnabled) {
|
|
109
70
|
return;
|
|
110
71
|
}
|
|
111
72
|
// Enable mouse event reporting in terminal
|
|
112
73
|
enableMouseEvents();
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
for (var subscribers_1 = __values(subscribers), subscribers_1_1 = subscribers_1.next(); !subscribers_1_1.done; subscribers_1_1 = subscribers_1.next()) {
|
|
118
|
-
var handler = subscribers_1_1.value;
|
|
119
|
-
handler(event);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
123
|
-
finally {
|
|
124
|
-
try {
|
|
125
|
-
if (subscribers_1_1 && !subscribers_1_1.done && (_a = subscribers_1.return)) _a.call(subscribers_1);
|
|
126
|
-
}
|
|
127
|
-
finally { if (e_3) throw e_3.error; }
|
|
74
|
+
let mouseBuffer = "";
|
|
75
|
+
const broadcast = (event) => {
|
|
76
|
+
for (const handler of subscribers) {
|
|
77
|
+
handler(event);
|
|
128
78
|
}
|
|
129
79
|
};
|
|
130
|
-
|
|
80
|
+
const handleData = (data) => {
|
|
131
81
|
mouseBuffer += typeof data === "string" ? data : data.toString("utf-8");
|
|
132
82
|
// Safety cap to prevent infinite buffer growth on garbage
|
|
133
83
|
if (mouseBuffer.length > MAX_MOUSE_BUFFER_SIZE) {
|
|
134
84
|
mouseBuffer = mouseBuffer.slice(-MAX_MOUSE_BUFFER_SIZE);
|
|
135
85
|
}
|
|
136
86
|
while (mouseBuffer.length > 0) {
|
|
137
|
-
|
|
87
|
+
const parsed = parseMouseEvent(mouseBuffer);
|
|
138
88
|
if (parsed) {
|
|
139
89
|
broadcast(parsed.event);
|
|
140
90
|
mouseBuffer = mouseBuffer.slice(parsed.length);
|
|
141
91
|
continue;
|
|
142
92
|
}
|
|
143
|
-
if (
|
|
93
|
+
if (isIncompleteMouseSequence(mouseBuffer)) {
|
|
144
94
|
break; // Wait for more data
|
|
145
95
|
}
|
|
146
96
|
// Not a valid sequence at start, and not waiting for more data.
|
|
147
97
|
// Discard garbage until next possible sequence start.
|
|
148
|
-
|
|
98
|
+
const nextEsc = mouseBuffer.indexOf(ESC, 1);
|
|
149
99
|
if (nextEsc !== -1) {
|
|
150
100
|
mouseBuffer = mouseBuffer.slice(nextEsc);
|
|
151
101
|
// Loop continues to try parsing at new location
|
|
@@ -158,13 +108,13 @@ function MouseProvider(props) {
|
|
|
158
108
|
};
|
|
159
109
|
if (!stdin)
|
|
160
110
|
return;
|
|
161
|
-
|
|
111
|
+
const stdinStream = stdin;
|
|
162
112
|
stdinStream.on("data", handleData);
|
|
163
|
-
return
|
|
113
|
+
return () => {
|
|
164
114
|
stdinStream.removeListener("data", handleData);
|
|
165
115
|
// Disable mouse event reporting when unmounting
|
|
166
116
|
disableMouseEvents();
|
|
167
117
|
};
|
|
168
118
|
}, [stdin, mouseEventsEnabled, subscribers]);
|
|
169
|
-
return ((
|
|
119
|
+
return (_jsx(MouseContext.Provider, { value: { subscribe, unsubscribe }, children: children }));
|
|
170
120
|
}
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
* @returns The mouse context value containing `subscribe` and `unsubscribe` methods.
|
|
7
7
|
* @throws Error if used outside of a `MouseProvider`.
|
|
8
8
|
*/
|
|
9
|
-
export declare function useMouseContext(): import("../
|
|
9
|
+
export declare function useMouseContext(): import("../index.js").MouseContextValue;
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.useMouseContext = useMouseContext;
|
|
4
|
-
var react_1 = require("react");
|
|
5
|
-
var MouseContext_js_1 = require("../contexts/MouseContext.js");
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { MouseContext } from "../contexts/MouseContext.js";
|
|
6
3
|
/**
|
|
7
4
|
* Hook to access the MouseContext.
|
|
8
5
|
*
|
|
@@ -11,8 +8,8 @@ var MouseContext_js_1 = require("../contexts/MouseContext.js");
|
|
|
11
8
|
* @returns The mouse context value containing `subscribe` and `unsubscribe` methods.
|
|
12
9
|
* @throws Error if used outside of a `MouseProvider`.
|
|
13
10
|
*/
|
|
14
|
-
function useMouseContext() {
|
|
15
|
-
|
|
11
|
+
export function useMouseContext() {
|
|
12
|
+
const context = useContext(MouseContext);
|
|
16
13
|
if (!context) {
|
|
17
14
|
throw new Error("useMouseContext must be used within a MouseProvider");
|
|
18
15
|
}
|
package/lib/hooks/use-mouse.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.useMouse = useMouse;
|
|
4
|
-
var react_1 = require("react");
|
|
5
|
-
var use_mouse_context_js_1 = require("./use-mouse-context.js");
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { useMouseContext } from "./use-mouse-context.js";
|
|
6
3
|
/**
|
|
7
4
|
* Hook to subscribe to mouse events.
|
|
8
5
|
*
|
|
@@ -19,14 +16,13 @@ var use_mouse_context_js_1 = require("./use-mouse-context.js");
|
|
|
19
16
|
* });
|
|
20
17
|
* ```
|
|
21
18
|
*/
|
|
22
|
-
function useMouse(handler,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
(0, react_1.useEffect)(function () {
|
|
19
|
+
export function useMouse(handler, { isActive = true } = {}) {
|
|
20
|
+
const { subscribe, unsubscribe } = useMouseContext();
|
|
21
|
+
useEffect(() => {
|
|
26
22
|
if (!isActive) {
|
|
27
23
|
return;
|
|
28
24
|
}
|
|
29
25
|
subscribe(handler);
|
|
30
|
-
return
|
|
26
|
+
return () => unsubscribe(handler);
|
|
31
27
|
}, [isActive, handler, subscribe, unsubscribe]);
|
|
32
28
|
}
|
package/lib/index.js
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var MouseContext_js_1 = require("./contexts/MouseContext.js");
|
|
5
|
-
Object.defineProperty(exports, "MouseProvider", { enumerable: true, get: function () { return MouseContext_js_1.MouseProvider; } });
|
|
6
|
-
Object.defineProperty(exports, "enableMouseEvents", { enumerable: true, get: function () { return MouseContext_js_1.enableMouseEvents; } });
|
|
7
|
-
Object.defineProperty(exports, "disableMouseEvents", { enumerable: true, get: function () { return MouseContext_js_1.disableMouseEvents; } });
|
|
8
|
-
var use_mouse_context_js_1 = require("./hooks/use-mouse-context.js");
|
|
9
|
-
Object.defineProperty(exports, "useMouseContext", { enumerable: true, get: function () { return use_mouse_context_js_1.useMouseContext; } });
|
|
10
|
-
var use_mouse_js_1 = require("./hooks/use-mouse.js");
|
|
11
|
-
Object.defineProperty(exports, "useMouse", { enumerable: true, get: function () { return use_mouse_js_1.useMouse; } });
|
|
1
|
+
export { MouseProvider, enableMouseEvents, disableMouseEvents, } from "./contexts/MouseContext.js";
|
|
2
|
+
export { useMouseContext } from "./hooks/use-mouse-context.js";
|
|
3
|
+
export { useMouse } from "./hooks/use-mouse.js";
|
package/lib/utils/mouse.js
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getMouseEventName = getMouseEventName;
|
|
4
|
-
exports.parseSGRMouseEvent = parseSGRMouseEvent;
|
|
5
|
-
exports.parseX11MouseEvent = parseX11MouseEvent;
|
|
6
|
-
exports.parseMouseEvent = parseMouseEvent;
|
|
7
|
-
exports.isIncompleteMouseSequence = isIncompleteMouseSequence;
|
|
8
|
-
var sequences_js_1 = require("./sequences.js");
|
|
1
|
+
import { SGR_MOUSE_REGEX, X11_MOUSE_REGEX, SGR_EVENT_PREFIX, X11_EVENT_PREFIX, couldBeMouseSequence, } from "./sequences.js";
|
|
9
2
|
/**
|
|
10
3
|
* Derives the `MouseEventName` from the SGR button code and release state.
|
|
11
4
|
*
|
|
@@ -13,8 +6,8 @@ var sequences_js_1 = require("./sequences.js");
|
|
|
13
6
|
* @param isRelease - Whether the event is a release event (last char is 'm').
|
|
14
7
|
* @returns The `MouseEventName` or `null` if unknown.
|
|
15
8
|
*/
|
|
16
|
-
function getMouseEventName(buttonCode, isRelease) {
|
|
17
|
-
|
|
9
|
+
export function getMouseEventName(buttonCode, isRelease) {
|
|
10
|
+
const isMove = (buttonCode & 32) !== 0;
|
|
18
11
|
if (buttonCode === 66) {
|
|
19
12
|
return "scroll-left";
|
|
20
13
|
}
|
|
@@ -33,22 +26,22 @@ function getMouseEventName(buttonCode, isRelease) {
|
|
|
33
26
|
return "move";
|
|
34
27
|
}
|
|
35
28
|
else {
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
const button = buttonCode & 3;
|
|
30
|
+
const type = isRelease ? "release" : "press";
|
|
38
31
|
switch (button) {
|
|
39
32
|
case 0:
|
|
40
|
-
return
|
|
33
|
+
return `left-${type}`;
|
|
41
34
|
case 1:
|
|
42
|
-
return
|
|
35
|
+
return `middle-${type}`;
|
|
43
36
|
case 2:
|
|
44
|
-
return
|
|
37
|
+
return `right-${type}`;
|
|
45
38
|
default:
|
|
46
39
|
return null;
|
|
47
40
|
}
|
|
48
41
|
}
|
|
49
42
|
}
|
|
50
43
|
function getButtonFromCode(code) {
|
|
51
|
-
|
|
44
|
+
const button = code & 3;
|
|
52
45
|
switch (button) {
|
|
53
46
|
case 0:
|
|
54
47
|
return "left";
|
|
@@ -71,27 +64,27 @@ function getButtonFromCode(code) {
|
|
|
71
64
|
* parseSGRMouseEvent("\x1b[<0;10;10M"); // Left press at 10,10
|
|
72
65
|
* ```
|
|
73
66
|
*/
|
|
74
|
-
function parseSGRMouseEvent(buffer) {
|
|
75
|
-
|
|
67
|
+
export function parseSGRMouseEvent(buffer) {
|
|
68
|
+
const match = buffer.match(SGR_MOUSE_REGEX);
|
|
76
69
|
if (match) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (
|
|
70
|
+
const buttonCode = parseInt(match[1], 10);
|
|
71
|
+
const col = parseInt(match[2], 10);
|
|
72
|
+
const row = parseInt(match[3], 10);
|
|
73
|
+
const action = match[4];
|
|
74
|
+
const isRelease = action === "m";
|
|
75
|
+
const shift = (buttonCode & 4) !== 0;
|
|
76
|
+
const meta = (buttonCode & 8) !== 0;
|
|
77
|
+
const ctrl = (buttonCode & 16) !== 0;
|
|
78
|
+
const name = getMouseEventName(buttonCode, isRelease);
|
|
79
|
+
if (name) {
|
|
87
80
|
return {
|
|
88
81
|
event: {
|
|
89
|
-
name
|
|
90
|
-
ctrl
|
|
91
|
-
meta
|
|
92
|
-
shift
|
|
93
|
-
col
|
|
94
|
-
row
|
|
82
|
+
name,
|
|
83
|
+
ctrl,
|
|
84
|
+
meta,
|
|
85
|
+
shift,
|
|
86
|
+
col,
|
|
87
|
+
row,
|
|
95
88
|
button: getButtonFromCode(buttonCode),
|
|
96
89
|
},
|
|
97
90
|
length: match[0].length,
|
|
@@ -112,22 +105,22 @@ function parseSGRMouseEvent(buffer) {
|
|
|
112
105
|
* parseX11MouseEvent("\x1b[M..."); // Parsed X11 event
|
|
113
106
|
* ```
|
|
114
107
|
*/
|
|
115
|
-
function parseX11MouseEvent(buffer) {
|
|
116
|
-
|
|
108
|
+
export function parseX11MouseEvent(buffer) {
|
|
109
|
+
const match = buffer.match(X11_MOUSE_REGEX);
|
|
117
110
|
if (!match)
|
|
118
111
|
return null;
|
|
119
112
|
// The 3 bytes are in match[1]
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
113
|
+
const b = match[1].charCodeAt(0) - 32;
|
|
114
|
+
const col = match[1].charCodeAt(1) - 32;
|
|
115
|
+
const row = match[1].charCodeAt(2) - 32;
|
|
116
|
+
const shift = (b & 4) !== 0;
|
|
117
|
+
const meta = (b & 8) !== 0;
|
|
118
|
+
const ctrl = (b & 16) !== 0;
|
|
119
|
+
const isMove = (b & 32) !== 0;
|
|
120
|
+
const isWheel = (b & 64) !== 0;
|
|
121
|
+
let name = null;
|
|
129
122
|
if (isWheel) {
|
|
130
|
-
|
|
123
|
+
const button = b & 3;
|
|
131
124
|
switch (button) {
|
|
132
125
|
case 0:
|
|
133
126
|
name = "scroll-up";
|
|
@@ -143,7 +136,7 @@ function parseX11MouseEvent(buffer) {
|
|
|
143
136
|
name = "move";
|
|
144
137
|
}
|
|
145
138
|
else {
|
|
146
|
-
|
|
139
|
+
const button = b & 3;
|
|
147
140
|
if (button === 3) {
|
|
148
141
|
// X11 reports 'release' (3) for all button releases without specifying which one.
|
|
149
142
|
// We'll default to 'left-release' as a best-effort guess if we don't track state.
|
|
@@ -166,19 +159,19 @@ function parseX11MouseEvent(buffer) {
|
|
|
166
159
|
}
|
|
167
160
|
}
|
|
168
161
|
if (name) {
|
|
169
|
-
|
|
162
|
+
let button = getButtonFromCode(b);
|
|
170
163
|
if (name === "left-release" && button === "none") {
|
|
171
164
|
button = "left";
|
|
172
165
|
}
|
|
173
166
|
return {
|
|
174
167
|
event: {
|
|
175
|
-
name
|
|
176
|
-
ctrl
|
|
177
|
-
meta
|
|
178
|
-
shift
|
|
179
|
-
col
|
|
180
|
-
row
|
|
181
|
-
button
|
|
168
|
+
name,
|
|
169
|
+
ctrl,
|
|
170
|
+
meta,
|
|
171
|
+
shift,
|
|
172
|
+
col,
|
|
173
|
+
row,
|
|
174
|
+
button,
|
|
182
175
|
},
|
|
183
176
|
length: match[0].length,
|
|
184
177
|
};
|
|
@@ -191,7 +184,7 @@ function parseX11MouseEvent(buffer) {
|
|
|
191
184
|
* @param buffer - The input string.
|
|
192
185
|
* @returns The parsed event and length, or `null`.
|
|
193
186
|
*/
|
|
194
|
-
function parseMouseEvent(buffer) {
|
|
187
|
+
export function parseMouseEvent(buffer) {
|
|
195
188
|
return parseSGRMouseEvent(buffer) || parseX11MouseEvent(buffer);
|
|
196
189
|
}
|
|
197
190
|
/**
|
|
@@ -201,17 +194,17 @@ function parseMouseEvent(buffer) {
|
|
|
201
194
|
* @param buffer - The input string.
|
|
202
195
|
* @returns `true` if the buffer looks like the start of a mouse sequence but is incomplete.
|
|
203
196
|
*/
|
|
204
|
-
function isIncompleteMouseSequence(buffer) {
|
|
205
|
-
if (!
|
|
197
|
+
export function isIncompleteMouseSequence(buffer) {
|
|
198
|
+
if (!couldBeMouseSequence(buffer))
|
|
206
199
|
return false;
|
|
207
200
|
// If it matches a complete sequence, it's not incomplete.
|
|
208
201
|
if (parseMouseEvent(buffer))
|
|
209
202
|
return false;
|
|
210
|
-
if (buffer.startsWith(
|
|
203
|
+
if (buffer.startsWith(X11_EVENT_PREFIX)) {
|
|
211
204
|
// X11 needs exactly 3 bytes after prefix.
|
|
212
|
-
return buffer.length <
|
|
205
|
+
return buffer.length < X11_EVENT_PREFIX.length + 3;
|
|
213
206
|
}
|
|
214
|
-
if (buffer.startsWith(
|
|
207
|
+
if (buffer.startsWith(SGR_EVENT_PREFIX)) {
|
|
215
208
|
// SGR sequences end with 'm' or 'M'.
|
|
216
209
|
// If it doesn't have it yet, it's incomplete.
|
|
217
210
|
// Add a reasonable max length check to fail early on garbage.
|
package/lib/utils/sequences.js
CHANGED
|
@@ -1,21 +1,15 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.X11_MOUSE_REGEX = exports.SGR_MOUSE_REGEX = exports.X11_EVENT_PREFIX = exports.SGR_EVENT_PREFIX = exports.ESC = void 0;
|
|
4
|
-
exports.couldBeSGRMouseSequence = couldBeSGRMouseSequence;
|
|
5
|
-
exports.couldBeMouseSequence = couldBeMouseSequence;
|
|
6
|
-
exports.getMouseSequenceLength = getMouseSequenceLength;
|
|
7
1
|
/* eslint-disable no-control-regex */
|
|
8
2
|
/** ESC character (ASCII 27). */
|
|
9
|
-
|
|
3
|
+
export const ESC = "\u001B";
|
|
10
4
|
/** Prefix for SGR (1006) mouse sequences. */
|
|
11
|
-
|
|
5
|
+
export const SGR_EVENT_PREFIX = `${ESC}[<`;
|
|
12
6
|
/** Prefix for X11 mouse sequences. */
|
|
13
|
-
|
|
7
|
+
export const X11_EVENT_PREFIX = `${ESC}[M`;
|
|
14
8
|
/** Regex to match a complete SGR mouse event sequence. */
|
|
15
|
-
|
|
9
|
+
export const SGR_MOUSE_REGEX = /^\x1b\[<(\d+);(\d+);(\d+)([mM])/; // SGR mouse events
|
|
16
10
|
// X11 is ESC [ M followed by 3 bytes.
|
|
17
11
|
/** Regex to match a complete X11 mouse event sequence. */
|
|
18
|
-
|
|
12
|
+
export const X11_MOUSE_REGEX = /^\x1b\[M([\s\S]{3})/;
|
|
19
13
|
/**
|
|
20
14
|
* Checks if the buffer starts with or is a prefix of an SGR mouse sequence.
|
|
21
15
|
*
|
|
@@ -29,14 +23,14 @@ exports.X11_MOUSE_REGEX = /^\x1b\[M([\s\S]{3})/;
|
|
|
29
23
|
* couldBeSGRMouseSequence("hello"); // false
|
|
30
24
|
* ```
|
|
31
25
|
*/
|
|
32
|
-
function couldBeSGRMouseSequence(buffer) {
|
|
26
|
+
export function couldBeSGRMouseSequence(buffer) {
|
|
33
27
|
if (buffer.length === 0)
|
|
34
28
|
return true;
|
|
35
29
|
// Check if buffer is a prefix of a mouse sequence starter
|
|
36
|
-
if (
|
|
30
|
+
if (SGR_EVENT_PREFIX.startsWith(buffer))
|
|
37
31
|
return true;
|
|
38
32
|
// Check if buffer is a mouse sequence prefix
|
|
39
|
-
if (buffer.startsWith(
|
|
33
|
+
if (buffer.startsWith(SGR_EVENT_PREFIX))
|
|
40
34
|
return true;
|
|
41
35
|
return false;
|
|
42
36
|
}
|
|
@@ -52,16 +46,16 @@ function couldBeSGRMouseSequence(buffer) {
|
|
|
52
46
|
* couldBeMouseSequence("\x1b[<"); // true
|
|
53
47
|
* ```
|
|
54
48
|
*/
|
|
55
|
-
function couldBeMouseSequence(buffer) {
|
|
49
|
+
export function couldBeMouseSequence(buffer) {
|
|
56
50
|
if (buffer.length === 0)
|
|
57
51
|
return true;
|
|
58
52
|
// Check SGR prefix
|
|
59
|
-
if (
|
|
60
|
-
buffer.startsWith(
|
|
53
|
+
if (SGR_EVENT_PREFIX.startsWith(buffer) ||
|
|
54
|
+
buffer.startsWith(SGR_EVENT_PREFIX))
|
|
61
55
|
return true;
|
|
62
56
|
// Check X11 prefix
|
|
63
|
-
if (
|
|
64
|
-
buffer.startsWith(
|
|
57
|
+
if (X11_EVENT_PREFIX.startsWith(buffer) ||
|
|
58
|
+
buffer.startsWith(X11_EVENT_PREFIX))
|
|
65
59
|
return true;
|
|
66
60
|
return false;
|
|
67
61
|
}
|
|
@@ -79,11 +73,11 @@ function couldBeMouseSequence(buffer) {
|
|
|
79
73
|
* getMouseSequenceLength("not mouse"); // 0
|
|
80
74
|
* ```
|
|
81
75
|
*/
|
|
82
|
-
function getMouseSequenceLength(buffer) {
|
|
83
|
-
|
|
76
|
+
export function getMouseSequenceLength(buffer) {
|
|
77
|
+
const sgrMatch = buffer.match(SGR_MOUSE_REGEX);
|
|
84
78
|
if (sgrMatch)
|
|
85
79
|
return sgrMatch[0].length;
|
|
86
|
-
|
|
80
|
+
const x11Match = buffer.match(X11_MOUSE_REGEX);
|
|
87
81
|
if (x11Match)
|
|
88
82
|
return x11Match[0].length;
|
|
89
83
|
return 0;
|