attach exec via SDK

This commit is contained in:
Jesse Duffield 2022-05-12 22:26:59 +10:00
parent 011ee89999
commit 7dd205535b
60 changed files with 5683 additions and 10 deletions

5
go.mod
View file

@ -18,6 +18,8 @@ require (
github.com/jesseduffield/yaml v0.0.0-20190702115811-b900b7e08b56
github.com/mcuadros/go-lookup v0.0.0-20171110082742-5650f26be767
github.com/mgutz/str v1.2.0
github.com/micmonay/keybd_event v1.1.1
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6
github.com/samber/lo v1.20.0
github.com/sirupsen/logrus v1.4.2
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad
@ -26,6 +28,7 @@ require (
)
require (
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Microsoft/go-winio v0.4.14 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/distribution v2.7.1+incompatible // indirect
@ -34,12 +37,12 @@ require (
github.com/gdamore/encoding v1.0.0 // indirect
github.com/gdamore/tcell/v2 v2.5.1 // indirect
github.com/gogo/protobuf v1.3.1 // indirect
github.com/google/go-cmp v0.5.5 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-colorable v0.1.4 // indirect
github.com/mattn/go-isatty v0.0.11 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect
github.com/onsi/ginkgo v1.8.0 // indirect
github.com/onsi/gomega v1.5.0 // indirect

3
go.sum
View file

@ -8,6 +8,7 @@ github.com/boz/go-throttle v0.0.0-20160922054636-fdc4eab740c1 h1:1fx+RA5lk1ZkzPA
github.com/boz/go-throttle v0.0.0-20160922054636-fdc4eab740c1/go.mod h1:z0nyIb42Zs97wyX1V+8MbEFhHeTw1OgFQfR6q57ZuHc=
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do=
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc=
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@ -75,6 +76,8 @@ github.com/mcuadros/go-lookup v0.0.0-20171110082742-5650f26be767 h1:BrhJNdEFWGui
github.com/mcuadros/go-lookup v0.0.0-20171110082742-5650f26be767/go.mod h1:ct+byCpkFokm4J0tiuAvB8cf2ttm6GcCe89Yr25nGKg=
github.com/mgutz/str v1.2.0 h1:4IzWSdIz9qPQWLfKZ0rJcV0jcUDpxvP4JVZ4GXQyvSw=
github.com/mgutz/str v1.2.0/go.mod h1:w1v0ofgLaJdoD0HpQ3fycxKD1WtxpjSo151pK/31q6w=
github.com/micmonay/keybd_event v1.1.1 h1:rv7omwXWYL9Lgf3PUq6uBgJI2k1yGkL/GD6dxc6nmSs=
github.com/micmonay/keybd_event v1.1.1/go.mod h1:CGMWMDNgsfPljzrAWoybUOSKafQPZpv+rLigt2LzNGI=
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc=
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE=

46
pkg/commands/attaching.go Normal file
View file

@ -0,0 +1,46 @@
package commands
import (
"context"
"github.com/docker/docker/api/types"
"github.com/jesseduffield/lazydocker/pkg/commands/streamer"
)
// AttachExecContainer attach container
func (c *DockerCommand) AttachExecContainer(id string, cmd []string) error {
exec, err := c.createExec(id, cmd)
if err != nil {
return err
}
ctx := context.TODO()
resp, err := c.Client.ContainerExecAttach(ctx, exec.ID, types.ExecStartCheck{Tty: true})
if err != nil {
return err
}
defer resp.Close()
f := func(ctx context.Context, id string, options types.ResizeOptions) error {
return c.Client.ContainerExecResize(ctx, id, options)
}
s := streamer.New(c.Log)
if err := s.Stream(ctx, exec.ID, resp, streamer.ResizeContainer(f)); err != nil {
return err
}
return nil
}
// createExec container exec create
func (c *DockerCommand) createExec(containerId string, cmd []string) (types.IDResponse, error) {
return c.Client.ContainerExecCreate(context.TODO(), containerId, types.ExecConfig{
Tty: true,
AttachStdin: true,
AttachStderr: true,
AttachStdout: true,
Cmd: cmd,
})
}

View file

@ -0,0 +1,15 @@
package streamer
import "github.com/moby/term"
type CommonStream struct {
Fd uintptr
IsTerminal bool
State *term.State
}
func (s *CommonStream) RestoreTerminal() {
if s.State != nil {
term.RestoreTerminal(s.Fd, s.State)
}
}

View file

@ -0,0 +1,44 @@
package streamer
import (
"io"
"github.com/moby/term"
)
type In struct {
CommonStream
in io.ReadCloser
}
func (i *In) Read(p []byte) (int, error) {
return i.in.Read(p)
}
func (i *In) Close() error {
return i.in.Close()
}
func (i *In) SetRawTerminal() error {
var err error
i.CommonStream.State, err = term.SetRawTerminal(i.Fd)
return err
}
func (i *In) RestoreTerminal() error {
if i.CommonStream.State == nil {
return nil
}
return term.RestoreTerminal(i.CommonStream.Fd, i.CommonStream.State)
}
func NewIn(in io.ReadCloser) *In {
fd, isTerminal := term.GetFdInfo(in)
return &In{
in: in,
CommonStream: CommonStream{
Fd: fd,
IsTerminal: isTerminal,
},
}
}

View file

@ -0,0 +1,40 @@
package streamer
import (
"io"
"log"
"github.com/moby/term"
)
type Out struct {
CommonStream
out io.Writer
}
func (o *Out) Write(p []byte) (int, error) {
return o.out.Write(p)
}
func (o *Out) GetTtySize() (uint, uint) {
if !o.IsTerminal {
return 0, 0
}
ws, err := term.GetWinsize(o.Fd)
if err != nil {
log.Printf("getting tty size: %s\n", err)
return 0, 0
}
return uint(ws.Height), uint(ws.Width)
}
func NewOut(out io.Writer) *Out {
fd, isTerminal := term.GetFdInfo(out)
return &Out{
out: out,
CommonStream: CommonStream{
Fd: fd,
IsTerminal: isTerminal,
},
}
}

View file

@ -0,0 +1,185 @@
// adapted from Skanehira's docui package which is no longer maintained
package streamer
import (
"context"
"errors"
"io"
"log"
"os"
"sync"
"time"
"github.com/docker/docker/api/types"
"github.com/moby/term"
"github.com/sirupsen/logrus"
)
type ResizeContainer func(ctx context.Context, id string, options types.ResizeOptions) error
var (
ErrEmptyExecID = errors.New("empty exec id")
ErrTtySizeIsZero = errors.New("tty size is 0")
)
type Streamer struct {
In *In
Out *Out
Err io.Writer
isTty bool
Log *logrus.Entry
}
func New(logger *logrus.Entry) *Streamer {
return &Streamer{
In: NewIn(os.Stdin),
Out: NewOut(os.Stdout),
Err: os.Stderr,
Log: logger,
}
}
func (s *Streamer) Stream(ctx context.Context, id string, resp types.HijackedResponse, resize ResizeContainer) (err error) {
if id == "" {
return ErrEmptyExecID
}
errCh := make(chan error, 1)
go func() {
defer close(errCh)
errCh <- s.stream(ctx, resp)
}()
if s.In.IsTerminal {
s.monitorTtySize(ctx, resize, id)
}
if err := <-errCh; err != nil {
s.Log.Errorf("stream error: %s", err)
return err
}
return nil
}
func (s *Streamer) stream(ctx context.Context, resp types.HijackedResponse) error {
// set raw mode
restore, err := s.SetRawTerminal()
if err != nil {
return err
}
defer restore()
// start stdin/stdout stream
outDone := s.streamOut(restore, resp)
inDone := s.streamIn(restore, resp)
select {
case err := <-outDone:
return err
case <-inDone:
select {
case err := <-outDone:
return err
case <-ctx.Done():
return ctx.Err()
}
case <-ctx.Done():
return ctx.Err()
}
}
func (s *Streamer) streamIn(restore func(), resp types.HijackedResponse) <-chan struct{} {
done := make(chan struct{})
go func() {
s.Log.Warn("in streamIn")
defer close(done)
defer restore()
_, err := io.Copy(resp.Conn, s.In)
if _, ok := err.(term.EscapeError); ok {
s.Log.Warn("not returning from here")
return
}
if err != nil {
s.Log.Errorf("in stream error: %s", err)
return
}
if err := resp.CloseWrite(); err != nil {
s.Log.Errorf("close response error: %s", err)
}
}()
return done
}
func (s *Streamer) streamOut(restore func(), resp types.HijackedResponse) <-chan error {
done := make(chan error, 1)
go func() {
_, err := io.Copy(s.Out, resp.Reader)
restore()
if err != nil {
s.Log.Errorf("output stream error: %s", err)
return
}
done <- err
}()
return done
}
func (s *Streamer) SetRawTerminal() (func(), error) {
if err := s.In.SetRawTerminal(); err != nil {
return nil, err
}
var once sync.Once
restore := func() {
once.Do(func() {
if err := s.In.RestoreTerminal(); err != nil {
s.Log.Errorf("failed to restore terminal: %s\n", err)
}
})
}
return restore, nil
}
func (s *Streamer) resizeTty(ctx context.Context, resize ResizeContainer, id string) error {
h, w := s.Out.GetTtySize()
if h == 0 && w == 0 {
return ErrTtySizeIsZero
}
options := types.ResizeOptions{
Height: h,
Width: w,
}
return resize(ctx, id, options)
}
func (s *Streamer) initTtySize(ctx context.Context, resize ResizeContainer, id string) {
if err := s.resizeTty(ctx, resize, id); err != nil {
go func() {
s.Log.Errorf("failed to resize tty: %s\n", err)
for retry := 0; retry < 5; retry++ {
time.Sleep(10 * time.Millisecond)
if err = s.resizeTty(ctx, resize, id); err == nil {
break
}
}
if err != nil {
log.Println("failed to resize tty, using default size")
}
}()
}
}

View file

@ -0,0 +1,22 @@
//go:build !windows
// +build !windows
package streamer
import (
"context"
"os"
"os/signal"
"syscall"
)
func (s *Streamer) monitorTtySize(ctx context.Context, resize ResizeContainer, id string) {
s.initTtySize(ctx, resize, id)
sigchan := make(chan os.Signal, 1)
signal.Notify(sigchan, syscall.SIGWINCH)
go func() {
for range sigchan {
_ = s.resizeTty(ctx, resize, id)
}
}()
}

View file

@ -0,0 +1,21 @@
//go:build windows
// +build windows
package streamer
import (
"context"
)
func (s *Streamer) monitorTtySize(ctx context.Context, resize ResizeContainer, id string) {
/* TODO: mattn: Currently, this is not supported on Windows.
s.initTtySize(ctx, resize, id)
sigchan := make(chan os.Signal, 1)
signal.Notify(sigchan, syscall.SIGWINCH)
go func() {
for range sigchan {
s.resizeTty(ctx, resize, id)
}
}()
*/
}

View file

@ -523,16 +523,28 @@ func (gui *Gui) handleContainersExecShell(g *gocui.Gui, v *gocui.View) error {
if err != nil {
return nil
}
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{
Container: container,
})
// TODO: use SDK
resolvedCommand := utils.ApplyTemplate("docker exec -it {{ .Container.ID }} /bin/sh -c 'eval $(grep ^$(id -un): /etc/passwd | cut -d : -f 7-)'", commandObject)
// attach and return the subprocess error
cmd := gui.OSCommand.ExecutableFromString(resolvedCommand)
gui.SubProcess = cmd
return gui.Errors.ErrSubProcess
if err := gui.g.Suspend(); err != nil {
gui.Log.Error(err)
return nil
}
defer func() {
if err := gui.g.Resume(); err != nil {
gui.Log.Error(err)
}
}()
err = gui.DockerCommand.AttachExecContainer(
container.ID,
[]string{"/bin/sh", "-c", "eval $(grep ^$(id -un): /etc/passwd | cut -d : -f 7-)"},
)
if err != nil {
gui.ErrorChan <- err
}
return nil
}
func (gui *Gui) handleContainersCustomCommand(g *gocui.Gui, v *gocui.View) error {

21
vendor/github.com/Azure/go-ansiterm/LICENSE generated vendored Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Microsoft Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

12
vendor/github.com/Azure/go-ansiterm/README.md generated vendored Normal file
View file

@ -0,0 +1,12 @@
# go-ansiterm
This is a cross platform Ansi Terminal Emulation library. It reads a stream of Ansi characters and produces the appropriate function calls. The results of the function calls are platform dependent.
For example the parser might receive "ESC, [, A" as a stream of three characters. This is the code for Cursor Up (http://www.vt100.net/docs/vt510-rm/CUU). The parser then calls the cursor up function (CUU()) on an event handler. The event handler determines what platform specific work must be done to cause the cursor to move up one position.
The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go).
See parser_test.go for examples exercising the state machine and generating appropriate function calls.
-----
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

188
vendor/github.com/Azure/go-ansiterm/constants.go generated vendored Normal file
View file

@ -0,0 +1,188 @@
package ansiterm
const LogEnv = "DEBUG_TERMINAL"
// ANSI constants
// References:
// -- http://www.ecma-international.org/publications/standards/Ecma-048.htm
// -- http://man7.org/linux/man-pages/man4/console_codes.4.html
// -- http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html
// -- http://en.wikipedia.org/wiki/ANSI_escape_code
// -- http://vt100.net/emu/dec_ansi_parser
// -- http://vt100.net/emu/vt500_parser.svg
// -- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
// -- http://www.inwap.com/pdp10/ansicode.txt
const (
// ECMA-48 Set Graphics Rendition
// Note:
// -- Constants leading with an underscore (e.g., _ANSI_xxx) are unsupported or reserved
// -- Fonts could possibly be supported via SetCurrentConsoleFontEx
// -- Windows does not expose the per-window cursor (i.e., caret) blink times
ANSI_SGR_RESET = 0
ANSI_SGR_BOLD = 1
ANSI_SGR_DIM = 2
_ANSI_SGR_ITALIC = 3
ANSI_SGR_UNDERLINE = 4
_ANSI_SGR_BLINKSLOW = 5
_ANSI_SGR_BLINKFAST = 6
ANSI_SGR_REVERSE = 7
_ANSI_SGR_INVISIBLE = 8
_ANSI_SGR_LINETHROUGH = 9
_ANSI_SGR_FONT_00 = 10
_ANSI_SGR_FONT_01 = 11
_ANSI_SGR_FONT_02 = 12
_ANSI_SGR_FONT_03 = 13
_ANSI_SGR_FONT_04 = 14
_ANSI_SGR_FONT_05 = 15
_ANSI_SGR_FONT_06 = 16
_ANSI_SGR_FONT_07 = 17
_ANSI_SGR_FONT_08 = 18
_ANSI_SGR_FONT_09 = 19
_ANSI_SGR_FONT_10 = 20
_ANSI_SGR_DOUBLEUNDERLINE = 21
ANSI_SGR_BOLD_DIM_OFF = 22
_ANSI_SGR_ITALIC_OFF = 23
ANSI_SGR_UNDERLINE_OFF = 24
_ANSI_SGR_BLINK_OFF = 25
_ANSI_SGR_RESERVED_00 = 26
ANSI_SGR_REVERSE_OFF = 27
_ANSI_SGR_INVISIBLE_OFF = 28
_ANSI_SGR_LINETHROUGH_OFF = 29
ANSI_SGR_FOREGROUND_BLACK = 30
ANSI_SGR_FOREGROUND_RED = 31
ANSI_SGR_FOREGROUND_GREEN = 32
ANSI_SGR_FOREGROUND_YELLOW = 33
ANSI_SGR_FOREGROUND_BLUE = 34
ANSI_SGR_FOREGROUND_MAGENTA = 35
ANSI_SGR_FOREGROUND_CYAN = 36
ANSI_SGR_FOREGROUND_WHITE = 37
_ANSI_SGR_RESERVED_01 = 38
ANSI_SGR_FOREGROUND_DEFAULT = 39
ANSI_SGR_BACKGROUND_BLACK = 40
ANSI_SGR_BACKGROUND_RED = 41
ANSI_SGR_BACKGROUND_GREEN = 42
ANSI_SGR_BACKGROUND_YELLOW = 43
ANSI_SGR_BACKGROUND_BLUE = 44
ANSI_SGR_BACKGROUND_MAGENTA = 45
ANSI_SGR_BACKGROUND_CYAN = 46
ANSI_SGR_BACKGROUND_WHITE = 47
_ANSI_SGR_RESERVED_02 = 48
ANSI_SGR_BACKGROUND_DEFAULT = 49
// 50 - 65: Unsupported
ANSI_MAX_CMD_LENGTH = 4096
MAX_INPUT_EVENTS = 128
DEFAULT_WIDTH = 80
DEFAULT_HEIGHT = 24
ANSI_BEL = 0x07
ANSI_BACKSPACE = 0x08
ANSI_TAB = 0x09
ANSI_LINE_FEED = 0x0A
ANSI_VERTICAL_TAB = 0x0B
ANSI_FORM_FEED = 0x0C
ANSI_CARRIAGE_RETURN = 0x0D
ANSI_ESCAPE_PRIMARY = 0x1B
ANSI_ESCAPE_SECONDARY = 0x5B
ANSI_OSC_STRING_ENTRY = 0x5D
ANSI_COMMAND_FIRST = 0x40
ANSI_COMMAND_LAST = 0x7E
DCS_ENTRY = 0x90
CSI_ENTRY = 0x9B
OSC_STRING = 0x9D
ANSI_PARAMETER_SEP = ";"
ANSI_CMD_G0 = '('
ANSI_CMD_G1 = ')'
ANSI_CMD_G2 = '*'
ANSI_CMD_G3 = '+'
ANSI_CMD_DECPNM = '>'
ANSI_CMD_DECPAM = '='
ANSI_CMD_OSC = ']'
ANSI_CMD_STR_TERM = '\\'
KEY_CONTROL_PARAM_2 = ";2"
KEY_CONTROL_PARAM_3 = ";3"
KEY_CONTROL_PARAM_4 = ";4"
KEY_CONTROL_PARAM_5 = ";5"
KEY_CONTROL_PARAM_6 = ";6"
KEY_CONTROL_PARAM_7 = ";7"
KEY_CONTROL_PARAM_8 = ";8"
KEY_ESC_CSI = "\x1B["
KEY_ESC_N = "\x1BN"
KEY_ESC_O = "\x1BO"
FILL_CHARACTER = ' '
)
func getByteRange(start byte, end byte) []byte {
bytes := make([]byte, 0, 32)
for i := start; i <= end; i++ {
bytes = append(bytes, byte(i))
}
return bytes
}
var toGroundBytes = getToGroundBytes()
var executors = getExecuteBytes()
// SPACE 20+A0 hex Always and everywhere a blank space
// Intermediate 20-2F hex !"#$%&'()*+,-./
var intermeds = getByteRange(0x20, 0x2F)
// Parameters 30-3F hex 0123456789:;<=>?
// CSI Parameters 30-39, 3B hex 0123456789;
var csiParams = getByteRange(0x30, 0x3F)
var csiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...)
// Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
var upperCase = getByteRange(0x40, 0x5F)
// Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~
var lowerCase = getByteRange(0x60, 0x7E)
// Alphabetics 40-7E hex (all of upper and lower case)
var alphabetics = append(upperCase, lowerCase...)
var printables = getByteRange(0x20, 0x7F)
var escapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E)
var escapeToGroundBytes = getEscapeToGroundBytes()
// See http://www.vt100.net/emu/vt500_parser.png for description of the complex
// byte ranges below
func getEscapeToGroundBytes() []byte {
escapeToGroundBytes := getByteRange(0x30, 0x4F)
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x51, 0x57)...)
escapeToGroundBytes = append(escapeToGroundBytes, 0x59)
escapeToGroundBytes = append(escapeToGroundBytes, 0x5A)
escapeToGroundBytes = append(escapeToGroundBytes, 0x5C)
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x60, 0x7E)...)
return escapeToGroundBytes
}
func getExecuteBytes() []byte {
executeBytes := getByteRange(0x00, 0x17)
executeBytes = append(executeBytes, 0x19)
executeBytes = append(executeBytes, getByteRange(0x1C, 0x1F)...)
return executeBytes
}
func getToGroundBytes() []byte {
groundBytes := []byte{0x18}
groundBytes = append(groundBytes, 0x1A)
groundBytes = append(groundBytes, getByteRange(0x80, 0x8F)...)
groundBytes = append(groundBytes, getByteRange(0x91, 0x97)...)
groundBytes = append(groundBytes, 0x99)
groundBytes = append(groundBytes, 0x9A)
groundBytes = append(groundBytes, 0x9C)
return groundBytes
}
// Delete 7F hex Always and everywhere ignored
// C1 Control 80-9F hex 32 additional control characters
// G1 Displayable A1-FE hex 94 additional displayable characters
// Special A0+FF hex Same as SPACE and DELETE

7
vendor/github.com/Azure/go-ansiterm/context.go generated vendored Normal file
View file

@ -0,0 +1,7 @@
package ansiterm
type ansiContext struct {
currentChar byte
paramBuffer []byte
interBuffer []byte
}

49
vendor/github.com/Azure/go-ansiterm/csi_entry_state.go generated vendored Normal file
View file

@ -0,0 +1,49 @@
package ansiterm
type csiEntryState struct {
baseState
}
func (csiState csiEntryState) Handle(b byte) (s state, e error) {
csiState.parser.logf("CsiEntry::Handle %#x", b)
nextState, err := csiState.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case sliceContains(alphabetics, b):
return csiState.parser.ground, nil
case sliceContains(csiCollectables, b):
return csiState.parser.csiParam, nil
case sliceContains(executors, b):
return csiState, csiState.parser.execute()
}
return csiState, nil
}
func (csiState csiEntryState) Transition(s state) error {
csiState.parser.logf("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name())
csiState.baseState.Transition(s)
switch s {
case csiState.parser.ground:
return csiState.parser.csiDispatch()
case csiState.parser.csiParam:
switch {
case sliceContains(csiParams, csiState.parser.context.currentChar):
csiState.parser.collectParam()
case sliceContains(intermeds, csiState.parser.context.currentChar):
csiState.parser.collectInter()
}
}
return nil
}
func (csiState csiEntryState) Enter() error {
csiState.parser.clear()
return nil
}

38
vendor/github.com/Azure/go-ansiterm/csi_param_state.go generated vendored Normal file
View file

@ -0,0 +1,38 @@
package ansiterm
type csiParamState struct {
baseState
}
func (csiState csiParamState) Handle(b byte) (s state, e error) {
csiState.parser.logf("CsiParam::Handle %#x", b)
nextState, err := csiState.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case sliceContains(alphabetics, b):
return csiState.parser.ground, nil
case sliceContains(csiCollectables, b):
csiState.parser.collectParam()
return csiState, nil
case sliceContains(executors, b):
return csiState, csiState.parser.execute()
}
return csiState, nil
}
func (csiState csiParamState) Transition(s state) error {
csiState.parser.logf("CsiParam::Transition %s --> %s", csiState.Name(), s.Name())
csiState.baseState.Transition(s)
switch s {
case csiState.parser.ground:
return csiState.parser.csiDispatch()
}
return nil
}

View file

@ -0,0 +1,36 @@
package ansiterm
type escapeIntermediateState struct {
baseState
}
func (escState escapeIntermediateState) Handle(b byte) (s state, e error) {
escState.parser.logf("escapeIntermediateState::Handle %#x", b)
nextState, err := escState.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case sliceContains(intermeds, b):
return escState, escState.parser.collectInter()
case sliceContains(executors, b):
return escState, escState.parser.execute()
case sliceContains(escapeIntermediateToGroundBytes, b):
return escState.parser.ground, nil
}
return escState, nil
}
func (escState escapeIntermediateState) Transition(s state) error {
escState.parser.logf("escapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name())
escState.baseState.Transition(s)
switch s {
case escState.parser.ground:
return escState.parser.escDispatch()
}
return nil
}

47
vendor/github.com/Azure/go-ansiterm/escape_state.go generated vendored Normal file
View file

@ -0,0 +1,47 @@
package ansiterm
type escapeState struct {
baseState
}
func (escState escapeState) Handle(b byte) (s state, e error) {
escState.parser.logf("escapeState::Handle %#x", b)
nextState, err := escState.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case b == ANSI_ESCAPE_SECONDARY:
return escState.parser.csiEntry, nil
case b == ANSI_OSC_STRING_ENTRY:
return escState.parser.oscString, nil
case sliceContains(executors, b):
return escState, escState.parser.execute()
case sliceContains(escapeToGroundBytes, b):
return escState.parser.ground, nil
case sliceContains(intermeds, b):
return escState.parser.escapeIntermediate, nil
}
return escState, nil
}
func (escState escapeState) Transition(s state) error {
escState.parser.logf("Escape::Transition %s --> %s", escState.Name(), s.Name())
escState.baseState.Transition(s)
switch s {
case escState.parser.ground:
return escState.parser.escDispatch()
case escState.parser.escapeIntermediate:
return escState.parser.collectInter()
}
return nil
}
func (escState escapeState) Enter() error {
escState.parser.clear()
return nil
}

90
vendor/github.com/Azure/go-ansiterm/event_handler.go generated vendored Normal file
View file

@ -0,0 +1,90 @@
package ansiterm
type AnsiEventHandler interface {
// Print
Print(b byte) error
// Execute C0 commands
Execute(b byte) error
// CUrsor Up
CUU(int) error
// CUrsor Down
CUD(int) error
// CUrsor Forward
CUF(int) error
// CUrsor Backward
CUB(int) error
// Cursor to Next Line
CNL(int) error
// Cursor to Previous Line
CPL(int) error
// Cursor Horizontal position Absolute
CHA(int) error
// Vertical line Position Absolute
VPA(int) error
// CUrsor Position
CUP(int, int) error
// Horizontal and Vertical Position (depends on PUM)
HVP(int, int) error
// Text Cursor Enable Mode
DECTCEM(bool) error
// Origin Mode
DECOM(bool) error
// 132 Column Mode
DECCOLM(bool) error
// Erase in Display
ED(int) error
// Erase in Line
EL(int) error
// Insert Line
IL(int) error
// Delete Line
DL(int) error
// Insert Character
ICH(int) error
// Delete Character
DCH(int) error
// Set Graphics Rendition
SGR([]int) error
// Pan Down
SU(int) error
// Pan Up
SD(int) error
// Device Attributes
DA([]string) error
// Set Top and Bottom Margins
DECSTBM(int, int) error
// Index
IND() error
// Reverse Index
RI() error
// Flush updates from previous commands
Flush() error
}

24
vendor/github.com/Azure/go-ansiterm/ground_state.go generated vendored Normal file
View file

@ -0,0 +1,24 @@
package ansiterm
type groundState struct {
baseState
}
func (gs groundState) Handle(b byte) (s state, e error) {
gs.parser.context.currentChar = b
nextState, err := gs.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case sliceContains(printables, b):
return gs, gs.parser.print()
case sliceContains(executors, b):
return gs, gs.parser.execute()
}
return gs, nil
}

View file

@ -0,0 +1,31 @@
package ansiterm
type oscStringState struct {
baseState
}
func (oscState oscStringState) Handle(b byte) (s state, e error) {
oscState.parser.logf("OscString::Handle %#x", b)
nextState, err := oscState.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case isOscStringTerminator(b):
return oscState.parser.ground, nil
}
return oscState, nil
}
// See below for OSC string terminators for linux
// http://man7.org/linux/man-pages/man4/console_codes.4.html
func isOscStringTerminator(b byte) bool {
if b == ANSI_BEL || b == 0x5C {
return true
}
return false
}

151
vendor/github.com/Azure/go-ansiterm/parser.go generated vendored Normal file
View file

@ -0,0 +1,151 @@
package ansiterm
import (
"errors"
"log"
"os"
)
type AnsiParser struct {
currState state
eventHandler AnsiEventHandler
context *ansiContext
csiEntry state
csiParam state
dcsEntry state
escape state
escapeIntermediate state
error state
ground state
oscString state
stateMap []state
logf func(string, ...interface{})
}
type Option func(*AnsiParser)
func WithLogf(f func(string, ...interface{})) Option {
return func(ap *AnsiParser) {
ap.logf = f
}
}
func CreateParser(initialState string, evtHandler AnsiEventHandler, opts ...Option) *AnsiParser {
ap := &AnsiParser{
eventHandler: evtHandler,
context: &ansiContext{},
}
for _, o := range opts {
o(ap)
}
if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" {
logFile, _ := os.Create("ansiParser.log")
logger := log.New(logFile, "", log.LstdFlags)
if ap.logf != nil {
l := ap.logf
ap.logf = func(s string, v ...interface{}) {
l(s, v...)
logger.Printf(s, v...)
}
} else {
ap.logf = logger.Printf
}
}
if ap.logf == nil {
ap.logf = func(string, ...interface{}) {}
}
ap.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: ap}}
ap.csiParam = csiParamState{baseState{name: "CsiParam", parser: ap}}
ap.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: ap}}
ap.escape = escapeState{baseState{name: "Escape", parser: ap}}
ap.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: ap}}
ap.error = errorState{baseState{name: "Error", parser: ap}}
ap.ground = groundState{baseState{name: "Ground", parser: ap}}
ap.oscString = oscStringState{baseState{name: "OscString", parser: ap}}
ap.stateMap = []state{
ap.csiEntry,
ap.csiParam,
ap.dcsEntry,
ap.escape,
ap.escapeIntermediate,
ap.error,
ap.ground,
ap.oscString,
}
ap.currState = getState(initialState, ap.stateMap)
ap.logf("CreateParser: parser %p", ap)
return ap
}
func getState(name string, states []state) state {
for _, el := range states {
if el.Name() == name {
return el
}
}
return nil
}
func (ap *AnsiParser) Parse(bytes []byte) (int, error) {
for i, b := range bytes {
if err := ap.handle(b); err != nil {
return i, err
}
}
return len(bytes), ap.eventHandler.Flush()
}
func (ap *AnsiParser) handle(b byte) error {
ap.context.currentChar = b
newState, err := ap.currState.Handle(b)
if err != nil {
return err
}
if newState == nil {
ap.logf("WARNING: newState is nil")
return errors.New("New state of 'nil' is invalid.")
}
if newState != ap.currState {
if err := ap.changeState(newState); err != nil {
return err
}
}
return nil
}
func (ap *AnsiParser) changeState(newState state) error {
ap.logf("ChangeState %s --> %s", ap.currState.Name(), newState.Name())
// Exit old state
if err := ap.currState.Exit(); err != nil {
ap.logf("Exit state '%s' failed with : '%v'", ap.currState.Name(), err)
return err
}
// Perform transition action
if err := ap.currState.Transition(newState); err != nil {
ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err)
return err
}
// Enter new state
if err := newState.Enter(); err != nil {
ap.logf("Enter state '%s' failed with: '%v'", newState.Name(), err)
return err
}
ap.currState = newState
return nil
}

View file

@ -0,0 +1,99 @@
package ansiterm
import (
"strconv"
)
func parseParams(bytes []byte) ([]string, error) {
paramBuff := make([]byte, 0, 0)
params := []string{}
for _, v := range bytes {
if v == ';' {
if len(paramBuff) > 0 {
// Completed parameter, append it to the list
s := string(paramBuff)
params = append(params, s)
paramBuff = make([]byte, 0, 0)
}
} else {
paramBuff = append(paramBuff, v)
}
}
// Last parameter may not be terminated with ';'
if len(paramBuff) > 0 {
s := string(paramBuff)
params = append(params, s)
}
return params, nil
}
func parseCmd(context ansiContext) (string, error) {
return string(context.currentChar), nil
}
func getInt(params []string, dflt int) int {
i := getInts(params, 1, dflt)[0]
return i
}
func getInts(params []string, minCount int, dflt int) []int {
ints := []int{}
for _, v := range params {
i, _ := strconv.Atoi(v)
// Zero is mapped to the default value in VT100.
if i == 0 {
i = dflt
}
ints = append(ints, i)
}
if len(ints) < minCount {
remaining := minCount - len(ints)
for i := 0; i < remaining; i++ {
ints = append(ints, dflt)
}
}
return ints
}
func (ap *AnsiParser) modeDispatch(param string, set bool) error {
switch param {
case "?3":
return ap.eventHandler.DECCOLM(set)
case "?6":
return ap.eventHandler.DECOM(set)
case "?25":
return ap.eventHandler.DECTCEM(set)
}
return nil
}
func (ap *AnsiParser) hDispatch(params []string) error {
if len(params) == 1 {
return ap.modeDispatch(params[0], true)
}
return nil
}
func (ap *AnsiParser) lDispatch(params []string) error {
if len(params) == 1 {
return ap.modeDispatch(params[0], false)
}
return nil
}
func getEraseParam(params []string) int {
param := getInt(params, 0)
if param < 0 || 3 < param {
param = 0
}
return param
}

119
vendor/github.com/Azure/go-ansiterm/parser_actions.go generated vendored Normal file
View file

@ -0,0 +1,119 @@
package ansiterm
func (ap *AnsiParser) collectParam() error {
currChar := ap.context.currentChar
ap.logf("collectParam %#x", currChar)
ap.context.paramBuffer = append(ap.context.paramBuffer, currChar)
return nil
}
func (ap *AnsiParser) collectInter() error {
currChar := ap.context.currentChar
ap.logf("collectInter %#x", currChar)
ap.context.paramBuffer = append(ap.context.interBuffer, currChar)
return nil
}
func (ap *AnsiParser) escDispatch() error {
cmd, _ := parseCmd(*ap.context)
intermeds := ap.context.interBuffer
ap.logf("escDispatch currentChar: %#x", ap.context.currentChar)
ap.logf("escDispatch: %v(%v)", cmd, intermeds)
switch cmd {
case "D": // IND
return ap.eventHandler.IND()
case "E": // NEL, equivalent to CRLF
err := ap.eventHandler.Execute(ANSI_CARRIAGE_RETURN)
if err == nil {
err = ap.eventHandler.Execute(ANSI_LINE_FEED)
}
return err
case "M": // RI
return ap.eventHandler.RI()
}
return nil
}
func (ap *AnsiParser) csiDispatch() error {
cmd, _ := parseCmd(*ap.context)
params, _ := parseParams(ap.context.paramBuffer)
ap.logf("Parsed params: %v with length: %d", params, len(params))
ap.logf("csiDispatch: %v(%v)", cmd, params)
switch cmd {
case "@":
return ap.eventHandler.ICH(getInt(params, 1))
case "A":
return ap.eventHandler.CUU(getInt(params, 1))
case "B":
return ap.eventHandler.CUD(getInt(params, 1))
case "C":
return ap.eventHandler.CUF(getInt(params, 1))
case "D":
return ap.eventHandler.CUB(getInt(params, 1))
case "E":
return ap.eventHandler.CNL(getInt(params, 1))
case "F":
return ap.eventHandler.CPL(getInt(params, 1))
case "G":
return ap.eventHandler.CHA(getInt(params, 1))
case "H":
ints := getInts(params, 2, 1)
x, y := ints[0], ints[1]
return ap.eventHandler.CUP(x, y)
case "J":
param := getEraseParam(params)
return ap.eventHandler.ED(param)
case "K":
param := getEraseParam(params)
return ap.eventHandler.EL(param)
case "L":
return ap.eventHandler.IL(getInt(params, 1))
case "M":
return ap.eventHandler.DL(getInt(params, 1))
case "P":
return ap.eventHandler.DCH(getInt(params, 1))
case "S":
return ap.eventHandler.SU(getInt(params, 1))
case "T":
return ap.eventHandler.SD(getInt(params, 1))
case "c":
return ap.eventHandler.DA(params)
case "d":
return ap.eventHandler.VPA(getInt(params, 1))
case "f":
ints := getInts(params, 2, 1)
x, y := ints[0], ints[1]
return ap.eventHandler.HVP(x, y)
case "h":
return ap.hDispatch(params)
case "l":
return ap.lDispatch(params)
case "m":
return ap.eventHandler.SGR(getInts(params, 1, 0))
case "r":
ints := getInts(params, 2, 1)
top, bottom := ints[0], ints[1]
return ap.eventHandler.DECSTBM(top, bottom)
default:
ap.logf("ERROR: Unsupported CSI command: '%s', with full context: %v", cmd, ap.context)
return nil
}
}
func (ap *AnsiParser) print() error {
return ap.eventHandler.Print(ap.context.currentChar)
}
func (ap *AnsiParser) clear() error {
ap.context = &ansiContext{}
return nil
}
func (ap *AnsiParser) execute() error {
return ap.eventHandler.Execute(ap.context.currentChar)
}

71
vendor/github.com/Azure/go-ansiterm/states.go generated vendored Normal file
View file

@ -0,0 +1,71 @@
package ansiterm
type stateID int
type state interface {
Enter() error
Exit() error
Handle(byte) (state, error)
Name() string
Transition(state) error
}
type baseState struct {
name string
parser *AnsiParser
}
func (base baseState) Enter() error {
return nil
}
func (base baseState) Exit() error {
return nil
}
func (base baseState) Handle(b byte) (s state, e error) {
switch {
case b == CSI_ENTRY:
return base.parser.csiEntry, nil
case b == DCS_ENTRY:
return base.parser.dcsEntry, nil
case b == ANSI_ESCAPE_PRIMARY:
return base.parser.escape, nil
case b == OSC_STRING:
return base.parser.oscString, nil
case sliceContains(toGroundBytes, b):
return base.parser.ground, nil
}
return nil, nil
}
func (base baseState) Name() string {
return base.name
}
func (base baseState) Transition(s state) error {
if s == base.parser.ground {
execBytes := []byte{0x18}
execBytes = append(execBytes, 0x1A)
execBytes = append(execBytes, getByteRange(0x80, 0x8F)...)
execBytes = append(execBytes, getByteRange(0x91, 0x97)...)
execBytes = append(execBytes, 0x99)
execBytes = append(execBytes, 0x9A)
if sliceContains(execBytes, base.parser.context.currentChar) {
return base.parser.execute()
}
}
return nil
}
type dcsEntryState struct {
baseState
}
type errorState struct {
baseState
}

21
vendor/github.com/Azure/go-ansiterm/utilities.go generated vendored Normal file
View file

@ -0,0 +1,21 @@
package ansiterm
import (
"strconv"
)
func sliceContains(bytes []byte, b byte) bool {
for _, v := range bytes {
if v == b {
return true
}
}
return false
}
func convertBytesToInteger(bytes []byte) int {
s := string(bytes)
i, _ := strconv.Atoi(s)
return i
}

196
vendor/github.com/Azure/go-ansiterm/winterm/ansi.go generated vendored Normal file
View file

@ -0,0 +1,196 @@
// +build windows
package winterm
import (
"fmt"
"os"
"strconv"
"strings"
"syscall"
"github.com/Azure/go-ansiterm"
windows "golang.org/x/sys/windows"
)
// 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
// syscall uses negative numbers
// windows package uses very big uint32
// Keep these switches split so we don't have to convert ints too much.
switch uint32(nFile) {
case windows.STD_INPUT_HANDLE:
file = os.Stdin
case windows.STD_OUTPUT_HANDLE:
file = os.Stdout
case windows.STD_ERROR_HANDLE:
file = os.Stderr
default:
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)
}

327
vendor/github.com/Azure/go-ansiterm/winterm/api.go generated vendored Normal file
View file

@ -0,0 +1,327 @@
// +build windows
package winterm
import (
"fmt"
"syscall"
"unsafe"
)
//===========================================================================================================
// IMPORTANT NOTE:
//
// The methods below make extensive use of the "unsafe" package to obtain the required pointers.
// Beginning in Go 1.3, the garbage collector may release local variables (e.g., incoming arguments, stack
// variables) the pointers reference *before* the API completes.
//
// As a result, in those cases, the code must hint that the variables remain in active by invoking the
// dummy method "use" (see below). Newer versions of Go are planned to change the mechanism to no longer
// require unsafe pointers.
//
// If you add or modify methods, ENSURE protection of local variables through the "use" builtin to inform
// the garbage collector the variables remain in use if:
//
// -- The value is not a pointer (e.g., int32, struct)
// -- The value is not referenced by the method after passing the pointer to Windows
//
// See http://golang.org/doc/go1.3.
//===========================================================================================================
var (
kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
getConsoleCursorInfoProc = kernel32DLL.NewProc("GetConsoleCursorInfo")
setConsoleCursorInfoProc = kernel32DLL.NewProc("SetConsoleCursorInfo")
setConsoleCursorPositionProc = kernel32DLL.NewProc("SetConsoleCursorPosition")
setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode")
getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize")
scrollConsoleScreenBufferProc = kernel32DLL.NewProc("ScrollConsoleScreenBufferA")
setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute")
setConsoleWindowInfoProc = kernel32DLL.NewProc("SetConsoleWindowInfo")
writeConsoleOutputProc = kernel32DLL.NewProc("WriteConsoleOutputW")
readConsoleInputProc = kernel32DLL.NewProc("ReadConsoleInputW")
waitForSingleObjectProc = kernel32DLL.NewProc("WaitForSingleObject")
)
// Windows Console constants
const (
// Console modes
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
ENABLE_PROCESSED_INPUT = 0x0001
ENABLE_LINE_INPUT = 0x0002
ENABLE_ECHO_INPUT = 0x0004
ENABLE_WINDOW_INPUT = 0x0008
ENABLE_MOUSE_INPUT = 0x0010
ENABLE_INSERT_MODE = 0x0020
ENABLE_QUICK_EDIT_MODE = 0x0040
ENABLE_EXTENDED_FLAGS = 0x0080
ENABLE_AUTO_POSITION = 0x0100
ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200
ENABLE_PROCESSED_OUTPUT = 0x0001
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
DISABLE_NEWLINE_AUTO_RETURN = 0x0008
ENABLE_LVB_GRID_WORLDWIDE = 0x0010
// Character attributes
// Note:
// -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan).
// Clearing all foreground or background colors results in black; setting all creates white.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes.
FOREGROUND_BLUE uint16 = 0x0001
FOREGROUND_GREEN uint16 = 0x0002
FOREGROUND_RED uint16 = 0x0004
FOREGROUND_INTENSITY uint16 = 0x0008
FOREGROUND_MASK uint16 = 0x000F
BACKGROUND_BLUE uint16 = 0x0010
BACKGROUND_GREEN uint16 = 0x0020
BACKGROUND_RED uint16 = 0x0040
BACKGROUND_INTENSITY uint16 = 0x0080
BACKGROUND_MASK uint16 = 0x00F0
COMMON_LVB_MASK uint16 = 0xFF00
COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000
COMMON_LVB_UNDERSCORE uint16 = 0x8000
// Input event types
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
KEY_EVENT = 0x0001
MOUSE_EVENT = 0x0002
WINDOW_BUFFER_SIZE_EVENT = 0x0004
MENU_EVENT = 0x0008
FOCUS_EVENT = 0x0010
// WaitForSingleObject return codes
WAIT_ABANDONED = 0x00000080
WAIT_FAILED = 0xFFFFFFFF
WAIT_SIGNALED = 0x0000000
WAIT_TIMEOUT = 0x00000102
// WaitForSingleObject wait duration
WAIT_INFINITE = 0xFFFFFFFF
WAIT_ONE_SECOND = 1000
WAIT_HALF_SECOND = 500
WAIT_QUARTER_SECOND = 250
)
// Windows API Console types
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD)
// -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment
type (
CHAR_INFO struct {
UnicodeChar uint16
Attributes uint16
}
CONSOLE_CURSOR_INFO struct {
Size uint32
Visible int32
}
CONSOLE_SCREEN_BUFFER_INFO struct {
Size COORD
CursorPosition COORD
Attributes uint16
Window SMALL_RECT
MaximumWindowSize COORD
}
COORD struct {
X int16
Y int16
}
SMALL_RECT struct {
Left int16
Top int16
Right int16
Bottom int16
}
// INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
INPUT_RECORD struct {
EventType uint16
KeyEvent KEY_EVENT_RECORD
}
KEY_EVENT_RECORD struct {
KeyDown int32
RepeatCount uint16
VirtualKeyCode uint16
VirtualScanCode uint16
UnicodeChar uint16
ControlKeyState uint32
}
WINDOW_BUFFER_SIZE struct {
Size COORD
}
)
// boolToBOOL converts a Go bool into a Windows int32.
func boolToBOOL(f bool) int32 {
if f {
return int32(1)
} else {
return int32(0)
}
}
// GetConsoleCursorInfo retrieves information about the size and visiblity of the console cursor.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683163(v=vs.85).aspx.
func GetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
r1, r2, err := getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
return checkError(r1, r2, err)
}
// SetConsoleCursorInfo sets the size and visiblity of the console cursor.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx.
func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
r1, r2, err := setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
return checkError(r1, r2, err)
}
// SetConsoleCursorPosition location of the console cursor.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx.
func SetConsoleCursorPosition(handle uintptr, coord COORD) error {
r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord))
use(coord)
return checkError(r1, r2, err)
}
// GetConsoleMode gets the console mode for given file descriptor
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx.
func GetConsoleMode(handle uintptr) (mode uint32, err error) {
err = syscall.GetConsoleMode(syscall.Handle(handle), &mode)
return mode, err
}
// SetConsoleMode sets the console mode for given file descriptor
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
func SetConsoleMode(handle uintptr, mode uint32) error {
r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0)
use(mode)
return checkError(r1, r2, err)
}
// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer.
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx.
func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
info := CONSOLE_SCREEN_BUFFER_INFO{}
err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0))
if err != nil {
return nil, err
}
return &info, nil
}
func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error {
r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char)))
use(scrollRect)
use(clipRect)
use(destOrigin)
use(char)
return checkError(r1, r2, err)
}
// SetConsoleScreenBufferSize sets the size of the console screen buffer.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx.
func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error {
r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord))
use(coord)
return checkError(r1, r2, err)
}
// SetConsoleTextAttribute sets the attributes of characters written to the
// console screen buffer by the WriteFile or WriteConsole function.
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx.
func SetConsoleTextAttribute(handle uintptr, attribute uint16) error {
r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0)
use(attribute)
return checkError(r1, r2, err)
}
// SetConsoleWindowInfo sets the size and position of the console screen buffer's window.
// Note that the size and location must be within and no larger than the backing console screen buffer.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx.
func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error {
r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect)))
use(isAbsolute)
use(rect)
return checkError(r1, r2, err)
}
// WriteConsoleOutput writes the CHAR_INFOs from the provided buffer to the active console buffer.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx.
func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error {
r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion)))
use(buffer)
use(bufferSize)
use(bufferCoord)
return checkError(r1, r2, err)
}
// ReadConsoleInput reads (and removes) data from the console input buffer.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx.
func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error {
r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count)))
use(buffer)
return checkError(r1, r2, err)
}
// WaitForSingleObject waits for the passed handle to be signaled.
// It returns true if the handle was signaled; false otherwise.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx.
func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) {
r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait)))
switch r1 {
case WAIT_ABANDONED, WAIT_TIMEOUT:
return false, nil
case WAIT_SIGNALED:
return true, nil
}
use(msWait)
return false, err
}
// String helpers
func (info CONSOLE_SCREEN_BUFFER_INFO) String() string {
return fmt.Sprintf("Size(%v) Cursor(%v) Window(%v) Max(%v)", info.Size, info.CursorPosition, info.Window, info.MaximumWindowSize)
}
func (coord COORD) String() string {
return fmt.Sprintf("%v,%v", coord.X, coord.Y)
}
func (rect SMALL_RECT) String() string {
return fmt.Sprintf("(%v,%v),(%v,%v)", rect.Left, rect.Top, rect.Right, rect.Bottom)
}
// checkError evaluates the results of a Windows API call and returns the error if it failed.
func checkError(r1, r2 uintptr, err error) error {
// Windows APIs return non-zero to indicate success
if r1 != 0 {
return nil
}
// Return the error if provided, otherwise default to EINVAL
if err != nil {
return err
}
return syscall.EINVAL
}
// coordToPointer converts a COORD into a uintptr (by fooling the type system).
func coordToPointer(c COORD) uintptr {
// Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass.
return uintptr(*((*uint32)(unsafe.Pointer(&c))))
}
// use is a no-op, but the compiler cannot see that it is.
// Calling use(p) ensures that p is kept live until that point.
func use(p interface{}) {}

View file

@ -0,0 +1,100 @@
// +build windows
package winterm
import "github.com/Azure/go-ansiterm"
const (
FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
BACKGROUND_COLOR_MASK = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
)
// collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the
// request represented by the passed ANSI mode.
func collectAnsiIntoWindowsAttributes(windowsMode uint16, inverted bool, baseMode uint16, ansiMode int16) (uint16, bool) {
switch ansiMode {
// Mode styles
case ansiterm.ANSI_SGR_BOLD:
windowsMode = windowsMode | FOREGROUND_INTENSITY
case ansiterm.ANSI_SGR_DIM, ansiterm.ANSI_SGR_BOLD_DIM_OFF:
windowsMode &^= FOREGROUND_INTENSITY
case ansiterm.ANSI_SGR_UNDERLINE:
windowsMode = windowsMode | COMMON_LVB_UNDERSCORE
case ansiterm.ANSI_SGR_REVERSE:
inverted = true
case ansiterm.ANSI_SGR_REVERSE_OFF:
inverted = false
case ansiterm.ANSI_SGR_UNDERLINE_OFF:
windowsMode &^= COMMON_LVB_UNDERSCORE
// Foreground colors
case ansiterm.ANSI_SGR_FOREGROUND_DEFAULT:
windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK)
case ansiterm.ANSI_SGR_FOREGROUND_BLACK:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK)
case ansiterm.ANSI_SGR_FOREGROUND_RED:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED
case ansiterm.ANSI_SGR_FOREGROUND_GREEN:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN
case ansiterm.ANSI_SGR_FOREGROUND_YELLOW:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN
case ansiterm.ANSI_SGR_FOREGROUND_BLUE:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE
case ansiterm.ANSI_SGR_FOREGROUND_MAGENTA:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE
case ansiterm.ANSI_SGR_FOREGROUND_CYAN:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE
case ansiterm.ANSI_SGR_FOREGROUND_WHITE:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
// Background colors
case ansiterm.ANSI_SGR_BACKGROUND_DEFAULT:
// Black with no intensity
windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK)
case ansiterm.ANSI_SGR_BACKGROUND_BLACK:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK)
case ansiterm.ANSI_SGR_BACKGROUND_RED:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED
case ansiterm.ANSI_SGR_BACKGROUND_GREEN:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN
case ansiterm.ANSI_SGR_BACKGROUND_YELLOW:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN
case ansiterm.ANSI_SGR_BACKGROUND_BLUE:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE
case ansiterm.ANSI_SGR_BACKGROUND_MAGENTA:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE
case ansiterm.ANSI_SGR_BACKGROUND_CYAN:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE
case ansiterm.ANSI_SGR_BACKGROUND_WHITE:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
}
return windowsMode, inverted
}
// invertAttributes inverts the foreground and background colors of a Windows attributes value
func invertAttributes(windowsMode uint16) uint16 {
return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4)
}

View file

@ -0,0 +1,101 @@
// +build windows
package winterm
const (
horizontal = iota
vertical
)
func (h *windowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT {
if h.originMode {
sr := h.effectiveSr(info.Window)
return SMALL_RECT{
Top: sr.top,
Bottom: sr.bottom,
Left: 0,
Right: info.Size.X - 1,
}
} else {
return SMALL_RECT{
Top: info.Window.Top,
Bottom: info.Window.Bottom,
Left: 0,
Right: info.Size.X - 1,
}
}
}
// setCursorPosition sets the cursor to the specified position, bounded to the screen size
func (h *windowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error {
position.X = ensureInRange(position.X, window.Left, window.Right)
position.Y = ensureInRange(position.Y, window.Top, window.Bottom)
err := SetConsoleCursorPosition(h.fd, position)
if err != nil {
return err
}
h.logf("Cursor position set: (%d, %d)", position.X, position.Y)
return err
}
func (h *windowsAnsiEventHandler) moveCursorVertical(param int) error {
return h.moveCursor(vertical, param)
}
func (h *windowsAnsiEventHandler) moveCursorHorizontal(param int) error {
return h.moveCursor(horizontal, param)
}
func (h *windowsAnsiEventHandler) moveCursor(moveMode int, param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
position := info.CursorPosition
switch moveMode {
case horizontal:
position.X += int16(param)
case vertical:
position.Y += int16(param)
}
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
return err
}
return nil
}
func (h *windowsAnsiEventHandler) moveCursorLine(param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
position := info.CursorPosition
position.X = 0
position.Y += int16(param)
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
return err
}
return nil
}
func (h *windowsAnsiEventHandler) moveCursorColumn(param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
position := info.CursorPosition
position.X = int16(param) - 1
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
return err
}
return nil
}

View file

@ -0,0 +1,84 @@
// +build windows
package winterm
import "github.com/Azure/go-ansiterm"
func (h *windowsAnsiEventHandler) clearRange(attributes uint16, fromCoord COORD, toCoord COORD) error {
// Ignore an invalid (negative area) request
if toCoord.Y < fromCoord.Y {
return nil
}
var err error
var coordStart = COORD{}
var coordEnd = COORD{}
xCurrent, yCurrent := fromCoord.X, fromCoord.Y
xEnd, yEnd := toCoord.X, toCoord.Y
// Clear any partial initial line
if xCurrent > 0 {
coordStart.X, coordStart.Y = xCurrent, yCurrent
coordEnd.X, coordEnd.Y = xEnd, yCurrent
err = h.clearRect(attributes, coordStart, coordEnd)
if err != nil {
return err
}
xCurrent = 0
yCurrent += 1
}
// Clear intervening rectangular section
if yCurrent < yEnd {
coordStart.X, coordStart.Y = xCurrent, yCurrent
coordEnd.X, coordEnd.Y = xEnd, yEnd-1
err = h.clearRect(attributes, coordStart, coordEnd)
if err != nil {
return err
}
xCurrent = 0
yCurrent = yEnd
}
// Clear remaining partial ending line
coordStart.X, coordStart.Y = xCurrent, yCurrent
coordEnd.X, coordEnd.Y = xEnd, yEnd
err = h.clearRect(attributes, coordStart, coordEnd)
if err != nil {
return err
}
return nil
}
func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD, toCoord COORD) error {
region := SMALL_RECT{Top: fromCoord.Y, Left: fromCoord.X, Bottom: toCoord.Y, Right: toCoord.X}
width := toCoord.X - fromCoord.X + 1
height := toCoord.Y - fromCoord.Y + 1
size := uint32(width) * uint32(height)
if size <= 0 {
return nil
}
buffer := make([]CHAR_INFO, size)
char := CHAR_INFO{ansiterm.FILL_CHARACTER, attributes}
for i := 0; i < int(size); i++ {
buffer[i] = char
}
err := WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, &region)
if err != nil {
return err
}
return nil
}

View file

@ -0,0 +1,118 @@
// +build windows
package winterm
// effectiveSr gets the current effective scroll region in buffer coordinates
func (h *windowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion {
top := addInRange(window.Top, h.sr.top, window.Top, window.Bottom)
bottom := addInRange(window.Top, h.sr.bottom, window.Top, window.Bottom)
if top >= bottom {
top = window.Top
bottom = window.Bottom
}
return scrollRegion{top: top, bottom: bottom}
}
func (h *windowsAnsiEventHandler) scrollUp(param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
sr := h.effectiveSr(info.Window)
return h.scroll(param, sr, info)
}
func (h *windowsAnsiEventHandler) scrollDown(param int) error {
return h.scrollUp(-param)
}
func (h *windowsAnsiEventHandler) deleteLines(param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
start := info.CursorPosition.Y
sr := h.effectiveSr(info.Window)
// Lines cannot be inserted or deleted outside the scrolling region.
if start >= sr.top && start <= sr.bottom {
sr.top = start
return h.scroll(param, sr, info)
} else {
return nil
}
}
func (h *windowsAnsiEventHandler) insertLines(param int) error {
return h.deleteLines(-param)
}
// scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates.
func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error {
h.logf("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom)
h.logf("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom)
// Copy from and clip to the scroll region (full buffer width)
scrollRect := SMALL_RECT{
Top: sr.top,
Bottom: sr.bottom,
Left: 0,
Right: info.Size.X - 1,
}
// Origin to which area should be copied
destOrigin := COORD{
X: 0,
Y: sr.top - int16(param),
}
char := CHAR_INFO{
UnicodeChar: ' ',
Attributes: h.attributes,
}
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
return err
}
return nil
}
func (h *windowsAnsiEventHandler) deleteCharacters(param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
return h.scrollLine(param, info.CursorPosition, info)
}
func (h *windowsAnsiEventHandler) insertCharacters(param int) error {
return h.deleteCharacters(-param)
}
// scrollLine scrolls a line horizontally starting at the provided position by a number of columns.
func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error {
// Copy from and clip to the scroll region (full buffer width)
scrollRect := SMALL_RECT{
Top: position.Y,
Bottom: position.Y,
Left: position.X,
Right: info.Size.X - 1,
}
// Origin to which area should be copied
destOrigin := COORD{
X: position.X - int16(columns),
Y: position.Y,
}
char := CHAR_INFO{
UnicodeChar: ' ',
Attributes: h.attributes,
}
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
return err
}
return nil
}

View file

@ -0,0 +1,9 @@
// +build windows
package winterm
// AddInRange increments a value by the passed quantity while ensuring the values
// always remain within the supplied min / max range.
func addInRange(n int16, increment int16, min int16, max int16) int16 {
return ensureInRange(n+increment, min, max)
}

View file

@ -0,0 +1,743 @@
// +build windows
package winterm
import (
"bytes"
"log"
"os"
"strconv"
"github.com/Azure/go-ansiterm"
)
type windowsAnsiEventHandler struct {
fd uintptr
file *os.File
infoReset *CONSOLE_SCREEN_BUFFER_INFO
sr scrollRegion
buffer bytes.Buffer
attributes uint16
inverted bool
wrapNext bool
drewMarginByte bool
originMode bool
marginByte byte
curInfo *CONSOLE_SCREEN_BUFFER_INFO
curPos COORD
logf func(string, ...interface{})
}
type Option func(*windowsAnsiEventHandler)
func WithLogf(f func(string, ...interface{})) Option {
return func(w *windowsAnsiEventHandler) {
w.logf = f
}
}
func CreateWinEventHandler(fd uintptr, file *os.File, opts ...Option) ansiterm.AnsiEventHandler {
infoReset, err := GetConsoleScreenBufferInfo(fd)
if err != nil {
return nil
}
h := &windowsAnsiEventHandler{
fd: fd,
file: file,
infoReset: infoReset,
attributes: infoReset.Attributes,
}
for _, o := range opts {
o(h)
}
if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" {
logFile, _ := os.Create("winEventHandler.log")
logger := log.New(logFile, "", log.LstdFlags)
if h.logf != nil {
l := h.logf
h.logf = func(s string, v ...interface{}) {
l(s, v...)
logger.Printf(s, v...)
}
} else {
h.logf = logger.Printf
}
}
if h.logf == nil {
h.logf = func(string, ...interface{}) {}
}
return h
}
type scrollRegion struct {
top int16
bottom int16
}
// simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the
// current cursor position and scroll region settings, in which case it returns
// true. If no special handling is necessary, then it does nothing and returns
// false.
//
// In the false case, the caller should ensure that a carriage return
// and line feed are inserted or that the text is otherwise wrapped.
func (h *windowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) {
if h.wrapNext {
if err := h.Flush(); err != nil {
return false, err
}
h.clearWrap()
}
pos, info, err := h.getCurrentInfo()
if err != nil {
return false, err
}
sr := h.effectiveSr(info.Window)
if pos.Y == sr.bottom {
// Scrolling is necessary. Let Windows automatically scroll if the scrolling region
// is the full window.
if sr.top == info.Window.Top && sr.bottom == info.Window.Bottom {
if includeCR {
pos.X = 0
h.updatePos(pos)
}
return false, nil
}
// A custom scroll region is active. Scroll the window manually to simulate
// the LF.
if err := h.Flush(); err != nil {
return false, err
}
h.logf("Simulating LF inside scroll region")
if err := h.scrollUp(1); err != nil {
return false, err
}
if includeCR {
pos.X = 0
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
return false, err
}
}
return true, nil
} else if pos.Y < info.Window.Bottom {
// Let Windows handle the LF.
pos.Y++
if includeCR {
pos.X = 0
}
h.updatePos(pos)
return false, nil
} else {
// The cursor is at the bottom of the screen but outside the scroll
// region. Skip the LF.
h.logf("Simulating LF outside scroll region")
if includeCR {
if err := h.Flush(); err != nil {
return false, err
}
pos.X = 0
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
return false, err
}
}
return true, nil
}
}
// executeLF executes a LF without a CR.
func (h *windowsAnsiEventHandler) executeLF() error {
handled, err := h.simulateLF(false)
if err != nil {
return err
}
if !handled {
// Windows LF will reset the cursor column position. Write the LF
// and restore the cursor position.
pos, _, err := h.getCurrentInfo()
if err != nil {
return err
}
h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
if pos.X != 0 {
if err := h.Flush(); err != nil {
return err
}
h.logf("Resetting cursor position for LF without CR")
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
return err
}
}
}
return nil
}
func (h *windowsAnsiEventHandler) Print(b byte) error {
if h.wrapNext {
h.buffer.WriteByte(h.marginByte)
h.clearWrap()
if _, err := h.simulateLF(true); err != nil {
return err
}
}
pos, info, err := h.getCurrentInfo()
if err != nil {
return err
}
if pos.X == info.Size.X-1 {
h.wrapNext = true
h.marginByte = b
} else {
pos.X++
h.updatePos(pos)
h.buffer.WriteByte(b)
}
return nil
}
func (h *windowsAnsiEventHandler) Execute(b byte) error {
switch b {
case ansiterm.ANSI_TAB:
h.logf("Execute(TAB)")
// Move to the next tab stop, but preserve auto-wrap if already set.
if !h.wrapNext {
pos, info, err := h.getCurrentInfo()
if err != nil {
return err
}
pos.X = (pos.X + 8) - pos.X%8
if pos.X >= info.Size.X {
pos.X = info.Size.X - 1
}
if err := h.Flush(); err != nil {
return err
}
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
return err
}
}
return nil
case ansiterm.ANSI_BEL:
h.buffer.WriteByte(ansiterm.ANSI_BEL)
return nil
case ansiterm.ANSI_BACKSPACE:
if h.wrapNext {
if err := h.Flush(); err != nil {
return err
}
h.clearWrap()
}
pos, _, err := h.getCurrentInfo()
if err != nil {
return err
}
if pos.X > 0 {
pos.X--
h.updatePos(pos)
h.buffer.WriteByte(ansiterm.ANSI_BACKSPACE)
}
return nil
case ansiterm.ANSI_VERTICAL_TAB, ansiterm.ANSI_FORM_FEED:
// Treat as true LF.
return h.executeLF()
case ansiterm.ANSI_LINE_FEED:
// Simulate a CR and LF for now since there is no way in go-ansiterm
// to tell if the LF should include CR (and more things break when it's
// missing than when it's incorrectly added).
handled, err := h.simulateLF(true)
if handled || err != nil {
return err
}
return h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
case ansiterm.ANSI_CARRIAGE_RETURN:
if h.wrapNext {
if err := h.Flush(); err != nil {
return err
}
h.clearWrap()
}
pos, _, err := h.getCurrentInfo()
if err != nil {
return err
}
if pos.X != 0 {
pos.X = 0
h.updatePos(pos)
h.buffer.WriteByte(ansiterm.ANSI_CARRIAGE_RETURN)
}
return nil
default:
return nil
}
}
func (h *windowsAnsiEventHandler) CUU(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("CUU: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.moveCursorVertical(-param)
}
func (h *windowsAnsiEventHandler) CUD(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("CUD: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.moveCursorVertical(param)
}
func (h *windowsAnsiEventHandler) CUF(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("CUF: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.moveCursorHorizontal(param)
}
func (h *windowsAnsiEventHandler) CUB(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("CUB: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.moveCursorHorizontal(-param)
}
func (h *windowsAnsiEventHandler) CNL(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("CNL: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.moveCursorLine(param)
}
func (h *windowsAnsiEventHandler) CPL(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("CPL: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.moveCursorLine(-param)
}
func (h *windowsAnsiEventHandler) CHA(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("CHA: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.moveCursorColumn(param)
}
func (h *windowsAnsiEventHandler) VPA(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("VPA: [[%d]]", param)
h.clearWrap()
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
window := h.getCursorWindow(info)
position := info.CursorPosition
position.Y = window.Top + int16(param) - 1
return h.setCursorPosition(position, window)
}
func (h *windowsAnsiEventHandler) CUP(row int, col int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("CUP: [[%d %d]]", row, col)
h.clearWrap()
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
window := h.getCursorWindow(info)
position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1}
return h.setCursorPosition(position, window)
}
func (h *windowsAnsiEventHandler) HVP(row int, col int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("HVP: [[%d %d]]", row, col)
h.clearWrap()
return h.CUP(row, col)
}
func (h *windowsAnsiEventHandler) DECTCEM(visible bool) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("DECTCEM: [%v]", []string{strconv.FormatBool(visible)})
h.clearWrap()
return nil
}
func (h *windowsAnsiEventHandler) DECOM(enable bool) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("DECOM: [%v]", []string{strconv.FormatBool(enable)})
h.clearWrap()
h.originMode = enable
return h.CUP(1, 1)
}
func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("DECCOLM: [%v]", []string{strconv.FormatBool(use132)})
h.clearWrap()
if err := h.ED(2); err != nil {
return err
}
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
targetWidth := int16(80)
if use132 {
targetWidth = 132
}
if info.Size.X < targetWidth {
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
h.logf("set buffer failed: %v", err)
return err
}
}
window := info.Window
window.Left = 0
window.Right = targetWidth - 1
if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
h.logf("set window failed: %v", err)
return err
}
if info.Size.X > targetWidth {
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
h.logf("set buffer failed: %v", err)
return err
}
}
return SetConsoleCursorPosition(h.fd, COORD{0, 0})
}
func (h *windowsAnsiEventHandler) ED(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("ED: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
// [J -- Erases from the cursor to the end of the screen, including the cursor position.
// [1J -- Erases from the beginning of the screen to the cursor, including the cursor position.
// [2J -- Erases the complete display. The cursor does not move.
// Notes:
// -- Clearing the entire buffer, versus just the Window, works best for Windows Consoles
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
var start COORD
var end COORD
switch param {
case 0:
start = info.CursorPosition
end = COORD{info.Size.X - 1, info.Size.Y - 1}
case 1:
start = COORD{0, 0}
end = info.CursorPosition
case 2:
start = COORD{0, 0}
end = COORD{info.Size.X - 1, info.Size.Y - 1}
}
err = h.clearRange(h.attributes, start, end)
if err != nil {
return err
}
// If the whole buffer was cleared, move the window to the top while preserving
// the window-relative cursor position.
if param == 2 {
pos := info.CursorPosition
window := info.Window
pos.Y -= window.Top
window.Bottom -= window.Top
window.Top = 0
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
return err
}
if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
return err
}
}
return nil
}
func (h *windowsAnsiEventHandler) EL(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("EL: [%v]", strconv.Itoa(param))
h.clearWrap()
// [K -- Erases from the cursor to the end of the line, including the cursor position.
// [1K -- Erases from the beginning of the line to the cursor, including the cursor position.
// [2K -- Erases the complete line.
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
var start COORD
var end COORD
switch param {
case 0:
start = info.CursorPosition
end = COORD{info.Size.X, info.CursorPosition.Y}
case 1:
start = COORD{0, info.CursorPosition.Y}
end = info.CursorPosition
case 2:
start = COORD{0, info.CursorPosition.Y}
end = COORD{info.Size.X, info.CursorPosition.Y}
}
err = h.clearRange(h.attributes, start, end)
if err != nil {
return err
}
return nil
}
func (h *windowsAnsiEventHandler) IL(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("IL: [%v]", strconv.Itoa(param))
h.clearWrap()
return h.insertLines(param)
}
func (h *windowsAnsiEventHandler) DL(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("DL: [%v]", strconv.Itoa(param))
h.clearWrap()
return h.deleteLines(param)
}
func (h *windowsAnsiEventHandler) ICH(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("ICH: [%v]", strconv.Itoa(param))
h.clearWrap()
return h.insertCharacters(param)
}
func (h *windowsAnsiEventHandler) DCH(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("DCH: [%v]", strconv.Itoa(param))
h.clearWrap()
return h.deleteCharacters(param)
}
func (h *windowsAnsiEventHandler) SGR(params []int) error {
if err := h.Flush(); err != nil {
return err
}
strings := []string{}
for _, v := range params {
strings = append(strings, strconv.Itoa(v))
}
h.logf("SGR: [%v]", strings)
if len(params) <= 0 {
h.attributes = h.infoReset.Attributes
h.inverted = false
} else {
for _, attr := range params {
if attr == ansiterm.ANSI_SGR_RESET {
h.attributes = h.infoReset.Attributes
h.inverted = false
continue
}
h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, int16(attr))
}
}
attributes := h.attributes
if h.inverted {
attributes = invertAttributes(attributes)
}
err := SetConsoleTextAttribute(h.fd, attributes)
if err != nil {
return err
}
return nil
}
func (h *windowsAnsiEventHandler) SU(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("SU: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.scrollUp(param)
}
func (h *windowsAnsiEventHandler) SD(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("SD: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.scrollDown(param)
}
func (h *windowsAnsiEventHandler) DA(params []string) error {
h.logf("DA: [%v]", params)
// DA cannot be implemented because it must send data on the VT100 input stream,
// which is not available to go-ansiterm.
return nil
}
func (h *windowsAnsiEventHandler) DECSTBM(top int, bottom int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("DECSTBM: [%d, %d]", top, bottom)
// Windows is 0 indexed, Linux is 1 indexed
h.sr.top = int16(top - 1)
h.sr.bottom = int16(bottom - 1)
// This command also moves the cursor to the origin.
h.clearWrap()
return h.CUP(1, 1)
}
func (h *windowsAnsiEventHandler) RI() error {
if err := h.Flush(); err != nil {
return err
}
h.logf("RI: []")
h.clearWrap()
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
sr := h.effectiveSr(info.Window)
if info.CursorPosition.Y == sr.top {
return h.scrollDown(1)
}
return h.moveCursorVertical(-1)
}
func (h *windowsAnsiEventHandler) IND() error {
h.logf("IND: []")
return h.executeLF()
}
func (h *windowsAnsiEventHandler) Flush() error {
h.curInfo = nil
if h.buffer.Len() > 0 {
h.logf("Flush: [%s]", h.buffer.Bytes())
if _, err := h.buffer.WriteTo(h.file); err != nil {
return err
}
}
if h.wrapNext && !h.drewMarginByte {
h.logf("Flush: drawing margin byte '%c'", h.marginByte)
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}}
size := COORD{1, 1}
position := COORD{0, 0}
region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y}
if err := WriteConsoleOutput(h.fd, charInfo, size, position, &region); err != nil {
return err
}
h.drewMarginByte = true
}
return nil
}
// cacheConsoleInfo ensures that the current console screen information has been queried
// since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos.
func (h *windowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) {
if h.curInfo == nil {
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return COORD{}, nil, err
}
h.curInfo = info
h.curPos = info.CursorPosition
}
return h.curPos, h.curInfo, nil
}
func (h *windowsAnsiEventHandler) updatePos(pos COORD) {
if h.curInfo == nil {
panic("failed to call getCurrentInfo before calling updatePos")
}
h.curPos = pos
}
// clearWrap clears the state where the cursor is in the margin
// waiting for the next character before wrapping the line. This must
// be done before most operations that act on the cursor.
func (h *windowsAnsiEventHandler) clearWrap() {
h.wrapNext = false
h.drewMarginByte = false
}

84
vendor/github.com/docker/docker/pkg/term/deprecated.go generated vendored Normal file
View file

@ -0,0 +1,84 @@
// Package term provides structures and helper functions to work with
// terminal (state, sizes).
//
// Deprecated: use github.com/moby/term instead
package term // import "github.com/docker/docker/pkg/term"
import (
"github.com/moby/term"
)
// EscapeError is special error which returned by a TTY proxy reader's Read()
// method in case its detach escape sequence is read.
// Deprecated: use github.com/moby/term.EscapeError
type EscapeError = term.EscapeError
// State represents the state of the terminal.
// Deprecated: use github.com/moby/term.State
type State = term.State
// Winsize represents the size of the terminal window.
// Deprecated: use github.com/moby/term.Winsize
type Winsize = term.Winsize
var (
// ASCII list the possible supported ASCII key sequence
ASCII = term.ASCII
// ToBytes converts a string representing a suite of key-sequence to the corresponding ASCII code.
// Deprecated: use github.com/moby/term.ToBytes
ToBytes = term.ToBytes
// StdStreams returns the standard streams (stdin, stdout, stderr).
// Deprecated: use github.com/moby/term.StdStreams
StdStreams = term.StdStreams
// GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal.
// Deprecated: use github.com/moby/term.GetFdInfo
GetFdInfo = term.GetFdInfo
// GetWinsize returns the window size based on the specified file descriptor.
// Deprecated: use github.com/moby/term.GetWinsize
GetWinsize = term.GetWinsize
// IsTerminal returns true if the given file descriptor is a terminal.
// Deprecated: use github.com/moby/term.IsTerminal
IsTerminal = term.IsTerminal
// RestoreTerminal restores the terminal connected to the given file descriptor
// to a previous state.
// Deprecated: use github.com/moby/term.RestoreTerminal
RestoreTerminal = term.RestoreTerminal
// SaveState saves the state of the terminal connected to the given file descriptor.
// Deprecated: use github.com/moby/term.SaveState
SaveState = term.SaveState
// DisableEcho applies the specified state to the terminal connected to the file
// descriptor, with echo disabled.
// Deprecated: use github.com/moby/term.DisableEcho
DisableEcho = term.DisableEcho
// SetRawTerminal puts the terminal connected to the given file descriptor into
// raw mode and returns the previous state. On UNIX, this puts both the input
// and output into raw mode. On Windows, it only puts the input into raw mode.
// Deprecated: use github.com/moby/term.SetRawTerminal
SetRawTerminal = term.SetRawTerminal
// SetRawTerminalOutput puts the output of terminal connected to the given file
// descriptor into raw mode. On UNIX, this does nothing and returns nil for the
// state. On Windows, it disables LF -> CRLF translation.
// Deprecated: use github.com/moby/term.SetRawTerminalOutput
SetRawTerminalOutput = term.SetRawTerminalOutput
// MakeRaw puts the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be restored.
// Deprecated: use github.com/moby/term.MakeRaw
MakeRaw = term.MakeRaw
// NewEscapeProxy returns a new TTY proxy reader which wraps the given reader
// and detects when the specified escape keys are read, in which case the Read
// method will return an error of type EscapeError.
// Deprecated: use github.com/moby/term.NewEscapeProxy
NewEscapeProxy = term.NewEscapeProxy
)

View file

@ -0,0 +1,21 @@
//go:build !windows
// +build !windows
package term // import "github.com/docker/docker/pkg/term"
import (
"github.com/moby/term"
)
// Termios is the Unix API for terminal I/O.
// Deprecated: use github.com/moby/term.Termios
type Termios = term.Termios
var (
// ErrInvalidState is returned if the state of the terminal is invalid.
ErrInvalidState = term.ErrInvalidState
// SetWinsize tries to set the specified window size for the specified file descriptor.
// Deprecated: use github.com/moby/term.GetWinsize
SetWinsize = term.SetWinsize
)

9
vendor/github.com/micmonay/keybd_event/LICENSE generated vendored Normal file
View file

@ -0,0 +1,9 @@
The MIT License (MIT)
Copyright (c) 2016 MicMonay
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

77
vendor/github.com/micmonay/keybd_event/README.md generated vendored Normal file
View file

@ -0,0 +1,77 @@
# keybd_event
[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/github.com/micmonay/keybd_event)
This library simulates the key press on a keyboard. It runs on Linux, Windows and Mac.
**Important :**
- The keys change in the different keyboard layouts of the target computer(s).
- I have tested this code on my system and I don't find any errors. If you have a bug, please create an issue.
### Example :
```go
package main
import (
"runtime"
"time"
"github.com/micmonay/keybd_event"
)
func main() {
kb, err := keybd_event.NewKeyBonding()
if err != nil {
panic(err)
}
// For linux, it is very important to wait 2 seconds
if runtime.GOOS == "linux" {
time.Sleep(2 * time.Second)
}
// Select keys to be pressed
kb.SetKeys(keybd_event.VK_A, keybd_event.VK_B)
// Set shift to be pressed
kb.HasSHIFT(true)
// Press the selected keys
err = kb.Launching()
if err != nil {
panic(err)
}
// Or you can use Press and Release
kb.Press()
time.Sleep(10 * time.Millisecond)
kb.Release()
// Here, the program will generate "ABAB" as if they were pressed on the keyboard.
}
```
For easy access to all the keys on the virtual keyboard, I have added more special keycodes constants `VK_SP*`.
Below is an illustration showing the "VK_" symbols for each key on the keyboard:
![keyboard.png](./keyboard.png)
## Linux
On Linux this library uses **uinput**, which on the major distributions requires root permissions.
The easy solution is executing through root user (by using `sudo`). A worse way is by changing the executable's permissions by using `chmod`.
### Secure Linux Example
```bash
sudo groupadd uinput
sudo usermod -a -G uinput my_username
sudo udevadm control --reload-rules
echo "SUBSYSTEM==\"misc\", KERNEL==\"uinput\", GROUP=\"uinput\", MODE=\"0660\"" | sudo tee /etc/udev/rules.d/uinput.rules
echo uinput | sudo tee /etc/modules-load.d/uinput.conf
```
Another subtlety on Linux: it is important after creating the `keybd_event` to **wait 2 seconds before running first keyboard actions**.
## Darwin (MacOS)
This library depends on Apple's frameworks, and I did not find a solution to cross-compile from another OS to MacOS.

262
vendor/github.com/micmonay/keybd_event/keybd_darwin.go generated vendored Normal file
View file

@ -0,0 +1,262 @@
package keybd_event
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Cocoa
#import <Foundation/Foundation.h>
CGEventRef CreateDown(int k){
CGEventRef event = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)k, true);
return event;
}
CGEventRef CreateUp(int k){
CGEventRef event = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)k, false);
return event;
}
void KeyTap(CGEventRef event){
CGEventPost(kCGAnnotatedSessionEventTap, event);
CFRelease(event);
}
void AddActionKey(CGEventFlags type,CGEventRef event){
CGEventSetFlags(event, type);
}
*/
import "C"
import "time"
const (
_AShift = C.kCGEventFlagMaskAlphaShift
_VK_SHIFT = C.kCGEventFlagMaskShift
_VK_CTRL = C.kCGEventFlagMaskControl
_VK_ALT = C.kCGEventFlagMaskAlternate
_VK_CMD = C.kCGEventFlagMaskCommand
_Help = C.kCGEventFlagMaskHelp
_VK_FN = C.kCGEventFlagMaskSecondaryFn
_NumPad = C.kCGEventFlagMaskNumericPad
_Coalesced = C.kCGEventFlagMaskNonCoalesced
_VK_Control = 0x3B
_VK_RightShift = 0x3C
_VK_RightControl = 0x3E
_VK_Command = 0x37
_VK_Shift = 0x38
)
func initKeyBD() error { return nil }
// Press key(s)
func (k *KeyBonding) Press() error {
for _, key := range k.keys {
k.keyPress(key)
}
return nil
}
// Release key(s)
func (k *KeyBonding) Release() error {
for _, key := range k.keys {
k.keyRelease(key)
}
return nil
}
// Launch key bounding
func (k *KeyBonding) Launching() error {
for _, key := range k.keys {
k.tapKey(key)
}
return nil
}
func altgr(event C.CGEventRef) {
alt(event)
}
func shift(event C.CGEventRef) {
C.AddActionKey(_VK_SHIFT, event)
}
func ctrl(event C.CGEventRef) {
C.AddActionKey(_VK_CTRL, event)
}
func alt(event C.CGEventRef) {
C.AddActionKey(_VK_ALT, event)
}
func cmd(event C.CGEventRef) {
C.AddActionKey(_VK_CMD, event)
}
func (k KeyBonding) keyPress(key int) {
downEvent := C.CreateDown(C.int(key))
if k.hasALT {
alt(downEvent)
}
if k.hasCTRL {
ctrl(downEvent)
}
if k.hasSHIFT {
shift(downEvent)
}
if k.hasRCTRL { //not support on mac
ctrl(downEvent)
}
if k.hasRSHIFT { //not support on mac
shift(downEvent)
}
if k.hasALTGR {
altgr(downEvent)
}
if k.hasSuper {
cmd(downEvent)
}
C.KeyTap(downEvent)
}
func (k KeyBonding) keyRelease(key int) {
upEvent := C.CreateUp(C.int(key))
if k.hasALT {
alt(upEvent)
}
if k.hasCTRL {
ctrl(upEvent)
}
if k.hasSHIFT {
shift(upEvent)
}
if k.hasRCTRL { //not support on mac
ctrl(upEvent)
}
if k.hasRSHIFT { //not support on mac
shift(upEvent)
}
if k.hasALTGR {
altgr(upEvent)
}
if k.hasSuper {
cmd(upEvent)
}
C.KeyTap(upEvent)
}
func (k KeyBonding) tapKey(key int) {
k.keyPress(key)
time.Sleep(100 * time.Millisecond) //ignore if speed is most in my test system
k.keyRelease(key)
}
const (
VK_SP1 = 0x0A
VK_SP2 = 0x1B
VK_SP3 = 0x18
VK_SP4 = 0x21
VK_SP5 = 0x1E
VK_SP6 = 0x29
VK_SP7 = 0x27
VK_SP8 = 0x2A
VK_SP9 = 0x2B
VK_SP10 = 0x2F
VK_SP11 = 0x2C
VK_SP12 = 0x32
VK_A = 0x00
VK_S = 0x01
VK_D = 0x02
VK_F = 0x03
VK_H = 0x04
VK_G = 0x05
VK_Z = 0x06
VK_X = 0x07
VK_C = 0x08
VK_V = 0x09
VK_B = 0x0B
VK_Q = 0x0C
VK_W = 0x0D
VK_E = 0x0E
VK_R = 0x0F
VK_Y = 0x10
VK_T = 0x11
VK_1 = 0x12
VK_2 = 0x13
VK_3 = 0x14
VK_4 = 0x15
VK_6 = 0x16
VK_5 = 0x17
VK_EQUAL = 0x18
VK_9 = 0x19
VK_7 = 0x1A
VK_MINUS = 0x1B
VK_8 = 0x1C
VK_0 = 0x1D
VK_RightBracket = 0x1E
VK_O = 0x1F
VK_U = 0x20
VK_LeftBracket = 0x21
VK_I = 0x22
VK_P = 0x23
VK_L = 0x25
VK_J = 0x26
VK_Quote = 0x27
VK_K = 0x28
VK_SEMICOLON = 0x29
VK_BACKSLASH = 0x2A
VK_COMMA = 0x2B
VK_SLASH = 0x2C
VK_N = 0x2D
VK_M = 0x2E
VK_Period = 0x2F
VK_GRAVE = 0x32
VK_KeypadDecimal = 0x41
VK_KeypadMultiply = 0x43
VK_KeypadPlus = 0x45
VK_KeypadClear = 0x47
VK_KeypadDivide = 0x4B
VK_KeypadEnter = 0x4C
VK_KeypadMinus = 0x4E
VK_KeypadEquals = 0x51
VK_Keypad0 = 0x52
VK_Keypad1 = 0x53
VK_Keypad2 = 0x54
VK_Keypad3 = 0x55
VK_Keypad4 = 0x56
VK_Keypad5 = 0x57
VK_Keypad6 = 0x58
VK_Keypad7 = 0x59
VK_Keypad8 = 0x5B
VK_Keypad9 = 0x5C
VK_ENTER = 0x24
VK_TAB = 0x30
VK_SPACE = 0x31
VK_DELETE = 0x33
VK_ESC = 0x35
VK_CAPSLOCK = 0x39
VK_Option = 0x3A
VK_RightOption = 0x3D
VK_Function = 0x3F
VK_F17 = 0x40
VK_VOLUMEUP = 0x48
VK_VOLUMEDOWN = 0x49
VK_MUTE = 0x4A
VK_F18 = 0x4F
VK_F19 = 0x50
VK_F20 = 0x5A
VK_F5 = 0x60
VK_F6 = 0x61
VK_F7 = 0x62
VK_F3 = 0x63
VK_F8 = 0x64
VK_F9 = 0x65
VK_F11 = 0x67
VK_F13 = 0x69
VK_F16 = 0x6A
VK_F14 = 0x6B
VK_F10 = 0x6D
VK_F12 = 0x6F
VK_F15 = 0x71
VK_HELP = 0x72
VK_HOME = 0x73
VK_PAGEUP = 0x74
VK_ForwardDelete = 0x75
VK_F4 = 0x76
VK_END = 0x77
VK_F2 = 0x78
VK_PAGEDOWN = 0x79
VK_F1 = 0x7A
VK_LEFT = 0x7B
VK_RIGHT = 0x7C
VK_DOWN = 0x7D
VK_UP = 0x7E
)

86
vendor/github.com/micmonay/keybd_event/keybd_event.go generated vendored Normal file
View file

@ -0,0 +1,86 @@
// Package keybd_event is used for a key press simulated in Windows, Linux and Mac
package keybd_event
//KeyBonding type for keybd_event
type KeyBonding struct {
hasCTRL bool
hasALT bool
hasSHIFT bool
hasRCTRL bool
hasRSHIFT bool
hasALTGR bool
hasSuper bool
keys []int
}
//NewKeyBonding Use for create struct KeyBounding
func NewKeyBonding() (KeyBonding, error) {
keyBounding := KeyBonding{}
keyBounding.Clear()
err := initKeyBD()
if err != nil {
return keyBounding, err
}
return keyBounding, nil
}
//Clear clean instance
func (k *KeyBonding) Clear() {
k.hasALT = false
k.hasCTRL = false
k.hasSHIFT = false
k.hasRCTRL = false
k.hasRSHIFT = false
k.hasALTGR = false
k.hasSuper = false
k.keys = []int{}
}
//SetKeys set keys
func (k *KeyBonding) SetKeys(keys ...int) {
k.keys = keys
}
//AddKey add one key pressed
func (k *KeyBonding) AddKey(key int) {
k.keys = append(k.keys, key)
}
//HasALT If key ALT pressed
func (k *KeyBonding) HasALT(b bool) {
k.hasALT = b
}
//HasCTRL If key CTRL pressed
func (k *KeyBonding) HasCTRL(b bool) {
k.hasCTRL = b
}
//HasSHIFT If key SHIFT pressed
func (k *KeyBonding) HasSHIFT(b bool) {
k.hasSHIFT = b
}
//HasALTGR If key ALTGR pressed
func (k *KeyBonding) HasALTGR(b bool) {
k.hasALTGR = b
}
//HasSuper If key Super pressed
func (k *KeyBonding) HasSuper(b bool) {
k.hasSuper = b
}
//HasCTRLR If key CTRLR pressed
//
//This is currently not supported on macOS
func (k *KeyBonding) HasCTRLR(b bool) {
k.hasRCTRL = b
}
//HasSHIFTR If key SHIFTR pressed
//
//This is currently not supported on macOS
func (k *KeyBonding) HasSHIFTR(b bool) {
k.hasRSHIFT = b
}

549
vendor/github.com/micmonay/keybd_event/keybd_linux.go generated vendored Normal file
View file

@ -0,0 +1,549 @@
package keybd_event
/*
#include <linux/uinput.h>
*/
import "C"
import (
"encoding/binary"
"errors"
"os"
"syscall"
)
type uinput_user_dev C.struct_uinput_user_dev
type timeval C.struct_timeval
type input_event C.struct_input_event
var fd *os.File
var X11 = true
const (
_EV_KEY = C.EV_KEY
_EV_SYN = C.EV_SYN
_UI_SET_EVBIT = C.UI_SET_EVBIT
_UI_SET_KEYBIT = C.UI_SET_KEYBIT
_UI_DEV_CREATE = C.UI_DEV_CREATE
_UI_DEV_DESTROY = C.UI_DEV_DESTROY
_UINPUT_MAX_NAME_SIZE = C.UINPUT_MAX_NAME_SIZE
_VK_LEFTCTRL = 29
_VK_RIGHTCTRL = 97
_VK_CTRL = 29
_VK_LEFTSHIFT = 42
_VK_RIGHTSHIFT = 54
_VK_SHIFT = 42
_VK_LEFTALT = 56
_VK_RIGHTALT = 100
_VK_ALT = 56
_VK_LEFTMETA = 125
_VK_RIGHTMETA = 126
)
func initKeyBD() error {
if fd != nil {
return nil
}
path, err := getFileUInput()
if err != nil {
return err
}
fdInit, err := os.OpenFile(path, os.O_WRONLY|syscall.O_NONBLOCK, os.ModeDevice)
fd = fdInit
if err != nil {
if os.IsPermission(err) {
return errors.New("permission error for " + path + " try cmd : sudo chmod +0666 " + path)
} else {
return err
}
}
_, _, errCall := syscall.Syscall(syscall.SYS_IOCTL, fd.Fd(), _UI_SET_EVBIT, uintptr(_EV_KEY))
if errCall != 0 {
return err
}
_, _, errCall = syscall.Syscall(syscall.SYS_IOCTL, fd.Fd(), _UI_SET_EVBIT, uintptr(_EV_SYN))
if errCall != 0 {
return err
}
keyEventSet()
uidev := uinput_user_dev{}
for i, c := range "keybd interface" {
uidev.name[i] = C.char(c)
}
uidev.id.bustype = C.BUS_USB
uidev.id.vendor = 0x1
uidev.id.product = 0x1
uidev.id.version = 0x1
err = binary.Write(fd, binary.LittleEndian, &uidev)
if err != nil {
return err
}
//Create device
_, _, errCall = syscall.Syscall(syscall.SYS_IOCTL, fd.Fd(), _UI_DEV_CREATE, 0)
if errCall != 0 {
return err
}
return nil
}
//actualy don't use
func destroyLinuxUInput() {
syscall.Syscall(syscall.SYS_IOCTL, fd.Fd(), _UI_DEV_DESTROY, 0)
fd.Close()
}
func getFileUInput() (string, error) {
if _, err := os.Stat("/dev/uinput"); err == nil {
return "/dev/uinput", nil
}
if _, err := os.Stat("/dev/input/uinput"); err == nil {
return "/dev/input/uinput", nil
}
err := errors.New("Not found uinput file. Try this cmd 'sudo modprobe uinput'")
return "", err
}
// Press key(s)
func (k *KeyBonding) Press() error {
var err error
if k.hasALT {
err = downKey(_VK_ALT)
if err != nil {
return err
}
}
if k.hasSHIFT {
err = downKey(_VK_SHIFT)
if err != nil {
return err
}
}
if k.hasCTRL {
err = downKey(_VK_CTRL)
if err != nil {
return err
}
}
if k.hasRSHIFT {
err = downKey(_VK_RIGHTSHIFT)
if err != nil {
return err
}
}
if k.hasRCTRL {
err = downKey(_VK_RIGHTCTRL)
if err != nil {
return err
}
}
if k.hasALTGR {
err = downKey(_VK_RIGHTALT)
if err != nil {
return err
}
}
if k.hasSuper {
err = downKey(_VK_LEFTMETA)
if err != nil {
return err
}
}
for _, key := range k.keys {
err = downKey(key)
if err != nil {
return err
}
}
err = sync()
if err != nil {
return err
}
return nil
}
// Release key(s)
func (k *KeyBonding) Release() error {
var err error
if k.hasALT {
err = upKey(_VK_ALT)
if err != nil {
return err
}
}
if k.hasSHIFT {
err = upKey(_VK_SHIFT)
if err != nil {
return err
}
}
if k.hasCTRL {
err = upKey(_VK_CTRL)
if err != nil {
return err
}
}
if k.hasRSHIFT {
err = upKey(_VK_RIGHTSHIFT)
if err != nil {
return err
}
}
if k.hasRCTRL {
err = upKey(_VK_RIGHTCTRL)
if err != nil {
return err
}
}
if k.hasALTGR {
err = upKey(_VK_RIGHTALT)
if err != nil {
return err
}
}
if k.hasSuper {
err := upKey(_VK_LEFTMETA)
if err != nil {
return err
}
}
for _, key := range k.keys {
err = upKey(key)
if err != nil {
return err
}
}
err = sync()
if err != nil {
return err
}
//Destroy device
return nil
}
// Launch key bounding
func (k *KeyBonding) Launching() error {
k.Press()
//key up
k.Release()
return nil
}
func keyEventSet() error {
for i := 0; i < 256; i++ {
_, _, errCall := syscall.Syscall(syscall.SYS_IOCTL, fd.Fd(), _UI_SET_KEYBIT, uintptr(i))
if errCall != 0 {
return errCall
}
}
return nil
}
func downKey(key int) error {
ev := input_event{}
ev._type = _EV_KEY
ev.code = C.__u16(key)
ev.value = 1
err := binary.Write(fd, binary.LittleEndian, &ev)
if err != nil {
return err
}
return nil
}
func sync() error {
ev := input_event{}
ev._type = _EV_SYN
ev.code = 0
ev.value = 0
err := binary.Write(fd, binary.LittleEndian, &ev)
if err != nil {
return err
}
return nil
}
func upKey(key int) error {
ev := input_event{}
ev._type = _EV_KEY
ev.code = C.__u16(key)
ev.value = 0
err := binary.Write(fd, binary.LittleEndian, &ev)
if err != nil {
return err
}
return nil
}
const (
VK_SP1 = 41
VK_SP2 = 12
VK_SP3 = 13
VK_SP4 = 26
VK_SP5 = 27
VK_SP6 = 39
VK_SP7 = 40
VK_SP8 = 43
VK_SP9 = 51
VK_SP10 = 52
VK_SP11 = 53
VK_SP12 = 86
VK_UP = 103
VK_DOWN = 108
VK_LEFT = 105
VK_RIGHT = 106
VK_ESC = 1
VK_1 = 2
VK_2 = 3
VK_3 = 4
VK_4 = 5
VK_5 = 6
VK_6 = 7
VK_7 = 8
VK_8 = 9
VK_9 = 10
VK_0 = 11
VK_Q = 16
VK_W = 17
VK_E = 18
VK_R = 19
VK_T = 20
VK_Y = 21
VK_U = 22
VK_I = 23
VK_O = 24
VK_P = 25
VK_A = 30
VK_S = 31
VK_D = 32
VK_F = 33
VK_G = 34
VK_H = 35
VK_J = 36
VK_K = 37
VK_L = 38
VK_Z = 44
VK_X = 45
VK_C = 46
VK_V = 47
VK_B = 48
VK_N = 49
VK_M = 50
VK_F1 = 59
VK_F2 = 60
VK_F3 = 61
VK_F4 = 62
VK_F5 = 63
VK_F6 = 64
VK_F7 = 65
VK_F8 = 66
VK_F9 = 67
VK_F10 = 68
VK_F11 = 87
VK_F12 = 88
VK_NUMLOCK = 69
VK_SCROLLLOCK = 70
VK_RESERVED = 0
VK_MINUS = 12
VK_EQUAL = 13
VK_BACKSPACE = 14
VK_TAB = 15
VK_LEFTBRACE = 26
VK_RIGHTBRACE = 27
VK_ENTER = 28
VK_SEMICOLON = 39
VK_APOSTROPHE = 40
VK_GRAVE = 41
VK_BACKSLASH = 43
VK_COMMA = 51
VK_DOT = 52
VK_SLASH = 53
VK_SPACE = 57
VK_CAPSLOCK = 58
VK_KP0 = 82
VK_KP1 = 79
VK_KP2 = 80
VK_KP3 = 81
VK_KP4 = 75
VK_KP5 = 76
VK_KP6 = 77
VK_KP7 = 71
VK_KP8 = 72
VK_KP9 = 73
VK_KPMINUS = 74
VK_KPPLUS = 78
VK_KPDOT = 83
VK_KPJPCOMMA = 95
VK_KPENTER = 96
VK_KPSLASH = 98
VK_KPASTERISK = 55
VK_KPEQUAL = 117
VK_KPPLUSMINUS = 118
VK_KPCOMMA = 121
VK_ZENKAKUHANKAKU = 85
VK_102ND = 86
VK_RO = 89
VK_KATAKANA = 90
VK_HIRAGANA = 91
VK_HENKAN = 92
VK_KATAKANAHIRAGANA = 93
VK_MUHENKAN = 94
VK_SYSRQ = 99
VK_LINEFEED = 101
VK_HOME = 102
VK_PAGEUP = 104
VK_END = 107
VK_PAGEDOWN = 109
VK_INSERT = 110
VK_DELETE = 111
VK_MACRO = 112
VK_MUTE = 113
VK_VOLUMEDOWN = 114
VK_VOLUMEUP = 115
VK_POWER = 116 /* SC System Power Down */
VK_PAUSE = 119
VK_SCALE = 120 /* AL Compiz Scale (Expose) */
VK_HANGEUL = 122
VK_HANGUEL = VK_HANGEUL
VK_HANJA = 123
VK_YEN = 124
VK_LEFTMETA = 125
VK_RIGHTMETA = 126
VK_COMPOSE = 127
VK_STOP = 128 /* AC Stop */
VK_AGAIN = 129
VK_PROPS = 130 /* AC Properties */
VK_UNDO = 131 /* AC Undo */
VK_FRONT = 132
VK_COPY = 133 /* AC Copy */
VK_OPEN = 134 /* AC Open */
VK_PASTE = 135 /* AC Paste */
VK_FIND = 136 /* AC Search */
VK_CUT = 137 /* AC Cut */
VK_HELP = 138 /* AL Integrated Help Center */
VK_MENU = 139 /* Menu (show menu) */
VK_CALC = 140 /* AL Calculator */
VK_SETUP = 141
VK_SLEEP = 142 /* SC System Sleep */
VK_WAKEUP = 143 /* System Wake Up */
VK_FILE = 144 /* AL Local Machine Browser */
VK_SENDFILE = 145
VK_DELETEFILE = 146
VK_XFER = 147
VK_PROG1 = 148
VK_PROG2 = 149
VK_WWW = 150 /* AL Internet Browser */
VK_MSDOS = 151
VK_COFFEE = 152 /* AL Terminal Lock/Screensaver */
VK_SCREENLOCK = VK_COFFEE
VK_ROTATE_DISPLAY = 153 /* Display orientation for e.g. tablets */
VK_DIRECTION = VK_ROTATE_DISPLAY
VK_CYCLEWINDOWS = 154
VK_MAIL = 155
VK_BOOKMARKS = 156 /* AC Bookmarks */
VK_COMPUTER = 157
VK_BACK = 158 /* AC Back */
VK_FORWARD = 159 /* AC Forward */
VK_CLOSECD = 160
VK_EJECTCD = 161
VK_EJECTCLOSECD = 162
VK_NEXTSONG = 163
VK_PLAYPAUSE = 164
VK_PREVIOUSSONG = 165
VK_STOPCD = 166
VK_RECORD = 167
VK_REWIND = 168
VK_PHONE = 169 /* Media Select Telephone */
VK_ISO = 170
VK_CONFIG = 171 /* AL Consumer Control Configuration */
VK_HOMEPAGE = 172 /* AC Home */
VK_REFRESH = 173 /* AC Refresh */
VK_EXIT = 174 /* AC Exit */
VK_MOVE = 175
VK_EDIT = 176
VK_SCROLLUP = 177
VK_SCROLLDOWN = 178
VK_KPLEFTPAREN = 179
VK_KPRIGHTPAREN = 180
VK_NEW = 181 /* AC New */
VK_REDO = 182 /* AC Redo/Repeat */
VK_F13 = 183
VK_F14 = 184
VK_F15 = 185
VK_F16 = 186
VK_F17 = 187
VK_F18 = 188
VK_F19 = 189
VK_F20 = 190
VK_F21 = 191
VK_F22 = 192
VK_F23 = 193
VK_F24 = 194
VK_PLAYCD = 200
VK_PAUSECD = 201
VK_PROG3 = 202
VK_PROG4 = 203
VK_DASHBOARD = 204 /* AL Dashboard */
VK_SUSPEND = 205
VK_CLOSE = 206 /* AC Close */
VK_PLAY = 207
VK_FASTFORWARD = 208
VK_BASSBOOST = 209
VK_PRINT = 210 /* AC Print */
VK_HP = 211
VK_CAMERA = 212
VK_SOUND = 213
VK_QUESTION = 214
VK_EMAIL = 215
VK_CHAT = 216
VK_SEARCH = 217
VK_CONNECT = 218
VK_FINANCE = 219 /* AL Checkbook/Finance */
VK_SPORT = 220
VK_SHOP = 221
VK_ALTERASE = 222
VK_CANCEL = 223 /* AC Cancel */
VK_BRIGHTNESSDOWN = 224
VK_BRIGHTNESSUP = 225
VK_MEDIA = 226
VK_SWITCHVIDEOMODE = 227 /* Cycle between available video
outputs (Monitor/LCD/TV-out/etc) */
VK_KBDILLUMTOGGLE = 228
VK_KBDILLUMDOWN = 229
VK_KBDILLUMUP = 230
VK_SEND = 231 /* AC Send */
VK_REPLY = 232 /* AC Reply */
VK_FORWARDMAIL = 233 /* AC Forward Msg */
VK_SAVE = 234 /* AC Save */
VK_DOCUMENTS = 235
VK_BATTERY = 236
VK_BLUETOOTH = 237
VK_WLAN = 238
VK_UWB = 239
VK_UNKNOWN = 240
VK_VIDEO_NEXT = 241 /* drive next video source */
VK_VIDEO_PREV = 242 /* drive previous video source */
VK_BRIGHTNESS_CYCLE = 243 /* brightness up, after max is min */
VK_BRIGHTNESS_AUTO = 244 /* Set Auto Brightness: manual
brightness control is off,
rely on ambient */
VK_BRIGHTNESS_ZERO = VK_BRIGHTNESS_AUTO
VK_DISPLAY_OFF = 245 /* display device to off state */
VK_WWAN = 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */
VK_WIMAX = VK_WWAN
VK_RFKILL = 247 /* Key that controls all radios */
VK_MICMUTE = 248 /* Mute / unmute the microphone */
)
//http://thiemonge.org/getting-started-with-uinput

310
vendor/github.com/micmonay/keybd_event/keybd_windows.go generated vendored Normal file
View file

@ -0,0 +1,310 @@
package keybd_event
import (
"syscall"
)
var dll = syscall.NewLazyDLL("user32.dll")
var procKeyBd = dll.NewProc("keybd_event")
// Press key(s)
func (k *KeyBonding) Press() error {
if k.hasALT {
downKey(_VK_ALT)
}
if k.hasALTGR {
downKey(_VK_ALT)
downKey(_VK_CTRL)
}
if k.hasSHIFT {
downKey(_VK_SHIFT)
}
if k.hasCTRL {
downKey(_VK_CTRL)
}
if k.hasRSHIFT {
downKey(_VK_RSHIFT)
}
if k.hasRCTRL {
downKey(_VK_RCONTROL)
}
if k.hasSuper {
downKey(_VK_LWIN)
}
for _, key := range k.keys {
downKey(key)
}
return nil
}
//Release key(s)
func (k *KeyBonding) Release() error {
if k.hasALT {
upKey(_VK_ALT)
}
if k.hasALTGR {
upKey(_VK_ALT)
upKey(_VK_CTRL)
}
if k.hasSHIFT {
upKey(_VK_SHIFT)
}
if k.hasCTRL {
upKey(_VK_CTRL)
}
if k.hasRSHIFT {
upKey(_VK_RSHIFT)
}
if k.hasRCTRL {
upKey(_VK_RCONTROL)
}
for _, key := range k.keys {
upKey(key)
}
if k.hasSuper {
upKey(_VK_LWIN)
}
return nil
}
// Launch key bounding
func (k *KeyBonding) Launching() error {
err := k.Press()
if err != nil {
return err
}
err = k.Release()
return err
}
func downKey(key int) {
flag := 0
if key < 0xFFF { // Detect if the key code is virtual or no
flag |= _KEYEVENTF_SCANCODE
} else {
key -= 0xFFF
}
vkey := key + 0x80
procKeyBd.Call(uintptr(key), uintptr(vkey), uintptr(flag), 0)
}
func upKey(key int) {
flag := _KEYEVENTF_KEYUP
if key < 0xFFF {
flag |= _KEYEVENTF_SCANCODE
} else {
key -= 0xFFF
}
vkey := key + 0x80
procKeyBd.Call(uintptr(key), uintptr(vkey), uintptr(flag), 0)
}
func initKeyBD() error { return nil }
const (
// I add 0xFFF for all Virtual key
_VK_SHIFT = 0x10 + 0xFFF
_VK_CTRL = 0x11 + 0xFFF
_VK_ALT = 0x12 + 0xFFF
_VK_LSHIFT = 0xA0 + 0xFFF
_VK_RSHIFT = 0xA1 + 0xFFF
_VK_LCONTROL = 0xA2 + 0xFFF
_VK_RCONTROL = 0xA3 + 0xFFF
_VK_LWIN = 0x5B + 0xFFF
_VK_RWIN = 0x5C + 0xFFF
_KEYEVENTF_KEYUP = 0x0002
_KEYEVENTF_SCANCODE = 0x0008
)
const (
VK_SP1 = 41
VK_SP2 = 12
VK_SP3 = 13
VK_SP4 = 26
VK_SP5 = 27
VK_SP6 = 39
VK_SP7 = 40
VK_SP8 = 43
VK_SP9 = 51
VK_SP10 = 52
VK_SP11 = 53
VK_SP12 = 86
VK_ESC = 1
VK_1 = 2
VK_2 = 3
VK_3 = 4
VK_4 = 5
VK_5 = 6
VK_6 = 7
VK_7 = 8
VK_8 = 9
VK_9 = 10
VK_0 = 11
VK_Q = 16
VK_W = 17
VK_E = 18
VK_R = 19
VK_T = 20
VK_Y = 21
VK_U = 22
VK_I = 23
VK_O = 24
VK_P = 25
VK_A = 30
VK_S = 31
VK_D = 32
VK_F = 33
VK_G = 34
VK_H = 35
VK_J = 36
VK_K = 37
VK_L = 38
VK_Z = 44
VK_X = 45
VK_C = 46
VK_V = 47
VK_B = 48
VK_N = 49
VK_M = 50
VK_F1 = 59
VK_F2 = 60
VK_F3 = 61
VK_F4 = 62
VK_F5 = 63
VK_F6 = 64
VK_F7 = 65
VK_F8 = 66
VK_F9 = 67
VK_F10 = 68
VK_F11 = 87
VK_F12 = 88
VK_F13 = 0x7C + 0xFFF
VK_F14 = 0x7D + 0xFFF
VK_F15 = 0x7E + 0xFFF
VK_F16 = 0x7F + 0xFFF
VK_F17 = 0x80 + 0xFFF
VK_F18 = 0x81 + 0xFFF
VK_F19 = 0x82 + 0xFFF
VK_F20 = 0x83 + 0xFFF
VK_F21 = 0x84 + 0xFFF
VK_F22 = 0x85 + 0xFFF
VK_F23 = 0x86 + 0xFFF
VK_F24 = 0x87 + 0xFFF
VK_NUMLOCK = 69
VK_SCROLLLOCK = 70
VK_RESERVED = 0
VK_MINUS = 12
VK_EQUAL = 13
VK_BACKSPACE = 14
VK_TAB = 15
VK_LEFTBRACE = 26
VK_RIGHTBRACE = 27
VK_ENTER = 28
VK_SEMICOLON = 39
VK_APOSTROPHE = 40
VK_GRAVE = 41
VK_BACKSLASH = 43
VK_COMMA = 51
VK_DOT = 52
VK_SLASH = 53
VK_KPASTERISK = 55
VK_SPACE = 57
VK_CAPSLOCK = 58
VK_KP0 = 82
VK_KP1 = 79
VK_KP2 = 80
VK_KP3 = 81
VK_KP4 = 75
VK_KP5 = 76
VK_KP6 = 77
VK_KP7 = 71
VK_KP8 = 72
VK_KP9 = 73
VK_KPMINUS = 74
VK_KPPLUS = 78
VK_KPDOT = 83
// I add 0xFFF for all Virtual key
VK_LBUTTON = 0x01 + 0xFFF
VK_RBUTTON = 0x02 + 0xFFF
VK_CANCEL = 0x03 + 0xFFF
VK_MBUTTON = 0x04 + 0xFFF
VK_XBUTTON1 = 0x05 + 0xFFF
VK_XBUTTON2 = 0x06 + 0xFFF
VK_BACK = 0x08 + 0xFFF
VK_CLEAR = 0x0C + 0xFFF
VK_PAUSE = 0x13 + 0xFFF
VK_CAPITAL = 0x14 + 0xFFF
VK_KANA = 0x15 + 0xFFF
VK_HANGUEL = 0x15 + 0xFFF
VK_HANGUL = 0x15 + 0xFFF
VK_JUNJA = 0x17 + 0xFFF
VK_FINAL = 0x18 + 0xFFF
VK_HANJA = 0x19 + 0xFFF
VK_KANJI = 0x19 + 0xFFF
VK_CONVERT = 0x1C + 0xFFF
VK_NONCONVERT = 0x1D + 0xFFF
VK_ACCEPT = 0x1E + 0xFFF
VK_MODECHANGE = 0x1F + 0xFFF
VK_PAGEUP = 0x21 + 0xFFF
VK_PAGEDOWN = 0x22 + 0xFFF
VK_END = 0x23 + 0xFFF
VK_HOME = 0x24 + 0xFFF
VK_LEFT = 0x25 + 0xFFF
VK_UP = 0x26 + 0xFFF
VK_RIGHT = 0x27 + 0xFFF
VK_DOWN = 0x28 + 0xFFF
VK_SELECT = 0x29 + 0xFFF
VK_PRINT = 0x2A + 0xFFF
VK_EXECUTE = 0x2B + 0xFFF
VK_SNAPSHOT = 0x2C + 0xFFF
VK_INSERT = 0x2D + 0xFFF
VK_DELETE = 0x2E + 0xFFF
VK_HELP = 0x2F + 0xFFF
VK_SCROLL = 0x91 + 0xFFF
VK_LMENU = 0xA4 + 0xFFF
VK_RMENU = 0xA5 + 0xFFF
VK_BROWSER_BACK = 0xA6 + 0xFFF
VK_BROWSER_FORWARD = 0xA7 + 0xFFF
VK_BROWSER_REFRESH = 0xA8 + 0xFFF
VK_BROWSER_STOP = 0xA9 + 0xFFF
VK_BROWSER_SEARCH = 0xAA + 0xFFF
VK_BROWSER_FAVORITES = 0xAB + 0xFFF
VK_BROWSER_HOME = 0xAC + 0xFFF
VK_VOLUME_MUTE = 0xAD + 0xFFF
VK_VOLUME_DOWN = 0xAE + 0xFFF
VK_VOLUME_UP = 0xAF + 0xFFF
VK_MEDIA_NEXT_TRACK = 0xB0 + 0xFFF
VK_MEDIA_PREV_TRACK = 0xB1 + 0xFFF
VK_MEDIA_STOP = 0xB2 + 0xFFF
VK_MEDIA_PLAY_PAUSE = 0xB3 + 0xFFF
VK_LAUNCH_MAIL = 0xB4 + 0xFFF
VK_LAUNCH_MEDIA_SELECT = 0xB5 + 0xFFF
VK_LAUNCH_APP1 = 0xB6 + 0xFFF
VK_LAUNCH_APP2 = 0xB7 + 0xFFF
VK_OEM_1 = 0xBA + 0xFFF
VK_OEM_PLUS = 0xBB + 0xFFF
VK_OEM_COMMA = 0xBC + 0xFFF
VK_OEM_MINUS = 0xBD + 0xFFF
VK_OEM_PERIOD = 0xBE + 0xFFF
VK_OEM_2 = 0xBF + 0xFFF
VK_OEM_3 = 0xC0 + 0xFFF
VK_OEM_4 = 0xDB + 0xFFF
VK_OEM_5 = 0xDC + 0xFFF
VK_OEM_6 = 0xDD + 0xFFF
VK_OEM_7 = 0xDE + 0xFFF
VK_OEM_8 = 0xDF + 0xFFF
VK_OEM_102 = 0xE2 + 0xFFF
VK_PROCESSKEY = 0xE5 + 0xFFF
VK_PACKET = 0xE7 + 0xFFF
VK_ATTN = 0xF6 + 0xFFF
VK_CRSEL = 0xF7 + 0xFFF
VK_EXSEL = 0xF8 + 0xFFF
VK_EREOF = 0xF9 + 0xFFF
VK_PLAY = 0xFA + 0xFFF
VK_ZOOM = 0xFB + 0xFFF
VK_NONAME = 0xFC + 0xFFF
VK_PA1 = 0xFD + 0xFFF
VK_OEM_CLEAR = 0xFE + 0xFFF
)

BIN
vendor/github.com/micmonay/keybd_event/keyboard.png generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

8
vendor/github.com/moby/term/.gitignore generated vendored Normal file
View file

@ -0,0 +1,8 @@
# if you want to ignore files created by your editor/tools, consider using a
# global .gitignore or .git/info/exclude see https://help.github.com/articles/ignoring-files
.*
!.github
!.gitignore
profile.out
# support running go modules in vendor mode for local development
vendor/

191
vendor/github.com/moby/term/LICENSE generated vendored Normal file
View file

@ -0,0 +1,191 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2013-2018 Docker, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

36
vendor/github.com/moby/term/README.md generated vendored Normal file
View file

@ -0,0 +1,36 @@
# term - utilities for dealing with terminals
![Test](https://github.com/moby/term/workflows/Test/badge.svg) [![GoDoc](https://godoc.org/github.com/moby/term?status.svg)](https://godoc.org/github.com/moby/term) [![Go Report Card](https://goreportcard.com/badge/github.com/moby/term)](https://goreportcard.com/report/github.com/moby/term)
term provides structures and helper functions to work with terminal (state, sizes).
#### Using term
```go
package main
import (
"log"
"os"
"github.com/moby/term"
)
func main() {
fd := os.Stdin.Fd()
if term.IsTerminal(fd) {
ws, err := term.GetWinsize(fd)
if err != nil {
log.Fatalf("term.GetWinsize: %s", err)
}
log.Printf("%d:%d\n", ws.Height, ws.Width)
}
}
```
## Contributing
Want to hack on term? [Docker's contributions guidelines](https://github.com/docker/docker/blob/master/CONTRIBUTING.md) apply.
## Copyright and license
Code and documentation copyright 2015 Docker, inc. Code released under the Apache 2.0 license. Docs released under Creative commons.

66
vendor/github.com/moby/term/ascii.go generated vendored Normal file
View file

@ -0,0 +1,66 @@
package term
import (
"fmt"
"strings"
)
// ASCII list the possible supported ASCII key sequence
var ASCII = []string{
"ctrl-@",
"ctrl-a",
"ctrl-b",
"ctrl-c",
"ctrl-d",
"ctrl-e",
"ctrl-f",
"ctrl-g",
"ctrl-h",
"ctrl-i",
"ctrl-j",
"ctrl-k",
"ctrl-l",
"ctrl-m",
"ctrl-n",
"ctrl-o",
"ctrl-p",
"ctrl-q",
"ctrl-r",
"ctrl-s",
"ctrl-t",
"ctrl-u",
"ctrl-v",
"ctrl-w",
"ctrl-x",
"ctrl-y",
"ctrl-z",
"ctrl-[",
"ctrl-\\",
"ctrl-]",
"ctrl-^",
"ctrl-_",
}
// ToBytes converts a string representing a suite of key-sequence to the corresponding ASCII code.
func ToBytes(keys string) ([]byte, error) {
codes := []byte{}
next:
for _, key := range strings.Split(keys, ",") {
if len(key) != 1 {
for code, ctrl := range ASCII {
if ctrl == key {
codes = append(codes, byte(code))
continue next
}
}
if key == "DEL" {
codes = append(codes, 127)
} else {
return nil, fmt.Errorf("Unknown character: '%s'", key)
}
} else {
codes = append(codes, key[0])
}
}
return codes, nil
}

88
vendor/github.com/moby/term/proxy.go generated vendored Normal file
View file

@ -0,0 +1,88 @@
package term
import (
"io"
)
// EscapeError is special error which returned by a TTY proxy reader's Read()
// method in case its detach escape sequence is read.
type EscapeError struct{}
func (EscapeError) Error() string {
return "read escape sequence"
}
// escapeProxy is used only for attaches with a TTY. It is used to proxy
// stdin keypresses from the underlying reader and look for the passed in
// escape key sequence to signal a detach.
type escapeProxy struct {
escapeKeys []byte
escapeKeyPos int
r io.Reader
buf []byte
}
// NewEscapeProxy returns a new TTY proxy reader which wraps the given reader
// and detects when the specified escape keys are read, in which case the Read
// method will return an error of type EscapeError.
func NewEscapeProxy(r io.Reader, escapeKeys []byte) io.Reader {
return &escapeProxy{
escapeKeys: escapeKeys,
r: r,
}
}
func (r *escapeProxy) Read(buf []byte) (n int, err error) {
if len(r.escapeKeys) > 0 && r.escapeKeyPos == len(r.escapeKeys) {
return 0, EscapeError{}
}
if len(r.buf) > 0 {
n = copy(buf, r.buf)
r.buf = r.buf[n:]
}
nr, err := r.r.Read(buf[n:])
n += nr
if len(r.escapeKeys) == 0 {
return n, err
}
for i := 0; i < n; i++ {
if buf[i] == r.escapeKeys[r.escapeKeyPos] {
r.escapeKeyPos++
// Check if the full escape sequence is matched.
if r.escapeKeyPos == len(r.escapeKeys) {
n = i + 1 - r.escapeKeyPos
if n < 0 {
n = 0
}
return n, EscapeError{}
}
continue
}
// If we need to prepend a partial escape sequence from the previous
// read, make sure the new buffer size doesn't exceed len(buf).
// Otherwise, preserve any extra data in a buffer for the next read.
if i < r.escapeKeyPos {
preserve := make([]byte, 0, r.escapeKeyPos+n)
preserve = append(preserve, r.escapeKeys[:r.escapeKeyPos]...)
preserve = append(preserve, buf[:n]...)
n = copy(buf, preserve)
i += r.escapeKeyPos
r.buf = append(r.buf, preserve[n:]...)
}
r.escapeKeyPos = 0
}
// If we're in the middle of reading an escape sequence, make sure we don't
// let the caller read it. If later on we find that this is not the escape
// sequence, we'll prepend it back to buf.
n -= r.escapeKeyPos
if n < 0 {
n = 0
}
return n, err
}

19
vendor/github.com/moby/term/tc.go generated vendored Normal file
View file

@ -0,0 +1,19 @@
// +build !windows
package term
import (
"golang.org/x/sys/unix"
)
func tcget(fd uintptr) (*Termios, error) {
p, err := unix.IoctlGetTermios(int(fd), getTermios)
if err != nil {
return nil, err
}
return p, nil
}
func tcset(fd uintptr, p *Termios) error {
return unix.IoctlSetTermios(int(fd), setTermios, p)
}

120
vendor/github.com/moby/term/term.go generated vendored Normal file
View file

@ -0,0 +1,120 @@
// +build !windows
// Package term provides structures and helper functions to work with
// terminal (state, sizes).
package term
import (
"errors"
"fmt"
"io"
"os"
"os/signal"
"golang.org/x/sys/unix"
)
var (
// ErrInvalidState is returned if the state of the terminal is invalid.
ErrInvalidState = errors.New("Invalid terminal state")
)
// State represents the state of the terminal.
type State struct {
termios Termios
}
// Winsize represents the size of the terminal window.
type Winsize struct {
Height uint16
Width uint16
x uint16
y uint16
}
// StdStreams returns the standard streams (stdin, stdout, stderr).
func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
return os.Stdin, os.Stdout, os.Stderr
}
// GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal.
func GetFdInfo(in interface{}) (uintptr, bool) {
var inFd uintptr
var isTerminalIn bool
if file, ok := in.(*os.File); ok {
inFd = file.Fd()
isTerminalIn = IsTerminal(inFd)
}
return inFd, isTerminalIn
}
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd uintptr) bool {
_, err := tcget(fd)
return err == nil
}
// RestoreTerminal restores the terminal connected to the given file descriptor
// to a previous state.
func RestoreTerminal(fd uintptr, state *State) error {
if state == nil {
return ErrInvalidState
}
return tcset(fd, &state.termios)
}
// SaveState saves the state of the terminal connected to the given file descriptor.
func SaveState(fd uintptr) (*State, error) {
termios, err := tcget(fd)
if err != nil {
return nil, err
}
return &State{termios: *termios}, nil
}
// DisableEcho applies the specified state to the terminal connected to the file
// descriptor, with echo disabled.
func DisableEcho(fd uintptr, state *State) error {
newState := state.termios
newState.Lflag &^= unix.ECHO
if err := tcset(fd, &newState); err != nil {
return err
}
handleInterrupt(fd, state)
return nil
}
// SetRawTerminal puts the terminal connected to the given file descriptor into
// raw mode and returns the previous state. On UNIX, this puts both the input
// and output into raw mode. On Windows, it only puts the input into raw mode.
func SetRawTerminal(fd uintptr) (*State, error) {
oldState, err := MakeRaw(fd)
if err != nil {
return nil, err
}
handleInterrupt(fd, oldState)
return oldState, err
}
// SetRawTerminalOutput puts the output of terminal connected to the given file
// descriptor into raw mode. On UNIX, this does nothing and returns nil for the
// state. On Windows, it disables LF -> CRLF translation.
func SetRawTerminalOutput(fd uintptr) (*State, error) {
return nil, nil
}
func handleInterrupt(fd uintptr, state *State) {
sigchan := make(chan os.Signal, 1)
signal.Notify(sigchan, os.Interrupt)
go func() {
for range sigchan {
// quit cleanly and the new terminal item is on a new line
fmt.Println()
signal.Stop(sigchan)
close(sigchan)
RestoreTerminal(fd, state)
os.Exit(1)
}
}()
}

231
vendor/github.com/moby/term/term_windows.go generated vendored Normal file
View file

@ -0,0 +1,231 @@
package term
import (
"io"
"os"
"os/signal"
windowsconsole "github.com/moby/term/windows"
"golang.org/x/sys/windows"
)
// State holds the console mode for the terminal.
type State struct {
mode uint32
}
// Winsize is used for window size.
type Winsize struct {
Height uint16
Width uint16
}
// vtInputSupported is true if winterm.ENABLE_VIRTUAL_TERMINAL_INPUT is supported by the console
var vtInputSupported bool
// StdStreams returns the standard streams (stdin, stdout, stderr).
func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
// Turn on VT handling on all std handles, if possible. This might
// fail, in which case we will fall back to terminal emulation.
var (
emulateStdin, emulateStdout, emulateStderr bool
mode uint32
)
fd := windows.Handle(os.Stdin.Fd())
if err := windows.GetConsoleMode(fd, &mode); err == nil {
// Validate that winterm.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it.
if err = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err != nil {
emulateStdin = true
} else {
vtInputSupported = true
}
// Unconditionally set the console mode back even on failure because SetConsoleMode
// remembers invalid bits on input handles.
_ = windows.SetConsoleMode(fd, mode)
}
fd = windows.Handle(os.Stdout.Fd())
if err := windows.GetConsoleMode(fd, &mode); err == nil {
// Validate winterm.DISABLE_NEWLINE_AUTO_RETURN is supported, but do not set it.
if err = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING|windows.DISABLE_NEWLINE_AUTO_RETURN); err != nil {
emulateStdout = true
} else {
_ = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
}
}
fd = windows.Handle(os.Stderr.Fd())
if err := windows.GetConsoleMode(fd, &mode); err == nil {
// Validate winterm.DISABLE_NEWLINE_AUTO_RETURN is supported, but do not set it.
if err = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING|windows.DISABLE_NEWLINE_AUTO_RETURN); err != nil {
emulateStderr = true
} else {
_ = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
}
}
// Temporarily use STD_INPUT_HANDLE, STD_OUTPUT_HANDLE and
// STD_ERROR_HANDLE from syscall rather than x/sys/windows as long as
// go-ansiterm hasn't switch to x/sys/windows.
// TODO: switch back to x/sys/windows once go-ansiterm has switched
if emulateStdin {
h := uint32(windows.STD_INPUT_HANDLE)
stdIn = windowsconsole.NewAnsiReader(int(h))
} else {
stdIn = os.Stdin
}
if emulateStdout {
h := uint32(windows.STD_OUTPUT_HANDLE)
stdOut = windowsconsole.NewAnsiWriter(int(h))
} else {
stdOut = os.Stdout
}
if emulateStderr {
h := uint32(windows.STD_ERROR_HANDLE)
stdErr = windowsconsole.NewAnsiWriter(int(h))
} else {
stdErr = os.Stderr
}
return
}
// GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal.
func GetFdInfo(in interface{}) (uintptr, bool) {
return windowsconsole.GetHandleInfo(in)
}
// GetWinsize returns the window size based on the specified file descriptor.
func GetWinsize(fd uintptr) (*Winsize, error) {
var info windows.ConsoleScreenBufferInfo
if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil {
return nil, err
}
winsize := &Winsize{
Width: uint16(info.Window.Right - info.Window.Left + 1),
Height: uint16(info.Window.Bottom - info.Window.Top + 1),
}
return winsize, nil
}
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd uintptr) bool {
var mode uint32
err := windows.GetConsoleMode(windows.Handle(fd), &mode)
return err == nil
}
// RestoreTerminal restores the terminal connected to the given file descriptor
// to a previous state.
func RestoreTerminal(fd uintptr, state *State) error {
return windows.SetConsoleMode(windows.Handle(fd), state.mode)
}
// SaveState saves the state of the terminal connected to the given file descriptor.
func SaveState(fd uintptr) (*State, error) {
var mode uint32
if err := windows.GetConsoleMode(windows.Handle(fd), &mode); err != nil {
return nil, err
}
return &State{mode: mode}, nil
}
// DisableEcho disables echo for the terminal connected to the given file descriptor.
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
func DisableEcho(fd uintptr, state *State) error {
mode := state.mode
mode &^= windows.ENABLE_ECHO_INPUT
mode |= windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT
err := windows.SetConsoleMode(windows.Handle(fd), mode)
if err != nil {
return err
}
// Register an interrupt handler to catch and restore prior state
restoreAtInterrupt(fd, state)
return nil
}
// SetRawTerminal puts the terminal connected to the given file descriptor into
// raw mode and returns the previous state. On UNIX, this puts both the input
// and output into raw mode. On Windows, it only puts the input into raw mode.
func SetRawTerminal(fd uintptr) (*State, error) {
state, err := MakeRaw(fd)
if err != nil {
return nil, err
}
// Register an interrupt handler to catch and restore prior state
restoreAtInterrupt(fd, state)
return state, err
}
// SetRawTerminalOutput puts the output of terminal connected to the given file
// descriptor into raw mode. On UNIX, this does nothing and returns nil for the
// state. On Windows, it disables LF -> CRLF translation.
func SetRawTerminalOutput(fd uintptr) (*State, error) {
state, err := SaveState(fd)
if err != nil {
return nil, err
}
// Ignore failures, since winterm.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this
// version of Windows.
_ = windows.SetConsoleMode(windows.Handle(fd), state.mode|windows.DISABLE_NEWLINE_AUTO_RETURN)
return state, err
}
// MakeRaw puts the terminal (Windows Console) connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be restored.
func MakeRaw(fd uintptr) (*State, error) {
state, err := SaveState(fd)
if err != nil {
return nil, err
}
mode := state.mode
// See
// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
// Disable these modes
mode &^= windows.ENABLE_ECHO_INPUT
mode &^= windows.ENABLE_LINE_INPUT
mode &^= windows.ENABLE_MOUSE_INPUT
mode &^= windows.ENABLE_WINDOW_INPUT
mode &^= windows.ENABLE_PROCESSED_INPUT
// Enable these modes
mode |= windows.ENABLE_EXTENDED_FLAGS
mode |= windows.ENABLE_INSERT_MODE
mode |= windows.ENABLE_QUICK_EDIT_MODE
if vtInputSupported {
mode |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT
}
err = windows.SetConsoleMode(windows.Handle(fd), mode)
if err != nil {
return nil, err
}
return state, nil
}
func restoreAtInterrupt(fd uintptr, state *State) {
sigchan := make(chan os.Signal, 1)
signal.Notify(sigchan, os.Interrupt)
go func() {
_ = <-sigchan
_ = RestoreTerminal(fd, state)
os.Exit(0)
}()
}

35
vendor/github.com/moby/term/termios.go generated vendored Normal file
View file

@ -0,0 +1,35 @@
// +build !windows
package term
import (
"golang.org/x/sys/unix"
)
// Termios is the Unix API for terminal I/O.
type Termios = unix.Termios
// MakeRaw puts the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func MakeRaw(fd uintptr) (*State, error) {
termios, err := tcget(fd)
if err != nil {
return nil, err
}
oldState := State{termios: *termios}
termios.Iflag &^= (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON)
termios.Oflag &^= unix.OPOST
termios.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN)
termios.Cflag &^= (unix.CSIZE | unix.PARENB)
termios.Cflag |= unix.CS8
termios.Cc[unix.VMIN] = 1
termios.Cc[unix.VTIME] = 0
if err := tcset(fd, termios); err != nil {
return nil, err
}
return &oldState, nil
}

12
vendor/github.com/moby/term/termios_bsd.go generated vendored Normal file
View file

@ -0,0 +1,12 @@
// +build darwin freebsd openbsd netbsd
package term
import (
"golang.org/x/sys/unix"
)
const (
getTermios = unix.TIOCGETA
setTermios = unix.TIOCSETA
)

12
vendor/github.com/moby/term/termios_nonbsd.go generated vendored Normal file
View file

@ -0,0 +1,12 @@
//+build !darwin,!freebsd,!netbsd,!openbsd,!windows
package term
import (
"golang.org/x/sys/unix"
)
const (
getTermios = unix.TCGETS
setTermios = unix.TCSETS
)

252
vendor/github.com/moby/term/windows/ansi_reader.go generated vendored Normal file
View file

@ -0,0 +1,252 @@
// +build windows
package windowsconsole
import (
"bytes"
"errors"
"fmt"
"io"
"os"
"strings"
"unsafe"
ansiterm "github.com/Azure/go-ansiterm"
"github.com/Azure/go-ansiterm/winterm"
)
const (
escapeSequence = ansiterm.KEY_ESC_CSI
)
// ansiReader wraps a standard input file (e.g., os.Stdin) providing ANSI sequence translation.
type ansiReader struct {
file *os.File
fd uintptr
buffer []byte
cbBuffer int
command []byte
}
// NewAnsiReader returns an io.ReadCloser that provides VT100 terminal emulation on top of a
// Windows console input handle.
func NewAnsiReader(nFile int) io.ReadCloser {
file, fd := winterm.GetStdFile(nFile)
return &ansiReader{
file: file,
fd: fd,
command: make([]byte, 0, ansiterm.ANSI_MAX_CMD_LENGTH),
buffer: make([]byte, 0),
}
}
// Close closes the wrapped file.
func (ar *ansiReader) Close() (err error) {
return ar.file.Close()
}
// Fd returns the file descriptor of the wrapped file.
func (ar *ansiReader) Fd() uintptr {
return ar.fd
}
// Read reads up to len(p) bytes of translated input events into p.
func (ar *ansiReader) Read(p []byte) (int, error) {
if len(p) == 0 {
return 0, nil
}
// Previously read bytes exist, read as much as we can and return
if len(ar.buffer) > 0 {
originalLength := len(ar.buffer)
copiedLength := copy(p, ar.buffer)
if copiedLength == originalLength {
ar.buffer = make([]byte, 0, len(p))
} else {
ar.buffer = ar.buffer[copiedLength:]
}
return copiedLength, nil
}
// Read and translate key events
events, err := readInputEvents(ar, len(p))
if err != nil {
return 0, err
} else if len(events) == 0 {
return 0, nil
}
keyBytes := translateKeyEvents(events, []byte(escapeSequence))
// Save excess bytes and right-size keyBytes
if len(keyBytes) > len(p) {
ar.buffer = keyBytes[len(p):]
keyBytes = keyBytes[:len(p)]
} else if len(keyBytes) == 0 {
return 0, nil
}
copiedLength := copy(p, keyBytes)
if copiedLength != len(keyBytes) {
return 0, errors.New("unexpected copy length encountered")
}
return copiedLength, nil
}
// readInputEvents polls until at least one event is available.
func readInputEvents(ar *ansiReader, maxBytes int) ([]winterm.INPUT_RECORD, error) {
// Determine the maximum number of records to retrieve
// -- Cast around the type system to obtain the size of a single INPUT_RECORD.
// unsafe.Sizeof requires an expression vs. a type-reference; the casting
// tricks the type system into believing it has such an expression.
recordSize := int(unsafe.Sizeof(*((*winterm.INPUT_RECORD)(unsafe.Pointer(&maxBytes)))))
countRecords := maxBytes / recordSize
if countRecords > ansiterm.MAX_INPUT_EVENTS {
countRecords = ansiterm.MAX_INPUT_EVENTS
} else if countRecords == 0 {
countRecords = 1
}
// Wait for and read input events
events := make([]winterm.INPUT_RECORD, countRecords)
nEvents := uint32(0)
eventsExist, err := winterm.WaitForSingleObject(ar.fd, winterm.WAIT_INFINITE)
if err != nil {
return nil, err
}
if eventsExist {
err = winterm.ReadConsoleInput(ar.fd, events, &nEvents)
if err != nil {
return nil, err
}
}
// Return a slice restricted to the number of returned records
return events[:nEvents], nil
}
// KeyEvent Translation Helpers
var arrowKeyMapPrefix = map[uint16]string{
winterm.VK_UP: "%s%sA",
winterm.VK_DOWN: "%s%sB",
winterm.VK_RIGHT: "%s%sC",
winterm.VK_LEFT: "%s%sD",
}
var keyMapPrefix = map[uint16]string{
winterm.VK_UP: "\x1B[%sA",
winterm.VK_DOWN: "\x1B[%sB",
winterm.VK_RIGHT: "\x1B[%sC",
winterm.VK_LEFT: "\x1B[%sD",
winterm.VK_HOME: "\x1B[1%s~", // showkey shows ^[[1
winterm.VK_END: "\x1B[4%s~", // showkey shows ^[[4
winterm.VK_INSERT: "\x1B[2%s~",
winterm.VK_DELETE: "\x1B[3%s~",
winterm.VK_PRIOR: "\x1B[5%s~",
winterm.VK_NEXT: "\x1B[6%s~",
winterm.VK_F1: "",
winterm.VK_F2: "",
winterm.VK_F3: "\x1B[13%s~",
winterm.VK_F4: "\x1B[14%s~",
winterm.VK_F5: "\x1B[15%s~",
winterm.VK_F6: "\x1B[17%s~",
winterm.VK_F7: "\x1B[18%s~",
winterm.VK_F8: "\x1B[19%s~",
winterm.VK_F9: "\x1B[20%s~",
winterm.VK_F10: "\x1B[21%s~",
winterm.VK_F11: "\x1B[23%s~",
winterm.VK_F12: "\x1B[24%s~",
}
// translateKeyEvents converts the input events into the appropriate ANSI string.
func translateKeyEvents(events []winterm.INPUT_RECORD, escapeSequence []byte) []byte {
var buffer bytes.Buffer
for _, event := range events {
if event.EventType == winterm.KEY_EVENT && event.KeyEvent.KeyDown != 0 {
buffer.WriteString(keyToString(&event.KeyEvent, escapeSequence))
}
}
return buffer.Bytes()
}
// keyToString maps the given input event record to the corresponding string.
func keyToString(keyEvent *winterm.KEY_EVENT_RECORD, escapeSequence []byte) string {
if keyEvent.UnicodeChar == 0 {
return formatVirtualKey(keyEvent.VirtualKeyCode, keyEvent.ControlKeyState, escapeSequence)
}
_, alt, control := getControlKeys(keyEvent.ControlKeyState)
if control {
// TODO(azlinux): Implement following control sequences
// <Ctrl>-D Signals the end of input from the keyboard; also exits current shell.
// <Ctrl>-H Deletes the first character to the left of the cursor. Also called the ERASE key.
// <Ctrl>-Q Restarts printing after it has been stopped with <Ctrl>-s.
// <Ctrl>-S Suspends printing on the screen (does not stop the program).
// <Ctrl>-U Deletes all characters on the current line. Also called the KILL key.
// <Ctrl>-E Quits current command and creates a core
}
// <Alt>+Key generates ESC N Key
if !control && alt {
return ansiterm.KEY_ESC_N + strings.ToLower(string(keyEvent.UnicodeChar))
}
return string(keyEvent.UnicodeChar)
}
// formatVirtualKey converts a virtual key (e.g., up arrow) into the appropriate ANSI string.
func formatVirtualKey(key uint16, controlState uint32, escapeSequence []byte) string {
shift, alt, control := getControlKeys(controlState)
modifier := getControlKeysModifier(shift, alt, control)
if format, ok := arrowKeyMapPrefix[key]; ok {
return fmt.Sprintf(format, escapeSequence, modifier)
}
if format, ok := keyMapPrefix[key]; ok {
return fmt.Sprintf(format, modifier)
}
return ""
}
// getControlKeys extracts the shift, alt, and ctrl key states.
func getControlKeys(controlState uint32) (shift, alt, control bool) {
shift = 0 != (controlState & winterm.SHIFT_PRESSED)
alt = 0 != (controlState & (winterm.LEFT_ALT_PRESSED | winterm.RIGHT_ALT_PRESSED))
control = 0 != (controlState & (winterm.LEFT_CTRL_PRESSED | winterm.RIGHT_CTRL_PRESSED))
return shift, alt, control
}
// getControlKeysModifier returns the ANSI modifier for the given combination of control keys.
func getControlKeysModifier(shift, alt, control bool) string {
if shift && alt && control {
return ansiterm.KEY_CONTROL_PARAM_8
}
if alt && control {
return ansiterm.KEY_CONTROL_PARAM_7
}
if shift && control {
return ansiterm.KEY_CONTROL_PARAM_6
}
if control {
return ansiterm.KEY_CONTROL_PARAM_5
}
if shift && alt {
return ansiterm.KEY_CONTROL_PARAM_4
}
if alt {
return ansiterm.KEY_CONTROL_PARAM_3
}
if shift {
return ansiterm.KEY_CONTROL_PARAM_2
}
return ""
}

56
vendor/github.com/moby/term/windows/ansi_writer.go generated vendored Normal file
View file

@ -0,0 +1,56 @@
// +build windows
package windowsconsole
import (
"io"
"os"
ansiterm "github.com/Azure/go-ansiterm"
"github.com/Azure/go-ansiterm/winterm"
)
// ansiWriter wraps a standard output file (e.g., os.Stdout) providing ANSI sequence translation.
type ansiWriter struct {
file *os.File
fd uintptr
infoReset *winterm.CONSOLE_SCREEN_BUFFER_INFO
command []byte
escapeSequence []byte
inAnsiSequence bool
parser *ansiterm.AnsiParser
}
// NewAnsiWriter returns an io.Writer that provides VT100 terminal emulation on top of a
// Windows console output handle.
func NewAnsiWriter(nFile int) io.Writer {
file, fd := winterm.GetStdFile(nFile)
info, err := winterm.GetConsoleScreenBufferInfo(fd)
if err != nil {
return nil
}
parser := ansiterm.CreateParser("Ground", winterm.CreateWinEventHandler(fd, file))
return &ansiWriter{
file: file,
fd: fd,
infoReset: info,
command: make([]byte, 0, ansiterm.ANSI_MAX_CMD_LENGTH),
escapeSequence: []byte(ansiterm.KEY_ESC_CSI),
parser: parser,
}
}
func (aw *ansiWriter) Fd() uintptr {
return aw.fd
}
// Write writes len(p) bytes from p to the underlying data stream.
func (aw *ansiWriter) Write(p []byte) (total int, err error) {
if len(p) == 0 {
return 0, nil
}
return aw.parser.Parse(p)
}

39
vendor/github.com/moby/term/windows/console.go generated vendored Normal file
View file

@ -0,0 +1,39 @@
// +build windows
package windowsconsole
import (
"os"
"golang.org/x/sys/windows"
)
// GetHandleInfo returns file descriptor and bool indicating whether the file is a console.
func GetHandleInfo(in interface{}) (uintptr, bool) {
switch t := in.(type) {
case *ansiReader:
return t.Fd(), true
case *ansiWriter:
return t.Fd(), true
}
var inFd uintptr
var isTerminal bool
if file, ok := in.(*os.File); ok {
inFd = file.Fd()
isTerminal = isConsole(inFd)
}
return inFd, isTerminal
}
// IsConsole returns true if the given file descriptor is a Windows Console.
// The code assumes that GetConsoleMode will return an error for file descriptors that are not a console.
// Deprecated: use golang.org/x/sys/windows.GetConsoleMode() or golang.org/x/term.IsTerminal()
var IsConsole = isConsole
func isConsole(fd uintptr) bool {
var mode uint32
err := windows.GetConsoleMode(windows.Handle(fd), &mode)
return err == nil
}

5
vendor/github.com/moby/term/windows/doc.go generated vendored Normal file
View file

@ -0,0 +1,5 @@
// These files implement ANSI-aware input and output streams for use by the Docker Windows client.
// When asked for the set of standard streams (e.g., stdin, stdout, stderr), the code will create
// and return pseudo-streams that convert ANSI sequences to / from Windows Console API calls.
package windowsconsole

20
vendor/github.com/moby/term/winsize.go generated vendored Normal file
View file

@ -0,0 +1,20 @@
// +build !windows
package term
import (
"golang.org/x/sys/unix"
)
// GetWinsize returns the window size based on the specified file descriptor.
func GetWinsize(fd uintptr) (*Winsize, error) {
uws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ)
ws := &Winsize{Height: uws.Row, Width: uws.Col, x: uws.Xpixel, y: uws.Ypixel}
return ws, err
}
// SetWinsize tries to set the specified window size for the specified file descriptor.
func SetWinsize(fd uintptr, ws *Winsize) error {
uws := &unix.Winsize{Row: ws.Height, Col: ws.Width, Xpixel: ws.x, Ypixel: ws.y}
return unix.IoctlSetWinsize(int(fd), unix.TIOCSWINSZ, uws)
}

12
vendor/modules.txt vendored
View file

@ -1,3 +1,7 @@
# github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1
## explicit; go 1.16
github.com/Azure/go-ansiterm
github.com/Azure/go-ansiterm/winterm
# github.com/Microsoft/go-winio v0.4.14
## explicit; go 1.12
github.com/Microsoft/go-winio
@ -39,6 +43,7 @@ github.com/docker/docker/api/types/volume
github.com/docker/docker/client
github.com/docker/docker/errdefs
github.com/docker/docker/pkg/stdcopy
github.com/docker/docker/pkg/term
# github.com/docker/go-connections v0.4.0
## explicit
github.com/docker/go-connections/nat
@ -103,6 +108,8 @@ github.com/gogo/protobuf/proto
# github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
## explicit
github.com/golang-collections/collections/stack
# github.com/google/go-cmp v0.5.5
## explicit; go 1.8
# github.com/gookit/color v1.5.0
## explicit; go 1.13
github.com/gookit/color
@ -142,8 +149,13 @@ github.com/mcuadros/go-lookup
# github.com/mgutz/str v1.2.0
## explicit
github.com/mgutz/str
# github.com/micmonay/keybd_event v1.1.1
## explicit; go 1.16
github.com/micmonay/keybd_event
# github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6
## explicit; go 1.13
github.com/moby/term
github.com/moby/term/windows
# github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c
## explicit
# github.com/onsi/ginkgo v1.8.0