update for github.com/AlecAivazis/survey => gopkg.in/AlecAivazis/survey.v1 package

This commit is contained in:
Cory Bennett
2017-09-06 08:40:34 -07:00
parent 4d79af4f5e
commit 9453179251
67 changed files with 4 additions and 4 deletions
+134
View File
@@ -0,0 +1,134 @@
// +build !windows
package terminal
import (
"bufio"
"fmt"
"os"
"regexp"
"strconv"
"strings"
)
// CursorUp moves the cursor n cells to up.
func CursorUp(n int) {
fmt.Printf("\x1b[%dA", n)
}
// CursorDown moves the cursor n cells to down.
func CursorDown(n int) {
fmt.Printf("\x1b[%dB", n)
}
// CursorForward moves the cursor n cells to right.
func CursorForward(n int) {
fmt.Printf("\x1b[%dC", n)
}
// CursorBack moves the cursor n cells to left.
func CursorBack(n int) {
fmt.Printf("\x1b[%dD", n)
}
// CursorNextLine moves cursor to beginning of the line n lines down.
func CursorNextLine(n int) {
fmt.Printf("\x1b[%dE", n)
}
// CursorPreviousLine moves cursor to beginning of the line n lines up.
func CursorPreviousLine(n int) {
fmt.Printf("\x1b[%dF", n)
}
// CursorHorizontalAbsolute moves cursor horizontally to x.
func CursorHorizontalAbsolute(x int) {
fmt.Printf("\x1b[%dG", x)
}
// CursorShow shows the cursor.
func CursorShow() {
fmt.Print("\x1b[?25h")
}
// CursorHide hide the cursor.
func CursorHide() {
fmt.Print("\x1b[?25l")
}
// CursorMove moves the cursor to a specific x,y location.
func CursorMove(x int, y int) {
fmt.Printf("\x1b[%d;%df", x, y)
}
// CursorLocation returns the current location of the cursor in the terminal
func CursorLocation() (*Coord, error) {
// print the escape sequence to recieve the position in our stdin
fmt.Print("\x1b[6n")
// read from stdin to get the response
reader := bufio.NewReader(os.Stdin)
// spec says we read 'til R, so do that
text, err := reader.ReadSlice('R')
if err != nil {
return nil, err
}
// spec also says they're split by ;, so do that too
if strings.Contains(string(text), ";") {
// a regex to parse the output of the ansi code
re := regexp.MustCompile(`\d+;\d+`)
line := re.FindString(string(text))
// find the column and rows embedded in the string
coords := strings.Split(line, ";")
// try to cast the col number to an int
col, err := strconv.Atoi(coords[1])
if err != nil {
return nil, err
}
// try to cast the row number to an int
row, err := strconv.Atoi(coords[0])
if err != nil {
return nil, err
}
// return the coordinate object with the col and row we calculated
return &Coord{Short(col), Short(row)}, nil
}
// it didn't work so return an error
return nil, fmt.Errorf("could not compute the cursor position using ascii escape sequences")
}
// Size returns the height and width of the terminal.
func Size() (*Coord, error) {
// the general approach here is to move the cursor to the very bottom
// of the terminal, ask for the current location and then move the
// cursor back where we started
// save the current location of the cursor
origin, err := CursorLocation()
if err != nil {
return nil, err
}
// move the cursor to the very bottom of the terminal
CursorMove(999, 999)
// ask for the current location
bottom, err := CursorLocation()
if err != nil {
return nil, err
}
// move back where we began
CursorUp(int(bottom.Y - origin.Y))
CursorHorizontalAbsolute(int(origin.X))
// sice the bottom was calcuated in the lower right corner, it
// is the dimensions we are looking for
return bottom, nil
}
+101
View File
@@ -0,0 +1,101 @@
package terminal
import (
"os"
"syscall"
"unsafe"
)
func CursorUp(n int) {
cursorMove(0, n)
}
func CursorDown(n int) {
cursorMove(0, -1*n)
}
func CursorForward(n int) {
cursorMove(n, 0)
}
func CursorBack(n int) {
cursorMove(-1*n, 0)
}
func cursorMove(x int, y int) {
handle := syscall.Handle(os.Stdout.Fd())
var csbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
var cursor Coord
cursor.X = csbi.cursorPosition.X + Short(x)
cursor.Y = csbi.cursorPosition.Y + Short(y)
procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor))))
}
func CursorNextLine(n int) {
CursorUp(n)
CursorHorizontalAbsolute(0)
}
func CursorPreviousLine(n int) {
CursorDown(n)
CursorHorizontalAbsolute(0)
}
func CursorHorizontalAbsolute(x int) {
handle := syscall.Handle(os.Stdout.Fd())
var csbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
var cursor Coord
cursor.X = Short(x)
cursor.Y = csbi.cursorPosition.Y
if csbi.size.X < cursor.X {
cursor.X = csbi.size.X
}
procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor))))
}
func CursorShow() {
handle := syscall.Handle(os.Stdout.Fd())
var cci consoleCursorInfo
procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
cci.visible = 1
procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
}
func CursorHide() {
handle := syscall.Handle(os.Stdout.Fd())
var cci consoleCursorInfo
procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
cci.visible = 0
procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
}
func CursorLocation() (Coord, error) {
handle := syscall.Handle(os.Stdout.Fd())
var csbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
return csbi.cursorPosition, nil
}
func Size() (Coord, error) {
handle := syscall.Handle(os.Stdout.Fd())
var csbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
return csbi.size, nil
}
+9
View File
@@ -0,0 +1,9 @@
package terminal
type EraseLineMode int
const (
ERASE_LINE_END EraseLineMode = iota
ERASE_LINE_START
ERASE_LINE_ALL
)
+11
View File
@@ -0,0 +1,11 @@
// +build !windows
package terminal
import (
"fmt"
)
func EraseLine(mode EraseLineMode) {
fmt.Printf("\x1b[%dK", mode)
}
+28
View File
@@ -0,0 +1,28 @@
package terminal
import (
"os"
"syscall"
"unsafe"
)
func EraseLine(mode EraseLineMode) {
handle := syscall.Handle(os.Stdout.Fd())
var csbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
var w uint32
var x Short
cursor := csbi.cursorPosition
switch mode {
case ERASE_LINE_END:
x = csbi.size.X
case ERASE_LINE_START:
x = 0
case ERASE_LINE_ALL:
cursor.X = 0
x = csbi.size.X
}
procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(x), uintptr(*(*int32)(unsafe.Pointer(&cursor))), uintptr(unsafe.Pointer(&w)))
}
+20
View File
@@ -0,0 +1,20 @@
// +build !windows
package terminal
import (
"io"
"os"
)
// Returns special stdout, which converts escape sequences to Windows API calls
// on Windows environment.
func NewAnsiStdout() io.Writer {
return os.Stdout
}
// Returns special stderr, which converts escape sequences to Windows API calls
// on Windows environment.
func NewAnsiStderr() io.Writer {
return os.Stderr
}
+204
View File
@@ -0,0 +1,204 @@
package terminal
import (
"bytes"
"fmt"
"io"
"os"
"strconv"
"strings"
"syscall"
"unsafe"
"github.com/mattn/go-isatty"
)
var (
singleArgFunctions = map[rune]func(int){
'A': CursorUp,
'B': CursorDown,
'C': CursorForward,
'D': CursorBack,
'E': CursorNextLine,
'F': CursorPreviousLine,
'G': CursorHorizontalAbsolute,
}
)
const (
foregroundBlue = 0x1
foregroundGreen = 0x2
foregroundRed = 0x4
foregroundIntensity = 0x8
foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
backgroundBlue = 0x10
backgroundGreen = 0x20
backgroundRed = 0x40
backgroundIntensity = 0x80
backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
)
type Writer struct {
out io.Writer
handle syscall.Handle
orgAttr word
}
func NewAnsiStdout() io.Writer {
var csbi consoleScreenBufferInfo
out := os.Stdout
if !isatty.IsTerminal(out.Fd()) {
return out
}
handle := syscall.Handle(out.Fd())
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
return &Writer{out: out, handle: handle, orgAttr: csbi.attributes}
}
func NewAnsiStderr() io.Writer {
var csbi consoleScreenBufferInfo
out := os.Stderr
if !isatty.IsTerminal(out.Fd()) {
return out
}
handle := syscall.Handle(out.Fd())
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
return &Writer{out: out, handle: handle, orgAttr: csbi.attributes}
}
func (w *Writer) Write(data []byte) (n int, err error) {
r := bytes.NewReader(data)
for {
ch, size, err := r.ReadRune()
if err != nil {
break
}
n += size
switch ch {
case '\x1b':
size, err = w.handleEscape(r)
n += size
if err != nil {
break
}
default:
fmt.Fprint(w.out, string(ch))
}
}
return
}
func (w *Writer) handleEscape(r *bytes.Reader) (n int, err error) {
buf := make([]byte, 0, 10)
buf = append(buf, "\x1b"...)
// Check '[' continues after \x1b
ch, size, err := r.ReadRune()
if err != nil {
fmt.Fprint(w.out, string(buf))
return
}
n += size
if ch != '[' {
fmt.Fprint(w.out, string(buf))
return
}
// Parse escape code
var code rune
argBuf := make([]byte, 0, 10)
for {
ch, size, err = r.ReadRune()
if err != nil {
fmt.Fprint(w.out, string(buf))
return
}
n += size
if ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') {
code = ch
break
}
argBuf = append(argBuf, string(ch)...)
}
w.applyEscapeCode(buf, string(argBuf), code)
return
}
func (w *Writer) applyEscapeCode(buf []byte, arg string, code rune) {
switch arg + string(code) {
case "?25h":
CursorShow()
return
case "?25l":
CursorHide()
return
}
if f, ok := singleArgFunctions[code]; ok {
if n, err := strconv.Atoi(arg); err == nil {
f(n)
return
}
}
switch code {
case 'm':
w.applySelectGraphicRendition(arg)
default:
buf = append(buf, string(code)...)
fmt.Fprint(w.out, string(buf))
}
}
// Original implementation: https://github.com/mattn/go-colorable
func (w *Writer) applySelectGraphicRendition(arg string) {
if arg == "" {
procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.orgAttr))
return
}
var csbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
attr := csbi.attributes
for _, param := range strings.Split(arg, ";") {
n, err := strconv.Atoi(param)
if err != nil {
continue
}
switch {
case n == 0 || n == 100:
attr = w.orgAttr
case 1 <= n && n <= 5:
attr |= foregroundIntensity
case 30 <= n && n <= 37:
attr = (attr & backgroundMask)
if (n-30)&1 != 0 {
attr |= foregroundRed
}
if (n-30)&2 != 0 {
attr |= foregroundGreen
}
if (n-30)&4 != 0 {
attr |= foregroundBlue
}
case 40 <= n && n <= 47:
attr = (attr & foregroundMask)
if (n-40)&1 != 0 {
attr |= backgroundRed
}
if (n-40)&2 != 0 {
attr |= backgroundGreen
}
if (n-40)&4 != 0 {
attr |= backgroundBlue
}
}
}
procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr))
}
+25
View File
@@ -0,0 +1,25 @@
package terminal
import (
"fmt"
)
var (
Stdout = NewAnsiStdout()
)
// Print prints given arguments with escape sequence conversion for windows.
func Print(a ...interface{}) (n int, err error) {
return fmt.Fprint(Stdout, a...)
}
// Printf prints a given format with escape sequence conversion for windows.
func Printf(format string, a ...interface{}) (n int, err error) {
return fmt.Fprintf(Stdout, format, a...)
}
// Println prints given arguments with newline and escape sequence conversion
// for windows.
func Println(a ...interface{}) (n int, err error) {
return fmt.Fprintln(Stdout, a...)
}
+184
View File
@@ -0,0 +1,184 @@
package terminal
import (
"fmt"
"os"
"unicode"
)
type RuneReader struct {
Input *os.File
state runeReaderState
}
func NewRuneReader(input *os.File) *RuneReader {
return &RuneReader{
Input: input,
state: newRuneReaderState(input),
}
}
func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) {
line := []rune{}
// we only care about horizontal displacements from the origin so start counting at 0
index := 0
for {
// wait for some input
r, _, err := rr.ReadRune()
if err != nil {
return line, err
}
// if the user pressed enter or some other newline/termination like ctrl+d
if r == '\r' || r == '\n' || r == KeyEndTransmission {
// go to the beginning of the next line
Print("\r\n")
// we're done processing the input
return line, nil
}
// if the user interrupts (ie with ctrl+c)
if r == KeyInterrupt {
// go to the beginning of the next line
Print("\r\n")
// we're done processing the input, and treat interrupt like an error
return line, fmt.Errorf("interrupt")
}
// allow for backspace/delete editing of inputs
if r == KeyBackspace || r == KeyDelete {
// and we're not at the beginning of the line
if index > 0 && len(line) > 0 {
// if we are at the end of the word
if index == len(line) {
// just remove the last letter from the internal representation
line = line[:len(line)-1]
// go back one
CursorBack(1)
// clear the rest of the line
EraseLine(ERASE_LINE_END)
} else {
// we need to remove a character from the middle of the word
// remove the current index from the list
line = append(line[:index-1], line[index:]...)
// go back one space so we can clear the rest
CursorBack(1)
// clear the rest of the line
EraseLine(ERASE_LINE_END)
// print what comes after
Print(string(line[index-1:]))
// leave the cursor where the user left it
CursorBack(len(line) - index + 1)
}
// decrement the index
index--
} else {
// otherwise the user pressed backspace while at the beginning of the line
soundBell()
}
// we're done processing this key
continue
}
// if the left arrow is pressed
if r == KeyArrowLeft {
// and we have space to the left
if index > 0 {
// move the cursor to the left
CursorBack(1)
// decrement the index
index--
} else {
// otherwise we are at the beginning of where we started reading lines
// sound the bell
soundBell()
}
// we're done processing this key press
continue
}
// if the right arrow is pressed
if r == KeyArrowRight {
// and we have space to the right of the word
if index < len(line) {
// move the cursor to the right
CursorForward(1)
// increment the index
index++
} else {
// otherwise we are at the end of the word and can't go past
// sound the bell
soundBell()
}
// we're done processing this key press
continue
}
// if the letter is another escape sequence
if unicode.IsControl(r) {
// ignore it
continue
}
// the user pressed a regular key
// if we are at the end of the line
if index == len(line) {
// just append the character at the end of the line
line = append(line, r)
// increment the location counter
index++
// if we don't need to mask the input
if mask == 0 {
// just print the character the user pressed
Printf("%c", r)
} else {
// otherwise print the mask we were given
Printf("%c", mask)
}
} else {
// we are in the middle of the word so we need to insert the character the user pressed
line = append(line[:index], append([]rune{r}, line[index:]...)...)
// visually insert the character by deleting the rest of the line
EraseLine(ERASE_LINE_END)
// print the rest of the word after
for _, char := range line[index:] {
// if we don't need to mask the input
if mask == 0 {
// just print the character the user pressed
Printf("%c", char)
} else {
// otherwise print the mask we were given
Printf("%c", mask)
}
}
// leave the cursor where the user left it
CursorBack(len(line) - index - 1)
// accomodate the new letter in our counter
index++
}
}
}
+13
View File
@@ -0,0 +1,13 @@
// copied from: https://github.com/golang/crypto/blob/master/ssh/terminal/util_bsd.go
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd netbsd openbsd
package terminal
import "syscall"
const ioctlReadTermios = syscall.TIOCGETA
const ioctlWriteTermios = syscall.TIOCSETA
+12
View File
@@ -0,0 +1,12 @@
// copied from https://github.com/golang/crypto/blob/master/ssh/terminal/util_linux.go
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package terminal
// These constants are declared here, rather than importing
// them from the syscall package as some syscall packages, even
// on linux, for example gccgo, do not declare them.
const ioctlReadTermios = 0x5401 // syscall.TCGETS
const ioctlWriteTermios = 0x5402 // syscall.TCSETS
+84
View File
@@ -0,0 +1,84 @@
// +build !windows
// The terminal mode manipluation code is derived heavily from:
// https://github.com/golang/crypto/blob/master/ssh/terminal/util.go:
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package terminal
import (
"bufio"
"fmt"
"os"
"syscall"
"unsafe"
)
type runeReaderState struct {
term syscall.Termios
buf *bufio.Reader
}
func newRuneReaderState(input *os.File) runeReaderState {
return runeReaderState{
buf: bufio.NewReader(input),
}
}
// For reading runes we just want to disable echo.
func (rr *RuneReader) SetTermMode() error {
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(rr.Input.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&rr.state.term)), 0, 0, 0); err != 0 {
return err
}
newState := rr.state.term
newState.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(rr.Input.Fd()), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
return err
}
return nil
}
func (rr *RuneReader) RestoreTermMode() error {
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(rr.Input.Fd()), ioctlWriteTermios, uintptr(unsafe.Pointer(&rr.state.term)), 0, 0, 0); err != 0 {
return err
}
return nil
}
func (rr *RuneReader) ReadRune() (rune, int, error) {
r, size, err := rr.state.buf.ReadRune()
if err != nil {
return r, size, err
}
// parse ^[ sequences to look for arrow keys
if r == '\033' {
r, size, err = rr.state.buf.ReadRune()
if err != nil {
return r, size, err
}
if r != '[' {
return r, size, fmt.Errorf("Unexpected Escape Sequence: %q", []rune{'\033', r})
}
r, size, err = rr.state.buf.ReadRune()
if err != nil {
return r, size, err
}
switch r {
case 'D':
return KeyArrowLeft, 1, nil
case 'C':
return KeyArrowRight, 1, nil
case 'A':
return KeyArrowUp, 1, nil
case 'B':
return KeyArrowDown, 1, nil
}
return r, size, fmt.Errorf("Unknown Escape Sequence: %q", []rune{'\033', '[', r})
}
return r, size, err
}
+130
View File
@@ -0,0 +1,130 @@
package terminal
import (
"os"
"syscall"
"unsafe"
)
var (
dll = syscall.NewLazyDLL("kernel32.dll")
setConsoleMode = dll.NewProc("SetConsoleMode")
getConsoleMode = dll.NewProc("GetConsoleMode")
readConsoleInput = dll.NewProc("ReadConsoleInputW")
)
const (
EVENT_KEY = 0x0001
// key codes for arrow keys
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
VK_LEFT = 0x25
VK_UP = 0x26
VK_RIGHT = 0x27
VK_DOWN = 0x28
RIGHT_CTRL_PRESSED = 0x0004
LEFT_CTRL_PRESSED = 0x0008
ENABLE_ECHO_INPUT uint32 = 0x0004
ENABLE_LINE_INPUT uint32 = 0x0002
ENABLE_PROCESSED_INPUT uint32 = 0x0001
)
type inputRecord struct {
eventType uint16
padding uint16
event [16]byte
}
type keyEventRecord struct {
bKeyDown int32
wRepeatCount uint16
wVirtualKeyCode uint16
wVirtualScanCode uint16
unicodeChar uint16
wdControlKeyState uint32
}
type runeReaderState struct {
term uint32
}
func newRuneReaderState(input *os.File) runeReaderState {
return runeReaderState{}
}
func (rr *RuneReader) SetTermMode() error {
r, _, err := getConsoleMode.Call(uintptr(rr.Input.Fd()), uintptr(unsafe.Pointer(&rr.state.term)))
// windows return 0 on error
if r == 0 {
return err
}
newState := rr.state.term
newState &^= ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT
r, _, err = setConsoleMode.Call(uintptr(rr.Input.Fd()), uintptr(newState))
// windows return 0 on error
if r == 0 {
return err
}
return nil
}
func (rr *RuneReader) RestoreTermMode() error {
r, _, err := setConsoleMode.Call(uintptr(rr.Input.Fd()), uintptr(rr.state.term))
// windows return 0 on error
if r == 0 {
return err
}
return nil
}
func (rr *RuneReader) ReadRune() (rune, int, error) {
ir := &inputRecord{}
bytesRead := 0
for {
rv, _, e := readConsoleInput.Call(rr.Input.Fd(), uintptr(unsafe.Pointer(ir)), 1, uintptr(unsafe.Pointer(&bytesRead)))
// windows returns non-zero to indicate success
if rv == 0 && e != nil {
return 0, 0, e
}
if ir.eventType != EVENT_KEY {
continue
}
// the event data is really a c struct union, so here we have to do an usafe
// cast to put the data into the keyEventRecord (since we have already verified
// above that this event does correspond to a key event
key := (*keyEventRecord)(unsafe.Pointer(&ir.event[0]))
// we only care about key down events
if key.bKeyDown == 0 {
continue
}
if key.wdControlKeyState&(LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED) != 0 && key.unicodeChar == 'C' {
return KeyInterrupt, bytesRead, nil
}
// not a normal character so look up the input sequence from the
// virtual key code mappings (VK_*)
if key.unicodeChar == 0 {
switch key.wVirtualKeyCode {
case VK_DOWN:
return KeyArrowDown, bytesRead, nil
case VK_LEFT:
return KeyArrowLeft, bytesRead, nil
case VK_RIGHT:
return KeyArrowRight, bytesRead, nil
case VK_UP:
return KeyArrowUp, bytesRead, nil
default:
// not a virtual key that we care about so just continue on to
// the next input key
continue
}
}
r := rune(key.unicodeChar)
return r, bytesRead, nil
}
}
+18
View File
@@ -0,0 +1,18 @@
package terminal
const (
KeyArrowLeft = '\x02'
KeyArrowRight = '\x06'
KeyArrowUp = '\x10'
KeyArrowDown = '\x0e'
KeySpace = ' '
KeyEnter = '\r'
KeyBackspace = '\b'
KeyDelete = '\x7f'
KeyInterrupt = '\x03'
KeyEndTransmission = '\x04'
)
func soundBell() {
Print("\a")
}
+39
View File
@@ -0,0 +1,39 @@
package terminal
import (
"syscall"
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo")
procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo")
)
type wchar uint16
type dword uint32
type word uint16
type smallRect struct {
left Short
top Short
right Short
bottom Short
}
type consoleScreenBufferInfo struct {
size Coord
cursorPosition Coord
attributes word
window smallRect
maximumWindowSize Coord
}
type consoleCursorInfo struct {
size dword
visible int32
}
+8
View File
@@ -0,0 +1,8 @@
package terminal
type Short int16
type Coord struct {
X Short
Y Short
}