ebiten: Support updating the gamepad mapping (#1775)

This is only supported on desktops yet (on mobile standard layout isn't
implemented yet, and on the web this is the browser's responsibility).

Closes #1723
This commit is contained in:
divVerent 2021-08-23 08:44:49 -04:00 committed by GitHub
parent 35deb53624
commit 7b11377bce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 58 additions and 0 deletions

View File

@ -234,6 +234,27 @@ func IsStandardGamepadLayoutAvailable(id GamepadID) bool {
return uiDriver().Input().IsStandardGamepadLayoutAvailable(id) return uiDriver().Input().IsStandardGamepadLayoutAvailable(id)
} }
// UpdateStandardGamepadLayoutMappings updates the gamepad layout definitions using a set of definitions in SDL_GameControllerDB format.
//
// Multiple input definitions can be provided separated by newlines.
// In particular, it is valid to pass an entire gamecontrollerdb.txt file.
//
// Note though that Ebiten already includes its own copy of this file,
// so this call should only be necessary to add mappings for hardware not supported yet;
// ideally games using the StandardGamepad functions should allow the user to provide mappings and then call this function if provided.
// When using this facility to support new hardware, please also send a pull request to https://github.com/gabomdq/SDL_GameControllerDB to make your mapping available to everyone else.
//
// UpdateStandardGamepadLayoutMappings reports whether the mappings were applied, and returns an error in case any occurred while parsing the mappings.
//
// On platforms where gamepad mappings are not managed by Ebiten, this always returns false and nil.
//
// UpdateStandardGamepadLayoutMappings must be called on the main thread before ebiten.Run, and is concurrent-safe after ebiten.Run.
//
// Updated mappings take effect immediately even for already connected gamepads.
func UpdateStandardGamepadLayoutMappings(mappings string) (bool, error) {
return uiDriver().Input().UpdateStandardGamepadLayoutMappings(mappings)
}
// TouchID represents a touch's identifier. // TouchID represents a touch's identifier.
type TouchID = driver.TouchID type TouchID = driver.TouchID

View File

@ -34,6 +34,7 @@ type Input interface {
IsStandardGamepadButtonPressed(id GamepadID, button StandardGamepadButton) bool IsStandardGamepadButtonPressed(id GamepadID, button StandardGamepadButton) bool
IsStandardGamepadLayoutAvailable(id GamepadID) bool IsStandardGamepadLayoutAvailable(id GamepadID) bool
StandardGamepadAxisValue(id GamepadID, button StandardGamepadAxis) float64 StandardGamepadAxisValue(id GamepadID, button StandardGamepadAxis) float64
UpdateStandardGamepadLayoutMappings(mapping string) (bool, error)
TouchPosition(id TouchID) (x, y int) TouchPosition(id TouchID) (x, y int)
Wheel() (xoff, yoff float64) Wheel() (xoff, yoff float64)
} }

View File

@ -452,3 +452,26 @@ func standardButtonToGLFWButton(button driver.StandardGamepadButton) glfw.Gamepa
panic(fmt.Sprintf("glfw: invalid or inconvertible StandardGamepadButton: %d", button)) panic(fmt.Sprintf("glfw: invalid or inconvertible StandardGamepadButton: %d", button))
} }
} }
// UpdateStandardGamepadLayoutMappings can be used to provide new gamepad mappings to Ebiten.
// The string must be in the format of SDL_GameControllerDB.
func (i *Input) UpdateStandardGamepadLayoutMappings(mapping string) (bool, error) {
var err error
if i.ui.isRunning() {
err = i.ui.t.Call(func() error {
return i.updateStandardGamepadLayoutMappings(mapping)
})
} else {
err = i.updateStandardGamepadLayoutMappings(mapping)
}
return err == nil, err
}
func (i *Input) updateStandardGamepadLayoutMappings(mapping string) error {
if !glfw.UpdateGamepadMappings(mapping) {
// Would be nice if we could actually get the error string.
// However, go-gl currently does not provide it in any way.
return fmt.Errorf("glfw: could not parse or update gamepad mappings")
}
return nil
}

View File

@ -496,3 +496,9 @@ func (i *Input) IsStandardGamepadButtonPressed(id driver.GamepadID, button drive
} }
return g.standardButtonPressed[button] return g.standardButtonPressed[button]
} }
// UpdateStandardGamepadLayoutMappings is not supported for JS - the browser maintains the mappings.
func (i *Input) UpdateStandardGamepadLayoutMappings(mapping string) (bool, error) {
// All OK - browser owns this though.
return false, nil
}

View File

@ -147,6 +147,13 @@ func (i *Input) StandardGamepadAxisValue(id driver.GamepadID, axis driver.Standa
return 0 return 0
} }
// UpdateStandardGamepadLayoutMappings is not supported on mobile - this still needs to be implemented.
func (i *Input) UpdateStandardGamepadLayoutMappings(mapping string) (bool, error) {
// TODO: Implement this (#1557)
// Note: NOT returning an error, as mappings also do not matter right now (all functions above return nothing is pressed anyway).
return false, nil
}
func (i *Input) AppendTouchIDs(touchIDs []driver.TouchID) []driver.TouchID { func (i *Input) AppendTouchIDs(touchIDs []driver.TouchID) []driver.TouchID {
i.ui.m.RLock() i.ui.m.RLock()
defer i.ui.m.RUnlock() defer i.ui.m.RUnlock()