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