Skip to content

Commit 3747797

Browse files
committed
fix: Duration() returns nonzero value after controller was disconnected
pipad.Duration() should return 0 for all buttons when controller was disconnected.
1 parent 3e7c6c1 commit 3747797

File tree

2 files changed

+89
-6
lines changed

2 files changed

+89
-6
lines changed

pipad/pipad.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,10 @@
5757
package pipad
5858

5959
import (
60-
"github.com/elgopher/pi/internal/input"
6160
"log"
6261

62+
"github.com/elgopher/pi/internal/input"
63+
6364
"github.com/elgopher/pi"
6465
"github.com/elgopher/pi/pievent"
6566
)
@@ -82,9 +83,17 @@ const (
8283
Y Button = "Y"
8384
)
8485

85-
// Duration returns button press duration for any controller
86+
// Duration returns button press duration for any controller.
87+
// If multiple controllers are pressed simultaneously, it returns
88+
// the longest duration among them.
8689
func Duration(b Button) int {
87-
return buttonAnyState.Duration(b)
90+
duration := 0
91+
92+
for _, state := range buttonState {
93+
duration = max(duration, state.Duration(b))
94+
}
95+
96+
return duration
8897
}
8998

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

104113
var buttonState = map[int]*input.State[Button]{}
105-
var buttonAnyState input.State[Button]
106114

107115
func init() {
108116
ButtonTarget().SubscribeAll(onButton)
@@ -117,10 +125,8 @@ func onButton(event EventButton, _ pievent.Handler) {
117125
switch event.Type {
118126
case EventDown:
119127
buttonState[event.Player].SetDownFrame(event.Button, pi.Frame)
120-
buttonAnyState.SetDownFrame(event.Button, pi.Frame)
121128
case EventUp:
122129
buttonState[event.Player].SetUpFrame(event.Button, pi.Frame)
123-
buttonAnyState.SetUpFrame(event.Button, pi.Frame)
124130
}
125131
}
126132

pipad/pipad_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright 2025 Jacek Olszak
2+
// This code is licensed under MIT license (see LICENSE for details)
3+
4+
package pipad_test
5+
6+
import (
7+
"testing"
8+
9+
"github.com/elgopher/pi"
10+
"github.com/elgopher/pi/pipad"
11+
"github.com/stretchr/testify/assert"
12+
)
13+
14+
var (
15+
player0connected = pipad.EventConnection{Type: pipad.EventConnect, Player: 0}
16+
player1connected = pipad.EventConnection{Type: pipad.EventConnect, Player: 1}
17+
player0disconnected = pipad.EventConnection{Type: pipad.EventDisconnect, Player: 0}
18+
player1disconnected = pipad.EventConnection{Type: pipad.EventDisconnect, Player: 1}
19+
)
20+
21+
func TestPlayerCount(t *testing.T) {
22+
assert.Equal(t, 0, pipad.PlayerCount())
23+
pipad.ConnectionTarget().Publish(player0connected)
24+
pipad.ConnectionTarget().Publish(player1connected)
25+
assert.Equal(t, 2, pipad.PlayerCount())
26+
pipad.ConnectionTarget().Publish(player0disconnected)
27+
assert.Equal(t, 1, pipad.PlayerCount())
28+
pipad.ConnectionTarget().Publish(player1disconnected)
29+
}
30+
31+
func TestDuration(t *testing.T) {
32+
{
33+
pipad.ConnectionTarget().Publish(player0connected)
34+
pipad.ButtonTarget().Publish(
35+
pipad.EventButton{Type: pipad.EventDown, Button: pipad.A, Player: 0},
36+
)
37+
38+
t.Run("should return duration when button was pressed", func(t *testing.T) {
39+
duration := pipad.Duration(pipad.A)
40+
assert.Equal(t, 1, duration)
41+
42+
playerDuration := pipad.PlayerDuration(pipad.A, 0)
43+
assert.Equal(t, 1, playerDuration)
44+
})
45+
46+
pi.Frame++
47+
48+
t.Run("should take into account how many frames passed", func(t *testing.T) {
49+
assert.Equal(t, 2, pipad.Duration(pipad.A))
50+
assert.Equal(t, 2, pipad.PlayerDuration(pipad.A, 0))
51+
})
52+
53+
pipad.ConnectionTarget().Publish(player0disconnected)
54+
}
55+
56+
t.Run("should return 0 after controller was disconnected", func(t *testing.T) {
57+
assert.Equal(t, 0, pipad.Duration(pipad.A))
58+
assert.Equal(t, 0, pipad.PlayerDuration(pipad.A, 0))
59+
})
60+
61+
t.Run("should return the longest duration when two controllers are pressed simultaneously", func(t *testing.T) {
62+
pipad.ConnectionTarget().Publish(player0connected)
63+
defer pipad.ConnectionTarget().Publish(player0disconnected)
64+
pipad.ConnectionTarget().Publish(player1connected)
65+
defer pipad.ConnectionTarget().Publish(player1disconnected)
66+
67+
pipad.ButtonTarget().Publish(
68+
pipad.EventButton{Type: pipad.EventDown, Button: pipad.A, Player: 0},
69+
)
70+
pi.Frame++
71+
pipad.ButtonTarget().Publish(
72+
pipad.EventButton{Type: pipad.EventUp, Button: pipad.A, Player: 1},
73+
)
74+
assert.Equal(t, 2, pipad.Duration(pipad.A))
75+
assert.Equal(t, 2, pipad.PlayerDuration(pipad.A, 0))
76+
})
77+
}

0 commit comments

Comments
 (0)