1/****************************************************************************
2**
3** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtTest/QTest>
30#include <qbackendnodetester.h>
31#include "testdevice.h"
32
33#include <Qt3DInput/private/actioninput_p.h>
34#include <Qt3DInput/private/inputchord_p.h>
35#include <Qt3DInput/private/inputhandler_p.h>
36#include <Qt3DInput/private/inputmanagers_p.h>
37#include <Qt3DInput/QActionInput>
38#include <Qt3DInput/QInputChord>
39
40class tst_InputChord : public Qt3DCore::QBackendNodeTester
41{
42 Q_OBJECT
43private Q_SLOTS:
44 void shouldMirrorPeerProperties()
45 {
46 // GIVEN
47 Qt3DInput::Input::InputChord backendInputChord;
48 Qt3DInput::QInputChord inputChord;
49 Qt3DInput::QActionInput actionInput;
50
51 inputChord.setTimeout(250);
52 inputChord.addChord(input: &actionInput);
53
54 // WHEN
55 simulateInitializationSync(frontend: &inputChord, backend: &backendInputChord);
56
57 // THEN
58 QCOMPARE(backendInputChord.peerId(), inputChord.id());
59 QCOMPARE(backendInputChord.isEnabled(), inputChord.isEnabled());
60 QCOMPARE(backendInputChord.timeout(), inputChord.timeout() * 1000000);
61 QCOMPARE(backendInputChord.chords().size(), inputChord.chords().size());
62
63 const int inputsCount = backendInputChord.chords().size();
64 if (inputsCount > 0) {
65 for (int i = 0; i < inputsCount; ++i)
66 QCOMPARE(backendInputChord.chords().at(i), inputChord.chords().at(i)->id());
67 }
68 }
69
70 void shouldHaveInitialAndCleanedUpStates()
71 {
72 // GIVEN
73 Qt3DInput::Input::InputChord backendInputChord;
74
75 // THEN
76 QVERIFY(backendInputChord.peerId().isNull());
77 QCOMPARE(backendInputChord.isEnabled(), false);
78 QCOMPARE(backendInputChord.timeout(), 0);
79 QCOMPARE(backendInputChord.chords().size(), 0);
80
81 // GIVEN
82 Qt3DInput::QInputChord inputChord;
83 Qt3DInput::QActionInput actionInput;
84
85 inputChord.setTimeout(250);
86 inputChord.addChord(input: &actionInput);
87
88 // WHEN
89 simulateInitializationSync(frontend: &inputChord, backend: &backendInputChord);
90 backendInputChord.cleanup();
91
92 // THEN
93 QCOMPARE(backendInputChord.isEnabled(), false);
94 QCOMPARE(backendInputChord.timeout(), 0);
95 QCOMPARE(backendInputChord.chords().size(), 0);
96 }
97
98 void shouldHandlePropertyChanges()
99 {
100 // GIVEN
101 Qt3DInput::QInputChord inputChord;
102 Qt3DInput::Input::InputChord backendInputChord;
103 simulateInitializationSync(frontend: &inputChord, backend: &backendInputChord);
104
105 // WHEN
106 inputChord.setTimeout(250);
107 backendInputChord.syncFromFrontEnd(frontEnd: &inputChord, firstTime: false);
108
109 // THEN
110 QCOMPARE(backendInputChord.timeout(), 250000000);
111
112 // WHEN
113 inputChord.setEnabled(false);
114 backendInputChord.syncFromFrontEnd(frontEnd: &inputChord, firstTime: false);
115
116 // THEN
117 QCOMPARE(backendInputChord.isEnabled(), false);
118
119 // WHEN
120 Qt3DInput::QActionInput input;
121 const Qt3DCore::QNodeId inputId = input.id();
122 inputChord.addChord(input: &input);
123 backendInputChord.syncFromFrontEnd(frontEnd: &inputChord, firstTime: false);
124
125 // THEN
126 QCOMPARE(backendInputChord.chords().size(), 1);
127 QCOMPARE(backendInputChord.chords().first(), inputId);
128
129 // WHEN
130 inputChord.removeChord(input: &input);
131 backendInputChord.syncFromFrontEnd(frontEnd: &inputChord, firstTime: false);
132
133 // THEN
134 QCOMPARE(backendInputChord.chords().size(), 0);
135 }
136
137 void shouldActivateWhenAllArePressed()
138 {
139 // GIVEN
140 TestDeviceIntegration deviceIntegration;
141 TestDevice *device = deviceIntegration.createPhysicalDevice(name: "keyboard");
142 TestDeviceBackendNode *deviceBackend = deviceIntegration.physicalDevice(id: device->id());
143 Qt3DInput::Input::InputHandler handler;
144 handler.addInputDeviceIntegration(inputIntegration: &deviceIntegration);
145
146 auto firstInput = new Qt3DInput::QActionInput;
147 firstInput->setButtons(QVector<int>() << Qt::Key_Q << Qt::Key_W);
148 firstInput->setSourceDevice(device);
149 auto backendFirstInput = handler.actionInputManager()->getOrCreateResource(id: firstInput->id());
150 simulateInitializationSync(frontend: firstInput, backend: backendFirstInput);
151
152 auto secondInput = new Qt3DInput::QActionInput;
153 secondInput->setButtons(QVector<int>() << Qt::Key_A << Qt::Key_S);
154 secondInput->setSourceDevice(device);
155 auto backendSecondInput = handler.actionInputManager()->getOrCreateResource(id: secondInput->id());
156 simulateInitializationSync(frontend: secondInput, backend: backendSecondInput);
157
158 Qt3DInput::Input::InputChord backendInputChord;
159 Qt3DInput::QInputChord inputChord;
160 inputChord.setEnabled(true);
161 inputChord.setTimeout(300);
162 inputChord.addChord(input: firstInput);
163 inputChord.addChord(input: secondInput);
164 simulateInitializationSync(frontend: &inputChord, backend: &backendInputChord);
165
166 // WHEN
167 deviceBackend->setButtonPressed(buttonIdentifier: Qt::Key_Up, pressed: true);
168
169 // THEN
170 QCOMPARE(backendInputChord.process(&handler, 1000000000), false);
171
172 // WHEN
173 deviceBackend->setButtonPressed(buttonIdentifier: Qt::Key_Up, pressed: false);
174 deviceBackend->setButtonPressed(buttonIdentifier: Qt::Key_Q, pressed: true);
175
176 // THEN
177 QCOMPARE(backendInputChord.process(&handler, 1100000000), false);
178
179 // WHEN
180 deviceBackend->setButtonPressed(buttonIdentifier: Qt::Key_A, pressed: true);
181
182 // THEN
183 QCOMPARE(backendInputChord.process(&handler, 1200000000), true);
184
185 // WHEN
186 deviceBackend->setButtonPressed(buttonIdentifier: Qt::Key_S, pressed: true);
187
188 // THEN
189 QCOMPARE(backendInputChord.process(&handler, 1300000000), true);
190
191 // WHEN
192 deviceBackend->setButtonPressed(buttonIdentifier: Qt::Key_W, pressed: true);
193
194 // THEN
195 QCOMPARE(backendInputChord.process(&handler, 1400000000), true);
196
197 // WHEN
198 deviceBackend->setButtonPressed(buttonIdentifier: Qt::Key_W, pressed: false);
199
200 // THEN
201 QCOMPARE(backendInputChord.process(&handler, 1500000000), true);
202
203 // THEN
204 QCOMPARE(backendInputChord.process(&handler, 1600000000), true);
205
206 // THEN
207 QCOMPARE(backendInputChord.process(&handler, 1700000000), true);
208
209 // THEN
210 QCOMPARE(backendInputChord.process(&handler, 1800000000), true);
211
212 // THEN
213 QCOMPARE(backendInputChord.process(&handler, 1900000000), true);
214
215 // WHEN
216 deviceBackend->setButtonPressed(buttonIdentifier: Qt::Key_Q, pressed: false);
217
218 // THEN
219 QCOMPARE(backendInputChord.process(&handler, 2000000000), false);
220
221 // THEN
222 QCOMPARE(backendInputChord.process(&handler, 2100000000), false);
223 }
224
225 void shouldRespectChordTimeout()
226 {
227 // GIVEN
228 TestDeviceIntegration deviceIntegration;
229 TestDevice *device = deviceIntegration.createPhysicalDevice(name: "keyboard");
230 TestDeviceBackendNode *deviceBackend = deviceIntegration.physicalDevice(id: device->id());
231 Qt3DInput::Input::InputHandler handler;
232 handler.addInputDeviceIntegration(inputIntegration: &deviceIntegration);
233
234 auto firstInput = new Qt3DInput::QActionInput;
235 firstInput->setButtons(QVector<int>() << Qt::Key_Q);
236 firstInput->setSourceDevice(device);
237 auto backendFirstInput = handler.actionInputManager()->getOrCreateResource(id: firstInput->id());
238 simulateInitializationSync(frontend: firstInput, backend: backendFirstInput);
239
240 auto secondInput = new Qt3DInput::QActionInput;
241 secondInput->setButtons(QVector<int>() << Qt::Key_W);
242 secondInput->setSourceDevice(device);
243 auto backendSecondInput = handler.actionInputManager()->getOrCreateResource(id: secondInput->id());
244 simulateInitializationSync(frontend: secondInput, backend: backendSecondInput);
245
246 Qt3DInput::Input::InputChord backendInputChord;
247 Qt3DInput::QInputChord inputChord;
248 inputChord.setEnabled(true);
249 inputChord.setTimeout(300);
250 inputChord.addChord(input: firstInput);
251 inputChord.addChord(input: secondInput);
252 simulateInitializationSync(frontend: &inputChord, backend: &backendInputChord);
253
254 // WHEN
255 deviceBackend->setButtonPressed(buttonIdentifier: Qt::Key_Q, pressed: true);
256
257 // THEN
258 QCOMPARE(backendInputChord.process(&handler, 1000000000), false);
259
260 // WHEN
261 deviceBackend->setButtonPressed(buttonIdentifier: Qt::Key_W, pressed: true);
262
263 // THEN
264 QCOMPARE(backendInputChord.process(&handler, 1400000000), false); // Too late
265
266 // THEN
267 QCOMPARE(backendInputChord.process(&handler, 1600000000), false);
268
269 // THEN
270 QCOMPARE(backendInputChord.process(&handler, 1800000000), false);
271 }
272
273 void shouldNotProcessWhenDisabled()
274 {
275 // GIVEN
276 TestDeviceIntegration deviceIntegration;
277 TestDevice *device = deviceIntegration.createPhysicalDevice(name: "keyboard");
278 TestDeviceBackendNode *deviceBackend = deviceIntegration.physicalDevice(id: device->id());
279 Qt3DInput::Input::InputHandler handler;
280 handler.addInputDeviceIntegration(inputIntegration: &deviceIntegration);
281
282 auto firstInput = new Qt3DInput::QActionInput;
283 firstInput->setButtons(QVector<int>() << Qt::Key_Q);
284 firstInput->setSourceDevice(device);
285 auto backendFirstInput = handler.actionInputManager()->getOrCreateResource(id: firstInput->id());
286 simulateInitializationSync(frontend: firstInput, backend: backendFirstInput);
287
288 auto secondInput = new Qt3DInput::QActionInput;
289 secondInput->setButtons(QVector<int>() << Qt::Key_W);
290 secondInput->setSourceDevice(device);
291 auto backendSecondInput = handler.actionInputManager()->getOrCreateResource(id: secondInput->id());
292 simulateInitializationSync(frontend: secondInput, backend: backendSecondInput);
293
294 Qt3DInput::Input::InputChord backendInputChord;
295 Qt3DInput::QInputChord inputChord;
296 inputChord.setEnabled(false);
297 inputChord.setTimeout(300);
298 inputChord.addChord(input: firstInput);
299 inputChord.addChord(input: secondInput);
300 simulateInitializationSync(frontend: &inputChord, backend: &backendInputChord);
301
302 // WHEN
303 deviceBackend->setButtonPressed(buttonIdentifier: Qt::Key_Q, pressed: true);
304 deviceBackend->setButtonPressed(buttonIdentifier: Qt::Key_W, pressed: true);
305
306 // THEN
307 QCOMPARE(backendInputChord.process(&handler, 1000000000), false);
308 }
309};
310
311QTEST_APPLESS_MAIN(tst_InputChord)
312
313#include "tst_inputchord.moc"
314

source code of qt3d/tests/auto/input/inputchord/tst_inputchord.cpp