Path: blob/main/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { localize } from '../../../../nls.js';6import { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationPropertySchema, IConfigurationRegistry } from '../../../../platform/configuration/common/configurationRegistry.js';7import { Registry } from '../../../../platform/registry/common/platform.js';8import { RawContextKey } from '../../../../platform/contextkey/common/contextkey.js';9import { workbenchConfigurationNodeBase, Extensions as WorkbenchExtensions, IConfigurationMigrationRegistry, ConfigurationKeyValuePairs, ConfigurationMigration } from '../../../common/configuration.js';10import { AccessibilitySignal } from '../../../../platform/accessibilitySignal/browser/accessibilitySignalService.js';11import { AccessibilityVoiceSettingId, ISpeechService, SPEECH_LANGUAGES } from '../../speech/common/speechService.js';12import { Disposable } from '../../../../base/common/lifecycle.js';13import { IWorkbenchContribution } from '../../../common/contributions.js';14import { Event } from '../../../../base/common/event.js';15import { isDefined } from '../../../../base/common/types.js';1617export const accessibilityHelpIsShown = new RawContextKey<boolean>('accessibilityHelpIsShown', false, true);18export const accessibleViewIsShown = new RawContextKey<boolean>('accessibleViewIsShown', false, true);19export const accessibleViewSupportsNavigation = new RawContextKey<boolean>('accessibleViewSupportsNavigation', false, true);20export const accessibleViewVerbosityEnabled = new RawContextKey<boolean>('accessibleViewVerbosityEnabled', false, true);21export const accessibleViewGoToSymbolSupported = new RawContextKey<boolean>('accessibleViewGoToSymbolSupported', false, true);22export const accessibleViewOnLastLine = new RawContextKey<boolean>('accessibleViewOnLastLine', false, true);23export const accessibleViewCurrentProviderId = new RawContextKey<string>('accessibleViewCurrentProviderId', undefined, undefined);24export const accessibleViewInCodeBlock = new RawContextKey<boolean>('accessibleViewInCodeBlock', undefined, undefined);25export const accessibleViewContainsCodeBlocks = new RawContextKey<boolean>('accessibleViewContainsCodeBlocks', undefined, undefined);26export const accessibleViewHasUnassignedKeybindings = new RawContextKey<boolean>('accessibleViewHasUnassignedKeybindings', undefined, undefined);27export const accessibleViewHasAssignedKeybindings = new RawContextKey<boolean>('accessibleViewHasAssignedKeybindings', undefined, undefined);2829/**30* Miscellaneous settings tagged with accessibility and implemented in the accessibility contrib but31* were better to live under workbench for discoverability.32*/33export const enum AccessibilityWorkbenchSettingId {34DimUnfocusedEnabled = 'accessibility.dimUnfocused.enabled',35DimUnfocusedOpacity = 'accessibility.dimUnfocused.opacity',36HideAccessibleView = 'accessibility.hideAccessibleView',37AccessibleViewCloseOnKeyPress = 'accessibility.accessibleView.closeOnKeyPress'38}3940export const enum ViewDimUnfocusedOpacityProperties {41Default = 0.75,42Minimum = 0.2,43Maximum = 144}4546export const enum AccessibilityVerbositySettingId {47Terminal = 'accessibility.verbosity.terminal',48DiffEditor = 'accessibility.verbosity.diffEditor',49MergeEditor = 'accessibility.verbosity.mergeEditor',50Chat = 'accessibility.verbosity.panelChat',51InlineChat = 'accessibility.verbosity.inlineChat',52TerminalChat = 'accessibility.verbosity.terminalChat',53InlineCompletions = 'accessibility.verbosity.inlineCompletions',54KeybindingsEditor = 'accessibility.verbosity.keybindingsEditor',55Notebook = 'accessibility.verbosity.notebook',56Editor = 'accessibility.verbosity.editor',57Hover = 'accessibility.verbosity.hover',58Notification = 'accessibility.verbosity.notification',59EmptyEditorHint = 'accessibility.verbosity.emptyEditorHint',60ReplEditor = 'accessibility.verbosity.replEditor',61Comments = 'accessibility.verbosity.comments',62DiffEditorActive = 'accessibility.verbosity.diffEditorActive',63Debug = 'accessibility.verbosity.debug',64Walkthrough = 'accessibility.verbosity.walkthrough',65SourceControl = 'accessibility.verbosity.sourceControl'66}6768const baseVerbosityProperty: IConfigurationPropertySchema = {69type: 'boolean',70default: true,71tags: ['accessibility']72};7374export const accessibilityConfigurationNodeBase = Object.freeze<IConfigurationNode>({75id: 'accessibility',76title: localize('accessibilityConfigurationTitle', "Accessibility"),77type: 'object'78});7980export const soundFeatureBase: IConfigurationPropertySchema = {81'type': 'string',82'enum': ['auto', 'on', 'off'],83'default': 'auto',84'enumDescriptions': [85localize('sound.enabled.auto', "Enable sound when a screen reader is attached."),86localize('sound.enabled.on', "Enable sound."),87localize('sound.enabled.off', "Disable sound.")88],89tags: ['accessibility'],90};9192const signalFeatureBase: IConfigurationPropertySchema = {93'type': 'object',94'tags': ['accessibility'],95additionalProperties: false,96default: {97sound: 'auto',98announcement: 'auto'99}100};101102export const announcementFeatureBase: IConfigurationPropertySchema = {103'type': 'string',104'enum': ['auto', 'off'],105'default': 'auto',106'enumDescriptions': [107localize('announcement.enabled.auto', "Enable announcement, will only play when in screen reader optimized mode."),108localize('announcement.enabled.off', "Disable announcement.")109],110tags: ['accessibility'],111};112113const defaultNoAnnouncement: IConfigurationPropertySchema = {114'type': 'object',115'tags': ['accessibility'],116additionalProperties: false,117'default': {118'sound': 'auto',119}120};121122const configuration: IConfigurationNode = {123...accessibilityConfigurationNodeBase,124scope: ConfigurationScope.RESOURCE,125properties: {126[AccessibilityVerbositySettingId.Terminal]: {127description: localize('verbosity.terminal.description', 'Provide information about how to access the terminal accessibility help menu when the terminal is focused.'),128...baseVerbosityProperty129},130[AccessibilityVerbositySettingId.DiffEditor]: {131description: localize('verbosity.diffEditor.description', 'Provide information about how to navigate changes in the diff editor when it is focused.'),132...baseVerbosityProperty133},134[AccessibilityVerbositySettingId.Chat]: {135description: localize('verbosity.chat.description', 'Provide information about how to access the chat help menu when the chat input is focused.'),136...baseVerbosityProperty137},138[AccessibilityVerbositySettingId.InlineChat]: {139description: localize('verbosity.interactiveEditor.description', 'Provide information about how to access the inline editor chat accessibility help menu and alert with hints that describe how to use the feature when the input is focused.'),140...baseVerbosityProperty141},142[AccessibilityVerbositySettingId.InlineCompletions]: {143description: localize('verbosity.inlineCompletions.description', 'Provide information about how to access the inline completions hover and Accessible View.'),144...baseVerbosityProperty145},146[AccessibilityVerbositySettingId.KeybindingsEditor]: {147description: localize('verbosity.keybindingsEditor.description', 'Provide information about how to change a keybinding in the keybindings editor when a row is focused.'),148...baseVerbosityProperty149},150[AccessibilityVerbositySettingId.Notebook]: {151description: localize('verbosity.notebook', 'Provide information about how to focus the cell container or inner editor when a notebook cell is focused.'),152...baseVerbosityProperty153},154[AccessibilityVerbositySettingId.Hover]: {155description: localize('verbosity.hover', 'Provide information about how to open the hover in an Accessible View.'),156...baseVerbosityProperty157},158[AccessibilityVerbositySettingId.Notification]: {159description: localize('verbosity.notification', 'Provide information about how to open the notification in an Accessible View.'),160...baseVerbosityProperty161},162[AccessibilityVerbositySettingId.EmptyEditorHint]: {163description: localize('verbosity.emptyEditorHint', 'Provide information about relevant actions in an empty text editor.'),164...baseVerbosityProperty165},166[AccessibilityVerbositySettingId.ReplEditor]: {167description: localize('verbosity.replEditor.description', 'Provide information about how to access the REPL editor accessibility help menu when the REPL editor is focused.'),168...baseVerbosityProperty169},170[AccessibilityVerbositySettingId.Comments]: {171description: localize('verbosity.comments', 'Provide information about actions that can be taken in the comment widget or in a file which contains comments.'),172...baseVerbosityProperty173},174[AccessibilityVerbositySettingId.DiffEditorActive]: {175description: localize('verbosity.diffEditorActive', 'Indicate when a diff editor becomes the active editor.'),176...baseVerbosityProperty177},178[AccessibilityVerbositySettingId.Debug]: {179description: localize('verbosity.debug', 'Provide information about how to access the debug console accessibility help dialog when the debug console or run and debug viewlet is focused. Note that a reload of the window is required for this to take effect.'),180...baseVerbosityProperty181},182[AccessibilityVerbositySettingId.Walkthrough]: {183description: localize('verbosity.walkthrough', 'Provide information about how to open the walkthrough in an Accessible View.'),184...baseVerbosityProperty185},186[AccessibilityWorkbenchSettingId.AccessibleViewCloseOnKeyPress]: {187markdownDescription: localize('terminal.integrated.accessibleView.closeOnKeyPress', "On keypress, close the Accessible View and focus the element from which it was invoked."),188type: 'boolean',189default: true190},191[AccessibilityVerbositySettingId.SourceControl]: {192description: localize('verbosity.scm', 'Provide information about how to access the source control accessibility help menu when the input is focused.'),193...baseVerbosityProperty194},195'accessibility.signalOptions.volume': {196'description': localize('accessibility.signalOptions.volume', "The volume of the sounds in percent (0-100)."),197'type': 'number',198'minimum': 0,199'maximum': 100,200'default': 70,201'tags': ['accessibility']202},203'accessibility.signalOptions.debouncePositionChanges': {204'description': localize('accessibility.signalOptions.debouncePositionChanges', "Whether or not position changes should be debounced"),205'type': 'boolean',206'default': false,207'tags': ['accessibility']208},209'accessibility.signalOptions.experimental.delays.general': {210'type': 'object',211'description': 'Delays for all signals besides error and warning at position',212'additionalProperties': false,213'properties': {214'announcement': {215'description': localize('accessibility.signalOptions.delays.general.announcement', "The delay in milliseconds before an announcement is made."),216'type': 'number',217'minimum': 0,218'default': 3000219},220'sound': {221'description': localize('accessibility.signalOptions.delays.general.sound', "The delay in milliseconds before a sound is played."),222'type': 'number',223'minimum': 0,224'default': 400225}226},227'tags': ['accessibility']228},229'accessibility.signalOptions.experimental.delays.warningAtPosition': {230'type': 'object',231'additionalProperties': false,232'properties': {233'announcement': {234'description': localize('accessibility.signalOptions.delays.warningAtPosition.announcement', "The delay in milliseconds before an announcement is made when there's a warning at the position."),235'type': 'number',236'minimum': 0,237'default': 3000238},239'sound': {240'description': localize('accessibility.signalOptions.delays.warningAtPosition.sound', "The delay in milliseconds before a sound is played when there's a warning at the position."),241'type': 'number',242'minimum': 0,243'default': 1000244}245},246'tags': ['accessibility']247},248'accessibility.signalOptions.experimental.delays.errorAtPosition': {249'type': 'object',250'additionalProperties': false,251'properties': {252'announcement': {253'description': localize('accessibility.signalOptions.delays.errorAtPosition.announcement', "The delay in milliseconds before an announcement is made when there's an error at the position."),254'type': 'number',255'minimum': 0,256'default': 3000257},258'sound': {259'description': localize('accessibility.signalOptions.delays.errorAtPosition.sound', "The delay in milliseconds before a sound is played when there's an error at the position."),260'type': 'number',261'minimum': 0,262'default': 1000263}264},265'tags': ['accessibility']266},267'accessibility.signals.lineHasBreakpoint': {268...signalFeatureBase,269'description': localize('accessibility.signals.lineHasBreakpoint', "Plays a signal - sound (audio cue) and/or announcement (alert) - when the active line has a breakpoint."),270'properties': {271'sound': {272'description': localize('accessibility.signals.lineHasBreakpoint.sound', "Plays a sound when the active line has a breakpoint."),273...soundFeatureBase274},275'announcement': {276'description': localize('accessibility.signals.lineHasBreakpoint.announcement', "Announces when the active line has a breakpoint."),277...announcementFeatureBase278},279},280},281'accessibility.signals.lineHasInlineSuggestion': {282...defaultNoAnnouncement,283'description': localize('accessibility.signals.lineHasInlineSuggestion', "Plays a sound / audio cue when the active line has an inline suggestion."),284'properties': {285'sound': {286'description': localize('accessibility.signals.lineHasInlineSuggestion.sound', "Plays a sound when the active line has an inline suggestion."),287...soundFeatureBase,288'default': 'off'289}290}291},292'accessibility.signals.nextEditSuggestion': {293...signalFeatureBase,294'description': localize('accessibility.signals.nextEditSuggestion', "Plays a signal - sound / audio cue and/or announcement (alert) when there is a next edit suggestion."),295'properties': {296'sound': {297'description': localize('accessibility.signals.nextEditSuggestion.sound', "Plays a sound when there is a next edit suggestion."),298...soundFeatureBase,299},300'announcement': {301'description': localize('accessibility.signals.nextEditSuggestion.announcement', "Announces when there is a next edit suggestion."),302...announcementFeatureBase,303},304}305},306'accessibility.signals.lineHasError': {307...signalFeatureBase,308'description': localize('accessibility.signals.lineHasError', "Plays a signal - sound (audio cue) and/or announcement (alert) - when the active line has an error."),309'properties': {310'sound': {311'description': localize('accessibility.signals.lineHasError.sound', "Plays a sound when the active line has an error."),312...soundFeatureBase313},314'announcement': {315'description': localize('accessibility.signals.lineHasError.announcement', "Announces when the active line has an error."),316...announcementFeatureBase,317default: 'off'318},319},320},321'accessibility.signals.lineHasFoldedArea': {322...signalFeatureBase,323'description': localize('accessibility.signals.lineHasFoldedArea', "Plays a signal - sound (audio cue) and/or announcement (alert) - the active line has a folded area that can be unfolded."),324'properties': {325'sound': {326'description': localize('accessibility.signals.lineHasFoldedArea.sound', "Plays a sound when the active line has a folded area that can be unfolded."),327...soundFeatureBase,328default: 'off'329},330'announcement': {331'description': localize('accessibility.signals.lineHasFoldedArea.announcement', "Announces when the active line has a folded area that can be unfolded."),332...announcementFeatureBase333},334}335},336'accessibility.signals.lineHasWarning': {337...signalFeatureBase,338'description': localize('accessibility.signals.lineHasWarning', "Plays a signal - sound (audio cue) and/or announcement (alert) - when the active line has a warning."),339'properties': {340'sound': {341'description': localize('accessibility.signals.lineHasWarning.sound', "Plays a sound when the active line has a warning."),342...soundFeatureBase343},344'announcement': {345'description': localize('accessibility.signals.lineHasWarning.announcement', "Announces when the active line has a warning."),346...announcementFeatureBase,347default: 'off'348},349},350},351'accessibility.signals.positionHasError': {352...signalFeatureBase,353'description': localize('accessibility.signals.positionHasError', "Plays a signal - sound (audio cue) and/or announcement (alert) - when the active line has a warning."),354'properties': {355'sound': {356'description': localize('accessibility.signals.positionHasError.sound', "Plays a sound when the active line has a warning."),357...soundFeatureBase358},359'announcement': {360'description': localize('accessibility.signals.positionHasError.announcement', "Announces when the active line has a warning."),361...announcementFeatureBase,362default: 'on'363},364},365},366'accessibility.signals.positionHasWarning': {367...signalFeatureBase,368'description': localize('accessibility.signals.positionHasWarning', "Plays a signal - sound (audio cue) and/or announcement (alert) - when the active line has a warning."),369'properties': {370'sound': {371'description': localize('accessibility.signals.positionHasWarning.sound', "Plays a sound when the active line has a warning."),372...soundFeatureBase373},374'announcement': {375'description': localize('accessibility.signals.positionHasWarning.announcement', "Announces when the active line has a warning."),376...announcementFeatureBase,377default: 'on'378},379},380},381'accessibility.signals.onDebugBreak': {382...signalFeatureBase,383'description': localize('accessibility.signals.onDebugBreak', "Plays a signal - sound (audio cue) and/or announcement (alert) - when the debugger stopped on a breakpoint."),384'properties': {385'sound': {386'description': localize('accessibility.signals.onDebugBreak.sound', "Plays a sound when the debugger stopped on a breakpoint."),387...soundFeatureBase388},389'announcement': {390'description': localize('accessibility.signals.onDebugBreak.announcement', "Announces when the debugger stopped on a breakpoint."),391...announcementFeatureBase392},393}394},395'accessibility.signals.noInlayHints': {396...signalFeatureBase,397'description': localize('accessibility.signals.noInlayHints', "Plays a signal - sound (audio cue) and/or announcement (alert) - when trying to read a line with inlay hints that has no inlay hints."),398'properties': {399'sound': {400'description': localize('accessibility.signals.noInlayHints.sound', "Plays a sound when trying to read a line with inlay hints that has no inlay hints."),401...soundFeatureBase402},403'announcement': {404'description': localize('accessibility.signals.noInlayHints.announcement', "Announces when trying to read a line with inlay hints that has no inlay hints."),405...announcementFeatureBase406},407}408},409'accessibility.signals.taskCompleted': {410...signalFeatureBase,411'description': localize('accessibility.signals.taskCompleted', "Plays a signal - sound (audio cue) and/or announcement (alert) - when a task is completed."),412'properties': {413'sound': {414'description': localize('accessibility.signals.taskCompleted.sound', "Plays a sound when a task is completed."),415...soundFeatureBase416},417'announcement': {418'description': localize('accessibility.signals.taskCompleted.announcement', "Announces when a task is completed."),419...announcementFeatureBase420},421}422},423'accessibility.signals.taskFailed': {424...signalFeatureBase,425'description': localize('accessibility.signals.taskFailed', "Plays a signal - sound (audio cue) and/or announcement (alert) - when a task fails (non-zero exit code)."),426'properties': {427'sound': {428'description': localize('accessibility.signals.taskFailed.sound', "Plays a sound when a task fails (non-zero exit code)."),429...soundFeatureBase430},431'announcement': {432'description': localize('accessibility.signals.taskFailed.announcement', "Announces when a task fails (non-zero exit code)."),433...announcementFeatureBase434},435}436},437'accessibility.signals.terminalCommandFailed': {438...signalFeatureBase,439'description': localize('accessibility.signals.terminalCommandFailed', "Plays a signal - sound (audio cue) and/or announcement (alert) - when a terminal command fails (non-zero exit code) or when a command with such an exit code is navigated to in the accessible view."),440'properties': {441'sound': {442'description': localize('accessibility.signals.terminalCommandFailed.sound', "Plays a sound when a terminal command fails (non-zero exit code) or when a command with such an exit code is navigated to in the accessible view."),443...soundFeatureBase444},445'announcement': {446'description': localize('accessibility.signals.terminalCommandFailed.announcement', "Announces when a terminal command fails (non-zero exit code) or when a command with such an exit code is navigated to in the accessible view."),447...announcementFeatureBase448},449}450},451'accessibility.signals.terminalCommandSucceeded': {452...signalFeatureBase,453'description': localize('accessibility.signals.terminalCommandSucceeded', "Plays a signal - sound (audio cue) and/or announcement (alert) - when a terminal command succeeds (zero exit code) or when a command with such an exit code is navigated to in the accessible view."),454'properties': {455'sound': {456'description': localize('accessibility.signals.terminalCommandSucceeded.sound', "Plays a sound when a terminal command succeeds (zero exit code) or when a command with such an exit code is navigated to in the accessible view."),457...soundFeatureBase458},459'announcement': {460'description': localize('accessibility.signals.terminalCommandSucceeded.announcement', "Announces when a terminal command succeeds (zero exit code) or when a command with such an exit code is navigated to in the accessible view."),461...announcementFeatureBase462},463}464},465'accessibility.signals.terminalQuickFix': {466...signalFeatureBase,467'description': localize('accessibility.signals.terminalQuickFix', "Plays a signal - sound (audio cue) and/or announcement (alert) - when terminal Quick Fixes are available."),468'properties': {469'sound': {470'description': localize('accessibility.signals.terminalQuickFix.sound', "Plays a sound when terminal Quick Fixes are available."),471...soundFeatureBase472},473'announcement': {474'description': localize('accessibility.signals.terminalQuickFix.announcement', "Announces when terminal Quick Fixes are available."),475...announcementFeatureBase476},477}478},479'accessibility.signals.terminalBell': {480...signalFeatureBase,481'description': localize('accessibility.signals.terminalBell', "Plays a signal - sound (audio cue) and/or announcement (alert) - when the terminal bell is ringing."),482'properties': {483'sound': {484'description': localize('accessibility.signals.terminalBell.sound', "Plays a sound when the terminal bell is ringing."),485...soundFeatureBase486},487'announcement': {488'description': localize('accessibility.signals.terminalBell.announcement', "Announces when the terminal bell is ringing."),489...announcementFeatureBase490},491}492},493'accessibility.signals.diffLineInserted': {494...defaultNoAnnouncement,495'description': localize('accessibility.signals.diffLineInserted', "Plays a sound / audio cue when the focus moves to an inserted line in Accessible Diff Viewer mode or to the next/previous change."),496'properties': {497'sound': {498'description': localize('accessibility.signals.sound', "Plays a sound when the focus moves to an inserted line in Accessible Diff Viewer mode or to the next/previous change."),499...soundFeatureBase500}501}502},503'accessibility.signals.diffLineModified': {504...defaultNoAnnouncement,505'description': localize('accessibility.signals.diffLineModified', "Plays a sound / audio cue when the focus moves to an modified line in Accessible Diff Viewer mode or to the next/previous change."),506'properties': {507'sound': {508'description': localize('accessibility.signals.diffLineModified.sound', "Plays a sound when the focus moves to a modified line in Accessible Diff Viewer mode or to the next/previous change."),509...soundFeatureBase510}511}512},513'accessibility.signals.diffLineDeleted': {514...defaultNoAnnouncement,515'description': localize('accessibility.signals.diffLineDeleted', "Plays a sound / audio cue when the focus moves to an deleted line in Accessible Diff Viewer mode or to the next/previous change."),516'properties': {517'sound': {518'description': localize('accessibility.signals.diffLineDeleted.sound', "Plays a sound when the focus moves to an deleted line in Accessible Diff Viewer mode or to the next/previous change."),519...soundFeatureBase520}521}522},523'accessibility.signals.chatEditModifiedFile': {524...defaultNoAnnouncement,525'description': localize('accessibility.signals.chatEditModifiedFile', "Plays a sound / audio cue when revealing a file with changes from chat edits"),526'properties': {527'sound': {528'description': localize('accessibility.signals.chatEditModifiedFile.sound', "Plays a sound when revealing a file with changes from chat edits"),529...soundFeatureBase530}531}532},533'accessibility.signals.notebookCellCompleted': {534...signalFeatureBase,535'description': localize('accessibility.signals.notebookCellCompleted', "Plays a signal - sound (audio cue) and/or announcement (alert) - when a notebook cell execution is successfully completed."),536'properties': {537'sound': {538'description': localize('accessibility.signals.notebookCellCompleted.sound', "Plays a sound when a notebook cell execution is successfully completed."),539...soundFeatureBase540},541'announcement': {542'description': localize('accessibility.signals.notebookCellCompleted.announcement', "Announces when a notebook cell execution is successfully completed."),543...announcementFeatureBase544},545}546},547'accessibility.signals.notebookCellFailed': {548...signalFeatureBase,549'description': localize('accessibility.signals.notebookCellFailed', "Plays a signal - sound (audio cue) and/or announcement (alert) - when a notebook cell execution fails."),550'properties': {551'sound': {552'description': localize('accessibility.signals.notebookCellFailed.sound', "Plays a sound when a notebook cell execution fails."),553...soundFeatureBase554},555'announcement': {556'description': localize('accessibility.signals.notebookCellFailed.announcement', "Announces when a notebook cell execution fails."),557...announcementFeatureBase558},559}560},561'accessibility.signals.progress': {562...signalFeatureBase,563'description': localize('accessibility.signals.progress', "Plays a signal - sound (audio cue) and/or announcement (alert) - on loop while progress is occurring."),564'properties': {565'sound': {566'description': localize('accessibility.signals.progress.sound', "Plays a sound on loop while progress is occurring."),567...soundFeatureBase568},569'announcement': {570'description': localize('accessibility.signals.progress.announcement', "Alerts on loop while progress is occurring."),571...announcementFeatureBase572},573},574},575'accessibility.signals.chatRequestSent': {576...signalFeatureBase,577'description': localize('accessibility.signals.chatRequestSent', "Plays a signal - sound (audio cue) and/or announcement (alert) - when a chat request is made."),578'properties': {579'sound': {580'description': localize('accessibility.signals.chatRequestSent.sound', "Plays a sound when a chat request is made."),581...soundFeatureBase582},583'announcement': {584'description': localize('accessibility.signals.chatRequestSent.announcement', "Announces when a chat request is made."),585...announcementFeatureBase586},587}588},589'accessibility.signals.chatResponseReceived': {590...defaultNoAnnouncement,591'description': localize('accessibility.signals.chatResponseReceived', "Plays a sound / audio cue when the response has been received."),592'properties': {593'sound': {594'description': localize('accessibility.signals.chatResponseReceived.sound', "Plays a sound on when the response has been received."),595...soundFeatureBase596},597}598},599'accessibility.signals.codeActionTriggered': {600...defaultNoAnnouncement,601'description': localize('accessibility.signals.codeActionTriggered', "Plays a sound / audio cue - when a code action has been triggered."),602'properties': {603'sound': {604'description': localize('accessibility.signals.codeActionTriggered.sound', "Plays a sound when a code action has been triggered."),605...soundFeatureBase606}607}608},609'accessibility.signals.codeActionApplied': {610...defaultNoAnnouncement,611'description': localize('accessibility.signals.codeActionApplied', "Plays a sound / audio cue when the code action has been applied."),612'properties': {613'sound': {614'description': localize('accessibility.signals.codeActionApplied.sound', "Plays a sound when the code action has been applied."),615...soundFeatureBase616},617}618},619'accessibility.signals.voiceRecordingStarted': {620...defaultNoAnnouncement,621'description': localize('accessibility.signals.voiceRecordingStarted', "Plays a sound / audio cue when the voice recording has started."),622'properties': {623'sound': {624'description': localize('accessibility.signals.voiceRecordingStarted.sound', "Plays a sound when the voice recording has started."),625...soundFeatureBase,626},627},628'default': {629'sound': 'on'630}631},632'accessibility.signals.voiceRecordingStopped': {633...defaultNoAnnouncement,634'description': localize('accessibility.signals.voiceRecordingStopped', "Plays a sound / audio cue when the voice recording has stopped."),635'properties': {636'sound': {637'description': localize('accessibility.signals.voiceRecordingStopped.sound', "Plays a sound when the voice recording has stopped."),638...soundFeatureBase,639default: 'off'640},641}642},643'accessibility.signals.clear': {644...signalFeatureBase,645'description': localize('accessibility.signals.clear', "Plays a signal - sound (audio cue) and/or announcement (alert) - when a feature is cleared (for example, the terminal, Debug Console, or Output channel)."),646'properties': {647'sound': {648'description': localize('accessibility.signals.clear.sound', "Plays a sound when a feature is cleared."),649...soundFeatureBase650},651'announcement': {652'description': localize('accessibility.signals.clear.announcement', "Announces when a feature is cleared."),653...announcementFeatureBase654},655},656},657'accessibility.signals.editsUndone': {658...signalFeatureBase,659'description': localize('accessibility.signals.editsUndone', "Plays a signal - sound (audio cue) and/or announcement (alert) - when edits have been undone."),660'properties': {661'sound': {662'description': localize('accessibility.signals.editsUndone.sound', "Plays a sound when edits have been undone."),663...soundFeatureBase664},665'announcement': {666'description': localize('accessibility.signals.editsUndone.announcement', "Announces when edits have been undone."),667...announcementFeatureBase668},669},670},671'accessibility.signals.editsKept': {672...signalFeatureBase,673'description': localize('accessibility.signals.editsKept', "Plays a signal - sound (audio cue) and/or announcement (alert) - when edits are kept."),674'properties': {675'sound': {676'description': localize('accessibility.signals.editsKept.sound', "Plays a sound when edits are kept."),677...soundFeatureBase678},679'announcement': {680'description': localize('accessibility.signals.editsKept.announcement', "Announces when edits are kept."),681...announcementFeatureBase682},683},684},685'accessibility.signals.save': {686'type': 'object',687'tags': ['accessibility'],688additionalProperties: false,689'markdownDescription': localize('accessibility.signals.save', "Plays a signal - sound (audio cue) and/or announcement (alert) - when a file is saved."),690'properties': {691'sound': {692'description': localize('accessibility.signals.save.sound', "Plays a sound when a file is saved."),693'type': 'string',694'enum': ['userGesture', 'always', 'never'],695'default': 'never',696'enumDescriptions': [697localize('accessibility.signals.save.sound.userGesture', "Plays the sound when a user explicitly saves a file."),698localize('accessibility.signals.save.sound.always', "Plays the sound whenever a file is saved, including auto save."),699localize('accessibility.signals.save.sound.never', "Never plays the sound.")700],701},702'announcement': {703'description': localize('accessibility.signals.save.announcement', "Announces when a file is saved."),704'type': 'string',705'enum': ['userGesture', 'always', 'never'],706'default': 'never',707'enumDescriptions': [708localize('accessibility.signals.save.announcement.userGesture', "Announces when a user explicitly saves a file."),709localize('accessibility.signals.save.announcement.always', "Announces whenever a file is saved, including auto save."),710localize('accessibility.signals.save.announcement.never', "Never plays the announcement.")711],712},713},714default: {715'sound': 'never',716'announcement': 'never'717}718},719'accessibility.signals.format': {720'type': 'object',721'tags': ['accessibility'],722additionalProperties: false,723'markdownDescription': localize('accessibility.signals.format', "Plays a signal - sound (audio cue) and/or announcement (alert) - when a file or notebook is formatted."),724'properties': {725'sound': {726'description': localize('accessibility.signals.format.sound', "Plays a sound when a file or notebook is formatted."),727'type': 'string',728'enum': ['userGesture', 'always', 'never'],729'default': 'never',730'enumDescriptions': [731localize('accessibility.signals.format.userGesture', "Plays the sound when a user explicitly formats a file."),732localize('accessibility.signals.format.always', "Plays the sound whenever a file is formatted, including if it is set to format on save, type, or, paste, or run of a cell."),733localize('accessibility.signals.format.never', "Never plays the sound.")734],735},736'announcement': {737'description': localize('accessibility.signals.format.announcement', "Announces when a file or notebook is formatted."),738'type': 'string',739'enum': ['userGesture', 'always', 'never'],740'default': 'never',741'enumDescriptions': [742localize('accessibility.signals.format.announcement.userGesture', "Announces when a user explicitly formats a file."),743localize('accessibility.signals.format.announcement.always', "Announces whenever a file is formatted, including if it is set to format on save, type, or, paste, or run of a cell."),744localize('accessibility.signals.format.announcement.never', "Never announces.")745],746},747},748default: {749'sound': 'never',750'announcement': 'never'751}752},753'accessibility.signals.chatUserActionRequired': {754...signalFeatureBase,755'markdownDescription': localize('accessibility.signals.chatUserActionRequired', "Plays a signal - sound (audio cue) and/or announcement (alert) - when user action is required in the chat."),756'properties': {757'sound': {758'description': localize('accessibility.signals.chatUserActionRequired.sound', "Plays a sound when user action is required in the chat."),759'type': 'string',760'enum': ['auto', 'on', 'off'],761'enumDescriptions': [762localize('sound.enabled.autoWindow', "Enable sound when a screen reader is attached."),763localize('sound.enabled.on', "Enable sound."),764localize('sound.enabled.off', "Disable sound.")765],766},767'announcement': {768'description': localize('accessibility.signals.chatUserActionRequired.announcement', "Announces when a user action is required in the chat - including information about the action and how to take it."),769...announcementFeatureBase770},771},772default: {773'sound': 'auto',774'announcement': 'auto'775},776tags: ['accessibility']777},778'accessibility.underlineLinks': {779'type': 'boolean',780'description': localize('accessibility.underlineLinks', "Controls whether links should be underlined in the workbench."),781'default': false,782},783'accessibility.debugWatchVariableAnnouncements': {784'type': 'boolean',785'description': localize('accessibility.debugWatchVariableAnnouncements', "Controls whether variable changes should be announced in the debug watch view."),786'default': true,787},788'accessibility.replEditor.readLastExecutionOutput': {789'type': 'boolean',790'description': localize('accessibility.replEditor.readLastExecutedOutput', "Controls whether the output from an execution in the native REPL will be announced."),791'default': true,792},793'accessibility.replEditor.autoFocusReplExecution': {794type: 'string',795enum: ['none', 'input', 'lastExecution'],796default: 'input',797description: localize('replEditor.autoFocusAppendedCell', "Control whether focus should automatically be sent to the REPL when code is executed."),798},799'accessibility.windowTitleOptimized': {800'type': 'boolean',801'default': true,802'markdownDescription': localize('accessibility.windowTitleOptimized', "Controls whether the {0} should be optimized for screen readers when in screen reader mode. When enabled, the window title will have {1} appended to the end.", '`#window.title#`', '`activeEditorState`')803},804'accessibility.openChatEditedFiles': {805'type': 'boolean',806'default': true,807'markdownDescription': localize('accessibility.openChatEditedFiles', "Controls whether files should be opened when the chat agent has applied edits to them.")808},809}810};811812export function registerAccessibilityConfiguration() {813const registry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);814registry.registerConfiguration(configuration);815816registry.registerConfiguration({817...workbenchConfigurationNodeBase,818properties: {819[AccessibilityWorkbenchSettingId.DimUnfocusedEnabled]: {820description: localize('dimUnfocusedEnabled', 'Whether to dim unfocused editors and terminals, which makes it more clear where typed input will go to. This works with the majority of editors with the notable exceptions of those that utilize iframes like notebooks and extension webview editors.'),821type: 'boolean',822default: false,823tags: ['accessibility'],824scope: ConfigurationScope.APPLICATION,825},826[AccessibilityWorkbenchSettingId.DimUnfocusedOpacity]: {827markdownDescription: localize('dimUnfocusedOpacity', 'The opacity fraction (0.2 to 1.0) to use for unfocused editors and terminals. This will only take effect when {0} is enabled.', `\`#${AccessibilityWorkbenchSettingId.DimUnfocusedEnabled}#\``),828type: 'number',829minimum: ViewDimUnfocusedOpacityProperties.Minimum,830maximum: ViewDimUnfocusedOpacityProperties.Maximum,831default: ViewDimUnfocusedOpacityProperties.Default,832tags: ['accessibility'],833scope: ConfigurationScope.APPLICATION,834},835[AccessibilityWorkbenchSettingId.HideAccessibleView]: {836description: localize('accessibility.hideAccessibleView', "Controls whether the Accessible View is hidden."),837type: 'boolean',838default: false,839tags: ['accessibility']840}841}842});843}844845export { AccessibilityVoiceSettingId };846847export const SpeechTimeoutDefault = 1200;848849export class DynamicSpeechAccessibilityConfiguration extends Disposable implements IWorkbenchContribution {850851static readonly ID = 'workbench.contrib.dynamicSpeechAccessibilityConfiguration';852853constructor(854@ISpeechService private readonly speechService: ISpeechService855) {856super();857858this._register(Event.runAndSubscribe(speechService.onDidChangeHasSpeechProvider, () => this.updateConfiguration()));859}860861private updateConfiguration(): void {862if (!this.speechService.hasSpeechProvider) {863return; // these settings require a speech provider864}865866const languages = this.getLanguages();867const languagesSorted = Object.keys(languages).sort((langA, langB) => {868return languages[langA].name.localeCompare(languages[langB].name);869});870871const registry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);872registry.registerConfiguration({873...accessibilityConfigurationNodeBase,874properties: {875[AccessibilityVoiceSettingId.SpeechTimeout]: {876'markdownDescription': localize('voice.speechTimeout', "The duration in milliseconds that voice speech recognition remains active after you stop speaking. For example in a chat session, the transcribed text is submitted automatically after the timeout is met. Set to `0` to disable this feature."),877'type': 'number',878'default': SpeechTimeoutDefault,879'minimum': 0,880'tags': ['accessibility']881},882[AccessibilityVoiceSettingId.IgnoreCodeBlocks]: {883'markdownDescription': localize('voice.ignoreCodeBlocks', "Whether to ignore code snippets in text-to-speech synthesis."),884'type': 'boolean',885'default': false,886'tags': ['accessibility']887},888[AccessibilityVoiceSettingId.SpeechLanguage]: {889'markdownDescription': localize('voice.speechLanguage', "The language that text-to-speech and speech-to-text should use. Select `auto` to use the configured display language if possible. Note that not all display languages maybe supported by speech recognition and synthesizers."),890'type': 'string',891'enum': languagesSorted,892'default': 'auto',893'tags': ['accessibility'],894'enumDescriptions': languagesSorted.map(key => languages[key].name),895'enumItemLabels': languagesSorted.map(key => languages[key].name)896},897[AccessibilityVoiceSettingId.AutoSynthesize]: {898'type': 'string',899'enum': ['on', 'off'],900'enumDescriptions': [901localize('accessibility.voice.autoSynthesize.on', "Enable the feature. When a screen reader is enabled, note that this will disable aria updates."),902localize('accessibility.voice.autoSynthesize.off', "Disable the feature."),903],904'markdownDescription': localize('autoSynthesize', "Whether a textual response should automatically be read out aloud when speech was used as input. For example in a chat session, a response is automatically synthesized when voice was used as chat request."),905'default': 'off',906'tags': ['accessibility']907}908}909});910}911912private getLanguages(): { [locale: string]: { name: string } } {913return {914['auto']: {915name: localize('speechLanguage.auto', "Auto (Use Display Language)")916},917...SPEECH_LANGUAGES918};919}920}921922Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMigration)923.registerConfigurationMigrations([{924key: 'audioCues.volume',925migrateFn: (value, accessor) => {926return [927['accessibility.signalOptions.volume', { value }],928['audioCues.volume', { value: undefined }]929];930}931}]);932933Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMigration)934.registerConfigurationMigrations([{935key: 'audioCues.debouncePositionChanges',936migrateFn: (value) => {937return [938['accessibility.signalOptions.debouncePositionChanges', { value }],939['audioCues.debouncePositionChanges', { value: undefined }]940];941}942}]);943944Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMigration)945.registerConfigurationMigrations([{946key: 'accessibility.signalOptions',947migrateFn: (value, accessor) => {948const delayGeneral = getDelaysFromConfig(accessor, 'general');949const delayError = getDelaysFromConfig(accessor, 'errorAtPosition');950const delayWarning = getDelaysFromConfig(accessor, 'warningAtPosition');951const volume = getVolumeFromConfig(accessor);952const debouncePositionChanges = getDebouncePositionChangesFromConfig(accessor);953const result: [key: string, { value: any }][] = [];954if (!!volume) {955result.push(['accessibility.signalOptions.volume', { value: volume }]);956}957if (!!delayGeneral) {958result.push(['accessibility.signalOptions.experimental.delays.general', { value: delayGeneral }]);959}960if (!!delayError) {961result.push(['accessibility.signalOptions.experimental.delays.errorAtPosition', { value: delayError }]);962}963if (!!delayWarning) {964result.push(['accessibility.signalOptions.experimental.delays.warningAtPosition', { value: delayWarning }]);965}966if (!!debouncePositionChanges) {967result.push(['accessibility.signalOptions.debouncePositionChanges', { value: debouncePositionChanges }]);968}969result.push(['accessibility.signalOptions', { value: undefined }]);970return result;971}972}]);973974975Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMigration)976.registerConfigurationMigrations([{977key: 'accessibility.signals.sounds.volume',978migrateFn: (value) => {979return [980['accessibility.signalOptions.volume', { value }],981['accessibility.signals.sounds.volume', { value: undefined }]982];983}984}]);985986Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMigration)987.registerConfigurationMigrations([{988key: 'accessibility.signals.debouncePositionChanges',989migrateFn: (value) => {990return [991['accessibility.signalOptions.debouncePositionChanges', { value }],992['accessibility.signals.debouncePositionChanges', { value: undefined }]993];994}995}]);996997function getDelaysFromConfig(accessor: (key: string) => any, type: 'general' | 'errorAtPosition' | 'warningAtPosition'): { announcement: number; sound: number } | undefined {998return accessor(`accessibility.signalOptions.experimental.delays.${type}`) || accessor('accessibility.signalOptions')?.['experimental.delays']?.[`${type}`] || accessor('accessibility.signalOptions')?.['delays']?.[`${type}`];999}10001001function getVolumeFromConfig(accessor: (key: string) => any): string | undefined {1002return accessor('accessibility.signalOptions.volume') || accessor('accessibility.signalOptions')?.volume || accessor('accessibility.signals.sounds.volume') || accessor('audioCues.volume');1003}10041005function getDebouncePositionChangesFromConfig(accessor: (key: string) => any): number | undefined {1006return accessor('accessibility.signalOptions.debouncePositionChanges') || accessor('accessibility.signalOptions')?.debouncePositionChanges || accessor('accessibility.signals.debouncePositionChanges') || accessor('audioCues.debouncePositionChanges');1007}10081009Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMigration)1010.registerConfigurationMigrations([{1011key: AccessibilityVoiceSettingId.AutoSynthesize,1012migrateFn: (value: boolean) => {1013let newValue: string | undefined;1014if (value === true) {1015newValue = 'on';1016} else if (value === false) {1017newValue = 'off';1018} else {1019return [];1020}1021return [1022[AccessibilityVoiceSettingId.AutoSynthesize, { value: newValue }],1023];1024}1025}]);10261027Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMigration)1028.registerConfigurationMigrations([{1029key: 'accessibility.signals.chatResponsePending',1030migrateFn: (value, accessor) => {1031return [1032['accessibility.signals.progress', { value }],1033['accessibility.signals.chatResponsePending', { value: undefined }],1034];1035}1036}]);10371038Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMigration)1039.registerConfigurationMigrations(AccessibilitySignal.allAccessibilitySignals.map<ConfigurationMigration | undefined>(item => item.legacySoundSettingsKey ? ({1040key: item.legacySoundSettingsKey,1041migrateFn: (sound, accessor) => {1042const configurationKeyValuePairs: ConfigurationKeyValuePairs = [];1043const legacyAnnouncementSettingsKey = item.legacyAnnouncementSettingsKey;1044let announcement: string | undefined;1045if (legacyAnnouncementSettingsKey) {1046announcement = accessor(legacyAnnouncementSettingsKey) ?? undefined;1047if (announcement !== undefined && typeof announcement !== 'string') {1048announcement = announcement ? 'auto' : 'off';1049}1050}1051configurationKeyValuePairs.push([`${item.legacySoundSettingsKey}`, { value: undefined }]);1052configurationKeyValuePairs.push([`${item.settingsKey}`, { value: announcement !== undefined ? { announcement, sound } : { sound } }]);1053return configurationKeyValuePairs;1054}1055}) : undefined).filter(isDefined));10561057Registry.as<IConfigurationMigrationRegistry>(WorkbenchExtensions.ConfigurationMigration)1058.registerConfigurationMigrations(AccessibilitySignal.allAccessibilitySignals.filter(i => !!i.legacyAnnouncementSettingsKey && !!i.legacySoundSettingsKey).map(item => ({1059key: item.legacyAnnouncementSettingsKey!,1060migrateFn: (announcement, accessor) => {1061const configurationKeyValuePairs: ConfigurationKeyValuePairs = [];1062const sound = accessor(item.settingsKey)?.sound || accessor(item.legacySoundSettingsKey!);1063if (announcement !== undefined && typeof announcement !== 'string') {1064announcement = announcement ? 'auto' : 'off';1065}1066configurationKeyValuePairs.push([`${item.settingsKey}`, { value: announcement !== undefined ? { announcement, sound } : { sound } }]);1067configurationKeyValuePairs.push([`${item.legacyAnnouncementSettingsKey}`, { value: undefined }]);1068configurationKeyValuePairs.push([`${item.legacySoundSettingsKey}`, { value: undefined }]);1069return configurationKeyValuePairs;1070}1071})));107210731074