1/****************************************************************************
2**
3** Copyright (C) 2014 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:LGPL$
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 Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "inputhandler_p.h"
41
42#include <Qt3DInput/private/assignkeyboardfocusjob_p.h>
43#include <Qt3DInput/private/eventsourcesetterhelper_p.h>
44#include <Qt3DInput/private/inputmanagers_p.h>
45#include <Qt3DInput/private/inputsettings_p.h>
46#include <Qt3DInput/private/keyboardeventfilter_p.h>
47#include <Qt3DInput/private/keyeventdispatcherjob_p.h>
48#include <Qt3DInput/private/mouseeventdispatcherjob_p.h>
49#include <Qt3DInput/private/mouseeventfilter_p.h>
50#include <Qt3DInput/private/qinputdeviceintegration_p.h>
51#include <Qt3DCore/private/qeventfilterservice_p.h>
52
53QT_BEGIN_NAMESPACE
54
55using namespace Qt3DCore;
56
57namespace Qt3DInput {
58namespace Input {
59
60InputHandler::InputHandler()
61 : m_keyboardDeviceManager(new KeyboardDeviceManager())
62 , m_keyboardInputManager(new KeyboardInputManager())
63 , m_mouseDeviceManager(new MouseDeviceManager())
64 , m_mouseInputManager(new MouseInputManager())
65 , m_keyboardEventFilter(new KeyboardEventFilter())
66 , m_mouseEventFilter(new MouseEventFilter())
67 , m_axisManager(new AxisManager())
68 , m_axisAccumulatorManager(new AxisAccumulatorManager())
69 , m_actionManager(new ActionManager())
70 , m_axisSettingManager(new AxisSettingManager())
71 , m_actionInputManager(new ActionInputManager())
72 , m_analogAxisInputManager(new AnalogAxisInputManager())
73 , m_buttonAxisInputManager(new ButtonAxisInputManager())
74 , m_inputChordManager(new InputChordManager())
75 , m_inputSequenceManager(new InputSequenceManager())
76 , m_logicalDeviceManager(new LogicalDeviceManager())
77 , m_genericPhysicalDeviceBackendNodeManager(new GenericDeviceBackendNodeManager)
78 , m_physicalDeviceProxyManager(new PhysicalDeviceProxyManager())
79 , m_settings(nullptr)
80 , m_eventSourceSetter(new Qt3DInput::Input::EventSourceSetterHelper(this))
81{
82 m_keyboardEventFilter->setInputHandler(this);
83 m_mouseEventFilter->setInputHandler(this);
84
85 // Created in the main thread
86 // m_eventSourceSetter needs to be in the main thread
87}
88
89InputHandler::~InputHandler()
90{
91 delete m_keyboardDeviceManager;
92 delete m_keyboardInputManager;
93 delete m_mouseDeviceManager;
94 delete m_mouseInputManager;
95 delete m_keyboardEventFilter;
96 delete m_mouseEventFilter;
97 delete m_axisManager;
98 delete m_axisAccumulatorManager;
99 delete m_actionManager;
100 delete m_axisSettingManager;
101 delete m_analogAxisInputManager;
102 delete m_buttonAxisInputManager;
103 delete m_actionInputManager;
104 delete m_inputChordManager;
105 delete m_inputSequenceManager;
106 delete m_logicalDeviceManager;
107 delete m_genericPhysicalDeviceBackendNodeManager;
108 delete m_physicalDeviceProxyManager;
109}
110
111// Called in MainThread (by the EventSourceHelperSetter)
112void InputHandler::registerEventFilters(QEventFilterService *service)
113{
114 clearPendingKeyEvents();
115 clearPendingMouseEvents();
116
117 service->registerEventFilter(m_keyboardEventFilter, 512);
118 service->registerEventFilter(m_mouseEventFilter, 513);
119}
120
121void InputHandler::unregisterEventFilters(Qt3DCore::QEventFilterService *service)
122{
123 service->unregisterEventFilter(m_keyboardEventFilter);
124 service->unregisterEventFilter(m_mouseEventFilter);
125}
126
127// Called by the keyboardEventFilter in the main thread
128void InputHandler::appendKeyEvent(const QT_PREPEND_NAMESPACE(QKeyEvent) &event)
129{
130 QMutexLocker lock(&m_mutex);
131 m_pendingKeyEvents.append(event);
132}
133
134// Called by QInputASpect::jobsToExecute (aspectThread)
135QList<QT_PREPEND_NAMESPACE(QKeyEvent)> InputHandler::pendingKeyEvents()
136{
137 QMutexLocker lock(&m_mutex);
138 return std::move(m_pendingKeyEvents);
139}
140
141// Called by QInputASpect::jobsToExecute (aspectThread)
142void InputHandler::clearPendingKeyEvents()
143{
144 QMutexLocker lock(&m_mutex);
145 m_pendingKeyEvents.clear();
146}
147
148void InputHandler::appendMouseEvent(const QT_PREPEND_NAMESPACE(QMouseEvent) &event)
149{
150 QMutexLocker lock(&m_mutex);
151 m_pendingMouseEvents.append(event);
152}
153
154QList<QT_PREPEND_NAMESPACE(QMouseEvent)> InputHandler::pendingMouseEvents()
155{
156 QMutexLocker lock(&m_mutex);
157 return std::move(m_pendingMouseEvents);
158}
159
160void InputHandler::clearPendingMouseEvents()
161{
162 QMutexLocker lock(&m_mutex);
163 m_pendingMouseEvents.clear();
164}
165
166#if QT_CONFIG(wheelevent)
167void InputHandler::appendWheelEvent(const QT_PREPEND_NAMESPACE(QWheelEvent) &event)
168{
169 QMutexLocker lock(&m_mutex);
170 m_pendingWheelEvents.append(event);
171}
172
173QList<QT_PREPEND_NAMESPACE (QWheelEvent)> Qt3DInput::Input::InputHandler::pendingWheelEvents()
174{
175 QMutexLocker lock(&m_mutex);
176 return std::move(m_pendingWheelEvents);
177}
178
179void InputHandler::clearPendingWheelEvents()
180{
181 QMutexLocker lock(&m_mutex);
182 m_pendingWheelEvents.clear();
183}
184#endif
185
186void InputHandler::appendKeyboardDevice(HKeyboardDevice device)
187{
188 m_activeKeyboardDevices.append(device);
189}
190
191void InputHandler::removeKeyboardDevice(HKeyboardDevice device)
192{
193 m_activeKeyboardDevices.removeAll(device);
194}
195
196void InputHandler::appendMouseDevice(HMouseDevice device)
197{
198 m_activeMouseDevices.append(device);
199}
200
201void InputHandler::removeMouseDevice(HMouseDevice device)
202{
203 m_activeMouseDevices.removeAll(device);
204}
205
206void Qt3DInput::Input::InputHandler::appendGenericDevice(HGenericDeviceBackendNode device)
207{
208 m_activeGenericPhysicalDevices.append(device);
209}
210
211void Qt3DInput::Input::InputHandler::removeGenericDevice(HGenericDeviceBackendNode device)
212{
213 m_activeGenericPhysicalDevices.removeAll(device);
214}
215
216// Return a vector of jobs to be performed for keyboard events
217// Handles all dependencies between jobs
218QVector<Qt3DCore::QAspectJobPtr> InputHandler::keyboardJobs()
219{
220 // One job for Keyboard focus change event per Keyboard device
221 QVector<QAspectJobPtr> jobs;
222 const QList<QT_PREPEND_NAMESPACE(QKeyEvent)> events = pendingKeyEvents();
223
224 for (const HKeyboardDevice &cHandle : qAsConst(m_activeKeyboardDevices)) {
225 KeyboardDevice *keyboardDevice = m_keyboardDeviceManager->data(cHandle);
226 if (keyboardDevice) {
227 keyboardDevice->updateKeyEvents(events);
228 bool haveFocusChangeJob = false;
229 if (keyboardDevice->lastKeyboardInputRequester() != keyboardDevice->currentFocusItem()) {
230 auto job = QSharedPointer<AssignKeyboardFocusJob>::create(keyboardDevice->peerId());
231 job->setInputHandler(this);
232 haveFocusChangeJob= true;
233 jobs.append(std::move(job));
234 // One job for Keyboard events (depends on the focus change job if there was one)
235 }
236 // Event dispacthing job
237 if (!events.isEmpty()) {
238 auto job = QSharedPointer<KeyEventDispatcherJob>::create(keyboardDevice->currentFocusItem(), events);
239 job->setInputHandler(this);
240 if (haveFocusChangeJob)
241 job->addDependency(qAsConst(jobs).back());
242 jobs.append(std::move(job));
243 }
244 }
245 }
246 return jobs;
247}
248
249QVector<Qt3DCore::QAspectJobPtr> InputHandler::mouseJobs()
250{
251 QVector<QAspectJobPtr> jobs;
252 const QList<QT_PREPEND_NAMESPACE(QMouseEvent)> mouseEvents = pendingMouseEvents();
253#if QT_CONFIG(wheelevent)
254 const QList<QT_PREPEND_NAMESPACE(QWheelEvent)> wheelEvents = pendingWheelEvents();
255#endif
256
257 for (const HMouseDevice &cHandle : qAsConst(m_activeMouseDevices)) {
258 MouseDevice *controller = m_mouseDeviceManager->data(cHandle);
259
260 controller->updateMouseEvents(mouseEvents);
261#if QT_CONFIG(wheelevent)
262 controller->updateWheelEvents(wheelEvents);
263#endif
264 // Event dispacthing job
265 if (!mouseEvents.isEmpty()
266#if QT_CONFIG(wheelevent)
267 || !wheelEvents.empty()
268#endif
269 ) {
270 // Send the events to the mouse handlers that have for sourceDevice controller
271 const QVector<HMouseHandler> activeMouseHandlers = m_mouseInputManager->activeHandles();
272 for (const HMouseHandler &mouseHandlerHandle : activeMouseHandlers) {
273
274 MouseHandler *mouseHandler = m_mouseInputManager->data(mouseHandlerHandle);
275 Q_ASSERT(mouseHandler);
276
277 if (mouseHandler->mouseDevice() == controller->peerId()) {
278 MouseEventDispatcherJob *job = new MouseEventDispatcherJob(mouseHandler->peerId(),
279 mouseEvents
280#if QT_CONFIG(wheelevent)
281 , wheelEvents
282#endif
283 );
284 job->setInputHandler(this);
285 jobs.append(QAspectJobPtr(job));
286 }
287 }
288 }
289 }
290
291 return jobs;
292}
293
294QVector<QInputDeviceIntegration *> InputHandler::inputDeviceIntegrations() const
295{
296 return m_inputDeviceIntegrations;
297}
298
299void InputHandler::addInputDeviceIntegration(QInputDeviceIntegration *inputIntegration)
300{
301 m_inputDeviceIntegrations.push_back(inputIntegration);
302}
303
304void InputHandler::setInputSettings(InputSettings *settings)
305{
306 if (m_settings && settings == nullptr)
307 m_eventSourceSetter->unsetEventSource(m_settings->eventSource());
308 m_settings = settings;
309}
310
311void InputHandler::setEventSourceHelper(EventSourceSetterHelper *helper)
312{
313 m_eventSourceSetter.reset(helper);
314}
315
316EventSourceSetterHelper *InputHandler::eventSourceHelper() const
317{
318 return m_eventSourceSetter.data();
319}
320
321QAbstractPhysicalDevice *Qt3DInput::Input::InputHandler::createPhysicalDevice(const QString &name)
322{
323 QAbstractPhysicalDevice *device = nullptr;
324 for (Qt3DInput::QInputDeviceIntegration *integration : qAsConst(m_inputDeviceIntegrations)) {
325 if ((device = integration->createPhysicalDevice(name)) != nullptr)
326 break;
327 }
328 return device;
329}
330
331void InputHandler::updateEventSource()
332{
333 if (m_settings != nullptr) {
334 // Will be updated only if eventSource is different than
335 // what was set last
336 QObject *eventSource = m_settings->eventSource();
337 m_eventSourceSetter->setEventSource(eventSource);
338 }
339}
340
341AbstractActionInput *InputHandler::lookupActionInput(Qt3DCore::QNodeId id) const
342{
343 AbstractActionInput *input = nullptr;
344 if ((input = actionInputManager()->lookupResource(id)) != nullptr)
345 return input;
346 if ((input = inputSequenceManager()->lookupResource(id)) != nullptr)
347 return input;
348 return inputChordManager()->lookupResource(id); // nullptr if not found
349}
350
351} // namespace Input
352} // namespace Qt3DInput
353
354QT_END_NAMESPACE
355