mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 11:18:54 +01:00
internal/gamepad: port the implementation for Android
This commit is contained in:
parent
ee1b5e2044
commit
d0e8efca33
167
internal/gamepad/extern_android.go
Normal file
167
internal/gamepad/extern_android.go
Normal file
@ -0,0 +1,167 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
package gamepad
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||
)
|
||||
|
||||
type AndroidHatDirection int
|
||||
|
||||
const (
|
||||
AndroidHatDirectionX AndroidHatDirection = iota
|
||||
AndroidHatDirectionY
|
||||
)
|
||||
|
||||
func AddAndroidGamepad(androidDeviceID int, name, sdlID string, axisCount, buttonCount, hatCount int) {
|
||||
theGamepads.addAndroidGamepad(androidDeviceID, name, sdlID, axisCount, buttonCount, hatCount)
|
||||
}
|
||||
|
||||
func RemoveAndroidGamepad(androidDeviceID int) {
|
||||
theGamepads.removeAndroidGamepad(androidDeviceID)
|
||||
}
|
||||
|
||||
func UpdateAndroidGamepadAxis(androidDeviceID int, axis int, value float64) {
|
||||
theGamepads.updateAndroidGamepadAxis(androidDeviceID, axis, value)
|
||||
}
|
||||
|
||||
func UpdateAndroidGamepadButton(androidDeviceID int, button driver.GamepadButton, pressed bool) {
|
||||
theGamepads.updateAndroidGamepadButton(androidDeviceID, button, pressed)
|
||||
}
|
||||
|
||||
func UpdateAndroidGamepadHat(androidDeviceID int, hat int, dir AndroidHatDirection, value int) {
|
||||
theGamepads.updateAndroidGamepadHat(androidDeviceID, hat, dir, value)
|
||||
}
|
||||
|
||||
func (g *gamepads) addAndroidGamepad(androidDeviceID int, name, sdlID string, axisCount, buttonCount, hatCount int) {
|
||||
g.m.Lock()
|
||||
defer g.m.Unlock()
|
||||
|
||||
gp := g.add(name, sdlID)
|
||||
gp.androidDeviceID = androidDeviceID
|
||||
gp.axisCount_ = axisCount
|
||||
gp.buttonCount_ = buttonCount
|
||||
gp.hatCount_ = hatCount
|
||||
gp.axes = make([]float64, axisCount)
|
||||
gp.buttons = make([]bool, buttonCount)
|
||||
gp.hats = make([]int, hatCount)
|
||||
}
|
||||
|
||||
func (g *gamepads) removeAndroidGamepad(androidDeviceID int) {
|
||||
g.m.Lock()
|
||||
defer g.m.Unlock()
|
||||
|
||||
g.remove(func(gamepad *Gamepad) bool {
|
||||
return gamepad.androidDeviceID == androidDeviceID
|
||||
})
|
||||
}
|
||||
|
||||
func (g *gamepads) updateAndroidGamepadAxis(androidDeviceID int, axis int, value float64) {
|
||||
g.m.Lock()
|
||||
defer g.m.Unlock()
|
||||
|
||||
gp := g.find(func(gamepad *Gamepad) bool {
|
||||
return gamepad.androidDeviceID == androidDeviceID
|
||||
})
|
||||
if gp == nil {
|
||||
return
|
||||
}
|
||||
gp.updateAndroidGamepadAxis(axis, value)
|
||||
}
|
||||
|
||||
func (g *gamepads) updateAndroidGamepadButton(androidDeviceID int, button driver.GamepadButton, pressed bool) {
|
||||
g.m.Lock()
|
||||
defer g.m.Unlock()
|
||||
|
||||
gp := g.find(func(gamepad *Gamepad) bool {
|
||||
return gamepad.androidDeviceID == androidDeviceID
|
||||
})
|
||||
if gp == nil {
|
||||
return
|
||||
}
|
||||
gp.updateAndroidGamepadButton(button, pressed)
|
||||
}
|
||||
|
||||
func (g *gamepads) updateAndroidGamepadHat(androidDeviceID int, hat int, dir AndroidHatDirection, value int) {
|
||||
g.m.Lock()
|
||||
defer g.m.Unlock()
|
||||
|
||||
gp := g.find(func(gamepad *Gamepad) bool {
|
||||
return gamepad.androidDeviceID == androidDeviceID
|
||||
})
|
||||
if gp == nil {
|
||||
return
|
||||
}
|
||||
gp.updateAndroidGamepadHat(hat, dir, value)
|
||||
}
|
||||
|
||||
func (g *Gamepad) updateAndroidGamepadAxis(axis int, value float64) {
|
||||
g.m.Lock()
|
||||
defer g.m.Unlock()
|
||||
|
||||
if axis < 0 || axis >= g.axisCount_ {
|
||||
return
|
||||
}
|
||||
g.axes[axis] = value
|
||||
}
|
||||
|
||||
func (g *Gamepad) updateAndroidGamepadButton(button driver.GamepadButton, pressed bool) {
|
||||
g.m.Lock()
|
||||
defer g.m.Unlock()
|
||||
|
||||
if button < 0 || int(button) >= g.buttonCount_ {
|
||||
return
|
||||
}
|
||||
g.buttons[button] = pressed
|
||||
}
|
||||
|
||||
func (g *Gamepad) updateAndroidGamepadHat(hat int, dir AndroidHatDirection, value int) {
|
||||
g.m.Lock()
|
||||
defer g.m.Unlock()
|
||||
|
||||
if hat < 0 || hat >= g.hatCount_ {
|
||||
return
|
||||
}
|
||||
v := g.hats[hat]
|
||||
switch dir {
|
||||
case AndroidHatDirectionX:
|
||||
switch {
|
||||
case value < 0:
|
||||
v |= hatLeft
|
||||
v &^= hatRight
|
||||
case value > 0:
|
||||
v &^= hatLeft
|
||||
v |= hatRight
|
||||
default:
|
||||
v &^= (hatLeft | hatRight)
|
||||
}
|
||||
case AndroidHatDirectionY:
|
||||
switch {
|
||||
case value < 0:
|
||||
v |= hatUp
|
||||
v &^= hatDown
|
||||
case value > 0:
|
||||
v &^= hatUp
|
||||
v |= hatDown
|
||||
default:
|
||||
v &^= (hatUp | hatDown)
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("gamepad: invalid direction: %d", dir))
|
||||
}
|
||||
g.hats[hat] = v
|
||||
}
|
91
internal/gamepad/gamepad_android.go
Normal file
91
internal/gamepad/gamepad_android.go
Normal file
@ -0,0 +1,91 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
package gamepad
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type nativeGamepads struct{}
|
||||
|
||||
func (*nativeGamepads) init(gamepads *gamepads) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*nativeGamepads) update(gamepads *gamepads) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type nativeGamepad struct {
|
||||
androidDeviceID int
|
||||
|
||||
axisCount_ int
|
||||
buttonCount_ int
|
||||
hatCount_ int
|
||||
|
||||
axes []float64
|
||||
buttons []bool
|
||||
hats []int
|
||||
}
|
||||
|
||||
func (*nativeGamepad) update(gamepad *gamepads) error {
|
||||
// Do nothing. The state of gamepads are given via APIs in extern_android.go.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*nativeGamepad) hasOwnStandardLayoutMapping() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (g *nativeGamepad) axisCount() int {
|
||||
return g.axisCount_
|
||||
}
|
||||
|
||||
func (g *nativeGamepad) buttonCount() int {
|
||||
return g.buttonCount_
|
||||
}
|
||||
|
||||
func (g *nativeGamepad) hatCount() int {
|
||||
return g.hatCount_
|
||||
}
|
||||
|
||||
func (g *nativeGamepad) axisValue(axis int) float64 {
|
||||
if axis < 0 || axis >= len(g.axes) {
|
||||
return 0
|
||||
}
|
||||
return g.axes[axis]
|
||||
}
|
||||
|
||||
func (g *nativeGamepad) isButtonPressed(button int) bool {
|
||||
if button < 0 || button >= len(g.buttons) {
|
||||
return false
|
||||
}
|
||||
return g.buttons[button]
|
||||
}
|
||||
|
||||
func (*nativeGamepad) buttonValue(button int) float64 {
|
||||
panic("gamepad: buttonValue is not implemented")
|
||||
}
|
||||
|
||||
func (g *nativeGamepad) hatState(hat int) int {
|
||||
if hat < 0 || hat >= len(g.hats) {
|
||||
return 0
|
||||
}
|
||||
return g.hats[hat]
|
||||
}
|
||||
|
||||
func (g *nativeGamepad) vibrate(duration time.Duration, strongMagnitude float64, weakMagnitude float64) {
|
||||
// TODO: Implement this (#1452)
|
||||
}
|
@ -12,10 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build (!darwin || ios) && !js && (!linux || android) && !windows
|
||||
//go:build (!darwin || ios) && !js && !linux && !windows
|
||||
// +build !darwin ios
|
||||
// +build !js
|
||||
// +build !linux android
|
||||
// +build !linux
|
||||
// +build !windows
|
||||
|
||||
package gamepad
|
||||
|
@ -12,8 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build android || ios
|
||||
// +build android ios
|
||||
//go:build android
|
||||
// +build android
|
||||
|
||||
package mobile
|
||||
|
||||
@ -21,186 +21,104 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/gamepaddb"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/gamepad"
|
||||
)
|
||||
|
||||
type Gamepad struct {
|
||||
ID driver.GamepadID
|
||||
SDLID string
|
||||
Name string
|
||||
Buttons [driver.GamepadButtonNum]bool
|
||||
ButtonNum int
|
||||
Axes [32]float32
|
||||
AxisNum int
|
||||
Hats [16]int
|
||||
HatNum int
|
||||
}
|
||||
|
||||
type gamepadState struct {
|
||||
g *Gamepad
|
||||
}
|
||||
|
||||
func (s gamepadState) Axis(index int) float64 {
|
||||
return float64(s.g.Axes[index])
|
||||
}
|
||||
|
||||
func (s gamepadState) Button(index int) bool {
|
||||
return s.g.Buttons[index]
|
||||
}
|
||||
|
||||
func (s gamepadState) Hat(index int) int {
|
||||
return s.g.Hats[index]
|
||||
}
|
||||
|
||||
func (i *Input) AppendGamepadIDs(gamepadIDs []driver.GamepadID) []driver.GamepadID {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
gamepadIDs = append(gamepadIDs, g.ID)
|
||||
}
|
||||
return gamepadIDs
|
||||
return gamepad.AppendGamepadIDs(gamepadIDs)
|
||||
}
|
||||
|
||||
func (i *Input) GamepadSDLID(id driver.GamepadID) string {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
return g.SDLID
|
||||
g := gamepad.Get(id)
|
||||
if g == nil {
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
return g.SDLID()
|
||||
}
|
||||
|
||||
func (i *Input) GamepadName(id driver.GamepadID) string {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
if name := gamepaddb.Name(g.SDLID); name != "" {
|
||||
return name
|
||||
}
|
||||
return g.Name
|
||||
g := gamepad.Get(id)
|
||||
if g == nil {
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
return g.Name()
|
||||
}
|
||||
|
||||
func (i *Input) GamepadAxisNum(id driver.GamepadID) int {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
return g.AxisNum
|
||||
g := gamepad.Get(id)
|
||||
if g == nil {
|
||||
return 0
|
||||
}
|
||||
return 0
|
||||
return g.AxisCount()
|
||||
}
|
||||
|
||||
func (i *Input) GamepadAxisValue(id driver.GamepadID, axis int) float64 {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
if g.AxisNum <= int(axis) {
|
||||
return 0
|
||||
}
|
||||
return float64(g.Axes[axis])
|
||||
g := gamepad.Get(id)
|
||||
if g == nil {
|
||||
return 0
|
||||
}
|
||||
return 0
|
||||
return g.Axis(axis)
|
||||
}
|
||||
|
||||
func (i *Input) GamepadButtonNum(id driver.GamepadID) int {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
return g.ButtonNum
|
||||
g := gamepad.Get(id)
|
||||
if g == nil {
|
||||
return 0
|
||||
}
|
||||
return 0
|
||||
return g.ButtonCount()
|
||||
}
|
||||
|
||||
func (i *Input) IsGamepadButtonPressed(id driver.GamepadID, button driver.GamepadButton) bool {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
if g.ButtonNum <= int(button) {
|
||||
return false
|
||||
}
|
||||
return g.Buttons[button]
|
||||
g := gamepad.Get(id)
|
||||
if g == nil {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
return g.Button(int(button))
|
||||
}
|
||||
|
||||
func (i *Input) IsStandardGamepadLayoutAvailable(id driver.GamepadID) bool {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
return gamepaddb.HasStandardLayoutMapping(g.SDLID)
|
||||
g := gamepad.Get(id)
|
||||
if g == nil {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
return g.IsStandardLayoutAvailable()
|
||||
}
|
||||
|
||||
func (i *Input) IsStandardGamepadButtonPressed(id driver.GamepadID, button driver.StandardGamepadButton) bool {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
return gamepaddb.IsButtonPressed(g.SDLID, button, gamepadState{&g})
|
||||
g := gamepad.Get(id)
|
||||
if g == nil {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
return g.IsStandardButtonPressed(button)
|
||||
}
|
||||
|
||||
func (i *Input) StandardGamepadButtonValue(id driver.GamepadID, button driver.StandardGamepadButton) float64 {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
return gamepaddb.ButtonValue(g.SDLID, button, gamepadState{&g})
|
||||
g := gamepad.Get(id)
|
||||
if g == nil {
|
||||
return 0
|
||||
}
|
||||
return 0
|
||||
return g.StandardButtonValue(button)
|
||||
}
|
||||
|
||||
func (i *Input) StandardGamepadAxisValue(id driver.GamepadID, axis driver.StandardGamepadAxis) float64 {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
return gamepaddb.AxisValue(g.SDLID, axis, gamepadState{&g})
|
||||
g := gamepad.Get(id)
|
||||
if g == nil {
|
||||
return 0
|
||||
}
|
||||
return 0
|
||||
return g.StandardAxisValue(axis)
|
||||
}
|
||||
|
||||
func (i *Input) VibrateGamepad(id driver.GamepadID, duration time.Duration, strongMagnitude float64, weakMagnitude float64) {
|
||||
// TODO: Implement this (#1452)
|
||||
g := gamepad.Get(id)
|
||||
if g == nil {
|
||||
return
|
||||
}
|
||||
g.Vibrate(duration, strongMagnitude, weakMagnitude)
|
||||
}
|
||||
|
||||
// TODO: Remove this struct after porting the gamepad part of iOS to internal/gamepad.
|
||||
type Gamepad struct{}
|
||||
|
||||
// TODO: Remove this function after porting the gamepad part of iOS to internal/gamepad.
|
||||
func (i *Input) updateGamepads() {
|
||||
}
|
||||
|
@ -1,34 +0,0 @@
|
||||
// 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.
|
||||
|
||||
package mobile
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||
)
|
||||
|
||||
// UpdateGamepads updates the gamepad states.
|
||||
// UpdateGamepads is called when the gamepad states are given from outside like Android.
|
||||
func (u *UserInterface) UpdateGamepads(gamepads []Gamepad) {
|
||||
u.input.updateGamepadsFromOutside(gamepads)
|
||||
}
|
||||
|
||||
func (i *Input) updateGamepadsFromOutside(gamepads []Gamepad) {
|
||||
i.gamepads = i.gamepads[:0]
|
||||
i.gamepads = append(i.gamepads, gamepads...)
|
||||
}
|
||||
|
||||
func (i *Input) updateGamepads() {
|
||||
// Do nothing.
|
||||
}
|
@ -22,11 +22,13 @@ import (
|
||||
)
|
||||
|
||||
type Input struct {
|
||||
keys map[driver.Key]struct{}
|
||||
runes []rune
|
||||
touches []Touch
|
||||
keys map[driver.Key]struct{}
|
||||
runes []rune
|
||||
touches []Touch
|
||||
ui *UserInterface
|
||||
|
||||
// gamepads is used only on iOS.
|
||||
gamepads []Gamepad
|
||||
ui *UserInterface
|
||||
}
|
||||
|
||||
func (i *Input) CursorPosition() (x, y int) {
|
||||
|
206
internal/uidriver/mobile/inputgamepad_ios.go
Normal file
206
internal/uidriver/mobile/inputgamepad_ios.go
Normal file
@ -0,0 +1,206 @@
|
||||
// Copyright 2022 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 ios
|
||||
// +build ios
|
||||
|
||||
package mobile
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/gamepaddb"
|
||||
)
|
||||
|
||||
type Gamepad struct {
|
||||
ID driver.GamepadID
|
||||
SDLID string
|
||||
Name string
|
||||
Buttons [driver.GamepadButtonNum]bool
|
||||
ButtonNum int
|
||||
Axes [32]float32
|
||||
AxisNum int
|
||||
Hats [16]int
|
||||
HatNum int
|
||||
}
|
||||
|
||||
type gamepadState struct {
|
||||
g *Gamepad
|
||||
}
|
||||
|
||||
func (s gamepadState) Axis(index int) float64 {
|
||||
return float64(s.g.Axes[index])
|
||||
}
|
||||
|
||||
func (s gamepadState) Button(index int) bool {
|
||||
return s.g.Buttons[index]
|
||||
}
|
||||
|
||||
func (s gamepadState) Hat(index int) int {
|
||||
return s.g.Hats[index]
|
||||
}
|
||||
|
||||
func (i *Input) AppendGamepadIDs(gamepadIDs []driver.GamepadID) []driver.GamepadID {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
gamepadIDs = append(gamepadIDs, g.ID)
|
||||
}
|
||||
return gamepadIDs
|
||||
}
|
||||
|
||||
func (i *Input) GamepadSDLID(id driver.GamepadID) string {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
return g.SDLID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (i *Input) GamepadName(id driver.GamepadID) string {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
if name := gamepaddb.Name(g.SDLID); name != "" {
|
||||
return name
|
||||
}
|
||||
return g.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (i *Input) GamepadAxisNum(id driver.GamepadID) int {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
return g.AxisNum
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (i *Input) GamepadAxisValue(id driver.GamepadID, axis int) float64 {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
if g.AxisNum <= int(axis) {
|
||||
return 0
|
||||
}
|
||||
return float64(g.Axes[axis])
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (i *Input) GamepadButtonNum(id driver.GamepadID) int {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
return g.ButtonNum
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (i *Input) IsGamepadButtonPressed(id driver.GamepadID, button driver.GamepadButton) bool {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
if g.ButtonNum <= int(button) {
|
||||
return false
|
||||
}
|
||||
return g.Buttons[button]
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (i *Input) IsStandardGamepadLayoutAvailable(id driver.GamepadID) bool {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
return gamepaddb.HasStandardLayoutMapping(g.SDLID)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (i *Input) IsStandardGamepadButtonPressed(id driver.GamepadID, button driver.StandardGamepadButton) bool {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
return gamepaddb.IsButtonPressed(g.SDLID, button, gamepadState{&g})
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (i *Input) StandardGamepadButtonValue(id driver.GamepadID, button driver.StandardGamepadButton) float64 {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
return gamepaddb.ButtonValue(g.SDLID, button, gamepadState{&g})
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (i *Input) StandardGamepadAxisValue(id driver.GamepadID, axis driver.StandardGamepadAxis) float64 {
|
||||
i.ui.m.RLock()
|
||||
defer i.ui.m.RUnlock()
|
||||
|
||||
for _, g := range i.gamepads {
|
||||
if g.ID != id {
|
||||
continue
|
||||
}
|
||||
return gamepaddb.AxisValue(g.SDLID, axis, gamepadState{&g})
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (i *Input) VibrateGamepad(id driver.GamepadID, duration time.Duration, strongMagnitude float64, weakMagnitude float64) {
|
||||
// TODO: Implement this (#1452)
|
||||
}
|
@ -34,6 +34,7 @@ import (
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/devicescale"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/gamepad"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicscommand"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/hooks"
|
||||
@ -83,7 +84,9 @@ func (u *UserInterface) Update() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: Remove this call after porting the gamepad part of iOS to internal/gamepad.
|
||||
u.input.updateGamepads()
|
||||
gamepad.Update()
|
||||
|
||||
renderCh <- struct{}{}
|
||||
go func() {
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
"unicode"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/uidriver/mobile"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/gamepad"
|
||||
)
|
||||
|
||||
// https://developer.android.com/reference/android/view/KeyEvent
|
||||
@ -180,30 +180,6 @@ var androidAxisIDToHatID2 = map[int]int{
|
||||
axisHatY: 1,
|
||||
}
|
||||
|
||||
var (
|
||||
// deviceIDToGamepadID is a map from Android device IDs to Ebiten gamepad IDs.
|
||||
// As convention, Ebiten gamepad IDs start with 0, and many applications depend on this fact.
|
||||
deviceIDToGamepadID = map[int]driver.GamepadID{}
|
||||
)
|
||||
|
||||
func gamepadIDFromDeviceID(deviceID int) driver.GamepadID {
|
||||
if id, ok := deviceIDToGamepadID[deviceID]; ok {
|
||||
return id
|
||||
}
|
||||
ids := map[driver.GamepadID]struct{}{}
|
||||
for _, id := range deviceIDToGamepadID {
|
||||
ids[id] = struct{}{}
|
||||
}
|
||||
for i := driver.GamepadID(0); ; i++ {
|
||||
if _, ok := ids[i]; ok {
|
||||
continue
|
||||
}
|
||||
deviceIDToGamepadID[deviceID] = i
|
||||
return i
|
||||
}
|
||||
panic("ebitenmobileview: a gamepad ID cannot be determined")
|
||||
}
|
||||
|
||||
func UpdateTouchesOnAndroid(action int, id int, x, y int) {
|
||||
switch action {
|
||||
case 0x00, 0x05, 0x02: // ACTION_DOWN, ACTION_POINTER_DOWN, ACTION_MOVE
|
||||
@ -215,27 +191,12 @@ func UpdateTouchesOnAndroid(action int, id int, x, y int) {
|
||||
}
|
||||
}
|
||||
|
||||
func gamepadFromGamepadID(id driver.GamepadID) *mobile.Gamepad {
|
||||
for i, g := range gamepads {
|
||||
if g.ID == id {
|
||||
return &gamepads[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func OnKeyDownOnAndroid(keyCode int, unicodeChar int, source int, deviceID int) {
|
||||
switch {
|
||||
case source&sourceGamepad == sourceGamepad:
|
||||
// A gamepad can be detected as a keyboard. Detect the device as a gamepad first.
|
||||
if button, ok := androidKeyToGamepadButton[keyCode]; ok {
|
||||
id := gamepadIDFromDeviceID(deviceID)
|
||||
g := gamepadFromGamepadID(id)
|
||||
if g == nil {
|
||||
return
|
||||
}
|
||||
g.Buttons[button] = true
|
||||
updateGamepads()
|
||||
gamepad.UpdateAndroidGamepadButton(deviceID, button, true)
|
||||
}
|
||||
case source&sourceJoystick == sourceJoystick:
|
||||
// DPAD keys can come here, but they are also treated as an axis at a motion event. Ignore them.
|
||||
@ -255,13 +216,7 @@ func OnKeyUpOnAndroid(keyCode int, source int, deviceID int) {
|
||||
case source&sourceGamepad == sourceGamepad:
|
||||
// A gamepad can be detected as a keyboard. Detect the device as a gamepad first.
|
||||
if button, ok := androidKeyToGamepadButton[keyCode]; ok {
|
||||
id := gamepadIDFromDeviceID(deviceID)
|
||||
g := gamepadFromGamepadID(id)
|
||||
if g == nil {
|
||||
return
|
||||
}
|
||||
g.Buttons[button] = false
|
||||
updateGamepads()
|
||||
gamepad.UpdateAndroidGamepadButton(deviceID, button, false)
|
||||
}
|
||||
case source&sourceJoystick == sourceJoystick:
|
||||
// DPAD keys can come here, but they are also treated as an axis at a motion event. Ignore them.
|
||||
@ -274,15 +229,8 @@ func OnKeyUpOnAndroid(keyCode int, source int, deviceID int) {
|
||||
}
|
||||
|
||||
func OnGamepadAxesOrHatsChanged(deviceID int, axisID int, value float32) {
|
||||
id := gamepadIDFromDeviceID(deviceID)
|
||||
g := gamepadFromGamepadID(id)
|
||||
if g == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if aid, ok := androidAxisIDToAxisID[axisID]; ok {
|
||||
g.Axes[aid] = value
|
||||
updateGamepads()
|
||||
if axis, ok := androidAxisIDToAxisID[axisID]; ok {
|
||||
gamepad.UpdateAndroidGamepadAxis(deviceID, axis, float64(value))
|
||||
return
|
||||
}
|
||||
|
||||
@ -293,38 +241,20 @@ func OnGamepadAxesOrHatsChanged(deviceID int, axisID int, value float32) {
|
||||
hatDown = 4
|
||||
hatLeft = 8
|
||||
)
|
||||
hid := hid2 / 2
|
||||
v := g.Hats[hid]
|
||||
if hid2%2 == 0 {
|
||||
hatX := int(math.Round(float64(value)))
|
||||
if hatX < 0 {
|
||||
v |= hatLeft
|
||||
v &^= hatRight
|
||||
} else if hatX > 0 {
|
||||
v &^= hatLeft
|
||||
v |= hatRight
|
||||
} else {
|
||||
v &^= (hatLeft | hatRight)
|
||||
}
|
||||
} else {
|
||||
hatY := int(math.Round(float64(value)))
|
||||
if hatY < 0 {
|
||||
v |= hatUp
|
||||
v &^= hatDown
|
||||
} else if hatY > 0 {
|
||||
v &^= hatUp
|
||||
v |= hatDown
|
||||
} else {
|
||||
v &^= (hatUp | hatDown)
|
||||
}
|
||||
hatID := hid2 / 2
|
||||
var dir gamepad.AndroidHatDirection
|
||||
switch hid2 % 2 {
|
||||
case 0:
|
||||
dir = gamepad.AndroidHatDirectionX
|
||||
case 1:
|
||||
dir = gamepad.AndroidHatDirectionY
|
||||
}
|
||||
g.Hats[hid] = v
|
||||
updateGamepads()
|
||||
gamepad.UpdateAndroidGamepadHat(deviceID, hatID, dir, int(math.Round(float64(value))))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func OnGamepadAdded(deviceID int, name string, buttonNum int, axisNum int, hatNum int, descriptor string, vendorID int, productID int, buttonMask int, axisMask int) {
|
||||
func OnGamepadAdded(deviceID int, name string, buttonCount int, axisCount int, hatCount int, descriptor string, vendorID int, productID int, buttonMask int, axisMask int) {
|
||||
// This emulates the implementation of Android_AddJoystick.
|
||||
// https://github.com/libsdl-org/SDL/blob/0e9560aea22818884921e5e5064953257bfe7fa7/src/joystick/android/SDL_sysjoystick.c#L386
|
||||
const SDL_HARDWARE_BUS_BLUETOOTH = 0x05
|
||||
@ -350,39 +280,9 @@ func OnGamepadAdded(deviceID int, name string, buttonNum int, axisNum int, hatNu
|
||||
sdlid[14] = byte(axisMask)
|
||||
sdlid[15] = byte(axisMask >> 8)
|
||||
|
||||
id := gamepadIDFromDeviceID(deviceID)
|
||||
gamepads = append(gamepads, mobile.Gamepad{
|
||||
ID: id,
|
||||
SDLID: hex.EncodeToString(sdlid[:]),
|
||||
Name: name,
|
||||
ButtonNum: buttonNum,
|
||||
AxisNum: axisNum,
|
||||
HatNum: hatNum,
|
||||
})
|
||||
updateGamepads()
|
||||
gamepad.AddAndroidGamepad(deviceID, name, hex.EncodeToString(sdlid[:]), axisCount, buttonCount, hatCount)
|
||||
}
|
||||
|
||||
func OnInputDeviceRemoved(deviceID int) {
|
||||
if id, ok := deviceIDToGamepadID[deviceID]; ok {
|
||||
idx := -1
|
||||
for i, g := range gamepads {
|
||||
if g.ID == id {
|
||||
idx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if idx >= 0 {
|
||||
lastIdx := len(gamepads) - 1
|
||||
gamepads[idx], gamepads[lastIdx] = gamepads[lastIdx], gamepads[idx]
|
||||
gamepads = gamepads[:len(gamepads)-1]
|
||||
}
|
||||
delete(deviceIDToGamepadID, deviceID)
|
||||
}
|
||||
updateGamepads()
|
||||
}
|
||||
|
||||
var gamepads []mobile.Gamepad
|
||||
|
||||
func updateGamepads() {
|
||||
mobile.Get().UpdateGamepads(gamepads)
|
||||
gamepad.RemoveAndroidGamepad(deviceID)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user