mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Rate limit row refresh, tweak live region
This commit is contained in:
@@ -15,6 +15,10 @@ export class AccessibilityManager implements IDisposable {
|
||||
private _liveRegion: HTMLElement;
|
||||
private _liveRegionLineCount: number = 0;
|
||||
|
||||
private _refreshRowStart: number;
|
||||
private _refreshRowEnd: number;
|
||||
private _refreshAnimationFrame: number = null;
|
||||
|
||||
private _disposables: IDisposable[] = [];
|
||||
|
||||
/**
|
||||
@@ -42,7 +46,7 @@ export class AccessibilityManager implements IDisposable {
|
||||
|
||||
this._liveRegion = document.createElement('div');
|
||||
this._liveRegion.classList.add('live-region');
|
||||
this._liveRegion.setAttribute('aria-live', 'polite');
|
||||
this._liveRegion.setAttribute('aria-live', 'assertive');
|
||||
this._accessibilityTreeRoot.appendChild(this._liveRegion);
|
||||
|
||||
this._terminal.element.appendChild(this._accessibilityTreeRoot);
|
||||
@@ -52,8 +56,12 @@ export class AccessibilityManager implements IDisposable {
|
||||
// Line feed is an issue as the prompt won't be read out after a command is run
|
||||
this._addTerminalEventListener('a11y.char', (char) => this._onChar(char));
|
||||
this._addTerminalEventListener('linefeed', () => this._onChar('\n'));
|
||||
// Ensure \t is covered, if not a line of output from `ls` is read as one word
|
||||
this._addTerminalEventListener('a11y.tab', () => this._onChar(' '));
|
||||
// Ensure \t is covered, if not 2 words separated by only a tab will be read as 1 word
|
||||
this._addTerminalEventListener('a11y.tab', spaceCount => {
|
||||
for (let i = 0; i < spaceCount; i++) {
|
||||
this._onChar(' ');
|
||||
}
|
||||
});
|
||||
this._addTerminalEventListener('charsizechanged', () => this._refreshRowsDimensions());
|
||||
this._addTerminalEventListener('key', keyChar => this._onKey(keyChar));
|
||||
this._addTerminalEventListener('blur', () => this._clearLiveRegion());
|
||||
@@ -105,9 +113,18 @@ export class AccessibilityManager implements IDisposable {
|
||||
// Have the screen reader ignore the char if it was just input
|
||||
const shiftedChar = this._charsToConsume.shift();
|
||||
if (shiftedChar !== char) {
|
||||
this._liveRegion.textContent += char;
|
||||
if (char === ' ') {
|
||||
// Always use nbsp for spaces in order to preserve the space between characters in
|
||||
// voiceover's caption window
|
||||
this._liveRegion.innerHTML += ' ';
|
||||
} else {
|
||||
this._liveRegion.textContent += char;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (char === ' ') {
|
||||
this._liveRegion.innerHTML += ' ';
|
||||
} else
|
||||
this._liveRegion.textContent += char;
|
||||
}
|
||||
|
||||
@@ -122,7 +139,9 @@ export class AccessibilityManager implements IDisposable {
|
||||
// Only detach/attach on mac as otherwise messages can go unaccounced
|
||||
if (isMac) {
|
||||
if (this._liveRegion.textContent.length > 0 && !this._liveRegion.parentNode) {
|
||||
this._accessibilityTreeRoot.appendChild(this._liveRegion);
|
||||
setTimeout(() => {
|
||||
this._accessibilityTreeRoot.appendChild(this._liveRegion);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,13 +169,28 @@ export class AccessibilityManager implements IDisposable {
|
||||
|
||||
// TODO: Hook up to refresh when the renderer refreshes the range? Slower to prevent layout thrashing?
|
||||
private _refreshRows(start?: number, end?: number): void {
|
||||
const buffer: IBuffer = (<any>this._terminal.buffer);
|
||||
start = start || 0;
|
||||
end = end || this._terminal.rows - 1;
|
||||
for (let i = start; i <= end; i++) {
|
||||
this._refreshRowStart = this._refreshRowStart ? Math.min(this._refreshRowStart, start) : start;
|
||||
this._refreshRowEnd = this._refreshRowEnd ? Math.max(this._refreshRowEnd, end) : end;
|
||||
|
||||
if (this._refreshAnimationFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._refreshAnimationFrame = window.requestAnimationFrame(() => this._innerRefreshRows());
|
||||
}
|
||||
|
||||
private _innerRefreshRows(): void {
|
||||
console.log('innerRefreshRows');
|
||||
const buffer: IBuffer = (<any>this._terminal.buffer);
|
||||
for (let i = this._refreshRowStart; i <= this._refreshRowEnd; i++) {
|
||||
const lineData = buffer.translateBufferLineToString(buffer.ybase + i, true);
|
||||
this._rowElements[i].textContent = lineData;
|
||||
}
|
||||
this._refreshRowStart = null;
|
||||
this._refreshRowEnd = null;
|
||||
this._refreshAnimationFrame = null;
|
||||
}
|
||||
|
||||
private _refreshRowsDimensions(): void {
|
||||
|
||||
+2
-1
@@ -166,9 +166,10 @@ export class InputHandler implements IInputHandler {
|
||||
* Horizontal Tab (HT) (Ctrl-I).
|
||||
*/
|
||||
public tab(): void {
|
||||
const originalX = this._terminal.buffer.x;
|
||||
this._terminal.buffer.x = this._terminal.buffer.nextStop();
|
||||
if (this._terminal.options.screenReaderMode) {
|
||||
this._terminal.emit('a11y.tab');
|
||||
this._terminal.emit('a11y.tab', this._terminal.buffer.x - originalX);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import { EventEmitter } from '../EventEmitter';
|
||||
export class Renderer extends EventEmitter implements IRenderer {
|
||||
/** A queue of the rows to be refreshed */
|
||||
private _refreshRowsQueue: {start: number, end: number}[] = [];
|
||||
private _refreshAnimationFrame = null;
|
||||
private _refreshAnimationFrame: number = null;
|
||||
|
||||
private _renderLayers: IRenderLayer[];
|
||||
private _devicePixelRatio: number;
|
||||
|
||||
Reference in New Issue
Block a user