Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/accessibility/browser/accessibilityService.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 { addDisposableListener } from '../../../base/browser/dom.js';
7
import { alert, status } from '../../../base/browser/ui/aria/aria.js';
8
import { mainWindow } from '../../../base/browser/window.js';
9
import { Emitter, Event } from '../../../base/common/event.js';
10
import { Disposable } from '../../../base/common/lifecycle.js';
11
import { AccessibilitySupport, CONTEXT_ACCESSIBILITY_MODE_ENABLED, IAccessibilityService } from '../common/accessibility.js';
12
import { IConfigurationService } from '../../configuration/common/configuration.js';
13
import { IContextKey, IContextKeyService } from '../../contextkey/common/contextkey.js';
14
import { ILayoutService } from '../../layout/browser/layoutService.js';
15
16
export class AccessibilityService extends Disposable implements IAccessibilityService {
17
declare readonly _serviceBrand: undefined;
18
19
private _accessibilityModeEnabledContext: IContextKey<boolean>;
20
protected _accessibilitySupport = AccessibilitySupport.Unknown;
21
protected readonly _onDidChangeScreenReaderOptimized = new Emitter<void>();
22
23
protected _configMotionReduced: 'auto' | 'on' | 'off';
24
protected _systemMotionReduced: boolean;
25
protected readonly _onDidChangeReducedMotion = new Emitter<void>();
26
27
private _linkUnderlinesEnabled: boolean;
28
protected readonly _onDidChangeLinkUnderline = new Emitter<void>();
29
30
constructor(
31
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
32
@ILayoutService private readonly _layoutService: ILayoutService,
33
@IConfigurationService protected readonly _configurationService: IConfigurationService
34
) {
35
super();
36
this._accessibilityModeEnabledContext = CONTEXT_ACCESSIBILITY_MODE_ENABLED.bindTo(this._contextKeyService);
37
38
const updateContextKey = () => this._accessibilityModeEnabledContext.set(this.isScreenReaderOptimized());
39
this._register(this._configurationService.onDidChangeConfiguration(e => {
40
if (e.affectsConfiguration('editor.accessibilitySupport')) {
41
updateContextKey();
42
this._onDidChangeScreenReaderOptimized.fire();
43
}
44
if (e.affectsConfiguration('workbench.reduceMotion')) {
45
this._configMotionReduced = this._configurationService.getValue('workbench.reduceMotion');
46
this._onDidChangeReducedMotion.fire();
47
}
48
}));
49
updateContextKey();
50
this._register(this.onDidChangeScreenReaderOptimized(() => updateContextKey()));
51
52
const reduceMotionMatcher = mainWindow.matchMedia(`(prefers-reduced-motion: reduce)`);
53
this._systemMotionReduced = reduceMotionMatcher.matches;
54
this._configMotionReduced = this._configurationService.getValue<'auto' | 'on' | 'off'>('workbench.reduceMotion');
55
56
this._linkUnderlinesEnabled = this._configurationService.getValue('accessibility.underlineLinks');
57
58
this.initReducedMotionListeners(reduceMotionMatcher);
59
this.initLinkUnderlineListeners();
60
}
61
62
private initReducedMotionListeners(reduceMotionMatcher: MediaQueryList) {
63
64
this._register(addDisposableListener(reduceMotionMatcher, 'change', () => {
65
this._systemMotionReduced = reduceMotionMatcher.matches;
66
if (this._configMotionReduced === 'auto') {
67
this._onDidChangeReducedMotion.fire();
68
}
69
}));
70
71
const updateRootClasses = () => {
72
const reduce = this.isMotionReduced();
73
this._layoutService.mainContainer.classList.toggle('reduce-motion', reduce);
74
this._layoutService.mainContainer.classList.toggle('enable-motion', !reduce);
75
};
76
77
updateRootClasses();
78
this._register(this.onDidChangeReducedMotion(() => updateRootClasses()));
79
}
80
81
private initLinkUnderlineListeners() {
82
this._register(this._configurationService.onDidChangeConfiguration(e => {
83
if (e.affectsConfiguration('accessibility.underlineLinks')) {
84
const linkUnderlinesEnabled = this._configurationService.getValue<boolean>('accessibility.underlineLinks');
85
this._linkUnderlinesEnabled = linkUnderlinesEnabled;
86
this._onDidChangeLinkUnderline.fire();
87
}
88
}));
89
90
const updateLinkUnderlineClasses = () => {
91
const underlineLinks = this._linkUnderlinesEnabled;
92
this._layoutService.mainContainer.classList.toggle('underline-links', underlineLinks);
93
};
94
95
updateLinkUnderlineClasses();
96
97
this._register(this.onDidChangeLinkUnderlines(() => updateLinkUnderlineClasses()));
98
}
99
100
public onDidChangeLinkUnderlines(listener: () => void) {
101
return this._onDidChangeLinkUnderline.event(listener);
102
}
103
104
get onDidChangeScreenReaderOptimized(): Event<void> {
105
return this._onDidChangeScreenReaderOptimized.event;
106
}
107
108
isScreenReaderOptimized(): boolean {
109
const config = this._configurationService.getValue('editor.accessibilitySupport');
110
return config === 'on' || (config === 'auto' && this._accessibilitySupport === AccessibilitySupport.Enabled);
111
}
112
113
get onDidChangeReducedMotion(): Event<void> {
114
return this._onDidChangeReducedMotion.event;
115
}
116
117
isMotionReduced(): boolean {
118
const config = this._configMotionReduced;
119
return config === 'on' || (config === 'auto' && this._systemMotionReduced);
120
}
121
122
alwaysUnderlineAccessKeys(): Promise<boolean> {
123
return Promise.resolve(false);
124
}
125
126
getAccessibilitySupport(): AccessibilitySupport {
127
return this._accessibilitySupport;
128
}
129
130
setAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void {
131
if (this._accessibilitySupport === accessibilitySupport) {
132
return;
133
}
134
135
this._accessibilitySupport = accessibilitySupport;
136
this._onDidChangeScreenReaderOptimized.fire();
137
}
138
139
alert(message: string): void {
140
alert(message);
141
}
142
143
status(message: string): void {
144
status(message);
145
}
146
}
147
148