Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions pipad/pipad.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,10 @@
package pipad

import (
"github.com/elgopher/pi/internal/input"
"log"

"github.com/elgopher/pi/internal/input"

"github.com/elgopher/pi"
"github.com/elgopher/pi/pievent"
)
Expand All @@ -82,9 +83,17 @@ const (
Y Button = "Y"
)

// Duration returns button press duration for any controller
// Duration returns button press duration for any controller.
// If multiple controllers are pressed simultaneously, it returns
// the longest duration among them.
func Duration(b Button) int {
return buttonAnyState.Duration(b)
duration := 0

for _, state := range buttonState {
duration = max(duration, state.Duration(b))
}

return duration
}

// PlayerCount returns the number of connected controllers
Expand All @@ -102,7 +111,6 @@ func PlayerDuration(b Button, player int) int {
}

var buttonState = map[int]*input.State[Button]{}
var buttonAnyState input.State[Button]

func init() {
ButtonTarget().SubscribeAll(onButton)
Expand All @@ -117,10 +125,8 @@ func onButton(event EventButton, _ pievent.Handler) {
switch event.Type {
case EventDown:
buttonState[event.Player].SetDownFrame(event.Button, pi.Frame)
buttonAnyState.SetDownFrame(event.Button, pi.Frame)
case EventUp:
buttonState[event.Player].SetUpFrame(event.Button, pi.Frame)
buttonAnyState.SetUpFrame(event.Button, pi.Frame)
}
}

Expand Down
81 changes: 81 additions & 0 deletions pipad/pipad_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright 2025 Jacek Olszak
// This code is licensed under MIT license (see LICENSE for details)

package pipad_test

import (
"testing"

"github.com/elgopher/pi"
"github.com/elgopher/pi/pipad"
"github.com/stretchr/testify/assert"
)

var (
player0connected = pipad.EventConnection{Type: pipad.EventConnect, Player: 0}
player1connected = pipad.EventConnection{Type: pipad.EventConnect, Player: 1}
player0disconnected = pipad.EventConnection{Type: pipad.EventDisconnect, Player: 0}
player1disconnected = pipad.EventConnection{Type: pipad.EventDisconnect, Player: 1}
)

func TestPlayerCount(t *testing.T) {
assert.Equal(t, 0, pipad.PlayerCount())
pipad.ConnectionTarget().Publish(player0connected)
pipad.ConnectionTarget().Publish(player1connected)
assert.Equal(t, 2, pipad.PlayerCount())
pipad.ConnectionTarget().Publish(player0disconnected)
assert.Equal(t, 1, pipad.PlayerCount())
pipad.ConnectionTarget().Publish(player1disconnected)
}

func TestDuration(t *testing.T) {
{
pipad.ConnectionTarget().Publish(player0connected)
pipad.ButtonTarget().Publish(
pipad.EventButton{Type: pipad.EventDown, Button: pipad.A, Player: 0},
)

t.Run("should return duration when button was pressed", func(t *testing.T) {
duration := pipad.Duration(pipad.A)
assert.Equal(t, 1, duration)

playerDuration := pipad.PlayerDuration(pipad.A, 0)
assert.Equal(t, 1, playerDuration)
})

pi.Frame++

t.Run("should take into account how many frames passed", func(t *testing.T) {
assert.Equal(t, 2, pipad.Duration(pipad.A))
assert.Equal(t, 2, pipad.PlayerDuration(pipad.A, 0))
})

pipad.ConnectionTarget().Publish(player0disconnected)
}

t.Run("should return 0 after controller was disconnected", func(t *testing.T) {
assert.Equal(t, 0, pipad.Duration(pipad.A))
assert.Equal(t, 0, pipad.PlayerDuration(pipad.A, 0))
})

t.Run("should return the longest duration when two controllers are pressed simultaneously", func(t *testing.T) {
pipad.ConnectionTarget().Publish(player0connected)
defer pipad.ConnectionTarget().Publish(player0disconnected)
pipad.ConnectionTarget().Publish(player1connected)
defer pipad.ConnectionTarget().Publish(player1disconnected)

pipad.ButtonTarget().Publish(
pipad.EventButton{Type: pipad.EventDown, Button: pipad.A, Player: 0},
)
pi.Frame++
pipad.ButtonTarget().Publish(
pipad.EventButton{Type: pipad.EventUp, Button: pipad.A, Player: 1},
)
assert.Equal(t, 2, pipad.Duration(pipad.A))
assert.Equal(t, 2, pipad.PlayerDuration(pipad.A, 0))
})

t.Run("should return 0 when player was never connected", func(t *testing.T) {
assert.Equal(t, 0, pipad.PlayerDuration(pipad.A, 2))
})
}