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 System.Collections.Generic;
6using NUnit.Framework;
7using osu.Framework.Graphics;
8using osu.Framework.Graphics.UserInterface;
9using osu.Framework.Input.Bindings;
10using osu.Framework.Testing;
11using osuTK;
12using osuTK.Input;
13
14namespace osu.Framework.Tests.Visual.Input
15{
16 [HeadlessTest]
17 public class TestSceneKeyBindingContainer : ManualInputManagerTestScene
18 {
19 [Test]
20 public void TestTriggerWithNoKeyBindings()
21 {
22 bool pressedReceived = false;
23 bool releasedReceived = false;
24
25 TestKeyBindingContainer keyBindingContainer = null;
26
27 AddStep("add container", () =>
28 {
29 pressedReceived = false;
30 releasedReceived = false;
31
32 Child = keyBindingContainer = new TestKeyBindingContainer
33 {
34 Child = new TestKeyBindingReceptor
35 {
36 Pressed = _ => pressedReceived = true,
37 Released = _ => releasedReceived = true
38 }
39 };
40 });
41
42 AddStep("trigger press", () => keyBindingContainer.TriggerPressed(TestAction.ActionA));
43 AddAssert("press received", () => pressedReceived);
44
45 AddStep("trigger release", () => keyBindingContainer.TriggerReleased(TestAction.ActionA));
46 AddAssert("release received", () => releasedReceived);
47 }
48
49 [Test]
50 public void TestPressKeyBeforeKeyBindingContainerAdded()
51 {
52 List<TestAction> pressedActions = new List<TestAction>();
53 List<TestAction> releasedActions = new List<TestAction>();
54
55 AddStep("press key B", () => InputManager.PressKey(Key.B));
56
57 AddStep("add container", () =>
58 {
59 pressedActions.Clear();
60 releasedActions.Clear();
61
62 Child = new TestKeyBindingContainer
63 {
64 Child = new TestKeyBindingReceptor
65 {
66 Pressed = a => pressedActions.Add(a),
67 Released = a => releasedActions.Add(a)
68 }
69 };
70 });
71
72 AddStep("press key A", () => InputManager.PressKey(Key.A));
73 AddAssert("only one action triggered", () => pressedActions.Count == 1);
74 AddAssert("ActionA triggered", () => pressedActions[0] == TestAction.ActionA);
75 AddAssert("no actions released", () => releasedActions.Count == 0);
76
77 AddStep("release key A", () => InputManager.ReleaseKey(Key.A));
78 AddAssert("only one action triggered", () => pressedActions.Count == 1);
79 AddAssert("only one action released", () => releasedActions.Count == 1);
80 AddAssert("ActionA released", () => releasedActions[0] == TestAction.ActionA);
81 }
82
83 [Test]
84 public void TestKeyHandledByOtherDrawableDoesNotTrigger()
85 {
86 List<TestAction> pressedActions = new List<TestAction>();
87 List<TestAction> releasedActions = new List<TestAction>();
88
89 TextBox textBox = null;
90
91 AddStep("add children", () =>
92 {
93 pressedActions.Clear();
94 releasedActions.Clear();
95
96 Child = new TestKeyBindingContainer
97 {
98 Children = new Drawable[]
99 {
100 textBox = new BasicTextBox
101 {
102 Anchor = Anchor.Centre,
103 Origin = Anchor.Centre,
104 Size = new Vector2(200, 30)
105 },
106 new TestKeyBindingReceptor
107 {
108 Pressed = a => pressedActions.Add(a),
109 Released = a => releasedActions.Add(a)
110 }
111 }
112 };
113 });
114
115 AddStep("focus textbox and move mouse away", () =>
116 {
117 InputManager.MoveMouseTo(textBox);
118 InputManager.Click(MouseButton.Left);
119 InputManager.MoveMouseTo(textBox, new Vector2(0, 100));
120 });
121
122 AddStep("press enter", () => InputManager.PressKey(Key.Enter));
123 AddStep("press mouse button", () => InputManager.PressButton(MouseButton.Left));
124
125 AddStep("release enter", () => InputManager.ReleaseKey(Key.Enter));
126 AddStep("release mouse button", () => InputManager.ReleaseButton(MouseButton.Left));
127
128 AddAssert("no pressed actions", () => pressedActions.Count == 0);
129 AddAssert("no released actions", () => releasedActions.Count == 0);
130 }
131
132 [Test]
133 public void TestReleasingSpecificModifierDoesNotReleaseCommonBindingIfOtherKeyIsActive()
134 {
135 bool pressedReceived = false;
136 bool releasedReceived = false;
137
138 AddStep("add container", () =>
139 {
140 pressedReceived = false;
141 releasedReceived = false;
142
143 Child = new TestKeyBindingContainer
144 {
145 Child = new TestKeyBindingReceptor
146 {
147 Pressed = _ => pressedReceived = true,
148 Released = _ => releasedReceived = true
149 }
150 };
151 });
152
153 AddStep("press lctrl", () => InputManager.PressKey(Key.LControl));
154 AddAssert("press received", () => pressedReceived);
155
156 AddStep("reset variables", () =>
157 {
158 pressedReceived = false;
159 releasedReceived = false;
160 });
161
162 AddStep("press rctrl", () => InputManager.PressKey(Key.RControl));
163 AddAssert("press not received", () => !pressedReceived);
164 AddAssert("release not received", () => !releasedReceived);
165
166 AddStep("release rctrl", () => InputManager.ReleaseKey(Key.RControl));
167 AddAssert("release not received", () => !releasedReceived);
168
169 AddStep("release lctrl", () => InputManager.ReleaseKey(Key.LControl));
170 AddAssert("release received", () => releasedReceived);
171 }
172
173 private class TestKeyBindingReceptor : Drawable, IKeyBindingHandler<TestAction>
174 {
175 public Action<TestAction> Pressed;
176 public Action<TestAction> Released;
177
178 public TestKeyBindingReceptor()
179 {
180 RelativeSizeAxes = Axes.Both;
181 }
182
183 public bool OnPressed(TestAction action)
184 {
185 Pressed?.Invoke(action);
186 return true;
187 }
188
189 public void OnReleased(TestAction action)
190 {
191 Released?.Invoke(action);
192 }
193 }
194
195 private class TestKeyBindingContainer : KeyBindingContainer<TestAction>
196 {
197 public override IEnumerable<IKeyBinding> DefaultKeyBindings => new IKeyBinding[]
198 {
199 new KeyBinding(InputKey.A, TestAction.ActionA),
200 new KeyBinding(new KeyCombination(InputKey.A, InputKey.B), TestAction.ActionAB),
201 new KeyBinding(InputKey.Enter, TestAction.ActionEnter),
202 new KeyBinding(InputKey.Control, TestAction.ActionControl)
203 };
204 }
205
206 private enum TestAction
207 {
208 ActionA,
209 ActionAB,
210 ActionEnter,
211 ActionControl
212 }
213 }
214}