OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / crypto / ssh / terminal / util_windows.go
1 // Copyright 2011 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 // +build windows
6
7 // Package terminal provides support functions for dealing with terminals, as
8 // commonly found on UNIX systems.
9 //
10 // Putting a terminal into raw mode is the most common requirement:
11 //
12 //      oldState, err := terminal.MakeRaw(0)
13 //      if err != nil {
14 //              panic(err)
15 //      }
16 //      defer terminal.Restore(0, oldState)
17 package terminal
18
19 import (
20         "syscall"
21         "unsafe"
22 )
23
24 const (
25         enableLineInput       = 2
26         enableEchoInput       = 4
27         enableProcessedInput  = 1
28         enableWindowInput     = 8
29         enableMouseInput      = 16
30         enableInsertMode      = 32
31         enableQuickEditMode   = 64
32         enableExtendedFlags   = 128
33         enableAutoPosition    = 256
34         enableProcessedOutput = 1
35         enableWrapAtEolOutput = 2
36 )
37
38 var kernel32 = syscall.NewLazyDLL("kernel32.dll")
39
40 var (
41         procGetConsoleMode             = kernel32.NewProc("GetConsoleMode")
42         procSetConsoleMode             = kernel32.NewProc("SetConsoleMode")
43         procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
44 )
45
46 type (
47         short int16
48         word  uint16
49
50         coord struct {
51                 x short
52                 y short
53         }
54         smallRect struct {
55                 left   short
56                 top    short
57                 right  short
58                 bottom short
59         }
60         consoleScreenBufferInfo struct {
61                 size              coord
62                 cursorPosition    coord
63                 attributes        word
64                 window            smallRect
65                 maximumWindowSize coord
66         }
67 )
68
69 type State struct {
70         mode uint32
71 }
72
73 // IsTerminal returns true if the given file descriptor is a terminal.
74 func IsTerminal(fd int) bool {
75         var st uint32
76         r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
77         return r != 0 && e == 0
78 }
79
80 // MakeRaw put the terminal connected to the given file descriptor into raw
81 // mode and returns the previous state of the terminal so that it can be
82 // restored.
83 func MakeRaw(fd int) (*State, error) {
84         var st uint32
85         _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
86         if e != 0 {
87                 return nil, error(e)
88         }
89         raw := st &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput)
90         _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(raw), 0)
91         if e != 0 {
92                 return nil, error(e)
93         }
94         return &State{st}, nil
95 }
96
97 // GetState returns the current state of a terminal which may be useful to
98 // restore the terminal after a signal.
99 func GetState(fd int) (*State, error) {
100         var st uint32
101         _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
102         if e != 0 {
103                 return nil, error(e)
104         }
105         return &State{st}, nil
106 }
107
108 // Restore restores the terminal connected to the given file descriptor to a
109 // previous state.
110 func Restore(fd int, state *State) error {
111         _, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0)
112         return err
113 }
114
115 // GetSize returns the dimensions of the given terminal.
116 func GetSize(fd int) (width, height int, err error) {
117         var info consoleScreenBufferInfo
118         _, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0)
119         if e != 0 {
120                 return 0, 0, error(e)
121         }
122         return int(info.size.x), int(info.size.y), nil
123 }
124
125 // passwordReader is an io.Reader that reads from a specific Windows HANDLE.
126 type passwordReader int
127
128 func (r passwordReader) Read(buf []byte) (int, error) {
129         return syscall.Read(syscall.Handle(r), buf)
130 }
131
132 // ReadPassword reads a line of input from a terminal without local echo.  This
133 // is commonly used for inputting passwords and other sensitive data. The slice
134 // returned does not include the \n.
135 func ReadPassword(fd int) ([]byte, error) {
136         var st uint32
137         _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
138         if e != 0 {
139                 return nil, error(e)
140         }
141         old := st
142
143         st &^= (enableEchoInput)
144         st |= (enableProcessedInput | enableLineInput | enableProcessedOutput)
145         _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0)
146         if e != 0 {
147                 return nil, error(e)
148         }
149
150         defer func() {
151                 syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0)
152         }()
153
154         return readPasswordLine(passwordReader(fd))
155 }