Change:
It doesn't matter in this case, but note that you collect all the keyListener disposables in the store of the AccessibleView class (even if you dispose them in , but the disposable is still in the disposableStore). This can lead to memory leaks. I can really recommend to compose components according to their life times. I think here the lifetime of the rendered content is owned by the caller of (the caller is supposed to call on the result). So the disposable returned by should be owned by whatever you return in . I suggest to create a DisposableStore in render, push the key listener to it once the text model resolves and return the disposable store at the end of render (also add the to the store). Also, note that the getTextModel promise can resolve after the caller called dispose. Originally posted by in

Discussion:
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; <del> import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; </del> <ins> import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; </ins> import { URI } from 'vs/base/common/uri'; import { IEditorConstructionOptions } from 'vs/editor/browser/config/editorConfiguration'; import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions';

import { LinkDetector } from 'vs/editor/contrib/links/browser/links'; import { localize } from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; <ins> import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; </ins> import { IContextViewDelegate, IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IOpenerService } from 'vs/platform/opener/common/opener';

type: AccessibleViewType; } <ins> export const accessibilityHelpIsShown = new RawContextKey<boolean>('accessibilityHelpIsShown', false, true); </ins> class AccessibleView extends Disposable { private _editorWidget: CodeEditorWidget; <ins> private _accessiblityHelpIsShown: IContextKey<boolean>; </ins> get editorWidget() { return this._editorWidget; } private _editorContainer: HTMLElement; <del> private _keyListener: IDisposable | undefined; </del> constructor( @IOpenerService private readonly _openerService: IOpenerService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @IConfigurationService private readonly _configurationService: IConfigurationService, @IModelService private readonly _modelService: IModelService, <del> @IContextViewService private readonly _contextViewService: IContextViewService </del> <ins> @IContextViewService private readonly _contextViewService: IContextViewService, @IContextKeyService private readonly _contextKeyService: IContextKeyService </ins> ) { super(); <ins> this._accessiblityHelpIsShown = accessibilityHelpIsShown.bindTo(this._contextKeyService); </ins> this._editorContainer = document.createElement('div'); this._editorContainer.classList.add('accessible-view'); const codeEditorWidgetOptions: ICodeEditorWidgetOptions = {

getAnchor: () => this._editorContainer, render: (container) => { return this._render(provider, container); <ins> }, onHide: () => { if (provider.options.type === AccessibleViewType.HelpMenu) { this._accessiblityHelpIsShown.reset(); } </ins> } }; this._contextViewService.showContextView(delegate); <ins> if (provider.options.type === AccessibleViewType.HelpMenu) { this._accessiblityHelpIsShown.set(true); } </ins> } private _render(provider: IAccessibleContentProvider, container: HTMLElement): IDisposable {

model.setLanguage(provider.options.language); } container.appendChild(this._editorContainer); <del> this._keyListener = this._register(this._editorWidget.onKeyUp((e) => { if (e.keyCode === KeyCode.Escape) { this._contextViewService.hideContextView(); // Delay to allow the context view to hide #186514 setTimeout(() => provider.onClose(), 100); this._keyListener?.dispose(); } else if (e.keyCode === KeyCode.KeyD && this._configurationService.getValue(settingKey)) { this._configurationService.updateValue(settingKey, false); } else if (e.keyCode === KeyCode.KeyH && provider.options.readMoreUrl) { const url: string = provider.options.readMoreUrl!; alert(AccessibilityHelpNLS.openingDocs); this._openerService.open(URI.parse(url)); } e.stopPropagation(); provider.onKeyDown?.(e); })); this._register(this._editorWidget.onDidBlurEditorText(() => this._contextViewService.hideContextView())); this._register(this._editorWidget.onDidContentSizeChange(() => this._layout())); </del> this._editorWidget.updateOptions({ ariaLabel: provider.options.ariaLabel }); this._editorWidget.focus(); }); <del> return toDisposable(() => { }); </del> <ins> const disposableStore = new DisposableStore(); disposableStore.add(this._editorWidget.onKeyUp((e) => { if (e.keyCode === KeyCode.Escape) { this._contextViewService.hideContextView(); // Delay to allow the context view to hide #186514 setTimeout(() => provider.onClose(), 100); } else if (e.keyCode === KeyCode.KeyD && this._configurationService.getValue(settingKey)) { this._configurationService.updateValue(settingKey, false); } e.stopPropagation(); provider.onKeyDown?.(e); })); disposableStore.add(this._editorWidget.onKeyDown((e) => { if (e.keyCode === KeyCode.KeyH && provider.options.readMoreUrl) { const url: string = provider.options.readMoreUrl!; alert(AccessibilityHelpNLS.openingDocs); this._openerService.open(URI.parse(url)); e.preventDefault(); e.stopPropagation(); } })); disposableStore.add(this._editorWidget.onDidBlurEditorText(() => this._contextViewService.hideContextView())); disposableStore.add(this._editorWidget.onDidContentSizeChange(() => this._layout())); return disposableStore; </ins> } private _layout(): void {

import { AccessibilitySupport, IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { TabFocus, TabFocusContext } from 'vs/editor/browser/config/tabFocus'; <ins> import { accessibilityHelpIsShown } from 'vs/workbench/contrib/accessibility/browser/accessibleView'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; </ins> const CONTEXT_ACCESSIBILITY_WIDGET_VISIBLE = new RawContextKey<boolean>('accessibilityHelpWidgetVisible', false);

id: 'editor.action.toggleScreenReaderAccessibilityMode', title: { value: nls.localize('toggleScreenReaderMode', "Toggle Screen Reader Accessibility Mode"), original: 'Toggle Screen Reader Accessibility Mode' }, f1: true, <ins> keybinding: { primary: KeyMod.CtrlCmd | KeyCode.KeyE, weight: KeybindingWeight.WorkbenchContrib + 10, when: accessibilityHelpIsShown } </ins> }); }