From 8987f7a6456ad1921bdca4108d8becdd0d4013f2 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Mon, 12 Jan 2015 14:36:13 +0900 Subject: [PATCH] Implement Gamepad API for JavaScript (working on Firefox so far) --- example/gamepad/main.go | 1 + internal/ui/input_glfw.go | 24 ++++++++++++------------ internal/ui/input_js.go | 37 +++++++++++++++++++++++++++++++++++++ internal/ui/ui_js.go | 15 ++++++++++++++- 4 files changed, 64 insertions(+), 13 deletions(-) diff --git a/example/gamepad/main.go b/example/gamepad/main.go index 540b54202..dede55f8d 100644 --- a/example/gamepad/main.go +++ b/example/gamepad/main.go @@ -29,6 +29,7 @@ const ( ) func update(screen *ebiten.Image) error { + // TODO: API to get the available, lowest ID const gamepadID = 0 axes := []string{} pressedButtons := []string{} diff --git a/internal/ui/input_glfw.go b/internal/ui/input_glfw.go index 559ae8722..772676c32 100644 --- a/internal/ui/input_glfw.go +++ b/internal/ui/input_glfw.go @@ -37,33 +37,33 @@ func (i *input) update(window *glfw.Window, scale int) error { x, y := window.GetCursorPosition() i.cursorX = int(math.Floor(x)) / scale i.cursorY = int(math.Floor(y)) / scale - for j := glfw.Joystick(0); j < glfw.Joystick(len(i.gamepads)); j++ { - if !glfw.JoystickPresent(j) { + for id := glfw.Joystick(0); id < glfw.Joystick(len(i.gamepads)); id++ { + if !glfw.JoystickPresent(id) { continue } - axes32, err := glfw.GetJoystickAxes(j) + axes32, err := glfw.GetJoystickAxes(id) if err != nil { return err } - i.gamepads[j].axisNum = len(axes32) - for a := 0; a < len(i.gamepads[j].axes); a++ { + i.gamepads[id].axisNum = len(axes32) + for a := 0; a < len(i.gamepads[id].axes); a++ { if len(axes32) <= a { - i.gamepads[j].axes[a] = 0 + i.gamepads[id].axes[a] = 0 continue } - i.gamepads[j].axes[a] = float64(axes32[a]) + i.gamepads[id].axes[a] = float64(axes32[a]) } - buttons, err := glfw.GetJoystickButtons(j) + buttons, err := glfw.GetJoystickButtons(id) if err != nil { return err } - i.gamepads[j].buttonNum = len(buttons) - for b := 0; b < len(i.gamepads[j].buttonPressed); b++ { + i.gamepads[id].buttonNum = len(buttons) + for b := 0; b < len(i.gamepads[id].buttonPressed); b++ { if len(buttons) <= b { - i.gamepads[j].buttonPressed[b] = false + i.gamepads[id].buttonPressed[b] = false continue } - i.gamepads[j].buttonPressed[b] = glfw.Action(buttons[b]) == glfw.Press + i.gamepads[id].buttonPressed[b] = glfw.Action(buttons[b]) == glfw.Press } } return nil diff --git a/internal/ui/input_js.go b/internal/ui/input_js.go index ef484e02d..12b9fdfd3 100644 --- a/internal/ui/input_js.go +++ b/internal/ui/input_js.go @@ -16,6 +16,10 @@ package ui +import ( + "github.com/gopherjs/gopherjs/js" +) + func (i *input) keyDown(key int) { k, ok := keyCodeToKey[key] if !ok { @@ -59,3 +63,36 @@ func (i *input) mouseUp(button int) { func (i *input) mouseMove(x, y int) { i.cursorX, i.cursorY = x, y } + +func (i *input) updateGamepads() { + gamepads := js.Global.Get("navigator").Call("getGamepads") + l := gamepads.Get("length").Int() + for id := 0; id < l; id++ { + gamepad := gamepads.Index(id) + if gamepad == js.Undefined || gamepad == nil { + continue + } + + axes := gamepad.Get("axes") + axesNum := axes.Get("length").Int() + i.gamepads[id].axisNum = axesNum + for a := 0; a < len(i.gamepads[id].axes); a++ { + if axesNum <= a { + i.gamepads[id].axes[a] = 0 + continue + } + i.gamepads[id].axes[a] = axes.Index(a).Float() + } + + buttons := gamepad.Get("buttons") + buttonsNum := buttons.Get("length").Int() + i.gamepads[id].buttonNum = buttonsNum + for b := 0; b < len(i.gamepads[id].buttonPressed); b++ { + if buttonsNum <= b { + i.gamepads[id].buttonPressed[b] = false + continue + } + i.gamepads[id].buttonPressed[b] = buttons.Index(b).Get("pressed").Bool() + } + } +} diff --git a/internal/ui/ui_js.go b/internal/ui/ui_js.go index 288b3fc1f..0278167d8 100644 --- a/internal/ui/ui_js.go +++ b/internal/ui/ui_js.go @@ -47,6 +47,7 @@ func DoEvents() error { for !shown() { vsync() } + currentInput.updateGamepads() return nil } @@ -66,9 +67,10 @@ func init() { // TODO: Implement this with node-webgl mainly for testing. doc := js.Global.Get("document") + window := js.Global.Get("window") if doc.Get("body") == nil { ch := make(chan struct{}) - js.Global.Get("window").Call("addEventListener", "load", func() { + window.Call("addEventListener", "load", func() { close(ch) }) <-ch @@ -127,6 +129,7 @@ func init() { canvas.Call("setAttribute", "tabindex", 1) canvas.Get("style").Set("outline", "none") + // Keyboard canvas.Call("addEventListener", "keydown", func(e js.Object) bool { code := e.Get("keyCode").Int() currentInput.keyDown(code) @@ -137,6 +140,8 @@ func init() { currentInput.keyUp(code) return false }) + + // Mouse canvas.Call("addEventListener", "mousedown", func(e js.Object) bool { button := e.Get("button").Int() currentInput.mouseDown(button) @@ -150,6 +155,14 @@ func init() { canvas.Call("addEventListener", "contextmenu", func(e js.Object) bool { return false }) + + // Gamepad + window.Call("addEventListener", "gamepadconnected", func(e js.Object) { + print(e) + }) + window.Call("addEventListener", "gamepaddisconnected", func(e js.Object) { + print(e) + }) } func devicePixelRatio() int {