Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/accessibilitySignals/browser/commands.ts
5260 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Codicon } from '../../../../base/common/codicons.js';
7
import { ThemeIcon } from '../../../../base/common/themables.js';
8
import { localize, localize2 } from '../../../../nls.js';
9
import { IAccessibilityService } from '../../../../platform/accessibility/common/accessibility.js';
10
import { Action2 } from '../../../../platform/actions/common/actions.js';
11
import { AccessibilitySignal, AcknowledgeDocCommentsToken, IAccessibilitySignalService } from '../../../../platform/accessibilitySignal/browser/accessibilitySignalService.js';
12
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
13
import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
14
import { IQuickInputService, IQuickPickItem } from '../../../../platform/quickinput/common/quickInput.js';
15
import { IPreferencesService } from '../../../services/preferences/common/preferences.js';
16
import { DisposableStore } from '../../../../base/common/lifecycle.js';
17
18
export class ShowSignalSoundHelp extends Action2 {
19
static readonly ID = 'signals.sounds.help';
20
21
constructor() {
22
super({
23
id: ShowSignalSoundHelp.ID,
24
title: localize2('signals.sound.help', "Help: List Signal Sounds"),
25
f1: true,
26
metadata: {
27
description: localize('accessibility.sound.help.description', "List all accessibility sounds, noises, or audio cues and configure their settings")
28
}
29
});
30
}
31
32
override async run(accessor: ServicesAccessor): Promise<void> {
33
const accessibilitySignalService = accessor.get(IAccessibilitySignalService);
34
const quickInputService = accessor.get(IQuickInputService);
35
const configurationService = accessor.get(IConfigurationService);
36
const accessibilityService = accessor.get(IAccessibilityService);
37
const preferencesService = accessor.get(IPreferencesService);
38
const userGestureSignals = [AccessibilitySignal.save, AccessibilitySignal.format];
39
const items: (IQuickPickItem & { signal: AccessibilitySignal })[] = AccessibilitySignal.allAccessibilitySignals.map((signal, idx) => ({
40
label: userGestureSignals.includes(signal) ? `${signal.name} (${configurationService.getValue(signal.settingsKey + '.sound')})` : signal.name,
41
signal,
42
buttons: userGestureSignals.includes(signal) ? [{
43
iconClass: ThemeIcon.asClassName(Codicon.settingsGear),
44
tooltip: localize('sounds.help.settings', 'Configure Sound'),
45
alwaysVisible: true
46
}] : []
47
})).sort((a, b) => a.label.localeCompare(b.label));
48
const disposables = new DisposableStore();
49
const qp = disposables.add(quickInputService.createQuickPick<IQuickPickItem & { signal: AccessibilitySignal }>());
50
qp.items = items;
51
qp.selectedItems = items.filter(i => accessibilitySignalService.isSoundEnabled(i.signal) || userGestureSignals.includes(i.signal) && configurationService.getValue(i.signal.settingsKey + '.sound') !== 'never');
52
disposables.add(qp.onDidAccept(() => {
53
const enabledSounds = qp.selectedItems.map(i => i.signal);
54
// eslint-disable-next-line local/code-no-any-casts
55
const disabledSounds = qp.items.map(i => (i as any).signal).filter(i => !enabledSounds.includes(i));
56
for (const signal of enabledSounds) {
57
let { sound, announcement } = configurationService.getValue<{ sound: string; announcement?: string }>(signal.settingsKey);
58
sound = userGestureSignals.includes(signal) ? 'userGesture' : accessibilityService.isScreenReaderOptimized() ? 'auto' : 'on';
59
if (announcement) {
60
configurationService.updateValue(signal.settingsKey, { sound, announcement });
61
} else {
62
configurationService.updateValue(signal.settingsKey, { sound });
63
}
64
}
65
66
for (const signal of disabledSounds) {
67
const announcement = configurationService.getValue(signal.settingsKey + '.announcement');
68
const sound = getDisabledSettingValue(userGestureSignals.includes(signal), accessibilityService.isScreenReaderOptimized());
69
const value = announcement ? { sound, announcement } : { sound };
70
configurationService.updateValue(signal.settingsKey, value);
71
}
72
qp.hide();
73
}));
74
disposables.add(qp.onDidTriggerItemButton(e => {
75
preferencesService.openUserSettings({ jsonEditor: true, revealSetting: { key: e.item.signal.settingsKey, edit: true } });
76
}));
77
disposables.add(qp.onDidChangeActive(() => {
78
accessibilitySignalService.playSound(qp.activeItems[0].signal.sound.getSound(true), true, AcknowledgeDocCommentsToken);
79
}));
80
disposables.add(qp.onDidHide(() => disposables.dispose()));
81
qp.placeholder = localize('sounds.help.placeholder', 'Select a sound to play and configure');
82
qp.canSelectMany = true;
83
await qp.show();
84
}
85
}
86
87
function getDisabledSettingValue(isUserGestureSignal: boolean, isScreenReaderOptimized: boolean): string {
88
return isScreenReaderOptimized ? (isUserGestureSignal ? 'never' : 'off') : (isUserGestureSignal ? 'never' : 'auto');
89
}
90
91
export class ShowAccessibilityAnnouncementHelp extends Action2 {
92
static readonly ID = 'accessibility.announcement.help';
93
94
constructor() {
95
super({
96
id: ShowAccessibilityAnnouncementHelp.ID,
97
title: localize2('accessibility.announcement.help', "Help: List Signal Announcements"),
98
f1: true,
99
metadata: {
100
description: localize('accessibility.announcement.help.description', "List all accessibility announcements, alerts, braille messages, and configure their settings")
101
}
102
});
103
}
104
105
override async run(accessor: ServicesAccessor): Promise<void> {
106
const accessibilitySignalService = accessor.get(IAccessibilitySignalService);
107
const quickInputService = accessor.get(IQuickInputService);
108
const configurationService = accessor.get(IConfigurationService);
109
const accessibilityService = accessor.get(IAccessibilityService);
110
const preferencesService = accessor.get(IPreferencesService);
111
const userGestureSignals = [AccessibilitySignal.save, AccessibilitySignal.format];
112
const items: (IQuickPickItem & { signal: AccessibilitySignal })[] = AccessibilitySignal.allAccessibilitySignals.filter(c => !!c.legacyAnnouncementSettingsKey).map((signal, idx) => ({
113
label: userGestureSignals.includes(signal) ? `${signal.name} (${configurationService.getValue(signal.settingsKey + '.announcement')})` : signal.name,
114
signal,
115
buttons: userGestureSignals.includes(signal) ? [{
116
iconClass: ThemeIcon.asClassName(Codicon.settingsGear),
117
tooltip: localize('announcement.help.settings', 'Configure Announcement'),
118
alwaysVisible: true,
119
}] : []
120
})).sort((a, b) => a.label.localeCompare(b.label));
121
const disposables = new DisposableStore();
122
const qp = disposables.add(quickInputService.createQuickPick<IQuickPickItem & { signal: AccessibilitySignal }>());
123
qp.items = items;
124
qp.selectedItems = items.filter(i => accessibilitySignalService.isAnnouncementEnabled(i.signal) || userGestureSignals.includes(i.signal) && configurationService.getValue(i.signal.settingsKey + '.announcement') !== 'never');
125
const screenReaderOptimized = accessibilityService.isScreenReaderOptimized();
126
disposables.add(qp.onDidAccept(() => {
127
if (!screenReaderOptimized) {
128
// announcements are off by default when screen reader is not active
129
qp.hide();
130
return;
131
}
132
const enabledAnnouncements = qp.selectedItems.map(i => i.signal);
133
const disabledAnnouncements = AccessibilitySignal.allAccessibilitySignals.filter(cue => !!cue.legacyAnnouncementSettingsKey && !enabledAnnouncements.includes(cue));
134
for (const signal of enabledAnnouncements) {
135
let { sound, announcement } = configurationService.getValue<{ sound: string; announcement?: string }>(signal.settingsKey);
136
announcement = userGestureSignals.includes(signal) ? 'userGesture' : signal.announcementMessage && accessibilityService.isScreenReaderOptimized() ? 'auto' : undefined;
137
configurationService.updateValue(signal.settingsKey, { sound, announcement });
138
}
139
140
for (const signal of disabledAnnouncements) {
141
const announcement = getDisabledSettingValue(userGestureSignals.includes(signal), true);
142
const sound = configurationService.getValue(signal.settingsKey + '.sound');
143
const value = announcement ? { sound, announcement } : { sound };
144
configurationService.updateValue(signal.settingsKey, value);
145
}
146
qp.hide();
147
}));
148
disposables.add(qp.onDidTriggerItemButton(e => {
149
preferencesService.openUserSettings({ jsonEditor: true, revealSetting: { key: e.item.signal.settingsKey, edit: true } });
150
}));
151
disposables.add(qp.onDidHide(() => disposables.dispose()));
152
qp.placeholder = screenReaderOptimized ? localize('announcement.help.placeholder', 'Select an announcement to configure') : localize('announcement.help.placeholder.disabled', 'Screen reader is not active, announcements are disabled by default.');
153
qp.canSelectMany = true;
154
await qp.show();
155
}
156
}
157
158