A game framework written with osu! in mind.
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2// See the LICENCE file in the repository root for full licence text.
3
4using System;
5using NUnit.Framework;
6using osu.Framework.Graphics;
7using osu.Framework.Graphics.Shapes;
8using osu.Framework.Input.Events;
9using osu.Framework.Testing;
10using osuTK;
11using osuTK.Input;
12
13namespace osu.Framework.Tests.Input
14{
15 [HeadlessTest]
16 public class KeyboardInputTest : ManualInputManagerTestScene
17 {
18 /// <summary>
19 /// Tests that if the hierarchy is changed while a key is held, the <see cref="Drawable.OnKeyUp"/> event is
20 /// only propagated to the hierarchy that originally handled <see cref="Drawable.OnKeyDown"/>.
21 /// </summary>
22 [Test]
23 public void TestKeyUpOnlyPropagatedToOriginalTargets()
24 {
25 var receptors = new InputReceptor[3];
26
27 AddStep("create hierarchy", () =>
28 {
29 Children = new Drawable[]
30 {
31 receptors[0] = new InputReceptor
32 {
33 Size = new Vector2(100),
34 KeyDown = () => true
35 },
36 receptors[1] = new InputReceptor { Size = new Vector2(100) }
37 };
38 });
39
40 AddStep("press key", () => InputManager.PressKey(Key.A));
41 AddStep("add receptor above", () =>
42 {
43 Add(receptors[2] = new InputReceptor
44 {
45 Size = new Vector2(100),
46 KeyDown = () => true,
47 KeyUp = () => true
48 });
49 });
50
51 AddStep("release key", () => InputManager.ReleaseKey(Key.A));
52
53 AddAssert("receptor 0 handled key down", () => receptors[0].DownReceived);
54 AddAssert("receptor 0 handled key up", () => receptors[0].UpReceived);
55 AddAssert("receptor 1 handled key down", () => receptors[1].DownReceived);
56 AddAssert("receptor 1 handled key up", () => receptors[1].UpReceived);
57 AddAssert("receptor 2 did not handle key down", () => !receptors[2].DownReceived);
58 AddAssert("receptor 2 did not handle key up", () => !receptors[2].UpReceived);
59 }
60
61 /// <summary>
62 /// Tests that a drawable that is removed from the hierarchy (or is otherwise removed from the input queues) won't receive OnKeyDown() events for every subsequent repeat.
63 /// </summary>
64 [Test]
65 public void TestNoLongerValidDrawableDoesNotReceiveRepeat()
66 {
67 var receptors = new InputReceptor[2];
68
69 AddStep("create hierarchy", () =>
70 {
71 Children = new Drawable[]
72 {
73 receptors[0] = new InputReceptor { Size = new Vector2(100) },
74 receptors[1] = new InputReceptor { Size = new Vector2(100) }
75 };
76 });
77
78 AddStep("press key", () => InputManager.PressKey(Key.A));
79 AddUntilStep("wait for repeat on receptor 0", () => receptors[0].RepeatReceived);
80
81 AddStep("remove receptor 0 & reset repeat", () =>
82 {
83 Remove(receptors[0]);
84 receptors[0].RepeatReceived = false;
85 receptors[1].RepeatReceived = false;
86 });
87
88 AddUntilStep("wait for repeat on receptor 1", () => receptors[1].RepeatReceived);
89 AddAssert("receptor 0 did not receive repeat", () => !receptors[0].RepeatReceived);
90 }
91
92 /// <summary>
93 /// Tests that a drawable that was previously removed from the hierarchy receives repeat OnKeyDown() events when re-added to the hierarchy,
94 /// if it previously received a non-repeat OnKeyDown() event.
95 /// </summary>
96 [Test]
97 public void TestReValidatedDrawableReceivesRepeat()
98 {
99 var receptors = new InputReceptor[2];
100
101 AddStep("create hierarchy", () =>
102 {
103 Children = new Drawable[]
104 {
105 receptors[0] = new InputReceptor { Size = new Vector2(100) },
106 receptors[1] = new InputReceptor { Size = new Vector2(100) }
107 };
108 });
109
110 AddStep("press key", () => InputManager.PressKey(Key.A));
111 AddStep("remove receptor 0 & reset repeat", () =>
112 {
113 Remove(receptors[0]);
114 receptors[0].RepeatReceived = false;
115 receptors[1].RepeatReceived = false;
116 });
117
118 AddUntilStep("wait for repeat on receptor 1", () => receptors[1].RepeatReceived);
119 AddStep("add back receptor 0", () => Add(receptors[0]));
120
121 AddUntilStep("wait for repeat on receptor 0", () => receptors[0].RepeatReceived);
122 }
123
124 private class InputReceptor : Box
125 {
126 public bool DownReceived { get; set; }
127 public bool UpReceived { get; set; }
128 public bool RepeatReceived { get; set; }
129
130 public Func<bool> KeyDown;
131 public Func<bool> KeyUp;
132
133 protected override bool OnKeyDown(KeyDownEvent e)
134 {
135 if (e.Repeat)
136 {
137 RepeatReceived = true;
138 return false;
139 }
140
141 DownReceived = true;
142 return KeyDown?.Invoke() ?? false;
143 }
144
145 protected override void OnKeyUp(KeyUpEvent e)
146 {
147 UpReceived = true;
148 KeyUp?.Invoke();
149 }
150 }
151 }
152}