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
3296 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
const disabledSounds = qp.items.map(i => (i as any).signal).filter(i => !enabledSounds.includes(i));
55
for (const signal of enabledSounds) {
56
let { sound, announcement } = configurationService.getValue<{ sound: string; announcement?: string }>(signal.settingsKey);
57
sound = userGestureSignals.includes(signal) ? 'userGesture' : accessibilityService.isScreenReaderOptimized() ? 'auto' : 'on';
58
if (announcement) {
59
configurationService.updateValue(signal.settingsKey, { sound, announcement });
60
} else {
61
configurationService.updateValue(signal.settingsKey, { sound });
62
}
63
}
64
65
for (const signal of disabledSounds) {
66
const announcement = configurationService.getValue(signal.settingsKey + '.announcement');
67
const sound = getDisabledSettingValue(userGestureSignals.includes(signal), accessibilityService.isScreenReaderOptimized());
68
const value = announcement ? { sound, announcement } : { sound };
69
configurationService.updateValue(signal.settingsKey, value);
70
}
71
qp.hide();
72
}));
73
disposables.add(qp.onDidTriggerItemButton(e => {
74
preferencesService.openUserSettings({ jsonEditor: true, revealSetting: { key: e.item.signal.settingsKey, edit: true } });
75
}));
76
disposables.add(qp.onDidChangeActive(() => {
77
accessibilitySignalService.playSound(qp.activeItems[0].signal.sound.getSound(true), true, AcknowledgeDocCommentsToken);
78
}));
79
disposables.add(qp.onDidHide(() => disposables.dispose()));
80
qp.placeholder = localize('sounds.help.placeholder', 'Select a sound to play and configure');
81
qp.canSelectMany = true;
82
await qp.show();
83
}
84
}
85
86
function getDisabledSettingValue(isUserGestureSignal: boolean, isScreenReaderOptimized: boolean): string {
87
return isScreenReaderOptimized ? (isUserGestureSignal ? 'never' : 'off') : (isUserGestureSignal ? 'never' : 'auto');
88
}
89
90
export class ShowAccessibilityAnnouncementHelp extends Action2 {
91
static readonly ID = 'accessibility.announcement.help';
92
93
constructor() {
94
super({
95
id: ShowAccessibilityAnnouncementHelp.ID,
96
title: localize2('accessibility.announcement.help', "Help: List Signal Announcements"),
97
f1: true,
98
metadata: {
99
description: localize('accessibility.announcement.help.description', "List all accessibility announcements, alerts, braille messages, and configure their settings")
100
}
101
});
102
}
103
104
override async run(accessor: ServicesAccessor): Promise<void> {
105
const accessibilitySignalService = accessor.get(IAccessibilitySignalService);
106
const quickInputService = accessor.get(IQuickInputService);
107
const configurationService = accessor.get(IConfigurationService);
108
const accessibilityService = accessor.get(IAccessibilityService);
109
const preferencesService = accessor.get(IPreferencesService);
110
const userGestureSignals = [AccessibilitySignal.save, AccessibilitySignal.format];
111
const items: (IQuickPickItem & { signal: AccessibilitySignal })[] = AccessibilitySignal.allAccessibilitySignals.filter(c => !!c.legacyAnnouncementSettingsKey).map((signal, idx) => ({
112
label: userGestureSignals.includes(signal) ? `${signal.name} (${configurationService.getValue(signal.settingsKey + '.announcement')})` : signal.name,
113
signal,
114
buttons: userGestureSignals.includes(signal) ? [{
115
iconClass: ThemeIcon.asClassName(Codicon.settingsGear),
116
tooltip: localize('announcement.help.settings', 'Configure Announcement'),
117
alwaysVisible: true,
118
}] : []
119
})).sort((a, b) => a.label.localeCompare(b.label));
120
const disposables = new DisposableStore();
121
const qp = disposables.add(quickInputService.createQuickPick<IQuickPickItem & { signal: AccessibilitySignal }>());
122
qp.items = items;
123
qp.selectedItems = items.filter(i => accessibilitySignalService.isAnnouncementEnabled(i.signal) || userGestureSignals.includes(i.signal) && configurationService.getValue(i.signal.settingsKey + '.announcement') !== 'never');
124
const screenReaderOptimized = accessibilityService.isScreenReaderOptimized();
125
disposables.add(qp.onDidAccept(() => {
126
if (!screenReaderOptimized) {
127
// announcements are off by default when screen reader is not active
128
qp.hide();
129
return;
130
}
131
const enabledAnnouncements = qp.selectedItems.map(i => i.signal);
132
const disabledAnnouncements = AccessibilitySignal.allAccessibilitySignals.filter(cue => !!cue.legacyAnnouncementSettingsKey && !enabledAnnouncements.includes(cue));
133
for (const signal of enabledAnnouncements) {
134
let { sound, announcement } = configurationService.getValue<{ sound: string; announcement?: string }>(signal.settingsKey);
135
announcement = userGestureSignals.includes(signal) ? 'userGesture' : signal.announcementMessage && accessibilityService.isScreenReaderOptimized() ? 'auto' : undefined;
136
configurationService.updateValue(signal.settingsKey, { sound, announcement });
137
}
138
139
for (const signal of disabledAnnouncements) {
140
const announcement = getDisabledSettingValue(userGestureSignals.includes(signal), true);
141
const sound = configurationService.getValue(signal.settingsKey + '.sound');
142
const value = announcement ? { sound, announcement } : { sound };
143
configurationService.updateValue(signal.settingsKey, value);
144
}
145
qp.hide();
146
}));
147
disposables.add(qp.onDidTriggerItemButton(e => {
148
preferencesService.openUserSettings({ jsonEditor: true, revealSetting: { key: e.item.signal.settingsKey, edit: true } });
149
}));
150
disposables.add(qp.onDidHide(() => disposables.dispose()));
151
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.');
152
qp.canSelectMany = true;
153
await qp.show();
154
}
155
}
156
157