Exemplo n.º 1
0
// HandleOutputCommand interpretes the Ansi commands and then makes appropriate Win32 calls
func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte) (n int, err error) {
	// always consider all the bytes in command, processed
	n = len(command)

	parsedCommand := parseAnsiCommand(command)
	logrus.Debugf("[windows] HandleOutputCommand: %v", parsedCommand)

	// console settings changes need to happen in atomic way
	term.outMutex.Lock()
	defer term.outMutex.Unlock()

	switch parsedCommand.Command {
	case "m":
		// [Value;...;Valuem
		// Set Graphics Mode:
		// Calls the graphics functions specified by the following values.
		// These specified functions remain active until the next occurrence of this escape sequence.
		// Graphics mode changes the colors and attributes of text (such as bold and underline) displayed on the screen.
		screenBufferInfo, err := GetConsoleScreenBufferInfo(handle)
		if err != nil {
			return n, err
		}
		flag := screenBufferInfo.Attributes
		for _, e := range parsedCommand.Parameters {
			value, _ := strconv.ParseInt(e, 10, 16) // base 10, 16 bit
			if value == ANSI_ATTR_RESET {
				flag = term.screenBufferInfo.Attributes // reset
			} else {
				flag, err = getWindowsTextAttributeForAnsiValue(flag, term.screenBufferInfo.Attributes, int16(value))
				if err != nil {
					return n, err
				}
			}
		}
		if err := setConsoleTextAttribute(handle, flag); err != nil {
			return n, err
		}
	case "H", "f":
		// [line;columnH
		// [line;columnf
		// Moves the cursor to the specified position (coordinates).
		// 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).
		screenBufferInfo, err := GetConsoleScreenBufferInfo(handle)
		if err != nil {
			return n, err
		}
		line, err := parseInt16OrDefault(parsedCommand.getParam(0), 1)
		if err != nil {
			return n, err
		}
		if line > int16(screenBufferInfo.Window.Bottom) {
			line = int16(screenBufferInfo.Window.Bottom) + 1
		}
		column, err := parseInt16OrDefault(parsedCommand.getParam(1), 1)
		if err != nil {
			return n, err
		}
		if column > int16(screenBufferInfo.Window.Right) {
			column = int16(screenBufferInfo.Window.Right) + 1
		}
		// The numbers are not 0 based, but 1 based
		logrus.Debugf("[windows] HandleOutputCommmand: Moving cursor to (%v,%v)", column-1, line-1)
		if err := setConsoleCursorPosition(handle, false, column-1, line-1); err != nil {
			return n, err
		}

	case "A":
		// [valueA
		// Moves the cursor up by the specified number of lines without changing columns.
		// If the cursor is already on the top line, ignores this sequence.
		value, err := parseInt16OrDefault(parsedCommand.getParam(0), 1)
		if err != nil {
			return len(command), err
		}
		if err := setConsoleCursorPosition(handle, true, 0, -value); err != nil {
			return n, err
		}
	case "B":
		// [valueB
		// Moves the cursor down by the specified number of lines without changing columns.
		// If the cursor is already on the bottom line, ignores this sequence.
		value, err := parseInt16OrDefault(parsedCommand.getParam(0), 1)
		if err != nil {
			return n, err
		}
		if err := setConsoleCursorPosition(handle, true, 0, value); err != nil {
			return n, err
		}
	case "C":
		// [valueC
		// Moves the cursor forward by the specified number of columns without changing lines.
		// If the cursor is already in the rightmost column, ignores this sequence.
		value, err := parseInt16OrDefault(parsedCommand.getParam(0), 1)
		if err != nil {
			return n, err
		}
		if err := setConsoleCursorPosition(handle, true, value, 0); err != nil {
			return n, err
		}
	case "D":
		// [valueD
		// Moves the cursor back by the specified number of columns without changing lines.
		// If the cursor is already in the leftmost column, ignores this sequence.
		value, err := parseInt16OrDefault(parsedCommand.getParam(0), 1)
		if err != nil {
			return n, err
		}
		if err := setConsoleCursorPosition(handle, true, -value, 0); err != nil {
			return n, err
		}
	case "J":
		// [J   Erases from the cursor to the end of the screen, including the cursor position.
		// [1J  Erases from the beginning of the screen to the cursor, including the cursor position.
		// [2J  Erases the complete display. The cursor does not move.
		// Clears the screen and moves the cursor to the home position (line 0, column 0).
		value, err := parseInt16OrDefault(parsedCommand.getParam(0), 0)
		if err != nil {
			return n, err
		}
		var start COORD
		var cursor COORD
		var end COORD
		screenBufferInfo, err := GetConsoleScreenBufferInfo(handle)
		if err != nil {
			return n, err
		}
		switch value {
		case 0:
			start = screenBufferInfo.CursorPosition
			// end of the buffer
			end.X = screenBufferInfo.Size.X - 1
			end.Y = screenBufferInfo.Size.Y - 1
			// cursor
			cursor = screenBufferInfo.CursorPosition
		case 1:

			// start of the screen
			start.X = 0
			start.Y = 0
			// end of the screen
			end = screenBufferInfo.CursorPosition
			// cursor
			cursor = screenBufferInfo.CursorPosition
		case 2:
			// start of the screen
			start.X = 0
			start.Y = 0
			// end of the buffer
			end.X = screenBufferInfo.Size.X - 1
			end.Y = screenBufferInfo.Size.Y - 1
			// cursor
			cursor.X = 0
			cursor.Y = 0
		}
		if _, err := clearDisplayRange(uintptr(handle), term.screenBufferInfo.Attributes, start, end); err != nil {
			return n, err
		}
		// remember the the cursor position is 1 based
		if err := setConsoleCursorPosition(handle, false, int16(cursor.X), int16(cursor.Y)); err != nil {
			return n, err
		}

	case "K":
		// [K
		// Clears all characters from the cursor position to the end of the line (including the character at the cursor position).
		// [K  Erases from the cursor to the end of the line, including the cursor position.
		// [1K  Erases from the beginning of the line to the cursor, including the cursor position.
		// [2K  Erases the complete line.
		value, err := parseInt16OrDefault(parsedCommand.getParam(0), 0)
		var start COORD
		var cursor COORD
		var end COORD
		screenBufferInfo, err := GetConsoleScreenBufferInfo(uintptr(handle))
		if err != nil {
			return n, err
		}
		switch value {
		case 0:
			// start is where cursor is
			start = screenBufferInfo.CursorPosition
			// end of line
			end.X = screenBufferInfo.Size.X - 1
			end.Y = screenBufferInfo.CursorPosition.Y
			// cursor remains the same
			cursor = screenBufferInfo.CursorPosition

		case 1:
			// beginning of line
			start.X = 0
			start.Y = screenBufferInfo.CursorPosition.Y
			// until cursor
			end = screenBufferInfo.CursorPosition
			// cursor remains the same
			cursor = screenBufferInfo.CursorPosition
		case 2:
			// start of the line
			start.X = 0
			start.Y = screenBufferInfo.CursorPosition.Y - 1
			// end of the line
			end.X = screenBufferInfo.Size.X - 1
			end.Y = screenBufferInfo.CursorPosition.Y - 1
			// cursor
			cursor.X = 0
			cursor.Y = screenBufferInfo.CursorPosition.Y - 1
		}
		if _, err := clearDisplayRange(uintptr(handle), term.screenBufferInfo.Attributes, start, end); err != nil {
			return n, err
		}
		// remember the the cursor position is 1 based
		if err := setConsoleCursorPosition(uintptr(handle), false, int16(cursor.X), int16(cursor.Y)); err != nil {
			return n, err
		}

	case "l":
		for _, value := range parsedCommand.Parameters {
			switch value {
			case "?25", "25":
				SetCursorVisible(uintptr(handle), BOOL(0))
			case "?1049", "1049":
				// TODO (azlinux):  Restore terminal
			case "?1", "1":
				// If the DECCKM function is reset, then the arrow keys send ANSI cursor sequences to the host.
				term.inputEscapeSequence = []byte(KEY_ESC_CSI)
			}
		}
	case "h":
		for _, value := range parsedCommand.Parameters {
			switch value {
			case "?25", "25":
				SetCursorVisible(uintptr(handle), BOOL(1))
			case "?1049", "1049":
				// TODO (azlinux): Save terminal
			case "?1", "1":
				// If the DECCKM function is set, then the arrow keys send application sequences to the host.
				// DECCKM (default off): When set, the cursor keys send an ESC O prefix, rather than ESC [.
				term.inputEscapeSequence = []byte(KEY_ESC_O)
			}
		}

	case "]":
		/*
			TODO (azlinux):
				Linux Console Private CSI Sequences

			       The following sequences are neither ECMA-48 nor native VT102.  They are
			       native  to the Linux console driver.  Colors are in SGR parameters: 0 =
			       black, 1 = red, 2 = green, 3 = brown, 4 = blue, 5 = magenta, 6 =  cyan,
			       7 = white.

			       ESC [ 1 ; n ]       Set color n as the underline color
			       ESC [ 2 ; n ]       Set color n as the dim color
			       ESC [ 8 ]           Make the current color pair the default attributes.
			       ESC [ 9 ; n ]       Set screen blank timeout to n minutes.
			       ESC [ 10 ; n ]      Set bell frequency in Hz.
			       ESC [ 11 ; n ]      Set bell duration in msec.
			       ESC [ 12 ; n ]      Bring specified console to the front.
			       ESC [ 13 ]          Unblank the screen.
			       ESC [ 14 ; n ]      Set the VESA powerdown interval in minutes.

		*/
	}
	return n, nil
}
Exemplo n.º 2
0
// SetWinsize sets the size of the given terminal connected to the passed file descriptor.
func SetWinsize(fd uintptr, ws *Winsize) error {
	// TODO(azlinux): Implement SetWinsize
	logrus.Debugf("[windows] SetWinsize: WARNING -- Unsupported method invoked")
	return nil
}