Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add clear audio cue, accessible notification service #195517

Merged
merged 12 commits into from
Oct 13, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { addDisposableListener } from 'vs/base/browser/dom';
import { alert } from 'vs/base/browser/ui/aria/aria';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { localize } from 'vs/nls';
import { AccessibilitySupport, CONTEXT_ACCESSIBILITY_MODE_ENABLED, IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
Expand All @@ -27,7 +26,7 @@ export class AccessibilityService extends Disposable implements IAccessibilitySe
constructor(
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
@ILayoutService private readonly _layoutService: ILayoutService,
@IConfigurationService protected readonly _configurationService: IConfigurationService,
@IConfigurationService protected readonly _configurationService: IConfigurationService
) {
super();
this._accessibilityModeEnabledContext = CONTEXT_ACCESSIBILITY_MODE_ENABLED.bindTo(this._contextKeyService);
Expand Down Expand Up @@ -116,9 +115,4 @@ export class AccessibilityService extends Disposable implements IAccessibilitySe
alert(message: string): void {
alert(message);
}
alertCleared(): void {
if (this.isScreenReaderOptimized()) {
alert(localize('cleared', "Cleared"));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Disposable } from 'vs/base/common/lifecycle';
import { localize } from 'vs/nls';
import { IAccessibilityService, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility';
import { AudioCue, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';

export class AccessibleNotificationService extends Disposable implements IAccessibleNotificationService {
declare readonly _serviceBrand: undefined;

constructor(
@IAudioCueService private readonly _audioCueService: IAudioCueService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IAccessibilityService private readonly _accessibilityService: IAccessibilityService) {
super();
}

notifyCleared(): void {
const audioCueValue = this._configurationService.getValue(AudioCue.clear.settingsKey);
if (audioCueValue === 'on' || audioCueValue === 'auto' && this._accessibilityService.isScreenReaderOptimized()) {
this._audioCueService.playAudioCue(AudioCue.clear);
} else {
alert(localize('cleared', "Cleared"));
}
}
}

export class TestAccessibleNotificationService extends Disposable implements IAccessibleNotificationService {

declare readonly _serviceBrand: undefined;

notifyCleared(): void { }
}
13 changes: 12 additions & 1 deletion src/vs/platform/accessibility/common/accessibility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export interface IAccessibilityService {
getAccessibilitySupport(): AccessibilitySupport;
setAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void;
alert(message: string): void;
alertCleared(): void;
}

export const enum AccessibilitySupport {
Expand All @@ -47,3 +46,15 @@ export function isAccessibilityInformation(obj: any): obj is IAccessibilityInfor
&& typeof obj.label === 'string'
&& (typeof obj.role === 'undefined' || typeof obj.role === 'string');
}

export const IAccessibleNotificationService = createDecorator<IAccessibleNotificationService>('accessibleNotificationService');
/**
* Manages whether an audio cue or an aria alert will be used
* in response to actions taken around the workbench.
* Targets screen reader and braille users.
*/
export interface IAccessibleNotificationService {
readonly _serviceBrand: undefined;
notifyCleared(): void;
}

Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,4 @@ export class TestAccessibilityService implements IAccessibilityService {
setAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void { }
getAccessibilitySupport(): AccessibilitySupport { return AccessibilitySupport.Unknown; }
alert(message: string): void { }
alertCleared(): void { }
}
7 changes: 7 additions & 0 deletions src/vs/platform/audioCues/browser/audioCueService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ export class Sound {
public static readonly chatResponseReceived2 = Sound.register({ fileName: 'chatResponseReceived2.mp3' });
public static readonly chatResponseReceived3 = Sound.register({ fileName: 'chatResponseReceived3.mp3' });
public static readonly chatResponseReceived4 = Sound.register({ fileName: 'chatResponseReceived4.mp3' });
public static readonly clear = Sound.register({ fileName: 'clear.mp3' });

private constructor(public readonly fileName: string) { }
}
Expand Down Expand Up @@ -419,6 +420,12 @@ export class AudioCue {
settingsKey: 'audioCues.chatResponsePending'
});

public static readonly clear = AudioCue.register({
name: localize('audioCues.clear', 'Clear'),
sound: Sound.clear,
settingsKey: 'audioCues.clear'
});

private constructor(
public readonly sound: SoundSource,
public readonly name: string,
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ import { UnfocusedViewDimmingContribution } from 'vs/workbench/contrib/accessibi
import { EditorAccessibilityHelpContribution, HoverAccessibleViewContribution, InlineCompletionsAccessibleViewContribution, NotificationAccessibleViewContribution } from 'vs/workbench/contrib/accessibility/browser/accessibilityContributions';
import { AccessibilityStatus } from 'vs/workbench/contrib/accessibility/browser/accessibilityStatus';
import { CommentsAccessibilityHelpContribution } from 'vs/workbench/contrib/comments/browser/comments.contribution';
import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility';
import { AccessibleNotificationService } from 'vs/platform/accessibility/browser/accessibleNotificationService';

registerAccessibilityConfiguration();
registerSingleton(IAccessibleViewService, AccessibleViewService, InstantiationType.Delayed);
registerSingleton(IAccessibleNotificationService, AccessibleNotificationService, InstantiationType.Delayed);

const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(EditorAccessibilityHelpContribution, LifecyclePhase.Eventually);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,13 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).regis
'description': localize('audioCues.chatResponseReceived', "Plays a sound on loop while the response has been received."),
...audioCueFeatureBase,
default: 'off'
}
}
},
'audioCues.clear': {
'description': localize('audioCues.clear', "Plays a sound when a feature is cleared (for example, the terminal, debug console, or output channel). When this is disabled, an aria alert will announce 'Cleared'."),
...audioCueFeatureBase,
default: 'off'
},
},
});
meganrogge marked this conversation as resolved.
Show resolved Hide resolved

registerAction2(ShowAudioCueHelp);
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Codicon } from 'vs/base/common/codicons';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { localize } from 'vs/nls';
import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility';
import { Action2, IAction2Options, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
Expand All @@ -18,7 +19,6 @@ import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
import { ChatEditorInput } from 'vs/workbench/contrib/chat/browser/chatEditorInput';
import { ChatViewPane } from 'vs/workbench/contrib/chat/browser/chatViewPane';
import { CONTEXT_IN_CHAT_SESSION, CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';

export const ACTION_ID_CLEAR_CHAT = `workbench.action.chat.clear`;

Expand Down Expand Up @@ -118,5 +118,5 @@ export function getClearAction(viewId: string, providerId: string) {
}

function announceChatCleared(accessor: ServicesAccessor): void {
accessor.get(IAccessibilityService).alertCleared();
accessor.get(IAccessibleNotificationService).notifyCleared();
}
6 changes: 3 additions & 3 deletions src/vs/workbench/contrib/debug/browser/repl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ import { Variable } from 'vs/workbench/contrib/debug/common/debugModel';
import { ReplEvaluationResult, ReplGroup } from 'vs/workbench/contrib/debug/common/replModel';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { registerNavigableContainer } from 'vs/workbench/browser/actions/widgetNavigationCommands';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility';

const $ = dom.$;

Expand Down Expand Up @@ -976,9 +976,9 @@ registerAction2(class extends ViewAction<Repl> {
}

runInView(_accessor: ServicesAccessor, view: Repl): void {
const accessibilityService = _accessor.get(IAccessibilityService);
const accessibleNotificationService = _accessor.get(IAccessibleNotificationService);
view.clearRepl();
accessibilityService.alertCleared();
accessibleNotificationService.notifyCleared();
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
import { Categories } from 'vs/platform/action/common/actionCommonCategories';
import { Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility';

// Register Service
registerSingleton(IOutputService, OutputService, InstantiationType.Delayed);
Expand Down Expand Up @@ -221,11 +221,11 @@ class OutputContribution extends Disposable implements IWorkbenchContribution {
}
async run(accessor: ServicesAccessor): Promise<void> {
const outputService = accessor.get(IOutputService);
const accesibilityService = accessor.get(IAccessibilityService);
const accessibleNotificationService = accessor.get(IAccessibleNotificationService);
const activeChannel = outputService.getActiveChannel();
if (activeChannel) {
activeChannel.clear();
accesibilityService.alertCleared();
accessibleNotificationService.notifyCleared();
}
}
}));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
@IOpenerService private readonly _openerService: IOpenerService,
@ICommandService private readonly _commandService: ICommandService,
@IAudioCueService private readonly _audioCueService: IAudioCueService,
@IViewDescriptorService private readonly _viewDescriptorService: IViewDescriptorService,
@IViewDescriptorService private readonly _viewDescriptorService: IViewDescriptorService
) {
super();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService
import { debounce } from 'vs/base/common/decorators';
import { MouseWheelClassifier } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { IMouseWheelEvent, StandardWheelEvent } from 'vs/base/browser/mouseEvent';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility';

const enum RenderConstants {
/**
Expand Down Expand Up @@ -204,7 +204,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@IClipboardService private readonly _clipboardService: IClipboardService,
@IContextKeyService contextKeyService: IContextKeyService,
@IAccessibilityService private readonly _accessibilityService: IAccessibilityService
@IAccessibleNotificationService private readonly _accessibleNotificationService: IAccessibleNotificationService
) {
super();
const font = this._configHelper.getFont(undefined, true);
Expand Down Expand Up @@ -590,7 +590,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach
// the prompt being written
this._capabilities.get(TerminalCapability.CommandDetection)?.handlePromptStart();
this._capabilities.get(TerminalCapability.CommandDetection)?.handleCommandStart();
this._accessibilityService.alertCleared();
this._accessibleNotificationService.notifyCleared();
}

hasSelection(): boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import * as assert from 'assert';
import { importAMDNodeModule } from 'vs/amdX';
import { isWindows } from 'vs/base/common/platform';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { TestAccessibilityService } from 'vs/platform/accessibility/test/common/testAccessibilityService';
import { TestAccessibleNotificationService } from 'vs/platform/accessibility/browser/accessibleNotificationService';
import { IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
Expand Down Expand Up @@ -67,7 +67,7 @@ suite('Buffer Content Tracker', () => {
instantiationService.stub(IContextMenuService, store.add(instantiationService.createInstance(ContextMenuService)));
instantiationService.stub(ILifecycleService, store.add(new TestLifecycleService()));
instantiationService.stub(IContextKeyService, store.add(new MockContextKeyService()));
instantiationService.stub(IAccessibilityService, new TestAccessibilityService());
instantiationService.stub(IAccessibleNotificationService, store.add(new TestAccessibleNotificationService()));
configHelper = store.add(instantiationService.createInstance(TerminalConfigHelper));
capabilities = store.add(new TerminalCapabilityStore());
if (!isWindows) {
Expand Down
Loading