mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
ebiten: Add the standard gamepad layout
This change introduces the standard gamepad layout. This changes adds these APIs: * func HasGamepadStandardLayoutMapping * func IsGamepadStandardButtonPressed * func GamepadStandardAxisValue * type StandardGamepadButton * type StandardGamepadAxis The standard gamepad layout is based on the web standard. See https://www.w3.org/TR/gamepad/#remapping. On desktops, the SDL's gamecontrllerdb.txt is used. If the gamepad is listed in the text file, the mapping works. GLFW's mapping featrue is not used. On browsers, the property of a gamepad 'mapping' is used. When the mapping value is 'standard', the gamepad is recognized to have the standard mapping. On mobiles, the implementation is still WIP. Updates #1557
This commit is contained in:
parent
f882dbda77
commit
aa694be6f6
@ -85,6 +85,109 @@ func (g *Game) Update() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func standardMap(id ebiten.GamepadID) string {
|
||||||
|
m := ` [FBL] [FBR]
|
||||||
|
[FTL] [FTR]
|
||||||
|
|
||||||
|
[LT] [CC] [RT]
|
||||||
|
[LL][LR] [CL][CR] [RL][RR]
|
||||||
|
[LB] [RB]
|
||||||
|
(LS) (RS)
|
||||||
|
`
|
||||||
|
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonRightBottom) {
|
||||||
|
m = strings.Replace(m, "[RB]", "[**]", 1)
|
||||||
|
} else {
|
||||||
|
m = strings.Replace(m, "[RB]", "[ ]", 1)
|
||||||
|
}
|
||||||
|
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonRightRight) {
|
||||||
|
m = strings.Replace(m, "[RR]", "[**]", 1)
|
||||||
|
} else {
|
||||||
|
m = strings.Replace(m, "[RR]", "[ ]", 1)
|
||||||
|
}
|
||||||
|
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonRightLeft) {
|
||||||
|
m = strings.Replace(m, "[RL]", "[**]", 1)
|
||||||
|
} else {
|
||||||
|
m = strings.Replace(m, "[RL]", "[ ]", 1)
|
||||||
|
}
|
||||||
|
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonRightTop) {
|
||||||
|
m = strings.Replace(m, "[RT]", "[**]", 1)
|
||||||
|
} else {
|
||||||
|
m = strings.Replace(m, "[RT]", "[ ]", 1)
|
||||||
|
}
|
||||||
|
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonFrontTopLeft) {
|
||||||
|
m = strings.Replace(m, "[FTL]", "[**]", 1)
|
||||||
|
} else {
|
||||||
|
m = strings.Replace(m, "[FTL]", "[ ]", 1)
|
||||||
|
}
|
||||||
|
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonFrontTopRight) {
|
||||||
|
m = strings.Replace(m, "[FTR]", "[**]", 1)
|
||||||
|
} else {
|
||||||
|
m = strings.Replace(m, "[FTR]", "[ ]", 1)
|
||||||
|
}
|
||||||
|
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonFrontBottomLeft) {
|
||||||
|
m = strings.Replace(m, "[FBL]", "[**]", 1)
|
||||||
|
} else {
|
||||||
|
m = strings.Replace(m, "[FBL]", "[ ]", 1)
|
||||||
|
}
|
||||||
|
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonFrontBottomRight) {
|
||||||
|
m = strings.Replace(m, "[FBR]", "[**]", 1)
|
||||||
|
} else {
|
||||||
|
m = strings.Replace(m, "[FBR]", "[ ]", 1)
|
||||||
|
}
|
||||||
|
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonCenterLeft) {
|
||||||
|
m = strings.Replace(m, "[CL]", "[**]", 1)
|
||||||
|
} else {
|
||||||
|
m = strings.Replace(m, "[CL]", "[ ]", 1)
|
||||||
|
}
|
||||||
|
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonCenterRight) {
|
||||||
|
m = strings.Replace(m, "[CR]", "[**]", 1)
|
||||||
|
} else {
|
||||||
|
m = strings.Replace(m, "[CR]", "[ ]", 1)
|
||||||
|
}
|
||||||
|
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonLeftStick) {
|
||||||
|
m = strings.Replace(m, "(LS)", "[**]", 1)
|
||||||
|
} else {
|
||||||
|
m = strings.Replace(m, "(LS)", "[ ]", 1)
|
||||||
|
}
|
||||||
|
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonRightStick) {
|
||||||
|
m = strings.Replace(m, "(RS)", "[**]", 1)
|
||||||
|
} else {
|
||||||
|
m = strings.Replace(m, "(RS)", "[ ]", 1)
|
||||||
|
}
|
||||||
|
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonLeftBottom) {
|
||||||
|
m = strings.Replace(m, "[LB]", "[**]", 1)
|
||||||
|
} else {
|
||||||
|
m = strings.Replace(m, "[LB]", "[ ]", 1)
|
||||||
|
}
|
||||||
|
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonLeftRight) {
|
||||||
|
m = strings.Replace(m, "[LR]", "[**]", 1)
|
||||||
|
} else {
|
||||||
|
m = strings.Replace(m, "[LR]", "[ ]", 1)
|
||||||
|
}
|
||||||
|
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonLeftLeft) {
|
||||||
|
m = strings.Replace(m, "[LL]", "[**]", 1)
|
||||||
|
} else {
|
||||||
|
m = strings.Replace(m, "[LL]", "[ ]", 1)
|
||||||
|
}
|
||||||
|
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonLeftTop) {
|
||||||
|
m = strings.Replace(m, "[LT]", "[**]", 1)
|
||||||
|
} else {
|
||||||
|
m = strings.Replace(m, "[LT]", "[ ]", 1)
|
||||||
|
}
|
||||||
|
if ebiten.IsStandardGamepadButtonPressed(id, ebiten.StandardGamepadButtonCenterCenter) {
|
||||||
|
m = strings.Replace(m, "[CC]", "[**]", 1)
|
||||||
|
} else {
|
||||||
|
m = strings.Replace(m, "[CC]", "[ ]", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
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.StandardGamepadAxisLeftStickVertical),
|
||||||
|
ebiten.StandardGamepadAxisValue(id, ebiten.StandardGamepadAxisRightStickHorizontal),
|
||||||
|
ebiten.StandardGamepadAxisValue(id, ebiten.StandardGamepadAxisRightStickVertical))
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
func (g *Game) Draw(screen *ebiten.Image) {
|
func (g *Game) Draw(screen *ebiten.Image) {
|
||||||
// Draw the current gamepad status.
|
// Draw the current gamepad status.
|
||||||
str := ""
|
str := ""
|
||||||
@ -97,9 +200,18 @@ func (g *Game) Draw(screen *ebiten.Image) {
|
|||||||
return ids[a] < ids[b]
|
return ids[a] < ids[b]
|
||||||
})
|
})
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
str += fmt.Sprintf("Gamepad (ID: %d, SDL ID: %s):\n", id, ebiten.GamepadSDLID(id))
|
var standard string
|
||||||
|
if ebiten.HasGamepadStandardLayoutMapping(id) {
|
||||||
|
standard = " (Standard Layout)"
|
||||||
|
}
|
||||||
|
str += fmt.Sprintf("Gamepad (ID: %d, SDL ID: %s)%s:\n", id, ebiten.GamepadSDLID(id), standard)
|
||||||
str += fmt.Sprintf(" Axes: %s\n", strings.Join(g.axes[id], ", "))
|
str += fmt.Sprintf(" Axes: %s\n", strings.Join(g.axes[id], ", "))
|
||||||
str += fmt.Sprintf(" Buttons: %s\n", strings.Join(g.pressedButtons[id], ", "))
|
str += fmt.Sprintf(" Buttons: %s\n", strings.Join(g.pressedButtons[id], ", "))
|
||||||
|
if ebiten.HasGamepadStandardLayoutMapping(id) {
|
||||||
|
str += "\n"
|
||||||
|
str += standardMap(id)
|
||||||
|
str += "\n"
|
||||||
|
}
|
||||||
str += "\n"
|
str += "\n"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
43
gamepad.go
43
gamepad.go
@ -18,7 +18,7 @@ import (
|
|||||||
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A GamepadButton represents a gamepad button.
|
// GamepadButton represents a gamepad button.
|
||||||
type GamepadButton = driver.GamepadButton
|
type GamepadButton = driver.GamepadButton
|
||||||
|
|
||||||
// GamepadButtons
|
// GamepadButtons
|
||||||
@ -57,3 +57,44 @@ const (
|
|||||||
GamepadButton31 GamepadButton = driver.GamepadButton31
|
GamepadButton31 GamepadButton = driver.GamepadButton31
|
||||||
GamepadButtonMax GamepadButton = GamepadButton31
|
GamepadButtonMax GamepadButton = GamepadButton31
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// StandardGamepadButton represents a gamepad button in the standard layout.
|
||||||
|
//
|
||||||
|
// The layout and the button values are based on the web standard.
|
||||||
|
// See https://www.w3.org/TR/gamepad/#remapping.
|
||||||
|
type StandardGamepadButton = driver.StandardGamepadButton
|
||||||
|
|
||||||
|
// StandardGamepadButtons
|
||||||
|
const (
|
||||||
|
StandardGamepadButtonRightBottom StandardGamepadButton = driver.StandardGamepadButtonRightBottom
|
||||||
|
StandardGamepadButtonRightRight StandardGamepadButton = driver.StandardGamepadButtonRightRight
|
||||||
|
StandardGamepadButtonRightLeft StandardGamepadButton = driver.StandardGamepadButtonRightLeft
|
||||||
|
StandardGamepadButtonRightTop StandardGamepadButton = driver.StandardGamepadButtonRightTop
|
||||||
|
StandardGamepadButtonFrontTopLeft StandardGamepadButton = driver.StandardGamepadButtonFrontTopLeft
|
||||||
|
StandardGamepadButtonFrontTopRight StandardGamepadButton = driver.StandardGamepadButtonFrontTopRight
|
||||||
|
StandardGamepadButtonFrontBottomLeft StandardGamepadButton = driver.StandardGamepadButtonFrontBottomLeft
|
||||||
|
StandardGamepadButtonFrontBottomRight StandardGamepadButton = driver.StandardGamepadButtonFrontBottomRight
|
||||||
|
StandardGamepadButtonCenterLeft StandardGamepadButton = driver.StandardGamepadButtonCenterLeft
|
||||||
|
StandardGamepadButtonCenterRight StandardGamepadButton = driver.StandardGamepadButtonCenterRight
|
||||||
|
StandardGamepadButtonLeftStick StandardGamepadButton = driver.StandardGamepadButtonLeftStick
|
||||||
|
StandardGamepadButtonRightStick StandardGamepadButton = driver.StandardGamepadButtonRightStick
|
||||||
|
StandardGamepadButtonLeftTop StandardGamepadButton = driver.StandardGamepadButtonLeftTop
|
||||||
|
StandardGamepadButtonLeftBottom StandardGamepadButton = driver.StandardGamepadButtonLeftBottom
|
||||||
|
StandardGamepadButtonLeftLeft StandardGamepadButton = driver.StandardGamepadButtonLeftLeft
|
||||||
|
StandardGamepadButtonLeftRight StandardGamepadButton = driver.StandardGamepadButtonLeftRight
|
||||||
|
StandardGamepadButtonCenterCenter StandardGamepadButton = driver.StandardGamepadButtonCenterCenter
|
||||||
|
)
|
||||||
|
|
||||||
|
// StandardGamepadAxis represents a gamepad axis in the standard layout.
|
||||||
|
//
|
||||||
|
// The layout and the button values are based on the web standard.
|
||||||
|
// See https://www.w3.org/TR/gamepad/#remapping.
|
||||||
|
type StandardGamepadAxis = driver.StandardGamepadAxis
|
||||||
|
|
||||||
|
// StandardGamepadAxes
|
||||||
|
const (
|
||||||
|
StandardGamepadAxisLeftStickHorizontal StandardGamepadAxis = driver.StandardGamepadAxisLeftStickHorizontal
|
||||||
|
StandardGamepadAxisLeftStickVertical StandardGamepadAxis = driver.StandardGamepadAxisLeftStickVertical
|
||||||
|
StandardGamepadAxisRightStickHorizontal StandardGamepadAxis = driver.StandardGamepadAxisRightStickHorizontal
|
||||||
|
StandardGamepadAxisRightStickVertical StandardGamepadAxis = driver.StandardGamepadAxisRightStickVertical
|
||||||
|
)
|
||||||
|
25
input.go
25
input.go
@ -209,6 +209,31 @@ func IsGamepadButtonPressed(id GamepadID, button GamepadButton) bool {
|
|||||||
return uiDriver().Input().IsGamepadButtonPressed(id, button)
|
return uiDriver().Input().IsGamepadButtonPressed(id, button)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StandardGamepadAxisValue returns a float value [-1.0 - 1.0] of the given gamepad (id)'s standard axis (axis).
|
||||||
|
//
|
||||||
|
// StandardGamepadAxisValue returns 0 when the gamepad doesn't have a standard gamepad layout mapping.
|
||||||
|
//
|
||||||
|
// StandardGamepadAxisValue is concurrent safe.
|
||||||
|
func StandardGamepadAxisValue(id GamepadID, axis StandardGamepadAxis) float64 {
|
||||||
|
return uiDriver().Input().StandardGamepadAxisValue(id, axis)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsStandardGamepadButtonPressed reports whether the given gamepad (id)'s standard gamepad button (button) is pressed.
|
||||||
|
//
|
||||||
|
// IsStandardGamepadButtonPressed returns false when the gamepad doesn't have a standard gamepad layout mapping.
|
||||||
|
//
|
||||||
|
// IsStandardGamepadButtonPressed is concurrent safe.
|
||||||
|
func IsStandardGamepadButtonPressed(id GamepadID, button StandardGamepadButton) bool {
|
||||||
|
return uiDriver().Input().IsStandardGamepadButtonPressed(id, button)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasGamepadStandardLayoutMapping reports whether the gamepad (id) has the standard gamepad layout.
|
||||||
|
//
|
||||||
|
// HasGamepadStandardLayoutMapping is concurrent-safe.
|
||||||
|
func HasGamepadStandardLayoutMapping(id GamepadID) bool {
|
||||||
|
return uiDriver().Input().HasGamepadStandardLayoutMapping(id)
|
||||||
|
}
|
||||||
|
|
||||||
// TouchID represents a touch's identifier.
|
// TouchID represents a touch's identifier.
|
||||||
type TouchID = driver.TouchID
|
type TouchID = driver.TouchID
|
||||||
|
|
||||||
|
@ -52,3 +52,36 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const GamepadButtonNum = 32
|
const GamepadButtonNum = 32
|
||||||
|
|
||||||
|
type StandardGamepadButton int
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/gamepad/#remapping
|
||||||
|
const (
|
||||||
|
StandardGamepadButtonRightBottom StandardGamepadButton = iota
|
||||||
|
StandardGamepadButtonRightRight
|
||||||
|
StandardGamepadButtonRightLeft
|
||||||
|
StandardGamepadButtonRightTop
|
||||||
|
StandardGamepadButtonFrontTopLeft
|
||||||
|
StandardGamepadButtonFrontTopRight
|
||||||
|
StandardGamepadButtonFrontBottomLeft
|
||||||
|
StandardGamepadButtonFrontBottomRight
|
||||||
|
StandardGamepadButtonCenterLeft
|
||||||
|
StandardGamepadButtonCenterRight
|
||||||
|
StandardGamepadButtonLeftStick
|
||||||
|
StandardGamepadButtonRightStick
|
||||||
|
StandardGamepadButtonLeftTop
|
||||||
|
StandardGamepadButtonLeftBottom
|
||||||
|
StandardGamepadButtonLeftLeft
|
||||||
|
StandardGamepadButtonLeftRight
|
||||||
|
StandardGamepadButtonCenterCenter
|
||||||
|
)
|
||||||
|
|
||||||
|
type StandardGamepadAxis int
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/gamepad/#remapping
|
||||||
|
const (
|
||||||
|
StandardGamepadAxisLeftStickHorizontal StandardGamepadAxis = iota
|
||||||
|
StandardGamepadAxisLeftStickVertical
|
||||||
|
StandardGamepadAxisRightStickHorizontal
|
||||||
|
StandardGamepadAxisRightStickVertical
|
||||||
|
)
|
||||||
|
@ -28,9 +28,12 @@ type Input interface {
|
|||||||
GamepadAxisValue(id GamepadID, axis int) float64
|
GamepadAxisValue(id GamepadID, axis int) float64
|
||||||
GamepadAxisNum(id GamepadID) int
|
GamepadAxisNum(id GamepadID) int
|
||||||
GamepadButtonNum(id GamepadID) int
|
GamepadButtonNum(id GamepadID) int
|
||||||
|
HasGamepadStandardLayoutMapping(id GamepadID) bool
|
||||||
IsGamepadButtonPressed(id GamepadID, button GamepadButton) bool
|
IsGamepadButtonPressed(id GamepadID, button GamepadButton) bool
|
||||||
IsKeyPressed(key Key) bool
|
IsKeyPressed(key Key) bool
|
||||||
IsMouseButtonPressed(button MouseButton) bool
|
IsMouseButtonPressed(button MouseButton) bool
|
||||||
|
IsStandardGamepadButtonPressed(id GamepadID, button StandardGamepadButton) bool
|
||||||
|
StandardGamepadAxisValue(id GamepadID, button StandardGamepadAxis) float64
|
||||||
TouchPosition(id TouchID) (x, y int)
|
TouchPosition(id TouchID) (x, y int)
|
||||||
Wheel() (xoff, yoff float64)
|
Wheel() (xoff, yoff float64)
|
||||||
}
|
}
|
||||||
|
1021
internal/gamepaddb/gamecontrollerdb.txt
Normal file
1021
internal/gamepaddb/gamecontrollerdb.txt
Normal file
File diff suppressed because it is too large
Load Diff
5
internal/gamepaddb/gamecontrollerdb.txt.go
Normal file
5
internal/gamepaddb/gamecontrollerdb.txt.go
Normal file
File diff suppressed because one or more lines are too long
379
internal/gamepaddb/gamepaddb.go
Normal file
379
internal/gamepaddb/gamepaddb.go
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
// Copyright 2021 The Ebiten Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// gamecontrollerdb.txt is downloaded at https://github.com/gabomdq/SDL_GameControllerDB.
|
||||||
|
|
||||||
|
//go:generate file2byteslice -package gamepaddb -input=./gamecontrollerdb.txt -output=./gamecontrollerdb.txt.go -var=gamecontrollerdbTxt
|
||||||
|
|
||||||
|
package gamepaddb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||||
|
)
|
||||||
|
|
||||||
|
type platform int
|
||||||
|
|
||||||
|
const (
|
||||||
|
platformUnknown platform = iota
|
||||||
|
platformWindows
|
||||||
|
platformMacOS
|
||||||
|
platformUnix
|
||||||
|
platformAndroid
|
||||||
|
platformIOS
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var currentPlatform platform
|
||||||
|
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
currentPlatform = platformWindows
|
||||||
|
} else if runtime.GOOS == "aix" ||
|
||||||
|
runtime.GOOS == "dragonfly" ||
|
||||||
|
runtime.GOOS == "freebsd" ||
|
||||||
|
runtime.GOOS == "hurd" ||
|
||||||
|
runtime.GOOS == "illumos" ||
|
||||||
|
runtime.GOOS == "linux" ||
|
||||||
|
runtime.GOOS == "netbsd" ||
|
||||||
|
runtime.GOOS == "openbsd" ||
|
||||||
|
runtime.GOOS == "solaris" {
|
||||||
|
currentPlatform = platformUnix
|
||||||
|
} else if runtime.GOOS == "android" {
|
||||||
|
currentPlatform = platformAndroid
|
||||||
|
} else if isIOS {
|
||||||
|
currentPlatform = platformIOS
|
||||||
|
} else if runtime.GOOS == "darwin" {
|
||||||
|
currentPlatform = platformMacOS
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentPlatform == platformUnknown {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r := bufio.NewReader(bytes.NewReader(gamecontrollerdbTxt))
|
||||||
|
for {
|
||||||
|
line, err := r.ReadString('\n')
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := processLine(line, currentPlatform); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type mappingType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
mappingTypeButton mappingType = iota
|
||||||
|
mappingTypeAxis
|
||||||
|
mappingTypeHat
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
HatUp = 1
|
||||||
|
HatRight = 2
|
||||||
|
HatDown = 4
|
||||||
|
HatLeft = 8
|
||||||
|
)
|
||||||
|
|
||||||
|
type mapping struct {
|
||||||
|
Type mappingType
|
||||||
|
Index int
|
||||||
|
AxisScale int
|
||||||
|
AxisOffset int
|
||||||
|
HatState int
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
gamepadButtonMappings = map[string]map[driver.StandardGamepadButton]*mapping{}
|
||||||
|
gamepadAxisMappings = map[string]map[driver.StandardGamepadAxis]*mapping{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func processLine(line string, platform platform) error {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if len(line) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if line[0] == '#' {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
tokens := strings.Split(line, ",")
|
||||||
|
id := tokens[0]
|
||||||
|
for _, token := range tokens[2:] {
|
||||||
|
if len(token) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tks := strings.Split(token, ":")
|
||||||
|
if tks[0] == "platform" {
|
||||||
|
switch tks[1] {
|
||||||
|
case "Windows":
|
||||||
|
if platform != platformWindows {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case "Mac OS X":
|
||||||
|
if platform != platformMacOS {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case "Linux":
|
||||||
|
if platform != platformUnix {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case "Android":
|
||||||
|
if platform != platformAndroid {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case "iOS":
|
||||||
|
if platform != platformIOS {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("gamepaddb: unexpected platform: %s", tks[1])
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
gb, err := parseMappingElement(tks[1])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if b, ok := toStandardGamepadButton(tks[0]); ok {
|
||||||
|
m, ok := gamepadButtonMappings[id]
|
||||||
|
if !ok {
|
||||||
|
m = map[driver.StandardGamepadButton]*mapping{}
|
||||||
|
gamepadButtonMappings[id] = m
|
||||||
|
}
|
||||||
|
m[b] = gb
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if a, ok := toStandardGamepadAxis(tks[0]); ok {
|
||||||
|
m, ok := gamepadAxisMappings[id]
|
||||||
|
if !ok {
|
||||||
|
m = map[driver.StandardGamepadAxis]*mapping{}
|
||||||
|
gamepadAxisMappings[id] = m
|
||||||
|
}
|
||||||
|
m[a] = gb
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// The buttons like "misc1" are ignored so far.
|
||||||
|
// There is no corresponding button in the Web standard gamepad layout.
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseMappingElement(str string) (*mapping, error) {
|
||||||
|
switch {
|
||||||
|
case str[0] == 'a' || strings.HasPrefix(str, "+a") || strings.HasPrefix(str, "-a"):
|
||||||
|
min := -1
|
||||||
|
max := 1
|
||||||
|
numstr := str[1:]
|
||||||
|
if str[0] == '+' {
|
||||||
|
numstr = str[2:]
|
||||||
|
min = 0
|
||||||
|
} else if str[0] == '-' {
|
||||||
|
numstr = str[2:]
|
||||||
|
max = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
scale := 2 / (max - min)
|
||||||
|
offset := -(max + min)
|
||||||
|
if numstr[len(numstr)-1] == '~' {
|
||||||
|
numstr = numstr[:len(numstr)-1]
|
||||||
|
scale = -scale
|
||||||
|
offset = -offset
|
||||||
|
}
|
||||||
|
|
||||||
|
index, err := strconv.Atoi(numstr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &mapping{
|
||||||
|
Type: mappingTypeAxis,
|
||||||
|
Index: index,
|
||||||
|
AxisScale: scale,
|
||||||
|
AxisOffset: offset,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
case str[0] == 'b':
|
||||||
|
index, err := strconv.Atoi(str[1:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &mapping{
|
||||||
|
Type: mappingTypeButton,
|
||||||
|
Index: index,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
case str[0] == 'h':
|
||||||
|
tokens := strings.Split(str[1:], ".")
|
||||||
|
if len(tokens) < 2 {
|
||||||
|
return nil, fmt.Errorf("gamepaddb: unexpected hat: %s", str)
|
||||||
|
}
|
||||||
|
index, err := strconv.Atoi(tokens[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hat, err := strconv.Atoi(tokens[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &mapping{
|
||||||
|
Type: mappingTypeHat,
|
||||||
|
Index: index,
|
||||||
|
HatState: hat,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("gamepaddb: unepxected mapping: %s", str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toStandardGamepadButton(str string) (driver.StandardGamepadButton, bool) {
|
||||||
|
switch str {
|
||||||
|
case "a":
|
||||||
|
return driver.StandardGamepadButtonRightBottom, true
|
||||||
|
case "b":
|
||||||
|
return driver.StandardGamepadButtonRightRight, true
|
||||||
|
case "x":
|
||||||
|
return driver.StandardGamepadButtonRightLeft, true
|
||||||
|
case "y":
|
||||||
|
return driver.StandardGamepadButtonRightTop, true
|
||||||
|
case "back":
|
||||||
|
return driver.StandardGamepadButtonCenterLeft, true
|
||||||
|
case "start":
|
||||||
|
return driver.StandardGamepadButtonCenterRight, true
|
||||||
|
case "guide":
|
||||||
|
return driver.StandardGamepadButtonCenterCenter, true
|
||||||
|
case "leftshoulder":
|
||||||
|
return driver.StandardGamepadButtonFrontTopLeft, true
|
||||||
|
case "rightshoulder":
|
||||||
|
return driver.StandardGamepadButtonFrontTopRight, true
|
||||||
|
case "leftstick":
|
||||||
|
return driver.StandardGamepadButtonLeftStick, true
|
||||||
|
case "rightstick":
|
||||||
|
return driver.StandardGamepadButtonRightStick, true
|
||||||
|
case "dpup":
|
||||||
|
return driver.StandardGamepadButtonLeftTop, true
|
||||||
|
case "dpright":
|
||||||
|
return driver.StandardGamepadButtonLeftRight, true
|
||||||
|
case "dpdown":
|
||||||
|
return driver.StandardGamepadButtonLeftBottom, true
|
||||||
|
case "dpleft":
|
||||||
|
return driver.StandardGamepadButtonLeftLeft, true
|
||||||
|
case "lefttrigger":
|
||||||
|
return driver.StandardGamepadButtonFrontBottomLeft, true
|
||||||
|
case "righttrigger":
|
||||||
|
return driver.StandardGamepadButtonFrontBottomRight, true
|
||||||
|
default:
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toStandardGamepadAxis(str string) (driver.StandardGamepadAxis, bool) {
|
||||||
|
switch str {
|
||||||
|
case "leftx":
|
||||||
|
return driver.StandardGamepadAxisLeftStickHorizontal, true
|
||||||
|
case "lefty":
|
||||||
|
return driver.StandardGamepadAxisLeftStickVertical, true
|
||||||
|
case "rightx":
|
||||||
|
return driver.StandardGamepadAxisRightStickHorizontal, true
|
||||||
|
case "righty":
|
||||||
|
return driver.StandardGamepadAxisRightStickVertical, true
|
||||||
|
default:
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func HasStandardLayoutMapping(id string) bool {
|
||||||
|
if _, ok := gamepadButtonMappings[id]; ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if _, ok := gamepadAxisMappings[id]; ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type GamepadState interface {
|
||||||
|
Axis(index int) float64
|
||||||
|
Button(index int) bool
|
||||||
|
Hat(index int) int
|
||||||
|
}
|
||||||
|
|
||||||
|
func AxisValue(id string, axis driver.StandardGamepadAxis, state GamepadState) float64 {
|
||||||
|
mappings, ok := gamepadAxisMappings[id]
|
||||||
|
if !ok {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
switch m := mappings[axis]; m.Type {
|
||||||
|
case mappingTypeAxis:
|
||||||
|
v := state.Axis(m.Index)*float64(m.AxisScale) + float64(m.AxisOffset)
|
||||||
|
if v > 1 {
|
||||||
|
return 1
|
||||||
|
} else if v < -1 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
case mappingTypeButton:
|
||||||
|
if state.Button(m.Index) {
|
||||||
|
return 1
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
case mappingTypeHat:
|
||||||
|
if state.Hat(m.Index)&m.HatState != 0 {
|
||||||
|
return 1
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsButtonPressed(id string, button driver.StandardGamepadButton, state GamepadState) bool {
|
||||||
|
mappings, ok := gamepadButtonMappings[id]
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch m := mappings[button]; m.Type {
|
||||||
|
case mappingTypeAxis:
|
||||||
|
v := state.Axis(m.Index)*float64(m.AxisScale) + float64(m.AxisOffset)
|
||||||
|
if m.AxisOffset < 0 || m.AxisOffset == 0 && m.AxisScale > 0 {
|
||||||
|
return v >= 0
|
||||||
|
} else {
|
||||||
|
return v <= 0
|
||||||
|
}
|
||||||
|
case mappingTypeButton:
|
||||||
|
return state.Button(m.Index)
|
||||||
|
case mappingTypeHat:
|
||||||
|
return state.Hat(m.Index)&m.HatState != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
20
internal/gamepaddb/gamepaddb_ios.go
Normal file
20
internal/gamepaddb/gamepaddb_ios.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2021 The Ebiten Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
//go:build darwin && ios
|
||||||
|
// +build darwin,ios
|
||||||
|
|
||||||
|
package gamepaddb
|
||||||
|
|
||||||
|
const isIOS = true
|
20
internal/gamepaddb/gamepaddb_notios.go
Normal file
20
internal/gamepaddb/gamepaddb_notios.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2021 The Ebiten Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
//go:build !darwin || !ios
|
||||||
|
// +build !darwin !ios
|
||||||
|
|
||||||
|
package gamepaddb
|
||||||
|
|
||||||
|
const isIOS = false
|
@ -22,16 +22,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
Action int
|
Action int
|
||||||
ErrorCode int
|
ErrorCode int
|
||||||
Hint int
|
Hint int
|
||||||
InputMode int
|
InputMode int
|
||||||
Joystick int
|
Joystick int
|
||||||
Key int
|
JoystickHatState int
|
||||||
ModifierKey int
|
Key int
|
||||||
MouseButton int
|
ModifierKey int
|
||||||
PeripheralEvent int
|
MouseButton int
|
||||||
StandardCursor int
|
PeripheralEvent int
|
||||||
|
StandardCursor int
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -154,3 +155,15 @@ const (
|
|||||||
HResizeCursor = StandardCursor(0x00036005)
|
HResizeCursor = StandardCursor(0x00036005)
|
||||||
VResizeCursor = StandardCursor(0x00036006)
|
VResizeCursor = StandardCursor(0x00036006)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
HatCentered = JoystickHatState(0)
|
||||||
|
HatUp = JoystickHatState(1)
|
||||||
|
HatRight = JoystickHatState(2)
|
||||||
|
HatDown = JoystickHatState(4)
|
||||||
|
HatLeft = JoystickHatState(8)
|
||||||
|
HatRightUp = HatRight | HatUp
|
||||||
|
HatRightDown = HatRight | HatDown
|
||||||
|
HatLeftUp = HatLeft | HatUp
|
||||||
|
HatLeftDown = HatLeft | HatDown
|
||||||
|
)
|
||||||
|
@ -281,6 +281,14 @@ func (j Joystick) GetButtons() []Action {
|
|||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (j Joystick) GetHats() []JoystickHatState {
|
||||||
|
var hats []JoystickHatState
|
||||||
|
for _, s := range glfw.Joystick(j).GetHats() {
|
||||||
|
hats = append(hats, JoystickHatState(s))
|
||||||
|
}
|
||||||
|
return hats
|
||||||
|
}
|
||||||
|
|
||||||
func GetMonitors() []*Monitor {
|
func GetMonitors() []*Monitor {
|
||||||
ms := []*Monitor{}
|
ms := []*Monitor{}
|
||||||
for _, m := range glfw.GetMonitors() {
|
for _, m := range glfw.GetMonitors() {
|
||||||
|
@ -393,6 +393,18 @@ func (j Joystick) GetButtons() []byte {
|
|||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (j Joystick) GetHats() []JoystickHatState {
|
||||||
|
var l int32
|
||||||
|
ptr := glfwDLL.call("glfwGetJoystickHats", uintptr(j), uintptr(unsafe.Pointer(&l)))
|
||||||
|
panicError()
|
||||||
|
hats := make([]JoystickHatState, l)
|
||||||
|
for i := int32(0); i < l; i++ {
|
||||||
|
hats[i] = *(*JoystickHatState)(unsafe.Pointer(ptr))
|
||||||
|
ptr++
|
||||||
|
}
|
||||||
|
return hats
|
||||||
|
}
|
||||||
|
|
||||||
func GetMonitors() []*Monitor {
|
func GetMonitors() []*Monitor {
|
||||||
var l int32
|
var l int32
|
||||||
ptr := glfwDLL.call("glfwGetMonitors", uintptr(unsafe.Pointer(&l)))
|
ptr := glfwDLL.call("glfwGetMonitors", uintptr(unsafe.Pointer(&l)))
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||||
|
"github.com/hajimehoshi/ebiten/v2/internal/gamepaddb"
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/glfw"
|
"github.com/hajimehoshi/ebiten/v2/internal/glfw"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,6 +37,8 @@ type gamepad struct {
|
|||||||
axes [16]float64
|
axes [16]float64
|
||||||
buttonNum int
|
buttonNum int
|
||||||
buttonPressed [256]bool
|
buttonPressed [256]bool
|
||||||
|
hatsNum int
|
||||||
|
hats [16]int
|
||||||
}
|
}
|
||||||
|
|
||||||
type Input struct {
|
type Input struct {
|
||||||
@ -344,8 +347,83 @@ func (i *Input) update(window *glfw.Window, context driver.UIContext) {
|
|||||||
i.gamepads[id].axes[a] = float64(axes32[a])
|
i.gamepads[id].axes[a] = float64(axes32[a])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hats := id.GetHats()
|
||||||
|
i.gamepads[id].hatsNum = len(hats)
|
||||||
|
for h := 0; h < len(i.gamepads[id].hats); h++ {
|
||||||
|
if len(hats) <= h {
|
||||||
|
i.gamepads[id].hats[h] = 0
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
i.gamepads[id].hats[h] = int(hats[h])
|
||||||
|
}
|
||||||
|
|
||||||
// Note that GLFW's gamepad GUID follows SDL's GUID.
|
// Note that GLFW's gamepad GUID follows SDL's GUID.
|
||||||
i.gamepads[id].guid = id.GetGUID()
|
i.gamepads[id].guid = id.GetGUID()
|
||||||
i.gamepads[id].name = id.GetName()
|
i.gamepads[id].name = id.GetName()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Input) HasGamepadStandardLayoutMapping(id driver.GamepadID) bool {
|
||||||
|
i.ui.m.Lock()
|
||||||
|
defer i.ui.m.Unlock()
|
||||||
|
|
||||||
|
if len(i.gamepads) <= int(id) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
g := i.gamepads[int(id)]
|
||||||
|
return gamepaddb.HasStandardLayoutMapping(g.guid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Input) StandardGamepadAxisValue(id driver.GamepadID, axis driver.StandardGamepadAxis) float64 {
|
||||||
|
i.ui.m.Lock()
|
||||||
|
defer i.ui.m.Unlock()
|
||||||
|
|
||||||
|
if len(i.gamepads) <= int(id) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
g := i.gamepads[int(id)]
|
||||||
|
return gamepaddb.AxisValue(g.guid, axis, &gamepadState{&g})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Input) IsStandardGamepadButtonPressed(id driver.GamepadID, button driver.StandardGamepadButton) bool {
|
||||||
|
i.ui.m.Lock()
|
||||||
|
defer i.ui.m.Unlock()
|
||||||
|
|
||||||
|
if len(i.gamepads) <= int(id) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
g := i.gamepads[int(id)]
|
||||||
|
return gamepaddb.IsButtonPressed(g.guid, button, &gamepadState{&g})
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Confirm that all the hat state values are the same.
|
||||||
|
if gamepaddb.HatUp != glfw.HatUp {
|
||||||
|
panic("glfw: gamepaddb.HatUp must equal to glfw.HatUp but not")
|
||||||
|
}
|
||||||
|
if gamepaddb.HatRight != glfw.HatRight {
|
||||||
|
panic("glfw: gamepaddb.HatRight must equal to glfw.HatRight but not")
|
||||||
|
}
|
||||||
|
if gamepaddb.HatDown != glfw.HatDown {
|
||||||
|
panic("glfw: gamepaddb.HatDown must equal to glfw.HatDown but not")
|
||||||
|
}
|
||||||
|
if gamepaddb.HatLeft != glfw.HatLeft {
|
||||||
|
panic("glfw: gamepaddb.HatLeft must equal to glfw.HatLeft but not")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type gamepadState struct {
|
||||||
|
g *gamepad
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *gamepadState) Axis(index int) float64 {
|
||||||
|
return s.g.axes[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *gamepadState) Button(index int) bool {
|
||||||
|
return s.g.buttonPressed[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *gamepadState) Hat(index int) int {
|
||||||
|
return s.g.hats[index]
|
||||||
|
}
|
||||||
|
@ -61,12 +61,17 @@ type pos struct {
|
|||||||
|
|
||||||
type gamepad struct {
|
type gamepad struct {
|
||||||
name string
|
name string
|
||||||
|
mapping string
|
||||||
axisNum int
|
axisNum int
|
||||||
axes [16]float64
|
axes [16]float64
|
||||||
buttonNum int
|
buttonNum int
|
||||||
buttonPressed [256]bool
|
buttonPressed [256]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *gamepad) hasStandardLayoutMapping() bool {
|
||||||
|
return g.mapping == "standard"
|
||||||
|
}
|
||||||
|
|
||||||
type Input struct {
|
type Input struct {
|
||||||
keyPressed map[int]bool
|
keyPressed map[int]bool
|
||||||
keyPressedEdge map[int]bool
|
keyPressedEdge map[int]bool
|
||||||
@ -298,6 +303,7 @@ func (i *Input) updateGamepads() {
|
|||||||
id := driver.GamepadID(gp.Get("index").Int())
|
id := driver.GamepadID(gp.Get("index").Int())
|
||||||
g := gamepad{}
|
g := gamepad{}
|
||||||
g.name = gp.Get("id").String()
|
g.name = gp.Get("id").String()
|
||||||
|
g.mapping = gp.Get("mapping").String()
|
||||||
|
|
||||||
axes := gp.Get("axes")
|
axes := gp.Get("axes")
|
||||||
axesNum := axes.Get("length").Int()
|
axesNum := axes.Get("length").Int()
|
||||||
@ -480,3 +486,39 @@ func (i *Input) updateForGo2Cpp() {
|
|||||||
i.gamepads[id] = g
|
i.gamepads[id] = g
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Input) HasGamepadStandardLayoutMapping(id driver.GamepadID) bool {
|
||||||
|
g, ok := i.gamepads[id]
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return g.hasStandardLayoutMapping()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Input) StandardGamepadAxisValue(id driver.GamepadID, axis driver.StandardGamepadAxis) float64 {
|
||||||
|
g, ok := i.gamepads[id]
|
||||||
|
if !ok {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if !g.hasStandardLayoutMapping() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the gamepad's mapping is "standard", the axes IDs are already mapped as the standard layout.
|
||||||
|
// See https://www.w3.org/TR/gamepad/#remapping.
|
||||||
|
return i.GamepadAxisValue(id, int(axis))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Input) IsStandardGamepadButtonPressed(id driver.GamepadID, button driver.StandardGamepadButton) bool {
|
||||||
|
g, ok := i.gamepads[id]
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !g.hasStandardLayoutMapping() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the gamepad's mapping is "standard", the button IDs are already mapped as the standard layout.
|
||||||
|
// See https://www.w3.org/TR/gamepad/#remapping.
|
||||||
|
return i.IsGamepadButtonPressed(id, driver.GamepadButton(button))
|
||||||
|
}
|
||||||
|
@ -132,6 +132,21 @@ func (i *Input) IsGamepadButtonPressed(id driver.GamepadID, button driver.Gamepa
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Input) HasGamepadStandardLayoutMapping(id driver.GamepadID) bool {
|
||||||
|
// TODO: Implement this (#1557)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Input) IsStandardGamepadButtonPressed(id driver.GamepadID, button driver.StandardGamepadButton) bool {
|
||||||
|
// TODO: Implement this (#1557)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Input) StandardGamepadAxisValue(id driver.GamepadID, axis driver.StandardGamepadAxis) float64 {
|
||||||
|
// TODO: Implement this (#1557)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
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()
|
||||||
|
@ -70,6 +70,8 @@ const (
|
|||||||
sourceJoystick = 0x01000010
|
sourceJoystick = 0x01000010
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: Can we map these values to the standard gamepad buttons?
|
||||||
|
|
||||||
var androidKeyToGamepadButton = map[int]driver.GamepadButton{
|
var androidKeyToGamepadButton = map[int]driver.GamepadButton{
|
||||||
keycodeButtonA: driver.GamepadButton0,
|
keycodeButtonA: driver.GamepadButton0,
|
||||||
keycodeButtonB: driver.GamepadButton1,
|
keycodeButtonB: driver.GamepadButton1,
|
||||||
|
Loading…
Reference in New Issue
Block a user