1// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "inputhandler_p.h"
5
6#include <Qt3DCore/private/qscene_p.h>
7#include <Qt3DInput/qmousehandler.h>
8#include <Qt3DInput/qkeyboardhandler.h>
9#include <Qt3DInput/private/assignkeyboardfocusjob_p.h>
10#include <Qt3DInput/private/inputmanagers_p.h>
11#include <Qt3DInput/private/inputsettings_p.h>
12#include <Qt3DInput/private/qinputdeviceintegration_p.h>
13#include <Qt3DInput/private/qmousehandler_p.h>
14#include <Qt3DInput/private/qkeyboardhandler_p.h>
15#include <Qt3DCore/private/qeventfilterservice_p.h>
16
17
18QT_BEGIN_NAMESPACE
19
20using namespace Qt3DCore;
21
22namespace Qt3DInput {
23namespace Input {
24
25class InternalEventFilter : public QObject
26{
27public:
28 explicit InternalEventFilter(QObject *parent = nullptr) : QObject(parent), m_inputHandler(nullptr) { }
29 ~InternalEventFilter() override;
30
31 void setInputHandler(Qt3DInput::Input::InputHandler *handler) { m_inputHandler = handler; }
32 inline Qt3DInput::Input::InputHandler *inputHandler() const { return m_inputHandler; }
33
34protected:
35 bool eventFilter(QObject *obj, QEvent *e) override {
36 switch (e->type()) {
37 case QEvent::MouseMove:
38 case QEvent::MouseButtonPress:
39 case QEvent::MouseButtonRelease:
40 case QEvent::MouseButtonDblClick:
41 return processMouseEvent(obj, event: static_cast<QT_PREPEND_NAMESPACE(QMouseEvent) *>(e));
42 case QEvent::HoverMove: {
43 const QHoverEvent *he = static_cast<QHoverEvent *>(e);
44 auto mouseEvent = QT_PREPEND_NAMESPACE(QMouseEvent)(QEvent::MouseMove,
45 he->position(),
46 he->globalPosition(),
47 Qt::NoButton, Qt::NoButton,
48 he->modifiers());
49 return processMouseEvent(obj, event: static_cast<QT_PREPEND_NAMESPACE(QMouseEvent) *>(&mouseEvent));
50 }
51#if QT_CONFIG(wheelevent)
52 case QEvent::Wheel:
53 return processWheelEvent(obj, event: static_cast<QT_PREPEND_NAMESPACE(QWheelEvent) *>(e));
54#endif
55 case QEvent::KeyPress:
56 case QEvent::KeyRelease:
57 return processKeyEvent(obj, event: static_cast<QT_PREPEND_NAMESPACE(QKeyEvent) *>(e));
58 default:
59 break;
60 }
61 return false;
62 }
63
64 bool processMouseEvent(QObject *obj, QT_PREPEND_NAMESPACE(QMouseEvent) *event);
65#if QT_CONFIG(wheelevent)
66 bool processWheelEvent(QObject *obj, QT_PREPEND_NAMESPACE(QWheelEvent) *event);
67#endif
68 bool processKeyEvent(QObject *obj, QT_PREPEND_NAMESPACE(QKeyEvent) *event);
69
70private:
71 Qt3DInput::Input::InputHandler *m_inputHandler;
72};
73
74
75InputHandler::InputHandler()
76 : m_keyboardDeviceManager(new KeyboardDeviceManager())
77 , m_keyboardInputManager(new KeyboardInputManager())
78 , m_mouseDeviceManager(new MouseDeviceManager())
79 , m_mouseInputManager(new MouseInputManager())
80 , m_eventFilter(new InternalEventFilter())
81 , m_axisManager(new AxisManager())
82 , m_axisAccumulatorManager(new AxisAccumulatorManager())
83 , m_actionManager(new ActionManager())
84 , m_axisSettingManager(new AxisSettingManager())
85 , m_actionInputManager(new ActionInputManager())
86 , m_analogAxisInputManager(new AnalogAxisInputManager())
87 , m_buttonAxisInputManager(new ButtonAxisInputManager())
88 , m_inputChordManager(new InputChordManager())
89 , m_inputSequenceManager(new InputSequenceManager())
90 , m_logicalDeviceManager(new LogicalDeviceManager())
91 , m_genericPhysicalDeviceBackendNodeManager(new GenericDeviceBackendNodeManager)
92 , m_physicalDeviceProxyManager(new PhysicalDeviceProxyManager())
93 , m_settings(nullptr)
94 , m_service(nullptr)
95 , m_lastEventSource(nullptr)
96{
97 m_eventFilter->setInputHandler(this);
98}
99
100InputHandler::~InputHandler()
101{
102 delete m_keyboardDeviceManager;
103 delete m_keyboardInputManager;
104 delete m_mouseDeviceManager;
105 delete m_mouseInputManager;
106 delete m_eventFilter;
107 delete m_axisManager;
108 delete m_axisAccumulatorManager;
109 delete m_actionManager;
110 delete m_axisSettingManager;
111 delete m_analogAxisInputManager;
112 delete m_buttonAxisInputManager;
113 delete m_actionInputManager;
114 delete m_inputChordManager;
115 delete m_inputSequenceManager;
116 delete m_logicalDeviceManager;
117 delete m_genericPhysicalDeviceBackendNodeManager;
118 delete m_physicalDeviceProxyManager;
119}
120
121// Called in MainThread (by the EventSourceHelperSetter)
122void InputHandler::registerEventFilters()
123{
124 if (m_service)
125 m_service->registerEventFilter(eventFilter: m_eventFilter, priority: 512);
126}
127
128void InputHandler::unregisterEventFilters()
129{
130 if (m_service)
131 m_service->unregisterEventFilter(eventFilter: m_eventFilter);
132}
133
134void InputHandler::setInputSettings(InputSettings *settings)
135{
136 if (m_settings && settings == nullptr) {
137 unregisterEventFilters();
138 m_lastEventSource = nullptr;
139 if (m_settings->eventSource() && m_service)
140 m_service->shutdown(eventSource: m_settings->eventSource());
141 }
142 if (m_service) {
143 unregisterEventFilters();
144 if (m_settings && m_settings->eventSource())
145 m_service->shutdown(eventSource: m_settings->eventSource());
146 }
147 m_settings = settings;
148}
149
150void InputHandler::updateEventSource()
151{
152 // Called every frame from input aspect
153 // Should probably just listen to changes in source property on settings object
154 if (!m_settings || !m_service)
155 return;
156
157 // Will be updated only if eventSource is different than
158 // what was set last
159 QObject *eventSource = m_settings->eventSource();
160 if (eventSource && m_lastEventSource != eventSource) {
161 m_service->initialize(eventSource);
162 registerEventFilters();
163 m_lastEventSource = eventSource;
164 }
165}
166
167void InputHandler::appendKeyboardDevice(HKeyboardDevice device)
168{
169 m_activeKeyboardDevices.append(t: device);
170}
171
172void InputHandler::removeKeyboardDevice(HKeyboardDevice device)
173{
174 m_activeKeyboardDevices.removeAll(t: device);
175}
176
177void InputHandler::appendMouseDevice(HMouseDevice device)
178{
179 m_activeMouseDevices.append(t: device);
180}
181
182void InputHandler::removeMouseDevice(HMouseDevice device)
183{
184 m_activeMouseDevices.removeAll(t: device);
185}
186
187void Qt3DInput::Input::InputHandler::appendGenericDevice(HGenericDeviceBackendNode device)
188{
189 m_activeGenericPhysicalDevices.append(t: device);
190}
191
192void Qt3DInput::Input::InputHandler::removeGenericDevice(HGenericDeviceBackendNode device)
193{
194 m_activeGenericPhysicalDevices.removeAll(t: device);
195}
196
197// called every frame to reset the
198void Qt3DInput::Input::InputHandler::resetMouseAxisState()
199{
200 for (const HMouseDevice &cHandle : std::as_const(t&: m_activeMouseDevices)) {
201 MouseDevice *controller = m_mouseDeviceManager->data(handle: cHandle);
202 controller->resetMouseAxisState();
203 }
204}
205
206QList<QInputDeviceIntegration *> InputHandler::inputDeviceIntegrations() const
207{
208 return m_inputDeviceIntegrations;
209}
210
211void InputHandler::addInputDeviceIntegration(QInputDeviceIntegration *inputIntegration)
212{
213 m_inputDeviceIntegrations.push_back(t: inputIntegration);
214}
215
216QAbstractPhysicalDevice *Qt3DInput::Input::InputHandler::createPhysicalDevice(const QString &name)
217{
218 QAbstractPhysicalDevice *device = nullptr;
219 for (Qt3DInput::QInputDeviceIntegration *integration : std::as_const(t&: m_inputDeviceIntegrations)) {
220 if ((device = integration->createPhysicalDevice(name)) != nullptr)
221 break;
222 }
223 return device;
224}
225
226void Qt3DInput::Input::InputHandler::setEventFilterService(QEventFilterService *service)
227{
228 m_service = service;
229}
230
231AbstractActionInput *InputHandler::lookupActionInput(Qt3DCore::QNodeId id) const
232{
233 AbstractActionInput *input = nullptr;
234 if ((input = actionInputManager()->lookupResource(id)) != nullptr)
235 return input;
236 if ((input = inputSequenceManager()->lookupResource(id)) != nullptr)
237 return input;
238 return inputChordManager()->lookupResource(id); // nullptr if not found
239}
240
241InternalEventFilter::~InternalEventFilter() = default;
242
243bool InternalEventFilter::processMouseEvent(QObject *obj, QT_PREPEND_NAMESPACE(QMouseEvent) *event)
244{
245 Q_UNUSED(obj);
246 Q_ASSERT(m_inputHandler);
247 if (!m_inputHandler->m_scene)
248 return false;
249
250 for (const HMouseDevice &cHandle : std::as_const(t&: m_inputHandler->m_activeMouseDevices)) {
251 MouseDevice *controller = m_inputHandler->m_mouseDeviceManager->data(handle: cHandle);
252
253 controller->updateMouseEvent(events: event);
254
255 // Send the events to the mouse handlers that have for sourceDevice controller
256 const std::vector<HMouseHandler> &activeMouseHandlers = m_inputHandler->m_mouseInputManager->activeHandles();
257 for (const HMouseHandler &mouseHandlerHandle : activeMouseHandlers) {
258 MouseHandler *mouseHandler = m_inputHandler->m_mouseInputManager->data(handle: mouseHandlerHandle);
259 Q_ASSERT(mouseHandler);
260
261 if (mouseHandler->mouseDevice() == controller->peerId()) {
262 QMouseHandler *node = qobject_cast<QMouseHandler *>(object: m_inputHandler->m_scene->lookupNode(id: mouseHandler->peerId()));
263 QMouseHandlerPrivate *dnode = static_cast<QMouseHandlerPrivate *>(QMouseHandlerPrivate::get(q: node));
264 dnode->mouseEvent(event: QMouseEventPtr::create(arguments&: *event)); // Do we really need Qt3D specific events?
265 }
266 }
267 }
268
269 return false;
270}
271
272#if QT_CONFIG(wheelevent)
273bool InternalEventFilter::processWheelEvent(QObject *obj, QT_PREPEND_NAMESPACE(QWheelEvent) *event)
274{
275 Q_UNUSED(obj);
276 Q_ASSERT(m_inputHandler);
277 if (!m_inputHandler->m_scene)
278 return false;
279
280 for (const HMouseDevice &cHandle : std::as_const(t&: m_inputHandler->m_activeMouseDevices)) {
281 MouseDevice *controller = m_inputHandler->m_mouseDeviceManager->data(handle: cHandle);
282
283 controller->updateWheelEvent(events: event);
284
285 // Send the events to the mouse handlers that have for sourceDevice controller
286 const std::vector<HMouseHandler> &activeMouseHandlers = m_inputHandler->m_mouseInputManager->activeHandles();
287 for (const HMouseHandler &mouseHandlerHandle : activeMouseHandlers) {
288 MouseHandler *mouseHandler = m_inputHandler->m_mouseInputManager->data(handle: mouseHandlerHandle);
289 Q_ASSERT(mouseHandler);
290
291 if (mouseHandler->mouseDevice() == controller->peerId()) {
292 QMouseHandler *node = qobject_cast<QMouseHandler *>(object: m_inputHandler->m_scene->lookupNode(id: mouseHandler->peerId()));
293 QWheelEvent we(*event);
294 node->wheel(wheel: &we); // Do we really need Qt3D specific events?
295 }
296 }
297 }
298
299 return false;
300}
301#endif
302
303bool InternalEventFilter::processKeyEvent(QObject *obj, QT_PREPEND_NAMESPACE(QKeyEvent) *event)
304{
305 Q_UNUSED(obj);
306 Q_ASSERT(m_inputHandler);
307 if (!m_inputHandler->m_scene)
308 return false;
309
310 for (const HKeyboardDevice &cHandle : std::as_const(t&: m_inputHandler->m_activeKeyboardDevices)) {
311 KeyboardDevice *keyboardDevice = m_inputHandler->m_keyboardDeviceManager->data(handle: cHandle);
312 if (keyboardDevice) {
313 keyboardDevice->updateKeyEvent(event);
314
315 // update the focus
316 if (keyboardDevice->lastKeyboardInputRequester() != keyboardDevice->currentFocusItem()) {
317 const auto handles = m_inputHandler->keyboardInputManager()->activeHandles();
318 for (const HKeyboardHandler &handle : handles) {
319 KeyboardHandler *input = m_inputHandler->keyboardInputManager()->data(handle);
320 Q_ASSERT(input);
321 if (input->keyboardDevice() == keyboardDevice->peerId()) {
322 bool hasFocus = input->peerId() == keyboardDevice->lastKeyboardInputRequester();
323 input->setFocus(hasFocus);
324 QKeyboardHandler *node = qobject_cast<QKeyboardHandler *>(object: m_inputHandler->m_scene->lookupNode(id: input->peerId()));
325 if (node) {
326 const bool b = node->blockNotifications(block: true);
327 node->setFocus(hasFocus);
328 node->blockNotifications(block: b);
329 }
330 if (hasFocus)
331 keyboardDevice->setCurrentFocusItem(input->peerId());
332 }
333 }
334 }
335
336 // deliver the event
337 QKeyboardHandler *node = qobject_cast<QKeyboardHandler *>(object: m_inputHandler->m_scene->lookupNode(id: keyboardDevice->currentFocusItem()));
338 if (node) {
339 QKeyboardHandlerPrivate *dnode = static_cast<QKeyboardHandlerPrivate *>(QKeyboardHandlerPrivate::get(q: node));
340
341 QKeyEvent ke(*event);
342 dnode->keyEvent(event: &ke); // Do we really need Qt3D specific events?
343 }
344 }
345 }
346
347 return false;
348}
349
350
351} // namespace Input
352} // namespace Qt3DInput
353
354QT_END_NAMESPACE
355

source code of qt3d/src/input/backend/inputhandler.cpp