...

Source file src/github.com/Azure/go-ansiterm/winterm/ansi.go

Documentation: github.com/Azure/go-ansiterm/winterm

     1  // +build windows
     2  
     3  package winterm
     4  
     5  import (
     6  	"fmt"
     7  	"os"
     8  	"strconv"
     9  	"strings"
    10  	"syscall"
    11  
    12  	"github.com/Azure/go-ansiterm"
    13  	windows "golang.org/x/sys/windows"
    14  )
    15  
    16  // Windows keyboard constants
    17  // See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx.
    18  const (
    19  	VK_PRIOR    = 0x21 // PAGE UP key
    20  	VK_NEXT     = 0x22 // PAGE DOWN key
    21  	VK_END      = 0x23 // END key
    22  	VK_HOME     = 0x24 // HOME key
    23  	VK_LEFT     = 0x25 // LEFT ARROW key
    24  	VK_UP       = 0x26 // UP ARROW key
    25  	VK_RIGHT    = 0x27 // RIGHT ARROW key
    26  	VK_DOWN     = 0x28 // DOWN ARROW key
    27  	VK_SELECT   = 0x29 // SELECT key
    28  	VK_PRINT    = 0x2A // PRINT key
    29  	VK_EXECUTE  = 0x2B // EXECUTE key
    30  	VK_SNAPSHOT = 0x2C // PRINT SCREEN key
    31  	VK_INSERT   = 0x2D // INS key
    32  	VK_DELETE   = 0x2E // DEL key
    33  	VK_HELP     = 0x2F // HELP key
    34  	VK_F1       = 0x70 // F1 key
    35  	VK_F2       = 0x71 // F2 key
    36  	VK_F3       = 0x72 // F3 key
    37  	VK_F4       = 0x73 // F4 key
    38  	VK_F5       = 0x74 // F5 key
    39  	VK_F6       = 0x75 // F6 key
    40  	VK_F7       = 0x76 // F7 key
    41  	VK_F8       = 0x77 // F8 key
    42  	VK_F9       = 0x78 // F9 key
    43  	VK_F10      = 0x79 // F10 key
    44  	VK_F11      = 0x7A // F11 key
    45  	VK_F12      = 0x7B // F12 key
    46  
    47  	RIGHT_ALT_PRESSED  = 0x0001
    48  	LEFT_ALT_PRESSED   = 0x0002
    49  	RIGHT_CTRL_PRESSED = 0x0004
    50  	LEFT_CTRL_PRESSED  = 0x0008
    51  	SHIFT_PRESSED      = 0x0010
    52  	NUMLOCK_ON         = 0x0020
    53  	SCROLLLOCK_ON      = 0x0040
    54  	CAPSLOCK_ON        = 0x0080
    55  	ENHANCED_KEY       = 0x0100
    56  )
    57  
    58  type ansiCommand struct {
    59  	CommandBytes []byte
    60  	Command      string
    61  	Parameters   []string
    62  	IsSpecial    bool
    63  }
    64  
    65  func newAnsiCommand(command []byte) *ansiCommand {
    66  
    67  	if isCharacterSelectionCmdChar(command[1]) {
    68  		// Is Character Set Selection commands
    69  		return &ansiCommand{
    70  			CommandBytes: command,
    71  			Command:      string(command),
    72  			IsSpecial:    true,
    73  		}
    74  	}
    75  
    76  	// last char is command character
    77  	lastCharIndex := len(command) - 1
    78  
    79  	ac := &ansiCommand{
    80  		CommandBytes: command,
    81  		Command:      string(command[lastCharIndex]),
    82  		IsSpecial:    false,
    83  	}
    84  
    85  	// more than a single escape
    86  	if lastCharIndex != 0 {
    87  		start := 1
    88  		// skip if double char escape sequence
    89  		if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY {
    90  			start++
    91  		}
    92  		// convert this to GetNextParam method
    93  		ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP)
    94  	}
    95  
    96  	return ac
    97  }
    98  
    99  func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 {
   100  	if index < 0 || index >= len(ac.Parameters) {
   101  		return defaultValue
   102  	}
   103  
   104  	param, err := strconv.ParseInt(ac.Parameters[index], 10, 16)
   105  	if err != nil {
   106  		return defaultValue
   107  	}
   108  
   109  	return int16(param)
   110  }
   111  
   112  func (ac *ansiCommand) String() string {
   113  	return fmt.Sprintf("0x%v \"%v\" (\"%v\")",
   114  		bytesToHex(ac.CommandBytes),
   115  		ac.Command,
   116  		strings.Join(ac.Parameters, "\",\""))
   117  }
   118  
   119  // isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands.
   120  // See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html.
   121  func isAnsiCommandChar(b byte) bool {
   122  	switch {
   123  	case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY:
   124  		return true
   125  	case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM:
   126  		// non-CSI escape sequence terminator
   127  		return true
   128  	case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL:
   129  		// String escape sequence terminator
   130  		return true
   131  	}
   132  	return false
   133  }
   134  
   135  func isXtermOscSequence(command []byte, current byte) bool {
   136  	return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL)
   137  }
   138  
   139  func isCharacterSelectionCmdChar(b byte) bool {
   140  	return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3)
   141  }
   142  
   143  // bytesToHex converts a slice of bytes to a human-readable string.
   144  func bytesToHex(b []byte) string {
   145  	hex := make([]string, len(b))
   146  	for i, ch := range b {
   147  		hex[i] = fmt.Sprintf("%X", ch)
   148  	}
   149  	return strings.Join(hex, "")
   150  }
   151  
   152  // ensureInRange adjusts the passed value, if necessary, to ensure it is within
   153  // the passed min / max range.
   154  func ensureInRange(n int16, min int16, max int16) int16 {
   155  	if n < min {
   156  		return min
   157  	} else if n > max {
   158  		return max
   159  	} else {
   160  		return n
   161  	}
   162  }
   163  
   164  func GetStdFile(nFile int) (*os.File, uintptr) {
   165  	var file *os.File
   166  
   167  	// syscall uses negative numbers
   168  	// windows package uses very big uint32
   169  	// Keep these switches split so we don't have to convert ints too much.
   170  	switch uint32(nFile) {
   171  	case windows.STD_INPUT_HANDLE:
   172  		file = os.Stdin
   173  	case windows.STD_OUTPUT_HANDLE:
   174  		file = os.Stdout
   175  	case windows.STD_ERROR_HANDLE:
   176  		file = os.Stderr
   177  	default:
   178  		switch nFile {
   179  		case syscall.STD_INPUT_HANDLE:
   180  			file = os.Stdin
   181  		case syscall.STD_OUTPUT_HANDLE:
   182  			file = os.Stdout
   183  		case syscall.STD_ERROR_HANDLE:
   184  			file = os.Stderr
   185  		default:
   186  			panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile))
   187  		}
   188  	}
   189  
   190  	fd, err := syscall.GetStdHandle(nFile)
   191  	if err != nil {
   192  		panic(fmt.Errorf("Invalid standard handle identifier: %v -- %v", nFile, err))
   193  	}
   194  
   195  	return file, uintptr(fd)
   196  }
   197  

View as plain text