Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/base/browser/globalPointerMoveMonitor.ts
3292 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import * as dom from './dom.js';
7
import { DisposableStore, IDisposable, toDisposable } from '../common/lifecycle.js';
8
9
export interface IPointerMoveCallback {
10
(event: PointerEvent): void;
11
}
12
13
export interface IOnStopCallback {
14
(browserEvent?: PointerEvent | KeyboardEvent): void;
15
}
16
17
export class GlobalPointerMoveMonitor implements IDisposable {
18
19
private readonly _hooks = new DisposableStore();
20
private _pointerMoveCallback: IPointerMoveCallback | null = null;
21
private _onStopCallback: IOnStopCallback | null = null;
22
23
public dispose(): void {
24
this.stopMonitoring(false);
25
this._hooks.dispose();
26
}
27
28
public stopMonitoring(invokeStopCallback: boolean, browserEvent?: PointerEvent | KeyboardEvent): void {
29
if (!this.isMonitoring()) {
30
// Not monitoring
31
return;
32
}
33
34
// Unhook
35
this._hooks.clear();
36
this._pointerMoveCallback = null;
37
const onStopCallback = this._onStopCallback;
38
this._onStopCallback = null;
39
40
if (invokeStopCallback && onStopCallback) {
41
onStopCallback(browserEvent);
42
}
43
}
44
45
public isMonitoring(): boolean {
46
return !!this._pointerMoveCallback;
47
}
48
49
public startMonitoring(
50
initialElement: Element,
51
pointerId: number,
52
initialButtons: number,
53
pointerMoveCallback: IPointerMoveCallback,
54
onStopCallback: IOnStopCallback
55
): void {
56
if (this.isMonitoring()) {
57
this.stopMonitoring(false);
58
}
59
this._pointerMoveCallback = pointerMoveCallback;
60
this._onStopCallback = onStopCallback;
61
62
let eventSource: Element | Window = initialElement;
63
64
try {
65
initialElement.setPointerCapture(pointerId);
66
this._hooks.add(toDisposable(() => {
67
try {
68
initialElement.releasePointerCapture(pointerId);
69
} catch (err) {
70
// See https://github.com/microsoft/vscode/issues/161731
71
//
72
// `releasePointerCapture` sometimes fails when being invoked with the exception:
73
// DOMException: Failed to execute 'releasePointerCapture' on 'Element':
74
// No active pointer with the given id is found.
75
//
76
// There's no need to do anything in case of failure
77
}
78
}));
79
} catch (err) {
80
// See https://github.com/microsoft/vscode/issues/144584
81
// See https://github.com/microsoft/vscode/issues/146947
82
// `setPointerCapture` sometimes fails when being invoked
83
// from a `mousedown` listener on macOS and Windows
84
// and it always fails on Linux with the exception:
85
// DOMException: Failed to execute 'setPointerCapture' on 'Element':
86
// No active pointer with the given id is found.
87
// In case of failure, we bind the listeners on the window
88
eventSource = dom.getWindow(initialElement);
89
}
90
91
this._hooks.add(dom.addDisposableListener(
92
eventSource,
93
dom.EventType.POINTER_MOVE,
94
(e) => {
95
if (e.buttons !== initialButtons) {
96
// Buttons state has changed in the meantime
97
this.stopMonitoring(true);
98
return;
99
}
100
101
e.preventDefault();
102
this._pointerMoveCallback!(e);
103
}
104
));
105
106
this._hooks.add(dom.addDisposableListener(
107
eventSource,
108
dom.EventType.POINTER_UP,
109
(e: PointerEvent) => this.stopMonitoring(true)
110
));
111
}
112
}
113
114