1717package console
1818
1919import (
20+ "fmt"
2021 "os"
2122
2223 "github.com/pkg/errors"
@@ -28,55 +29,90 @@ var (
2829 ErrNotImplemented = errors .New ("not implemented" )
2930)
3031
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
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
4450 } else {
45- windows .SetConsoleMode (m .h , m .mode )
51+ windows .SetConsoleMode (m .out , m .outMode )
4652 }
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 )
4766 }
4867}
4968
5069type master struct {
51- h windows.Handle
52- mode uint32
53- f * os.File
70+ in windows.Handle
71+ inMode uint32
72+
73+ out windows.Handle
74+ outMode uint32
75+
76+ err windows.Handle
77+ errMode uint32
5478}
5579
5680func (m * master ) SetRaw () error {
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 )
81+ if err := makeInputRaw (m .in , m .inMode ); err != nil {
82+ return err
6683 }
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+
6793 return nil
6894}
6995
7096func (m * master ) Reset () error {
71- if err := windows .SetConsoleMode (m .h , m .mode ); err != nil {
72- return errors .Wrap (err , "unable to restore console mode" )
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+ }
73108 }
109+
74110 return nil
75111}
76112
77113func (m * master ) Size () (WinSize , error ) {
78114 var info windows.ConsoleScreenBufferInfo
79- err := windows .GetConsoleScreenBufferInfo (m .h , & info )
115+ err := windows .GetConsoleScreenBufferInfo (m .out , & info )
80116 if err != nil {
81117 return WinSize {}, errors .Wrap (err , "unable to get console info" )
82118 }
@@ -98,11 +134,11 @@ func (m *master) ResizeFrom(c Console) error {
98134}
99135
100136func (m * master ) DisableEcho () error {
101- mode := m .mode &^ windows .ENABLE_ECHO_INPUT
137+ mode := m .inMode &^ windows .ENABLE_ECHO_INPUT
102138 mode |= windows .ENABLE_PROCESSED_INPUT
103139 mode |= windows .ENABLE_LINE_INPUT
104140
105- if err := windows .SetConsoleMode (m .h , mode ); err != nil {
141+ if err := windows .SetConsoleMode (m .in , mode ); err != nil {
106142 return errors .Wrap (err , "unable to set console to disable echo" )
107143 }
108144
@@ -114,15 +150,15 @@ func (m *master) Close() error {
114150}
115151
116152func (m * master ) Read (b []byte ) (int , error ) {
117- return m . f .Read (b )
153+ return os . Stdin .Read (b )
118154}
119155
120156func (m * master ) Write (b []byte ) (int , error ) {
121- return m . f .Write (b )
157+ return os . Stdout .Write (b )
122158}
123159
124160func (m * master ) Fd () uintptr {
125- return uintptr (m .h )
161+ return uintptr (m .in )
126162}
127163
128164// on windows, console can only be made from os.Std{in,out,err}, hence there
@@ -174,7 +210,7 @@ func newMaster(f *os.File) (Console, error) {
174210 if f != os .Stdin && f != os .Stdout && f != os .Stderr {
175211 return nil , errors .New ("creating a console from a file is not supported on windows" )
176212 }
177- m := & master {f : f }
178- m .init ()
213+ m := & master {}
214+ m .initStdios ()
179215 return m , nil
180216}
0 commit comments