···
163
163
export type KeyEvent = KeyDown | KeyRepeat | KeyUp;
164
164
165
165
/**
166
166
-
* A mouse button was pressed or released
166
166
+
* A mouse button was pressed.
167
167
*/
168
168
-
export interface MouseEvent extends KeyModifiers {
169
169
-
type: "mouse";
168
168
+
export interface MouseDownEvent extends KeyModifiers {
169
169
+
type: "mousedown";
170
170
+
/**
171
171
+
* Which mouse button triggered this event.
172
172
+
*/
173
173
+
button: "left" | "right" | "middle";
174
174
+
175
175
+
/**
176
176
+
* `x` coordinate of this event
177
177
+
*/
178
178
+
x: number;
179
179
+
180
180
+
/**
181
181
+
* `y` coordinate of this event
182
182
+
*/
183
183
+
y: number;
184
184
+
}
185
185
+
186
186
+
/**
187
187
+
* A mouse button was released.
188
188
+
*/
189
189
+
export interface MouseUpEvent extends KeyModifiers {
190
190
+
type: "mouseup";
170
191
/**
171
192
* Which mouse button triggered this event.
172
193
*
···
185
206
* `y` coordinate of this event
186
207
*/
187
208
y: number;
188
188
-
189
189
-
/**
190
190
-
* True if the event represents a button being released.
191
191
-
*/
192
192
-
release?: true;
193
209
}
194
210
195
211
/**
196
212
* Mouse movement while a button is held.
197
213
*/
198
198
-
export interface DragEvent extends KeyModifiers {
199
199
-
type: "drag";
214
214
+
export interface MouseMoveEvent extends KeyModifiers {
215
215
+
type: "mousemove";
200
216
/**
201
217
* Which mouse button is being held during the drag.
202
218
*/
···
251
267
252
268
export type InputEvent =
253
269
| KeyEvent
254
254
-
| MouseEvent
255
255
-
| DragEvent
270
270
+
| MouseDownEvent
271
271
+
| MouseUpEvent
272
272
+
| MouseMoveEvent
256
273
| WheelEvent
257
274
| ResizeEvent;
258
275
···
441
458
[KEY_SCROLL_LOCK, "ScrollLock"],
442
459
]);
443
460
444
444
-
const BUTTON_NAMES = new Map<number, MouseEvent["button"]>([
461
461
+
const BUTTON_NAMES = new Map<number, MouseUpEvent["button"]>([
445
462
[KEY_MOUSE_LEFT, "left"],
446
463
[KEY_MOUSE_RIGHT, "right"],
447
464
[KEY_MOUSE_MIDDLE, "middle"],
···
526
543
if (native.mod & MOD_MOTION) {
527
544
let button = BUTTON_NAMES.get(native.key) ?? "left";
528
545
return {
529
529
-
type: "drag" as const,
546
546
+
type: "mousemove" as const,
530
547
button: button === "release" ? "left" as const : button,
531
548
x: native.x,
532
549
y: native.y,
···
534
551
};
535
552
}
536
553
let button = BUTTON_NAMES.get(native.key) ?? "left";
537
537
-
let m = mods(native);
538
538
-
let ev: MouseEvent = {
539
539
-
type: "mouse",
540
540
-
button,
541
541
-
x: native.x,
542
542
-
y: native.y,
543
543
-
...m,
544
544
-
};
545
545
-
if (native.mod & MOD_RELEASE) ev.release = true;
546
546
-
return ev;
554
554
+
if (native.mod & MOD_RELEASE) {
555
555
+
return {
556
556
+
type: "mouseup" as const,
557
557
+
button,
558
558
+
x: native.x,
559
559
+
y: native.y,
560
560
+
...mods(native),
561
561
+
};
562
562
+
} else {
563
563
+
return {
564
564
+
type: "mousedown" as const,
565
565
+
button: button as MouseDownEvent["button"],
566
566
+
x: native.x,
567
567
+
y: native.y,
568
568
+
...mods(native),
569
569
+
};
570
570
+
}
547
571
}
548
572
case EVENT_RESIZE: {
549
573
return { type: "resize", width: native.w, height: native.h };
···
61
61
#define MOUSE_BUTTON_RELEASE 3
62
62
#define MOUSE_WHEEL_BIT 64
63
63
64
64
+
static uint8_t mouse_mods(int b) {
65
65
+
uint8_t m = 0;
66
66
+
if (b & 4) m |= MOD_SHIFT;
67
67
+
if (b & 8) m |= MOD_ALT;
68
68
+
if (b & 16) m |= MOD_CTRL;
69
69
+
if (b & 32) m |= MOD_MOTION;
70
70
+
return m;
71
71
+
}
72
72
+
64
73
static uint16_t mouse_button(int b) {
65
74
switch (b & MOUSE_BUTTON_MASK) {
66
75
case MOUSE_BUTTON_LEFT:
···
94
103
int b = st->buf[3] - 0x20;
95
104
ev->type = EVENT_MOUSE;
96
105
ev->key = mouse_button(b);
97
97
-
ev->mod = (b & 32) ? MOD_MOTION : 0;
106
106
+
ev->mod = mouse_mods(b);
98
107
if (ev->key == KEY_MOUSE_RELEASE)
99
108
ev->mod |= MOD_RELEASE;
100
109
ev->x = ((uint8_t)st->buf[4]) - 0x21;
···
139
148
140
149
ev->type = EVENT_MOUSE;
141
150
ev->key = mouse_button(num[0]);
142
142
-
ev->mod = (num[0] & 32) ? MOD_MOTION : 0;
151
151
+
ev->mod = mouse_mods(num[0]);
143
152
if (trail == 'm')
144
153
ev->mod |= MOD_RELEASE;
145
154
ev->x = (num[1] - 1 < 0) ? 0 : num[1] - 1;
···
185
194
int b = num[0] - 0x20;
186
195
ev->type = EVENT_MOUSE;
187
196
ev->key = mouse_button(b);
188
188
-
ev->mod = (b & 32) ? MOD_MOTION : 0;
197
197
+
ev->mod = mouse_mods(b);
189
198
if (ev->key == KEY_MOUSE_RELEASE)
190
199
ev->mod |= MOD_RELEASE;
191
200
ev->x = (num[1] - 1 < 0) ? 0 : num[1] - 1;
···
160
160
let result = input.scan(str("\x1b[<0;35;12M"));
161
161
expect(result.events.length).toBe(1);
162
162
expect(result.events[0]).toMatchObject({
163
163
-
type: "mouse",
163
163
+
type: "mousedown",
164
164
button: "left",
165
165
x: 34,
166
166
y: 11,
···
171
171
let result = input.scan(str("\x1b[<0;10;5m"));
172
172
expect(result.events.length).toBe(1);
173
173
expect(result.events[0]).toMatchObject({
174
174
-
type: "mouse",
174
174
+
type: "mouseup",
175
175
button: "left",
176
176
x: 9,
177
177
y: 4,
178
178
-
release: true,
179
178
});
180
179
});
181
180
···
183
182
let result = input.scan(str("\x1b[<2;10;5m"));
184
183
expect(result.events.length).toBe(1);
185
184
expect(result.events[0]).toMatchObject({
186
186
-
type: "mouse",
185
185
+
type: "mouseup",
187
186
button: "right",
188
187
x: 9,
189
188
y: 4,
190
190
-
release: true,
191
189
});
192
190
});
193
191
···
195
193
let result = input.scan(str("\x1b[<1;10;5m"));
196
194
expect(result.events.length).toBe(1);
197
195
expect(result.events[0]).toMatchObject({
198
198
-
type: "mouse",
196
196
+
type: "mouseup",
199
197
button: "middle",
200
198
x: 9,
201
199
y: 4,
202
202
-
release: true,
203
200
});
204
201
});
205
202
···
208
205
let result = input.scan(bytes(0x1b, 0x5b, 0x4d, 0x23, 0x2b, 0x26));
209
206
expect(result.events.length).toBe(1);
210
207
expect(result.events[0]).toMatchObject({
211
211
-
type: "mouse",
208
208
+
type: "mouseup",
212
209
button: "release",
213
210
x: 10,
214
211
y: 5,
215
215
-
release: true,
216
212
});
217
213
});
218
214
···
243
239
let result = input.scan(bytes(0x1b, 0x5b, 0x4d, 0x20, 0x2b, 0x26));
244
240
expect(result.events.length).toBe(1);
245
241
expect(result.events[0]).toMatchObject({
246
246
-
type: "mouse",
242
242
+
type: "mousedown",
247
243
button: "left",
248
244
x: 10,
249
245
y: 5,
246
246
+
});
247
247
+
});
248
248
+
249
249
+
it("parses SGR mouse press with shift", () => {
250
250
+
// btn=4 (shift bit) => left + shift
251
251
+
let result = input.scan(str("\x1b[<4;10;5M"));
252
252
+
expect(result.events.length).toBe(1);
253
253
+
expect(result.events[0]).toMatchObject({
254
254
+
type: "mousedown",
255
255
+
button: "left",
256
256
+
x: 9,
257
257
+
y: 4,
258
258
+
shift: true,
259
259
+
});
260
260
+
});
261
261
+
262
262
+
it("parses SGR mouse press with ctrl", () => {
263
263
+
// btn=16 (ctrl bit) => left + ctrl
264
264
+
let result = input.scan(str("\x1b[<16;10;5M"));
265
265
+
expect(result.events.length).toBe(1);
266
266
+
expect(result.events[0]).toMatchObject({
267
267
+
type: "mousedown",
268
268
+
button: "left",
269
269
+
x: 9,
270
270
+
y: 4,
271
271
+
ctrl: true,
272
272
+
});
273
273
+
});
274
274
+
275
275
+
it("parses SGR mouse press with alt", () => {
276
276
+
// btn=8 (alt bit) => left + alt
277
277
+
let result = input.scan(str("\x1b[<8;10;5M"));
278
278
+
expect(result.events.length).toBe(1);
279
279
+
expect(result.events[0]).toMatchObject({
280
280
+
type: "mousedown",
281
281
+
button: "left",
282
282
+
x: 9,
283
283
+
y: 4,
284
284
+
alt: true,
285
285
+
});
286
286
+
});
287
287
+
288
288
+
it("parses SGR mouse press with ctrl+shift", () => {
289
289
+
// btn=20 (ctrl=16 + shift=4) => left + ctrl + shift
290
290
+
let result = input.scan(str("\x1b[<20;10;5M"));
291
291
+
expect(result.events.length).toBe(1);
292
292
+
expect(result.events[0]).toMatchObject({
293
293
+
type: "mousedown",
294
294
+
button: "left",
295
295
+
x: 9,
296
296
+
y: 4,
297
297
+
ctrl: true,
298
298
+
shift: true,
250
299
});
251
300
});
252
301
});