Revamp escape sequence processing for WSL
Also add support for alt-[0-9] and f1[12]
This commit is contained in:
parent
4b332d831e
commit
8c661d4e8c
@ -330,6 +330,10 @@ func isAlphabet(char uint8) bool {
|
|||||||
return char >= 'a' && char <= 'z'
|
return char >= 'a' && char <= 'z'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isNumeric(char uint8) bool {
|
||||||
|
return char >= '0' && char <= '9'
|
||||||
|
}
|
||||||
|
|
||||||
func parseAlgo(str string) algo.Algo {
|
func parseAlgo(str string) algo.Algo {
|
||||||
switch str {
|
switch str {
|
||||||
case "v1":
|
case "v1":
|
||||||
@ -406,11 +410,17 @@ func parseKeyChords(str string, message string) map[int]string {
|
|||||||
chord = tui.DoubleClick
|
chord = tui.DoubleClick
|
||||||
case "f10":
|
case "f10":
|
||||||
chord = tui.F10
|
chord = tui.F10
|
||||||
|
case "f11":
|
||||||
|
chord = tui.F11
|
||||||
|
case "f12":
|
||||||
|
chord = tui.F12
|
||||||
default:
|
default:
|
||||||
if len(key) == 6 && strings.HasPrefix(lkey, "ctrl-") && isAlphabet(lkey[5]) {
|
if len(key) == 6 && strings.HasPrefix(lkey, "ctrl-") && isAlphabet(lkey[5]) {
|
||||||
chord = tui.CtrlA + int(lkey[5]) - 'a'
|
chord = tui.CtrlA + int(lkey[5]) - 'a'
|
||||||
} else if len(key) == 5 && strings.HasPrefix(lkey, "alt-") && isAlphabet(lkey[4]) {
|
} else if len(key) == 5 && strings.HasPrefix(lkey, "alt-") && isAlphabet(lkey[4]) {
|
||||||
chord = tui.AltA + int(lkey[4]) - 'a'
|
chord = tui.AltA + int(lkey[4]) - 'a'
|
||||||
|
} else if len(key) == 5 && strings.HasPrefix(lkey, "alt-") && isNumeric(lkey[4]) {
|
||||||
|
chord = tui.Alt0 + int(lkey[4]) - '0'
|
||||||
} else if len(key) == 2 && strings.HasPrefix(lkey, "f") && key[1] >= '1' && key[1] <= '9' {
|
} else if len(key) == 2 && strings.HasPrefix(lkey, "f") && key[1] >= '1' && key[1] <= '9' {
|
||||||
chord = tui.F1 + int(key[1]) - '1'
|
chord = tui.F1 + int(key[1]) - '1'
|
||||||
} else if utf8.RuneCountInString(key) == 1 {
|
} else if utf8.RuneCountInString(key) == 1 {
|
||||||
|
@ -10,8 +10,12 @@ package tui
|
|||||||
#cgo static LDFLAGS: -l:libncursesw.a -l:libtinfo.a -l:libgpm.a -ldl
|
#cgo static LDFLAGS: -l:libncursesw.a -l:libtinfo.a -l:libgpm.a -ldl
|
||||||
#cgo android static LDFLAGS: -l:libncurses.a -fPIE -march=armv7-a -mfpu=neon -mhard-float -Wl,--no-warn-mismatch
|
#cgo android static LDFLAGS: -l:libncurses.a -fPIE -march=armv7-a -mfpu=neon -mhard-float -Wl,--no-warn-mismatch
|
||||||
|
|
||||||
SCREEN *c_newterm () {
|
FILE* c_tty() {
|
||||||
return newterm(NULL, stderr, stdin);
|
return fopen("/dev/tty", "r");
|
||||||
|
}
|
||||||
|
|
||||||
|
SCREEN* c_newterm(FILE* tty) {
|
||||||
|
return newterm(NULL, stderr, tty);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
@ -20,7 +24,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
@ -59,7 +62,6 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_in *os.File
|
|
||||||
_screen *C.SCREEN
|
_screen *C.SCREEN
|
||||||
_colorMap map[int]ColorPair
|
_colorMap map[int]ColorPair
|
||||||
_colorFn func(ColorPair, Attr) C.int
|
_colorFn func(ColorPair, Attr) C.int
|
||||||
@ -81,18 +83,13 @@ func DefaultTheme() *ColorTheme {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Init(theme *ColorTheme, black bool, mouse bool) {
|
func Init(theme *ColorTheme, black bool, mouse bool) {
|
||||||
{
|
|
||||||
in, err := os.OpenFile("/dev/tty", syscall.O_RDONLY, 0)
|
|
||||||
if err != nil {
|
|
||||||
panic("Failed to open /dev/tty")
|
|
||||||
}
|
|
||||||
_in = in
|
|
||||||
// Break STDIN
|
|
||||||
// syscall.Dup2(int(in.Fd()), int(os.Stdin.Fd()))
|
|
||||||
}
|
|
||||||
|
|
||||||
C.setlocale(C.LC_ALL, C.CString(""))
|
C.setlocale(C.LC_ALL, C.CString(""))
|
||||||
_screen = C.c_newterm()
|
tty := C.c_tty()
|
||||||
|
if tty == nil {
|
||||||
|
fmt.Println("Failed to open /dev/tty")
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
_screen = C.c_newterm(tty)
|
||||||
if _screen == nil {
|
if _screen == nil {
|
||||||
fmt.Println("Invalid $TERM: " + os.Getenv("TERM"))
|
fmt.Println("Invalid $TERM: " + os.Getenv("TERM"))
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
@ -100,9 +97,14 @@ func Init(theme *ColorTheme, black bool, mouse bool) {
|
|||||||
C.set_term(_screen)
|
C.set_term(_screen)
|
||||||
if mouse {
|
if mouse {
|
||||||
C.mousemask(C.ALL_MOUSE_EVENTS, nil)
|
C.mousemask(C.ALL_MOUSE_EVENTS, nil)
|
||||||
|
C.mouseinterval(0)
|
||||||
}
|
}
|
||||||
C.noecho()
|
C.noecho()
|
||||||
C.raw() // stty dsusp undef
|
C.raw() // stty dsusp undef
|
||||||
|
C.nonl()
|
||||||
|
C.keypad(C.stdscr, true)
|
||||||
|
C.set_escdelay(200)
|
||||||
|
C.timeout(100) // ESCDELAY 200ms + timeout 100ms
|
||||||
|
|
||||||
_color = theme != nil
|
_color = theme != nil
|
||||||
if _color {
|
if _color {
|
||||||
@ -283,246 +285,167 @@ func PairFor(fg Color, bg Color) ColorPair {
|
|||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
func getch(nonblock bool) int {
|
func consume(expects ...rune) bool {
|
||||||
b := make([]byte, 1)
|
for _, r := range expects {
|
||||||
syscall.SetNonblock(int(_in.Fd()), nonblock)
|
if int(C.getch()) != int(r) {
|
||||||
_, err := _in.Read(b)
|
return false
|
||||||
if err != nil {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return int(b[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetBytes() []byte {
|
|
||||||
c := getch(false)
|
|
||||||
retries := 0
|
|
||||||
if c == 27 {
|
|
||||||
// Wait for additional keys after ESC for 100ms (10 * 10ms)
|
|
||||||
retries = 10
|
|
||||||
}
|
|
||||||
_buf = append(_buf, byte(c))
|
|
||||||
|
|
||||||
for {
|
|
||||||
c = getch(true)
|
|
||||||
if c == -1 {
|
|
||||||
if retries > 0 {
|
|
||||||
retries--
|
|
||||||
time.Sleep(10 * time.Millisecond)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
retries = 0
|
|
||||||
_buf = append(_buf, byte(c))
|
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
return _buf
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 27 (91 79) 77 type x y
|
func escSequence() Event {
|
||||||
func mouseSequence(sz *int) Event {
|
// nodelay is not thread-safe (e.g. <ESC><CTRL-P>)
|
||||||
if len(_buf) < 6 {
|
// C.nodelay(C.stdscr, true)
|
||||||
return Event{Invalid, 0, nil}
|
c := C.getch()
|
||||||
}
|
switch c {
|
||||||
*sz = 6
|
case C.ERR:
|
||||||
switch _buf[3] {
|
|
||||||
case 32, 36, 40, 48, // mouse-down / shift / cmd / ctrl
|
|
||||||
35, 39, 43, 51: // mouse-up / shift / cmd / ctrl
|
|
||||||
mod := _buf[3] >= 36
|
|
||||||
down := _buf[3]%2 == 0
|
|
||||||
x := int(_buf[4] - 33)
|
|
||||||
y := int(_buf[5] - 33)
|
|
||||||
double := false
|
|
||||||
if down {
|
|
||||||
now := time.Now()
|
|
||||||
if now.Sub(_prevDownTime) < doubleClickDuration {
|
|
||||||
_clickY = append(_clickY, y)
|
|
||||||
} else {
|
|
||||||
_clickY = []int{y}
|
|
||||||
}
|
|
||||||
_prevDownTime = now
|
|
||||||
} else {
|
|
||||||
if len(_clickY) > 1 && _clickY[0] == _clickY[1] &&
|
|
||||||
time.Now().Sub(_prevDownTime) < doubleClickDuration {
|
|
||||||
double = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Event{Mouse, 0, &MouseEvent{y, x, 0, down, double, mod}}
|
|
||||||
case 96, 100, 104, 112, // scroll-up / shift / cmd / ctrl
|
|
||||||
97, 101, 105, 113: // scroll-down / shift / cmd / ctrl
|
|
||||||
mod := _buf[3] >= 100
|
|
||||||
s := 1 - int(_buf[3]%2)*2
|
|
||||||
x := int(_buf[4] - 33)
|
|
||||||
y := int(_buf[5] - 33)
|
|
||||||
return Event{Mouse, 0, &MouseEvent{y, x, s, false, false, mod}}
|
|
||||||
}
|
|
||||||
return Event{Invalid, 0, nil}
|
|
||||||
}
|
|
||||||
|
|
||||||
func escSequence(sz *int) Event {
|
|
||||||
if len(_buf) < 2 {
|
|
||||||
return Event{ESC, 0, nil}
|
return Event{ESC, 0, nil}
|
||||||
}
|
case CtrlM:
|
||||||
*sz = 2
|
|
||||||
switch _buf[1] {
|
|
||||||
case 13:
|
|
||||||
return Event{AltEnter, 0, nil}
|
return Event{AltEnter, 0, nil}
|
||||||
case 32:
|
case '/':
|
||||||
return Event{AltSpace, 0, nil}
|
|
||||||
case 47:
|
|
||||||
return Event{AltSlash, 0, nil}
|
return Event{AltSlash, 0, nil}
|
||||||
case 98:
|
case ' ':
|
||||||
return Event{AltB, 0, nil}
|
return Event{AltSpace, 0, nil}
|
||||||
case 100:
|
case 127, C.KEY_BACKSPACE:
|
||||||
return Event{AltD, 0, nil}
|
|
||||||
case 102:
|
|
||||||
return Event{AltF, 0, nil}
|
|
||||||
case 127:
|
|
||||||
return Event{AltBS, 0, nil}
|
return Event{AltBS, 0, nil}
|
||||||
case 91, 79:
|
case '[':
|
||||||
if len(_buf) < 3 {
|
// Bracketed paste mode (printf "\e[?2004h")
|
||||||
|
// \e[200~ TEXT \e[201~
|
||||||
|
if consume('2', '0', '0', '~') {
|
||||||
return Event{Invalid, 0, nil}
|
return Event{Invalid, 0, nil}
|
||||||
}
|
}
|
||||||
*sz = 3
|
}
|
||||||
switch _buf[2] {
|
if c >= 'a' && c <= 'z' {
|
||||||
case 68:
|
return Event{AltA + int(c) - 'a', 0, nil}
|
||||||
return Event{Left, 0, nil}
|
}
|
||||||
case 67:
|
|
||||||
return Event{Right, 0, nil}
|
if c >= '0' && c <= '9' {
|
||||||
case 66:
|
return Event{Alt0 + int(c) - '0', 0, nil}
|
||||||
return Event{Down, 0, nil}
|
}
|
||||||
case 65:
|
|
||||||
return Event{Up, 0, nil}
|
// Don't care. Ignore the rest.
|
||||||
case 90:
|
for ; c != C.ERR; c = C.getch() {
|
||||||
return Event{BTab, 0, nil}
|
|
||||||
case 72:
|
|
||||||
return Event{Home, 0, nil}
|
|
||||||
case 70:
|
|
||||||
return Event{End, 0, nil}
|
|
||||||
case 77:
|
|
||||||
return mouseSequence(sz)
|
|
||||||
case 80:
|
|
||||||
return Event{F1, 0, nil}
|
|
||||||
case 81:
|
|
||||||
return Event{F2, 0, nil}
|
|
||||||
case 82:
|
|
||||||
return Event{F3, 0, nil}
|
|
||||||
case 83:
|
|
||||||
return Event{F4, 0, nil}
|
|
||||||
case 49, 50, 51, 52, 53, 54:
|
|
||||||
if len(_buf) < 4 {
|
|
||||||
return Event{Invalid, 0, nil}
|
|
||||||
}
|
|
||||||
*sz = 4
|
|
||||||
switch _buf[2] {
|
|
||||||
case 50:
|
|
||||||
if len(_buf) == 5 && _buf[4] == 126 {
|
|
||||||
*sz = 5
|
|
||||||
switch _buf[3] {
|
|
||||||
case 48:
|
|
||||||
return Event{F9, 0, nil}
|
|
||||||
case 49:
|
|
||||||
return Event{F10, 0, nil}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Bracketed paste mode \e[200~ / \e[201
|
|
||||||
if _buf[3] == 48 && (_buf[4] == 48 || _buf[4] == 49) && _buf[5] == 126 {
|
|
||||||
*sz = 6
|
|
||||||
return Event{Invalid, 0, nil}
|
|
||||||
}
|
|
||||||
return Event{Invalid, 0, nil} // INS
|
|
||||||
case 51:
|
|
||||||
return Event{Del, 0, nil}
|
|
||||||
case 52:
|
|
||||||
return Event{End, 0, nil}
|
|
||||||
case 53:
|
|
||||||
return Event{PgUp, 0, nil}
|
|
||||||
case 54:
|
|
||||||
return Event{PgDn, 0, nil}
|
|
||||||
case 49:
|
|
||||||
switch _buf[3] {
|
|
||||||
case 126:
|
|
||||||
return Event{Home, 0, nil}
|
|
||||||
case 53, 55, 56, 57:
|
|
||||||
if len(_buf) == 5 && _buf[4] == 126 {
|
|
||||||
*sz = 5
|
|
||||||
switch _buf[3] {
|
|
||||||
case 53:
|
|
||||||
return Event{F5, 0, nil}
|
|
||||||
case 55:
|
|
||||||
return Event{F6, 0, nil}
|
|
||||||
case 56:
|
|
||||||
return Event{F7, 0, nil}
|
|
||||||
case 57:
|
|
||||||
return Event{F8, 0, nil}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Event{Invalid, 0, nil}
|
|
||||||
case 59:
|
|
||||||
if len(_buf) != 6 {
|
|
||||||
return Event{Invalid, 0, nil}
|
|
||||||
}
|
|
||||||
*sz = 6
|
|
||||||
switch _buf[4] {
|
|
||||||
case 50:
|
|
||||||
switch _buf[5] {
|
|
||||||
case 68:
|
|
||||||
return Event{Home, 0, nil}
|
|
||||||
case 67:
|
|
||||||
return Event{End, 0, nil}
|
|
||||||
}
|
|
||||||
case 53:
|
|
||||||
switch _buf[5] {
|
|
||||||
case 68:
|
|
||||||
return Event{SLeft, 0, nil}
|
|
||||||
case 67:
|
|
||||||
return Event{SRight, 0, nil}
|
|
||||||
}
|
|
||||||
} // _buf[4]
|
|
||||||
} // _buf[3]
|
|
||||||
} // _buf[2]
|
|
||||||
} // _buf[2]
|
|
||||||
} // _buf[1]
|
|
||||||
if _buf[1] >= 'a' && _buf[1] <= 'z' {
|
|
||||||
return Event{AltA + int(_buf[1]) - 'a', 0, nil}
|
|
||||||
}
|
}
|
||||||
return Event{Invalid, 0, nil}
|
return Event{Invalid, 0, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetChar() Event {
|
func GetChar() Event {
|
||||||
if len(_buf) == 0 {
|
c := C.getch()
|
||||||
_buf = GetBytes()
|
switch c {
|
||||||
}
|
case C.ERR:
|
||||||
if len(_buf) == 0 {
|
return Event{Invalid, 0, nil}
|
||||||
panic("Empty _buffer")
|
case C.KEY_UP:
|
||||||
}
|
return Event{Up, 0, nil}
|
||||||
|
case C.KEY_DOWN:
|
||||||
sz := 1
|
return Event{Down, 0, nil}
|
||||||
defer func() {
|
case C.KEY_LEFT:
|
||||||
_buf = _buf[sz:]
|
return Event{Left, 0, nil}
|
||||||
}()
|
case C.KEY_RIGHT:
|
||||||
|
return Event{Right, 0, nil}
|
||||||
switch _buf[0] {
|
case C.KEY_HOME:
|
||||||
case CtrlC:
|
return Event{Home, 0, nil}
|
||||||
return Event{CtrlC, 0, nil}
|
case C.KEY_END:
|
||||||
case CtrlG:
|
return Event{End, 0, nil}
|
||||||
return Event{CtrlG, 0, nil}
|
case C.KEY_BACKSPACE:
|
||||||
case CtrlQ:
|
return Event{BSpace, 0, nil}
|
||||||
return Event{CtrlQ, 0, nil}
|
case C.KEY_F0 + 1:
|
||||||
|
return Event{F1, 0, nil}
|
||||||
|
case C.KEY_F0 + 2:
|
||||||
|
return Event{F2, 0, nil}
|
||||||
|
case C.KEY_F0 + 3:
|
||||||
|
return Event{F3, 0, nil}
|
||||||
|
case C.KEY_F0 + 4:
|
||||||
|
return Event{F4, 0, nil}
|
||||||
|
case C.KEY_F0 + 5:
|
||||||
|
return Event{F5, 0, nil}
|
||||||
|
case C.KEY_F0 + 6:
|
||||||
|
return Event{F6, 0, nil}
|
||||||
|
case C.KEY_F0 + 7:
|
||||||
|
return Event{F7, 0, nil}
|
||||||
|
case C.KEY_F0 + 8:
|
||||||
|
return Event{F8, 0, nil}
|
||||||
|
case C.KEY_F0 + 9:
|
||||||
|
return Event{F9, 0, nil}
|
||||||
|
case C.KEY_F0 + 10:
|
||||||
|
return Event{F10, 0, nil}
|
||||||
|
case C.KEY_F0 + 11:
|
||||||
|
return Event{F11, 0, nil}
|
||||||
|
case C.KEY_F0 + 12:
|
||||||
|
return Event{F12, 0, nil}
|
||||||
|
case C.KEY_DC:
|
||||||
|
return Event{Del, 0, nil}
|
||||||
|
case C.KEY_PPAGE:
|
||||||
|
return Event{PgUp, 0, nil}
|
||||||
|
case C.KEY_NPAGE:
|
||||||
|
return Event{PgDn, 0, nil}
|
||||||
|
case C.KEY_BTAB:
|
||||||
|
return Event{BTab, 0, nil}
|
||||||
|
case C.KEY_ENTER:
|
||||||
|
return Event{CtrlM, 0, nil}
|
||||||
|
case C.KEY_SLEFT:
|
||||||
|
return Event{SLeft, 0, nil}
|
||||||
|
case C.KEY_SRIGHT:
|
||||||
|
return Event{SRight, 0, nil}
|
||||||
|
case C.KEY_MOUSE:
|
||||||
|
var me C.MEVENT
|
||||||
|
if C.getmouse(&me) != C.ERR {
|
||||||
|
mod := ((me.bstate & C.BUTTON_SHIFT) | (me.bstate & C.BUTTON_CTRL) | (me.bstate & C.BUTTON_ALT)) > 0
|
||||||
|
x := int(me.x)
|
||||||
|
y := int(me.y)
|
||||||
|
/* Cannot use BUTTON1_DOUBLE_CLICKED due to mouseinterval(0) */
|
||||||
|
if (me.bstate & C.BUTTON1_PRESSED) > 0 {
|
||||||
|
now := time.Now()
|
||||||
|
if now.Sub(_prevDownTime) < doubleClickDuration {
|
||||||
|
_clickY = append(_clickY, y)
|
||||||
|
} else {
|
||||||
|
_clickY = []int{y}
|
||||||
|
_prevDownTime = now
|
||||||
|
}
|
||||||
|
return Event{Mouse, 0, &MouseEvent{y, x, 0, true, false, mod}}
|
||||||
|
} else if (me.bstate & C.BUTTON1_RELEASED) > 0 {
|
||||||
|
double := false
|
||||||
|
if len(_clickY) > 1 && _clickY[0] == _clickY[1] &&
|
||||||
|
time.Now().Sub(_prevDownTime) < doubleClickDuration {
|
||||||
|
double = true
|
||||||
|
}
|
||||||
|
return Event{Mouse, 0, &MouseEvent{y, x, 0, false, double, mod}}
|
||||||
|
} else if (me.bstate&0x8000000) > 0 || (me.bstate&0x80) > 0 {
|
||||||
|
return Event{Mouse, 0, &MouseEvent{y, x, -1, false, false, mod}}
|
||||||
|
} else if (me.bstate & C.BUTTON4_PRESSED) > 0 {
|
||||||
|
return Event{Mouse, 0, &MouseEvent{y, x, 1, false, false, mod}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Event{Invalid, 0, nil}
|
||||||
|
case C.KEY_RESIZE:
|
||||||
|
return Event{Invalid, 0, nil}
|
||||||
|
case ESC:
|
||||||
|
return escSequence()
|
||||||
case 127:
|
case 127:
|
||||||
return Event{BSpace, 0, nil}
|
return Event{BSpace, 0, nil}
|
||||||
case ESC:
|
}
|
||||||
return escSequence(&sz)
|
// CTRL-A ~ CTRL-Z
|
||||||
|
if c >= CtrlA && c <= CtrlZ {
|
||||||
|
return Event{int(c), 0, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CTRL-A ~ CTRL-Z
|
// Multi-byte character
|
||||||
if _buf[0] <= CtrlZ {
|
buffer := []byte{byte(c)}
|
||||||
return Event{int(_buf[0]), 0, nil}
|
for {
|
||||||
|
r, _ := utf8.DecodeRune(buffer)
|
||||||
|
if r != utf8.RuneError {
|
||||||
|
return Event{Rune, r, nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
c := C.getch()
|
||||||
|
if c == C.ERR {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if c >= C.KEY_CODE_YES {
|
||||||
|
C.ungetch(c)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
buffer = append(buffer, byte(c))
|
||||||
}
|
}
|
||||||
r, rsz := utf8.DecodeRune(_buf)
|
return Event{Invalid, 0, nil}
|
||||||
if r == utf8.RuneError {
|
|
||||||
return Event{ESC, 0, nil}
|
|
||||||
}
|
|
||||||
sz = rsz
|
|
||||||
return Event{Rune, r, nil}
|
|
||||||
}
|
}
|
||||||
|
@ -207,8 +207,8 @@ func GetChar() Event {
|
|||||||
_clickY = append(_clickY, x)
|
_clickY = append(_clickY, x)
|
||||||
} else {
|
} else {
|
||||||
_clickY = []int{x}
|
_clickY = []int{x}
|
||||||
|
_prevDownTime = now
|
||||||
}
|
}
|
||||||
_prevDownTime = now
|
|
||||||
} else {
|
} else {
|
||||||
if len(_clickY) > 1 && _clickY[0] == _clickY[1] &&
|
if len(_clickY) > 1 && _clickY[0] == _clickY[1] &&
|
||||||
time.Now().Sub(_prevDownTime) < doubleClickDuration {
|
time.Now().Sub(_prevDownTime) < doubleClickDuration {
|
||||||
@ -326,9 +326,9 @@ func GetChar() Event {
|
|||||||
case tcell.KeyF10:
|
case tcell.KeyF10:
|
||||||
return Event{F10, 0, nil}
|
return Event{F10, 0, nil}
|
||||||
case tcell.KeyF11:
|
case tcell.KeyF11:
|
||||||
return Event{Invalid, 0, nil}
|
return Event{F11, 0, nil}
|
||||||
case tcell.KeyF12:
|
case tcell.KeyF12:
|
||||||
return Event{Invalid, 0, nil}
|
return Event{F12, 0, nil}
|
||||||
|
|
||||||
// ev.Ch doesn't work for some reason for space:
|
// ev.Ch doesn't work for some reason for space:
|
||||||
case tcell.KeyRune:
|
case tcell.KeyRune:
|
||||||
@ -343,6 +343,9 @@ func GetChar() Event {
|
|||||||
if r >= 'a' && r <= 'z' {
|
if r >= 'a' && r <= 'z' {
|
||||||
return Event{AltA + int(r) - 'a', 0, nil}
|
return Event{AltA + int(r) - 'a', 0, nil}
|
||||||
}
|
}
|
||||||
|
if r >= '0' && r <= '9' {
|
||||||
|
return Event{Alt0 + int(r) - '0', 0, nil}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Event{Rune, r, nil}
|
return Event{Rune, r, nil}
|
||||||
|
|
||||||
|
@ -67,18 +67,24 @@ const (
|
|||||||
F8
|
F8
|
||||||
F9
|
F9
|
||||||
F10
|
F10
|
||||||
|
F11
|
||||||
|
F12
|
||||||
|
|
||||||
AltEnter
|
AltEnter
|
||||||
AltSpace
|
AltSpace
|
||||||
AltSlash
|
AltSlash
|
||||||
AltBS
|
AltBS
|
||||||
AltA
|
|
||||||
|
Alt0
|
||||||
|
)
|
||||||
|
|
||||||
|
const ( // Reset iota
|
||||||
|
AltA = Alt0 + 'a' - '0' + iota
|
||||||
AltB
|
AltB
|
||||||
AltC
|
AltC
|
||||||
AltD
|
AltD
|
||||||
AltE
|
AltE
|
||||||
AltF
|
AltF
|
||||||
|
|
||||||
AltZ = AltA + 'z' - 'a'
|
AltZ = AltA + 'z' - 'a'
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -136,7 +142,6 @@ type MouseEvent struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_buf []byte
|
|
||||||
_color bool
|
_color bool
|
||||||
_prevDownTime time.Time
|
_prevDownTime time.Time
|
||||||
_clickY []int
|
_clickY []int
|
||||||
|
Loading…
Reference in New Issue
Block a user