diff --git a/genkeys.go b/genkeys.go index a7709df51..75ad474fa 100644 --- a/genkeys.go +++ b/genkeys.go @@ -287,13 +287,13 @@ const ( ) ` -const inputKeysGlfwTmpl = `{{.License}} +const uidriverGlfwKeysTmpl = `{{.License}} {{.DoNotEdit}} {{.BuildTag}} -package input +package glfw import ( "github.com/hajimehoshi/ebiten/internal/driver" @@ -312,13 +312,13 @@ var glfwKeyCodeToKey = map[glfw.Key]driver.Key{ } ` -const inputKeysJSTmpl = `{{.License}} +const uidriverJsKeysTmpl = `{{.License}} {{.DoNotEdit}} {{.BuildTag}} -package input +package js import ( "github.com/hajimehoshi/ebiten/internal/driver" @@ -472,11 +472,11 @@ func main() { sort.Strings(codes) for path, tmpl := range map[string]string{ - "keys.go": ebitenKeysTmpl, - "internal/driver/keys.go": driverKeysTmpl, - "internal/input/keys_glfw.go": inputKeysGlfwTmpl, - "internal/input/keys_js.go": inputKeysJSTmpl, - "internal/glfw/keys.go": glfwKeysTmpl, + "keys.go": ebitenKeysTmpl, + "internal/driver/keys.go": driverKeysTmpl, + "internal/glfw/keys.go": glfwKeysTmpl, + "internal/uidriver/glfw/keys.go": uidriverGlfwKeysTmpl, + "internal/uidriver/js/keys.go": uidriverJsKeysTmpl, } { f, err := os.Create(path) if err != nil { @@ -496,12 +496,12 @@ func main() { // Pass the build tag and extract this in the template to make `go vet` happy. buildTag := "" switch path { - case "internal/input/keys_glfw.go": + case "internal/uidriver/glfw/keys.go": buildTag = "// +build darwin freebsd linux windows" + "\n// +build !js" + "\n// +build !android" + "\n// +build !ios" - case "internal/input/keys_js.go": + case "internal/uidriver/js/keys.go": buildTag = "// +build js" } // NOTE: According to godoc, maps are automatically sorted by key. diff --git a/internal/driver/ui.go b/internal/driver/ui.go index bd3b73eb8..ecceb482c 100644 --- a/internal/driver/ui.go +++ b/internal/driver/ui.go @@ -39,7 +39,7 @@ type UI interface { IsWindowDecorated() bool IsWindowResizable() bool Loop(ch <-chan error) error - Run(width, height int, scale float64, title string, g GraphicsContext, mainloop bool, graphics Graphics, input Input) error + Run(width, height int, scale float64, title string, g GraphicsContext, mainloop bool, graphics Graphics) error ScreenPadding() (x0, y0, x1, y1 float64) ScreenScale() float64 ScreenSizeInFullscreen() (int, int) diff --git a/internal/input/input_mobile.go b/internal/input/input_mobile.go deleted file mode 100644 index 1c966ebfa..000000000 --- a/internal/input/input_mobile.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2016 Hajime Hoshi -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build android ios - -package input - -import ( - "sync" - - "github.com/hajimehoshi/ebiten/internal/driver" -) - -type Input struct { - cursorX int - cursorY int - gamepads [16]gamePad - touches map[int]pos - m sync.RWMutex -} - -func (i *Input) RuneBuffer() []rune { - return nil -} - -func (i *Input) IsKeyPressed(key driver.Key) bool { - return false -} - -func (i *Input) Wheel() (xoff, yoff float64) { - return 0, 0 -} - -func (i *Input) IsMouseButtonPressed(key driver.MouseButton) bool { - return false -} - -func (i *Input) Update(touches []*driver.Touch) { - i.m.Lock() - i.touches = map[int]pos{} - for _, t := range touches { - i.touches[t.ID] = pos{ - X: t.X, - Y: t.Y, - } - } - i.m.Unlock() -} - -func (i *Input) ResetForFrame() { - // Do nothing -} diff --git a/internal/input/input_glfw.go b/internal/uidriver/glfw/input.go similarity index 71% rename from internal/input/input_glfw.go rename to internal/uidriver/glfw/input.go index 69ed7fa22..7774ef720 100644 --- a/internal/input/input_glfw.go +++ b/internal/uidriver/glfw/input.go @@ -17,7 +17,7 @@ // +build !android // +build !ios -package input +package glfw import ( "sync" @@ -27,6 +27,14 @@ import ( "github.com/hajimehoshi/ebiten/internal/glfw" ) +type gamePad struct { + valid bool + axisNum int + axes [16]float64 + buttonNum int + buttonPressed [256]bool +} + type Input struct { keyPressed map[glfw.Key]bool mouseButtonPressed map[glfw.MouseButton]bool @@ -41,6 +49,95 @@ type Input struct { m sync.RWMutex } +type pos struct { + X int + Y int +} + +func (i *Input) CursorPosition() (x, y int) { + i.m.RLock() + defer i.m.RUnlock() + return i.cursorX, i.cursorY +} + +func (i *Input) GamepadIDs() []int { + i.m.RLock() + defer i.m.RUnlock() + if len(i.gamepads) == 0 { + return nil + } + r := []int{} + for id, g := range i.gamepads { + if g.valid { + r = append(r, id) + } + } + return r +} + +func (i *Input) GamepadAxisNum(id int) int { + i.m.RLock() + defer i.m.RUnlock() + if len(i.gamepads) <= id { + return 0 + } + return i.gamepads[id].axisNum +} + +func (i *Input) GamepadAxis(id int, axis int) float64 { + i.m.RLock() + defer i.m.RUnlock() + if len(i.gamepads) <= id { + return 0 + } + return i.gamepads[id].axes[axis] +} + +func (i *Input) GamepadButtonNum(id int) int { + i.m.RLock() + defer i.m.RUnlock() + if len(i.gamepads) <= id { + return 0 + } + return i.gamepads[id].buttonNum +} + +func (i *Input) IsGamepadButtonPressed(id int, button driver.GamepadButton) bool { + i.m.RLock() + defer i.m.RUnlock() + if len(i.gamepads) <= id { + return false + } + return i.gamepads[id].buttonPressed[button] +} + +func (i *Input) TouchIDs() []int { + i.m.RLock() + defer i.m.RUnlock() + + if len(i.touches) == 0 { + return nil + } + + var ids []int + for id := range i.touches { + ids = append(ids, id) + } + return ids +} + +func (i *Input) TouchPosition(id int) (x, y int) { + i.m.RLock() + defer i.m.RUnlock() + + for tid, pos := range i.touches { + if id == tid { + return pos.X, pos.Y + } + } + return 0, 0 +} + func (i *Input) RuneBuffer() []rune { i.m.RLock() defer i.m.RUnlock() @@ -116,7 +213,7 @@ func (i *Input) setWheel(xoff, yoff float64) { i.m.Unlock() } -func (i *Input) Update(window *glfw.Window, scale float64) { +func (i *Input) update(window *glfw.Window, scale float64) { i.m.Lock() defer i.m.Unlock() diff --git a/internal/input/keys_glfw.go b/internal/uidriver/glfw/keys.go similarity index 99% rename from internal/input/keys_glfw.go rename to internal/uidriver/glfw/keys.go index a75bca571..dbb8847ac 100644 --- a/internal/input/keys_glfw.go +++ b/internal/uidriver/glfw/keys.go @@ -19,7 +19,7 @@ // +build !android // +build !ios -package input +package glfw import ( "github.com/hajimehoshi/ebiten/internal/driver" diff --git a/internal/uidriver/glfw/ui.go b/internal/uidriver/glfw/ui.go index a9cdcd350..868139bd6 100644 --- a/internal/uidriver/glfw/ui.go +++ b/internal/uidriver/glfw/ui.go @@ -65,7 +65,7 @@ type UserInterface struct { reqHeight int graphics driver.Graphics - input driver.Input + input Input m sync.Mutex } @@ -552,10 +552,9 @@ func (u *UserInterface) DeviceScaleFactor() float64 { return f } -func (u *UserInterface) Run(width, height int, scale float64, title string, g driver.GraphicsContext, mainloop bool, graphics driver.Graphics, input driver.Input) error { +func (u *UserInterface) Run(width, height int, scale float64, title string, g driver.GraphicsContext, mainloop bool, graphics driver.Graphics) error { _ = mainthread.Run(func() error { u.graphics = graphics - u.input = input if graphics.IsGL() { glfw.WindowHint(glfw.ContextVersionMajor, 2) @@ -745,11 +744,7 @@ func (u *UserInterface) update(g driver.GraphicsContext) error { _ = mainthread.Run(func() error { glfw.PollEvents() - type updater interface { - Update(window *glfw.Window, scale float64) - } - - u.input.(updater).Update(u.window, u.getScale()*u.glfwScale()) + u.input.update(u.window, u.getScale()*u.glfwScale()) defer hooks.ResumeAudio() @@ -943,5 +938,5 @@ func (u *UserInterface) currentMonitor() *glfw.Monitor { } func (u *UserInterface) Input() driver.Input { - return u.input + return &u.input } diff --git a/internal/input/input_js.go b/internal/uidriver/js/input.go similarity index 82% rename from internal/input/input_js.go rename to internal/uidriver/js/input.go index ab680a4d4..4dd3c1a89 100644 --- a/internal/input/input_js.go +++ b/internal/uidriver/js/input.go @@ -14,7 +14,7 @@ // +build js -package input +package js import ( "unicode" @@ -24,12 +24,18 @@ import ( "github.com/hajimehoshi/ebiten/internal/driver" ) -type mockRWLock struct{} +type pos struct { + X int + Y int +} -func (m mockRWLock) Lock() {} -func (m mockRWLock) Unlock() {} -func (m mockRWLock) RLock() {} -func (m mockRWLock) RUnlock() {} +type gamePad struct { + valid bool + axisNum int + axes [16]float64 + buttonNum int + buttonPressed [256]bool +} type Input struct { keyPressed map[string]bool @@ -42,7 +48,72 @@ type Input struct { gamepads [16]gamePad touches map[int]pos runeBuffer []rune - m mockRWLock +} + +func (i *Input) CursorPosition() (x, y int) { + return i.cursorX, i.cursorY +} + +func (i *Input) GamepadIDs() []int { + if len(i.gamepads) == 0 { + return nil + } + r := []int{} + for id, g := range i.gamepads { + if g.valid { + r = append(r, id) + } + } + return r +} + +func (i *Input) GamepadAxisNum(id int) int { + if len(i.gamepads) <= id { + return 0 + } + return i.gamepads[id].axisNum +} + +func (i *Input) GamepadAxis(id int, axis int) float64 { + if len(i.gamepads) <= id { + return 0 + } + return i.gamepads[id].axes[axis] +} + +func (i *Input) GamepadButtonNum(id int) int { + if len(i.gamepads) <= id { + return 0 + } + return i.gamepads[id].buttonNum +} + +func (i *Input) IsGamepadButtonPressed(id int, button driver.GamepadButton) bool { + if len(i.gamepads) <= id { + return false + } + return i.gamepads[id].buttonPressed[button] +} + +func (i *Input) TouchIDs() []int { + if len(i.touches) == 0 { + return nil + } + + var ids []int + for id := range i.touches { + ids = append(ids, id) + } + return ids +} + +func (i *Input) TouchPosition(id int) (x, y int) { + for tid, pos := range i.touches { + if id == tid { + return pos.X, pos.Y + } + } + return 0, 0 } func (i *Input) RuneBuffer() []rune { diff --git a/internal/input/keys_js.go b/internal/uidriver/js/keys.go similarity index 99% rename from internal/input/keys_js.go rename to internal/uidriver/js/keys.go index 843ad3a94..a00a683f1 100644 --- a/internal/input/keys_js.go +++ b/internal/uidriver/js/keys.go @@ -16,7 +16,7 @@ // +build js -package input +package js import ( "github.com/hajimehoshi/ebiten/internal/driver" diff --git a/internal/uidriver/js/ui.go b/internal/uidriver/js/ui.go index cf8812c0f..ad92ea08c 100644 --- a/internal/uidriver/js/ui.go +++ b/internal/uidriver/js/ui.go @@ -31,13 +31,6 @@ import ( var canvas js.Value -type inputDriver interface { - driver.Input - - Update(e js.Value) - UpdateGamepads() -} - type UserInterface struct { width int height int @@ -53,7 +46,7 @@ type UserInterface struct { lastActualScale float64 - input inputDriver + input Input } var theUI = &UserInterface{ @@ -389,9 +382,7 @@ func (u *UserInterface) Loop(ch <-chan error) error { return <-ch } -func (u *UserInterface) Run(width, height int, scale float64, title string, g driver.GraphicsContext, mainloop bool, graphics driver.Graphics, input driver.Input) error { - u.input = input.(inputDriver) - +func (u *UserInterface) Run(width, height int, scale float64, title string, g driver.GraphicsContext, mainloop bool, graphics driver.Graphics) error { document.Set("title", title) u.setScreenSize(width, height, scale, u.fullscreen) canvas.Call("focus") @@ -438,5 +429,5 @@ func (u *UserInterface) updateScreenSize() { } func (u *UserInterface) Input() driver.Input { - return u.input + return &u.input } diff --git a/internal/input/input.go b/internal/uidriver/mobile/input.go similarity index 62% rename from internal/input/input.go rename to internal/uidriver/mobile/input.go index 470bfc887..807ca5dce 100644 --- a/internal/input/input.go +++ b/internal/uidriver/mobile/input.go @@ -1,4 +1,4 @@ -// Copyright 2015 Hajime Hoshi +// Copyright 2016 Hajime Hoshi // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,21 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -package input +// +build android ios + +package mobile import ( + "sync" + "github.com/hajimehoshi/ebiten/internal/driver" ) -var theInput = &Input{} - type pos struct { X int Y int } -func Get() driver.Input { - return theInput +type Input struct { + cursorX int + cursorY int + touches map[int]pos + m sync.RWMutex } func (i *Input) CursorPosition() (x, y int) { @@ -36,54 +41,23 @@ func (i *Input) CursorPosition() (x, y int) { } func (i *Input) GamepadIDs() []int { - i.m.RLock() - defer i.m.RUnlock() - if len(i.gamepads) == 0 { - return nil - } - r := []int{} - for id, g := range i.gamepads { - if g.valid { - r = append(r, id) - } - } - return r + return nil } func (i *Input) GamepadAxisNum(id int) int { - i.m.RLock() - defer i.m.RUnlock() - if len(i.gamepads) <= id { - return 0 - } - return i.gamepads[id].axisNum + return 0 } func (i *Input) GamepadAxis(id int, axis int) float64 { - i.m.RLock() - defer i.m.RUnlock() - if len(i.gamepads) <= id { - return 0 - } - return i.gamepads[id].axes[axis] + return 0 } func (i *Input) GamepadButtonNum(id int) int { - i.m.RLock() - defer i.m.RUnlock() - if len(i.gamepads) <= id { - return 0 - } - return i.gamepads[id].buttonNum + return 0 } func (i *Input) IsGamepadButtonPressed(id int, button driver.GamepadButton) bool { - i.m.RLock() - defer i.m.RUnlock() - if len(i.gamepads) <= id { - return false - } - return i.gamepads[id].buttonPressed[button] + return false } func (i *Input) TouchIDs() []int { @@ -113,10 +87,34 @@ func (i *Input) TouchPosition(id int) (x, y int) { return 0, 0 } -type gamePad struct { - valid bool - axisNum int - axes [16]float64 - buttonNum int - buttonPressed [256]bool +func (i *Input) RuneBuffer() []rune { + return nil +} + +func (i *Input) IsKeyPressed(key driver.Key) bool { + return false +} + +func (i *Input) Wheel() (xoff, yoff float64) { + return 0, 0 +} + +func (i *Input) IsMouseButtonPressed(key driver.MouseButton) bool { + return false +} + +func (i *Input) update(touches []*driver.Touch) { + i.m.Lock() + i.touches = map[int]pos{} + for _, t := range touches { + i.touches[t.ID] = pos{ + X: t.X, + Y: t.Y, + } + } + i.m.Unlock() +} + +func (i *Input) ResetForFrame() { + // Do nothing } diff --git a/internal/uidriver/mobile/ui.go b/internal/uidriver/mobile/ui.go index b871fc005..84bc0e743 100644 --- a/internal/uidriver/mobile/ui.go +++ b/internal/uidriver/mobile/ui.go @@ -34,7 +34,6 @@ import ( "github.com/hajimehoshi/ebiten/internal/driver" "github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl" "github.com/hajimehoshi/ebiten/internal/hooks" - "github.com/hajimehoshi/ebiten/internal/input" ) var ( @@ -78,6 +77,8 @@ type UserInterface struct { fullscreenWidthPx int fullscreenHeightPx int + input Input + m sync.RWMutex } @@ -144,15 +145,12 @@ func appMain(a app.App) { for _, t := range touches { ts = append(ts, t) } - type updater interface { - Update(touches []*driver.Touch) - } - input.Get().(updater).Update(ts) + theUI.input.update(ts) } } } -func (u *UserInterface) Run(width, height int, scale float64, title string, g driver.GraphicsContext, mainloop bool, graphics driver.Graphics, input driver.Input) error { +func (u *UserInterface) Run(width, height int, scale float64, title string, g driver.GraphicsContext, mainloop bool, graphics driver.Graphics) error { if graphics != opengl.Get() { panic("ui: graphics driver must be OpenGL") } @@ -404,5 +402,9 @@ func (u *UserInterface) DeviceScaleFactor() float64 { } func (u *UserInterface) Input() driver.Input { - return input.Get() + return &u.input +} + +func (u *UserInterface) UpdateInput(touches []*driver.Touch) { + u.input.update(touches) } diff --git a/mobile/touches_mobile.go b/mobile/touches_mobile.go index 10ee7a1e9..b8f5b875f 100644 --- a/mobile/touches_mobile.go +++ b/mobile/touches_mobile.go @@ -18,7 +18,7 @@ package mobile import ( "github.com/hajimehoshi/ebiten/internal/driver" - "github.com/hajimehoshi/ebiten/internal/input" + "github.com/hajimehoshi/ebiten/internal/uidriver/mobile" ) type position struct { @@ -39,8 +39,5 @@ func updateTouches() { Y: position.y, }) } - type updater interface { - Update(touches []*driver.Touch) - } - input.Get().(updater).Update(ts) + mobile.Get().UpdateInput(ts) } diff --git a/run.go b/run.go index 5634d4dfd..806ec9c1c 100644 --- a/run.go +++ b/run.go @@ -20,7 +20,6 @@ import ( "github.com/hajimehoshi/ebiten/internal/clock" "github.com/hajimehoshi/ebiten/internal/driver" - "github.com/hajimehoshi/ebiten/internal/input" "github.com/hajimehoshi/ebiten/internal/web" ) @@ -97,7 +96,7 @@ func run(width, height int, scale float64, title string, g *graphicsContext, mai if !web.IsGopherJS() { defer atomic.StoreInt32(&isRunning, 0) } - if err := uiDriver().Run(width, height, scale, title, g, mainloop, graphicsDriver(), input.Get()); err != nil { + if err := uiDriver().Run(width, height, scale, title, g, mainloop, graphicsDriver()); err != nil { if err == driver.RegularTermination { return nil }