Path: blob/main/src/vs/workbench/contrib/inlineChat/electron-browser/inlineChatActions.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*--------------------------------------------------------------------------------------------*/4import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js';5import { ICodeEditor } from '../../../../editor/browser/editorBrowser.js';6import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';7import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';8import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';9import { InlineChatController } from '../browser/inlineChatController.js';10import { AbstractInline1ChatAction, setHoldForSpeech } from '../browser/inlineChatActions.js';11import { disposableTimeout } from '../../../../base/common/async.js';12import { EditorContextKeys } from '../../../../editor/common/editorContextKeys.js';13import { ICommandService } from '../../../../platform/commands/common/commands.js';14import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js';15import { StartVoiceChatAction, StopListeningAction, VOICE_KEY_HOLD_THRESHOLD } from '../../chat/electron-browser/actions/voiceChatActions.js';16import { IChatExecuteActionContext } from '../../chat/browser/actions/chatExecuteActions.js';17import { CTX_INLINE_CHAT_VISIBLE, InlineChatConfigKeys } from '../common/inlineChat.js';18import { HasSpeechProvider, ISpeechService } from '../../speech/common/speechService.js';19import { localize2 } from '../../../../nls.js';20import { Action2 } from '../../../../platform/actions/common/actions.js';21import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';22import { EditorAction2 } from '../../../../editor/browser/editorExtensions.js';2324export class HoldToSpeak extends EditorAction2 {2526constructor() {27super({28id: 'inlineChat.holdForSpeech',29category: AbstractInline1ChatAction.category,30precondition: ContextKeyExpr.and(HasSpeechProvider, CTX_INLINE_CHAT_VISIBLE),31title: localize2('holdForSpeech', "Hold for Speech"),32keybinding: {33when: EditorContextKeys.textInputFocus,34weight: KeybindingWeight.WorkbenchContrib,35primary: KeyMod.CtrlCmd | KeyCode.KeyI,36},37});38}3940override runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ..._args: any[]) {41const ctrl = InlineChatController.get(editor);42if (ctrl) {43holdForSpeech(accessor, ctrl, this);44}45}46}4748function holdForSpeech(accessor: ServicesAccessor, ctrl: InlineChatController, action: Action2): void {4950const configService = accessor.get(IConfigurationService);51const speechService = accessor.get(ISpeechService);52const keybindingService = accessor.get(IKeybindingService);53const commandService = accessor.get(ICommandService);5455// enabled or possible?56if (!configService.getValue<boolean>(InlineChatConfigKeys.HoldToSpeech || !speechService.hasSpeechProvider)) {57return;58}5960const holdMode = keybindingService.enableKeybindingHoldMode(action.desc.id);61if (!holdMode) {62return;63}64let listening = false;65const handle = disposableTimeout(() => {66// start VOICE input67commandService.executeCommand(StartVoiceChatAction.ID, { voice: { disableTimeout: true } } satisfies IChatExecuteActionContext);68listening = true;69}, VOICE_KEY_HOLD_THRESHOLD);7071holdMode.finally(() => {72if (listening) {73commandService.executeCommand(StopListeningAction.ID).finally(() => {74ctrl.widget.chatWidget.acceptInput();75});76}77handle.dispose();78});79}8081// make this accessible to the chat actions from the browser layer82setHoldForSpeech(holdForSpeech);838485