Skip to content

Commit c12b1e7

Browse files
authored
Merge pull request #29 from crosbymichael/win
Updates for windows consoles
2 parents 4d8a41f + 7a61819 commit c12b1e7

File tree

1 file changed

+72
-36
lines changed

1 file changed

+72
-36
lines changed

console_windows.go

+72-36
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package console
1818

1919
import (
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

5069
type 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

5680
func (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

7096
func (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

77113
func (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

100136
func (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

116152
func (m *master) Read(b []byte) (int, error) {
117-
return m.f.Read(b)
153+
return os.Stdin.Read(b)
118154
}
119155

120156
func (m *master) Write(b []byte) (int, error) {
121-
return m.f.Write(b)
157+
return os.Stdout.Write(b)
122158
}
123159

124160
func (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

Comments
 (0)