123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- // +build windows
- package winterm
- import (
- "fmt"
- "os"
- "strconv"
- "strings"
- "syscall"
- "github.com/Azure/go-ansiterm"
- )
- // Windows keyboard constants
- // See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx.
- const (
- VK_PRIOR = 0x21 // PAGE UP key
- VK_NEXT = 0x22 // PAGE DOWN key
- VK_END = 0x23 // END key
- VK_HOME = 0x24 // HOME key
- VK_LEFT = 0x25 // LEFT ARROW key
- VK_UP = 0x26 // UP ARROW key
- VK_RIGHT = 0x27 // RIGHT ARROW key
- VK_DOWN = 0x28 // DOWN ARROW key
- VK_SELECT = 0x29 // SELECT key
- VK_PRINT = 0x2A // PRINT key
- VK_EXECUTE = 0x2B // EXECUTE key
- VK_SNAPSHOT = 0x2C // PRINT SCREEN key
- VK_INSERT = 0x2D // INS key
- VK_DELETE = 0x2E // DEL key
- VK_HELP = 0x2F // HELP key
- VK_F1 = 0x70 // F1 key
- VK_F2 = 0x71 // F2 key
- VK_F3 = 0x72 // F3 key
- VK_F4 = 0x73 // F4 key
- VK_F5 = 0x74 // F5 key
- VK_F6 = 0x75 // F6 key
- VK_F7 = 0x76 // F7 key
- VK_F8 = 0x77 // F8 key
- VK_F9 = 0x78 // F9 key
- VK_F10 = 0x79 // F10 key
- VK_F11 = 0x7A // F11 key
- VK_F12 = 0x7B // F12 key
- RIGHT_ALT_PRESSED = 0x0001
- LEFT_ALT_PRESSED = 0x0002
- RIGHT_CTRL_PRESSED = 0x0004
- LEFT_CTRL_PRESSED = 0x0008
- SHIFT_PRESSED = 0x0010
- NUMLOCK_ON = 0x0020
- SCROLLLOCK_ON = 0x0040
- CAPSLOCK_ON = 0x0080
- ENHANCED_KEY = 0x0100
- )
- type ansiCommand struct {
- CommandBytes []byte
- Command string
- Parameters []string
- IsSpecial bool
- }
- func newAnsiCommand(command []byte) *ansiCommand {
- if isCharacterSelectionCmdChar(command[1]) {
- // Is Character Set Selection commands
- return &ansiCommand{
- CommandBytes: command,
- Command: string(command),
- IsSpecial: true,
- }
- }
- // last char is command character
- lastCharIndex := len(command) - 1
- ac := &ansiCommand{
- CommandBytes: command,
- Command: string(command[lastCharIndex]),
- IsSpecial: false,
- }
- // more than a single escape
- if lastCharIndex != 0 {
- start := 1
- // skip if double char escape sequence
- if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY {
- start++
- }
- // convert this to GetNextParam method
- ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP)
- }
- return ac
- }
- func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 {
- if index < 0 || index >= len(ac.Parameters) {
- return defaultValue
- }
- param, err := strconv.ParseInt(ac.Parameters[index], 10, 16)
- if err != nil {
- return defaultValue
- }
- return int16(param)
- }
- func (ac *ansiCommand) String() string {
- return fmt.Sprintf("0x%v \"%v\" (\"%v\")",
- bytesToHex(ac.CommandBytes),
- ac.Command,
- strings.Join(ac.Parameters, "\",\""))
- }
- // isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands.
- // See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html.
- func isAnsiCommandChar(b byte) bool {
- switch {
- case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY:
- return true
- case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM:
- // non-CSI escape sequence terminator
- return true
- case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL:
- // String escape sequence terminator
- return true
- }
- return false
- }
- func isXtermOscSequence(command []byte, current byte) bool {
- return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL)
- }
- func isCharacterSelectionCmdChar(b byte) bool {
- return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3)
- }
- // bytesToHex converts a slice of bytes to a human-readable string.
- func bytesToHex(b []byte) string {
- hex := make([]string, len(b))
- for i, ch := range b {
- hex[i] = fmt.Sprintf("%X", ch)
- }
- return strings.Join(hex, "")
- }
- // ensureInRange adjusts the passed value, if necessary, to ensure it is within
- // the passed min / max range.
- func ensureInRange(n int16, min int16, max int16) int16 {
- if n < min {
- return min
- } else if n > max {
- return max
- } else {
- return n
- }
- }
- func GetStdFile(nFile int) (*os.File, uintptr) {
- var file *os.File
- switch nFile {
- case syscall.STD_INPUT_HANDLE:
- file = os.Stdin
- case syscall.STD_OUTPUT_HANDLE:
- file = os.Stdout
- case syscall.STD_ERROR_HANDLE:
- file = os.Stderr
- default:
- panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile))
- }
- fd, err := syscall.GetStdHandle(nFile)
- if err != nil {
- panic(fmt.Errorf("Invalid standard handle identifier: %v -- %v", nFile, err))
- }
- return file, uintptr(fd)
- }
|