diff --git a/demos/kibodo/game/game.go b/demos/kibodo/game/game.go index 4e1e3c5..6cbcf70 100644 --- a/demos/kibodo/game/game.go +++ b/demos/kibodo/game/game.go @@ -16,6 +16,8 @@ type game struct { userInput []byte + incomingInput []*kibodo.Input + op *ebiten.DrawImageOptions spinnerIndex int @@ -54,31 +56,7 @@ func (g *game) showKeyboard() { g.userInput = nil // Show keyboard - ch := make(chan *kibodo.Input, 10) - g.k.Show(ch) - - // Handle input - for input := range ch { - if input.Rune > 0 { - g.userInput = append(g.userInput, []byte(string(input.Rune))...) - continue - } - if input.Key == ebiten.KeyBackspace { - s := string(g.userInput) - if len(s) > 0 { - g.userInput = []byte(s[:len(s)-1]) - } - continue - } else if input.Key == ebiten.KeyEnter { - g.userInput = nil - continue - } else if input.Key < 0 { - continue - } - g.userInput = append(g.userInput, []byte("<"+input.Key.String()+">")...) - } - - g.userInput = []byte("(Hidden, click to show keyboard)") + g.k.Show() } func (g *game) Layout(outsideWidth, outsideHeight int) (int, int) { @@ -102,8 +80,29 @@ func (g *game) Layout(outsideWidth, outsideHeight int) (int, int) { } func (g *game) Update() error { - if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) { - go g.showKeyboard() + if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) && !g.k.Visible() { + g.showKeyboard() + } + + g.incomingInput = g.k.AppendInput(g.incomingInput[:0]) + for _, input := range g.incomingInput { + if input.Rune > 0 { + g.userInput = append(g.userInput, []byte(string(input.Rune))...) + continue + } + if input.Key == ebiten.KeyBackspace { + s := string(g.userInput) + if len(s) > 0 { + g.userInput = []byte(s[:len(s)-1]) + } + continue + } else if input.Key == ebiten.KeyEnter { + g.userInput = nil + continue + } else if input.Key < 0 { + continue + } + g.userInput = append(g.userInput, []byte("<"+input.Key.String()+">")...) } return g.k.Update() diff --git a/go.mod b/go.mod index aa6b5c4..1521eb9 100644 --- a/go.mod +++ b/go.mod @@ -3,16 +3,16 @@ module code.rocketnine.space/tslocum/kibodo go 1.17 require ( - github.com/hajimehoshi/ebiten/v2 v2.2.0-alpha.14.0.20210916141036-9c321d1fcf27 + github.com/hajimehoshi/ebiten/v2 v2.2.0 golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d ) require ( github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210727001814-0db043d8d5be // indirect github.com/jezek/xgb v0.0.0-20210312150743-0e0f116e1240 // indirect - golang.org/x/exp v0.0.0-20210916165020-5cb4fee858ee // indirect - golang.org/x/mobile v0.0.0-20210902104108-5d9a33257ab5 // indirect + golang.org/x/exp v0.0.0-20211012155715-ffe10e552389 // indirect + golang.org/x/mobile v0.0.0-20210924032853-1c027f395ef7 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/sys v0.0.0-20210915083310-ed5796bab164 // indirect + golang.org/x/sys v0.0.0-20211015200801-69063c4bb744 // indirect golang.org/x/text v0.3.7 // indirect ) diff --git a/go.sum b/go.sum index d46f8b3..60ef11a 100644 --- a/go.sum +++ b/go.sum @@ -98,12 +98,12 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hajimehoshi/bitmapfont/v2 v2.1.3 h1:JefUkL0M4nrdVwVq7MMZxSTh6mSxOylm+C4Anoucbb0= github.com/hajimehoshi/bitmapfont/v2 v2.1.3/go.mod h1:2BnYrkTQGThpr/CY6LorYtt/zEPNzvE/ND69CRTaHMs= -github.com/hajimehoshi/ebiten/v2 v2.2.0-alpha.14.0.20210916141036-9c321d1fcf27 h1:QkZ/7JEkaoLrqMaNjskMvCoOV979VsfHTaDJzTBwGFw= -github.com/hajimehoshi/ebiten/v2 v2.2.0-alpha.14.0.20210916141036-9c321d1fcf27/go.mod h1:2sY8DHIXNs0Lf/pyTZXltEQtqCKZ2HyXbeUWzrLTlg0= -github.com/hajimehoshi/file2byteslice v0.0.0-20200812174855-0e5e8a80490e/go.mod h1:CqqAHp7Dk/AqQiwuhV1yT2334qbA/tFWQW0MD2dGqUE= +github.com/hajimehoshi/ebiten/v2 v2.2.0 h1:2mP9HrLLqiH9X3MajElYZEjVZU/CGh22iFkjatxhT4w= +github.com/hajimehoshi/ebiten/v2 v2.2.0/go.mod h1:olKl/qqhMBBAm2oI7Zy292nCtE+nitlmYKNF3UpbFn0= +github.com/hajimehoshi/file2byteslice v0.0.0-20210813153925-5340248a8f41/go.mod h1:CqqAHp7Dk/AqQiwuhV1yT2334qbA/tFWQW0MD2dGqUE= github.com/hajimehoshi/go-mp3 v0.3.2/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM= github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI= -github.com/hajimehoshi/oto/v2 v2.1.0-alpha.1/go.mod h1:rUKQmwMkqmRxe+IAof9+tuYA2ofm8cAWXFmSfzDN8vQ= +github.com/hajimehoshi/oto/v2 v2.1.0-alpha.2/go.mod h1:rUKQmwMkqmRxe+IAof9+tuYA2ofm8cAWXFmSfzDN8vQ= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -253,6 +253,7 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -285,8 +286,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= -golang.org/x/exp v0.0.0-20210916165020-5cb4fee858ee h1:qlrAyYdKz4o7rWVUjiKqQJMa4PEpd55fqBU8jpsl4Iw= -golang.org/x/exp v0.0.0-20210916165020-5cb4fee858ee/go.mod h1:a3o/VtDNHN+dCVLEpzjjUHOzR+Ln3DHX056ZPzoZGGA= +golang.org/x/exp v0.0.0-20211012155715-ffe10e552389 h1:qFfBYVpJAdBCk6Nmd7ZbcyhGmKmv8fps+OyoOfpjvu8= +golang.org/x/exp v0.0.0-20211012155715-ffe10e552389/go.mod h1:a3o/VtDNHN+dCVLEpzjjUHOzR+Ln3DHX056ZPzoZGGA= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -300,8 +301,9 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= -golang.org/x/mobile v0.0.0-20210902104108-5d9a33257ab5 h1:peBP2oZO/xVnGMaWMCyFEI0WENsGj71wx5K12mRELHQ= golang.org/x/mobile v0.0.0-20210902104108-5d9a33257ab5/go.mod h1:c4YKU3ZylDmvbw+H/PSvm42vhdWbuxCzbonauEAP9B8= +golang.org/x/mobile v0.0.0-20210924032853-1c027f395ef7 h1:CyFUjc175y/mbMjxe+WdqI72jguLyjQChKCDe9mfTvg= +golang.org/x/mobile v0.0.0-20210924032853-1c027f395ef7/go.mod h1:c4YKU3ZylDmvbw+H/PSvm42vhdWbuxCzbonauEAP9B8= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= @@ -327,6 +329,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -360,10 +363,12 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210915083310-ed5796bab164 h1:7ZDGnxgHAMw7thfC5bEos0RDAccZKxioiWBhfIe+tvw= -golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211015200801-69063c4bb744 h1:KzbpndAYEM+4oHRp9JmB2ewj0NHHxO3Z0g7Gus2O1kk= +golang.org/x/sys v0.0.0-20211015200801-69063c4bb744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -391,6 +396,7 @@ golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/key.go b/key.go index b7d4968..5509a19 100644 --- a/key.go +++ b/key.go @@ -18,7 +18,7 @@ type Key struct { pressedTouchID ebiten.TouchID } -// Input represents the input from a key press. +// Input represents the input event from a key press. type Input struct { Rune rune Key ebiten.Key diff --git a/keyboard.go b/keyboard.go index 0d93f93..a1af709 100644 --- a/keyboard.go +++ b/keyboard.go @@ -24,8 +24,9 @@ type Keyboard struct { passPhysical bool allowUserHide bool - internalBuffer []rune - inputBuffer chan *Input + incomingBuffer []rune + + inputEvents []*Input keys [][]*Key @@ -211,7 +212,7 @@ func (k *Keyboard) Hit(key *Key) { return } - k.inputBuffer <- input + k.inputEvents = append(k.inputEvents, input) } // Update handles user input. This function is called by Ebiten. @@ -223,10 +224,10 @@ func (k *Keyboard) Update() error { // Pass through physical keyboard input if k.passPhysical { // Read input characters - k.internalBuffer = ebiten.AppendInputChars(k.internalBuffer[:0]) - if len(k.internalBuffer) > 0 { - for _, r := range k.internalBuffer { - k.inputBuffer <- &Input{Rune: r} // Pass through + k.incomingBuffer = ebiten.AppendInputChars(k.incomingBuffer[:0]) + if len(k.incomingBuffer) > 0 { + for _, r := range k.incomingBuffer { + k.inputEvents = append(k.inputEvents, &Input{Rune: r}) // Pass through } } else { // Read keys @@ -236,7 +237,7 @@ func (k *Keyboard) Update() error { // Hidden return nil } - k.inputBuffer <- &Input{Key: key} // Pass through + k.inputEvents = append(k.inputEvents, &Input{Key: key}) // Pass through } } } @@ -453,20 +454,20 @@ func (k *Keyboard) Draw(target *ebiten.Image) { k.op.ColorM.Reset() // Draw border - darkShade := color.RGBA{60, 60, 60, 255} + /*darkShade := color.RGBA{60, 60, 60, 255} ox, oy := k.x+key.x, k.y+key.y for j := 0; j < key.w; j++ { target.Set(ox+j, oy, darkShade) } for j := 0; j < key.h; j++ { target.Set(ox, oy+j, darkShade) - } + }*/ } } } // SetAllowUserHide sets a flag that controls whether the widget may be hidden -// by the user. The input buffer channel is closed when the widget is hidden. +// by the user. func (k *Keyboard) SetAllowUserHide(allow bool) { k.allowUserHide = allow } @@ -483,26 +484,24 @@ func (k *Keyboard) SetAlpha(alpha float64) { k.alpha = alpha } -// Show shows the widget and begins sending input to the provided channel. The -// channel is closed if the widget is hidden. -func (k *Keyboard) Show(inputBuffer chan *Input) { - if k.inputBuffer != nil { - close(k.inputBuffer) - } - k.inputBuffer = inputBuffer +// Show shows the widget. +func (k *Keyboard) Show() { k.visible = true } -// Visible returns whether the keyboard is currently shown. +// Visible returns whether the widget is currently shown. func (k *Keyboard) Visible() bool { return k.visible } -// Hide hides the widget and closes the input buffer channel. +// Hide hides the widget. func (k *Keyboard) Hide() { - if k.inputBuffer != nil { - close(k.inputBuffer) - k.inputBuffer = nil - } k.visible = false } + +// AppendInput appends user input that was received since the function was last called. +func (k *Keyboard) AppendInput(events []*Input) []*Input { + events = append(events, k.inputEvents...) + k.inputEvents = nil + return events +} diff --git a/keyboard_test.go b/keyboard_test.go index 39177ce..72f2fdf 100644 --- a/keyboard_test.go +++ b/keyboard_test.go @@ -11,14 +11,14 @@ import ( // TODO test presses registered func TestKeyboard_Draw(t *testing.T) { - k, _ := newTestKeyboard() + k := newTestKeyboard() // Warm caches k.drawBackground() } func BenchmarkKeyboard_Draw(b *testing.B) { - k, _ := newTestKeyboard() + k := newTestKeyboard() // Warm caches k.drawBackground() @@ -34,7 +34,7 @@ func BenchmarkKeyboard_Press(b *testing.B) { go func() { time.Sleep(2 * time.Second) - k, _ := newTestKeyboard() + k := newTestKeyboard() // Warm caches k.drawBackground() @@ -57,14 +57,11 @@ func BenchmarkKeyboard_Press(b *testing.B) { } } -func newTestKeyboard() (*Keyboard, chan *Input) { - ch := make(chan *Input, 10) - +func newTestKeyboard() *Keyboard { k := NewKeyboard() k.SetRect(0, 0, 300, 100) - k.Show(ch) - return k, ch + return k } type DummyGame struct {