diff --git a/examples/gamepad/main.go b/examples/gamepad/main.go index ab05660bb..1ea64635a 100644 --- a/examples/gamepad/main.go +++ b/examples/gamepad/main.go @@ -32,11 +32,15 @@ const ( ) func update(screen *ebiten.Image) error { - // TODO: API to get the available, lowest ID const gamepadID = 0 + presences := [4]bool{} axes := []string{} pressedButtons := []string{} + for i := range presences { + presences[i] = ebiten.IsGamepadPresent(i) + } + maxAxis := ebiten.GamepadAxisNum(gamepadID) for a := 0; a < maxAxis; a++ { v := ebiten.GamepadAxis(gamepadID, a) @@ -53,10 +57,21 @@ func update(screen *ebiten.Image) error { return nil } - str := `Gamepad + ids := []string{} + for i, p := range presences { + if p { + ids = append(ids, strconv.Itoa(i)) + } + } + + str := `Gamepad ({{.GamepadIDs}}) + +Gamepad (ID: {{.GamepadID}}) status: Axes: {{.Axes}} Pressed Buttons: {{.Buttons}}` + str = strings.Replace(str, "{{.GamepadIDs}}", strings.Join(ids, ","), -1) + str = strings.Replace(str, "{{.GamepadID}}", strconv.Itoa(gamepadID), -1) str = strings.Replace(str, "{{.Axes}}", strings.Join(axes, "\n "), -1) str = strings.Replace(str, "{{.Buttons}}", strings.Join(pressedButtons, ", "), -1) ebitenutil.DebugPrint(screen, str) diff --git a/input.go b/input.go index ba1e955b5..8b38ae977 100644 --- a/input.go +++ b/input.go @@ -56,6 +56,15 @@ func IsMouseButtonPressed(mouseButton MouseButton) bool { return ui.CurrentInput().IsMouseButtonPressed(ui.MouseButton(mouseButton)) } +// IsGamepadPresent returns a boolean value indicating whether the gamepad for the given id exists. +// +// This function is concurrent-safe. +// +// NOTE: Gamepad API is available only on desktops, Chrome and Firefox. +func IsGamepadPresent(id int) bool { + return ui.CurrentInput().IsGamepadPresent(id) +} + // GamepadAxisNum returns the number of axes of the gamepad (id). // // This function is concurrent-safe. diff --git a/internal/ui/input.go b/internal/ui/input.go index 7675b26ac..d993f57e6 100644 --- a/internal/ui/input.go +++ b/internal/ui/input.go @@ -31,6 +31,15 @@ func (i *Input) CursorPosition() (x, y int) { return adjustCursorPosition(i.cursorX, i.cursorY) } +func (i *Input) IsGamepadPresent(id int) bool { + i.m.RLock() + defer i.m.RUnlock() + if len(i.gamepads) <= id { + return false + } + return i.gamepads[id].valid +} + func (i *Input) GamepadAxisNum(id int) int { i.m.RLock() defer i.m.RUnlock() @@ -78,6 +87,7 @@ func (in *Input) Touches() []Touch { } type gamePad struct { + valid bool axisNum int axes [16]float64 buttonNum int diff --git a/internal/ui/input_glfw.go b/internal/ui/input_glfw.go index 4eaa99862..55a954f6e 100644 --- a/internal/ui/input_glfw.go +++ b/internal/ui/input_glfw.go @@ -112,9 +112,12 @@ func (i *Input) update(window *glfw.Window, scale float64) { i.cursorX = int(x / scale) i.cursorY = int(y / scale) for id := glfw.Joystick(0); id < glfw.Joystick(len(i.gamepads)); id++ { + i.gamepads[id].valid = false if !glfw.JoystickPresent(id) { continue } + i.gamepads[id].valid = true + axes32 := glfw.GetJoystickAxes(id) i.gamepads[id].axisNum = len(axes32) for a := 0; a < len(i.gamepads[id].axes); a++ { diff --git a/internal/ui/input_js.go b/internal/ui/input_js.go index 8a2f39494..bcf5735c6 100644 --- a/internal/ui/input_js.go +++ b/internal/ui/input_js.go @@ -139,10 +139,12 @@ func (i *Input) updateGamepads() { gamepads := nav.Call("getGamepads") l := gamepads.Get("length").Int() for id := 0; id < l; id++ { + i.gamepads[id].valid = false gamepad := gamepads.Index(id) if gamepad == js.Undefined || gamepad == nil { continue } + i.gamepads[id].valid = true axes := gamepad.Get("axes") axesNum := axes.Get("length").Int()