Skip to content

Commit 907f26b

Browse files
committed
feat: Input UserAction now provides API for double key/button presses
1 parent ffb97c6 commit 907f26b

File tree

3 files changed

+85
-1
lines changed

3 files changed

+85
-1
lines changed

fxgl-core/src/main/kotlin/com/almasb/fxgl/input/Input.kt

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,27 @@ class Input {
120120
*/
121121
private val currentActions = FXCollections.observableArrayList<UserAction>()
122122

123+
/**
124+
* K - user action.
125+
* V - time in seconds when last triggered.
126+
*/
127+
private val actionTimes = hashMapOf<UserAction, Double>()
128+
123129
private val activeTriggers = arrayListOf<Trigger>()
124130
private val listeners = arrayListOf<TriggerListener>()
125131

126132
private val inputQueue = ArrayDeque<KeyCode>()
127133

134+
/**
135+
* Time accumulated by this input in seconds.
136+
*/
137+
private var time = 0.0
138+
139+
/**
140+
* Time in seconds within which a double press can occur.
141+
*/
142+
var doublePressTimeThreshold = 0.25
143+
128144
/**
129145
* If action events should be processed.
130146
*/
@@ -259,6 +275,8 @@ class Input {
259275
}
260276

261277
fun update(tpf: Double) {
278+
time += tpf
279+
262280
if (isCapturing) {
263281
currentCapture!!.update(tpf)
264282
}
@@ -353,8 +371,19 @@ class Input {
353371
.forEach { (act, _) ->
354372
currentActions.add(act)
355373

356-
if (processInput)
374+
if (processInput) {
357375
act.begin()
376+
377+
val lastTime = actionTimes[act] ?: -Int.MAX_VALUE.toDouble()
378+
379+
actionTimes[act] = time
380+
381+
if (time - lastTime <= doublePressTimeThreshold) {
382+
// this resets action time, so that 3rd action will not trigger double action
383+
actionTimes.remove(act)
384+
act.beginDoubleAction()
385+
}
386+
}
358387
}
359388

360389
if (event.eventType == KeyEvent.KEY_PRESSED) {
@@ -444,7 +473,10 @@ class Input {
444473
currentActions.forEach { it.end() }
445474
}
446475

476+
time = 0.0
477+
447478
currentActions.clear()
479+
actionTimes.clear()
448480
activeTriggers.clear()
449481

450482
stopCapture()

fxgl-core/src/main/kotlin/com/almasb/fxgl/input/UserAction.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ abstract class UserAction(
3737
internal fun begin() = onActionBegin()
3838
internal fun action() = onAction()
3939
internal fun end() = onActionEnd()
40+
internal fun beginDoubleAction() = onDoubleActionBegin()
4041

4142
/**
4243
* Called once in the same tick when triggered.
@@ -53,4 +54,10 @@ abstract class UserAction(
5354
* Called once in the same tick when trigger was released.
5455
*/
5556
protected open fun onActionEnd() {}
57+
58+
/**
59+
* Called once in the same tick when triggered for the second time
60+
* within a specified period of time.
61+
*/
62+
protected open fun onDoubleActionBegin() {}
5663
}

fxgl-core/src/test/kotlin/com/almasb/fxgl/input/InputTest.kt

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,51 @@ class InputTest {
10121012
assertThat(capture1, `is`(not(capture3)))
10131013
}
10141014

1015+
@Test
1016+
fun `Double press action`() {
1017+
var calls = 0
1018+
1019+
val action = object : UserAction("Action1") {
1020+
override fun onDoubleActionBegin() {
1021+
calls++
1022+
}
1023+
}
1024+
1025+
input.addAction(action, KeyCode.A)
1026+
1027+
input.mockKeyPress(KeyCode.A)
1028+
input.mockKeyRelease(KeyCode.A)
1029+
assertThat(calls, `is`(0))
1030+
1031+
// within threshold, so 2nd press triggers it
1032+
input.mockKeyPress(KeyCode.A)
1033+
input.mockKeyRelease(KeyCode.A)
1034+
assertThat(calls, `is`(1))
1035+
1036+
// 3rd press should not trigger since action should be reset
1037+
input.mockKeyPress(KeyCode.A)
1038+
input.mockKeyRelease(KeyCode.A)
1039+
assertThat(calls, `is`(1))
1040+
1041+
// 4th press should trigger as normal
1042+
input.mockKeyPress(KeyCode.A)
1043+
input.mockKeyRelease(KeyCode.A)
1044+
assertThat(calls, `is`(2))
1045+
1046+
input.doublePressTimeThreshold = 0.1
1047+
1048+
input.mockKeyPress(KeyCode.A)
1049+
input.mockKeyRelease(KeyCode.A)
1050+
assertThat(calls, `is`(2))
1051+
1052+
input.update(0.2)
1053+
1054+
// does not trigger it since more time has passed than threshold
1055+
input.mockKeyPress(KeyCode.A)
1056+
input.mockKeyRelease(KeyCode.A)
1057+
assertThat(calls, `is`(2))
1058+
}
1059+
10151060
// @Test
10161061
// fun `Serialization`() {
10171062
// val action = object : UserAction("Action") {}

0 commit comments

Comments
 (0)