term_windows.go raw

   1  // Copyright 2019 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  package term
   6  
   7  import (
   8  	"os"
   9  
  10  	"golang.org/x/sys/windows"
  11  )
  12  
  13  type state struct {
  14  	mode uint32
  15  }
  16  
  17  func isTerminal(fd int) bool {
  18  	var st uint32
  19  	err := windows.GetConsoleMode(windows.Handle(fd), &st)
  20  	return err == nil
  21  }
  22  
  23  // This is intended to be used on a console input handle.
  24  // See https://learn.microsoft.com/en-us/windows/console/setconsolemode
  25  func makeRaw(fd int) (*State, error) {
  26  	var st uint32
  27  	if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil {
  28  		return nil, err
  29  	}
  30  	raw := st &^ (windows.ENABLE_ECHO_INPUT | windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT)
  31  	raw |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT
  32  	if err := windows.SetConsoleMode(windows.Handle(fd), raw); err != nil {
  33  		return nil, err
  34  	}
  35  	return &State{state{st}}, nil
  36  }
  37  
  38  func getState(fd int) (*State, error) {
  39  	var st uint32
  40  	if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil {
  41  		return nil, err
  42  	}
  43  	return &State{state{st}}, nil
  44  }
  45  
  46  func restore(fd int, state *State) error {
  47  	return windows.SetConsoleMode(windows.Handle(fd), state.mode)
  48  }
  49  
  50  func getSize(fd int) (width, height int, err error) {
  51  	var info windows.ConsoleScreenBufferInfo
  52  	if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil {
  53  		return 0, 0, err
  54  	}
  55  	return int(info.Window.Right - info.Window.Left + 1), int(info.Window.Bottom - info.Window.Top + 1), nil
  56  }
  57  
  58  func readPassword(fd int) ([]byte, error) {
  59  	var st uint32
  60  	if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil {
  61  		return nil, err
  62  	}
  63  	old := st
  64  
  65  	st &^= (windows.ENABLE_ECHO_INPUT | windows.ENABLE_LINE_INPUT)
  66  	st |= (windows.ENABLE_PROCESSED_OUTPUT | windows.ENABLE_PROCESSED_INPUT)
  67  	if err := windows.SetConsoleMode(windows.Handle(fd), st); err != nil {
  68  		return nil, err
  69  	}
  70  
  71  	defer windows.SetConsoleMode(windows.Handle(fd), old)
  72  
  73  	var h windows.Handle
  74  	p, _ := windows.GetCurrentProcess()
  75  	if err := windows.DuplicateHandle(p, windows.Handle(fd), p, &h, 0, false, windows.DUPLICATE_SAME_ACCESS); err != nil {
  76  		return nil, err
  77  	}
  78  
  79  	f := os.NewFile(uintptr(h), "stdin")
  80  	defer f.Close()
  81  	return readPasswordLine(f)
  82  }
  83