1717package console
1818
1919import (
20- "fmt"
2120 "os"
2221
2322 "github.com/pkg/errors"
@@ -29,90 +28,55 @@ var (
2928 ErrNotImplemented = errors .New ("not implemented" )
3029)
3130
32- func (m * master ) initStdios () {
33- m .in = windows .Handle (os .Stdin .Fd ())
34- if err := windows .GetConsoleMode (m .in , & m .inMode ); err == nil {
35- // Validate that windows.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it.
36- if err = windows .SetConsoleMode (m .in , m .inMode | windows .ENABLE_VIRTUAL_TERMINAL_INPUT ); err == nil {
37- vtInputSupported = true
38- }
39- // Unconditionally set the console mode back even on failure because SetConsoleMode
40- // remembers invalid bits on input handles.
41- windows .SetConsoleMode (m .in , m .inMode )
42- } else {
43- fmt .Printf ("failed to get console mode for stdin: %v\n " , err )
44- }
45-
46- m .out = windows .Handle (os .Stdout .Fd ())
47- if err := windows .GetConsoleMode (m .out , & m .outMode ); err == nil {
48- if err := windows .SetConsoleMode (m .out , m .outMode | windows .ENABLE_VIRTUAL_TERMINAL_PROCESSING ); err == nil {
49- m .outMode |= windows .ENABLE_VIRTUAL_TERMINAL_PROCESSING
31+ func (m * master ) init () {
32+ m .h = windows .Handle (m .f .Fd ())
33+ if err := windows .GetConsoleMode (m .h , & m .mode ); err == nil {
34+ if m .f == os .Stdin {
35+ // Validate that windows.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it.
36+ if err = windows .SetConsoleMode (m .h , m .mode | windows .ENABLE_VIRTUAL_TERMINAL_INPUT ); err == nil {
37+ vtInputSupported = true
38+ }
39+ // Unconditionally set the console mode back even on failure because SetConsoleMode
40+ // remembers invalid bits on input handles.
41+ windows .SetConsoleMode (m .h , m .mode )
42+ } else if err := windows .SetConsoleMode (m .h , m .mode | windows .ENABLE_VIRTUAL_TERMINAL_PROCESSING ); err == nil {
43+ m .mode |= windows .ENABLE_VIRTUAL_TERMINAL_PROCESSING
5044 } else {
51- windows .SetConsoleMode (m .out , m .outMode )
45+ windows .SetConsoleMode (m .h , m .mode )
5246 }
53- } else {
54- fmt .Printf ("failed to get console mode for stdout: %v\n " , err )
55- }
56-
57- m .err = windows .Handle (os .Stderr .Fd ())
58- if err := windows .GetConsoleMode (m .err , & m .errMode ); err == nil {
59- if err := windows .SetConsoleMode (m .err , m .errMode | windows .ENABLE_VIRTUAL_TERMINAL_PROCESSING ); err == nil {
60- m .errMode |= windows .ENABLE_VIRTUAL_TERMINAL_PROCESSING
61- } else {
62- windows .SetConsoleMode (m .err , m .errMode )
63- }
64- } else {
65- fmt .Printf ("failed to get console mode for stderr: %v\n " , err )
6647 }
6748}
6849
6950type master struct {
70- in windows.Handle
71- inMode uint32
72-
73- out windows.Handle
74- outMode uint32
75-
76- err windows.Handle
77- errMode uint32
51+ h windows.Handle
52+ mode uint32
53+ f * os.File
7854}
7955
8056func (m * master ) SetRaw () error {
81- if err := makeInputRaw (m .in , m .inMode ); err != nil {
82- return err
57+ if m .f == os .Stdin {
58+ if err := makeInputRaw (m .h , m .mode ); err != nil {
59+ return err
60+ }
61+ } else {
62+ // Set StdOut and StdErr to raw mode, we ignore failures since
63+ // windows.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this version of
64+ // Windows.
65+ windows .SetConsoleMode (m .h , m .mode | windows .DISABLE_NEWLINE_AUTO_RETURN )
8366 }
84-
85- // Set StdOut and StdErr to raw mode, we ignore failures since
86- // windows.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this version of
87- // Windows.
88-
89- windows .SetConsoleMode (m .out , m .outMode | windows .DISABLE_NEWLINE_AUTO_RETURN )
90-
91- windows .SetConsoleMode (m .err , m .errMode | windows .DISABLE_NEWLINE_AUTO_RETURN )
92-
9367 return nil
9468}
9569
9670func (m * master ) Reset () error {
97- for _ , s := range []struct {
98- fd windows.Handle
99- mode uint32
100- }{
101- {m .in , m .inMode },
102- {m .out , m .outMode },
103- {m .err , m .errMode },
104- } {
105- if err := windows .SetConsoleMode (s .fd , s .mode ); err != nil {
106- return errors .Wrap (err , "unable to restore console mode" )
107- }
71+ if err := windows .SetConsoleMode (m .h , m .mode ); err != nil {
72+ return errors .Wrap (err , "unable to restore console mode" )
10873 }
109-
11074 return nil
11175}
11276
11377func (m * master ) Size () (WinSize , error ) {
11478 var info windows.ConsoleScreenBufferInfo
115- err := windows .GetConsoleScreenBufferInfo (m .out , & info )
79+ err := windows .GetConsoleScreenBufferInfo (m .h , & info )
11680 if err != nil {
11781 return WinSize {}, errors .Wrap (err , "unable to get console info" )
11882 }
@@ -134,11 +98,11 @@ func (m *master) ResizeFrom(c Console) error {
13498}
13599
136100func (m * master ) DisableEcho () error {
137- mode := m .inMode &^ windows .ENABLE_ECHO_INPUT
101+ mode := m .mode &^ windows .ENABLE_ECHO_INPUT
138102 mode |= windows .ENABLE_PROCESSED_INPUT
139103 mode |= windows .ENABLE_LINE_INPUT
140104
141- if err := windows .SetConsoleMode (m .in , mode ); err != nil {
105+ if err := windows .SetConsoleMode (m .h , mode ); err != nil {
142106 return errors .Wrap (err , "unable to set console to disable echo" )
143107 }
144108
@@ -150,15 +114,15 @@ func (m *master) Close() error {
150114}
151115
152116func (m * master ) Read (b []byte ) (int , error ) {
153- panic ( "not implemented on windows" )
117+ return m . f . Read ( b )
154118}
155119
156120func (m * master ) Write (b []byte ) (int , error ) {
157- panic ( "not implemented on windows" )
121+ return m . f . Write ( b )
158122}
159123
160124func (m * master ) Fd () uintptr {
161- return uintptr (m .in )
125+ return uintptr (m .h )
162126}
163127
164128// on windows, console can only be made from os.Std{in,out,err}, hence there
@@ -210,7 +174,7 @@ func newMaster(f *os.File) (Console, error) {
210174 if f != os .Stdin && f != os .Stdout && f != os .Stderr {
211175 return nil , errors .New ("creating a console from a file is not supported on windows" )
212176 }
213- m := & master {}
214- m .initStdios ()
177+ m := & master {f : f }
178+ m .init ()
215179 return m , nil
216180}
0 commit comments