diff --git a/demo/index.html b/demo/index.html index 93399f9cd..e0c355d09 100644 --- a/demo/index.html +++ b/demo/index.html @@ -63,6 +63,14 @@ +
+

Accessibility

+

+ +

+

+ +

Attention: The demo is a barebones implementation and is designed for xterm.js evaluation purposes only. Exposing the demo to the public as is would introduce security risks for the host.

diff --git a/demo/main.js b/demo/main.js index 95b15a0db..df11a27fd 100644 --- a/demo/main.js +++ b/demo/main.js @@ -29,8 +29,10 @@ var terminalContainer = document.getElementById('terminal-container'), cursorStyle: document.querySelector('#option-cursor-style'), scrollback: document.querySelector('#option-scrollback'), tabstopwidth: document.querySelector('#option-tabstopwidth'), - bellStyle: document.querySelector('#option-bell-style') + bellStyle: document.querySelector('#option-bell-style'), + screenReaderMode: document.querySelector('#option-screen-reader-mode') }, + navigationModeElement = document.querySelector('#screen-reader-navigation-mode'), colsElement = document.getElementById('cols'), rowsElement = document.getElementById('rows'); @@ -78,6 +80,16 @@ optionElements.scrollback.addEventListener('change', function () { optionElements.tabstopwidth.addEventListener('change', function () { term.setOption('tabStopWidth', parseInt(optionElements.tabstopwidth.value, 10)); }); +optionElements.screenReaderMode.addEventListener('change', function () { + term.setOption('screenReaderMode', optionElements.screenReaderMode.value); +}); +navigationModeElement.addEventListener('click', function () { + if (term.getOption('screenReaderMode')) { + term.enterNavigationMode(); + } else { + console.warn('screenReaderMode must be true to enter navigation mode'); + } +}); createTerminal(); @@ -89,7 +101,8 @@ function createTerminal() { term = new Terminal({ cursorBlink: optionElements.cursorBlink.checked, scrollback: parseInt(optionElements.scrollback.value, 10), - tabStopWidth: parseInt(optionElements.tabstopwidth.value, 10) + tabStopWidth: parseInt(optionElements.tabstopwidth.value, 10), + screenReaderMode: optionElements.screenReaderMode.checked }); window.term = term; // Expose `term` to window for debugging purposes term.on('resize', function (size) { diff --git a/src/AccessibilityManager.ts b/src/AccessibilityManager.ts index d2fe7e1a1..930ae9f0d 100644 --- a/src/AccessibilityManager.ts +++ b/src/AccessibilityManager.ts @@ -47,6 +47,8 @@ export class AccessibilityManager implements IDisposable { this._accessibilityTreeRoot.appendChild(this._rowContainer); this._renderRowsDebouncer = new RenderDebouncer(this._terminal, this._renderRows.bind(this)); + this._refreshRows(); + this._navigationMode = new NavigationMode(this._terminal, this._rowContainer, this._rowElements, this); this._liveRegion = document.createElement('div'); @@ -92,6 +94,10 @@ export class AccessibilityManager implements IDisposable { return this._navigationMode.isActive; } + public enterNavigationMode(): void { + this._navigationMode.enter(); + } + private _onResize(cols: number, rows: number): void { // Grow rows as required for (let i = this._rowContainer.children.length; i < this._terminal.rows; i++) { diff --git a/src/Terminal.ts b/src/Terminal.ts index 619387e29..62dcab8d9 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -1334,6 +1334,12 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT } } + public enterNavigationMode(): void { + if (this._accessibilityManager) { + this._accessibilityManager.enterNavigationMode(); + } + } + /** * Gets whether the terminal has an active selection. */ diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 5ebe578e4..856637344 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -332,6 +332,12 @@ declare module 'xterm' { */ deregisterLinkMatcher(matcherId: number): void; + /** + * Enters screen reader navigation mode. This will only work when + * the screenReaderMode option is true. + */ + enterNavigationMode(): void; + /** * Gets whether the terminal has an active selection. */