diff --git a/internal/input/input_js.go b/internal/input/input_js.go index ccace33b0..50ac12a11 100644 --- a/internal/input/input_js.go +++ b/internal/input/input_js.go @@ -19,7 +19,7 @@ package input import ( "unicode" - "github.com/gopherjs/gopherjs/js" + "github.com/hajimehoshi/gopherwasm/js" ) type mockRWLock struct{} @@ -147,7 +147,7 @@ func (i *Input) UpdateGamepads() { for id := 0; id < l; id++ { i.gamepads[id].valid = false gamepad := gamepads.Index(id) - if gamepad == js.Undefined || gamepad == nil { + if gamepad == js.Undefined || gamepad == js.Null { continue } i.gamepads[id].valid = true @@ -176,7 +176,7 @@ func (i *Input) UpdateGamepads() { } } -func OnKeyDown(e *js.Object) { +func OnKeyDown(e js.Value) { c := e.Get("code") if c == js.Undefined { code := e.Get("keyCode").Int() @@ -203,15 +203,13 @@ func OnKeyDown(e *js.Object) { theInput.keyDown(cs) } -func OnKeyPress(e *js.Object) { - e.Call("preventDefault") +func OnKeyPress(e js.Value) { if r := rune(e.Get("charCode").Int()); unicode.IsPrint(r) { theInput.runeBuffer = append(theInput.runeBuffer, r) } } -func OnKeyUp(e *js.Object) { - e.Call("preventDefault") +func OnKeyUp(e js.Value) { if e.Get("code") == js.Undefined { // Assume that UA is Edge. code := e.Get("keyCode").Int() @@ -222,46 +220,40 @@ func OnKeyUp(e *js.Object) { theInput.keyUp(code) } -func OnMouseDown(e *js.Object) { - e.Call("preventDefault") +func OnMouseDown(e js.Value) { button := e.Get("button").Int() theInput.mouseDown(button) setMouseCursorFromEvent(e) } -func OnMouseUp(e *js.Object) { - e.Call("preventDefault") +func OnMouseUp(e js.Value) { button := e.Get("button").Int() theInput.mouseUp(button) setMouseCursorFromEvent(e) } -func OnMouseMove(e *js.Object) { - e.Call("preventDefault") +func OnMouseMove(e js.Value) { setMouseCursorFromEvent(e) } -func OnTouchStart(e *js.Object) { - e.Call("preventDefault") +func OnTouchStart(e js.Value) { theInput.updateTouches(e) } -func OnTouchEnd(e *js.Object) { - e.Call("preventDefault") +func OnTouchEnd(e js.Value) { theInput.updateTouches(e) } -func OnTouchMove(e *js.Object) { - e.Call("preventDefault") +func OnTouchMove(e js.Value) { theInput.updateTouches(e) } -func setMouseCursorFromEvent(e *js.Object) { +func setMouseCursorFromEvent(e js.Value) { x, y := e.Get("clientX").Int(), e.Get("clientY").Int() theInput.setMouseCursor(x, y) } -func (i *Input) updateTouches(e *js.Object) { +func (i *Input) updateTouches(e js.Value) { j := e.Get("targetTouches") ts := make([]*Touch, j.Get("length").Int()) for i := 0; i < len(ts); i++ { diff --git a/internal/ui/ui_js.go b/internal/ui/ui_js.go index b3b99df07..1ba578f78 100644 --- a/internal/ui/ui_js.go +++ b/internal/ui/ui_js.go @@ -18,9 +18,10 @@ package ui import ( "image" + "runtime" "strconv" - "github.com/gopherjs/gopherjs/js" + "github.com/hajimehoshi/gopherwasm/js" "github.com/hajimehoshi/ebiten/internal/devicescale" "github.com/hajimehoshi/ebiten/internal/hooks" @@ -29,7 +30,7 @@ import ( "github.com/hajimehoshi/ebiten/internal/web" ) -var canvas *js.Object +var canvas js.Value type userInterface struct { width int @@ -204,69 +205,66 @@ func (u *userInterface) update(g GraphicsContext) error { func (u *userInterface) loop(g GraphicsContext) error { ch := make(chan error) - var f func() - f = func() { - go func() { - if err := u.update(g); err != nil { - ch <- err - close(ch) - return - } - js.Global.Get("window").Call("requestAnimationFrame", f) - }() + var f func([]js.Value) + var cf js.Callback + f = func([]js.Value) { + if err := u.update(g); err != nil { + ch <- err + close(ch) + return + } + js.Global.Get("window").Call("requestAnimationFrame", cf) } - f() + cf = js.NewCallback(f) + f(nil) return <-ch } func init() { - if err := initialize(); err != nil { - panic(err) - } -} - -func initialize() error { // Do nothing in node.js. if web.IsNodeJS() { - return nil + return } - doc := js.Global.Get("document") window := js.Global.Get("window") - if doc.Get("body") == nil { + if doc.Get("body") == js.Null { ch := make(chan struct{}) - window.Call("addEventListener", "load", func() { + window.Call("addEventListener", "load", js.NewCallback(func([]js.Value) { close(ch) - }) + })) + if runtime.GOARCH == "js" { + js.Global.Get("console").Call("warn", "'deadlock' error is raised from GopherJS, but this is a known issue: https://github.com/gopherjs/gopherjs/issues/826") + } <-ch } - window.Call("addEventListener", "focus", func() { + + window.Call("addEventListener", "focus", js.NewCallback(func([]js.Value) { currentUI.windowFocus = true if currentUI.suspended() { hooks.SuspendAudio() } else { hooks.ResumeAudio() } - }) - window.Call("addEventListener", "blur", func() { + })) + window.Call("addEventListener", "blur", js.NewCallback(func([]js.Value) { currentUI.windowFocus = false if currentUI.suspended() { hooks.SuspendAudio() } else { hooks.ResumeAudio() } - }) - doc.Call("addEventListener", "visibilitychange", func() { + })) + doc.Call("addEventListener", "visibilitychange", js.NewCallback(func([]js.Value) { currentUI.pageVisible = !doc.Get("hidden").Bool() if currentUI.suspended() { hooks.SuspendAudio() } else { hooks.ResumeAudio() } - }) - window.Call("addEventListener", "resize", func() { + })) + window.Call("addEventListener", "resize", js.NewCallback(func([]js.Value) { currentUI.updateScreenSize() - }) + })) // Adjust the initial scale to 1. // https://developer.mozilla.org/en/docs/Mozilla/Mobile/Viewport_meta_tag @@ -293,9 +291,9 @@ func initialize() error { bodyStyle.Set("padding", "0") // TODO: This is OK as long as the game is in an independent iframe. // What if the canvas is embedded in a HTML directly? - doc.Get("body").Call("addEventListener", "click", func() { + doc.Get("body").Call("addEventListener", "click", js.NewCallback(func([]js.Value) { canvas.Call("focus") - }) + })) canvasStyle := canvas.Get("style") canvasStyle.Set("position", "absolute") @@ -305,36 +303,35 @@ func initialize() error { canvas.Get("style").Set("outline", "none") // Keyboard - canvas.Call("addEventListener", "keydown", input.OnKeyDown) - canvas.Call("addEventListener", "keypress", input.OnKeyPress) - canvas.Call("addEventListener", "keyup", input.OnKeyUp) + canvas.Call("addEventListener", "keydown", js.NewEventCallback(true, false, false, input.OnKeyDown)) + canvas.Call("addEventListener", "keypress", js.NewEventCallback(true, false, false, input.OnKeyPress)) + canvas.Call("addEventListener", "keyup", js.NewEventCallback(true, false, false, input.OnKeyUp)) // Mouse - canvas.Call("addEventListener", "mousedown", input.OnMouseDown) - canvas.Call("addEventListener", "mouseup", input.OnMouseUp) - canvas.Call("addEventListener", "mousemove", input.OnMouseMove) - canvas.Call("addEventListener", "contextmenu", func(e *js.Object) { - e.Call("preventDefault") - }) + canvas.Call("addEventListener", "mousedown", js.NewEventCallback(true, false, false, input.OnMouseDown)) + canvas.Call("addEventListener", "mouseup", js.NewEventCallback(true, false, false, input.OnMouseUp)) + canvas.Call("addEventListener", "mousemove", js.NewEventCallback(true, false, false, input.OnMouseMove)) // Touch - canvas.Call("addEventListener", "touchstart", input.OnTouchStart) - canvas.Call("addEventListener", "touchend", input.OnTouchEnd) - canvas.Call("addEventListener", "touchmove", input.OnTouchMove) + canvas.Call("addEventListener", "touchstart", js.NewEventCallback(true, false, false, input.OnTouchStart)) + canvas.Call("addEventListener", "touchend", js.NewEventCallback(true, false, false, input.OnTouchEnd)) + canvas.Call("addEventListener", "touchmove", js.NewEventCallback(true, false, false, input.OnTouchMove)) // Gamepad - window.Call("addEventListener", "gamepadconnected", func(e *js.Object) { + window.Call("addEventListener", "gamepadconnected", js.NewCallback(func(e []js.Value) { // Do nothing. - }) + })) - canvas.Call("addEventListener", "webglcontextlost", func(e *js.Object) { - e.Call("preventDefault") - }) - canvas.Call("addEventListener", "webglcontextrestored", func(e *js.Object) { + canvas.Call("addEventListener", "contextmenu", js.NewEventCallback(true, false, false, func(js.Value) { // Do nothing. - }) + })) - return nil + canvas.Call("addEventListener", "webglcontextlost", js.NewEventCallback(true, false, false, func(js.Value) { + // Do nothing. + })) + canvas.Call("addEventListener", "webglcontextrestored", js.NewCallback(func(e []js.Value) { + // Do nothing. + })) } func RunMainThreadLoop(ch <-chan error) error {