split src/devices/input into src/devices/input/{raw,wrap}
This commit is contained in:
101
src/device/input/wrap/buffered.go
Normal file
101
src/device/input/wrap/buffered.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package wrap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Buffered struct {
|
||||
ctx context.Context
|
||||
can context.CancelFunc
|
||||
lock sync.Mutex
|
||||
keys map[byte]int64
|
||||
input Wrap
|
||||
listenInterval time.Duration
|
||||
expirationInterval time.Duration
|
||||
}
|
||||
|
||||
func NewBuffered(ctx context.Context, input Wrap) *Buffered {
|
||||
ctx, can := context.WithCancel(ctx)
|
||||
expirationInterval := time.Millisecond * 125
|
||||
if d, err := time.ParseDuration(os.Getenv("WRAP_BUFFERED_STICKY_DURATION")); err == nil {
|
||||
expirationInterval = d
|
||||
}
|
||||
result := &Buffered{
|
||||
input: input,
|
||||
ctx: ctx,
|
||||
can: can,
|
||||
lock: sync.Mutex{},
|
||||
keys: map[byte]int64{},
|
||||
listenInterval: time.Millisecond * 10,
|
||||
expirationInterval: expirationInterval,
|
||||
}
|
||||
go result.listen()
|
||||
return result
|
||||
}
|
||||
|
||||
func (b *Buffered) listen() {
|
||||
for b.ctx.Err() == nil {
|
||||
buttons := b.input.Read()
|
||||
|
||||
b.lock.Lock()
|
||||
for i := range buttons {
|
||||
if buttons[i].Down {
|
||||
b.keys[buttons[i].Char] = time.Now().UnixNano()
|
||||
} else {
|
||||
b.keys[buttons[i].Char] = 0
|
||||
}
|
||||
}
|
||||
b.lock.Unlock()
|
||||
select {
|
||||
case <-b.ctx.Done():
|
||||
case <-time.After(b.listenInterval):
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Buffered) Close() {
|
||||
b.input.Close()
|
||||
b.can()
|
||||
}
|
||||
|
||||
func (b *Buffered) Read() []Button {
|
||||
for b.ctx.Err() == nil {
|
||||
result := b.read()
|
||||
if len(result) > 0 {
|
||||
return result
|
||||
}
|
||||
select {
|
||||
case <-b.ctx.Done():
|
||||
case <-time.After(b.listenInterval):
|
||||
}
|
||||
}
|
||||
return []Button{}
|
||||
}
|
||||
|
||||
func (b *Buffered) read() []Button {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
result := make([]Button, 0, len(b.keys))
|
||||
for k, v := range b.keys {
|
||||
isFresh := v > 0
|
||||
isStale := v < 0 && time.Since(time.Unix(0, -1*v)) > b.expirationInterval
|
||||
if isFresh || isStale {
|
||||
result = append(result, Button{Char: k, Down: isFresh})
|
||||
}
|
||||
if isFresh {
|
||||
b.keys[k] = -1 * v
|
||||
}
|
||||
}
|
||||
|
||||
for i := range result {
|
||||
if !result[i].Down {
|
||||
delete(b.keys, result[i].Char)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user