split src/devices/input into src/devices/input/{raw,wrap}
parent
ab673a81f0
commit
38b00e55b0
|
|
@ -2,63 +2,16 @@ package input
|
|||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"mayhem-party/src/device/input/raw"
|
||||
"mayhem-party/src/device/input/wrap"
|
||||
)
|
||||
|
||||
type Input interface {
|
||||
Read() []Button
|
||||
Read() []wrap.Button
|
||||
Close()
|
||||
}
|
||||
|
||||
func New(ctx context.Context) Input {
|
||||
return newNew(ctx)()
|
||||
}
|
||||
|
||||
func newNew(ctx context.Context) func() Input {
|
||||
maker := newSourceFunc()
|
||||
|
||||
if os.Getenv("INPUT_BUFFERED") == "true" {
|
||||
oldMaker := maker
|
||||
maker = func() Input {
|
||||
return NewBuffered(ctx, oldMaker())
|
||||
}
|
||||
}
|
||||
if p := os.Getenv("INPUT_REMAP_FILE"); p != "" {
|
||||
oldMaker := maker
|
||||
maker = func() Input {
|
||||
return NewRemapFromFile(oldMaker(), p)
|
||||
}
|
||||
}
|
||||
if os.Getenv("INPUT_REFRESH_ON_SIGUSR1") != "" {
|
||||
oldMaker := maker
|
||||
c := NewRefreshCh(syscall.SIGUSR1)
|
||||
maker = func() Input {
|
||||
return NewRefresh(oldMaker, c)
|
||||
}
|
||||
}
|
||||
return maker
|
||||
}
|
||||
|
||||
func newSourceFunc() func() Input {
|
||||
if os.Getenv("INPUT_KEYBOARD") == "true" {
|
||||
singletonKeyboard := NewKeyboard()
|
||||
return func() Input {
|
||||
return singletonKeyboard
|
||||
}
|
||||
}
|
||||
if port, _ := strconv.Atoi(os.Getenv("INPUT_UDP")); port != 0 {
|
||||
singletonUDP := NewUDP(port)
|
||||
return func() Input {
|
||||
return singletonUDP
|
||||
}
|
||||
}
|
||||
return func() Input {
|
||||
generator := randomCharFromRange('a', 'g')
|
||||
if p, ok := os.LookupEnv("INPUT_RANDOM_WEIGHT_FILE"); ok && len(p) > 0 {
|
||||
generator = randomCharFromWeightFile(p)
|
||||
}
|
||||
return NewRandom(generator)
|
||||
}
|
||||
src := raw.New(ctx)
|
||||
return wrap.New(ctx, src)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,11 +30,11 @@ func TestNewRemapped(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
os.Setenv("INPUT_REMAP_FILE", remap)
|
||||
os.Setenv("INPUT_RANDOM_WEIGHT_FILE", rand)
|
||||
os.Setenv("WRAP_REMAP_FILE", remap)
|
||||
os.Setenv("RAW_RANDOM_WEIGHT_FILE", rand)
|
||||
t.Cleanup(func() {
|
||||
os.Unsetenv("INPUT_REMAP_FILE")
|
||||
os.Unsetenv("INPUT_RANDOM_WEIGHT_FILE")
|
||||
os.Unsetenv("WRAP_REMAP_FILE")
|
||||
os.Unsetenv("RAW_RANDOM_WEIGHT_FILE")
|
||||
})
|
||||
|
||||
r := input.New(context.Background())
|
||||
|
|
@ -50,9 +50,9 @@ func TestNewRemapped(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNewBuffered(t *testing.T) {
|
||||
os.Setenv("INPUT_BUFFERED", "true")
|
||||
os.Setenv("WRAP_BUFFERED", "true")
|
||||
t.Cleanup(func() {
|
||||
os.Unsetenv("INPUT_BUFFERED")
|
||||
os.Unsetenv("WRAP_BUFFERED")
|
||||
})
|
||||
|
||||
r := input.New(context.Background())
|
||||
|
|
@ -71,9 +71,9 @@ func TestNewRandomWeightFile(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
os.Setenv("INPUT_RANDOM_WEIGHT_FILE", p)
|
||||
os.Setenv("RAW_RANDOM_WEIGHT_FILE", p)
|
||||
t.Cleanup(func() {
|
||||
os.Unsetenv("INPUT_RANDOM_WEIGHT_FILE")
|
||||
os.Unsetenv("RAW_RANDOM_WEIGHT_FILE")
|
||||
})
|
||||
|
||||
r := input.New(context.Background())
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
package input
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInput(t *testing.T) {
|
||||
var _ Input = &Random{}
|
||||
var _ Input = Keyboard{}
|
||||
var _ Input = &Buffered{}
|
||||
var _ Input = Remap{}
|
||||
var _ Input = &Refresh{}
|
||||
var _ Input = UDP{}
|
||||
}
|
||||
|
||||
func TestNewNew(t *testing.T) {
|
||||
t.Run("refreshing", func(t *testing.T) {
|
||||
ctx, can := context.WithCancel(context.Background())
|
||||
defer can()
|
||||
os.Setenv("INPUT_BUFFERED", "true")
|
||||
os.Setenv("INPUT_REFRESH_ON_SIGUSR1", "true")
|
||||
foo := New(ctx)
|
||||
if refresh, ok := foo.(*Refresh); !ok {
|
||||
t.Errorf("%T", foo)
|
||||
} else if buffered, ok := refresh.input.(*Buffered); !ok {
|
||||
t.Errorf("%T", refresh.input)
|
||||
} else if _, ok := buffered.input.(*Random); !ok {
|
||||
t.Errorf("%T", buffered.input)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package input
|
||||
package raw
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
|
@ -44,25 +44,14 @@ func (kb Keyboard) Close() {
|
|||
}
|
||||
}
|
||||
|
||||
func (kb Keyboard) Read() []Button {
|
||||
func (kb Keyboard) Read() []byte {
|
||||
b := make([]byte, 5)
|
||||
n, err := os.Stdin.Read(b)
|
||||
if err != nil && err != io.EOF {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
down := true
|
||||
result := make([]Button, 0, n)
|
||||
for i := 0; i < n; i++ {
|
||||
if b[i] == '!' {
|
||||
down = false
|
||||
} else if b[i] != '\n' {
|
||||
result = append(result, Button{Char: b[i], Down: down})
|
||||
down = true
|
||||
}
|
||||
}
|
||||
if os.Getenv("DEBUG") == "true" {
|
||||
log.Printf("input.Keyboard.Read() %s => %+v", b[:n], result)
|
||||
log.Printf("raw.Keyboard.Read() %s", b[:n])
|
||||
}
|
||||
return result
|
||||
return b[:n]
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package input
|
||||
package raw
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
|
@ -12,14 +12,9 @@ import (
|
|||
"github.com/go-yaml/yaml"
|
||||
)
|
||||
|
||||
type Button struct {
|
||||
Char byte
|
||||
Down bool
|
||||
}
|
||||
|
||||
type Random struct {
|
||||
generator func() byte
|
||||
down []Button
|
||||
down []byte
|
||||
}
|
||||
|
||||
func NewRandom(generator func() byte) *Random {
|
||||
|
|
@ -30,19 +25,8 @@ func NewRandom(generator func() byte) *Random {
|
|||
func (r *Random) Close() {
|
||||
}
|
||||
|
||||
func (r *Random) Read() []Button {
|
||||
if len(r.down) > 0 && rand.Int()%2 == 0 {
|
||||
was := r.down
|
||||
for i := range was {
|
||||
was[i].Down = false
|
||||
}
|
||||
r.down = r.down[:0]
|
||||
return was
|
||||
} else {
|
||||
c := Button{Char: r.generator(), Down: true}
|
||||
r.down = append(r.down, c)
|
||||
return []Button{c}
|
||||
}
|
||||
func (r *Random) Read() []byte {
|
||||
return []byte{r.generator()}
|
||||
}
|
||||
|
||||
func randomCharFromRange(start, stop byte) func() byte {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package input
|
||||
package raw
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package raw
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Raw interface {
|
||||
Read() []byte
|
||||
Close()
|
||||
}
|
||||
|
||||
func New(ctx context.Context) Raw {
|
||||
if os.Getenv("RAW_KEYBOARD") == "true" {
|
||||
return NewKeyboard()
|
||||
}
|
||||
if port, _ := strconv.Atoi(os.Getenv("RAW_UDP")); port != 0 {
|
||||
return NewUDP(port)
|
||||
}
|
||||
generator := randomCharFromRange('a', 'g')
|
||||
if p, ok := os.LookupEnv("RAW_RANDOM_WEIGHT_FILE"); ok && len(p) > 0 {
|
||||
generator = randomCharFromWeightFile(p)
|
||||
}
|
||||
return NewRandom(generator)
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package raw
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestRaw(t *testing.T) {
|
||||
var _ Raw = &Random{}
|
||||
var _ Raw = UDP{}
|
||||
var _ Raw = Keyboard{}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package input
|
||||
package raw
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
|
|
@ -19,26 +21,17 @@ func NewUDP(port int) UDP {
|
|||
}
|
||||
}
|
||||
|
||||
func (udp UDP) Read() []Button {
|
||||
func (udp UDP) Read() []byte {
|
||||
panic("NEEDS TO BE IN BG THREAD SO WE CAN SHUT DOWN WITHOUT BLOCKING ON READ OR AT LEAST BE RESPONSIVE")
|
||||
buff := make([]byte, 1024)
|
||||
n, _, err := udp.conn.ReadFrom(buff)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buttons := make([]Button, 0, n)
|
||||
down := true
|
||||
for i := range buff[:n] {
|
||||
if buff[i] == '!' {
|
||||
down = false
|
||||
} else {
|
||||
if buff[i] != '\n' {
|
||||
buttons = append(buttons, Button{Char: buff[i], Down: down})
|
||||
}
|
||||
down = true
|
||||
}
|
||||
if os.Getenv("DEBUG") == "true" {
|
||||
log.Printf("raw.UDP.Read() => %s", buff[:n])
|
||||
}
|
||||
return buttons
|
||||
return buff[:n]
|
||||
}
|
||||
|
||||
func (udp UDP) Close() {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package input
|
||||
package wrap
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -12,15 +12,15 @@ type Buffered struct {
|
|||
can context.CancelFunc
|
||||
lock sync.Mutex
|
||||
keys map[byte]int64
|
||||
input Input
|
||||
input Wrap
|
||||
listenInterval time.Duration
|
||||
expirationInterval time.Duration
|
||||
}
|
||||
|
||||
func NewBuffered(ctx context.Context, input Input) *Buffered {
|
||||
func NewBuffered(ctx context.Context, input Wrap) *Buffered {
|
||||
ctx, can := context.WithCancel(ctx)
|
||||
expirationInterval := time.Millisecond * 125
|
||||
if d, err := time.ParseDuration(os.Getenv("INPUT_BUFFERED_STICKY_DURATION")); err == nil {
|
||||
if d, err := time.ParseDuration(os.Getenv("WRAP_BUFFERED_STICKY_DURATION")); err == nil {
|
||||
expirationInterval = d
|
||||
}
|
||||
result := &Buffered{
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package wrap
|
||||
|
||||
type Button struct {
|
||||
Char byte
|
||||
Down bool
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package input
|
||||
package wrap
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
type Refresh struct {
|
||||
can context.CancelFunc
|
||||
input Input
|
||||
input Wrap
|
||||
}
|
||||
|
||||
func NewRefreshCh(sig os.Signal) <-chan os.Signal {
|
||||
|
|
@ -18,11 +18,11 @@ func NewRefreshCh(sig os.Signal) <-chan os.Signal {
|
|||
return c
|
||||
}
|
||||
|
||||
func NewRefresh(newInput func() Input, ch <-chan os.Signal) *Refresh {
|
||||
func NewRefresh(newWrap func() Wrap, ch <-chan os.Signal) *Refresh {
|
||||
ctx, can := context.WithCancel(context.Background())
|
||||
result := &Refresh{
|
||||
can: can,
|
||||
input: newInput(),
|
||||
input: newWrap(),
|
||||
}
|
||||
go func() {
|
||||
defer log.Println("refreshing done")
|
||||
|
|
@ -32,7 +32,7 @@ func NewRefresh(newInput func() Input, ch <-chan os.Signal) *Refresh {
|
|||
return
|
||||
case sig := <-ch:
|
||||
log.Println("refreshing for", sig)
|
||||
result.input = newInput()
|
||||
result.input = newWrap()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package input
|
||||
package wrap
|
||||
|
||||
import (
|
||||
"mayhem-party/src/device/input/raw"
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
|
@ -9,9 +10,9 @@ import (
|
|||
|
||||
func TestRefresh(t *testing.T) {
|
||||
b := byte('a')
|
||||
generator := func() Input {
|
||||
generator := func() Wrap {
|
||||
b += byte(1)
|
||||
return NewRandom(func() byte { return b })
|
||||
return explicit{src: raw.NewRandom(func() byte { return b })}
|
||||
}
|
||||
ch := make(chan os.Signal, 1)
|
||||
defer close(ch)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package input
|
||||
package wrap
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
|
@ -7,11 +7,11 @@ import (
|
|||
)
|
||||
|
||||
type Remap struct {
|
||||
input Input
|
||||
input Wrap
|
||||
m map[byte]byte
|
||||
}
|
||||
|
||||
func NewRemapFromFile(input Input, p string) Remap {
|
||||
func NewRemapFromFile(input Wrap, p string) Remap {
|
||||
b, err := os.ReadFile(p)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
@ -30,7 +30,7 @@ func NewRemapFromFile(input Input, p string) Remap {
|
|||
return NewRemap(input, remap)
|
||||
}
|
||||
|
||||
func NewRemap(input Input, m map[byte]byte) Remap {
|
||||
func NewRemap(input Wrap, m map[byte]byte) Remap {
|
||||
return Remap{
|
||||
input: input,
|
||||
m: m,
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package wrap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"mayhem-party/src/device/input/raw"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type Wrap interface {
|
||||
Read() []Button
|
||||
Close()
|
||||
}
|
||||
|
||||
func New(ctx context.Context, src raw.Raw) Wrap {
|
||||
maker := func() Wrap {
|
||||
return explicit{src: src}
|
||||
}
|
||||
if os.Getenv("WRAP_BUFFERED") == "true" {
|
||||
oldMaker := maker
|
||||
maker = func() Wrap {
|
||||
return NewBuffered(ctx, oldMaker())
|
||||
}
|
||||
}
|
||||
if p := os.Getenv("WRAP_REMAP_FILE"); p != "" {
|
||||
oldMaker := maker
|
||||
maker = func() Wrap {
|
||||
return NewRemapFromFile(oldMaker(), p)
|
||||
}
|
||||
}
|
||||
if os.Getenv("WRAP_REFRESH_ON_SIGUSR1") != "" {
|
||||
oldMaker := maker
|
||||
c := NewRefreshCh(syscall.SIGUSR1)
|
||||
maker = func() Wrap {
|
||||
return NewRefresh(oldMaker, c)
|
||||
}
|
||||
}
|
||||
return maker()
|
||||
}
|
||||
|
||||
type explicit struct {
|
||||
src raw.Raw
|
||||
}
|
||||
|
||||
func (e explicit) Close() {
|
||||
e.src.Close()
|
||||
}
|
||||
|
||||
func (e explicit) Read() []Button {
|
||||
b := e.src.Read()
|
||||
buttons := make([]Button, 0, len(b))
|
||||
down := true
|
||||
for i := range b {
|
||||
if b[i] == '!' {
|
||||
down = false
|
||||
} else {
|
||||
if b[i] != '\n' {
|
||||
buttons = append(buttons, Button{Char: b[i], Down: down})
|
||||
}
|
||||
down = true
|
||||
}
|
||||
}
|
||||
return buttons
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package wrap
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestWrap(t *testing.T) {
|
||||
var _ Wrap = explicit{}
|
||||
var _ Wrap = &Refresh{}
|
||||
var _ Wrap = &Buffered{}
|
||||
var _ Wrap = &Remap{}
|
||||
}
|
||||
Loading…
Reference in New Issue