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,43 @@
/*---------------------------------------------------------------------------------------------
* 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 } from 'vs/platform/accessibility/common/accessibility';
import { AudioCue, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';

export const IScreenReaderNotificationService = createDecorator<IScreenReaderNotificationService>('screenReaderNotificationService');

export interface IScreenReaderNotificationService {
notifyCleared(): void;
}

export class ScreenReaderNotificationService extends Disposable implements IScreenReaderNotificationService {
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('audioCues.clear');
if (audioCueValue === 'on' || audioCueValue === 'auto' && this._accessibilityService.isScreenReaderOptimized()) {
this._audioCueService.playAudioCue(AudioCue.clear);
} else {
alert(localize('cleared', "Cleared"));
}
}
}

export class TestScreenReaderNotificationService implements IScreenReaderNotificationService {

declare readonly _serviceBrand: undefined;

notifyCleared(): void { }
}
1 change: 0 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 Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export class TestAccessibilityService implements IAccessibilityService {

onDidChangeScreenReaderOptimized = Event.None;
onDidChangeReducedMotion = Event.None;
onDidRequestPlayClearAudioCue = Event.None;

isScreenReaderOptimized(): boolean { return false; }
isMotionReduced(): boolean { return false; }
Expand Down
8 changes: 8 additions & 0 deletions src/vs/platform/audioCues/browser/audioCueService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export class AudioCueService extends Disposable implements IAudioCueService {

public async playAudioCue(cue: AudioCue, options: IAudioCueOptions = {}): Promise<void> {
if (this.isEnabled(cue)) {
console.log('playing cue', cue.name);
this.sendAudioCueTelemetry(cue, options.source);
await this.playSound(cue.sound.getSound(), options.allowManyInParallel);
}
Expand Down Expand Up @@ -254,6 +255,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 +421,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 @@ -131,8 +131,12 @@ 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)."),
...audioCueFeatureBase,
default: 'off'
},
},
});

registerAction2(ShowAudioCueHelp);
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ 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';
import { IScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService';

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(IScreenReaderNotificationService).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 { IScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService';

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 screenReaderNotificationService = _accessor.get(IScreenReaderNotificationService);
view.clearRepl();
accessibilityService.alertCleared();
screenReaderNotificationService.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 { IScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService';

// 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 screenReaderNotificationService = accessor.get(IScreenReaderNotificationService);
const activeChannel = outputService.getActiveChannel();
if (activeChannel) {
activeChannel.clear();
accesibilityService.alertCleared();
screenReaderNotificationService.notifyCleared();
}
}
}));
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 { IScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService';

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
@IScreenReaderNotificationService private readonly _screenReaderNotificationService: IScreenReaderNotificationService
) {
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._screenReaderNotificationService.notifyCleared();
}

hasSelection(): boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ 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 { IScreenReaderNotificationService, TestScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService';
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 +66,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(IScreenReaderNotificationService, new TestScreenReaderNotificationService());
configHelper = store.add(instantiationService.createInstance(TerminalConfigHelper));
capabilities = store.add(new TerminalCapabilityStore());
if (!isWindows) {
Expand Down
2 changes: 2 additions & 0 deletions src/vs/workbench/workbench.web.main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ import { WebLanguagePacksService } from 'vs/platform/languagePacks/browser/langu

registerSingleton(IWorkbenchExtensionManagementService, ExtensionManagementService, InstantiationType.Delayed);
registerSingleton(IAccessibilityService, AccessibilityService, InstantiationType.Delayed);
registerSingleton(IScreenReaderNotificationService, ScreenReaderNotificationService, InstantiationType.Delayed);
registerSingleton(IContextMenuService, ContextMenuService, InstantiationType.Delayed);
registerSingleton(IUserDataSyncStoreService, UserDataSyncStoreService, InstantiationType.Delayed);
registerSingleton(IUserDataSyncMachinesService, UserDataSyncMachinesService, InstantiationType.Delayed);
Expand Down Expand Up @@ -181,6 +182,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { GroupOrientation } from 'vs/workbench/services/editor/common/editorGroupsService';
import { UserDataSyncResourceProviderService } from 'vs/platform/userDataSync/common/userDataSyncResourceProvider';
import { RemoteAuthorityResolverError, RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { IScreenReaderNotificationService, ScreenReaderNotificationService } from 'vs/platform/accessibility/browser/screenReaderNotificationService';

export {

Expand Down