github.com/endophage/docker@v1.4.2-0.20161027011718-242853499895/pkg/term/windows/ansi_reader.go (about)

     1  // +build windows
     2  
     3  package windows
     4  
     5  import (
     6  	"bytes"
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"os"
    11  	"strings"
    12  	"unsafe"
    13  
    14  	ansiterm "github.com/Azure/go-ansiterm"
    15  	"github.com/Azure/go-ansiterm/winterm"
    16  )
    17  
    18  const (
    19  	escapeSequence = ansiterm.KEY_ESC_CSI
    20  )
    21  
    22  // ansiReader wraps a standard input file (e.g., os.Stdin) providing ANSI sequence translation.
    23  type ansiReader struct {
    24  	file     *os.File
    25  	fd       uintptr
    26  	buffer   []byte
    27  	cbBuffer int
    28  	command  []byte
    29  }
    30  
    31  // NewAnsiReader returns an io.ReadCloser that provides VT100 terminal emulation on top of a
    32  // Windows console input handle.
    33  func NewAnsiReader(nFile int) io.ReadCloser {
    34  	initLogger()
    35  	file, fd := winterm.GetStdFile(nFile)
    36  	return &ansiReader{
    37  		file:    file,
    38  		fd:      fd,
    39  		command: make([]byte, 0, ansiterm.ANSI_MAX_CMD_LENGTH),
    40  		buffer:  make([]byte, 0),
    41  	}
    42  }
    43  
    44  // Close closes the wrapped file.
    45  func (ar *ansiReader) Close() (err error) {
    46  	return ar.file.Close()
    47  }
    48  
    49  // Fd returns the file descriptor of the wrapped file.
    50  func (ar *ansiReader) Fd() uintptr {
    51  	return ar.fd
    52  }
    53  
    54  // Read reads up to len(p) bytes of translated input events into p.
    55  func (ar *ansiReader) Read(p []byte) (int, error) {
    56  	if len(p) == 0 {
    57  		return 0, nil
    58  	}
    59  
    60  	// Previously read bytes exist, read as much as we can and return
    61  	if len(ar.buffer) > 0 {
    62  		logger.Debugf("Reading previously cached bytes")
    63  
    64  		originalLength := len(ar.buffer)
    65  		copiedLength := copy(p, ar.buffer)
    66  
    67  		if copiedLength == originalLength {
    68  			ar.buffer = make([]byte, 0, len(p))
    69  		} else {
    70  			ar.buffer = ar.buffer[copiedLength:]
    71  		}
    72  
    73  		logger.Debugf("Read from cache p[%d]: % x", copiedLength, p)
    74  		return copiedLength, nil
    75  	}
    76  
    77  	// Read and translate key events
    78  	events, err := readInputEvents(ar.fd, len(p))
    79  	if err != nil {
    80  		return 0, err
    81  	} else if len(events) == 0 {
    82  		logger.Debug("No input events detected")
    83  		return 0, nil
    84  	}
    85  
    86  	keyBytes := translateKeyEvents(events, []byte(escapeSequence))
    87  
    88  	// Save excess bytes and right-size keyBytes
    89  	if len(keyBytes) > len(p) {
    90  		logger.Debugf("Received %d keyBytes, only room for %d bytes", len(keyBytes), len(p))
    91  		ar.buffer = keyBytes[len(p):]
    92  		keyBytes = keyBytes[:len(p)]
    93  	} else if len(keyBytes) == 0 {
    94  		logger.Debug("No key bytes returned from the translator")
    95  		return 0, nil
    96  	}
    97  
    98  	copiedLength := copy(p, keyBytes)
    99  	if copiedLength != len(keyBytes) {
   100  		return 0, errors.New("Unexpected copy length encountered.")
   101  	}
   102  
   103  	logger.Debugf("Read        p[%d]: % x", copiedLength, p)
   104  	logger.Debugf("Read keyBytes[%d]: % x", copiedLength, keyBytes)
   105  	return copiedLength, nil
   106  }
   107  
   108  // readInputEvents polls until at least one event is available.
   109  func readInputEvents(fd uintptr, maxBytes int) ([]winterm.INPUT_RECORD, error) {
   110  	// Determine the maximum number of records to retrieve
   111  	// -- Cast around the type system to obtain the size of a single INPUT_RECORD.
   112  	//    unsafe.Sizeof requires an expression vs. a type-reference; the casting
   113  	//    tricks the type system into believing it has such an expression.
   114  	recordSize := int(unsafe.Sizeof(*((*winterm.INPUT_RECORD)(unsafe.Pointer(&maxBytes)))))
   115  	countRecords := maxBytes / recordSize
   116  	if countRecords > ansiterm.MAX_INPUT_EVENTS {
   117  		countRecords = ansiterm.MAX_INPUT_EVENTS
   118  	}
   119  	logger.Debugf("[windows] readInputEvents: Reading %v records (buffer size %v, record size %v)", countRecords, maxBytes, recordSize)
   120  
   121  	// Wait for and read input events
   122  	events := make([]winterm.INPUT_RECORD, countRecords)
   123  	nEvents := uint32(0)
   124  	eventsExist, err := winterm.WaitForSingleObject(fd, winterm.WAIT_INFINITE)
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  
   129  	if eventsExist {
   130  		err = winterm.ReadConsoleInput(fd, events, &nEvents)
   131  		if err != nil {
   132  			return nil, err
   133  		}
   134  	}
   135  
   136  	// Return a slice restricted to the number of returned records
   137  	logger.Debugf("[windows] readInputEvents: Read %v events", nEvents)
   138  	return events[:nEvents], nil
   139  }
   140  
   141  // KeyEvent Translation Helpers
   142  
   143  var arrowKeyMapPrefix = map[uint16]string{
   144  	winterm.VK_UP:    "%s%sA",
   145  	winterm.VK_DOWN:  "%s%sB",
   146  	winterm.VK_RIGHT: "%s%sC",
   147  	winterm.VK_LEFT:  "%s%sD",
   148  }
   149  
   150  var keyMapPrefix = map[uint16]string{
   151  	winterm.VK_UP:     "\x1B[%sA",
   152  	winterm.VK_DOWN:   "\x1B[%sB",
   153  	winterm.VK_RIGHT:  "\x1B[%sC",
   154  	winterm.VK_LEFT:   "\x1B[%sD",
   155  	winterm.VK_HOME:   "\x1B[1%s~", // showkey shows ^[[1
   156  	winterm.VK_END:    "\x1B[4%s~", // showkey shows ^[[4
   157  	winterm.VK_INSERT: "\x1B[2%s~",
   158  	winterm.VK_DELETE: "\x1B[3%s~",
   159  	winterm.VK_PRIOR:  "\x1B[5%s~",
   160  	winterm.VK_NEXT:   "\x1B[6%s~",
   161  	winterm.VK_F1:     "",
   162  	winterm.VK_F2:     "",
   163  	winterm.VK_F3:     "\x1B[13%s~",
   164  	winterm.VK_F4:     "\x1B[14%s~",
   165  	winterm.VK_F5:     "\x1B[15%s~",
   166  	winterm.VK_F6:     "\x1B[17%s~",
   167  	winterm.VK_F7:     "\x1B[18%s~",
   168  	winterm.VK_F8:     "\x1B[19%s~",
   169  	winterm.VK_F9:     "\x1B[20%s~",
   170  	winterm.VK_F10:    "\x1B[21%s~",
   171  	winterm.VK_F11:    "\x1B[23%s~",
   172  	winterm.VK_F12:    "\x1B[24%s~",
   173  }
   174  
   175  // translateKeyEvents converts the input events into the appropriate ANSI string.
   176  func translateKeyEvents(events []winterm.INPUT_RECORD, escapeSequence []byte) []byte {
   177  	var buffer bytes.Buffer
   178  	for _, event := range events {
   179  		if event.EventType == winterm.KEY_EVENT && event.KeyEvent.KeyDown != 0 {
   180  			buffer.WriteString(keyToString(&event.KeyEvent, escapeSequence))
   181  		}
   182  	}
   183  
   184  	return buffer.Bytes()
   185  }
   186  
   187  // keyToString maps the given input event record to the corresponding string.
   188  func keyToString(keyEvent *winterm.KEY_EVENT_RECORD, escapeSequence []byte) string {
   189  	if keyEvent.UnicodeChar == 0 {
   190  		return formatVirtualKey(keyEvent.VirtualKeyCode, keyEvent.ControlKeyState, escapeSequence)
   191  	}
   192  
   193  	_, alt, control := getControlKeys(keyEvent.ControlKeyState)
   194  	if control {
   195  		// TODO(azlinux): Implement following control sequences
   196  		// <Ctrl>-D  Signals the end of input from the keyboard; also exits current shell.
   197  		// <Ctrl>-H  Deletes the first character to the left of the cursor. Also called the ERASE key.
   198  		// <Ctrl>-Q  Restarts printing after it has been stopped with <Ctrl>-s.
   199  		// <Ctrl>-S  Suspends printing on the screen (does not stop the program).
   200  		// <Ctrl>-U  Deletes all characters on the current line. Also called the KILL key.
   201  		// <Ctrl>-E  Quits current command and creates a core
   202  
   203  	}
   204  
   205  	// <Alt>+Key generates ESC N Key
   206  	if !control && alt {
   207  		return ansiterm.KEY_ESC_N + strings.ToLower(string(keyEvent.UnicodeChar))
   208  	}
   209  
   210  	return string(keyEvent.UnicodeChar)
   211  }
   212  
   213  // formatVirtualKey converts a virtual key (e.g., up arrow) into the appropriate ANSI string.
   214  func formatVirtualKey(key uint16, controlState uint32, escapeSequence []byte) string {
   215  	shift, alt, control := getControlKeys(controlState)
   216  	modifier := getControlKeysModifier(shift, alt, control)
   217  
   218  	if format, ok := arrowKeyMapPrefix[key]; ok {
   219  		return fmt.Sprintf(format, escapeSequence, modifier)
   220  	}
   221  
   222  	if format, ok := keyMapPrefix[key]; ok {
   223  		return fmt.Sprintf(format, modifier)
   224  	}
   225  
   226  	return ""
   227  }
   228  
   229  // getControlKeys extracts the shift, alt, and ctrl key states.
   230  func getControlKeys(controlState uint32) (shift, alt, control bool) {
   231  	shift = 0 != (controlState & winterm.SHIFT_PRESSED)
   232  	alt = 0 != (controlState & (winterm.LEFT_ALT_PRESSED | winterm.RIGHT_ALT_PRESSED))
   233  	control = 0 != (controlState & (winterm.LEFT_CTRL_PRESSED | winterm.RIGHT_CTRL_PRESSED))
   234  	return shift, alt, control
   235  }
   236  
   237  // getControlKeysModifier returns the ANSI modifier for the given combination of control keys.
   238  func getControlKeysModifier(shift, alt, control bool) string {
   239  	if shift && alt && control {
   240  		return ansiterm.KEY_CONTROL_PARAM_8
   241  	}
   242  	if alt && control {
   243  		return ansiterm.KEY_CONTROL_PARAM_7
   244  	}
   245  	if shift && control {
   246  		return ansiterm.KEY_CONTROL_PARAM_6
   247  	}
   248  	if control {
   249  		return ansiterm.KEY_CONTROL_PARAM_5
   250  	}
   251  	if shift && alt {
   252  		return ansiterm.KEY_CONTROL_PARAM_4
   253  	}
   254  	if alt {
   255  		return ansiterm.KEY_CONTROL_PARAM_3
   256  	}
   257  	if shift {
   258  		return ansiterm.KEY_CONTROL_PARAM_2
   259  	}
   260  	return ""
   261  }