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 "qinputaspect.h"
++ #include "qinputaspect_p.h"
++
++ #include <Qt3DInput/qabstractphysicaldevice.h>
++ #include <Qt3DInput/qaction.h>
++ #include <Qt3DInput/qactioninput.h>
++ #include <Qt3DInput/qanalogaxisinput.h>
++ #include <Qt3DInput/qaxis.h>
++ #include <Qt3DInput/qaxisaccumulator.h>
++ #include <Qt3DInput/qaxissetting.h>
++ #include <Qt3DInput/qbuttonaxisinput.h>
++ #include <Qt3DInput/qinputchord.h>
++ #include <Qt3DInput/qinputsequence.h>
++ #include <Qt3DInput/qinputsettings.h>
++ #include <Qt3DInput/qkeyboarddevice.h>
++ #include <Qt3DInput/qkeyboardhandler.h>
++ #include <Qt3DInput/qlogicaldevice.h>
++ #include <Qt3DInput/qmousedevice.h>
++ #include <Qt3DInput/qmousehandler.h>
++ #include <QtCore/QDir>
++
++ #include <QtCore/QLibraryInfo>
++ #include <QtCore/QPluginLoader>
++
++ #include <Qt3DInput/private/backendnode_p.h>
++ #include <Qt3DInput/private/action_p.h>
++ #include <Qt3DInput/private/actioninput_p.h>
++ #include <Qt3DInput/private/axis_p.h>
++ #include <Qt3DInput/private/axisaccumulator_p.h>
++ #include <Qt3DInput/private/axisaccumulatorjob_p.h>
++ #include <Qt3DInput/private/axissetting_p.h>
++ #include <Qt3DInput/private/buttonaxisinput_p.h>
++ #include <Qt3DInput/private/genericdevicebackendnode_p.h>
++ #include <Qt3DInput/private/inputbackendnodefunctor_p.h>
++ #include <Qt3DInput/private/inputchord_p.h>
++ #include <Qt3DInput/private/inputhandler_p.h>
++ #include <Qt3DInput/private/inputmanagers_p.h>
++ #include <Qt3DInput/private/inputsequence_p.h>
++ #include <Qt3DInput/private/inputsettings_p.h>
++ #include <Qt3DInput/private/keyboarddevice_p.h>
++ #include <Qt3DInput/private/keyboardhandler_p.h>
++ #include <Qt3DInput/private/keyboardmousegenericdeviceintegration_p.h>
++ #include <Qt3DInput/private/loadproxydevicejob_p.h>
++ #include <Qt3DInput/private/logicaldevice_p.h>
++ #include <Qt3DInput/private/mousedevice_p.h>
++ #include <Qt3DInput/private/mousehandler_p.h>
++ #include <Qt3DInput/private/qabstractphysicaldeviceproxy_p.h>
++ #include <Qt3DInput/private/qgenericinputdevice_p.h>
++ #include <Qt3DInput/private/qinputdeviceintegration_p.h>
++ #include <Qt3DInput/private/qinputdeviceintegrationfactory_p.h>
++ #include <Qt3DInput/private/updateaxisactionjob_p.h>
++ #include <Qt3DCore/private/qeventfilterservice_p.h>
++ #include <Qt3DCore/private/qservicelocator_p.h>
++ #include <Qt3DCore/private/qaspectmanager_p.h>
++ #include <Qt3DCore/private/vector_helper_p.h>
++
++ #ifdef HAVE_QGAMEPAD
++ # include <Qt3DInput/private/qgamepadinput_p.h>
++ #endif
++
++ QT_BEGIN_NAMESPACE
++
++
++ namespace Qt3DInput {
++
++ using namespace Qt3DCore;
++
++ QInputAspectPrivate::QInputAspectPrivate()
++ : QAbstractAspectPrivate()
++ , m_inputHandler(new Input::InputHandler())
++ , m_keyboardMouseIntegration(new Input::KeyboardMouseGenericDeviceIntegration(m_inputHandler.data()))
++ , m_time(0)
++ {
++ }
++
++ /*!
++ \class Qt3DInput::QInputAspect
++ \inherits Qt3DCore::QAbstractAspect
++ \inmodule Qt3DInput
++ \brief Responsible for creating physical devices and handling associated jobs.
++ \since 5.5
++ \brief Handles mapping between front and backend nodes
++
++ QInputAspect is responsible for creating physical devices.
++ It is also the object responsible establishing the jobs to run at a particular time from the current input setup.
++ */
++
++ /*!
++ * Constructs a new QInputAspect with \a parent.
++ */
++ QInputAspect::QInputAspect(QObject *parent)
++ : QInputAspect(*new QInputAspectPrivate, parent)
++ {
++ }
++
++ /*! \internal */
++ QInputAspect::QInputAspect(QInputAspectPrivate &dd, QObject *parent)
++ : QAbstractAspect(dd, parent)
++ {
++ setObjectName(QStringLiteral("Input Aspect"));
++
++ qRegisterMetaType<Qt3DInput::QAbstractPhysicalDevice*>();
++
++ registerBackendType<QKeyboardDevice>(QBackendNodeMapperPtr(new Input::KeyboardDeviceFunctor(this, d_func()->m_inputHandler.data())));
++ registerBackendType<QKeyboardHandler>(QBackendNodeMapperPtr(new Input::KeyboardHandlerFunctor(d_func()->m_inputHandler.data())));
++ registerBackendType<QMouseDevice>(QBackendNodeMapperPtr(new Input::MouseDeviceFunctor(this, d_func()->m_inputHandler.data())));
++ registerBackendType<QMouseHandler>(QBackendNodeMapperPtr(new Input::MouseHandlerFunctor(d_func()->m_inputHandler.data())));
++ registerBackendType<QAxis>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::Axis, Input::AxisManager>(d_func()->m_inputHandler->axisManager())));
++ registerBackendType<QAxisAccumulator>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::AxisAccumulator, Input::AxisAccumulatorManager>(d_func()->m_inputHandler->axisAccumulatorManager())));
++ registerBackendType<QAnalogAxisInput>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::AnalogAxisInput, Input::AnalogAxisInputManager>(d_func()->m_inputHandler->analogAxisInputManager())));
++ registerBackendType<QButtonAxisInput>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::ButtonAxisInput, Input::ButtonAxisInputManager>(d_func()->m_inputHandler->buttonAxisInputManager())));
++ registerBackendType<QAxisSetting>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::AxisSetting, Input::AxisSettingManager>(d_func()->m_inputHandler->axisSettingManager())));
++ registerBackendType<Qt3DInput::QAction>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::Action, Input::ActionManager>(d_func()->m_inputHandler->actionManager())));
++ registerBackendType<QActionInput>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::ActionInput, Input::ActionInputManager>(d_func()->m_inputHandler->actionInputManager())));
++ registerBackendType<QInputChord>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::InputChord, Input::InputChordManager>(d_func()->m_inputHandler->inputChordManager())));
++ registerBackendType<QInputSequence>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::InputSequence, Input::InputSequenceManager>(d_func()->m_inputHandler->inputSequenceManager())));
++ registerBackendType<QLogicalDevice>(QBackendNodeMapperPtr(new Input::LogicalDeviceNodeFunctor(d_func()->m_inputHandler->logicalDeviceManager())));
++ registerBackendType<QGenericInputDevice>(QBackendNodeMapperPtr(new Input::GenericDeviceBackendFunctor(this, d_func()->m_inputHandler.data())));
++ registerBackendType<QInputSettings>(QBackendNodeMapperPtr(new Input::InputSettingsFunctor(d_func()->m_inputHandler.data())));
++ registerBackendType<QAbstractPhysicalDeviceProxy>(QBackendNodeMapperPtr(new Input::PhysicalDeviceProxyNodeFunctor(d_func()->m_inputHandler->physicalDeviceProxyManager())));
++
++ #ifdef HAVE_QGAMEPAD
++ registerBackendType<QGamepadInput>(QBackendNodeMapperPtr(new Input::GenericDeviceBackendFunctor(this, d_func()->m_inputHandler.data())));
++ #endif
++
++ Q_D(QInputAspect);
++ // Plugins are QInputDeviceIntegration instances
++ d->loadInputDevicePlugins();
++
++ // KeyboardDevice and MouseDevice also provide their own QInputDeviceIntegration
++ d->m_inputHandler->addInputDeviceIntegration(d->m_keyboardMouseIntegration.data());
++ }
++
++ /*! \internal */
++ QInputAspect::~QInputAspect()
++ {
++ }
++
++ /*
++ Create each of the detected input device integrations through the Integration Factory
++ */
++ void QInputAspectPrivate::loadInputDevicePlugins()
++ {
++ const QStringList keys = QInputDeviceIntegrationFactory::keys();
++ for (const QString &key : keys) {
++ Qt3DInput::QInputDeviceIntegration *integration = QInputDeviceIntegrationFactory::create(key, QStringList());
++ if (integration != nullptr) {
++ m_inputHandler->addInputDeviceIntegration(integration);
++ // Initialize will allow the InputDeviceIntegration to
++ // register their frontend / backend types,
++ // create their managers
++ // launch a thread to listen to the actual physical device....
++ integration->initialize(q_func());
++ }
++ }
++ }
++
++ /*!
++ Create a physical device identified by \a name using the input device integrations present
++ returns a \c nullptr if it is not found.
++
++ \note Caller is responsible for ownership.
++ */
++ QAbstractPhysicalDevice *QInputAspect::createPhysicalDevice(const QString &name)
++ {
++ Q_D(QInputAspect);
++ return d->m_inputHandler->createPhysicalDevice(name);
++ }
++
++ /*!
++ Returns a list of all available physical devices.
++ */
++ QStringList QInputAspect::availablePhysicalDevices() const
++ {
++ Q_D(const QInputAspect);
++ QStringList deviceNamesList;
++ const auto deviceIntegrations = d->m_inputHandler->inputDeviceIntegrations();
++ for (const QInputDeviceIntegration *integration : deviceIntegrations)
++ deviceNamesList += integration->deviceNames();
++ return deviceNamesList;
++ }
++
++ /*!
++ \internal
++ */
++ std::vector<QAspectJobPtr> QInputAspect::jobsToExecute(qint64 time)
++ {
++ Q_D(QInputAspect);
++ const qint64 deltaTime = time - d->m_time;
++ const float dt = static_cast<float>(deltaTime) / 1.0e9f;
++ d->m_time = time;
++
++ std::vector<QAspectJobPtr> jobs;
++
++ d->m_inputHandler->updateEventSource();
++
++ // Mouse and keyboard handlers will have seen the events already.
++ // All we need now is to update the axis and the accumulators since
++ // they depend on time, and other bookkeeping.
++
++ const auto integrations = d->m_inputHandler->inputDeviceIntegrations();
++ for (QInputDeviceIntegration *integration : integrations) {
++ std::vector<QAspectJobPtr> integrationJobs = integration->jobsToExecute(time);
++ Qt3DCore::moveAtEnd(jobs, std::move(integrationJobs));
++ }
++
++ const QList<Qt3DCore::QNodeId> proxiesToLoad = d->m_inputHandler->physicalDeviceProxyManager()->takePendingProxiesToLoad();
++ if (!proxiesToLoad.isEmpty()) {
++ // Since loading wrappers occurs quite rarely, no point in keeping the job in a
++ // member variable
++ auto loadWrappersJob = Input::LoadProxyDeviceJobPtr::create();
++ loadWrappersJob->setProxiesToLoad(std::move(proxiesToLoad));
++ loadWrappersJob->setInputHandler(d->m_inputHandler.data());
++ jobs.push_back(loadWrappersJob);
++ }
++
++ // All the jobs added up until this point are independents
++ // but the axis action jobs will be dependent on these
++ const std::vector<QAspectJobPtr> dependsOnJobs = jobs;
++
++ // Jobs that update Axis/Action (store combined axis/action value)
++ const auto devHandles = d->m_inputHandler->logicalDeviceManager()->activeDevices();
++ std::vector<QAspectJobPtr> axisActionJobs;
++ axisActionJobs.reserve(devHandles.size());
++ for (const Input::HLogicalDevice &devHandle : devHandles) {
++ const auto device = d->m_inputHandler->logicalDeviceManager()->data(devHandle);
++ if (!device->isEnabled())
++ continue;
++
++ QAspectJobPtr updateAxisActionJob(new Input::UpdateAxisActionJob(time, d->m_inputHandler.data(), devHandle));
++ jobs.push_back(updateAxisActionJob);
++ axisActionJobs.push_back(updateAxisActionJob);
++ for (const QAspectJobPtr &job : dependsOnJobs)
++ updateAxisActionJob->addDependency(job);
++ }
++
++ // Once all the axes have been updated we can step the integrations on
++ // the AxisAccumulators
++ auto accumulateJob = Input::AxisAccumulatorJobPtr::create(d->m_inputHandler->axisAccumulatorManager(),
++ d->m_inputHandler->axisManager());
++ accumulateJob->setDeltaTime(dt);
++ for (const QAspectJobPtr &job : std::as_const(axisActionJobs))
++ accumulateJob->addDependency(job);
++ jobs.push_back(accumulateJob);
++
++ return jobs;
++ }
++
++ /*!
++ \internal
++ */
++ void QInputAspect::onRegistered()
++ {
++ Q_D(QInputAspect);
++ Qt3DCore::QEventFilterService *eventService = d->services()->eventFilterService();
++ Q_ASSERT(eventService);
++
++ // Set it on the input handler which will also handle its lifetime
++ d->m_inputHandler->setEventFilterService(eventService);
++ }
++
++ /*!
++ \internal
++ */
++ void QInputAspect::onUnregistered()
++ {
++ Q_D(QInputAspect);
++ // At this point it is too late to call removeEventFilter as the eventSource (Window)
++ // may already be destroyed
++ d->m_inputHandler.reset(nullptr);
++ }
++
++ void QInputAspect::onEngineStartup()
++ {
++ Q_D(QInputAspect);
++ d->m_inputHandler->setScene(d->m_aspectManager->scene());
++ }
++
++ void QInputAspect::jobsDone()
++ {
++ Q_D(QInputAspect);
++ d->m_inputHandler->resetMouseAxisState();
++ }
++
++ } // namespace Qt3DInput
++
++ QT_END_NAMESPACE
++
++ QT3D_REGISTER_NAMESPACED_ASPECT("input", QT_PREPEND_NAMESPACE(Qt3DInput), QInputAspect)
++
++ #include "moc_qinputaspect.cpp"