alert screen reader users with changes in watch variables (#221847)

This commit is contained in:
Megan Rogge
2024-07-16 20:03:46 -07:00
committed by GitHub
parent d61fc5c12f
commit 4a103b0eea
4 changed files with 51 additions and 0 deletions
@@ -60,6 +60,7 @@ import { launchSchemaId } from 'vs/workbench/services/configuration/common/confi
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import './debugSettingMigration';
import { DebugAccessibilityHelp } from 'vs/workbench/contrib/debug/browser/debugAccessibilityHelp';
import { DebugWatchAccessibilityAnnouncer } from 'vs/workbench/contrib/debug/common/debugAccessibilityAnnouncer';
import { ReplAccessibilityAnnouncer } from 'vs/workbench/contrib/debug/common/replAccessibilityAnnouncer';
const debugCategory = nls.localize('debugCategory', "Debug");
@@ -646,4 +647,5 @@ configurationRegistry.registerConfiguration({
AccessibleViewRegistry.register(new DebugAccessibleView());
AccessibleViewRegistry.register(new DebugAccessibilityHelp());
registerWorkbenchContribution2(DebugWatchAccessibilityAnnouncer.ID, DebugWatchAccessibilityAnnouncer, WorkbenchPhase.AfterRestored);
registerWorkbenchContribution2(ReplAccessibilityAnnouncer.ID, ReplAccessibilityAnnouncer, WorkbenchPhase.AfterRestored);
@@ -743,7 +743,14 @@ export interface IDebugModel extends ITreeElement {
getBreakpointModes(forBreakpointType: 'source' | 'exception' | 'data' | 'instruction'): DebugProtocol.BreakpointMode[];
onDidChangeBreakpoints: Event<IBreakpointsChangeEvent | undefined>;
onDidChangeCallStack: Event<void>;
/**
* The expression has been added, removed, or repositioned.
*/
onDidChangeWatchExpressions: Event<IExpression | undefined>;
/**
* The expression's value has changed.
*/
onDidChangeWatchExpressionValue: Event<IExpression | undefined>;
fetchCallstack(thread: IThread, levels?: number): Promise<void>;
}
@@ -0,0 +1,30 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IDebugService } from 'vs/workbench/contrib/debug/common/debug';
import { Disposable } from 'vs/base/common/lifecycle';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { ILogService } from 'vs/platform/log/common/log';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
export class DebugWatchAccessibilityAnnouncer extends Disposable implements IWorkbenchContribution {
static ID = 'workbench.contrib.debugWatchAccessibilityAnnouncer';
constructor(
@IDebugService _debugService: IDebugService,
@ILogService _logService: ILogService,
@IAccessibilityService _accessibilityService: IAccessibilityService
) {
super();
this._register(_debugService.getModel().onDidChangeWatchExpressionValue((e) => {
if (!e || e.value === 'not available') {
return;
}
// TODO: get user feedback, perhaps setting to configure verbosity + whether value, name, neither, or both are announced
_accessibilityService.alert(`${e.name} = ${e.value}`);
_logService.trace(`debugAccessibilityAnnouncerValueChanged ${e.name} ${e.value}`);
}));
}
}
@@ -298,6 +298,9 @@ export class Expression extends ExpressionContainer implements IExpression {
public available: boolean;
private readonly _onDidChangeValue = new Emitter<IExpression>();
public readonly onDidChangeValue: Event<IExpression> = this._onDidChangeValue.event;
constructor(public name: string, id = generateUuid()) {
super(undefined, undefined, 0, id);
this.available = false;
@@ -310,6 +313,9 @@ export class Expression extends ExpressionContainer implements IExpression {
async evaluate(session: IDebugSession | undefined, stackFrame: IStackFrame | undefined, context: string, keepLazyVars?: boolean, location?: IDebugEvaluatePosition): Promise<void> {
this.available = await this.evaluateExpression(this.name, session, stackFrame, context, keepLazyVars, location);
if (this.valueChanged) {
this._onDidChangeValue.fire(this);
}
}
override toString(): string {
@@ -1403,6 +1409,7 @@ export class DebugModel extends Disposable implements IDebugModel {
private readonly _onDidChangeBreakpoints = this._register(new Emitter<IBreakpointsChangeEvent | undefined>());
private readonly _onDidChangeCallStack = this._register(new Emitter<void>());
private readonly _onDidChangeWatchExpressions = this._register(new Emitter<IExpression | undefined>());
private readonly _onDidChangeWatchExpressionValue = this._register(new Emitter<IExpression | undefined>());
private readonly _breakpointModes = new Map<string, IBreakpointModeInternal>();
private breakpoints!: Breakpoint[];
private functionBreakpoints!: FunctionBreakpoint[];
@@ -1497,6 +1504,10 @@ export class DebugModel extends Disposable implements IDebugModel {
return this._onDidChangeWatchExpressions.event;
}
get onDidChangeWatchExpressionValue(): Event<IExpression | undefined> {
return this._onDidChangeWatchExpressionValue.event;
}
rawUpdate(data: IRawModelUpdate): void {
const session = this.sessions.find(p => p.getId() === data.sessionId);
if (session) {
@@ -2003,6 +2014,7 @@ export class DebugModel extends Disposable implements IDebugModel {
addWatchExpression(name?: string): IExpression {
const we = new Expression(name || '');
this._register(we.onDidChangeValue((e) => this._onDidChangeWatchExpressionValue.fire(e)));
this.watchExpressions.push(we);
this._onDidChangeWatchExpressions.fire(we);