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.
7 // Package terminal provides support functions for dealing with terminals, as
8 // commonly found on UNIX systems.
10 // Putting a terminal into raw mode is the most common requirement:
12 // oldState, err := terminal.MakeRaw(0)
16 // defer terminal.Restore(0, oldState)
27 enableProcessedInput = 1
31 enableQuickEditMode = 64
32 enableExtendedFlags = 128
33 enableAutoPosition = 256
34 enableProcessedOutput = 1
35 enableWrapAtEolOutput = 2
38 var kernel32 = syscall.NewLazyDLL("kernel32.dll")
41 procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
42 procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
43 procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
60 consoleScreenBufferInfo struct {
65 maximumWindowSize coord
73 // IsTerminal returns true if the given file descriptor is a terminal.
74 func IsTerminal(fd int) bool {
76 r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
77 return r != 0 && e == 0
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
83 func MakeRaw(fd int) (*State, error) {
85 _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
89 raw := st &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput)
90 _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(raw), 0)
94 return &State{st}, nil
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) {
101 _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
105 return &State{st}, nil
108 // Restore restores the terminal connected to the given file descriptor to a
110 func Restore(fd int, state *State) error {
111 _, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0)
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)
120 return 0, 0, error(e)
122 return int(info.size.x), int(info.size.y), nil
125 // passwordReader is an io.Reader that reads from a specific Windows HANDLE.
126 type passwordReader int
128 func (r passwordReader) Read(buf []byte) (int, error) {
129 return syscall.Read(syscall.Handle(r), buf)
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) {
137 _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
143 st &^= (enableEchoInput)
144 st |= (enableProcessedInput | enableLineInput | enableProcessedOutput)
145 _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0)
151 syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0)
154 return readPasswordLine(passwordReader(fd))