ebiten: add IsStandardGamepadAxisAvailable and IsStandardGamepadButtonAvailable (#2241)

Closes #2040
This commit is contained in:
Hajime Hoshi 2022-08-11 12:35:20 +09:00 committed by GitHub
parent 8f792fef45
commit 094726915b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 194 additions and 2 deletions

View File

@ -154,13 +154,17 @@ func standardMap(id ebiten.GamepadID) string {
for b, str := range standardButtonToString { for b, str := range standardButtonToString {
placeholder := "[" + str + strings.Repeat(" ", 4-len(str)) + "]" placeholder := "[" + str + strings.Repeat(" ", 4-len(str)) + "]"
v := ebiten.StandardGamepadButtonValue(id, b) v := ebiten.StandardGamepadButtonValue(id, b)
if ebiten.IsStandardGamepadButtonPressed(id, b) { switch {
case !ebiten.IsStandardGamepadButtonAvailable(id, b):
m = strings.Replace(m, placeholder, " -- ", 1)
case ebiten.IsStandardGamepadButtonPressed(id, b):
m = strings.Replace(m, placeholder, fmt.Sprintf("[%0.2f]", v), 1) m = strings.Replace(m, placeholder, fmt.Sprintf("[%0.2f]", v), 1)
} else { default:
m = strings.Replace(m, placeholder, fmt.Sprintf(" %0.2f ", v), 1) m = strings.Replace(m, placeholder, fmt.Sprintf(" %0.2f ", v), 1)
} }
} }
// TODO: Use ebiten.IsStandardGamepadAxisAvailable
m += fmt.Sprintf(" Left Stick: X: %+0.2f, Y: %+0.2f\n Right Stick: X: %+0.2f, Y: %+0.2f", m += fmt.Sprintf(" Left Stick: X: %+0.2f, Y: %+0.2f\n Right Stick: X: %+0.2f, Y: %+0.2f",
ebiten.StandardGamepadAxisValue(id, ebiten.StandardGamepadAxisLeftStickHorizontal), ebiten.StandardGamepadAxisValue(id, ebiten.StandardGamepadAxisLeftStickHorizontal),
ebiten.StandardGamepadAxisValue(id, ebiten.StandardGamepadAxisLeftStickVertical), ebiten.StandardGamepadAxisValue(id, ebiten.StandardGamepadAxisLeftStickVertical),

View File

@ -303,6 +303,28 @@ func IsStandardGamepadLayoutAvailable(id GamepadID) bool {
return g.IsStandardLayoutAvailable() return g.IsStandardLayoutAvailable()
} }
// IsStandardGamepadAxisAvailable reports whether the standard gamepad axis is available on the gamepad (id).
//
// IsStandardGamepadAxisAvailable is concurrent-safe.
func IsStandardGamepadAxisAvailable(id GamepadID, axis StandardGamepadAxis) bool {
g := gamepad.Get(id)
if g == nil {
return false
}
return g.IsStandardAxisAvailable(axis)
}
// IsStandardGamepadButtonAvailable reports whether the standard gamepad button is available on the gamepad (id).
//
// IsStandardGamepadButtonAvailable is concurrent-safe.
func IsStandardGamepadButtonAvailable(id GamepadID, button StandardGamepadButton) bool {
g := gamepad.Get(id)
if g == nil {
return false
}
return g.IsStandardButtonAvailable(button)
}
// UpdateStandardGamepadLayoutMappings parses the specified string mappings in SDL_GameControllerDB format and // UpdateStandardGamepadLayoutMappings parses the specified string mappings in SDL_GameControllerDB format and
// updates the gamepad layout definitions. // updates the gamepad layout definitions.
// //

View File

@ -190,6 +190,8 @@ type Gamepad struct {
type nativeGamepad interface { type nativeGamepad interface {
update(gamepads *gamepads) error update(gamepads *gamepads) error
hasOwnStandardLayoutMapping() bool hasOwnStandardLayoutMapping() bool
isStandardAxisAvailableInOwnMapping(axis gamepaddb.StandardAxis) bool
isStandardButtonAvailableInOwnMapping(button gamepaddb.StandardButton) bool
axisCount() int axisCount() int
buttonCount() int buttonCount() int
hatCount() int hatCount() int
@ -281,6 +283,28 @@ func (g *Gamepad) IsStandardLayoutAvailable() bool {
return g.native.hasOwnStandardLayoutMapping() return g.native.hasOwnStandardLayoutMapping()
} }
// IsStandardAxisAvailable is concurrent safe.
func (g *Gamepad) IsStandardAxisAvailable(button gamepaddb.StandardAxis) bool {
g.m.Lock()
defer g.m.Unlock()
if gamepaddb.HasStandardLayoutMapping(g.sdlID) {
return gamepaddb.HasStandardAxis(g.sdlID, button)
}
return g.native.isStandardAxisAvailableInOwnMapping(button)
}
// IsStandardButtonAvailable is concurrent safe.
func (g *Gamepad) IsStandardButtonAvailable(button gamepaddb.StandardButton) bool {
g.m.Lock()
defer g.m.Unlock()
if gamepaddb.HasStandardLayoutMapping(g.sdlID) {
return gamepaddb.HasStandardButton(g.sdlID, button)
}
return g.native.isStandardButtonAvailableInOwnMapping(button)
}
// StandardAxisValue is concurrent-safe. // StandardAxisValue is concurrent-safe.
func (g *Gamepad) StandardAxisValue(axis gamepaddb.StandardAxis) float64 { func (g *Gamepad) StandardAxisValue(axis gamepaddb.StandardAxis) float64 {
if gamepaddb.HasStandardLayoutMapping(g.sdlID) { if gamepaddb.HasStandardLayoutMapping(g.sdlID) {

View File

@ -19,6 +19,8 @@ package gamepad
import ( import (
"time" "time"
"github.com/hajimehoshi/ebiten/v2/internal/gamepaddb"
) )
type nativeGamepadsImpl struct{} type nativeGamepadsImpl struct{}
@ -52,6 +54,14 @@ func (*nativeGamepadImpl) hasOwnStandardLayoutMapping() bool {
return false return false
} }
func (*nativeGamepadImpl) isStandardAxisAvailableInOwnMapping(axis gamepaddb.StandardAxis) bool {
return false
}
func (*nativeGamepadImpl) isStandardButtonAvailableInOwnMapping(button gamepaddb.StandardButton) bool {
return false
}
func (g *nativeGamepadImpl) axisCount() int { func (g *nativeGamepadImpl) axisCount() int {
return len(g.axes) return len(g.axes)
} }

View File

@ -21,6 +21,7 @@ import (
"time" "time"
"github.com/hajimehoshi/ebiten/v2/internal/cbackend" "github.com/hajimehoshi/ebiten/v2/internal/cbackend"
"github.com/hajimehoshi/ebiten/v2/internal/gamepaddb"
) )
type nativeGamepadsImpl struct { type nativeGamepadsImpl struct {
@ -98,6 +99,16 @@ func (g *nativeGamepadImpl) hasOwnStandardLayoutMapping() bool {
return g.standard return g.standard
} }
func (g *nativeGamepadImpl) isStandardAxisAvailableInOwnMapping(axis gamepaddb.StandardAxis) bool {
// TODO: Implement this on the C side.
return axis >= 0 && int(axis) < len(g.axisValues)
}
func (g *nativeGamepadImpl) isStandardButtonAvailableInOwnMapping(button gamepaddb.StandardButton) bool {
// TODO: Implement this on the C side.
return button >= 0 && int(button) < len(g.buttonValues)
}
func (g *nativeGamepadImpl) axisCount() int { func (g *nativeGamepadImpl) axisCount() int {
return len(g.axisValues) return len(g.axisValues)
} }

View File

@ -24,6 +24,8 @@ import (
"sync" "sync"
"time" "time"
"unsafe" "unsafe"
"github.com/hajimehoshi/ebiten/v2/internal/gamepaddb"
) )
// #cgo LDFLAGS: -framework CoreFoundation -framework IOKit // #cgo LDFLAGS: -framework CoreFoundation -framework IOKit
@ -406,6 +408,14 @@ func (g *nativeGamepadImpl) hasOwnStandardLayoutMapping() bool {
return false return false
} }
func (g *nativeGamepadImpl) isStandardAxisAvailableInOwnMapping(axis gamepaddb.StandardAxis) bool {
return false
}
func (g *nativeGamepadImpl) isStandardButtonAvailableInOwnMapping(button gamepaddb.StandardButton) bool {
return false
}
func (g *nativeGamepadImpl) axisCount() int { func (g *nativeGamepadImpl) axisCount() int {
return len(g.axisValues) return len(g.axisValues)
} }

View File

@ -28,6 +28,8 @@ import (
"unsafe" "unsafe"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"github.com/hajimehoshi/ebiten/v2/internal/gamepaddb"
) )
type dinputObjectType int type dinputObjectType int
@ -571,6 +573,14 @@ func (*nativeGamepadDesktop) hasOwnStandardLayoutMapping() bool {
return false return false
} }
func (*nativeGamepadDesktop) isStandardAxisAvailableInOwnMapping(axis gamepaddb.StandardAxis) bool {
return false
}
func (*nativeGamepadDesktop) isStandardButtonAvailableInOwnMapping(button gamepaddb.StandardButton) bool {
return false
}
func (g *nativeGamepadDesktop) usesDInput() bool { func (g *nativeGamepadDesktop) usesDInput() bool {
return g.dinputDevice != nil return g.dinputDevice != nil
} }

View File

@ -19,6 +19,8 @@ package gamepad
import ( import (
"time" "time"
"github.com/hajimehoshi/ebiten/v2/internal/gamepaddb"
) )
type nativeGamepadsImpl struct{} type nativeGamepadsImpl struct{}
@ -57,6 +59,14 @@ func (*nativeGamepadImpl) hasOwnStandardLayoutMapping() bool {
return false return false
} }
func (*nativeGamepadImpl) isStandardAxisAvailableInOwnMapping(axis gamepaddb.StandardAxis) bool {
return false
}
func (*nativeGamepadImpl) isStandardButtonAvailableInOwnMapping(button gamepaddb.StandardButton) bool {
return false
}
func (g *nativeGamepadImpl) axisCount() int { func (g *nativeGamepadImpl) axisCount() int {
return len(g.axes) return len(g.axes)
} }

View File

@ -18,6 +18,8 @@ import (
"encoding/hex" "encoding/hex"
"syscall/js" "syscall/js"
"time" "time"
"github.com/hajimehoshi/ebiten/v2/internal/gamepaddb"
) )
var ( var (
@ -114,6 +116,20 @@ func (g *nativeGamepadImpl) hasOwnStandardLayoutMapping() bool {
return g.mapping == "standard" return g.mapping == "standard"
} }
func (g *nativeGamepadImpl) isStandardAxisAvailableInOwnMapping(axis gamepaddb.StandardAxis) bool {
if !g.hasOwnStandardLayoutMapping() {
return false
}
return axis >= 0 && int(axis) < g.axisCount()
}
func (g *nativeGamepadImpl) isStandardButtonAvailableInOwnMapping(button gamepaddb.StandardButton) bool {
if !g.hasOwnStandardLayoutMapping() {
return false
}
return button >= 0 && int(button) < g.buttonCount()
}
func (g *nativeGamepadImpl) update(gamepads *gamepads) error { func (g *nativeGamepadImpl) update(gamepads *gamepads) error {
return nil return nil
} }

View File

@ -27,6 +27,8 @@ import (
"unsafe" "unsafe"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"github.com/hajimehoshi/ebiten/v2/internal/gamepaddb"
) )
const dirName = "/dev/input" const dirName = "/dev/input"
@ -410,6 +412,14 @@ func (*nativeGamepadImpl) hasOwnStandardLayoutMapping() bool {
return false return false
} }
func (*nativeGamepadImpl) isStandardAxisAvailableInOwnMapping(axis gamepaddb.StandardAxis) bool {
return false
}
func (*nativeGamepadImpl) isStandardButtonAvailableInOwnMapping(button gamepaddb.StandardButton) bool {
return false
}
func (g *nativeGamepadImpl) axisCount() int { func (g *nativeGamepadImpl) axisCount() int {
return g.axisCount_ return g.axisCount_
} }

View File

@ -19,6 +19,8 @@ package gamepad
import ( import (
"time" "time"
"github.com/hajimehoshi/ebiten/v2/internal/gamepaddb"
) )
type nativeGamepadsImpl struct{} type nativeGamepadsImpl struct{}
@ -45,6 +47,14 @@ func (*nativeGamepadImpl) hasOwnStandardLayoutMapping() bool {
return false return false
} }
func (*nativeGamepadImpl) isStandardAxisAvailableInOwnMapping(axis gamepaddb.StandardAxis) bool {
return false
}
func (*nativeGamepadImpl) isStandardButtonAvailableInOwnMapping(button gamepaddb.StandardButton) bool {
return false
}
func (*nativeGamepadImpl) axisCount() int { func (*nativeGamepadImpl) axisCount() int {
return 0 return 0
} }

View File

@ -158,6 +158,27 @@ func (n *nativeGamepadXbox) hasOwnStandardLayoutMapping() bool {
return true return true
} }
func (n *nativeGamepadXbox) isStandardAxisAvailableInOwnMapping(axis gamepaddb.StandardAxis) bool {
switch gamepaddb.StandardAxis(axis) {
case gamepaddb.StandardAxisLeftStickHorizontal,
gamepaddb.StandardAxisLeftStickVertical,
gamepaddb.StandardAxisRightStickHorizontal,
gamepaddb.StandardAxisRightStickVertical:
return true
}
return false
}
func (n *nativeGamepadXbox) isStandardButtonAvailableInOwnMapping(button gamepaddb.StandardButton) bool {
switch gamepaddb.StandardButton(button) {
case gamepaddb.StandardButtonFrontBottomLeft,
gamepaddb.StandardButtonFrontBottomRight:
return true
}
_, ok := standardButtonToGamepadInputGamepadButton(button)
return ok
}
func (n *nativeGamepadXbox) axisCount() int { func (n *nativeGamepadXbox) axisCount() int {
return int(gamepaddb.StandardAxisMax) + 1 return int(gamepaddb.StandardAxisMax) + 1
} }

View File

@ -389,6 +389,23 @@ func Name(id string) string {
return gamepadNames[id] return gamepadNames[id]
} }
func HasStandardAxis(id string, axis StandardAxis) bool {
mappingsM.RLock()
defer mappingsM.RUnlock()
mappings := axisMappings(id)
if mappings == nil {
return false
}
mapping := mappings[axis]
if mapping == nil {
return false
}
return true
}
func AxisValue(id string, axis StandardAxis, state GamepadState) float64 { func AxisValue(id string, axis StandardAxis, state GamepadState) float64 {
mappingsM.RLock() mappingsM.RLock()
defer mappingsM.RUnlock() defer mappingsM.RUnlock()
@ -429,6 +446,23 @@ func AxisValue(id string, axis StandardAxis, state GamepadState) float64 {
return 0 return 0
} }
func HasStandardButton(id string, button StandardButton) bool {
mappingsM.RLock()
defer mappingsM.RUnlock()
mappings := buttonMappings(id)
if mappings == nil {
return false
}
mapping := mappings[button]
if mapping == nil {
return false
}
return true
}
func ButtonValue(id string, button StandardButton, state GamepadState) float64 { func ButtonValue(id string, button StandardButton, state GamepadState) float64 {
mappingsM.RLock() mappingsM.RLock()
defer mappingsM.RUnlock() defer mappingsM.RUnlock()