Updated vendor termbox
This commit is contained in:
parent
a8e9ca072c
commit
f67b7198e6
|
@ -14,7 +14,7 @@ There are also some interesting projects using termbox-go:
|
||||||
- [sokoban-go](https://github.com/rn2dy/sokoban-go) is an implementation of sokoban game.
|
- [sokoban-go](https://github.com/rn2dy/sokoban-go) is an implementation of sokoban game.
|
||||||
- [hecate](https://github.com/evanmiller/hecate) is a hex editor designed by Satan.
|
- [hecate](https://github.com/evanmiller/hecate) is a hex editor designed by Satan.
|
||||||
- [httopd](https://github.com/verdverm/httopd) is top for httpd logs.
|
- [httopd](https://github.com/verdverm/httopd) is top for httpd logs.
|
||||||
- [mop](https://github.com/michaeldv/mop) is stock market tracker for hackers.
|
- [mop](https://github.com/mop-tracker/mop) is stock market tracker for hackers.
|
||||||
- [termui](https://github.com/gizak/termui) is a terminal dashboard.
|
- [termui](https://github.com/gizak/termui) is a terminal dashboard.
|
||||||
- [termloop](https://github.com/JoelOtter/termloop) is a terminal game engine.
|
- [termloop](https://github.com/JoelOtter/termloop) is a terminal game engine.
|
||||||
- [xterm-color-chart](https://github.com/kutuluk/xterm-color-chart) is a XTerm 256 color chart.
|
- [xterm-color-chart](https://github.com/kutuluk/xterm-color-chart) is a XTerm 256 color chart.
|
||||||
|
@ -27,6 +27,13 @@ There are also some interesting projects using termbox-go:
|
||||||
- [lf](https://github.com/gokcehan/lf) is a terminal file manager
|
- [lf](https://github.com/gokcehan/lf) is a terminal file manager
|
||||||
- [rat](https://github.com/ericfreese/rat) lets you compose shell commands to build terminal applications.
|
- [rat](https://github.com/ericfreese/rat) lets you compose shell commands to build terminal applications.
|
||||||
- [httplab](https://github.com/gchaincl/httplab) An interactive web server.
|
- [httplab](https://github.com/gchaincl/httplab) An interactive web server.
|
||||||
|
- [tetris](https://github.com/MichaelS11/tetris) Go Tetris with AI option
|
||||||
|
- [wot](https://github.com/kyu-suke/wot) Wait time during command is completed.
|
||||||
|
- [2048-go](https://github.com/1984weed/2048-go) is 2048 in Go
|
||||||
|
- [jv](https://github.com/maxzender/jv) helps you view JSON on the command-line.
|
||||||
|
- [pinger](https://github.com/hirose31/pinger) helps you to monitor numerous hosts using ICMP ECHO_REQUEST.
|
||||||
|
- [vixl44](https://github.com/sebashwa/vixl44) lets you create pixel art inside your terminal using vim movements
|
||||||
|
- [zterm](https://github.com/varunrau/zterm) is a typing game inspired by http://zty.pe/
|
||||||
|
|
||||||
### API reference
|
### API reference
|
||||||
[godoc.org/github.com/nsf/termbox-go](http://godoc.org/github.com/nsf/termbox-go)
|
[godoc.org/github.com/nsf/termbox-go](http://godoc.org/github.com/nsf/termbox-go)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import "os"
|
||||||
import "os/signal"
|
import "os/signal"
|
||||||
import "syscall"
|
import "syscall"
|
||||||
import "runtime"
|
import "runtime"
|
||||||
|
import "time"
|
||||||
|
|
||||||
// public API
|
// public API
|
||||||
|
|
||||||
|
@ -253,8 +254,8 @@ func CellBuffer() []Cell {
|
||||||
// NOTE: This API is experimental and may change in future.
|
// NOTE: This API is experimental and may change in future.
|
||||||
func ParseEvent(data []byte) Event {
|
func ParseEvent(data []byte) Event {
|
||||||
event := Event{Type: EventKey}
|
event := Event{Type: EventKey}
|
||||||
ok := extract_event(data, &event)
|
status := extract_event(data, &event, false)
|
||||||
if !ok {
|
if status != event_extracted {
|
||||||
return Event{Type: EventNone, N: event.N}
|
return Event{Type: EventNone, N: event.N}
|
||||||
}
|
}
|
||||||
return event
|
return event
|
||||||
|
@ -303,34 +304,65 @@ func PollRawEvent(data []byte) Event {
|
||||||
|
|
||||||
// Wait for an event and return it. This is a blocking function call.
|
// Wait for an event and return it. This is a blocking function call.
|
||||||
func PollEvent() Event {
|
func PollEvent() Event {
|
||||||
|
// Constant governing macOS specific behavior. See https://github.com/nsf/termbox-go/issues/132
|
||||||
|
// This is an arbitrary delay which hopefully will be enough time for any lagging
|
||||||
|
// partial escape sequences to come through.
|
||||||
|
const esc_wait_delay = 100 * time.Millisecond
|
||||||
|
|
||||||
var event Event
|
var event Event
|
||||||
|
var esc_wait_timer *time.Timer
|
||||||
|
var esc_timeout <-chan time.Time
|
||||||
|
|
||||||
// try to extract event from input buffer, return on success
|
// try to extract event from input buffer, return on success
|
||||||
event.Type = EventKey
|
event.Type = EventKey
|
||||||
ok := extract_event(inbuf, &event)
|
status := extract_event(inbuf, &event, true)
|
||||||
if event.N != 0 {
|
if event.N != 0 {
|
||||||
copy(inbuf, inbuf[event.N:])
|
copy(inbuf, inbuf[event.N:])
|
||||||
inbuf = inbuf[:len(inbuf)-event.N]
|
inbuf = inbuf[:len(inbuf)-event.N]
|
||||||
}
|
}
|
||||||
if ok {
|
if status == event_extracted {
|
||||||
return event
|
return event
|
||||||
|
} else if status == esc_wait {
|
||||||
|
esc_wait_timer = time.NewTimer(esc_wait_delay)
|
||||||
|
esc_timeout = esc_wait_timer.C
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case ev := <-input_comm:
|
case ev := <-input_comm:
|
||||||
|
if esc_wait_timer != nil {
|
||||||
|
if !esc_wait_timer.Stop() {
|
||||||
|
<-esc_wait_timer.C
|
||||||
|
}
|
||||||
|
esc_wait_timer = nil
|
||||||
|
}
|
||||||
|
|
||||||
if ev.err != nil {
|
if ev.err != nil {
|
||||||
return Event{Type: EventError, Err: ev.err}
|
return Event{Type: EventError, Err: ev.err}
|
||||||
}
|
}
|
||||||
|
|
||||||
inbuf = append(inbuf, ev.data...)
|
inbuf = append(inbuf, ev.data...)
|
||||||
input_comm <- ev
|
input_comm <- ev
|
||||||
ok := extract_event(inbuf, &event)
|
status := extract_event(inbuf, &event, true)
|
||||||
if event.N != 0 {
|
if event.N != 0 {
|
||||||
copy(inbuf, inbuf[event.N:])
|
copy(inbuf, inbuf[event.N:])
|
||||||
inbuf = inbuf[:len(inbuf)-event.N]
|
inbuf = inbuf[:len(inbuf)-event.N]
|
||||||
}
|
}
|
||||||
if ok {
|
if status == event_extracted {
|
||||||
|
return event
|
||||||
|
} else if status == esc_wait {
|
||||||
|
esc_wait_timer = time.NewTimer(esc_wait_delay)
|
||||||
|
esc_timeout = esc_wait_timer.C
|
||||||
|
}
|
||||||
|
case <-esc_timeout:
|
||||||
|
esc_wait_timer = nil
|
||||||
|
|
||||||
|
status := extract_event(inbuf, &event, false)
|
||||||
|
if event.N != 0 {
|
||||||
|
copy(inbuf, inbuf[event.N:])
|
||||||
|
inbuf = inbuf[:len(inbuf)-event.N]
|
||||||
|
}
|
||||||
|
if status == event_extracted {
|
||||||
return event
|
return event
|
||||||
}
|
}
|
||||||
case <-interrupt_comm:
|
case <-interrupt_comm:
|
||||||
|
@ -418,12 +450,12 @@ func SetInputMode(mode InputMode) InputMode {
|
||||||
//
|
//
|
||||||
// 3. Output216 => [1..216]
|
// 3. Output216 => [1..216]
|
||||||
// This mode supports the 3rd range of the 256 mode only.
|
// This mode supports the 3rd range of the 256 mode only.
|
||||||
// But you dont need to provide an offset.
|
// But you don't need to provide an offset.
|
||||||
//
|
//
|
||||||
// 4. OutputGrayscale => [1..26]
|
// 4. OutputGrayscale => [1..26]
|
||||||
// This mode supports the 4th range of the 256 mode
|
// This mode supports the 4th range of the 256 mode
|
||||||
// and black and white colors from 3th range of the 256 mode
|
// and black and white colors from 3th range of the 256 mode
|
||||||
// But you dont need to provide an offset.
|
// But you don't need to provide an offset.
|
||||||
//
|
//
|
||||||
// In all modes, 0x00 represents the default color.
|
// In all modes, 0x00 represents the default color.
|
||||||
//
|
//
|
||||||
|
|
|
@ -148,7 +148,7 @@ const (
|
||||||
// using bitwise OR ('|'). Although, colors cannot be combined. But you can
|
// using bitwise OR ('|'). Although, colors cannot be combined. But you can
|
||||||
// combine attributes and a single color.
|
// combine attributes and a single color.
|
||||||
//
|
//
|
||||||
// It's worth mentioning that some platforms don't support certain attibutes.
|
// It's worth mentioning that some platforms don't support certain attributes.
|
||||||
// For example windows console doesn't support AttrUnderline. And on some
|
// For example windows console doesn't support AttrUnderline. And on some
|
||||||
// terminals applying AttrBold to background may result in blinking text. Use
|
// terminals applying AttrBold to background may result in blinking text. Use
|
||||||
// them with caution and test your code on various terminals.
|
// them with caution and test your code on various terminals.
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
// +build !darwin
|
||||||
|
|
||||||
|
package termbox
|
||||||
|
|
||||||
|
// On all systems other than macOS, disable behavior which will wait before
|
||||||
|
// deciding that the escape key was pressed, to account for partially send
|
||||||
|
// escape sequences, especially with regard to lengthy mouse sequences.
|
||||||
|
// See https://github.com/nsf/termbox-go/issues/132
|
||||||
|
func enable_wait_for_escape_sequence() bool {
|
||||||
|
return false
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package termbox
|
||||||
|
|
||||||
|
// On macOS, enable behavior which will wait before deciding that the escape
|
||||||
|
// key was pressed, to account for partially send escape sequences, especially
|
||||||
|
// with regard to lengthy mouse sequences.
|
||||||
|
// See https://github.com/nsf/termbox-go/issues/132
|
||||||
|
func enable_wait_for_escape_sequence() bool {
|
||||||
|
return true
|
||||||
|
}
|
|
@ -41,6 +41,14 @@ type input_event struct {
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type extract_event_res int
|
||||||
|
|
||||||
|
const (
|
||||||
|
event_not_extracted extract_event_res = iota
|
||||||
|
event_extracted
|
||||||
|
esc_wait
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// term specific sequences
|
// term specific sequences
|
||||||
keys []string
|
keys []string
|
||||||
|
@ -417,7 +425,7 @@ func parse_escape_sequence(event *Event, buf []byte) (int, bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if none of the keys match, let's try mouse seqences
|
// if none of the keys match, let's try mouse sequences
|
||||||
return parse_mouse_event(event, bufstr)
|
return parse_mouse_event(event, bufstr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,17 +448,27 @@ func extract_raw_event(data []byte, event *Event) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func extract_event(inbuf []byte, event *Event) bool {
|
func extract_event(inbuf []byte, event *Event, allow_esc_wait bool) extract_event_res {
|
||||||
if len(inbuf) == 0 {
|
if len(inbuf) == 0 {
|
||||||
event.N = 0
|
event.N = 0
|
||||||
return false
|
return event_not_extracted
|
||||||
}
|
}
|
||||||
|
|
||||||
if inbuf[0] == '\033' {
|
if inbuf[0] == '\033' {
|
||||||
// possible escape sequence
|
// possible escape sequence
|
||||||
if n, ok := parse_escape_sequence(event, inbuf); n != 0 {
|
if n, ok := parse_escape_sequence(event, inbuf); n != 0 {
|
||||||
event.N = n
|
event.N = n
|
||||||
return ok
|
if ok {
|
||||||
|
return event_extracted
|
||||||
|
} else {
|
||||||
|
return event_not_extracted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// possible partially read escape sequence; trigger a wait if appropriate
|
||||||
|
if enable_wait_for_escape_sequence() && allow_esc_wait {
|
||||||
|
event.N = 0
|
||||||
|
return esc_wait
|
||||||
}
|
}
|
||||||
|
|
||||||
// it's not escape sequence, then it's Alt or Esc, check input_mode
|
// it's not escape sequence, then it's Alt or Esc, check input_mode
|
||||||
|
@ -461,17 +479,17 @@ func extract_event(inbuf []byte, event *Event) bool {
|
||||||
event.Key = KeyEsc
|
event.Key = KeyEsc
|
||||||
event.Mod = 0
|
event.Mod = 0
|
||||||
event.N = 1
|
event.N = 1
|
||||||
return true
|
return event_extracted
|
||||||
case input_mode&InputAlt != 0:
|
case input_mode&InputAlt != 0:
|
||||||
// if we're in alt mode, set Alt modifier to event and redo parsing
|
// if we're in alt mode, set Alt modifier to event and redo parsing
|
||||||
event.Mod = ModAlt
|
event.Mod = ModAlt
|
||||||
ok := extract_event(inbuf[1:], event)
|
status := extract_event(inbuf[1:], event, false)
|
||||||
if ok {
|
if status == event_extracted {
|
||||||
event.N++
|
event.N++
|
||||||
} else {
|
} else {
|
||||||
event.N = 0
|
event.N = 0
|
||||||
}
|
}
|
||||||
return ok
|
return status
|
||||||
default:
|
default:
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
|
@ -486,7 +504,7 @@ func extract_event(inbuf []byte, event *Event) bool {
|
||||||
event.Ch = 0
|
event.Ch = 0
|
||||||
event.Key = Key(inbuf[0])
|
event.Key = Key(inbuf[0])
|
||||||
event.N = 1
|
event.N = 1
|
||||||
return true
|
return event_extracted
|
||||||
}
|
}
|
||||||
|
|
||||||
// the only possible option is utf8 rune
|
// the only possible option is utf8 rune
|
||||||
|
@ -494,10 +512,10 @@ func extract_event(inbuf []byte, event *Event) bool {
|
||||||
event.Ch = r
|
event.Ch = r
|
||||||
event.Key = 0
|
event.Key = 0
|
||||||
event.N = n
|
event.N = n
|
||||||
return true
|
return event_extracted
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return event_not_extracted
|
||||||
}
|
}
|
||||||
|
|
||||||
func fcntl(fd int, cmd int, arg int) (val int, err error) {
|
func fcntl(fd int, cmd int, arg int) (val int, err error) {
|
||||||
|
|
|
@ -63,6 +63,8 @@ const (
|
||||||
mouse_lmb = 0x1
|
mouse_lmb = 0x1
|
||||||
mouse_rmb = 0x2
|
mouse_rmb = 0x2
|
||||||
mouse_mmb = 0x4 | 0x8 | 0x10
|
mouse_mmb = 0x4 | 0x8 | 0x10
|
||||||
|
SM_CXMIN = 28
|
||||||
|
SM_CYMIN = 29
|
||||||
)
|
)
|
||||||
|
|
||||||
func (this coord) uintptr() uintptr {
|
func (this coord) uintptr() uintptr {
|
||||||
|
@ -70,6 +72,7 @@ func (this coord) uintptr() uintptr {
|
||||||
}
|
}
|
||||||
|
|
||||||
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||||
|
var moduser32 = syscall.NewLazyDLL("user32.dll")
|
||||||
var is_cjk = runewidth.IsEastAsian()
|
var is_cjk = runewidth.IsEastAsian()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -91,6 +94,7 @@ var (
|
||||||
proc_create_event = kernel32.NewProc("CreateEventW")
|
proc_create_event = kernel32.NewProc("CreateEventW")
|
||||||
proc_wait_for_multiple_objects = kernel32.NewProc("WaitForMultipleObjects")
|
proc_wait_for_multiple_objects = kernel32.NewProc("WaitForMultipleObjects")
|
||||||
proc_set_event = kernel32.NewProc("SetEvent")
|
proc_set_event = kernel32.NewProc("SetEvent")
|
||||||
|
get_system_metrics = moduser32.NewProc("GetSystemMetrics")
|
||||||
)
|
)
|
||||||
|
|
||||||
func set_console_active_screen_buffer(h syscall.Handle) (err error) {
|
func set_console_active_screen_buffer(h syscall.Handle) (err error) {
|
||||||
|
@ -397,15 +401,44 @@ func get_term_size(out syscall.Handle) coord {
|
||||||
return tmp_info.size
|
return tmp_info.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func get_win_min_size(out syscall.Handle) coord {
|
||||||
|
x, _, err := get_system_metrics.Call(SM_CXMIN)
|
||||||
|
y, _, err := get_system_metrics.Call(SM_CYMIN)
|
||||||
|
|
||||||
|
if x == 0 || y == 0 {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return coord{
|
||||||
|
x: short(x),
|
||||||
|
y: short(y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func get_win_size(out syscall.Handle) coord {
|
func get_win_size(out syscall.Handle) coord {
|
||||||
err := get_console_screen_buffer_info(out, &tmp_info)
|
err := get_console_screen_buffer_info(out, &tmp_info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return coord{
|
|
||||||
|
min_size := get_win_min_size(out)
|
||||||
|
|
||||||
|
size := coord{
|
||||||
x: tmp_info.window.right - tmp_info.window.left + 1,
|
x: tmp_info.window.right - tmp_info.window.left + 1,
|
||||||
y: tmp_info.window.bottom - tmp_info.window.top + 1,
|
y: tmp_info.window.bottom - tmp_info.window.top + 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if size.x < min_size.x {
|
||||||
|
size.x = min_size.x
|
||||||
|
}
|
||||||
|
|
||||||
|
if size.y < min_size.y {
|
||||||
|
size.y = min_size.y
|
||||||
|
}
|
||||||
|
|
||||||
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
func update_size_maybe() {
|
func update_size_maybe() {
|
||||||
|
|
Loading…
Reference in New Issue