Revision control

++ // 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 <Qt3DCore/private/qscene_p.h>
++ #include <Qt3DInput/qmousehandler.h>
++ #include <Qt3DInput/qkeyboardhandler.h>
++ #include <Qt3DInput/private/assignkeyboardfocusjob_p.h>
++ #include <Qt3DInput/private/inputmanagers_p.h>
++ #include <Qt3DInput/private/inputsettings_p.h>
++ #include <Qt3DInput/private/qinputdeviceintegration_p.h>
++ #include <Qt3DInput/private/qmousehandler_p.h>
++ #include <Qt3DInput/private/qkeyboardhandler_p.h>
++ #include <Qt3DCore/private/qeventfilterservice_p.h>
++
++
++ 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<QT_PREPEND_NAMESPACE(QMouseEvent) *>(e));
++ case QEvent::HoverMove: {
++ const QHoverEvent *he = static_cast<QHoverEvent *>(e);
++ auto mouseEvent = QT_PREPEND_NAMESPACE(QMouseEvent)(QEvent::MouseMove,
++ he->position(),
++ he->globalPosition(),
++ Qt::NoButton, Qt::NoButton,
++ he->modifiers());
++ return processMouseEvent(obj, static_cast<QT_PREPEND_NAMESPACE(QMouseEvent) *>(&mouseEvent));
++ }
++ #if QT_CONFIG(wheelevent)
++ case QEvent::Wheel:
++ return processWheelEvent(obj, static_cast<QT_PREPEND_NAMESPACE(QWheelEvent) *>(e));
++ #endif
++ case QEvent::KeyPress:
++ case QEvent::KeyRelease:
++ return processKeyEvent(obj, static_cast<QT_PREPEND_NAMESPACE(QKeyEvent) *>(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<QInputDeviceIntegration *> 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<HMouseHandler> &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<QMouseHandler *>(m_inputHandler->m_scene->lookupNode(mouseHandler->peerId()));
++ if (node) {
++ QMouseHandlerPrivate *dnode = static_cast<QMouseHandlerPrivate *>(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<HMouseHandler> &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<QMouseHandler *>(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<QKeyboardHandler *>(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<QKeyboardHandler *>(m_inputHandler->m_scene->lookupNode(keyboardDevice->currentFocusItem()));
++ if (node) {
++ QKeyboardHandlerPrivate *dnode = static_cast<QKeyboardHandlerPrivate *>(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