Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions cli/azd/pkg/ux/internal/console_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

//go:build !windows

package internal

import "os"

// disableVirtualTerminalInput is a no-op on non-Windows platforms.
func disableVirtualTerminalInput(_ *os.File) error {
return nil
}
43 changes: 43 additions & 0 deletions cli/azd/pkg/ux/internal/console_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

//go:build windows

package internal

import (
"os"

"golang.org/x/sys/windows"
)

const enableVirtualTerminalInput uint32 = 0x0200

// disableVirtualTerminalInput clears the ENABLE_VIRTUAL_TERMINAL_INPUT
// console mode flag so that Windows delivers native virtual-key codes
// (KEY_EVENT_RECORD with wVirtualKeyCode) instead of ANSI escape
// sequences for arrow keys and other special keys.
//
// The survey library's Windows RuneReader expects native VK codes
// (it checks unicodeChar == 0, then switches on wVirtualKeyCode).
// When ENABLE_VIRTUAL_TERMINAL_INPUT is set — as it is by default in
// Windows Terminal, PowerShell 7, VS Code, and Ghostty — the console
// emits ESC [ A / ESC [ B / etc. instead, which leak through as
// literal characters.
//
// This function is called after SetTermMode() and its effect is
// reversed when RestoreTermMode() restores the original console mode.
func disableVirtualTerminalInput(f *os.File) error {
h := windows.Handle(f.Fd())

var mode uint32
if err := windows.GetConsoleMode(h, &mode); err != nil {
return err
}

if mode&enableVirtualTerminalInput == 0 {
return nil // VTI not set, nothing to do
}

return windows.SetConsoleMode(h, mode&^enableVirtualTerminalInput)
}
11 changes: 11 additions & 0 deletions cli/azd/pkg/ux/internal/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@ func (i *Input) ReadInput(ctx context.Context, config *InputConfig, handler KeyP
errChan <- err
return
}

// On Windows, clear ENABLE_VIRTUAL_TERMINAL_INPUT so the
// console delivers native virtual-key codes instead of ANSI
// escape sequences. The survey library's RuneReader expects
// VK codes for arrow key dispatch. RestoreTermMode() will
// restore the original console mode when input completes.
if err := disableVirtualTerminalInput(os.Stdin); err != nil {
// Non-fatal: worst case is the pre-existing ANSI leak.
_ = err
}

defer func() {
if err := rr.RestoreTermMode(); err != nil {
log.Printf("Error restoring terminal mode: %v\n", err)
Expand Down
Loading