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.Collections.Generic;
5using NUnit.Framework;
6using osu.Framework.Graphics;
7using osu.Framework.Graphics.Shapes;
8using osu.Framework.Input;
9using osu.Framework.Input.Bindings;
10using osu.Framework.Input.Events;
11using osu.Framework.Testing;
12using osuTK;
13using osuTK.Input;
14
15namespace osu.Framework.Tests.Input
16{
17 [HeadlessTest]
18 public class KeyBindingInputTest : ManualInputManagerTestScene
19 {
20 /// <summary>
21 /// Tests that if the current input queue is changed, drawables that originally handled <see cref="IKeyBindingHandler{T}.OnPressed"/>
22 /// will receive a corresponding <see cref="IKeyBindingHandler{T}.OnReleased"/> event.
23 /// </summary>
24 [Test]
25 public void TestReleaseAlwaysPressedToOriginalTargets()
26 {
27 InputReceptor receptorBelow = null;
28 InputReceptor receptorAbove = null;
29
30 AddStep("setup", () =>
31 {
32 Child = new TestKeyBindingContainer
33 {
34 RelativeSizeAxes = Axes.Both,
35 Children = new Drawable[]
36 {
37 receptorBelow = new InputReceptor(true)
38 {
39 Size = new Vector2(100),
40 },
41 receptorAbove = new InputReceptor(false)
42 {
43 Size = new Vector2(100),
44 Position = new Vector2(100),
45 }
46 }
47 };
48 });
49
50 // Input is positional
51
52 AddStep("move mouse to receptorBelow", () => InputManager.MoveMouseTo(receptorBelow));
53 AddStep("press keybind1", () => InputManager.PressKey(Key.Up));
54 AddAssert("receptorBelow received press", () => receptorBelow.PressedReceived);
55
56 AddStep("move mouse to receptorAbove", () => InputManager.MoveMouseTo(receptorAbove));
57 AddStep("release keybind1", () => InputManager.ReleaseKey(Key.Up));
58 AddAssert("receptorBelow received release", () => receptorBelow.ReleasedReceived);
59 }
60
61 private class InputReceptor : Box, IKeyBindingHandler<TestKeyBinding>
62 {
63 public bool PressedReceived { get; private set; }
64 public bool ReleasedReceived { get; private set; }
65
66 private readonly bool keybindings;
67
68 public InputReceptor(bool keybindings)
69 {
70 this.keybindings = keybindings;
71 }
72
73 public override bool HandlePositionalInput => true; // IsHovered is used
74
75 protected override bool OnKeyDown(KeyDownEvent e)
76 {
77 if (keybindings)
78 return false;
79
80 if (!IsHovered)
81 return false;
82
83 return true;
84 }
85
86 protected override void OnKeyUp(KeyUpEvent e)
87 {
88 }
89
90 public bool OnPressed(TestKeyBinding action)
91 {
92 if (!keybindings)
93 return false;
94
95 if (!IsHovered)
96 return false;
97
98 PressedReceived = true;
99 return true;
100 }
101
102 public void OnReleased(TestKeyBinding action)
103 {
104 if (!keybindings)
105 return;
106
107 ReleasedReceived = true;
108 }
109 }
110
111 private class TestKeyBindingContainer : KeyBindingContainer<TestKeyBinding>, IHandleGlobalKeyboardInput
112 {
113 public TestKeyBindingContainer()
114 : base(SimultaneousBindingMode.Unique, KeyCombinationMatchingMode.Modifiers)
115 {
116 }
117
118 public override IEnumerable<IKeyBinding> DefaultKeyBindings => new[]
119 {
120 new KeyBinding(InputKey.Up, TestKeyBinding.Binding1),
121 new KeyBinding(InputKey.Down, TestKeyBinding.Binding2),
122 };
123 }
124
125 private enum TestKeyBinding
126 {
127 Binding1,
128 Binding2
129 }
130 }
131}