diff --git a/term/term.go b/term/term.go index d21c73f..b7a5d18 100644 --- a/term/term.go +++ b/term/term.go @@ -30,7 +30,7 @@ func StdStreams() (stdOut io.Writer, stdErr io.Writer, stdIn io.ReadCloser) { return os.Stdout, os.Stderr, os.Stdin } -func GetHandleInfo(in interface{}) (uintptr, bool) { +func GetFdInfo(in interface{}) (uintptr, bool) { var inFd uintptr var isTerminalIn bool if file, ok := in.(*os.File); ok { diff --git a/term/term_windows.go b/term/term_windows.go index 711f744..7135728 100644 --- a/term/term_windows.go +++ b/term/term_windows.go @@ -107,8 +107,8 @@ func MakeRaw(fd uintptr) (*State, error) { return state, nil } -// GetHandleInfo returns file descriptor and bool indicating whether the file is a terminal -func GetHandleInfo(in interface{}) (uintptr, bool) { +// GetFdInfo returns file descriptor and bool indicating whether the file is a terminal +func GetFdInfo(in interface{}) (uintptr, bool) { return winconsole.GetHandleInfo(in) } diff --git a/term/winconsole/console_windows.go b/term/winconsole/console_windows.go index 8121aee..2d0421f 100644 --- a/term/winconsole/console_windows.go +++ b/term/winconsole/console_windows.go @@ -83,11 +83,6 @@ const ( ANSI_MAX_CMD_LENGTH = 256 - // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683231(v=vs.85).aspx - STD_INPUT_HANDLE = -10 - STD_OUTPUT_HANDLE = -11 - STD_ERROR_HANDLE = -12 - MAX_INPUT_BUFFER = 1024 DEFAULT_WIDTH = 80 DEFAULT_HEIGHT = 24 @@ -212,7 +207,10 @@ func StdStreams() (stdOut io.Writer, stdErr io.Writer, stdIn io.ReadCloser) { } // Save current screen buffer info - handle, _ := syscall.GetStdHandle(STD_OUTPUT_HANDLE) + handle, err := syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE) + if nil != err { + panic("This should never happen as it is predefined handle.") + } screenBufferInfo, err := GetConsoleScreenBufferInfo(uintptr(handle)) if err == nil { handler.screenBufferInfo = screenBufferInfo @@ -225,26 +223,36 @@ func StdStreams() (stdOut io.Writer, stdErr io.Writer, stdIn io.ReadCloser) { wrappedWriter: os.Stdout, emulator: handler, command: make([]byte, 0, ANSI_MAX_CMD_LENGTH), + fd: uintptr(handle), } } else { stdOut = os.Stdout } if IsTerminal(os.Stderr.Fd()) { + handle, err := syscall.GetStdHandle(syscall.STD_ERROR_HANDLE) + if nil != err { + panic("This should never happen as it is predefined handle.") + } stdErr = &terminalWriter{ wrappedWriter: os.Stderr, emulator: handler, command: make([]byte, 0, ANSI_MAX_CMD_LENGTH), + fd: uintptr(handle), } } else { stdErr = os.Stderr - } if IsTerminal(os.Stdin.Fd()) { + handle, err := syscall.GetStdHandle(syscall.STD_INPUT_HANDLE) + if nil != err { + panic("This should never happen as it is predefined handle.") + } stdIn = &terminalReader{ wrappedReader: os.Stdin, emulator: handler, command: make([]byte, 0, ANSI_MAX_CMD_LENGTH), + fd: uintptr(handle), } } else { stdIn = os.Stdin @@ -626,7 +634,7 @@ func getWindowsTextAttributeForAnsiValue(originalFlag WORD, defaultValue WORD, a } // HandleOutputCommand interpretes the Ansi commands and then makes appropriate Win32 calls -func (term *WindowsTerminal) HandleOutputCommand(command []byte) (n int, err error) { +func (term *WindowsTerminal) HandleOutputCommand(fd uintptr, command []byte) (n int, err error) { // console settings changes need to happen in atomic way term.outMutex.Lock() defer term.outMutex.Unlock() @@ -636,7 +644,7 @@ func (term *WindowsTerminal) HandleOutputCommand(command []byte) (n int, err err parsedCommand := parseAnsiCommand(command) // use appropriate handle - handle, _ := syscall.GetStdHandle(STD_OUTPUT_HANDLE) + handle := syscall.Handle(fd) switch parsedCommand.Command { case "m": @@ -891,7 +899,7 @@ func (term *WindowsTerminal) HandleOutputCommand(command []byte) (n int, err err } // WriteChars writes the bytes to given writer. -func (term *WindowsTerminal) WriteChars(w io.Writer, p []byte) (n int, err error) { +func (term *WindowsTerminal) WriteChars(fd uintptr, w io.Writer, p []byte) (n int, err error) { return w.Write(p) } @@ -1027,8 +1035,8 @@ func mapKeystokeToTerminalString(keyEvent *KEY_EVENT_RECORD, escapeSequence []by // getAvailableInputEvents polls the console for availble events // The function does not return until at least one input record has been read. -func getAvailableInputEvents() (inputEvents []INPUT_RECORD, err error) { - handle, _ := syscall.GetStdHandle(STD_INPUT_HANDLE) +func getAvailableInputEvents(fd uintptr) (inputEvents []INPUT_RECORD, err error) { + handle := syscall.Handle(fd) if nil != err { return nil, err } @@ -1064,7 +1072,7 @@ func getTranslatedKeyCodes(inputEvents []INPUT_RECORD, escapeSequence []byte) st } // ReadChars reads the characters from the given reader -func (term *WindowsTerminal) ReadChars(w io.Reader, p []byte) (n int, err error) { +func (term *WindowsTerminal) ReadChars(fd uintptr, w io.Reader, p []byte) (n int, err error) { n = 0 for n < len(p) { select { @@ -1076,7 +1084,7 @@ func (term *WindowsTerminal) ReadChars(w io.Reader, p []byte) (n int, err error) if n > 0 { return n, nil } - inputEvents, _ := getAvailableInputEvents() + inputEvents, _ := getAvailableInputEvents(fd) if inputEvents != nil { if len(inputEvents) == 0 && nil != err { return n, err @@ -1094,7 +1102,7 @@ func (term *WindowsTerminal) ReadChars(w io.Reader, p []byte) (n int, err error) } // HandleInputSequence interprets the input sequence command -func (term *WindowsTerminal) HandleInputSequence(command []byte) (n int, err error) { +func (term *WindowsTerminal) HandleInputSequence(fd uintptr, command []byte) (n int, err error) { return 0, nil } diff --git a/term/winconsole/term_emulator.go b/term/winconsole/term_emulator.go index 13bcde8..2678aab 100644 --- a/term/winconsole/term_emulator.go +++ b/term/winconsole/term_emulator.go @@ -27,10 +27,10 @@ const ( // Interface that implements terminal handling type terminalEmulator interface { - HandleOutputCommand(command []byte) (n int, err error) - HandleInputSequence(command []byte) (n int, err error) - WriteChars(w io.Writer, p []byte) (n int, err error) - ReadChars(w io.Reader, p []byte) (n int, err error) + HandleOutputCommand(fd uintptr, command []byte) (n int, err error) + HandleInputSequence(fd uintptr, command []byte) (n int, err error) + WriteChars(fd uintptr, w io.Writer, p []byte) (n int, err error) + ReadChars(fd uintptr, w io.Reader, p []byte) (n int, err error) } type terminalWriter struct { @@ -38,6 +38,7 @@ type terminalWriter struct { emulator terminalEmulator command []byte inSequence bool + fd uintptr } type terminalReader struct { @@ -45,6 +46,7 @@ type terminalReader struct { emulator terminalEmulator command []byte inSequence bool + fd uintptr } // http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html @@ -91,7 +93,7 @@ func (tw *terminalWriter) Write(p []byte) (n int, err error) { if !isXtermOscSequence(tw.command, p[current]) { // found the last command character. // Now we have a complete command. - nchar, err := tw.emulator.HandleOutputCommand(tw.command) + nchar, err := tw.emulator.HandleOutputCommand(tw.fd, tw.command) totalWritten += nchar if err != nil { return totalWritten, err @@ -110,7 +112,7 @@ func (tw *terminalWriter) Write(p []byte) (n int, err error) { tw.inSequence = true // indicates end of "normal sequence", write whatever you have so far if len(p[start:current]) > 0 { - nw, err := tw.emulator.WriteChars(tw.wrappedWriter, p[start:current]) + nw, err := tw.emulator.WriteChars(tw.fd, tw.wrappedWriter, p[start:current]) totalWritten += nw if err != nil { return totalWritten, err @@ -126,7 +128,7 @@ func (tw *terminalWriter) Write(p []byte) (n int, err error) { if !tw.inSequence { // assumption is that we can't be inside sequence and therefore command should be empty if len(p[start:]) > 0 { - nw, err := tw.emulator.WriteChars(tw.wrappedWriter, p[start:]) + nw, err := tw.emulator.WriteChars(tw.fd, tw.wrappedWriter, p[start:]) totalWritten += nw if err != nil { return totalWritten, err @@ -148,7 +150,7 @@ func (tr *terminalReader) Read(p []byte) (n int, err error) { if nil == tr.emulator { return tr.readFromWrappedReader(p) } - return tr.emulator.ReadChars(tr.wrappedReader, p) + return tr.emulator.ReadChars(tr.fd, tr.wrappedReader, p) } // Close the underlying stream diff --git a/term/winconsole/term_emulator_test.go b/term/winconsole/term_emulator_test.go index 7017d42..65de5a7 100644 --- a/term/winconsole/term_emulator_test.go +++ b/term/winconsole/term_emulator_test.go @@ -71,21 +71,21 @@ func (mt *mockTerminal) record(operation int, data []byte) { mt.OutputCommandSequence = append(mt.OutputCommandSequence, op) } -func (mt *mockTerminal) HandleOutputCommand(command []byte) (n int, err error) { +func (mt *mockTerminal) HandleOutputCommand(fd uintptr, command []byte) (n int, err error) { mt.record(COMMAND_OPERATION, command) return len(command), nil } -func (mt *mockTerminal) HandleInputSequence(command []byte) (n int, err error) { +func (mt *mockTerminal) HandleInputSequence(fd uintptr, command []byte) (n int, err error) { return 0, nil } -func (mt *mockTerminal) WriteChars(w io.Writer, p []byte) (n int, err error) { +func (mt *mockTerminal) WriteChars(fd uintptr, w io.Writer, p []byte) (n int, err error) { mt.record(WRITE_OPERATION, p) return len(p), nil } -func (mt *mockTerminal) ReadChars(w io.Reader, p []byte) (n int, err error) { +func (mt *mockTerminal) ReadChars(fd uintptr, w io.Reader, p []byte) (n int, err error) { return len(p), nil }