// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "inputhandler_p.h" #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE namespace Qt3DInput { namespace Input { using namespace Qt3DCore; class InternalEventFilter : public QObject { public: explicit InternalEventFilter(QObject *parent = nullptr) : QObject(parent), m_inputHandler(nullptr) { } ~InternalEventFilter() override; void setInputHandler(Qt3DInput::Input::InputHandler *handler) { m_inputHandler = handler; } inline Qt3DInput::Input::InputHandler *inputHandler() const { return m_inputHandler; } protected: bool eventFilter(QObject *obj, QEvent *e) override { switch (e->type()) { case QEvent::MouseMove: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: return processMouseEvent(obj, static_cast(e)); case QEvent::HoverMove: { const QHoverEvent *he = static_cast(e); auto mouseEvent = QT_PREPEND_NAMESPACE(QMouseEvent)(QEvent::MouseMove, he->position(), he->globalPosition(), Qt::NoButton, Qt::NoButton, he->modifiers()); return processMouseEvent(obj, static_cast(&mouseEvent)); } #if QT_CONFIG(wheelevent) case QEvent::Wheel: return processWheelEvent(obj, static_cast(e)); #endif case QEvent::KeyPress: case QEvent::KeyRelease: return processKeyEvent(obj, static_cast(e)); default: break; } return false; } bool processMouseEvent(QObject *obj, QT_PREPEND_NAMESPACE(QMouseEvent) *event); #if QT_CONFIG(wheelevent) bool processWheelEvent(QObject *obj, QT_PREPEND_NAMESPACE(QWheelEvent) *event); #endif bool processKeyEvent(QObject *obj, QT_PREPEND_NAMESPACE(QKeyEvent) *event); private: Qt3DInput::Input::InputHandler *m_inputHandler; }; InputHandler::InputHandler() : m_keyboardDeviceManager(new KeyboardDeviceManager()) , m_keyboardInputManager(new KeyboardInputManager()) , m_mouseDeviceManager(new MouseDeviceManager()) , m_mouseInputManager(new MouseInputManager()) , m_eventFilter(new InternalEventFilter()) , m_axisManager(new AxisManager()) , m_axisAccumulatorManager(new AxisAccumulatorManager()) , m_actionManager(new ActionManager()) , m_axisSettingManager(new AxisSettingManager()) , m_actionInputManager(new ActionInputManager()) , m_analogAxisInputManager(new AnalogAxisInputManager()) , m_buttonAxisInputManager(new ButtonAxisInputManager()) , m_inputChordManager(new InputChordManager()) , m_inputSequenceManager(new InputSequenceManager()) , m_logicalDeviceManager(new LogicalDeviceManager()) , m_genericPhysicalDeviceBackendNodeManager(new GenericDeviceBackendNodeManager) , m_physicalDeviceProxyManager(new PhysicalDeviceProxyManager()) , m_settings(nullptr) , m_service(nullptr) , m_lastEventSource(nullptr) { m_eventFilter->setInputHandler(this); } InputHandler::~InputHandler() { delete m_keyboardDeviceManager; delete m_keyboardInputManager; delete m_mouseDeviceManager; delete m_mouseInputManager; delete m_eventFilter; delete m_axisManager; delete m_axisAccumulatorManager; delete m_actionManager; delete m_axisSettingManager; delete m_analogAxisInputManager; delete m_buttonAxisInputManager; delete m_actionInputManager; delete m_inputChordManager; delete m_inputSequenceManager; delete m_logicalDeviceManager; delete m_genericPhysicalDeviceBackendNodeManager; delete m_physicalDeviceProxyManager; } // Called in MainThread (by the EventSourceHelperSetter) void InputHandler::registerEventFilters() { if (m_service) m_service->registerEventFilter(m_eventFilter, 512); } void InputHandler::unregisterEventFilters() { if (m_service) m_service->unregisterEventFilter(m_eventFilter); } void InputHandler::setInputSettings(InputSettings *settings) { if (m_settings && settings == nullptr) { unregisterEventFilters(); m_lastEventSource = nullptr; if (m_settings->eventSource() && m_service) m_service->shutdown(m_settings->eventSource()); } if (m_service) { unregisterEventFilters(); if (m_settings && m_settings->eventSource()) m_service->shutdown(m_settings->eventSource()); } m_settings = settings; } void InputHandler::updateEventSource() { // Called every frame from input aspect // Should probably just listen to changes in source property on settings object if (!m_settings || !m_service) return; // Will be updated only if eventSource is different than // what was set last QObject *eventSource = m_settings->eventSource(); if (eventSource && m_lastEventSource != eventSource) { m_service->initialize(eventSource); registerEventFilters(); m_lastEventSource = eventSource; } } void InputHandler::appendKeyboardDevice(HKeyboardDevice device) { m_activeKeyboardDevices.append(device); } void InputHandler::removeKeyboardDevice(HKeyboardDevice device) { m_activeKeyboardDevices.removeAll(device); } void InputHandler::appendMouseDevice(HMouseDevice device) { m_activeMouseDevices.append(device); } void InputHandler::removeMouseDevice(HMouseDevice device) { m_activeMouseDevices.removeAll(device); } void Qt3DInput::Input::InputHandler::appendGenericDevice(HGenericDeviceBackendNode device) { m_activeGenericPhysicalDevices.append(device); } void Qt3DInput::Input::InputHandler::removeGenericDevice(HGenericDeviceBackendNode device) { m_activeGenericPhysicalDevices.removeAll(device); } // called every frame to reset the void Qt3DInput::Input::InputHandler::resetMouseAxisState() { for (const HMouseDevice &cHandle : std::as_const(m_activeMouseDevices)) { MouseDevice *controller = m_mouseDeviceManager->data(cHandle); controller->resetMouseAxisState(); } } QList InputHandler::inputDeviceIntegrations() const { return m_inputDeviceIntegrations; } void InputHandler::addInputDeviceIntegration(QInputDeviceIntegration *inputIntegration) { m_inputDeviceIntegrations.push_back(inputIntegration); } QAbstractPhysicalDevice *Qt3DInput::Input::InputHandler::createPhysicalDevice(const QString &name) { QAbstractPhysicalDevice *device = nullptr; for (Qt3DInput::QInputDeviceIntegration *integration : std::as_const(m_inputDeviceIntegrations)) { if ((device = integration->createPhysicalDevice(name)) != nullptr) break; } return device; } void Qt3DInput::Input::InputHandler::setEventFilterService(QEventFilterService *service) { m_service = service; } AbstractActionInput *InputHandler::lookupActionInput(Qt3DCore::QNodeId id) const { AbstractActionInput *input = nullptr; if ((input = actionInputManager()->lookupResource(id)) != nullptr) return input; if ((input = inputSequenceManager()->lookupResource(id)) != nullptr) return input; return inputChordManager()->lookupResource(id); // nullptr if not found } InternalEventFilter::~InternalEventFilter() = default; bool InternalEventFilter::processMouseEvent(QObject *obj, QT_PREPEND_NAMESPACE(QMouseEvent) *event) { Q_UNUSED(obj); Q_ASSERT(m_inputHandler); if (!m_inputHandler->m_scene) return false; for (const HMouseDevice &cHandle : std::as_const(m_inputHandler->m_activeMouseDevices)) { MouseDevice *controller = m_inputHandler->m_mouseDeviceManager->data(cHandle); controller->updateMouseEvent(event); // Send the events to the mouse handlers that have for sourceDevice controller const std::vector &activeMouseHandlers = m_inputHandler->m_mouseInputManager->activeHandles(); for (const HMouseHandler &mouseHandlerHandle : activeMouseHandlers) { MouseHandler *mouseHandler = m_inputHandler->m_mouseInputManager->data(mouseHandlerHandle); Q_ASSERT(mouseHandler); if (mouseHandler->mouseDevice() == controller->peerId()) { QMouseHandler *node = qobject_cast(m_inputHandler->m_scene->lookupNode(mouseHandler->peerId())); QMouseHandlerPrivate *dnode = static_cast(QMouseHandlerPrivate::get(node)); dnode->mouseEvent(QMouseEventPtr::create(*event)); // Do we really need Qt3D specific events? } } } return false; } #if QT_CONFIG(wheelevent) bool InternalEventFilter::processWheelEvent(QObject *obj, QT_PREPEND_NAMESPACE(QWheelEvent) *event) { Q_UNUSED(obj); Q_ASSERT(m_inputHandler); if (!m_inputHandler->m_scene) return false; for (const HMouseDevice &cHandle : std::as_const(m_inputHandler->m_activeMouseDevices)) { MouseDevice *controller = m_inputHandler->m_mouseDeviceManager->data(cHandle); controller->updateWheelEvent(event); // Send the events to the mouse handlers that have for sourceDevice controller const std::vector &activeMouseHandlers = m_inputHandler->m_mouseInputManager->activeHandles(); for (const HMouseHandler &mouseHandlerHandle : activeMouseHandlers) { MouseHandler *mouseHandler = m_inputHandler->m_mouseInputManager->data(mouseHandlerHandle); Q_ASSERT(mouseHandler); if (mouseHandler->mouseDevice() == controller->peerId()) { QMouseHandler *node = qobject_cast(m_inputHandler->m_scene->lookupNode(mouseHandler->peerId())); QWheelEvent we(*event); node->wheel(&we); // Do we really need Qt3D specific events? } } } return false; } #endif bool InternalEventFilter::processKeyEvent(QObject *obj, QT_PREPEND_NAMESPACE(QKeyEvent) *event) { Q_UNUSED(obj); Q_ASSERT(m_inputHandler); if (!m_inputHandler->m_scene) return false; for (const HKeyboardDevice &cHandle : std::as_const(m_inputHandler->m_activeKeyboardDevices)) { KeyboardDevice *keyboardDevice = m_inputHandler->m_keyboardDeviceManager->data(cHandle); if (keyboardDevice) { keyboardDevice->updateKeyEvent(event); // update the focus if (keyboardDevice->lastKeyboardInputRequester() != keyboardDevice->currentFocusItem()) { const auto handles = m_inputHandler->keyboardInputManager()->activeHandles(); for (const HKeyboardHandler &handle : handles) { KeyboardHandler *input = m_inputHandler->keyboardInputManager()->data(handle); Q_ASSERT(input); if (input->keyboardDevice() == keyboardDevice->peerId()) { bool hasFocus = input->peerId() == keyboardDevice->lastKeyboardInputRequester(); input->setFocus(hasFocus); QKeyboardHandler *node = qobject_cast(m_inputHandler->m_scene->lookupNode(input->peerId())); if (node) { const bool b = node->blockNotifications(true); node->setFocus(hasFocus); node->blockNotifications(b); } if (hasFocus) keyboardDevice->setCurrentFocusItem(input->peerId()); } } } // deliver the event QKeyboardHandler *node = qobject_cast(m_inputHandler->m_scene->lookupNode(keyboardDevice->currentFocusItem())); if (node) { QKeyboardHandlerPrivate *dnode = static_cast(QKeyboardHandlerPrivate::get(node)); QKeyEvent ke(*event); dnode->keyEvent(&ke); // Do we really need Qt3D specific events? } } } return false; } } // namespace Input } // namespace Qt3DInput QT_END_NAMESPACE