diff --git a/gamepad.go b/gamepad.go index d830b1e3d..681d28e9b 100644 --- a/gamepad.go +++ b/gamepad.go @@ -15,7 +15,7 @@ package ebiten import ( - "github.com/hajimehoshi/ebiten/internal/ui" + "github.com/hajimehoshi/ebiten/internal/input" ) // A GamepadButton represents a gamepad button. @@ -23,37 +23,37 @@ type GamepadButton int // GamepadButtons const ( - GamepadButton0 GamepadButton = GamepadButton(ui.GamepadButton0) - GamepadButton1 GamepadButton = GamepadButton(ui.GamepadButton1) - GamepadButton2 GamepadButton = GamepadButton(ui.GamepadButton2) - GamepadButton3 GamepadButton = GamepadButton(ui.GamepadButton3) - GamepadButton4 GamepadButton = GamepadButton(ui.GamepadButton4) - GamepadButton5 GamepadButton = GamepadButton(ui.GamepadButton5) - GamepadButton6 GamepadButton = GamepadButton(ui.GamepadButton6) - GamepadButton7 GamepadButton = GamepadButton(ui.GamepadButton7) - GamepadButton8 GamepadButton = GamepadButton(ui.GamepadButton8) - GamepadButton9 GamepadButton = GamepadButton(ui.GamepadButton9) - GamepadButton10 GamepadButton = GamepadButton(ui.GamepadButton10) - GamepadButton11 GamepadButton = GamepadButton(ui.GamepadButton11) - GamepadButton12 GamepadButton = GamepadButton(ui.GamepadButton12) - GamepadButton13 GamepadButton = GamepadButton(ui.GamepadButton13) - GamepadButton14 GamepadButton = GamepadButton(ui.GamepadButton14) - GamepadButton15 GamepadButton = GamepadButton(ui.GamepadButton15) - GamepadButton16 GamepadButton = GamepadButton(ui.GamepadButton16) - GamepadButton17 GamepadButton = GamepadButton(ui.GamepadButton17) - GamepadButton18 GamepadButton = GamepadButton(ui.GamepadButton18) - GamepadButton19 GamepadButton = GamepadButton(ui.GamepadButton19) - GamepadButton20 GamepadButton = GamepadButton(ui.GamepadButton20) - GamepadButton21 GamepadButton = GamepadButton(ui.GamepadButton21) - GamepadButton22 GamepadButton = GamepadButton(ui.GamepadButton22) - GamepadButton23 GamepadButton = GamepadButton(ui.GamepadButton23) - GamepadButton24 GamepadButton = GamepadButton(ui.GamepadButton24) - GamepadButton25 GamepadButton = GamepadButton(ui.GamepadButton25) - GamepadButton26 GamepadButton = GamepadButton(ui.GamepadButton26) - GamepadButton27 GamepadButton = GamepadButton(ui.GamepadButton27) - GamepadButton28 GamepadButton = GamepadButton(ui.GamepadButton28) - GamepadButton29 GamepadButton = GamepadButton(ui.GamepadButton29) - GamepadButton30 GamepadButton = GamepadButton(ui.GamepadButton30) - GamepadButton31 GamepadButton = GamepadButton(ui.GamepadButton31) + GamepadButton0 GamepadButton = GamepadButton(input.GamepadButton0) + GamepadButton1 GamepadButton = GamepadButton(input.GamepadButton1) + GamepadButton2 GamepadButton = GamepadButton(input.GamepadButton2) + GamepadButton3 GamepadButton = GamepadButton(input.GamepadButton3) + GamepadButton4 GamepadButton = GamepadButton(input.GamepadButton4) + GamepadButton5 GamepadButton = GamepadButton(input.GamepadButton5) + GamepadButton6 GamepadButton = GamepadButton(input.GamepadButton6) + GamepadButton7 GamepadButton = GamepadButton(input.GamepadButton7) + GamepadButton8 GamepadButton = GamepadButton(input.GamepadButton8) + GamepadButton9 GamepadButton = GamepadButton(input.GamepadButton9) + GamepadButton10 GamepadButton = GamepadButton(input.GamepadButton10) + GamepadButton11 GamepadButton = GamepadButton(input.GamepadButton11) + GamepadButton12 GamepadButton = GamepadButton(input.GamepadButton12) + GamepadButton13 GamepadButton = GamepadButton(input.GamepadButton13) + GamepadButton14 GamepadButton = GamepadButton(input.GamepadButton14) + GamepadButton15 GamepadButton = GamepadButton(input.GamepadButton15) + GamepadButton16 GamepadButton = GamepadButton(input.GamepadButton16) + GamepadButton17 GamepadButton = GamepadButton(input.GamepadButton17) + GamepadButton18 GamepadButton = GamepadButton(input.GamepadButton18) + GamepadButton19 GamepadButton = GamepadButton(input.GamepadButton19) + GamepadButton20 GamepadButton = GamepadButton(input.GamepadButton20) + GamepadButton21 GamepadButton = GamepadButton(input.GamepadButton21) + GamepadButton22 GamepadButton = GamepadButton(input.GamepadButton22) + GamepadButton23 GamepadButton = GamepadButton(input.GamepadButton23) + GamepadButton24 GamepadButton = GamepadButton(input.GamepadButton24) + GamepadButton25 GamepadButton = GamepadButton(input.GamepadButton25) + GamepadButton26 GamepadButton = GamepadButton(input.GamepadButton26) + GamepadButton27 GamepadButton = GamepadButton(input.GamepadButton27) + GamepadButton28 GamepadButton = GamepadButton(input.GamepadButton28) + GamepadButton29 GamepadButton = GamepadButton(input.GamepadButton29) + GamepadButton30 GamepadButton = GamepadButton(input.GamepadButton30) + GamepadButton31 GamepadButton = GamepadButton(input.GamepadButton31) GamepadButtonMax GamepadButton = GamepadButton31 ) diff --git a/genkeys.go b/genkeys.go index eb0c94c50..9ddfa3453 100644 --- a/genkeys.go +++ b/genkeys.go @@ -137,7 +137,7 @@ const ebitenKeysTmpl = `{{.License}} package ebiten import ( - "github.com/hajimehoshi/ebiten/internal/ui" + "github.com/hajimehoshi/ebiten/internal/input" ) // A Key represents a keyboard key. @@ -147,16 +147,16 @@ type Key int // Keys const ( -{{range $index, $name := .KeyNames}}Key{{$name}} Key = Key(ui.Key{{$name}}) +{{range $index, $name := .KeyNames}}Key{{$name}} Key = Key(input.Key{{$name}}) {{end}} KeyMax Key = Key{{.LastKeyName}} ) ` -const uiKeysTmpl = `{{.License}} +const inputKeysTmpl = `{{.License}} {{.DoNotEdit}} -package ui +package input type Key int @@ -166,13 +166,13 @@ const ( ) ` -const uiKeysGlfwTmpl = `{{.License}} +const inputKeysGlfwTmpl = `{{.License}} {{.DoNotEdit}} {{.BuildTag}} -package ui +package input import ( glfw "github.com/go-gl/glfw/v3.2/glfw" @@ -190,13 +190,13 @@ var glfwKeyCodeToKey = map[glfw.Key]Key{ } ` -const uiKeysJSTmpl = `{{.License}} +const inputKeysJSTmpl = `{{.License}} {{.DoNotEdit}} {{.BuildTag}} -package ui +package input var keyToCodes = map[Key][]string{ {{range $name, $codes := .NameToCodes}}Key{{$name}}: []string{ @@ -322,10 +322,10 @@ func main() { sort.Strings(codes) for path, tmpl := range map[string]string{ - "keys.go": ebitenKeysTmpl, - "internal/ui/keys.go": uiKeysTmpl, - "internal/ui/keys_glfw.go": uiKeysGlfwTmpl, - "internal/ui/keys_js.go": uiKeysJSTmpl, + "keys.go": ebitenKeysTmpl, + "internal/input/keys.go": inputKeysTmpl, + "internal/input/keys_glfw.go": inputKeysGlfwTmpl, + "internal/input/keys_js.go": inputKeysJSTmpl, } { f, err := os.Create(path) if err != nil { @@ -340,12 +340,12 @@ func main() { // Pass the build tag and extract this in the template to make `go vet` happy. buildTag := "" switch path { - case "internal/ui/keys_glfw.go": + case "internal/input/keys_glfw.go": buildTag = "// +build darwin freebsd linux windows" + "\n// +build !js" + "\n// +build !android" + "\n// +build !ios" - case "internal/ui/keys_js.go": + case "internal/input/keys_js.go": buildTag = "// +build js" } // NOTE: According to godoc, maps are automatically sorted by key. diff --git a/input.go b/input.go index b93d57d42..0dd8e212e 100644 --- a/input.go +++ b/input.go @@ -15,6 +15,7 @@ package ebiten import ( + "github.com/hajimehoshi/ebiten/internal/input" "github.com/hajimehoshi/ebiten/internal/ui" ) @@ -28,7 +29,7 @@ import ( // // This function is concurrent-safe. func InputChars() []rune { - rb := ui.CurrentInput().RuneBuffer() + rb := input.Get().RuneBuffer() return append(make([]rune, 0, len(rb)), rb...) } @@ -36,14 +37,14 @@ func InputChars() []rune { // // This function is concurrent-safe. func IsKeyPressed(key Key) bool { - return ui.CurrentInput().IsKeyPressed(ui.Key(key)) + return input.Get().IsKeyPressed(input.Key(key)) } // CursorPosition returns a position of a mouse cursor. // // This function is concurrent-safe. func CursorPosition() (x, y int) { - return ui.CurrentInput().CursorPosition() + return ui.AdjustedCursorPosition() } // IsMouseButtonPressed returns a boolean indicating whether mouseButton is pressed. @@ -53,7 +54,7 @@ func CursorPosition() (x, y int) { // Note that touch events not longer affect this function's result as of 1.4.0-alpha. // Use Touches instead. func IsMouseButtonPressed(mouseButton MouseButton) bool { - return ui.CurrentInput().IsMouseButtonPressed(ui.MouseButton(mouseButton)) + return input.Get().IsMouseButtonPressed(input.MouseButton(mouseButton)) } // GamepadIDs returns a slice indicating available gamepad IDs. @@ -62,7 +63,7 @@ func IsMouseButtonPressed(mouseButton MouseButton) bool { // // This function always returns an empty slice on mobiles. func GamepadIDs() []int { - return ui.CurrentInput().GamepadIDs() + return input.Get().GamepadIDs() } // GamepadAxisNum returns the number of axes of the gamepad (id). @@ -71,7 +72,7 @@ func GamepadIDs() []int { // // This function always returns 0 on mobiles. func GamepadAxisNum(id int) int { - return ui.CurrentInput().GamepadAxisNum(id) + return input.Get().GamepadAxisNum(id) } // GamepadAxis returns the float value [-1.0 - 1.0] of the given gamepad (id)'s axis (axis). @@ -80,7 +81,7 @@ func GamepadAxisNum(id int) int { // // This function always returns 0 on mobiles. func GamepadAxis(id int, axis int) float64 { - return ui.CurrentInput().GamepadAxis(id, axis) + return input.Get().GamepadAxis(id, axis) } // GamepadButtonNum returns the number of the buttons of the given gamepad (id). @@ -89,7 +90,7 @@ func GamepadAxis(id int, axis int) float64 { // // This function always returns 0 on mobiles. func GamepadButtonNum(id int) int { - return ui.CurrentInput().GamepadButtonNum(id) + return input.Get().GamepadButtonNum(id) } // IsGamepadButtonPressed returns the boolean indicating the given button of the gamepad (id) is pressed or not. @@ -102,7 +103,7 @@ func GamepadButtonNum(id int) int { // // This function always returns false on mobiles. func IsGamepadButtonPressed(id int, button GamepadButton) bool { - return ui.CurrentInput().IsGamepadButtonPressed(id, ui.GamepadButton(button)) + return input.Get().IsGamepadButtonPressed(id, input.GamepadButton(button)) } // Touch represents a touch state. @@ -118,7 +119,7 @@ type Touch interface { // // Touches always returns nil on desktops. func Touches() []Touch { - t := ui.CurrentInput().Touches() + t := input.Get().Touches() tt := make([]Touch, len(t)) for i := 0; i < len(tt); i++ { tt[i] = t[i] diff --git a/internal/ui/gamepadbutton.go b/internal/input/gamepadbutton.go similarity index 98% rename from internal/ui/gamepadbutton.go rename to internal/input/gamepadbutton.go index c0f0780ed..a932fc1f5 100644 --- a/internal/ui/gamepadbutton.go +++ b/internal/input/gamepadbutton.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package ui +package input type GamepadButton int diff --git a/internal/ui/input.go b/internal/input/input.go similarity index 83% rename from internal/ui/input.go rename to internal/input/input.go index a0a46dcb9..fc503597b 100644 --- a/internal/ui/input.go +++ b/internal/input/input.go @@ -12,23 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -package ui +package input -var currentInput = &Input{} +var theInput = &Input{} -type Touch interface { - ID() int - Position() (x, y int) -} - -func CurrentInput() *Input { - return currentInput +func Get() *Input { + return theInput } func (i *Input) CursorPosition() (x, y int) { i.m.RLock() defer i.m.RUnlock() - return adjustCursorPosition(i.cursorX, i.cursorY) + return i.cursorX, i.cursorY } var emptyIDs = []int{} @@ -86,9 +81,9 @@ func (i *Input) IsGamepadButtonPressed(id int, button GamepadButton) bool { return i.gamepads[id].buttonPressed[button] } -var emptyTouches = []Touch{} +var emptyTouches = []*Touch{} -func (in *Input) Touches() []Touch { +func (in *Input) Touches() []*Touch { in.m.RLock() defer in.m.RUnlock() @@ -98,9 +93,9 @@ func (in *Input) Touches() []Touch { return emptyTouches } - t := make([]Touch, len(in.touches)) + t := make([]*Touch, len(in.touches)) for i := 0; i < len(t); i++ { - t[i] = &in.touches[i] + t[i] = in.touches[i] } return t } @@ -113,16 +108,24 @@ type gamePad struct { buttonPressed [256]bool } -type touch struct { +type Touch struct { id int x int y int } -func (t *touch) ID() int { +func NewTouch(id int, x, y int) *Touch { + return &Touch{ + id: id, + x: x, + y: y, + } +} + +func (t *Touch) ID() int { return t.id } -func (t *touch) Position() (x, y int) { +func (t *Touch) Position() (x, y int) { return t.x, t.y } diff --git a/internal/ui/input_glfw.go b/internal/input/input_glfw.go similarity index 92% rename from internal/ui/input_glfw.go rename to internal/input/input_glfw.go index 55a954f6e..c1a9ed05b 100644 --- a/internal/ui/input_glfw.go +++ b/internal/input/input_glfw.go @@ -17,7 +17,7 @@ // +build !android // +build !ios -package ui +package input import ( "sync" @@ -32,7 +32,7 @@ type Input struct { cursorX int cursorY int gamepads [16]gamePad - touches []touch // This is not updated until GLFW 3.3 is available (#417) + touches []*Touch // This is not updated until GLFW 3.3 is available (#417) runeBuffer []rune m sync.RWMutex } @@ -43,6 +43,12 @@ func (i *Input) RuneBuffer() []rune { return i.runeBuffer } +func (i *Input) ClearRuneBuffer() { + i.m.RLock() + defer i.m.RUnlock() + i.runeBuffer = i.runeBuffer[:0] +} + func (i *Input) IsKeyPressed(key Key) bool { i.m.RLock() defer i.m.RUnlock() @@ -83,7 +89,7 @@ var glfwMouseButtonToMouseButton = map[glfw.MouseButton]MouseButton{ glfw.MouseButtonMiddle: MouseButtonMiddle, } -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() if i.runeBuffer == nil { diff --git a/internal/ui/input_js.go b/internal/input/input_js.go similarity index 55% rename from internal/ui/input_js.go rename to internal/input/input_js.go index 825119a10..986da047d 100644 --- a/internal/ui/input_js.go +++ b/internal/input/input_js.go @@ -14,9 +14,11 @@ // +build js -package ui +package input import ( + "unicode" + "github.com/gopherjs/gopherjs/js" ) @@ -34,7 +36,7 @@ type Input struct { cursorX int cursorY int gamepads [16]gamePad - touches []touch + touches []*Touch runeBuffer []rune m mockRWLock } @@ -43,6 +45,10 @@ func (i *Input) RuneBuffer() []rune { return i.runeBuffer } +func (i *Input) ClearRuneBuffer() { + i.runeBuffer = nil +} + func (i *Input) IsKeyPressed(key Key) bool { if i.keyPressed != nil { for _, c := range keyToCodes[key] { @@ -131,7 +137,7 @@ func (i *Input) setMouseCursor(x, y int) { i.cursorX, i.cursorY = x, y } -func (i *Input) updateGamepads() { +func (i *Input) UpdateGamepads() { nav := js.Global.Get("navigator") if nav.Get("getGamepads") == js.Undefined { return @@ -170,7 +176,111 @@ func (i *Input) updateGamepads() { } } -func (i *Input) updateTouches(t []touch) { - i.touches = make([]touch, len(t)) +func (i *Input) updateTouches(t []*Touch) { + i.touches = make([]*Touch, len(t)) copy(i.touches, t) } + +func OnKeyDown(e *js.Object) { + c := e.Get("code") + if c == js.Undefined { + code := e.Get("keyCode").Int() + if keyCodeToKeyEdge[code] == KeyUp || + keyCodeToKeyEdge[code] == KeyDown || + keyCodeToKeyEdge[code] == KeyLeft || + keyCodeToKeyEdge[code] == KeyRight || + keyCodeToKeyEdge[code] == KeyBackspace || + keyCodeToKeyEdge[code] == KeyTab { + e.Call("preventDefault") + } + theInput.keyDownEdge(code) + return + } + cs := c.String() + if cs == keyToCodes[KeyUp][0] || + cs == keyToCodes[KeyDown][0] || + cs == keyToCodes[KeyLeft][0] || + cs == keyToCodes[KeyRight][0] || + cs == keyToCodes[KeyBackspace][0] || + cs == keyToCodes[KeyTab][0] { + e.Call("preventDefault") + } + theInput.keyDown(cs) +} + +func OnKeyPress(e *js.Object) { + e.Call("preventDefault") + if r := rune(e.Get("charCode").Int()); unicode.IsPrint(r) { + theInput.runeBuffer = append(theInput.runeBuffer, r) + } +} + +func OnKeyUp(e *js.Object) { + e.Call("preventDefault") + if e.Get("code") == js.Undefined { + // Assume that UA is Edge. + code := e.Get("keyCode").Int() + theInput.keyUpEdge(code) + return + } + code := e.Get("code").String() + theInput.keyUp(code) +} + +func OnMouseDown(e *js.Object, scale float64, left, top int) { + e.Call("preventDefault") + button := e.Get("button").Int() + theInput.mouseDown(button) + setMouseCursorFromEvent(e, scale, left, top) +} + +func OnMouseUp(e *js.Object, scale float64, left, top int) { + e.Call("preventDefault") + button := e.Get("button").Int() + theInput.mouseUp(button) + setMouseCursorFromEvent(e, scale, left, top) +} + +func OnMouseMove(e *js.Object, scale float64, left, top int) { + e.Call("preventDefault") + setMouseCursorFromEvent(e, scale, left, top) +} + +func OnTouchStart(e *js.Object, scale float64, left, top int) { + e.Call("preventDefault") + theInput.updateTouches(touchEventToTouches(e, scale, left, top)) +} + +func OnTouchEnd(e *js.Object, scale float64, left, top int) { + e.Call("preventDefault") + theInput.updateTouches(touchEventToTouches(e, scale, left, top)) +} + +func OnTouchMove(e *js.Object, scale float64, left, top int) { + e.Call("preventDefault") + theInput.updateTouches(touchEventToTouches(e, scale, left, top)) +} + +func setMouseCursorFromEvent(e *js.Object, scale float64, left, top int) { + x, y := e.Get("clientX").Int(), e.Get("clientY").Int() + x -= left + y -= top + theInput.setMouseCursor(int(float64(x)/scale), int(float64(y)/scale)) +} + +func touchEventToTouches(e *js.Object, scale float64, left, top int) []*Touch { + j := e.Get("targetTouches") + t := make([]*Touch, j.Get("length").Int()) + for i := 0; i < len(t); i++ { + jj := j.Call("item", i) + id := jj.Get("identifier").Int() + x := int(float64(jj.Get("clientX").Int()-left) / scale) + y := int(float64(jj.Get("clientY").Int()-top) / scale) + t[i] = &Touch{ + id: id, + x: x, + y: y, + } + } + return t +} diff --git a/internal/ui/input_mobile.go b/internal/input/input_mobile.go similarity index 83% rename from internal/ui/input_mobile.go rename to internal/input/input_mobile.go index c27941da2..27c8305c5 100644 --- a/internal/ui/input_mobile.go +++ b/internal/input/input_mobile.go @@ -14,7 +14,7 @@ // +build android ios -package ui +package input import ( "sync" @@ -24,7 +24,7 @@ type Input struct { cursorX int cursorY int gamepads [16]gamePad - touches []touch + touches []*Touch m sync.RWMutex } @@ -40,13 +40,16 @@ func (i *Input) IsMouseButtonPressed(key MouseButton) bool { return false } -func (i *Input) updateTouches(touches []Touch, dx, dy int) { +func (i *Input) UpdateTouches(touches []*Touch, dx, dy int) { i.m.Lock() - ts := make([]touch, len(touches)) + ts := make([]*Touch, len(touches)) for i := 0; i < len(ts); i++ { - ts[i].id = touches[i].ID() x, y := touches[i].Position() - ts[i].x, ts[i].y = x+dx, y+dy + ts[i] = &Touch{ + id: touches[i].id, + x: x + dx, + y: y + dy, + } } i.touches = ts i.m.Unlock() diff --git a/internal/ui/keys.go b/internal/input/keys.go similarity index 98% rename from internal/ui/keys.go rename to internal/input/keys.go index 793df2a3e..542b13a0d 100644 --- a/internal/ui/keys.go +++ b/internal/input/keys.go @@ -14,7 +14,7 @@ // Code generated by genkeys.go using 'go generate'. DO NOT EDIT. -package ui +package input type Key int diff --git a/internal/ui/keys_glfw.go b/internal/input/keys_glfw.go similarity index 99% rename from internal/ui/keys_glfw.go rename to internal/input/keys_glfw.go index 9371cff11..f2bc67f09 100644 --- a/internal/ui/keys_glfw.go +++ b/internal/input/keys_glfw.go @@ -19,7 +19,7 @@ // +build !android // +build !ios -package ui +package input import ( glfw "github.com/go-gl/glfw/v3.2/glfw" diff --git a/internal/ui/keys_js.go b/internal/input/keys_js.go similarity index 99% rename from internal/ui/keys_js.go rename to internal/input/keys_js.go index 2067a74b6..118f0649b 100644 --- a/internal/ui/keys_js.go +++ b/internal/input/keys_js.go @@ -16,7 +16,7 @@ // +build js -package ui +package input var keyToCodes = map[Key][]string{ Key0: { diff --git a/internal/ui/mousebutton.go b/internal/input/mousebutton.go similarity index 98% rename from internal/ui/mousebutton.go rename to internal/input/mousebutton.go index 276a6ebe2..5b69d5ba1 100644 --- a/internal/ui/mousebutton.go +++ b/internal/input/mousebutton.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package ui +package input type MouseButton int diff --git a/internal/ui/mainloop_gomobilebuild.go b/internal/ui/mainloop_gomobilebuild.go index d36296ffa..caea53c8f 100644 --- a/internal/ui/mainloop_gomobilebuild.go +++ b/internal/ui/mainloop_gomobilebuild.go @@ -22,9 +22,10 @@ import ( "golang.org/x/mobile/event/lifecycle" "golang.org/x/mobile/event/paint" "golang.org/x/mobile/event/size" - mtouch "golang.org/x/mobile/event/touch" + "golang.org/x/mobile/event/touch" "golang.org/x/mobile/gl" + "github.com/hajimehoshi/ebiten/internal/input" "github.com/hajimehoshi/ebiten/internal/opengl" ) @@ -34,7 +35,7 @@ var ( func appMain(a app.App) { var glctx gl.Context - touches := map[mtouch.Sequence]*touch{} + touches := map[touch.Sequence]*input.Touch{} for e := range a.Events() { switch e := a.Filter(e).(type) { case lifecycle.Event: @@ -61,20 +62,17 @@ func appMain(a app.App) { <-chRenderEnd a.Publish() a.Send(paint.Event{}) - case mtouch.Event: + case touch.Event: switch e.Type { - case mtouch.TypeBegin, mtouch.TypeMove: + case touch.TypeBegin, touch.TypeMove: s := float32(actualScale()) - t := &touch{ - id: int(e.Sequence), // TODO: Is it ok to cast from int64 to int here? - x: int(e.X / s), - y: int(e.Y / s), - } + // TODO: Is it ok to cast from int64 to int here? + t := input.NewTouch(int(e.Sequence), int(e.X/s), int(e.Y/s)) touches[e.Sequence] = t - case mtouch.TypeEnd: + case touch.TypeEnd: delete(touches, e.Sequence) } - ts := []Touch{} + ts := []*input.Touch{} for _, t := range touches { ts = append(ts, t) } diff --git a/internal/ui/ui_glfw.go b/internal/ui/ui_glfw.go index e210a20c5..422cdd690 100644 --- a/internal/ui/ui_glfw.go +++ b/internal/ui/ui_glfw.go @@ -29,6 +29,7 @@ import ( "github.com/go-gl/glfw/v3.2/glfw" "github.com/hajimehoshi/ebiten/internal/devicescale" + "github.com/hajimehoshi/ebiten/internal/input" "github.com/hajimehoshi/ebiten/internal/opengl" ) @@ -347,6 +348,10 @@ func ScreenPadding() (x0, y0, x1, y1 float64) { return ox, oy, ox, oy } +func AdjustedCursorPosition() (x, y int) { + return adjustCursorPosition(input.Get().CursorPosition()) +} + func adjustCursorPosition(x, y int) (int, int) { u := currentUI if !u.isRunning() { @@ -486,7 +491,7 @@ func (u *userInterface) actualScreenScale() float64 { // pollEvents must be called from the main thread. func (u *userInterface) pollEvents() { glfw.PollEvents() - currentInput.update(u.window, u.getScale()*glfwScale()) + input.Get().Update(u.window, u.getScale()*glfwScale()) } func (u *userInterface) updateGraphicsContext(g GraphicsContext) { @@ -542,7 +547,7 @@ func (u *userInterface) update(g GraphicsContext) error { return nil }) if err := g.Update(func() { - currentInput.runeBuffer = currentInput.runeBuffer[:0] + input.Get().ClearRuneBuffer() // The offscreens must be updated every frame (#490). u.updateGraphicsContext(g) }); err != nil { diff --git a/internal/ui/ui_js.go b/internal/ui/ui_js.go index 9babbd28e..80e0049a9 100644 --- a/internal/ui/ui_js.go +++ b/internal/ui/ui_js.go @@ -19,11 +19,11 @@ package ui import ( "image" "strconv" - "unicode" "github.com/gopherjs/gopherjs/js" "github.com/hajimehoshi/ebiten/internal/devicescale" + "github.com/hajimehoshi/ebiten/internal/input" "github.com/hajimehoshi/ebiten/internal/opengl" ) @@ -77,8 +77,8 @@ func ScreenPadding() (x0, y0, x1, y1 float64) { return 0, 0, 0, 0 } -func adjustCursorPosition(x, y int) (int, int) { - return x, y +func AdjustedCursorPosition() (x, y int) { + return input.Get().CursorPosition() } func IsCursorVisible() bool { @@ -151,10 +151,10 @@ func (u *userInterface) update(g GraphicsContext) error { return nil } - currentInput.updateGamepads() + input.Get().UpdateGamepads() u.updateGraphicsContext(g) if err := g.Update(func() { - currentInput.runeBuffer = nil + input.Get().ClearRuneBuffer() // The offscreens must be updated every frame (#490). u.updateGraphicsContext(g) }); err != nil { @@ -180,21 +180,6 @@ func (u *userInterface) loop(g GraphicsContext) error { return <-ch } -func touchEventToTouches(e *js.Object) []touch { - scale := currentUI.getScale() - j := e.Get("targetTouches") - rect := canvas.Call("getBoundingClientRect") - left, top := rect.Get("left").Int(), rect.Get("top").Int() - t := make([]touch, j.Get("length").Int()) - for i := 0; i < len(t); i++ { - jj := j.Call("item", i) - t[i].id = jj.Get("identifier").Int() - t[i].x = int(float64(jj.Get("clientX").Int()-left) / scale) - t[i].y = int(float64(jj.Get("clientY").Int()-top) / scale) - } - return t -} - func init() { if err := initialize(); err != nil { panic(err) @@ -263,66 +248,22 @@ func initialize() error { canvas.Get("style").Set("outline", "none") // Keyboard - canvas.Call("addEventListener", "keydown", func(e *js.Object) { - c := e.Get("code") - if c == js.Undefined { - code := e.Get("keyCode").Int() - if keyCodeToKeyEdge[code] == KeyUp || - keyCodeToKeyEdge[code] == KeyDown || - keyCodeToKeyEdge[code] == KeyLeft || - keyCodeToKeyEdge[code] == KeyRight || - keyCodeToKeyEdge[code] == KeyBackspace || - keyCodeToKeyEdge[code] == KeyTab { - e.Call("preventDefault") - } - currentInput.keyDownEdge(code) - return - } - cs := c.String() - if cs == keyToCodes[KeyUp][0] || - cs == keyToCodes[KeyDown][0] || - cs == keyToCodes[KeyLeft][0] || - cs == keyToCodes[KeyRight][0] || - cs == keyToCodes[KeyBackspace][0] || - cs == keyToCodes[KeyTab][0] { - e.Call("preventDefault") - } - currentInput.keyDown(cs) - }) - canvas.Call("addEventListener", "keypress", func(e *js.Object) { - e.Call("preventDefault") - if r := rune(e.Get("charCode").Int()); unicode.IsPrint(r) { - currentInput.runeBuffer = append(currentInput.runeBuffer, r) - } - }) - canvas.Call("addEventListener", "keyup", func(e *js.Object) { - e.Call("preventDefault") - if e.Get("code") == js.Undefined { - // Assume that UA is Edge. - code := e.Get("keyCode").Int() - currentInput.keyUpEdge(code) - return - } - code := e.Get("code").String() - currentInput.keyUp(code) - }) + canvas.Call("addEventListener", "keydown", input.OnKeyDown) + canvas.Call("addEventListener", "keypress", input.OnKeyPress) + canvas.Call("addEventListener", "keyup", input.OnKeyUp) // Mouse canvas.Call("addEventListener", "mousedown", func(e *js.Object) { - e.Call("preventDefault") - button := e.Get("button").Int() - currentInput.mouseDown(button) - setMouseCursorFromEvent(e) + rect := canvas.Call("getBoundingClientRect") + input.OnMouseDown(e, currentUI.getScale(), rect.Get("left").Int(), rect.Get("top").Int()) }) canvas.Call("addEventListener", "mouseup", func(e *js.Object) { - e.Call("preventDefault") - button := e.Get("button").Int() - currentInput.mouseUp(button) - setMouseCursorFromEvent(e) + rect := canvas.Call("getBoundingClientRect") + input.OnMouseUp(e, currentUI.getScale(), rect.Get("left").Int(), rect.Get("top").Int()) }) canvas.Call("addEventListener", "mousemove", func(e *js.Object) { - e.Call("preventDefault") - setMouseCursorFromEvent(e) + rect := canvas.Call("getBoundingClientRect") + input.OnMouseMove(e, currentUI.getScale(), rect.Get("left").Int(), rect.Get("top").Int()) }) canvas.Call("addEventListener", "contextmenu", func(e *js.Object) { e.Call("preventDefault") @@ -330,16 +271,16 @@ func initialize() error { // Touch canvas.Call("addEventListener", "touchstart", func(e *js.Object) { - e.Call("preventDefault") - currentInput.updateTouches(touchEventToTouches(e)) + rect := canvas.Call("getBoundingClientRect") + input.OnTouchStart(e, currentUI.getScale(), rect.Get("left").Int(), rect.Get("top").Int()) }) canvas.Call("addEventListener", "touchend", func(e *js.Object) { - e.Call("preventDefault") - currentInput.updateTouches(touchEventToTouches(e)) + rect := canvas.Call("getBoundingClientRect") + input.OnTouchEnd(e, currentUI.getScale(), rect.Get("left").Int(), rect.Get("top").Int()) }) canvas.Call("addEventListener", "touchmove", func(e *js.Object) { - e.Call("preventDefault") - currentInput.updateTouches(touchEventToTouches(e)) + rect := canvas.Call("getBoundingClientRect") + input.OnTouchMove(e, currentUI.getScale(), rect.Get("left").Int(), rect.Get("top").Int()) }) // Gamepad @@ -357,15 +298,6 @@ func initialize() error { return nil } -func setMouseCursorFromEvent(e *js.Object) { - scale := currentUI.getScale() - rect := canvas.Call("getBoundingClientRect") - x, y := e.Get("clientX").Int(), e.Get("clientY").Int() - x -= rect.Get("left").Int() - y -= rect.Get("top").Int() - currentInput.setMouseCursor(int(float64(x)/scale), int(float64(y)/scale)) -} - func RunMainThreadLoop(ch <-chan error) error { return <-ch } diff --git a/internal/ui/ui_mobile.go b/internal/ui/ui_mobile.go index a7bbc6260..c670c0850 100644 --- a/internal/ui/ui_mobile.go +++ b/internal/ui/ui_mobile.go @@ -24,6 +24,7 @@ import ( "time" "github.com/hajimehoshi/ebiten/internal/devicescale" + "github.com/hajimehoshi/ebiten/internal/input" "github.com/hajimehoshi/ebiten/internal/opengl" ) @@ -237,8 +238,8 @@ func (u *userInterface) screenPaddingImpl() (x0, y0, x1, y1 float64) { return ox, oy, ox, oy } -func adjustCursorPosition(x, y int) (int, int) { - return currentUI.adjustCursorPosition(x, y) +func AdjustedCursorPosition() (x, y int) { + return currentUI.adjustCursorPosition(input.Get().CursorPosition()) } func (u *userInterface) adjustCursorPosition(x, y int) (int, int) { @@ -285,10 +286,10 @@ func SetWindowDecorated(decorated bool) { // Do nothing } -func UpdateTouches(touches []Touch) { +func UpdateTouches(touches []*input.Touch) { currentUI.m.Lock() ox, oy, _, _ := currentUI.screenPaddingImpl() s := currentUI.actualScaleImpl() currentUI.m.Unlock() - currentInput.updateTouches(touches, -int(ox/s), -int(oy/s)) + input.Get().UpdateTouches(touches, -int(ox/s), -int(oy/s)) } diff --git a/keys.go b/keys.go index 67d7071a1..f514c9fc4 100644 --- a/keys.go +++ b/keys.go @@ -17,7 +17,7 @@ package ebiten import ( - "github.com/hajimehoshi/ebiten/internal/ui" + "github.com/hajimehoshi/ebiten/internal/input" ) // A Key represents a keyboard key. @@ -27,83 +27,83 @@ type Key int // Keys const ( - Key0 Key = Key(ui.Key0) - Key1 Key = Key(ui.Key1) - Key2 Key = Key(ui.Key2) - Key3 Key = Key(ui.Key3) - Key4 Key = Key(ui.Key4) - Key5 Key = Key(ui.Key5) - Key6 Key = Key(ui.Key6) - Key7 Key = Key(ui.Key7) - Key8 Key = Key(ui.Key8) - Key9 Key = Key(ui.Key9) - KeyA Key = Key(ui.KeyA) - KeyB Key = Key(ui.KeyB) - KeyC Key = Key(ui.KeyC) - KeyD Key = Key(ui.KeyD) - KeyE Key = Key(ui.KeyE) - KeyF Key = Key(ui.KeyF) - KeyG Key = Key(ui.KeyG) - KeyH Key = Key(ui.KeyH) - KeyI Key = Key(ui.KeyI) - KeyJ Key = Key(ui.KeyJ) - KeyK Key = Key(ui.KeyK) - KeyL Key = Key(ui.KeyL) - KeyM Key = Key(ui.KeyM) - KeyN Key = Key(ui.KeyN) - KeyO Key = Key(ui.KeyO) - KeyP Key = Key(ui.KeyP) - KeyQ Key = Key(ui.KeyQ) - KeyR Key = Key(ui.KeyR) - KeyS Key = Key(ui.KeyS) - KeyT Key = Key(ui.KeyT) - KeyU Key = Key(ui.KeyU) - KeyV Key = Key(ui.KeyV) - KeyW Key = Key(ui.KeyW) - KeyX Key = Key(ui.KeyX) - KeyY Key = Key(ui.KeyY) - KeyZ Key = Key(ui.KeyZ) - KeyAlt Key = Key(ui.KeyAlt) - KeyApostrophe Key = Key(ui.KeyApostrophe) - KeyBackslash Key = Key(ui.KeyBackslash) - KeyBackspace Key = Key(ui.KeyBackspace) - KeyCapsLock Key = Key(ui.KeyCapsLock) - KeyComma Key = Key(ui.KeyComma) - KeyControl Key = Key(ui.KeyControl) - KeyDelete Key = Key(ui.KeyDelete) - KeyDown Key = Key(ui.KeyDown) - KeyEnd Key = Key(ui.KeyEnd) - KeyEnter Key = Key(ui.KeyEnter) - KeyEqual Key = Key(ui.KeyEqual) - KeyEscape Key = Key(ui.KeyEscape) - KeyF1 Key = Key(ui.KeyF1) - KeyF2 Key = Key(ui.KeyF2) - KeyF3 Key = Key(ui.KeyF3) - KeyF4 Key = Key(ui.KeyF4) - KeyF5 Key = Key(ui.KeyF5) - KeyF6 Key = Key(ui.KeyF6) - KeyF7 Key = Key(ui.KeyF7) - KeyF8 Key = Key(ui.KeyF8) - KeyF9 Key = Key(ui.KeyF9) - KeyF10 Key = Key(ui.KeyF10) - KeyF11 Key = Key(ui.KeyF11) - KeyF12 Key = Key(ui.KeyF12) - KeyGraveAccent Key = Key(ui.KeyGraveAccent) - KeyHome Key = Key(ui.KeyHome) - KeyInsert Key = Key(ui.KeyInsert) - KeyLeft Key = Key(ui.KeyLeft) - KeyLeftBracket Key = Key(ui.KeyLeftBracket) - KeyMinus Key = Key(ui.KeyMinus) - KeyPageDown Key = Key(ui.KeyPageDown) - KeyPageUp Key = Key(ui.KeyPageUp) - KeyPeriod Key = Key(ui.KeyPeriod) - KeyRight Key = Key(ui.KeyRight) - KeyRightBracket Key = Key(ui.KeyRightBracket) - KeySemicolon Key = Key(ui.KeySemicolon) - KeyShift Key = Key(ui.KeyShift) - KeySlash Key = Key(ui.KeySlash) - KeySpace Key = Key(ui.KeySpace) - KeyTab Key = Key(ui.KeyTab) - KeyUp Key = Key(ui.KeyUp) + Key0 Key = Key(input.Key0) + Key1 Key = Key(input.Key1) + Key2 Key = Key(input.Key2) + Key3 Key = Key(input.Key3) + Key4 Key = Key(input.Key4) + Key5 Key = Key(input.Key5) + Key6 Key = Key(input.Key6) + Key7 Key = Key(input.Key7) + Key8 Key = Key(input.Key8) + Key9 Key = Key(input.Key9) + KeyA Key = Key(input.KeyA) + KeyB Key = Key(input.KeyB) + KeyC Key = Key(input.KeyC) + KeyD Key = Key(input.KeyD) + KeyE Key = Key(input.KeyE) + KeyF Key = Key(input.KeyF) + KeyG Key = Key(input.KeyG) + KeyH Key = Key(input.KeyH) + KeyI Key = Key(input.KeyI) + KeyJ Key = Key(input.KeyJ) + KeyK Key = Key(input.KeyK) + KeyL Key = Key(input.KeyL) + KeyM Key = Key(input.KeyM) + KeyN Key = Key(input.KeyN) + KeyO Key = Key(input.KeyO) + KeyP Key = Key(input.KeyP) + KeyQ Key = Key(input.KeyQ) + KeyR Key = Key(input.KeyR) + KeyS Key = Key(input.KeyS) + KeyT Key = Key(input.KeyT) + KeyU Key = Key(input.KeyU) + KeyV Key = Key(input.KeyV) + KeyW Key = Key(input.KeyW) + KeyX Key = Key(input.KeyX) + KeyY Key = Key(input.KeyY) + KeyZ Key = Key(input.KeyZ) + KeyAlt Key = Key(input.KeyAlt) + KeyApostrophe Key = Key(input.KeyApostrophe) + KeyBackslash Key = Key(input.KeyBackslash) + KeyBackspace Key = Key(input.KeyBackspace) + KeyCapsLock Key = Key(input.KeyCapsLock) + KeyComma Key = Key(input.KeyComma) + KeyControl Key = Key(input.KeyControl) + KeyDelete Key = Key(input.KeyDelete) + KeyDown Key = Key(input.KeyDown) + KeyEnd Key = Key(input.KeyEnd) + KeyEnter Key = Key(input.KeyEnter) + KeyEqual Key = Key(input.KeyEqual) + KeyEscape Key = Key(input.KeyEscape) + KeyF1 Key = Key(input.KeyF1) + KeyF2 Key = Key(input.KeyF2) + KeyF3 Key = Key(input.KeyF3) + KeyF4 Key = Key(input.KeyF4) + KeyF5 Key = Key(input.KeyF5) + KeyF6 Key = Key(input.KeyF6) + KeyF7 Key = Key(input.KeyF7) + KeyF8 Key = Key(input.KeyF8) + KeyF9 Key = Key(input.KeyF9) + KeyF10 Key = Key(input.KeyF10) + KeyF11 Key = Key(input.KeyF11) + KeyF12 Key = Key(input.KeyF12) + KeyGraveAccent Key = Key(input.KeyGraveAccent) + KeyHome Key = Key(input.KeyHome) + KeyInsert Key = Key(input.KeyInsert) + KeyLeft Key = Key(input.KeyLeft) + KeyLeftBracket Key = Key(input.KeyLeftBracket) + KeyMinus Key = Key(input.KeyMinus) + KeyPageDown Key = Key(input.KeyPageDown) + KeyPageUp Key = Key(input.KeyPageUp) + KeyPeriod Key = Key(input.KeyPeriod) + KeyRight Key = Key(input.KeyRight) + KeyRightBracket Key = Key(input.KeyRightBracket) + KeySemicolon Key = Key(input.KeySemicolon) + KeyShift Key = Key(input.KeyShift) + KeySlash Key = Key(input.KeySlash) + KeySpace Key = Key(input.KeySpace) + KeyTab Key = Key(input.KeyTab) + KeyUp Key = Key(input.KeyUp) KeyMax Key = KeyUp ) diff --git a/mobile/touches_mobile.go b/mobile/touches_mobile.go index c716d3ca5..2c205a550 100644 --- a/mobile/touches_mobile.go +++ b/mobile/touches_mobile.go @@ -17,6 +17,7 @@ package mobile import ( + "github.com/hajimehoshi/ebiten/internal/input" "github.com/hajimehoshi/ebiten/internal/ui" ) @@ -29,26 +30,13 @@ var ( touches = map[int]position{} ) -// touch implements ui.Touch. -type touch struct { - id int - position position -} - -func (t touch) ID() int { - return t.id -} - -func (t touch) Position() (int, int) { - // TODO: Is this OK to adjust the position here? - return int(float64(t.position.x) / ui.ScreenScale()), - int(float64(t.position.y) / ui.ScreenScale()) -} - func updateTouches() { - ts := []ui.Touch{} + ts := []*input.Touch{} for id, position := range touches { - ts = append(ts, touch{id, position}) + // TODO: Is this OK to adjust the position here? + x := int(float64(position.x) / ui.ScreenScale()) + y := int(float64(position.y) / ui.ScreenScale()) + ts = append(ts, input.NewTouch(id, x, y)) } ui.UpdateTouches(ts) } diff --git a/mousebuttons.go b/mousebuttons.go index d1315206a..1479a342b 100644 --- a/mousebuttons.go +++ b/mousebuttons.go @@ -15,7 +15,7 @@ package ebiten import ( - "github.com/hajimehoshi/ebiten/internal/ui" + "github.com/hajimehoshi/ebiten/internal/input" ) // A MouseButton represents a mouse button. @@ -23,7 +23,7 @@ type MouseButton int // MouseButtons const ( - MouseButtonLeft MouseButton = MouseButton(ui.MouseButtonLeft) - MouseButtonRight MouseButton = MouseButton(ui.MouseButtonRight) - MouseButtonMiddle MouseButton = MouseButton(ui.MouseButtonMiddle) + MouseButtonLeft MouseButton = MouseButton(input.MouseButtonLeft) + MouseButtonRight MouseButton = MouseButton(input.MouseButtonRight) + MouseButtonMiddle MouseButton = MouseButton(input.MouseButtonMiddle) )