Support analog inputs (#416)

This commit is contained in:
Jean-André Santoni authored and GitHub committed 2021-05-14 18:34:17 +07:00
1 parent 3f9e9e5a36
commit d201e5321d
6 files changed
+99 -59

No files matched your search

+67 -27
View File
@@ -26,8 +26,11 @@ type bind struct {
threshold float32
}
// States is the state of inputs for all players
type States [MaxPlayers][ActionLast]bool
// States can store the state of inputs for all players
type States [MaxPlayers][ActionLast]int16
// AnalogStates can store the state of analog inputs for all players
type AnalogStates [MaxPlayers][2]int16
// Input state for all the players
var (
@@ -35,6 +38,8 @@ var (
OldState States // input state for the previous frame
Released States // keys just released during this frame
Pressed States // keys just pressed during this frame
NewAnalogState AnalogStates // analog input state for the current frame
)
// Hot keys
@@ -75,8 +80,12 @@ func Init(v *video.Video) {
glfw.SetJoystickCallback(joystickCallback)
}
func floatToAnalog(v float32) int16 {
return int16(v * 32767.0)
}
// pollJoypads process joypads of all players
func pollJoypads(state States) States {
func pollJoypads(state States, analogState AnalogStates) (States, AnalogStates) {
for p := range state {
buttonState := glfw.Joystick.GetButtons(glfw.Joystick(p))
axisState := glfw.Joystick.GetAxes(glfw.Joystick(p))
@@ -88,41 +97,47 @@ func pollJoypads(state States) States {
case btn:
if int(k.index) < len(buttonState) &&
glfw.Action(buttonState[k.index]) == glfw.Press {
state[p][v] = true
state[p][v] = 1
}
case axis:
if int(k.index) < len(axisState) &&
k.direction*axisState[k.index] > k.threshold*k.direction {
state[p][v] = true
state[p][v] = 1
}
}
if !settings.Current.MapAxisToDPad {
continue
}
switch {
case axisState[0] < -0.5:
state[p][libretro.DeviceIDJoypadLeft] = true
case axisState[0] > 0.5:
state[p][libretro.DeviceIDJoypadRight] = true
}
switch {
case axisState[1] > 0.5:
state[p][libretro.DeviceIDJoypadDown] = true
case axisState[1] < -0.5:
state[p][libretro.DeviceIDJoypadUp] = true
if settings.Current.MapAxisToDPad {
if axisState[0] < -0.5 {
state[p][libretro.DeviceIDJoypadLeft] = 1
} else if axisState[0] > 0.5 {
state[p][libretro.DeviceIDJoypadRight] = 1
}
if axisState[1] > 0.5 {
state[p][libretro.DeviceIDJoypadDown] = 1
} else if axisState[1] < -0.5 {
state[p][libretro.DeviceIDJoypadUp] = 1
}
}
}
}
}
return state
for p := range analogState {
axisState := glfw.Joystick.GetAxes(glfw.Joystick(p))
if len(axisState) >= 1 {
analogState[p][0] = floatToAnalog(axisState[0])
analogState[p][1] = floatToAnalog(axisState[1])
}
}
return state, analogState
}
// pollKeyboard processes keyboard keys
func pollKeyboard(state States) States {
for k, v := range keyBinds {
if vid.Window.GetKey(k) == glfw.Press {
state[0][v] = true
state[0][v] = 1
}
}
return state
@@ -132,8 +147,16 @@ func pollKeyboard(state States) States {
func getPressedReleased(new States, old States) (States, States) {
for p := range new {
for k := range new[p] {
Pressed[p][k] = new[p][k] && !old[p][k]
Released[p][k] = !new[p][k] && old[p][k]
if new[p][k] == 1 && old[p][k] == 0 {
Pressed[p][k] = 1
} else {
Pressed[p][k] = 0
}
if new[p][k] == 0 && old[p][k] == 1 {
Released[p][k] = 1
} else {
Released[p][k] = 0
}
}
}
return Pressed, Released
@@ -142,7 +165,7 @@ func getPressedReleased(new States, old States) (States, States) {
// Poll calculates the input state. It is meant to be called for each frame.
func Poll() {
NewState = States{}
NewState = pollJoypads(NewState)
NewState, NewAnalogState = pollJoypads(NewState, NewAnalogState)
NewState = pollKeyboard(NewState)
Pressed, Released = getPressedReleased(NewState, OldState)
@@ -153,13 +176,30 @@ func Poll() {
// State is a callback passed to core.SetInputState
// It returns 1 if the button corresponding to the parameters is pressed
func State(port uint, device uint32, index uint, id uint) int16 {
if id >= 255 || index > 0 || port >= MaxPlayers || device&libretro.DeviceJoypad != 1 || id > uint(libretro.DeviceIDJoypadR3) {
if port >= MaxPlayers {
return 0
}
if NewState[port][id] {
return 1
if device == libretro.DeviceJoypad {
if id >= uint(ActionLast) || index > 0 {
return 0
}
return NewState[port][id]
}
if device == libretro.DeviceAnalog {
if id > uint(libretro.DeviceIDAnalogY) {
// invalid
return 0
}
switch uint32(index) {
case libretro.DeviceIndexAnalogLeft:
return NewAnalogState[port][id]
case libretro.DeviceIndexAnalogRight:
return NewAnalogState[port][id]
}
}
return 0
}
+4 -4
View File
@@ -7,14 +7,14 @@ import (
func Test_getPressedReleased(t *testing.T) {
t.Run("works", func(t *testing.T) {
var old = States{
{false, true, false, false},
{0, 1, 0, 0},
}
var new = States{
{false, false, false, true},
{0, 0, 0, 1},
}
pressed, released := getPressedReleased(new, old)
wantpressed := States{{false, false, false, true}}
wantreleased := States{{false, true, false, false}}
wantpressed := States{{0, 0, 0, 1}}
wantreleased := States{{0, 1, 0, 0}}
if pressed != wantpressed {
t.Errorf("got = %v, want %v", pressed, wantpressed)
}
+14 -14
View File
@@ -66,7 +66,7 @@ func withRepeat() func(dt float32, pressed bool, f func()) {
// vertically in entry lists, and also respond to presses on OK and Cancel.
func genericInput(list *entry, dt float32) {
// Down
repeatDown(dt, input.NewState[0][libretro.DeviceIDJoypadDown], func() {
repeatDown(dt, input.NewState[0][libretro.DeviceIDJoypadDown] == 1, func() {
list.ptr++
if list.ptr >= len(list.children) {
list.ptr = 0
@@ -76,7 +76,7 @@ func genericInput(list *entry, dt float32) {
})
// Up
repeatUp(dt, input.NewState[0][libretro.DeviceIDJoypadUp], func() {
repeatUp(dt, input.NewState[0][libretro.DeviceIDJoypadUp] == 1, func() {
list.ptr--
if list.ptr < 0 {
list.ptr = len(list.children) - 1
@@ -86,7 +86,7 @@ func genericInput(list *entry, dt float32) {
})
// OK
if input.Released[0][libretro.DeviceIDJoypadA] {
if input.Released[0][libretro.DeviceIDJoypadA] == 1 {
if list.children[list.ptr].callbackOK != nil {
audio.PlayEffect(audio.Effects["ok"])
list.children[list.ptr].callbackOK()
@@ -94,7 +94,7 @@ func genericInput(list *entry, dt float32) {
}
// Right
if input.Released[0][libretro.DeviceIDJoypadRight] {
if input.Released[0][libretro.DeviceIDJoypadRight] == 1 {
if list.children[list.ptr].incr != nil {
audio.PlayEffect(audio.Effects["up"])
list.children[list.ptr].incr(1)
@@ -102,7 +102,7 @@ func genericInput(list *entry, dt float32) {
}
// Left
if input.Released[0][libretro.DeviceIDJoypadLeft] {
if input.Released[0][libretro.DeviceIDJoypadLeft] == 1 {
if list.children[list.ptr].incr != nil {
audio.PlayEffect(audio.Effects["down"])
list.children[list.ptr].incr(-1)
@@ -110,7 +110,7 @@ func genericInput(list *entry, dt float32) {
}
// Cancel
if input.Released[0][libretro.DeviceIDJoypadB] {
if input.Released[0][libretro.DeviceIDJoypadB] == 1 {
if len(menu.stack) > 1 {
audio.PlayEffect(audio.Effects["cancel"])
menu.stack[len(menu.stack)-2].segueBack()
@@ -119,14 +119,14 @@ func genericInput(list *entry, dt float32) {
}
// Jump to next letter
if input.Released[0][libretro.DeviceIDJoypadR] && len(list.indexes) > 0 {
if input.Released[0][libretro.DeviceIDJoypadR] == 1 && len(list.indexes) > 0 {
list.ptr = indexed(list, +1)
audio.PlayEffect(audio.Effects["down"])
genericAnimate(list)
}
// Jump to previous letter
if input.Released[0][libretro.DeviceIDJoypadL] && len(list.indexes) > 0 {
if input.Released[0][libretro.DeviceIDJoypadL] == 1 && len(list.indexes) > 0 {
list.ptr = indexed(list, -1)
audio.PlayEffect(audio.Effects["up"])
genericAnimate(list)
@@ -159,10 +159,10 @@ func (m *Menu) ProcessHotkeys() {
}
// Toggle the menu if ActionMenuToggle or the combo L3+R3 is pressed
combo := input.NewState[0][libretro.DeviceIDJoypadL3] && input.Pressed[0][libretro.DeviceIDJoypadR3]
combo = combo || input.Pressed[0][libretro.DeviceIDJoypadL3] && input.NewState[0][libretro.DeviceIDJoypadR3]
combo := input.NewState[0][libretro.DeviceIDJoypadL3] == 1 && input.Pressed[0][libretro.DeviceIDJoypadR3] == 1
combo = combo || input.Pressed[0][libretro.DeviceIDJoypadL3] == 1 && input.NewState[0][libretro.DeviceIDJoypadR3] == 1
if (input.Pressed[0][input.ActionMenuToggle] || combo) && state.Global.CoreRunning {
if (input.Pressed[0][input.ActionMenuToggle] == 1 || combo) && state.Global.CoreRunning {
state.Global.MenuActive = !state.Global.MenuActive
state.Global.FastForward = false
if state.Global.MenuActive {
@@ -173,7 +173,7 @@ func (m *Menu) ProcessHotkeys() {
}
// Toggle fullscreen if ActionFullscreenToggle is pressed
if input.Pressed[0][input.ActionFullscreenToggle] {
if input.Pressed[0][input.ActionFullscreenToggle] == 1 {
settings.Current.VideoFullscreen = !settings.Current.VideoFullscreen
vid.Reconfigure(settings.Current.VideoFullscreen)
m.ContextReset()
@@ -183,7 +183,7 @@ func (m *Menu) ProcessHotkeys() {
}
}
if input.Pressed[0][input.ActionFastForwardToggle] && !state.Global.MenuActive {
if input.Pressed[0][input.ActionFastForwardToggle] == 1 && !state.Global.MenuActive {
state.Global.FastForward = !state.Global.FastForward
if state.Global.FastForward {
ntf.DisplayAndLog(ntf.Info, "Menu", "Fast forward ON")
@@ -194,7 +194,7 @@ func (m *Menu) ProcessHotkeys() {
// Close if ActionShouldClose is pressed, but display a confirmation dialog
// in case a game is running
if input.Pressed[0][input.ActionShouldClose] {
if input.Pressed[0][input.ActionShouldClose] == 1 {
askConfirmation(func() {
vid.Window.SetShouldClose(true)
})
+2 -2
View File
@@ -33,13 +33,13 @@ func (s *sceneDialog) segueBack() {
func (s *sceneDialog) update(dt float32) {
// OK
if input.Released[0][libretro.DeviceIDJoypadA] {
if input.Released[0][libretro.DeviceIDJoypadA] == 1 {
audio.PlayEffect(audio.Effects["ok"])
s.callbackOK()
}
// Cancel
if input.Released[0][libretro.DeviceIDJoypadB] {
if input.Released[0][libretro.DeviceIDJoypadB] == 1 {
audio.PlayEffect(audio.Effects["cancel"])
menu.stack[len(menu.stack)-2].segueBack()
menu.stack = menu.stack[:len(menu.stack)-1]
+9 -9
View File
@@ -70,7 +70,7 @@ func (s *sceneKeyboard) segueBack() {
func (s *sceneKeyboard) update(dt float32) {
// Right
repeatRight(dt, input.NewState[0][libretro.DeviceIDJoypadRight], func() {
repeatRight(dt, input.NewState[0][libretro.DeviceIDJoypadRight] == 1, func() {
audio.PlayEffect(audio.Effects["up"])
if (s.index+1)%10 == 0 {
s.index -= 9
@@ -80,7 +80,7 @@ func (s *sceneKeyboard) update(dt float32) {
})
// Left
repeatLeft(dt, input.NewState[0][libretro.DeviceIDJoypadLeft], func() {
repeatLeft(dt, input.NewState[0][libretro.DeviceIDJoypadLeft] == 1, func() {
audio.PlayEffect(audio.Effects["down"])
if s.index%10 == 0 {
s.index += 9
@@ -90,7 +90,7 @@ func (s *sceneKeyboard) update(dt float32) {
})
// Up
repeatUp(dt, input.NewState[0][libretro.DeviceIDJoypadUp], func() {
repeatUp(dt, input.NewState[0][libretro.DeviceIDJoypadUp] == 1, func() {
audio.PlayEffect(audio.Effects["up"])
if s.index < 10 {
s.index += len(layouts[s.layout]) - 10
@@ -100,7 +100,7 @@ func (s *sceneKeyboard) update(dt float32) {
})
// Down
repeatDown(dt, input.NewState[0][libretro.DeviceIDJoypadDown], func() {
repeatDown(dt, input.NewState[0][libretro.DeviceIDJoypadDown] == 1, func() {
audio.PlayEffect(audio.Effects["down"])
if s.index >= len(layouts[s.layout])-10 {
s.index -= len(layouts[s.layout]) - 10
@@ -110,13 +110,13 @@ func (s *sceneKeyboard) update(dt float32) {
})
// OK
if input.Released[0][libretro.DeviceIDJoypadA] {
if input.Released[0][libretro.DeviceIDJoypadA] == 1 {
audio.PlayEffect(audio.Effects["ok"])
s.value += layouts[s.layout][s.index]
}
// Switch layout
if input.Released[0][libretro.DeviceIDJoypadX] {
if input.Released[0][libretro.DeviceIDJoypadX] == 1 {
audio.PlayEffect(audio.Effects["ok"])
s.layout++
if s.layout >= len(layouts) {
@@ -125,7 +125,7 @@ func (s *sceneKeyboard) update(dt float32) {
}
// Delete character
repeatY(dt, input.NewState[0][libretro.DeviceIDJoypadY], func() {
repeatY(dt, input.NewState[0][libretro.DeviceIDJoypadY] == 1, func() {
if len(s.value) > 0 {
audio.PlayEffect(audio.Effects["cancel"])
s.value = s.value[:len(s.value)-1]
@@ -133,14 +133,14 @@ func (s *sceneKeyboard) update(dt float32) {
})
// Cancel
if input.Released[0][libretro.DeviceIDJoypadB] && len(menu.stack) > 1 {
if input.Released[0][libretro.DeviceIDJoypadB] == 1 && len(menu.stack) > 1 {
audio.PlayEffect(audio.Effects["cancel"])
menu.stack[len(menu.stack)-2].segueBack()
menu.stack = menu.stack[:len(menu.stack)-1]
}
// Done
if input.Released[0][libretro.DeviceIDJoypadStart] && s.value != "" {
if input.Released[0][libretro.DeviceIDJoypadStart] == 1 && s.value != "" {
audio.PlayEffect(audio.Effects["notice"])
s.callbackDone(s.value)
menu.stack[len(menu.stack)-2].segueBack()
+3 -3
View File
@@ -227,7 +227,7 @@ func (tabs *sceneTabs) segueNext() {
func (tabs *sceneTabs) update(dt float32) {
// Right
repeatRight(dt, input.NewState[0][libretro.DeviceIDJoypadRight], func() {
repeatRight(dt, input.NewState[0][libretro.DeviceIDJoypadRight] == 1, func() {
tabs.ptr++
if tabs.ptr >= len(tabs.children) {
tabs.ptr = 0
@@ -237,7 +237,7 @@ func (tabs *sceneTabs) update(dt float32) {
})
// Left
repeatLeft(dt, input.NewState[0][libretro.DeviceIDJoypadLeft], func() {
repeatLeft(dt, input.NewState[0][libretro.DeviceIDJoypadLeft] == 1, func() {
tabs.ptr--
if tabs.ptr < 0 {
tabs.ptr = len(tabs.children) - 1
@@ -247,7 +247,7 @@ func (tabs *sceneTabs) update(dt float32) {
})
// OK
if input.Released[0][libretro.DeviceIDJoypadA] {
if input.Released[0][libretro.DeviceIDJoypadA] == 1 {
if tabs.children[tabs.ptr].callbackOK != nil {
audio.PlayEffect(audio.Effects["ok"])
tabs.segueNext()