github.com/lmars/docker@v1.6.0-rc2/pkg/term/winconsole/console_windows.go (about)

     1  // +build windows
     2  
     3  package winconsole
     4  
     5  import (
     6  	"bytes"
     7  	"fmt"
     8  	"io"
     9  	"os"
    10  	"strconv"
    11  	"strings"
    12  	"sync"
    13  	"syscall"
    14  	"unsafe"
    15  )
    16  
    17  const (
    18  	// Consts for Get/SetConsoleMode function
    19  	// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx
    20  	ENABLE_ECHO_INPUT      = 0x0004
    21  	ENABLE_INSERT_MODE     = 0x0020
    22  	ENABLE_LINE_INPUT      = 0x0002
    23  	ENABLE_MOUSE_INPUT     = 0x0010
    24  	ENABLE_PROCESSED_INPUT = 0x0001
    25  	ENABLE_QUICK_EDIT_MODE = 0x0040
    26  	ENABLE_WINDOW_INPUT    = 0x0008
    27  	// If parameter is a screen buffer handle, additional values
    28  	ENABLE_PROCESSED_OUTPUT   = 0x0001
    29  	ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
    30  
    31  	//http://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes
    32  	FOREGROUND_BLUE       = 1
    33  	FOREGROUND_GREEN      = 2
    34  	FOREGROUND_RED        = 4
    35  	FOREGROUND_INTENSITY  = 8
    36  	FOREGROUND_MASK_SET   = 0x000F
    37  	FOREGROUND_MASK_UNSET = 0xFFF0
    38  
    39  	BACKGROUND_BLUE       = 16
    40  	BACKGROUND_GREEN      = 32
    41  	BACKGROUND_RED        = 64
    42  	BACKGROUND_INTENSITY  = 128
    43  	BACKGROUND_MASK_SET   = 0x00F0
    44  	BACKGROUND_MASK_UNSET = 0xFF0F
    45  
    46  	COMMON_LVB_REVERSE_VIDEO = 0x4000
    47  	COMMON_LVB_UNDERSCORE    = 0x8000
    48  
    49  	// http://man7.org/linux/man-pages/man4/console_codes.4.html
    50  	// ECMA-48 Set Graphics Rendition
    51  	ANSI_ATTR_RESET     = 0
    52  	ANSI_ATTR_BOLD      = 1
    53  	ANSI_ATTR_DIM       = 2
    54  	ANSI_ATTR_UNDERLINE = 4
    55  	ANSI_ATTR_BLINK     = 5
    56  	ANSI_ATTR_REVERSE   = 7
    57  	ANSI_ATTR_INVISIBLE = 8
    58  
    59  	ANSI_ATTR_UNDERLINE_OFF = 24
    60  	ANSI_ATTR_BLINK_OFF     = 25
    61  	ANSI_ATTR_REVERSE_OFF   = 27
    62  	ANSI_ATTR_INVISIBLE_OFF = 8
    63  
    64  	ANSI_FOREGROUND_BLACK   = 30
    65  	ANSI_FOREGROUND_RED     = 31
    66  	ANSI_FOREGROUND_GREEN   = 32
    67  	ANSI_FOREGROUND_YELLOW  = 33
    68  	ANSI_FOREGROUND_BLUE    = 34
    69  	ANSI_FOREGROUND_MAGENTA = 35
    70  	ANSI_FOREGROUND_CYAN    = 36
    71  	ANSI_FOREGROUND_WHITE   = 37
    72  	ANSI_FOREGROUND_DEFAULT = 39
    73  
    74  	ANSI_BACKGROUND_BLACK   = 40
    75  	ANSI_BACKGROUND_RED     = 41
    76  	ANSI_BACKGROUND_GREEN   = 42
    77  	ANSI_BACKGROUND_YELLOW  = 43
    78  	ANSI_BACKGROUND_BLUE    = 44
    79  	ANSI_BACKGROUND_MAGENTA = 45
    80  	ANSI_BACKGROUND_CYAN    = 46
    81  	ANSI_BACKGROUND_WHITE   = 47
    82  	ANSI_BACKGROUND_DEFAULT = 49
    83  
    84  	ANSI_MAX_CMD_LENGTH = 256
    85  
    86  	MAX_INPUT_EVENTS = 128
    87  	MAX_INPUT_BUFFER = 1024
    88  	DEFAULT_WIDTH    = 80
    89  	DEFAULT_HEIGHT   = 24
    90  )
    91  
    92  // http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
    93  const (
    94  	VK_PRIOR    = 0x21 // PAGE UP key
    95  	VK_NEXT     = 0x22 // PAGE DOWN key
    96  	VK_END      = 0x23 // END key
    97  	VK_HOME     = 0x24 // HOME key
    98  	VK_LEFT     = 0x25 // LEFT ARROW key
    99  	VK_UP       = 0x26 // UP ARROW key
   100  	VK_RIGHT    = 0x27 //RIGHT ARROW key
   101  	VK_DOWN     = 0x28 //DOWN ARROW key
   102  	VK_SELECT   = 0x29 //SELECT key
   103  	VK_PRINT    = 0x2A //PRINT key
   104  	VK_EXECUTE  = 0x2B //EXECUTE key
   105  	VK_SNAPSHOT = 0x2C //PRINT SCREEN key
   106  	VK_INSERT   = 0x2D //INS key
   107  	VK_DELETE   = 0x2E //DEL key
   108  	VK_HELP     = 0x2F //HELP key
   109  	VK_F1       = 0x70 //F1 key
   110  	VK_F2       = 0x71 //F2 key
   111  	VK_F3       = 0x72 //F3 key
   112  	VK_F4       = 0x73 //F4 key
   113  	VK_F5       = 0x74 //F5 key
   114  	VK_F6       = 0x75 //F6 key
   115  	VK_F7       = 0x76 //F7 key
   116  	VK_F8       = 0x77 //F8 key
   117  	VK_F9       = 0x78 //F9 key
   118  	VK_F10      = 0x79 //F10 key
   119  	VK_F11      = 0x7A //F11 key
   120  	VK_F12      = 0x7B //F12 key
   121  )
   122  
   123  var kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
   124  
   125  var (
   126  	setConsoleModeProc                = kernel32DLL.NewProc("SetConsoleMode")
   127  	getConsoleScreenBufferInfoProc    = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
   128  	setConsoleCursorPositionProc      = kernel32DLL.NewProc("SetConsoleCursorPosition")
   129  	setConsoleTextAttributeProc       = kernel32DLL.NewProc("SetConsoleTextAttribute")
   130  	fillConsoleOutputCharacterProc    = kernel32DLL.NewProc("FillConsoleOutputCharacterW")
   131  	writeConsoleOutputProc            = kernel32DLL.NewProc("WriteConsoleOutputW")
   132  	readConsoleInputProc              = kernel32DLL.NewProc("ReadConsoleInputW")
   133  	getNumberOfConsoleInputEventsProc = kernel32DLL.NewProc("GetNumberOfConsoleInputEvents")
   134  	getConsoleCursorInfoProc          = kernel32DLL.NewProc("GetConsoleCursorInfo")
   135  	setConsoleCursorInfoProc          = kernel32DLL.NewProc("SetConsoleCursorInfo")
   136  	setConsoleWindowInfoProc          = kernel32DLL.NewProc("SetConsoleWindowInfo")
   137  	setConsoleScreenBufferSizeProc    = kernel32DLL.NewProc("SetConsoleScreenBufferSize")
   138  )
   139  
   140  // types for calling various windows API
   141  // see http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093(v=vs.85).aspx
   142  type (
   143  	SHORT      int16
   144  	SMALL_RECT struct {
   145  		Left   SHORT
   146  		Top    SHORT
   147  		Right  SHORT
   148  		Bottom SHORT
   149  	}
   150  
   151  	COORD struct {
   152  		X SHORT
   153  		Y SHORT
   154  	}
   155  
   156  	BOOL  int32
   157  	WORD  uint16
   158  	WCHAR uint16
   159  	DWORD uint32
   160  
   161  	CONSOLE_SCREEN_BUFFER_INFO struct {
   162  		Size              COORD
   163  		CursorPosition    COORD
   164  		Attributes        WORD
   165  		Window            SMALL_RECT
   166  		MaximumWindowSize COORD
   167  	}
   168  
   169  	CONSOLE_CURSOR_INFO struct {
   170  		Size    DWORD
   171  		Visible BOOL
   172  	}
   173  
   174  	// http://msdn.microsoft.com/en-us/library/windows/desktop/ms684166(v=vs.85).aspx
   175  	KEY_EVENT_RECORD struct {
   176  		KeyDown         BOOL
   177  		RepeatCount     WORD
   178  		VirtualKeyCode  WORD
   179  		VirtualScanCode WORD
   180  		UnicodeChar     WCHAR
   181  		ControlKeyState DWORD
   182  	}
   183  
   184  	INPUT_RECORD struct {
   185  		EventType WORD
   186  		KeyEvent  KEY_EVENT_RECORD
   187  	}
   188  
   189  	CHAR_INFO struct {
   190  		UnicodeChar WCHAR
   191  		Attributes  WORD
   192  	}
   193  )
   194  
   195  // Implements the TerminalEmulator interface
   196  type WindowsTerminal struct {
   197  	outMutex            sync.Mutex
   198  	inMutex             sync.Mutex
   199  	inputBuffer         []byte
   200  	inputSize           int
   201  	inputEvents         []INPUT_RECORD
   202  	screenBufferInfo    *CONSOLE_SCREEN_BUFFER_INFO
   203  	inputEscapeSequence []byte
   204  }
   205  
   206  func getStdHandle(stdhandle int) uintptr {
   207  	handle, err := syscall.GetStdHandle(stdhandle)
   208  	if err != nil {
   209  		panic(fmt.Errorf("could not get standard io handle %d", stdhandle))
   210  	}
   211  	return uintptr(handle)
   212  }
   213  
   214  func StdStreams() (stdIn io.ReadCloser, stdOut io.Writer, stdErr io.Writer) {
   215  	handler := &WindowsTerminal{
   216  		inputBuffer:         make([]byte, MAX_INPUT_BUFFER),
   217  		inputEscapeSequence: []byte(KEY_ESC_CSI),
   218  		inputEvents:         make([]INPUT_RECORD, MAX_INPUT_EVENTS),
   219  	}
   220  
   221  	if IsTerminal(os.Stdin.Fd()) {
   222  		stdIn = &terminalReader{
   223  			wrappedReader: os.Stdin,
   224  			emulator:      handler,
   225  			command:       make([]byte, 0, ANSI_MAX_CMD_LENGTH),
   226  			fd:            getStdHandle(syscall.STD_INPUT_HANDLE),
   227  		}
   228  	} else {
   229  		stdIn = os.Stdin
   230  	}
   231  
   232  	if IsTerminal(os.Stdout.Fd()) {
   233  		stdoutHandle := getStdHandle(syscall.STD_OUTPUT_HANDLE)
   234  
   235  		// Save current screen buffer info
   236  		screenBufferInfo, err := GetConsoleScreenBufferInfo(stdoutHandle)
   237  		if err != nil {
   238  			// If GetConsoleScreenBufferInfo returns a nil error, it usually means that stdout is not a TTY.
   239  			// However, this is in the branch where stdout is a TTY, hence the panic.
   240  			panic("could not get console screen buffer info")
   241  		}
   242  		handler.screenBufferInfo = screenBufferInfo
   243  
   244  		// Set the window size
   245  		SetWindowSize(stdoutHandle, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_HEIGHT)
   246  		buffer = make([]CHAR_INFO, screenBufferInfo.MaximumWindowSize.X*screenBufferInfo.MaximumWindowSize.Y)
   247  
   248  		stdOut = &terminalWriter{
   249  			wrappedWriter: os.Stdout,
   250  			emulator:      handler,
   251  			command:       make([]byte, 0, ANSI_MAX_CMD_LENGTH),
   252  			fd:            stdoutHandle,
   253  		}
   254  	} else {
   255  		stdOut = os.Stdout
   256  	}
   257  
   258  	if IsTerminal(os.Stderr.Fd()) {
   259  		stdErr = &terminalWriter{
   260  			wrappedWriter: os.Stderr,
   261  			emulator:      handler,
   262  			command:       make([]byte, 0, ANSI_MAX_CMD_LENGTH),
   263  			fd:            getStdHandle(syscall.STD_ERROR_HANDLE),
   264  		}
   265  	} else {
   266  		stdErr = os.Stderr
   267  	}
   268  
   269  	return stdIn, stdOut, stdErr
   270  }
   271  
   272  // GetHandleInfo returns file descriptor and bool indicating whether the file is a terminal
   273  func GetHandleInfo(in interface{}) (uintptr, bool) {
   274  	var inFd uintptr
   275  	var isTerminalIn bool
   276  	if file, ok := in.(*os.File); ok {
   277  		inFd = file.Fd()
   278  		isTerminalIn = IsTerminal(inFd)
   279  	}
   280  	if tr, ok := in.(*terminalReader); ok {
   281  		if file, ok := tr.wrappedReader.(*os.File); ok {
   282  			inFd = file.Fd()
   283  			isTerminalIn = IsTerminal(inFd)
   284  		}
   285  	}
   286  	return inFd, isTerminalIn
   287  }
   288  
   289  func getError(r1, r2 uintptr, lastErr error) error {
   290  	// If the function fails, the return value is zero.
   291  	if r1 == 0 {
   292  		if lastErr != nil {
   293  			return lastErr
   294  		}
   295  		return syscall.EINVAL
   296  	}
   297  	return nil
   298  }
   299  
   300  // GetConsoleMode gets the console mode for given file descriptor
   301  // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx
   302  func GetConsoleMode(handle uintptr) (uint32, error) {
   303  	var mode uint32
   304  	err := syscall.GetConsoleMode(syscall.Handle(handle), &mode)
   305  	return mode, err
   306  }
   307  
   308  // SetConsoleMode sets the console mode for given file descriptor
   309  // http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
   310  func SetConsoleMode(handle uintptr, mode uint32) error {
   311  	return getError(setConsoleModeProc.Call(handle, uintptr(mode), 0))
   312  }
   313  
   314  // SetCursorVisible sets the cursor visbility
   315  // http://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx
   316  func SetCursorVisible(handle uintptr, isVisible BOOL) (bool, error) {
   317  	var cursorInfo CONSOLE_CURSOR_INFO
   318  	if err := getError(getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(&cursorInfo)), 0)); err != nil {
   319  		return false, err
   320  	}
   321  	cursorInfo.Visible = isVisible
   322  	if err := getError(setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(&cursorInfo)), 0)); err != nil {
   323  		return false, err
   324  	}
   325  	return true, nil
   326  }
   327  
   328  // SetWindowSize sets the size of the console window.
   329  func SetWindowSize(handle uintptr, width, height, max SHORT) (bool, error) {
   330  	window := SMALL_RECT{Left: 0, Top: 0, Right: width - 1, Bottom: height - 1}
   331  	coord := COORD{X: width - 1, Y: max}
   332  	if err := getError(setConsoleWindowInfoProc.Call(handle, uintptr(1), uintptr(unsafe.Pointer(&window)))); err != nil {
   333  		return false, err
   334  	}
   335  	if err := getError(setConsoleScreenBufferSizeProc.Call(handle, marshal(coord))); err != nil {
   336  		return false, err
   337  	}
   338  	return true, nil
   339  }
   340  
   341  // GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer.
   342  // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx
   343  func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
   344  	var info CONSOLE_SCREEN_BUFFER_INFO
   345  	if err := getError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0)); err != nil {
   346  		return nil, err
   347  	}
   348  	return &info, nil
   349  }
   350  
   351  // setConsoleTextAttribute sets the attributes of characters written to the
   352  // console screen buffer by the WriteFile or WriteConsole function,
   353  // http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx
   354  func setConsoleTextAttribute(handle uintptr, attribute WORD) error {
   355  	return getError(setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0))
   356  }
   357  
   358  func writeConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) (bool, error) {
   359  	if err := getError(writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), marshal(bufferSize), marshal(bufferCoord), uintptr(unsafe.Pointer(writeRegion)))); err != nil {
   360  		return false, err
   361  	}
   362  	return true, nil
   363  }
   364  
   365  // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682663(v=vs.85).aspx
   366  func fillConsoleOutputCharacter(handle uintptr, fillChar byte, length uint32, writeCord COORD) (bool, error) {
   367  	out := int64(0)
   368  	if err := getError(fillConsoleOutputCharacterProc.Call(handle, uintptr(fillChar), uintptr(length), marshal(writeCord), uintptr(unsafe.Pointer(&out)))); err != nil {
   369  		return false, err
   370  	}
   371  	return true, nil
   372  }
   373  
   374  // Gets the number of space characters to write for "clearing" the section of terminal
   375  func getNumberOfChars(fromCoord COORD, toCoord COORD, screenSize COORD) uint32 {
   376  	// must be valid cursor position
   377  	if fromCoord.X < 0 || fromCoord.Y < 0 || toCoord.X < 0 || toCoord.Y < 0 {
   378  		return 0
   379  	}
   380  	if fromCoord.X >= screenSize.X || fromCoord.Y >= screenSize.Y || toCoord.X >= screenSize.X || toCoord.Y >= screenSize.Y {
   381  		return 0
   382  	}
   383  	// can't be backwards
   384  	if fromCoord.Y > toCoord.Y {
   385  		return 0
   386  	}
   387  	// same line
   388  	if fromCoord.Y == toCoord.Y {
   389  		return uint32(toCoord.X-fromCoord.X) + 1
   390  	}
   391  	// spans more than one line
   392  	if fromCoord.Y < toCoord.Y {
   393  		// from start till end of line for first line +  from start of line till end
   394  		retValue := uint32(screenSize.X-fromCoord.X) + uint32(toCoord.X) + 1
   395  		// don't count first and last line
   396  		linesBetween := toCoord.Y - fromCoord.Y - 1
   397  		if linesBetween > 0 {
   398  			retValue = retValue + uint32(linesBetween*screenSize.X)
   399  		}
   400  		return retValue
   401  	}
   402  	return 0
   403  }
   404  
   405  var buffer []CHAR_INFO
   406  
   407  func clearDisplayRect(handle uintptr, fillChar rune, attributes WORD, fromCoord COORD, toCoord COORD, windowSize COORD) (uint32, error) {
   408  	var writeRegion SMALL_RECT
   409  	writeRegion.Top = fromCoord.Y
   410  	writeRegion.Left = fromCoord.X
   411  	writeRegion.Right = toCoord.X
   412  	writeRegion.Bottom = toCoord.Y
   413  
   414  	// allocate and initialize buffer
   415  	width := toCoord.X - fromCoord.X + 1
   416  	height := toCoord.Y - fromCoord.Y + 1
   417  	size := width * height
   418  	if size > 0 {
   419  		for i := 0; i < int(size); i++ {
   420  			buffer[i].UnicodeChar = WCHAR(fillChar)
   421  			buffer[i].Attributes = attributes
   422  		}
   423  
   424  		// Write to buffer
   425  		r, err := writeConsoleOutput(handle, buffer[:size], windowSize, COORD{X: 0, Y: 0}, &writeRegion)
   426  		if !r {
   427  			if err != nil {
   428  				return 0, err
   429  			}
   430  			return 0, syscall.EINVAL
   431  		}
   432  	}
   433  	return uint32(size), nil
   434  }
   435  
   436  func clearDisplayRange(handle uintptr, fillChar rune, attributes WORD, fromCoord COORD, toCoord COORD, windowSize COORD) (uint32, error) {
   437  	nw := uint32(0)
   438  	// start and end on same line
   439  	if fromCoord.Y == toCoord.Y {
   440  		return clearDisplayRect(handle, fillChar, attributes, fromCoord, toCoord, windowSize)
   441  	}
   442  	// TODO(azlinux): if full screen, optimize
   443  
   444  	// spans more than one line
   445  	if fromCoord.Y < toCoord.Y {
   446  		// from start position till end of line for first line
   447  		n, err := clearDisplayRect(handle, fillChar, attributes, fromCoord, COORD{X: windowSize.X - 1, Y: fromCoord.Y}, windowSize)
   448  		if err != nil {
   449  			return nw, err
   450  		}
   451  		nw += n
   452  		// lines between
   453  		linesBetween := toCoord.Y - fromCoord.Y - 1
   454  		if linesBetween > 0 {
   455  			n, err = clearDisplayRect(handle, fillChar, attributes, COORD{X: 0, Y: fromCoord.Y + 1}, COORD{X: windowSize.X - 1, Y: toCoord.Y - 1}, windowSize)
   456  			if err != nil {
   457  				return nw, err
   458  			}
   459  			nw += n
   460  		}
   461  		// lines at end
   462  		n, err = clearDisplayRect(handle, fillChar, attributes, COORD{X: 0, Y: toCoord.Y}, toCoord, windowSize)
   463  		if err != nil {
   464  			return nw, err
   465  		}
   466  		nw += n
   467  	}
   468  	return nw, nil
   469  }
   470  
   471  // setConsoleCursorPosition sets the console cursor position
   472  // Note The X and Y are zero based
   473  // If relative is true then the new position is relative to current one
   474  func setConsoleCursorPosition(handle uintptr, isRelative bool, column int16, line int16) error {
   475  	screenBufferInfo, err := GetConsoleScreenBufferInfo(handle)
   476  	if err != nil {
   477  		return err
   478  	}
   479  	var position COORD
   480  	if isRelative {
   481  		position.X = screenBufferInfo.CursorPosition.X + SHORT(column)
   482  		position.Y = screenBufferInfo.CursorPosition.Y + SHORT(line)
   483  	} else {
   484  		position.X = SHORT(column)
   485  		position.Y = SHORT(line)
   486  	}
   487  	return getError(setConsoleCursorPositionProc.Call(handle, marshal(position), 0))
   488  }
   489  
   490  // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683207(v=vs.85).aspx
   491  func getNumberOfConsoleInputEvents(handle uintptr) (uint16, error) {
   492  	var n WORD
   493  	if err := getError(getNumberOfConsoleInputEventsProc.Call(handle, uintptr(unsafe.Pointer(&n)))); err != nil {
   494  		return 0, err
   495  	}
   496  	return uint16(n), nil
   497  }
   498  
   499  //http://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx
   500  func readConsoleInputKey(handle uintptr, inputBuffer []INPUT_RECORD) (int, error) {
   501  	var nr WORD
   502  	if err := getError(readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&inputBuffer[0])), uintptr(len(inputBuffer)), uintptr(unsafe.Pointer(&nr)))); err != nil {
   503  		return 0, err
   504  	}
   505  	return int(nr), nil
   506  }
   507  
   508  func getWindowsTextAttributeForAnsiValue(originalFlag WORD, defaultValue WORD, ansiValue int16) (WORD, error) {
   509  	flag := WORD(originalFlag)
   510  	if flag == 0 {
   511  		flag = defaultValue
   512  	}
   513  	switch ansiValue {
   514  	case ANSI_ATTR_RESET:
   515  		flag &^= COMMON_LVB_UNDERSCORE
   516  		flag &^= BACKGROUND_INTENSITY
   517  		flag = flag | FOREGROUND_INTENSITY
   518  	case ANSI_ATTR_INVISIBLE:
   519  		// TODO: how do you reset reverse?
   520  	case ANSI_ATTR_UNDERLINE:
   521  		flag = flag | COMMON_LVB_UNDERSCORE
   522  	case ANSI_ATTR_BLINK:
   523  		// seems like background intenisty is blink
   524  		flag = flag | BACKGROUND_INTENSITY
   525  	case ANSI_ATTR_UNDERLINE_OFF:
   526  		flag &^= COMMON_LVB_UNDERSCORE
   527  	case ANSI_ATTR_BLINK_OFF:
   528  		// seems like background intenisty is blink
   529  		flag &^= BACKGROUND_INTENSITY
   530  	case ANSI_ATTR_BOLD:
   531  		flag = flag | FOREGROUND_INTENSITY
   532  	case ANSI_ATTR_DIM:
   533  		flag &^= FOREGROUND_INTENSITY
   534  	case ANSI_ATTR_REVERSE, ANSI_ATTR_REVERSE_OFF:
   535  		// swap forground and background bits
   536  		foreground := flag & FOREGROUND_MASK_SET
   537  		background := flag & BACKGROUND_MASK_SET
   538  		flag = (flag & BACKGROUND_MASK_UNSET & FOREGROUND_MASK_UNSET) | (foreground << 4) | (background >> 4)
   539  
   540  	// FOREGROUND
   541  	case ANSI_FOREGROUND_DEFAULT:
   542  		flag = (flag & FOREGROUND_MASK_UNSET) | (defaultValue & FOREGROUND_MASK_SET)
   543  	case ANSI_FOREGROUND_BLACK:
   544  		flag = flag ^ (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
   545  	case ANSI_FOREGROUND_RED:
   546  		flag = (flag & FOREGROUND_MASK_UNSET) | FOREGROUND_RED
   547  	case ANSI_FOREGROUND_GREEN:
   548  		flag = (flag & FOREGROUND_MASK_UNSET) | FOREGROUND_GREEN
   549  	case ANSI_FOREGROUND_YELLOW:
   550  		flag = (flag & FOREGROUND_MASK_UNSET) | FOREGROUND_RED | FOREGROUND_GREEN
   551  	case ANSI_FOREGROUND_BLUE:
   552  		flag = (flag & FOREGROUND_MASK_UNSET) | FOREGROUND_BLUE
   553  	case ANSI_FOREGROUND_MAGENTA:
   554  		flag = (flag & FOREGROUND_MASK_UNSET) | FOREGROUND_RED | FOREGROUND_BLUE
   555  	case ANSI_FOREGROUND_CYAN:
   556  		flag = (flag & FOREGROUND_MASK_UNSET) | FOREGROUND_GREEN | FOREGROUND_BLUE
   557  	case ANSI_FOREGROUND_WHITE:
   558  		flag = (flag & FOREGROUND_MASK_UNSET) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
   559  
   560  	// Background
   561  	case ANSI_BACKGROUND_DEFAULT:
   562  		// Black with no intensity
   563  		flag = (flag & BACKGROUND_MASK_UNSET) | (defaultValue & BACKGROUND_MASK_SET)
   564  	case ANSI_BACKGROUND_BLACK:
   565  		flag = (flag & BACKGROUND_MASK_UNSET)
   566  	case ANSI_BACKGROUND_RED:
   567  		flag = (flag & BACKGROUND_MASK_UNSET) | BACKGROUND_RED
   568  	case ANSI_BACKGROUND_GREEN:
   569  		flag = (flag & BACKGROUND_MASK_UNSET) | BACKGROUND_GREEN
   570  	case ANSI_BACKGROUND_YELLOW:
   571  		flag = (flag & BACKGROUND_MASK_UNSET) | BACKGROUND_RED | BACKGROUND_GREEN
   572  	case ANSI_BACKGROUND_BLUE:
   573  		flag = (flag & BACKGROUND_MASK_UNSET) | BACKGROUND_BLUE
   574  	case ANSI_BACKGROUND_MAGENTA:
   575  		flag = (flag & BACKGROUND_MASK_UNSET) | BACKGROUND_RED | BACKGROUND_BLUE
   576  	case ANSI_BACKGROUND_CYAN:
   577  		flag = (flag & BACKGROUND_MASK_UNSET) | BACKGROUND_GREEN | BACKGROUND_BLUE
   578  	case ANSI_BACKGROUND_WHITE:
   579  		flag = (flag & BACKGROUND_MASK_UNSET) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
   580  	}
   581  	return flag, nil
   582  }
   583  
   584  // HandleOutputCommand interpretes the Ansi commands and then makes appropriate Win32 calls
   585  func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte) (n int, err error) {
   586  	// always consider all the bytes in command, processed
   587  	n = len(command)
   588  
   589  	parsedCommand := parseAnsiCommand(command)
   590  
   591  	// console settings changes need to happen in atomic way
   592  	term.outMutex.Lock()
   593  	defer term.outMutex.Unlock()
   594  
   595  	switch parsedCommand.Command {
   596  	case "m":
   597  		// [Value;...;Valuem
   598  		// Set Graphics Mode:
   599  		// Calls the graphics functions specified by the following values.
   600  		// These specified functions remain active until the next occurrence of this escape sequence.
   601  		// Graphics mode changes the colors and attributes of text (such as bold and underline) displayed on the screen.
   602  		screenBufferInfo, err := GetConsoleScreenBufferInfo(handle)
   603  		if err != nil {
   604  			return n, err
   605  		}
   606  		flag := screenBufferInfo.Attributes
   607  		for _, e := range parsedCommand.Parameters {
   608  			value, _ := strconv.ParseInt(e, 10, 16) // base 10, 16 bit
   609  			if value == ANSI_ATTR_RESET {
   610  				flag = term.screenBufferInfo.Attributes // reset
   611  			} else {
   612  				flag, err = getWindowsTextAttributeForAnsiValue(flag, term.screenBufferInfo.Attributes, int16(value))
   613  				if err != nil {
   614  					return n, err
   615  				}
   616  			}
   617  		}
   618  		if err := setConsoleTextAttribute(handle, flag); err != nil {
   619  			return n, err
   620  		}
   621  	case "H", "f":
   622  		// [line;columnH
   623  		// [line;columnf
   624  		// Moves the cursor to the specified position (coordinates).
   625  		// If you do not specify a position, the cursor moves to the home position at the upper-left corner of the screen (line 0, column 0).
   626  		screenBufferInfo, err := GetConsoleScreenBufferInfo(handle)
   627  		if err != nil {
   628  			return n, err
   629  		}
   630  		line, err := parseInt16OrDefault(parsedCommand.getParam(0), 1)
   631  		if err != nil {
   632  			return n, err
   633  		}
   634  		if line > int16(screenBufferInfo.Window.Bottom) {
   635  			line = int16(screenBufferInfo.Window.Bottom)
   636  		}
   637  		column, err := parseInt16OrDefault(parsedCommand.getParam(1), 1)
   638  		if err != nil {
   639  			return n, err
   640  		}
   641  		if column > int16(screenBufferInfo.Window.Right) {
   642  			column = int16(screenBufferInfo.Window.Right)
   643  		}
   644  		// The numbers are not 0 based, but 1 based
   645  		if err := setConsoleCursorPosition(handle, false, column-1, line-1); err != nil {
   646  			return n, err
   647  		}
   648  
   649  	case "A":
   650  		// [valueA
   651  		// Moves the cursor up by the specified number of lines without changing columns.
   652  		// If the cursor is already on the top line, ignores this sequence.
   653  		value, err := parseInt16OrDefault(parsedCommand.getParam(0), 1)
   654  		if err != nil {
   655  			return len(command), err
   656  		}
   657  		if err := setConsoleCursorPosition(handle, true, 0, -value); err != nil {
   658  			return n, err
   659  		}
   660  	case "B":
   661  		// [valueB
   662  		// Moves the cursor down by the specified number of lines without changing columns.
   663  		// If the cursor is already on the bottom line, ignores this sequence.
   664  		value, err := parseInt16OrDefault(parsedCommand.getParam(0), 1)
   665  		if err != nil {
   666  			return n, err
   667  		}
   668  		if err := setConsoleCursorPosition(handle, true, 0, value); err != nil {
   669  			return n, err
   670  		}
   671  	case "C":
   672  		// [valueC
   673  		// Moves the cursor forward by the specified number of columns without changing lines.
   674  		// If the cursor is already in the rightmost column, ignores this sequence.
   675  		value, err := parseInt16OrDefault(parsedCommand.getParam(0), 1)
   676  		if err != nil {
   677  			return n, err
   678  		}
   679  		if err := setConsoleCursorPosition(handle, true, value, 0); err != nil {
   680  			return n, err
   681  		}
   682  	case "D":
   683  		// [valueD
   684  		// Moves the cursor back by the specified number of columns without changing lines.
   685  		// If the cursor is already in the leftmost column, ignores this sequence.
   686  		value, err := parseInt16OrDefault(parsedCommand.getParam(0), 1)
   687  		if err != nil {
   688  			return n, err
   689  		}
   690  		if err := setConsoleCursorPosition(handle, true, -value, 0); err != nil {
   691  			return n, err
   692  		}
   693  	case "J":
   694  		// [J   Erases from the cursor to the end of the screen, including the cursor position.
   695  		// [1J  Erases from the beginning of the screen to the cursor, including the cursor position.
   696  		// [2J  Erases the complete display. The cursor does not move.
   697  		// Clears the screen and moves the cursor to the home position (line 0, column 0).
   698  		value, err := parseInt16OrDefault(parsedCommand.getParam(0), 0)
   699  		if err != nil {
   700  			return n, err
   701  		}
   702  		var start COORD
   703  		var cursor COORD
   704  		var end COORD
   705  		screenBufferInfo, err := GetConsoleScreenBufferInfo(handle)
   706  		if err != nil {
   707  			return n, err
   708  		}
   709  		switch value {
   710  		case 0:
   711  			start = screenBufferInfo.CursorPosition
   712  			// end of the screen
   713  			end.X = screenBufferInfo.MaximumWindowSize.X - 1
   714  			end.Y = screenBufferInfo.MaximumWindowSize.Y - 1
   715  			// cursor
   716  			cursor = screenBufferInfo.CursorPosition
   717  		case 1:
   718  
   719  			// start of the screen
   720  			start.X = 0
   721  			start.Y = 0
   722  			// end of the screen
   723  			end = screenBufferInfo.CursorPosition
   724  			// cursor
   725  			cursor = screenBufferInfo.CursorPosition
   726  		case 2:
   727  			// start of the screen
   728  			start.X = 0
   729  			start.Y = 0
   730  			// end of the screen
   731  			end.X = screenBufferInfo.MaximumWindowSize.X - 1
   732  			end.Y = screenBufferInfo.MaximumWindowSize.Y - 1
   733  			// cursor
   734  			cursor.X = 0
   735  			cursor.Y = 0
   736  		}
   737  		if _, err := clearDisplayRange(uintptr(handle), ' ', term.screenBufferInfo.Attributes, start, end, screenBufferInfo.MaximumWindowSize); err != nil {
   738  			return n, err
   739  		}
   740  		// remember the the cursor position is 1 based
   741  		if err := setConsoleCursorPosition(handle, false, int16(cursor.X), int16(cursor.Y)); err != nil {
   742  			return n, err
   743  		}
   744  	case "K":
   745  		// [K
   746  		// Clears all characters from the cursor position to the end of the line (including the character at the cursor position).
   747  		// [K  Erases from the cursor to the end of the line, including the cursor position.
   748  		// [1K  Erases from the beginning of the line to the cursor, including the cursor position.
   749  		// [2K  Erases the complete line.
   750  		value, err := parseInt16OrDefault(parsedCommand.getParam(0), 0)
   751  		var start COORD
   752  		var cursor COORD
   753  		var end COORD
   754  		screenBufferInfo, err := GetConsoleScreenBufferInfo(uintptr(handle))
   755  		if err != nil {
   756  			return n, err
   757  		}
   758  		switch value {
   759  		case 0:
   760  			// start is where cursor is
   761  			start = screenBufferInfo.CursorPosition
   762  			// end of line
   763  			end.X = screenBufferInfo.MaximumWindowSize.X - 1
   764  			end.Y = screenBufferInfo.CursorPosition.Y
   765  			// cursor remains the same
   766  			cursor = screenBufferInfo.CursorPosition
   767  
   768  		case 1:
   769  			// beginning of line
   770  			start.X = 0
   771  			start.Y = screenBufferInfo.CursorPosition.Y
   772  			// until cursor
   773  			end = screenBufferInfo.CursorPosition
   774  			// cursor remains the same
   775  			cursor = screenBufferInfo.CursorPosition
   776  		case 2:
   777  			// start of the line
   778  			start.X = 0
   779  			start.Y = screenBufferInfo.MaximumWindowSize.Y - 1
   780  			// end of the line
   781  			end.X = screenBufferInfo.MaximumWindowSize.X - 1
   782  			end.Y = screenBufferInfo.MaximumWindowSize.Y - 1
   783  			// cursor
   784  			cursor.X = 0
   785  			cursor.Y = screenBufferInfo.MaximumWindowSize.Y - 1
   786  		}
   787  		if _, err := clearDisplayRange(uintptr(handle), ' ', term.screenBufferInfo.Attributes, start, end, screenBufferInfo.MaximumWindowSize); err != nil {
   788  			return n, err
   789  		}
   790  		// remember the the cursor position is 1 based
   791  		if err := setConsoleCursorPosition(uintptr(handle), false, int16(cursor.X), int16(cursor.Y)); err != nil {
   792  			return n, err
   793  		}
   794  
   795  	case "l":
   796  		for _, value := range parsedCommand.Parameters {
   797  			switch value {
   798  			case "?25", "25":
   799  				SetCursorVisible(uintptr(handle), BOOL(0))
   800  			case "?1049", "1049":
   801  				// TODO (azlinux):  Restore terminal
   802  			case "?1", "1":
   803  				// If the DECCKM function is reset, then the arrow keys send ANSI cursor sequences to the host.
   804  				term.inputEscapeSequence = []byte(KEY_ESC_CSI)
   805  			}
   806  		}
   807  	case "h":
   808  		for _, value := range parsedCommand.Parameters {
   809  			switch value {
   810  			case "?25", "25":
   811  				SetCursorVisible(uintptr(handle), BOOL(1))
   812  			case "?1049", "1049":
   813  				// TODO (azlinux): Save terminal
   814  			case "?1", "1":
   815  				// If the DECCKM function is set, then the arrow keys send application sequences to the host.
   816  				// DECCKM (default off): When set, the cursor keys send an ESC O prefix, rather than ESC [.
   817  				term.inputEscapeSequence = []byte(KEY_ESC_O)
   818  			}
   819  		}
   820  
   821  	case "]":
   822  		/*
   823  			TODO (azlinux):
   824  				Linux Console Private CSI Sequences
   825  
   826  			       The following sequences are neither ECMA-48 nor native VT102.  They are
   827  			       native  to the Linux console driver.  Colors are in SGR parameters: 0 =
   828  			       black, 1 = red, 2 = green, 3 = brown, 4 = blue, 5 = magenta, 6 =  cyan,
   829  			       7 = white.
   830  
   831  			       ESC [ 1 ; n ]       Set color n as the underline color
   832  			       ESC [ 2 ; n ]       Set color n as the dim color
   833  			       ESC [ 8 ]           Make the current color pair the default attributes.
   834  			       ESC [ 9 ; n ]       Set screen blank timeout to n minutes.
   835  			       ESC [ 10 ; n ]      Set bell frequency in Hz.
   836  			       ESC [ 11 ; n ]      Set bell duration in msec.
   837  			       ESC [ 12 ; n ]      Bring specified console to the front.
   838  			       ESC [ 13 ]          Unblank the screen.
   839  			       ESC [ 14 ; n ]      Set the VESA powerdown interval in minutes.
   840  
   841  		*/
   842  	}
   843  	return n, nil
   844  }
   845  
   846  // WriteChars writes the bytes to given writer.
   847  func (term *WindowsTerminal) WriteChars(fd uintptr, w io.Writer, p []byte) (n int, err error) {
   848  	if len(p) == 0 {
   849  		return 0, nil
   850  	}
   851  	return w.Write(p)
   852  }
   853  
   854  const (
   855  	CAPSLOCK_ON        = 0x0080 //The CAPS LOCK light is on.
   856  	ENHANCED_KEY       = 0x0100 //The key is enhanced.
   857  	LEFT_ALT_PRESSED   = 0x0002 //The left ALT key is pressed.
   858  	LEFT_CTRL_PRESSED  = 0x0008 //The left CTRL key is pressed.
   859  	NUMLOCK_ON         = 0x0020 //The NUM LOCK light is on.
   860  	RIGHT_ALT_PRESSED  = 0x0001 //The right ALT key is pressed.
   861  	RIGHT_CTRL_PRESSED = 0x0004 //The right CTRL key is pressed.
   862  	SCROLLLOCK_ON      = 0x0040 //The SCROLL LOCK light is on.
   863  	SHIFT_PRESSED      = 0x0010 // The SHIFT key is pressed.
   864  )
   865  
   866  const (
   867  	KEY_CONTROL_PARAM_2 = ";2"
   868  	KEY_CONTROL_PARAM_3 = ";3"
   869  	KEY_CONTROL_PARAM_4 = ";4"
   870  	KEY_CONTROL_PARAM_5 = ";5"
   871  	KEY_CONTROL_PARAM_6 = ";6"
   872  	KEY_CONTROL_PARAM_7 = ";7"
   873  	KEY_CONTROL_PARAM_8 = ";8"
   874  	KEY_ESC_CSI         = "\x1B["
   875  	KEY_ESC_N           = "\x1BN"
   876  	KEY_ESC_O           = "\x1BO"
   877  )
   878  
   879  var keyMapPrefix = map[WORD]string{
   880  	VK_UP:     "\x1B[%sA",
   881  	VK_DOWN:   "\x1B[%sB",
   882  	VK_RIGHT:  "\x1B[%sC",
   883  	VK_LEFT:   "\x1B[%sD",
   884  	VK_HOME:   "\x1B[1%s~", // showkey shows ^[[1
   885  	VK_END:    "\x1B[4%s~", // showkey shows ^[[4
   886  	VK_INSERT: "\x1B[2%s~",
   887  	VK_DELETE: "\x1B[3%s~",
   888  	VK_PRIOR:  "\x1B[5%s~",
   889  	VK_NEXT:   "\x1B[6%s~",
   890  	VK_F1:     "",
   891  	VK_F2:     "",
   892  	VK_F3:     "\x1B[13%s~",
   893  	VK_F4:     "\x1B[14%s~",
   894  	VK_F5:     "\x1B[15%s~",
   895  	VK_F6:     "\x1B[17%s~",
   896  	VK_F7:     "\x1B[18%s~",
   897  	VK_F8:     "\x1B[19%s~",
   898  	VK_F9:     "\x1B[20%s~",
   899  	VK_F10:    "\x1B[21%s~",
   900  	VK_F11:    "\x1B[23%s~",
   901  	VK_F12:    "\x1B[24%s~",
   902  }
   903  
   904  var arrowKeyMapPrefix = map[WORD]string{
   905  	VK_UP:    "%s%sA",
   906  	VK_DOWN:  "%s%sB",
   907  	VK_RIGHT: "%s%sC",
   908  	VK_LEFT:  "%s%sD",
   909  }
   910  
   911  func getControlStateParameter(shift, alt, control, meta bool) string {
   912  	if shift && alt && control {
   913  		return KEY_CONTROL_PARAM_8
   914  	}
   915  	if alt && control {
   916  		return KEY_CONTROL_PARAM_7
   917  	}
   918  	if shift && control {
   919  		return KEY_CONTROL_PARAM_6
   920  	}
   921  	if control {
   922  		return KEY_CONTROL_PARAM_5
   923  	}
   924  	if shift && alt {
   925  		return KEY_CONTROL_PARAM_4
   926  	}
   927  	if alt {
   928  		return KEY_CONTROL_PARAM_3
   929  	}
   930  	if shift {
   931  		return KEY_CONTROL_PARAM_2
   932  	}
   933  	return ""
   934  }
   935  
   936  func getControlKeys(controlState DWORD) (shift, alt, control bool) {
   937  	shift = 0 != (controlState & SHIFT_PRESSED)
   938  	alt = 0 != (controlState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
   939  	control = 0 != (controlState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
   940  	return shift, alt, control
   941  }
   942  
   943  func charSequenceForKeys(key WORD, controlState DWORD, escapeSequence []byte) string {
   944  	i, ok := arrowKeyMapPrefix[key]
   945  	if ok {
   946  		shift, alt, control := getControlKeys(controlState)
   947  		modifier := getControlStateParameter(shift, alt, control, false)
   948  		return fmt.Sprintf(i, escapeSequence, modifier)
   949  	}
   950  
   951  	i, ok = keyMapPrefix[key]
   952  	if ok {
   953  		shift, alt, control := getControlKeys(controlState)
   954  		modifier := getControlStateParameter(shift, alt, control, false)
   955  		return fmt.Sprintf(i, modifier)
   956  	}
   957  
   958  	return ""
   959  }
   960  
   961  // mapKeystokeToTerminalString maps the given input event record to string
   962  func mapKeystokeToTerminalString(keyEvent *KEY_EVENT_RECORD, escapeSequence []byte) string {
   963  	_, alt, control := getControlKeys(keyEvent.ControlKeyState)
   964  	if keyEvent.UnicodeChar == 0 {
   965  		return charSequenceForKeys(keyEvent.VirtualKeyCode, keyEvent.ControlKeyState, escapeSequence)
   966  	}
   967  	if control {
   968  		// TODO(azlinux): Implement following control sequences
   969  		// <Ctrl>-D  Signals the end of input from the keyboard; also exits current shell.
   970  		// <Ctrl>-H  Deletes the first character to the left of the cursor. Also called the ERASE key.
   971  		// <Ctrl>-Q  Restarts printing after it has been stopped with <Ctrl>-s.
   972  		// <Ctrl>-S  Suspends printing on the screen (does not stop the program).
   973  		// <Ctrl>-U  Deletes all characters on the current line. Also called the KILL key.
   974  		// <Ctrl>-E  Quits current command and creates a core
   975  
   976  	}
   977  	// <Alt>+Key generates ESC N Key
   978  	if !control && alt {
   979  		return KEY_ESC_N + strings.ToLower(string(keyEvent.UnicodeChar))
   980  	}
   981  	return string(keyEvent.UnicodeChar)
   982  }
   983  
   984  // getAvailableInputEvents polls the console for availble events
   985  // The function does not return until at least one input record has been read.
   986  func getAvailableInputEvents(handle uintptr, inputEvents []INPUT_RECORD) (n int, err error) {
   987  	// TODO(azlinux): Why is there a for loop? Seems to me, that `n` cannot be negative. - tibor
   988  	for {
   989  		// Read number of console events available
   990  		n, err = readConsoleInputKey(handle, inputEvents)
   991  		if err != nil || n >= 0 {
   992  			return n, err
   993  		}
   994  	}
   995  }
   996  
   997  // getTranslatedKeyCodes converts the input events into the string of characters
   998  // The ansi escape sequence are used to map key strokes to the strings
   999  func getTranslatedKeyCodes(inputEvents []INPUT_RECORD, escapeSequence []byte) string {
  1000  	var buf bytes.Buffer
  1001  	for i := 0; i < len(inputEvents); i++ {
  1002  		input := inputEvents[i]
  1003  		if input.EventType == KEY_EVENT && input.KeyEvent.KeyDown != 0 {
  1004  			keyString := mapKeystokeToTerminalString(&input.KeyEvent, escapeSequence)
  1005  			buf.WriteString(keyString)
  1006  		}
  1007  	}
  1008  	return buf.String()
  1009  }
  1010  
  1011  // ReadChars reads the characters from the given reader
  1012  func (term *WindowsTerminal) ReadChars(fd uintptr, r io.Reader, p []byte) (n int, err error) {
  1013  	for term.inputSize == 0 {
  1014  		nr, err := getAvailableInputEvents(fd, term.inputEvents)
  1015  		if nr == 0 && nil != err {
  1016  			return n, err
  1017  		}
  1018  		if nr > 0 {
  1019  			keyCodes := getTranslatedKeyCodes(term.inputEvents[:nr], term.inputEscapeSequence)
  1020  			term.inputSize = copy(term.inputBuffer, keyCodes)
  1021  		}
  1022  	}
  1023  	n = copy(p, term.inputBuffer[:term.inputSize])
  1024  	term.inputSize -= n
  1025  	return n, nil
  1026  }
  1027  
  1028  // HandleInputSequence interprets the input sequence command
  1029  func (term *WindowsTerminal) HandleInputSequence(fd uintptr, command []byte) (n int, err error) {
  1030  	return 0, nil
  1031  }
  1032  
  1033  func marshal(c COORD) uintptr {
  1034  	// works only on intel-endian machines
  1035  	return uintptr(uint32(uint32(uint16(c.Y))<<16 | uint32(uint16(c.X))))
  1036  }
  1037  
  1038  // IsTerminal returns true if the given file descriptor is a terminal.
  1039  func IsTerminal(fd uintptr) bool {
  1040  	_, e := GetConsoleMode(fd)
  1041  	return e == nil
  1042  }