Path: blob/main/vendor/github.com/chzyer/readline/term_windows.go
2875 views
// Copyright 2011 The Go Authors. All rights reserved.1// Use of this source code is governed by a BSD-style2// license that can be found in the LICENSE file.34// +build windows56// Package terminal provides support functions for dealing with terminals, as7// commonly found on UNIX systems.8//9// Putting a terminal into raw mode is the most common requirement:10//11// oldState, err := terminal.MakeRaw(0)12// if err != nil {13// panic(err)14// }15// defer terminal.Restore(0, oldState)16package readline1718import (19"io"20"syscall"21"unsafe"22)2324const (25enableLineInput = 226enableEchoInput = 427enableProcessedInput = 128enableWindowInput = 829enableMouseInput = 1630enableInsertMode = 3231enableQuickEditMode = 6432enableExtendedFlags = 12833enableAutoPosition = 25634enableProcessedOutput = 135enableWrapAtEolOutput = 236)3738var kernel32 = syscall.NewLazyDLL("kernel32.dll")3940var (41procGetConsoleMode = kernel32.NewProc("GetConsoleMode")42procSetConsoleMode = kernel32.NewProc("SetConsoleMode")43procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")44)4546type (47coord struct {48x short49y short50}51smallRect struct {52left short53top short54right short55bottom short56}57consoleScreenBufferInfo struct {58size coord59cursorPosition coord60attributes word61window smallRect62maximumWindowSize coord63}64)6566type State struct {67mode uint3268}6970// IsTerminal returns true if the given file descriptor is a terminal.71func IsTerminal(fd int) bool {72var st uint3273r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)74return r != 0 && e == 075}7677// MakeRaw put the terminal connected to the given file descriptor into raw78// mode and returns the previous state of the terminal so that it can be79// restored.80func MakeRaw(fd int) (*State, error) {81var st uint3282_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)83if e != 0 {84return nil, error(e)85}86raw := st &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput)87_, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(raw), 0)88if e != 0 {89return nil, error(e)90}91return &State{st}, nil92}9394// GetState returns the current state of a terminal which may be useful to95// restore the terminal after a signal.96func GetState(fd int) (*State, error) {97var st uint3298_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)99if e != 0 {100return nil, error(e)101}102return &State{st}, nil103}104105// Restore restores the terminal connected to the given file descriptor to a106// previous state.107func restoreTerm(fd int, state *State) error {108_, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0)109return err110}111112// GetSize returns the dimensions of the given terminal.113func GetSize(fd int) (width, height int, err error) {114var info consoleScreenBufferInfo115_, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0)116if e != 0 {117return 0, 0, error(e)118}119return int(info.size.x), int(info.size.y), nil120}121122// ReadPassword reads a line of input from a terminal without local echo. This123// is commonly used for inputting passwords and other sensitive data. The slice124// returned does not include the \n.125func ReadPassword(fd int) ([]byte, error) {126var st uint32127_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)128if e != 0 {129return nil, error(e)130}131old := st132133st &^= (enableEchoInput)134st |= (enableProcessedInput | enableLineInput | enableProcessedOutput)135_, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0)136if e != 0 {137return nil, error(e)138}139140defer func() {141syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0)142}()143144var buf [16]byte145var ret []byte146for {147n, err := syscall.Read(syscall.Handle(fd), buf[:])148if err != nil {149return nil, err150}151if n == 0 {152if len(ret) == 0 {153return nil, io.EOF154}155break156}157if buf[n-1] == '\n' {158n--159}160if n > 0 && buf[n-1] == '\r' {161n--162}163ret = append(ret, buf[:n]...)164if n < len(buf) {165break166}167}168169return ret, nil170}171172173