ui: Use gopherwasm

This commit is contained in:
Hajime Hoshi 2018-05-27 01:59:35 +09:00
parent faaf391619
commit 8e9c3bd304
2 changed files with 64 additions and 75 deletions

View File

@ -19,7 +19,7 @@ package input
import ( import (
"unicode" "unicode"
"github.com/gopherjs/gopherjs/js" "github.com/hajimehoshi/gopherwasm/js"
) )
type mockRWLock struct{} type mockRWLock struct{}
@ -147,7 +147,7 @@ func (i *Input) UpdateGamepads() {
for id := 0; id < l; id++ { for id := 0; id < l; id++ {
i.gamepads[id].valid = false i.gamepads[id].valid = false
gamepad := gamepads.Index(id) gamepad := gamepads.Index(id)
if gamepad == js.Undefined || gamepad == nil { if gamepad == js.Undefined || gamepad == js.Null {
continue continue
} }
i.gamepads[id].valid = true 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") c := e.Get("code")
if c == js.Undefined { if c == js.Undefined {
code := e.Get("keyCode").Int() code := e.Get("keyCode").Int()
@ -203,15 +203,13 @@ func OnKeyDown(e *js.Object) {
theInput.keyDown(cs) theInput.keyDown(cs)
} }
func OnKeyPress(e *js.Object) { func OnKeyPress(e js.Value) {
e.Call("preventDefault")
if r := rune(e.Get("charCode").Int()); unicode.IsPrint(r) { if r := rune(e.Get("charCode").Int()); unicode.IsPrint(r) {
theInput.runeBuffer = append(theInput.runeBuffer, r) theInput.runeBuffer = append(theInput.runeBuffer, r)
} }
} }
func OnKeyUp(e *js.Object) { func OnKeyUp(e js.Value) {
e.Call("preventDefault")
if e.Get("code") == js.Undefined { if e.Get("code") == js.Undefined {
// Assume that UA is Edge. // Assume that UA is Edge.
code := e.Get("keyCode").Int() code := e.Get("keyCode").Int()
@ -222,46 +220,40 @@ func OnKeyUp(e *js.Object) {
theInput.keyUp(code) theInput.keyUp(code)
} }
func OnMouseDown(e *js.Object) { func OnMouseDown(e js.Value) {
e.Call("preventDefault")
button := e.Get("button").Int() button := e.Get("button").Int()
theInput.mouseDown(button) theInput.mouseDown(button)
setMouseCursorFromEvent(e) setMouseCursorFromEvent(e)
} }
func OnMouseUp(e *js.Object) { func OnMouseUp(e js.Value) {
e.Call("preventDefault")
button := e.Get("button").Int() button := e.Get("button").Int()
theInput.mouseUp(button) theInput.mouseUp(button)
setMouseCursorFromEvent(e) setMouseCursorFromEvent(e)
} }
func OnMouseMove(e *js.Object) { func OnMouseMove(e js.Value) {
e.Call("preventDefault")
setMouseCursorFromEvent(e) setMouseCursorFromEvent(e)
} }
func OnTouchStart(e *js.Object) { func OnTouchStart(e js.Value) {
e.Call("preventDefault")
theInput.updateTouches(e) theInput.updateTouches(e)
} }
func OnTouchEnd(e *js.Object) { func OnTouchEnd(e js.Value) {
e.Call("preventDefault")
theInput.updateTouches(e) theInput.updateTouches(e)
} }
func OnTouchMove(e *js.Object) { func OnTouchMove(e js.Value) {
e.Call("preventDefault")
theInput.updateTouches(e) theInput.updateTouches(e)
} }
func setMouseCursorFromEvent(e *js.Object) { func setMouseCursorFromEvent(e js.Value) {
x, y := e.Get("clientX").Int(), e.Get("clientY").Int() x, y := e.Get("clientX").Int(), e.Get("clientY").Int()
theInput.setMouseCursor(x, y) theInput.setMouseCursor(x, y)
} }
func (i *Input) updateTouches(e *js.Object) { func (i *Input) updateTouches(e js.Value) {
j := e.Get("targetTouches") j := e.Get("targetTouches")
ts := make([]*Touch, j.Get("length").Int()) ts := make([]*Touch, j.Get("length").Int())
for i := 0; i < len(ts); i++ { for i := 0; i < len(ts); i++ {

View File

@ -18,9 +18,10 @@ package ui
import ( import (
"image" "image"
"runtime"
"strconv" "strconv"
"github.com/gopherjs/gopherjs/js" "github.com/hajimehoshi/gopherwasm/js"
"github.com/hajimehoshi/ebiten/internal/devicescale" "github.com/hajimehoshi/ebiten/internal/devicescale"
"github.com/hajimehoshi/ebiten/internal/hooks" "github.com/hajimehoshi/ebiten/internal/hooks"
@ -29,7 +30,7 @@ import (
"github.com/hajimehoshi/ebiten/internal/web" "github.com/hajimehoshi/ebiten/internal/web"
) )
var canvas *js.Object var canvas js.Value
type userInterface struct { type userInterface struct {
width int width int
@ -204,69 +205,66 @@ func (u *userInterface) update(g GraphicsContext) error {
func (u *userInterface) loop(g GraphicsContext) error { func (u *userInterface) loop(g GraphicsContext) error {
ch := make(chan error) ch := make(chan error)
var f func() var f func([]js.Value)
f = func() { var cf js.Callback
go func() { f = func([]js.Value) {
if err := u.update(g); err != nil { if err := u.update(g); err != nil {
ch <- err ch <- err
close(ch) close(ch)
return return
} }
js.Global.Get("window").Call("requestAnimationFrame", f) js.Global.Get("window").Call("requestAnimationFrame", cf)
}()
} }
f() cf = js.NewCallback(f)
f(nil)
return <-ch return <-ch
} }
func init() { func init() {
if err := initialize(); err != nil {
panic(err)
}
}
func initialize() error {
// Do nothing in node.js. // Do nothing in node.js.
if web.IsNodeJS() { if web.IsNodeJS() {
return nil return
} }
doc := js.Global.Get("document") doc := js.Global.Get("document")
window := js.Global.Get("window") window := js.Global.Get("window")
if doc.Get("body") == nil { if doc.Get("body") == js.Null {
ch := make(chan struct{}) ch := make(chan struct{})
window.Call("addEventListener", "load", func() { window.Call("addEventListener", "load", js.NewCallback(func([]js.Value) {
close(ch) 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 <-ch
} }
window.Call("addEventListener", "focus", func() {
window.Call("addEventListener", "focus", js.NewCallback(func([]js.Value) {
currentUI.windowFocus = true currentUI.windowFocus = true
if currentUI.suspended() { if currentUI.suspended() {
hooks.SuspendAudio() hooks.SuspendAudio()
} else { } else {
hooks.ResumeAudio() hooks.ResumeAudio()
} }
}) }))
window.Call("addEventListener", "blur", func() { window.Call("addEventListener", "blur", js.NewCallback(func([]js.Value) {
currentUI.windowFocus = false currentUI.windowFocus = false
if currentUI.suspended() { if currentUI.suspended() {
hooks.SuspendAudio() hooks.SuspendAudio()
} else { } else {
hooks.ResumeAudio() hooks.ResumeAudio()
} }
}) }))
doc.Call("addEventListener", "visibilitychange", func() { doc.Call("addEventListener", "visibilitychange", js.NewCallback(func([]js.Value) {
currentUI.pageVisible = !doc.Get("hidden").Bool() currentUI.pageVisible = !doc.Get("hidden").Bool()
if currentUI.suspended() { if currentUI.suspended() {
hooks.SuspendAudio() hooks.SuspendAudio()
} else { } else {
hooks.ResumeAudio() hooks.ResumeAudio()
} }
}) }))
window.Call("addEventListener", "resize", func() { window.Call("addEventListener", "resize", js.NewCallback(func([]js.Value) {
currentUI.updateScreenSize() currentUI.updateScreenSize()
}) }))
// Adjust the initial scale to 1. // Adjust the initial scale to 1.
// https://developer.mozilla.org/en/docs/Mozilla/Mobile/Viewport_meta_tag // https://developer.mozilla.org/en/docs/Mozilla/Mobile/Viewport_meta_tag
@ -293,9 +291,9 @@ func initialize() error {
bodyStyle.Set("padding", "0") bodyStyle.Set("padding", "0")
// TODO: This is OK as long as the game is in an independent iframe. // TODO: This is OK as long as the game is in an independent iframe.
// What if the canvas is embedded in a HTML directly? // 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") canvas.Call("focus")
}) }))
canvasStyle := canvas.Get("style") canvasStyle := canvas.Get("style")
canvasStyle.Set("position", "absolute") canvasStyle.Set("position", "absolute")
@ -305,36 +303,35 @@ func initialize() error {
canvas.Get("style").Set("outline", "none") canvas.Get("style").Set("outline", "none")
// Keyboard // Keyboard
canvas.Call("addEventListener", "keydown", input.OnKeyDown) canvas.Call("addEventListener", "keydown", js.NewEventCallback(true, false, false, input.OnKeyDown))
canvas.Call("addEventListener", "keypress", input.OnKeyPress) canvas.Call("addEventListener", "keypress", js.NewEventCallback(true, false, false, input.OnKeyPress))
canvas.Call("addEventListener", "keyup", input.OnKeyUp) canvas.Call("addEventListener", "keyup", js.NewEventCallback(true, false, false, input.OnKeyUp))
// Mouse // Mouse
canvas.Call("addEventListener", "mousedown", input.OnMouseDown) canvas.Call("addEventListener", "mousedown", js.NewEventCallback(true, false, false, input.OnMouseDown))
canvas.Call("addEventListener", "mouseup", input.OnMouseUp) canvas.Call("addEventListener", "mouseup", js.NewEventCallback(true, false, false, input.OnMouseUp))
canvas.Call("addEventListener", "mousemove", input.OnMouseMove) canvas.Call("addEventListener", "mousemove", js.NewEventCallback(true, false, false, input.OnMouseMove))
canvas.Call("addEventListener", "contextmenu", func(e *js.Object) {
e.Call("preventDefault")
})
// Touch // Touch
canvas.Call("addEventListener", "touchstart", input.OnTouchStart) canvas.Call("addEventListener", "touchstart", js.NewEventCallback(true, false, false, input.OnTouchStart))
canvas.Call("addEventListener", "touchend", input.OnTouchEnd) canvas.Call("addEventListener", "touchend", js.NewEventCallback(true, false, false, input.OnTouchEnd))
canvas.Call("addEventListener", "touchmove", input.OnTouchMove) canvas.Call("addEventListener", "touchmove", js.NewEventCallback(true, false, false, input.OnTouchMove))
// Gamepad // Gamepad
window.Call("addEventListener", "gamepadconnected", func(e *js.Object) { window.Call("addEventListener", "gamepadconnected", js.NewCallback(func(e []js.Value) {
// Do nothing. // Do nothing.
}) }))
canvas.Call("addEventListener", "webglcontextlost", func(e *js.Object) { canvas.Call("addEventListener", "contextmenu", js.NewEventCallback(true, false, false, func(js.Value) {
e.Call("preventDefault")
})
canvas.Call("addEventListener", "webglcontextrestored", func(e *js.Object) {
// Do nothing. // 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 { func RunMainThreadLoop(ch <-chan error) error {