github.com/hustcat/docker@v1.3.3-0.20160314103604-901c67a8eeab/pkg/term/windows/ansi_reader.go (about)

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