@xterm/xterm 6.1.0-beta.23 → 6.1.0-beta.231
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/README.md +62 -38
- package/css/xterm.css +29 -22
- package/lib/xterm.js +1 -1
- package/lib/xterm.js.map +1 -1
- package/lib/xterm.mjs +8 -34
- package/lib/xterm.mjs.map +4 -4
- package/package.json +25 -22
- package/src/browser/AccessibilityManager.ts +11 -6
- package/src/browser/Clipboard.ts +6 -3
- package/src/browser/CoreBrowserTerminal.ts +149 -319
- package/src/browser/Dom.ts +178 -0
- package/src/browser/Linkifier.ts +11 -11
- package/src/browser/OscLinkProvider.ts +82 -14
- package/src/browser/RenderDebouncer.ts +2 -2
- package/src/browser/TimeBasedDebouncer.ts +2 -2
- package/src/browser/Types.ts +12 -11
- package/src/browser/Viewport.ts +55 -20
- package/src/browser/decorations/BufferDecorationRenderer.ts +1 -1
- package/src/browser/decorations/OverviewRulerRenderer.ts +33 -17
- package/src/browser/input/CompositionHelper.ts +44 -8
- package/src/browser/public/Terminal.ts +25 -28
- package/src/browser/renderer/dom/DomRenderer.ts +242 -76
- package/src/browser/renderer/dom/DomRendererRowFactory.ts +19 -13
- package/src/browser/renderer/dom/WidthCache.ts +54 -52
- package/src/browser/renderer/shared/Constants.ts +7 -0
- package/src/browser/renderer/shared/TextBlinkStateManager.ts +97 -0
- package/src/browser/renderer/shared/Types.ts +8 -2
- package/src/browser/scrollable/abstractScrollbar.ts +300 -0
- package/src/browser/scrollable/fastDomNode.ts +126 -0
- package/src/browser/scrollable/globalPointerMoveMonitor.ts +90 -0
- package/src/browser/scrollable/horizontalScrollbar.ts +85 -0
- package/src/browser/scrollable/mouseEvent.ts +292 -0
- package/src/browser/scrollable/scrollable.ts +486 -0
- package/src/browser/scrollable/scrollableElement.ts +581 -0
- package/src/browser/scrollable/scrollableElementOptions.ts +161 -0
- package/src/browser/scrollable/scrollbarArrow.ts +110 -0
- package/src/browser/scrollable/scrollbarState.ts +246 -0
- package/src/browser/scrollable/scrollbarVisibilityController.ts +113 -0
- package/src/browser/scrollable/touch.ts +485 -0
- package/src/browser/scrollable/verticalScrollbar.ts +143 -0
- package/src/browser/scrollable/widget.ts +23 -0
- package/src/browser/services/CharSizeService.ts +2 -2
- package/src/browser/services/CoreBrowserService.ts +7 -5
- package/src/browser/services/KeyboardService.ts +67 -0
- package/src/browser/services/LinkProviderService.ts +1 -1
- package/src/browser/services/MouseCoordsService.ts +47 -0
- package/src/browser/services/MouseService.ts +518 -25
- package/src/browser/services/RenderService.ts +28 -16
- package/src/browser/services/SelectionService.ts +45 -39
- package/src/browser/services/Services.ts +40 -17
- package/src/browser/services/ThemeService.ts +2 -2
- package/src/common/Async.ts +141 -0
- package/src/common/CircularList.ts +2 -2
- package/src/common/Color.ts +8 -0
- package/src/common/CoreTerminal.ts +31 -21
- package/src/common/Event.ts +118 -0
- package/src/common/InputHandler.ts +283 -81
- package/src/common/Lifecycle.ts +113 -0
- package/src/common/Platform.ts +13 -3
- package/src/common/SortedList.ts +7 -3
- package/src/common/TaskQueue.ts +14 -5
- package/src/common/Types.ts +51 -31
- package/src/common/Version.ts +9 -0
- package/src/common/buffer/Buffer.ts +34 -19
- package/src/common/buffer/BufferLine.ts +133 -65
- package/src/common/buffer/BufferLineStringCache.ts +69 -0
- package/src/common/buffer/BufferSet.ts +11 -6
- package/src/common/buffer/CellData.ts +57 -0
- package/src/common/buffer/Marker.ts +2 -2
- package/src/common/buffer/Types.ts +6 -2
- package/src/common/data/EscapeSequences.ts +71 -70
- package/src/common/input/Keyboard.ts +14 -7
- package/src/common/input/KittyKeyboard.ts +526 -0
- package/src/common/input/Win32InputMode.ts +297 -0
- package/src/common/input/WriteBuffer.ts +69 -32
- package/src/common/input/XParseColor.ts +2 -2
- package/src/common/parser/ApcParser.ts +197 -0
- package/src/common/parser/Constants.ts +14 -4
- package/src/common/parser/DcsParser.ts +5 -5
- package/src/common/parser/EscapeSequenceParser.ts +205 -63
- package/src/common/parser/OscParser.ts +5 -5
- package/src/common/parser/Params.ts +27 -8
- package/src/common/parser/Types.ts +36 -2
- package/src/common/public/BufferLineApiView.ts +2 -2
- package/src/common/public/BufferNamespaceApi.ts +3 -3
- package/src/common/public/ParserApi.ts +3 -0
- package/src/common/services/BufferService.ts +14 -9
- package/src/common/services/CharsetService.ts +4 -0
- package/src/common/services/CoreService.ts +18 -4
- package/src/common/services/DecorationService.ts +258 -8
- package/src/common/services/LogService.ts +1 -31
- package/src/common/services/{CoreMouseService.ts → MouseStateService.ts} +21 -132
- package/src/common/services/OptionsService.ts +13 -4
- package/src/common/services/ServiceRegistry.ts +9 -7
- package/src/common/services/Services.ts +49 -40
- package/src/common/services/UnicodeService.ts +1 -1
- package/typings/xterm.d.ts +318 -34
- package/src/common/TypedArrayUtils.ts +0 -17
- package/src/vs/base/browser/browser.ts +0 -141
- package/src/vs/base/browser/canIUse.ts +0 -49
- package/src/vs/base/browser/dom.ts +0 -2369
- package/src/vs/base/browser/fastDomNode.ts +0 -316
- package/src/vs/base/browser/globalPointerMoveMonitor.ts +0 -112
- package/src/vs/base/browser/iframe.ts +0 -135
- package/src/vs/base/browser/keyboardEvent.ts +0 -213
- package/src/vs/base/browser/mouseEvent.ts +0 -229
- package/src/vs/base/browser/touch.ts +0 -372
- package/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts +0 -303
- package/src/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts +0 -114
- package/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +0 -720
- package/src/vs/base/browser/ui/scrollbar/scrollableElementOptions.ts +0 -165
- package/src/vs/base/browser/ui/scrollbar/scrollbarArrow.ts +0 -114
- package/src/vs/base/browser/ui/scrollbar/scrollbarState.ts +0 -243
- package/src/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts +0 -118
- package/src/vs/base/browser/ui/scrollbar/verticalScrollbar.ts +0 -116
- package/src/vs/base/browser/ui/widget.ts +0 -57
- package/src/vs/base/browser/window.ts +0 -14
- package/src/vs/base/common/arrays.ts +0 -887
- package/src/vs/base/common/arraysFind.ts +0 -202
- package/src/vs/base/common/assert.ts +0 -71
- package/src/vs/base/common/async.ts +0 -1992
- package/src/vs/base/common/cancellation.ts +0 -148
- package/src/vs/base/common/charCode.ts +0 -450
- package/src/vs/base/common/collections.ts +0 -140
- package/src/vs/base/common/decorators.ts +0 -130
- package/src/vs/base/common/equals.ts +0 -146
- package/src/vs/base/common/errors.ts +0 -303
- package/src/vs/base/common/event.ts +0 -1778
- package/src/vs/base/common/functional.ts +0 -32
- package/src/vs/base/common/hash.ts +0 -316
- package/src/vs/base/common/iterator.ts +0 -159
- package/src/vs/base/common/keyCodes.ts +0 -526
- package/src/vs/base/common/keybindings.ts +0 -284
- package/src/vs/base/common/lazy.ts +0 -47
- package/src/vs/base/common/lifecycle.ts +0 -801
- package/src/vs/base/common/linkedList.ts +0 -142
- package/src/vs/base/common/map.ts +0 -202
- package/src/vs/base/common/numbers.ts +0 -98
- package/src/vs/base/common/observable.ts +0 -76
- package/src/vs/base/common/observableInternal/api.ts +0 -31
- package/src/vs/base/common/observableInternal/autorun.ts +0 -281
- package/src/vs/base/common/observableInternal/base.ts +0 -489
- package/src/vs/base/common/observableInternal/debugName.ts +0 -145
- package/src/vs/base/common/observableInternal/derived.ts +0 -428
- package/src/vs/base/common/observableInternal/lazyObservableValue.ts +0 -146
- package/src/vs/base/common/observableInternal/logging.ts +0 -328
- package/src/vs/base/common/observableInternal/promise.ts +0 -209
- package/src/vs/base/common/observableInternal/utils.ts +0 -610
- package/src/vs/base/common/platform.ts +0 -281
- package/src/vs/base/common/scrollable.ts +0 -522
- package/src/vs/base/common/sequence.ts +0 -34
- package/src/vs/base/common/stopwatch.ts +0 -43
- package/src/vs/base/common/strings.ts +0 -557
- package/src/vs/base/common/symbols.ts +0 -9
- package/src/vs/base/common/uint.ts +0 -59
- package/src/vs/patches/nls.ts +0 -90
- package/src/vs/typings/base-common.d.ts +0 -20
- package/src/vs/typings/require.d.ts +0 -42
- package/src/vs/typings/vscode-globals-nls.d.ts +0 -36
- package/src/vs/typings/vscode-globals-product.d.ts +0 -33
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*
|
|
5
|
+
* Win32 input mode implementation.
|
|
6
|
+
* @see https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md
|
|
7
|
+
*
|
|
8
|
+
* Format: CSI Vk ; Sc ; Uc ; Kd ; Cs ; Rc _
|
|
9
|
+
* Vk: Virtual key code (decimal)
|
|
10
|
+
* Sc: Scan code (decimal)
|
|
11
|
+
* Uc: Unicode character (decimal codepoint, 0 if none)
|
|
12
|
+
* Kd: Key down (1) or up (0)
|
|
13
|
+
* Cs: Control key state (modifier flags)
|
|
14
|
+
* Rc: Repeat count (usually 1)
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { IKeyboardEvent, IKeyboardResult, KeyboardResultType } from 'common/Types';
|
|
18
|
+
import { C0 } from 'common/data/EscapeSequences';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Win32 control key state flags (from Windows API).
|
|
22
|
+
*/
|
|
23
|
+
export const enum Win32ControlKeyState {
|
|
24
|
+
RIGHT_ALT_PRESSED = 0b000000001,
|
|
25
|
+
LEFT_ALT_PRESSED = 0b000000010,
|
|
26
|
+
RIGHT_CTRL_PRESSED = 0b000000100,
|
|
27
|
+
LEFT_CTRL_PRESSED = 0b000001000,
|
|
28
|
+
SHIFT_PRESSED = 0b000010000,
|
|
29
|
+
NUMLOCK_ON = 0b000100000,
|
|
30
|
+
SCROLLLOCK_ON = 0b001000000,
|
|
31
|
+
CAPSLOCK_ON = 0b010000000,
|
|
32
|
+
ENHANCED_KEY = 0b100000000,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Win32 input mode handler. Lookup tables are only initialized when this class
|
|
37
|
+
* is instantiated, reducing bundle size for environments that don't use this mode.
|
|
38
|
+
*/
|
|
39
|
+
export class Win32InputMode {
|
|
40
|
+
/**
|
|
41
|
+
* Mapping from browser KeyboardEvent.code to Win32 virtual key codes.
|
|
42
|
+
* Based on https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
|
43
|
+
*/
|
|
44
|
+
private readonly _codeToVk: { [code: string]: number } = {
|
|
45
|
+
// Letters
|
|
46
|
+
'KeyA': 0x41, 'KeyB': 0x42, 'KeyC': 0x43, 'KeyD': 0x44, 'KeyE': 0x45,
|
|
47
|
+
'KeyF': 0x46, 'KeyG': 0x47, 'KeyH': 0x48, 'KeyI': 0x49, 'KeyJ': 0x4A,
|
|
48
|
+
'KeyK': 0x4B, 'KeyL': 0x4C, 'KeyM': 0x4D, 'KeyN': 0x4E, 'KeyO': 0x4F,
|
|
49
|
+
'KeyP': 0x50, 'KeyQ': 0x51, 'KeyR': 0x52, 'KeyS': 0x53, 'KeyT': 0x54,
|
|
50
|
+
'KeyU': 0x55, 'KeyV': 0x56, 'KeyW': 0x57, 'KeyX': 0x58, 'KeyY': 0x59,
|
|
51
|
+
'KeyZ': 0x5A,
|
|
52
|
+
|
|
53
|
+
// Digits
|
|
54
|
+
'Digit0': 0x30, 'Digit1': 0x31, 'Digit2': 0x32, 'Digit3': 0x33, 'Digit4': 0x34,
|
|
55
|
+
'Digit5': 0x35, 'Digit6': 0x36, 'Digit7': 0x37, 'Digit8': 0x38, 'Digit9': 0x39,
|
|
56
|
+
|
|
57
|
+
// Function keys
|
|
58
|
+
'F1': 0x70, 'F2': 0x71, 'F3': 0x72, 'F4': 0x73, 'F5': 0x74, 'F6': 0x75,
|
|
59
|
+
'F7': 0x76, 'F8': 0x77, 'F9': 0x78, 'F10': 0x79, 'F11': 0x7A, 'F12': 0x7B,
|
|
60
|
+
'F13': 0x7C, 'F14': 0x7D, 'F15': 0x7E, 'F16': 0x7F, 'F17': 0x80, 'F18': 0x81,
|
|
61
|
+
'F19': 0x82, 'F20': 0x83, 'F21': 0x84, 'F22': 0x85, 'F23': 0x86, 'F24': 0x87,
|
|
62
|
+
|
|
63
|
+
// Numpad
|
|
64
|
+
'Numpad0': 0x60, 'Numpad1': 0x61, 'Numpad2': 0x62, 'Numpad3': 0x63, 'Numpad4': 0x64,
|
|
65
|
+
'Numpad5': 0x65, 'Numpad6': 0x66, 'Numpad7': 0x67, 'Numpad8': 0x68, 'Numpad9': 0x69,
|
|
66
|
+
'NumpadMultiply': 0x6A, 'NumpadAdd': 0x6B, 'NumpadSeparator': 0x6C,
|
|
67
|
+
'NumpadSubtract': 0x6D, 'NumpadDecimal': 0x6E, 'NumpadDivide': 0x6F,
|
|
68
|
+
'NumpadEnter': 0x0D, // Same as Enter but with ENHANCED_KEY flag
|
|
69
|
+
'NumLock': 0x90,
|
|
70
|
+
|
|
71
|
+
// Navigation
|
|
72
|
+
'ArrowUp': 0x26, 'ArrowDown': 0x28, 'ArrowLeft': 0x25, 'ArrowRight': 0x27,
|
|
73
|
+
'Home': 0x24, 'End': 0x23, 'PageUp': 0x21, 'PageDown': 0x22,
|
|
74
|
+
'Insert': 0x2D, 'Delete': 0x2E,
|
|
75
|
+
|
|
76
|
+
// Modifiers
|
|
77
|
+
'ShiftLeft': 0x10, 'ShiftRight': 0x10,
|
|
78
|
+
'ControlLeft': 0x11, 'ControlRight': 0x11,
|
|
79
|
+
'AltLeft': 0x12, 'AltRight': 0x12,
|
|
80
|
+
'MetaLeft': 0x5B, 'MetaRight': 0x5C,
|
|
81
|
+
'CapsLock': 0x14, 'ScrollLock': 0x91,
|
|
82
|
+
|
|
83
|
+
// Special keys
|
|
84
|
+
'Escape': 0x1B, 'Enter': 0x0D, 'Tab': 0x09, 'Space': 0x20,
|
|
85
|
+
'Backspace': 0x08, 'Pause': 0x13, 'ContextMenu': 0x5D, 'PrintScreen': 0x2C,
|
|
86
|
+
|
|
87
|
+
// OEM keys (US keyboard layout)
|
|
88
|
+
'Semicolon': 0xBA, // ;:
|
|
89
|
+
'Equal': 0xBB, // =+
|
|
90
|
+
'Comma': 0xBC, // ,<
|
|
91
|
+
'Minus': 0xBD, // -_
|
|
92
|
+
'Period': 0xBE, // .>
|
|
93
|
+
'Slash': 0xBF, // /?
|
|
94
|
+
'Backquote': 0xC0, // `~
|
|
95
|
+
'BracketLeft': 0xDB, // [{
|
|
96
|
+
'Backslash': 0xDC, // \|
|
|
97
|
+
'BracketRight': 0xDD, // ]}
|
|
98
|
+
'Quote': 0xDE, // '"
|
|
99
|
+
'IntlBackslash': 0xE2 // Non-US backslash
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Mapping from browser KeyboardEvent.code to approximate Win32 scan codes.
|
|
104
|
+
* Note: Scan codes can vary by keyboard layout. These are approximations
|
|
105
|
+
* based on standard US keyboard layout.
|
|
106
|
+
*/
|
|
107
|
+
private readonly _codeToScancode: { [code: string]: number } = {
|
|
108
|
+
// Letters (row by row)
|
|
109
|
+
'KeyQ': 0x10, 'KeyW': 0x11, 'KeyE': 0x12, 'KeyR': 0x13, 'KeyT': 0x14,
|
|
110
|
+
'KeyY': 0x15, 'KeyU': 0x16, 'KeyI': 0x17, 'KeyO': 0x18, 'KeyP': 0x19,
|
|
111
|
+
'KeyA': 0x1E, 'KeyS': 0x1F, 'KeyD': 0x20, 'KeyF': 0x21, 'KeyG': 0x22,
|
|
112
|
+
'KeyH': 0x23, 'KeyJ': 0x24, 'KeyK': 0x25, 'KeyL': 0x26,
|
|
113
|
+
'KeyZ': 0x2C, 'KeyX': 0x2D, 'KeyC': 0x2E, 'KeyV': 0x2F, 'KeyB': 0x30,
|
|
114
|
+
'KeyN': 0x31, 'KeyM': 0x32,
|
|
115
|
+
|
|
116
|
+
// Digits
|
|
117
|
+
'Digit1': 0x02, 'Digit2': 0x03, 'Digit3': 0x04, 'Digit4': 0x05, 'Digit5': 0x06,
|
|
118
|
+
'Digit6': 0x07, 'Digit7': 0x08, 'Digit8': 0x09, 'Digit9': 0x0A, 'Digit0': 0x0B,
|
|
119
|
+
|
|
120
|
+
// Function keys
|
|
121
|
+
'F1': 0x3B, 'F2': 0x3C, 'F3': 0x3D, 'F4': 0x3E, 'F5': 0x3F, 'F6': 0x40,
|
|
122
|
+
'F7': 0x41, 'F8': 0x42, 'F9': 0x43, 'F10': 0x44, 'F11': 0x57, 'F12': 0x58,
|
|
123
|
+
|
|
124
|
+
// Numpad
|
|
125
|
+
'Numpad0': 0x52, 'Numpad1': 0x4F, 'Numpad2': 0x50, 'Numpad3': 0x51, 'Numpad4': 0x4B,
|
|
126
|
+
'Numpad5': 0x4C, 'Numpad6': 0x4D, 'Numpad7': 0x47, 'Numpad8': 0x48, 'Numpad9': 0x49,
|
|
127
|
+
'NumpadMultiply': 0x37, 'NumpadAdd': 0x4E, 'NumpadSubtract': 0x4A,
|
|
128
|
+
'NumpadDecimal': 0x53, 'NumpadDivide': 0x35, 'NumpadEnter': 0x1C,
|
|
129
|
+
'NumLock': 0x45,
|
|
130
|
+
|
|
131
|
+
// Navigation (extended keys)
|
|
132
|
+
'ArrowUp': 0x48, 'ArrowDown': 0x50, 'ArrowLeft': 0x4B, 'ArrowRight': 0x4D,
|
|
133
|
+
'Home': 0x47, 'End': 0x4F, 'PageUp': 0x49, 'PageDown': 0x51,
|
|
134
|
+
'Insert': 0x52, 'Delete': 0x53,
|
|
135
|
+
|
|
136
|
+
// Modifiers
|
|
137
|
+
'ShiftLeft': 0x2A, 'ShiftRight': 0x36,
|
|
138
|
+
'ControlLeft': 0x1D, 'ControlRight': 0x1D,
|
|
139
|
+
'AltLeft': 0x38, 'AltRight': 0x38,
|
|
140
|
+
'CapsLock': 0x3A, 'ScrollLock': 0x46,
|
|
141
|
+
|
|
142
|
+
// Special keys
|
|
143
|
+
'Escape': 0x01, 'Enter': 0x1C, 'Tab': 0x0F, 'Space': 0x39,
|
|
144
|
+
'Backspace': 0x0E, 'Pause': 0x45,
|
|
145
|
+
|
|
146
|
+
// OEM keys
|
|
147
|
+
'Semicolon': 0x27, 'Equal': 0x0D, 'Comma': 0x33, 'Minus': 0x0C,
|
|
148
|
+
'Period': 0x34, 'Slash': 0x35, 'Backquote': 0x29,
|
|
149
|
+
'BracketLeft': 0x1A, 'Backslash': 0x2B, 'BracketRight': 0x1B, 'Quote': 0x28
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Codes that represent enhanced keys (extended keyboard keys).
|
|
154
|
+
*/
|
|
155
|
+
private readonly _enhancedKeyCodes = new Set([
|
|
156
|
+
'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight',
|
|
157
|
+
'Home', 'End', 'PageUp', 'PageDown', 'Insert', 'Delete',
|
|
158
|
+
'NumpadEnter', 'NumpadDivide',
|
|
159
|
+
'ControlRight', 'AltRight',
|
|
160
|
+
'PrintScreen', 'Pause', 'ContextMenu',
|
|
161
|
+
'MetaLeft', 'MetaRight'
|
|
162
|
+
]);
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Mapping of special keys (ev.key values) to their Unicode control character codes.
|
|
166
|
+
* These keys have multi-character ev.key strings but produce control characters.
|
|
167
|
+
* @see https://docs.microsoft.com/en-us/windows/console/key-event-record-str
|
|
168
|
+
*/
|
|
169
|
+
private readonly _keyToControlChar: { [key: string]: number } = {
|
|
170
|
+
'Enter': 0x0D, // Carriage return
|
|
171
|
+
'Backspace': 0x08, // Backspace
|
|
172
|
+
'Tab': 0x09, // Horizontal tab
|
|
173
|
+
'Escape': 0x1B // Escape
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Get the Win32 virtual key code for a keyboard event.
|
|
178
|
+
*/
|
|
179
|
+
private _getVirtualKeyCode(ev: IKeyboardEvent): number {
|
|
180
|
+
const vk = this._codeToVk[ev.code];
|
|
181
|
+
if (vk !== undefined) {
|
|
182
|
+
return vk;
|
|
183
|
+
}
|
|
184
|
+
// Fall back to keyCode for unmapped keys
|
|
185
|
+
return ev.keyCode || 0;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Get the Win32 scan code for a keyboard event.
|
|
190
|
+
* Returns 0 if unknown (scan codes vary by hardware).
|
|
191
|
+
*/
|
|
192
|
+
private _getScanCode(ev: IKeyboardEvent): number {
|
|
193
|
+
return this._codeToScancode[ev.code] || 0;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Get the unicode character for a keyboard event.
|
|
198
|
+
* Returns 0 for non-character keys.
|
|
199
|
+
*/
|
|
200
|
+
private _getUnicodeChar(ev: IKeyboardEvent): number {
|
|
201
|
+
// Handle special keys that produce control characters
|
|
202
|
+
// Ctrl modifies some of these: Ctrl+Enter=LF, Ctrl+Backspace=DEL
|
|
203
|
+
if (ev.ctrlKey && !ev.altKey && !ev.metaKey) {
|
|
204
|
+
if (ev.key === 'Enter') {
|
|
205
|
+
return 0x0A; // Line feed (Ctrl+Enter)
|
|
206
|
+
}
|
|
207
|
+
if (ev.key === 'Backspace') {
|
|
208
|
+
return 0x7F; // DEL (Ctrl+Backspace)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Check for special keys that always produce control characters
|
|
213
|
+
const controlChar = this._keyToControlChar[ev.key];
|
|
214
|
+
if (controlChar !== undefined) {
|
|
215
|
+
return controlChar;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Only single-character keys produce unicode output
|
|
219
|
+
if (ev.key.length === 1) {
|
|
220
|
+
const codePoint = ev.key.codePointAt(0) || 0;
|
|
221
|
+
|
|
222
|
+
// Handle Ctrl+letter combinations - these produce control characters (0x01-0x1A)
|
|
223
|
+
if (ev.ctrlKey && !ev.altKey && !ev.metaKey) {
|
|
224
|
+
// Convert A-Z or a-z to control character (Ctrl+A = 0x01, Ctrl+C = 0x03, etc.)
|
|
225
|
+
if (codePoint >= 0x41 && codePoint <= 0x5A) { // A-Z
|
|
226
|
+
return codePoint - 0x40;
|
|
227
|
+
}
|
|
228
|
+
if (codePoint >= 0x61 && codePoint <= 0x7A) { // a-z
|
|
229
|
+
return codePoint - 0x60;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return codePoint;
|
|
234
|
+
}
|
|
235
|
+
return 0;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Get the Win32 control key state flags.
|
|
240
|
+
*/
|
|
241
|
+
private _getControlKeyState(ev: IKeyboardEvent): number {
|
|
242
|
+
let state = 0;
|
|
243
|
+
|
|
244
|
+
if (ev.shiftKey) {
|
|
245
|
+
state |= Win32ControlKeyState.SHIFT_PRESSED;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Note: We can't distinguish left/right for ctrl/alt in standard browser events,
|
|
249
|
+
// so we use the generic pressed flags. The right-side flags are used when
|
|
250
|
+
// we can detect them (e.g., via code property).
|
|
251
|
+
if (ev.ctrlKey) {
|
|
252
|
+
if (ev.code === 'ControlRight') {
|
|
253
|
+
state |= Win32ControlKeyState.RIGHT_CTRL_PRESSED;
|
|
254
|
+
} else {
|
|
255
|
+
state |= Win32ControlKeyState.LEFT_CTRL_PRESSED;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (ev.altKey) {
|
|
260
|
+
if (ev.code === 'AltRight') {
|
|
261
|
+
state |= Win32ControlKeyState.RIGHT_ALT_PRESSED;
|
|
262
|
+
} else {
|
|
263
|
+
state |= Win32ControlKeyState.LEFT_ALT_PRESSED;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Check for enhanced key
|
|
268
|
+
if (this._enhancedKeyCodes.has(ev.code)) {
|
|
269
|
+
state |= Win32ControlKeyState.ENHANCED_KEY;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return state;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Evaluate a keyboard event using Win32 input mode.
|
|
277
|
+
*
|
|
278
|
+
* @param ev The keyboard event.
|
|
279
|
+
* @param isKeyDown Whether this is a keydown (true) or keyup (false) event.
|
|
280
|
+
* @returns The keyboard result with the encoded key sequence.
|
|
281
|
+
*/
|
|
282
|
+
public evaluateKeyboardEvent(ev: IKeyboardEvent, isKeyDown: boolean): IKeyboardResult {
|
|
283
|
+
const vk = this._getVirtualKeyCode(ev);
|
|
284
|
+
const sc = this._getScanCode(ev);
|
|
285
|
+
const uc = this._getUnicodeChar(ev);
|
|
286
|
+
const kd = isKeyDown ? 1 : 0;
|
|
287
|
+
const cs = this._getControlKeyState(ev);
|
|
288
|
+
const rc = 1; // Repeat count, always 1 for now
|
|
289
|
+
|
|
290
|
+
// Format: CSI Vk ; Sc ; Uc ; Kd ; Cs ; Rc _
|
|
291
|
+
return {
|
|
292
|
+
type: KeyboardResultType.SEND_KEY,
|
|
293
|
+
cancel: true,
|
|
294
|
+
key: `${C0.ESC}[${vk};${sc};${uc};${kd};${cs};${rc}_`
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
@@ -4,35 +4,35 @@
|
|
|
4
4
|
* @license MIT
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { Disposable } from '
|
|
8
|
-
import { Emitter } from '
|
|
7
|
+
import { Disposable } from 'common/Lifecycle';
|
|
8
|
+
import { Emitter } from 'common/Event';
|
|
9
9
|
|
|
10
10
|
declare const setTimeout: (handler: () => void, timeout?: number) => void;
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
12
|
+
const enum Constants {
|
|
13
|
+
/**
|
|
14
|
+
* Safety watermark to avoid memory exhaustion and browser engine crash on fast data input.
|
|
15
|
+
* Enable flow control to avoid this limit and make sure that your backend correctly
|
|
16
|
+
* propagates this to the underlying pty. (see docs for further instructions)
|
|
17
|
+
* Since this limit is meant as a safety parachute to prevent browser crashs,
|
|
18
|
+
* it is set to a very high number. Typically xterm.js gets unresponsive with
|
|
19
|
+
* a 100 times lower number (>500 kB).
|
|
20
|
+
*/
|
|
21
|
+
DISCARD_WATERMARK = 50000000, // ~50 MB
|
|
22
|
+
/**
|
|
23
|
+
* The max number of ms to spend on writes before allowing the renderer to
|
|
24
|
+
* catch up with a 0ms setTimeout. A value of < 33 to keep us close to
|
|
25
|
+
* 30fps, and a value of < 16 to try to run at 60fps. Of course, the real FPS
|
|
26
|
+
* depends on the time it takes for the renderer to draw the frame.
|
|
27
|
+
*/
|
|
28
|
+
WRITE_TIMEOUT_MS = 12,
|
|
29
|
+
/**
|
|
30
|
+
* Threshold of max held chunks in the write buffer, that were already processed.
|
|
31
|
+
* This is a tradeoff between extensive write buffer shifts (bad runtime) and high
|
|
32
|
+
* memory consumption by data thats not used anymore.
|
|
33
|
+
*/
|
|
34
|
+
WRITE_BUFFER_LENGTH_THRESHOLD = 50
|
|
35
|
+
}
|
|
36
36
|
|
|
37
37
|
export class WriteBuffer extends Disposable {
|
|
38
38
|
private _writeBuffer: (string | Uint8Array)[] = [];
|
|
@@ -54,6 +54,43 @@ export class WriteBuffer extends Disposable {
|
|
|
54
54
|
this._didUserInput = true;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Flushes all pending writes synchronously. This is useful when you need to
|
|
59
|
+
* ensure all queued data is processed before performing an operation that
|
|
60
|
+
* depends upon everything being parsed like resize.
|
|
61
|
+
*
|
|
62
|
+
* Note: This is unreliable with async parser handlers as it does not wait for
|
|
63
|
+
* promises to resolve.
|
|
64
|
+
*/
|
|
65
|
+
public flushSync(): void {
|
|
66
|
+
// exit early if another sync write loop is active
|
|
67
|
+
if (this._isSyncWriting) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
this._isSyncWriting = true;
|
|
71
|
+
|
|
72
|
+
// Process all pending chunks synchronously
|
|
73
|
+
let chunk: string | Uint8Array | undefined;
|
|
74
|
+
let didProcess = false;
|
|
75
|
+
while (chunk = this._writeBuffer.shift()) {
|
|
76
|
+
didProcess = true;
|
|
77
|
+
this._action(chunk);
|
|
78
|
+
const cb = this._callbacks.shift();
|
|
79
|
+
if (cb) cb();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Reset buffer state
|
|
83
|
+
this._pendingData = 0;
|
|
84
|
+
this._bufferOffset = 0x7FFFFFFF;
|
|
85
|
+
this._writeBuffer.length = 0;
|
|
86
|
+
this._callbacks.length = 0;
|
|
87
|
+
|
|
88
|
+
this._isSyncWriting = false;
|
|
89
|
+
if (didProcess) {
|
|
90
|
+
this._onWriteParsed.fire();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
57
94
|
/**
|
|
58
95
|
* @deprecated Unreliable, to be removed soon.
|
|
59
96
|
*/
|
|
@@ -101,7 +138,7 @@ export class WriteBuffer extends Disposable {
|
|
|
101
138
|
}
|
|
102
139
|
|
|
103
140
|
public write(data: string | Uint8Array, callback?: () => void): void {
|
|
104
|
-
if (this._pendingData > DISCARD_WATERMARK) {
|
|
141
|
+
if (this._pendingData > Constants.DISCARD_WATERMARK) {
|
|
105
142
|
throw new Error('write data discarded, use flow control to avoid losing data');
|
|
106
143
|
}
|
|
107
144
|
|
|
@@ -137,7 +174,7 @@ export class WriteBuffer extends Disposable {
|
|
|
137
174
|
* effectively lowering the redrawing needs, schematically:
|
|
138
175
|
*
|
|
139
176
|
* macroTask _innerWrite:
|
|
140
|
-
* if (performance.now() - (lastTime | 0) < WRITE_TIMEOUT_MS):
|
|
177
|
+
* if (performance.now() - (lastTime | 0) < Constants.WRITE_TIMEOUT_MS):
|
|
141
178
|
* schedule microTask _innerWrite(lastTime)
|
|
142
179
|
* else:
|
|
143
180
|
* schedule macroTask _innerWrite(0)
|
|
@@ -186,7 +223,7 @@ export class WriteBuffer extends Disposable {
|
|
|
186
223
|
* responsibility to slice hard work), but we can at least schedule a screen update as we
|
|
187
224
|
* gain control.
|
|
188
225
|
*/
|
|
189
|
-
const continuation: (r: boolean) => void = (r: boolean) => performance.now() - startTime >= WRITE_TIMEOUT_MS
|
|
226
|
+
const continuation: (r: boolean) => void = (r: boolean) => performance.now() - startTime >= Constants.WRITE_TIMEOUT_MS
|
|
190
227
|
? setTimeout(() => this._innerWrite(0, r))
|
|
191
228
|
: this._innerWrite(startTime, r);
|
|
192
229
|
|
|
@@ -203,7 +240,7 @@ export class WriteBuffer extends Disposable {
|
|
|
203
240
|
* current microtask queue (executed before setTimeout).
|
|
204
241
|
*/
|
|
205
242
|
// const continuation: (r: boolean) => void = performance.now() - startTime >=
|
|
206
|
-
// WRITE_TIMEOUT_MS
|
|
243
|
+
// Constants.WRITE_TIMEOUT_MS
|
|
207
244
|
// ? r => setTimeout(() => this._innerWrite(0, r))
|
|
208
245
|
// : r => this._innerWrite(startTime, r);
|
|
209
246
|
|
|
@@ -223,14 +260,14 @@ export class WriteBuffer extends Disposable {
|
|
|
223
260
|
this._bufferOffset++;
|
|
224
261
|
this._pendingData -= data.length;
|
|
225
262
|
|
|
226
|
-
if (performance.now() - startTime >= WRITE_TIMEOUT_MS) {
|
|
263
|
+
if (performance.now() - startTime >= Constants.WRITE_TIMEOUT_MS) {
|
|
227
264
|
break;
|
|
228
265
|
}
|
|
229
266
|
}
|
|
230
267
|
if (this._writeBuffer.length > this._bufferOffset) {
|
|
231
268
|
// Allow renderer to catch up before processing the next batch
|
|
232
269
|
// trim already processed chunks if we are above threshold
|
|
233
|
-
if (this._bufferOffset > WRITE_BUFFER_LENGTH_THRESHOLD) {
|
|
270
|
+
if (this._bufferOffset > Constants.WRITE_BUFFER_LENGTH_THRESHOLD) {
|
|
234
271
|
this._writeBuffer = this._writeBuffer.slice(this._bufferOffset);
|
|
235
272
|
this._callbacks = this._callbacks.slice(this._bufferOffset);
|
|
236
273
|
this._bufferOffset = 0;
|
|
@@ -24,7 +24,7 @@ export function parseColor(data: string): [number, number, number] | undefined {
|
|
|
24
24
|
if (!data) return;
|
|
25
25
|
// also handle uppercases
|
|
26
26
|
let low = data.toLowerCase();
|
|
27
|
-
if (low.
|
|
27
|
+
if (low.startsWith('rgb:')) {
|
|
28
28
|
// 'rgb:' specifier
|
|
29
29
|
low = low.slice(4);
|
|
30
30
|
const m = RGB_REX.exec(low);
|
|
@@ -36,7 +36,7 @@ export function parseColor(data: string): [number, number, number] | undefined {
|
|
|
36
36
|
Math.round(parseInt(m[3] || m[6] || m[9] || m[12], 16) / base * 255)
|
|
37
37
|
];
|
|
38
38
|
}
|
|
39
|
-
} else if (low.
|
|
39
|
+
} else if (low.startsWith('#')) {
|
|
40
40
|
// '#' specifier
|
|
41
41
|
low = low.slice(1);
|
|
42
42
|
if (HASH_REX.exec(low) && [3, 6, 9, 12].includes(low.length)) {
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { IApcHandler, IHandlerCollection, ApcFallbackHandlerType, IApcParser, ISubParserStackState } from 'common/parser/Types';
|
|
7
|
+
import { ParserConstants } from 'common/parser/Constants';
|
|
8
|
+
import { utf32ToString } from 'common/input/TextDecoder';
|
|
9
|
+
import { IDisposable } from 'common/Types';
|
|
10
|
+
|
|
11
|
+
const EMPTY_HANDLERS: IApcHandler[] = [];
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* APC Parser for handling Application Program Command sequences.
|
|
15
|
+
* APC sequences use the format: ESC _ <identifier><data> ESC \
|
|
16
|
+
*
|
|
17
|
+
* Unlike OSC which uses numeric identifiers (e.g., OSC 1337),
|
|
18
|
+
* APC uses the first character as the identifier (e.g., 'G' for Kitty graphics).
|
|
19
|
+
* The identifier is the character code of the first byte after ESC _.
|
|
20
|
+
*/
|
|
21
|
+
export class ApcParser implements IApcParser {
|
|
22
|
+
private _handlers: IHandlerCollection<IApcHandler> = Object.create(null);
|
|
23
|
+
private _active = EMPTY_HANDLERS;
|
|
24
|
+
private _ident: number = 0;
|
|
25
|
+
private _handlerFb: ApcFallbackHandlerType = () => { };
|
|
26
|
+
private _stack: ISubParserStackState = {
|
|
27
|
+
paused: false,
|
|
28
|
+
loopPosition: 0,
|
|
29
|
+
fallThrough: false
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Register an APC handler for a specific identifier.
|
|
34
|
+
* @param ident The character code of the first byte (e.g., 0x47 for 'G')
|
|
35
|
+
* @param handler The handler to register
|
|
36
|
+
*/
|
|
37
|
+
public registerHandler(ident: number, handler: IApcHandler): IDisposable {
|
|
38
|
+
this._handlers[ident] ??= [];
|
|
39
|
+
const handlerList = this._handlers[ident];
|
|
40
|
+
handlerList.push(handler);
|
|
41
|
+
return {
|
|
42
|
+
dispose: () => {
|
|
43
|
+
const handlerIndex = handlerList.indexOf(handler);
|
|
44
|
+
if (handlerIndex !== -1) {
|
|
45
|
+
handlerList.splice(handlerIndex, 1);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public clearHandler(ident: number): void {
|
|
52
|
+
if (this._handlers[ident]) delete this._handlers[ident];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public setHandlerFallback(handler: ApcFallbackHandlerType): void {
|
|
56
|
+
this._handlerFb = handler;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public dispose(): void {
|
|
60
|
+
this._handlers = Object.create(null);
|
|
61
|
+
this._handlerFb = () => { };
|
|
62
|
+
this._active = EMPTY_HANDLERS;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public reset(): void {
|
|
66
|
+
// force cleanup handlers
|
|
67
|
+
if (this._active.length) {
|
|
68
|
+
for (let j = this._stack.paused ? this._stack.loopPosition - 1 : this._active.length - 1; j >= 0; --j) {
|
|
69
|
+
this._active[j].end(false);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
this._stack.paused = false;
|
|
73
|
+
this._active = EMPTY_HANDLERS;
|
|
74
|
+
this._ident = 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public start(ident: number): void {
|
|
78
|
+
// always reset leftover handlers
|
|
79
|
+
this.reset();
|
|
80
|
+
this._ident = ident;
|
|
81
|
+
this._active = this._handlers[ident] || EMPTY_HANDLERS;
|
|
82
|
+
if (!this._active.length) {
|
|
83
|
+
this._handlerFb(this._ident, 'START');
|
|
84
|
+
} else {
|
|
85
|
+
for (let j = this._active.length - 1; j >= 0; j--) {
|
|
86
|
+
this._active[j].start();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public put(data: Uint32Array, start: number, end: number): void {
|
|
92
|
+
if (!this._active.length) {
|
|
93
|
+
this._handlerFb(this._ident, 'PUT', utf32ToString(data, start, end));
|
|
94
|
+
} else {
|
|
95
|
+
for (let j = this._active.length - 1; j >= 0; j--) {
|
|
96
|
+
this._active[j].put(data, start, end);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Indicates end of an APC command.
|
|
103
|
+
* Whether the APC got aborted or finished normally
|
|
104
|
+
* is indicated by `success`.
|
|
105
|
+
*/
|
|
106
|
+
public end(success: boolean, promiseResult: boolean = true): void | Promise<boolean> {
|
|
107
|
+
if (!this._active.length) {
|
|
108
|
+
this._handlerFb(this._ident, 'END', success);
|
|
109
|
+
} else {
|
|
110
|
+
let handlerResult: boolean | Promise<boolean> = false;
|
|
111
|
+
let j = this._active.length - 1;
|
|
112
|
+
let fallThrough = false;
|
|
113
|
+
if (this._stack.paused) {
|
|
114
|
+
j = this._stack.loopPosition - 1;
|
|
115
|
+
handlerResult = promiseResult;
|
|
116
|
+
fallThrough = this._stack.fallThrough;
|
|
117
|
+
this._stack.paused = false;
|
|
118
|
+
}
|
|
119
|
+
if (!fallThrough && handlerResult === false) {
|
|
120
|
+
for (; j >= 0; j--) {
|
|
121
|
+
handlerResult = this._active[j].end(success);
|
|
122
|
+
if (handlerResult === true) {
|
|
123
|
+
break;
|
|
124
|
+
} else if (handlerResult instanceof Promise) {
|
|
125
|
+
this._stack.paused = true;
|
|
126
|
+
this._stack.loopPosition = j;
|
|
127
|
+
this._stack.fallThrough = false;
|
|
128
|
+
return handlerResult;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
j--;
|
|
132
|
+
}
|
|
133
|
+
// cleanup left over handlers (fallThrough for async)
|
|
134
|
+
for (; j >= 0; j--) {
|
|
135
|
+
handlerResult = this._active[j].end(false);
|
|
136
|
+
if (handlerResult instanceof Promise) {
|
|
137
|
+
this._stack.paused = true;
|
|
138
|
+
this._stack.loopPosition = j;
|
|
139
|
+
this._stack.fallThrough = true;
|
|
140
|
+
return handlerResult;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
this._active = EMPTY_HANDLERS;
|
|
145
|
+
this._ident = 0;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Convenient class to allow attaching string based handler functions
|
|
151
|
+
* as APC handlers.
|
|
152
|
+
*/
|
|
153
|
+
export class ApcHandler implements IApcHandler {
|
|
154
|
+
private static _payloadLimit = ParserConstants.PAYLOAD_LIMIT;
|
|
155
|
+
|
|
156
|
+
private _data = '';
|
|
157
|
+
private _hitLimit: boolean = false;
|
|
158
|
+
|
|
159
|
+
constructor(private _handler: (data: string) => boolean | Promise<boolean>) { }
|
|
160
|
+
|
|
161
|
+
public start(): void {
|
|
162
|
+
this._data = '';
|
|
163
|
+
this._hitLimit = false;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public put(data: Uint32Array, start: number, end: number): void {
|
|
167
|
+
if (this._hitLimit) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
this._data += utf32ToString(data, start, end);
|
|
171
|
+
if (this._data.length > ApcHandler._payloadLimit) {
|
|
172
|
+
this._data = '';
|
|
173
|
+
this._hitLimit = true;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
public end(success: boolean): boolean | Promise<boolean> {
|
|
178
|
+
let ret: boolean | Promise<boolean> = false;
|
|
179
|
+
if (this._hitLimit) {
|
|
180
|
+
ret = false;
|
|
181
|
+
} else if (success) {
|
|
182
|
+
ret = this._handler(this._data);
|
|
183
|
+
if (ret instanceof Promise) {
|
|
184
|
+
// need to hold data until `ret` got resolved
|
|
185
|
+
// dont care for errors, data will be freed anyway on next start
|
|
186
|
+
return ret.then(res => {
|
|
187
|
+
this._data = '';
|
|
188
|
+
this._hitLimit = false;
|
|
189
|
+
return res;
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
this._data = '';
|
|
194
|
+
this._hitLimit = false;
|
|
195
|
+
return ret;
|
|
196
|
+
}
|
|
197
|
+
}
|