mirror of
https://github.com/gdamore/tcell.git
synced 2025-04-24 13:48:51 +08:00
fixes #129 Very high IDLE_WAKE - Power consumption
fixes #164 KeyEscape does not work in Go 1.9 under Linux This is a complete refactor of the input loop for UNIX systems. We use a blocking reader on the TTY, and a separate select loop for timers and other events. This means that our idle use should be low now.
This commit is contained in:
parent
0a0db94084
commit
50f9ed7673
65
tscreen.go
65
tscreen.go
@ -1,4 +1,4 @@
|
||||
// Copyright 2016 The TCell Authors
|
||||
// Copyright 2017 The TCell Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use file except in compliance with the License.
|
||||
@ -20,6 +20,7 @@ import (
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/transform"
|
||||
@ -79,6 +80,9 @@ type tScreen struct {
|
||||
indoneq chan struct{}
|
||||
keyexist map[Key]bool
|
||||
keycodes map[string]*tKeyCode
|
||||
keychan chan []byte
|
||||
keytimer *time.Timer
|
||||
keyexpire time.Time
|
||||
cx int
|
||||
cy int
|
||||
mouse []byte
|
||||
@ -105,6 +109,8 @@ type tScreen struct {
|
||||
func (t *tScreen) Init() error {
|
||||
t.evch = make(chan Event, 10)
|
||||
t.indoneq = make(chan struct{})
|
||||
t.keychan = make(chan []byte, 10)
|
||||
t.keytimer = time.NewTimer(time.Millisecond * 50)
|
||||
t.charset = "UTF-8"
|
||||
|
||||
t.charset = getCharset()
|
||||
@ -164,6 +170,7 @@ func (t *tScreen) Init() error {
|
||||
t.resize()
|
||||
t.Unlock()
|
||||
|
||||
go t.mainLoop()
|
||||
go t.inputLoop()
|
||||
|
||||
return nil
|
||||
@ -1234,10 +1241,8 @@ func (t *tScreen) scanInput(buf *bytes.Buffer, expire bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *tScreen) inputLoop() {
|
||||
func (t *tScreen) mainLoop() {
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
chunk := make([]byte, 128)
|
||||
for {
|
||||
select {
|
||||
case <-t.quit:
|
||||
@ -1252,26 +1257,56 @@ func (t *tScreen) inputLoop() {
|
||||
t.draw()
|
||||
t.Unlock()
|
||||
continue
|
||||
default:
|
||||
case <-t.keytimer.C:
|
||||
// If the timer fired, and the current time
|
||||
// is after the expiration of the escape sequence,
|
||||
// then we assume the escape sequence reached it's
|
||||
// conclusion, and process the chunk independently.
|
||||
// This lets us detect conflicts such as a lone ESC.
|
||||
if buf.Len() > 0 {
|
||||
if time.Now().After(t.keyexpire) {
|
||||
t.scanInput(buf, true)
|
||||
}
|
||||
}
|
||||
if buf.Len() > 0 {
|
||||
if !t.keytimer.Stop() {
|
||||
select {
|
||||
case <-t.keytimer.C:
|
||||
default:
|
||||
}
|
||||
}
|
||||
t.keytimer.Reset(time.Millisecond * 50)
|
||||
}
|
||||
case chunk := <-t.keychan:
|
||||
buf.Write(chunk)
|
||||
t.keyexpire = time.Now().Add(time.Millisecond * 50)
|
||||
t.scanInput(buf, false)
|
||||
if !t.keytimer.Stop() {
|
||||
select {
|
||||
case <-t.keytimer.C:
|
||||
default:
|
||||
}
|
||||
}
|
||||
if buf.Len() > 0 {
|
||||
t.keytimer.Reset(time.Millisecond * 50)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *tScreen) inputLoop() {
|
||||
|
||||
chunk := make([]byte, 128)
|
||||
for {
|
||||
n, e := t.in.Read(chunk)
|
||||
switch e {
|
||||
case io.EOF:
|
||||
// If we timeout waiting for more bytes, then it's
|
||||
// time to give up on it. Even at 300 baud it takes
|
||||
// less than 0.5 ms to transmit a whole byte.
|
||||
if buf.Len() > 0 {
|
||||
t.scanInput(buf, true)
|
||||
}
|
||||
continue
|
||||
case nil:
|
||||
default:
|
||||
close(t.indoneq)
|
||||
return
|
||||
}
|
||||
buf.Write(chunk[:n])
|
||||
// Now we need to parse the input buffer for events
|
||||
t.scanInput(buf, false)
|
||||
t.keychan <- chunk[:n]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// +build darwin freebsd netbsd openbsd dragonfly
|
||||
|
||||
// Copyright 2015 The TCell Authors
|
||||
// Copyright 2017 The TCell Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use file except in compliance with the License.
|
||||
@ -61,13 +61,6 @@ func (t *tScreen) termioInit() error {
|
||||
newtios.Cflag &^= syscall.CSIZE | syscall.PARENB
|
||||
newtios.Cflag |= syscall.CS8
|
||||
|
||||
// We wake up at the earliest of 100 msec or when data is received.
|
||||
// We need to wake up frequently to permit us to exit cleanly and
|
||||
// close file descriptors on systems like Darwin, where close does
|
||||
// cause a wakeup. (Probably we could reasonably increase this to
|
||||
// something like 1 sec or 500 msec.)
|
||||
newtios.Cc[syscall.VMIN] = 0
|
||||
newtios.Cc[syscall.VTIME] = 1
|
||||
tios = uintptr(unsafe.Pointer(&newtios))
|
||||
|
||||
ioc = uintptr(syscall.TIOCSETA)
|
||||
|
@ -1,6 +1,6 @@
|
||||
// +build linux
|
||||
|
||||
// Copyright 2015 The TCell Authors
|
||||
// Copyright 2017 The TCell Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use file except in compliance with the License.
|
||||
@ -61,13 +61,13 @@ func (t *tScreen) termioInit() error {
|
||||
newtios.Cflag &^= syscall.CSIZE | syscall.PARENB
|
||||
newtios.Cflag |= syscall.CS8
|
||||
|
||||
// We wake up at the earliest of 100 msec or when data is received.
|
||||
// We need to wake up frequently to permit us to exit cleanly and
|
||||
// close file descriptors on systems like Darwin, where close does
|
||||
// cause a wakeup. (Probably we could reasonably increase this to
|
||||
// something like 1 sec or 500 msec.)
|
||||
newtios.Cc[syscall.VMIN] = 0
|
||||
newtios.Cc[syscall.VTIME] = 1
|
||||
// This is setup for blocking reads. In the past we attempted to
|
||||
// use non-blocking reads, but now a separate input loop and timer
|
||||
// copes with the problems we had on some systems (BSD/Darwin)
|
||||
// where close hung forever.
|
||||
newtios.Cc[syscall.VMIN] = 1
|
||||
newtios.Cc[syscall.VTIME] = 0
|
||||
|
||||
tios = uintptr(unsafe.Pointer(&newtios))
|
||||
|
||||
// Well this kind of sucks, because we don't have TCSETSF, but only
|
||||
|
@ -1,6 +1,6 @@
|
||||
// +build solaris
|
||||
|
||||
// Copyright 2015 The TCell Authors
|
||||
// Copyright 2017 The TCell Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use file except in compliance with the License.
|
||||
@ -152,13 +152,12 @@ func (t *tScreen) termioInit() error {
|
||||
newtios.c_cflag &^= C.CSIZE | C.PARENB
|
||||
newtios.c_cflag |= C.CS8
|
||||
|
||||
// We wake up at the earliest of 100 msec or when data is received.
|
||||
// We need to wake up frequently to permit us to exit cleanly and
|
||||
// close file descriptors on systems like Darwin, where close does
|
||||
// cause a wakeup. (Probably we could reasonably increase this to
|
||||
// something like 1 sec or 500 msec.)
|
||||
newtios.c_cc[C.VMIN] = 0
|
||||
newtios.c_cc[C.VTIME] = 1
|
||||
// This is setup for blocking reads. In the past we attempted to
|
||||
// use non-blocking reads, but now a separate input loop and timer
|
||||
// copes with the problems we had on some systems (BSD/Darwin)
|
||||
// where close hung forever.
|
||||
newtios.Cc[syscall.VMIN] = 1
|
||||
newtios.Cc[syscall.VTIME] = 0
|
||||
|
||||
if rv, e = C.tcsetattr(fd, C.TCSANOW|C.TCSAFLUSH, &newtios); rv != 0 {
|
||||
goto failed
|
||||
|
Loading…
x
Reference in New Issue
Block a user