mirror of
https://github.com/overte-org/overte.git
synced 2025-04-09 13:02:24 +02:00
trying to fix HUD events, abstracting touch event logic (wip), seth's comments
This commit is contained in:
parent
dd4275430b
commit
ce58b6c401
21 changed files with 304 additions and 233 deletions
|
@ -1504,14 +1504,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
|
||||
});
|
||||
|
||||
auto pointerManager = DependencyManager::get<PointerManager>();
|
||||
connect(pointerManager.data(), &PointerManager::hoverBeginHUD, this, &Application::handleHUDPointerEvent);
|
||||
connect(pointerManager.data(), &PointerManager::hoverContinueHUD, this, &Application::handleHUDPointerEvent);
|
||||
connect(pointerManager.data(), &PointerManager::hoverEndHUD, this, &Application::handleHUDPointerEvent);
|
||||
connect(pointerManager.data(), &PointerManager::triggerBeginHUD, this, &Application::handleHUDPointerEvent);
|
||||
connect(pointerManager.data(), &PointerManager::triggerContinueHUD, this, &Application::handleHUDPointerEvent);
|
||||
connect(pointerManager.data(), &PointerManager::triggerEndHUD, this, &Application::handleHUDPointerEvent);
|
||||
|
||||
// Add periodic checks to send user activity data
|
||||
static int CHECK_NEARBY_AVATARS_INTERVAL_MS = 10000;
|
||||
static int NEARBY_AVATAR_RADIUS_METERS = 10;
|
||||
|
@ -3304,7 +3296,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
|
|||
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
auto eventPosition = compositor.getMouseEventPosition(event);
|
||||
QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition, _glWidget);
|
||||
QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition);
|
||||
auto button = event->button();
|
||||
auto buttons = event->buttons();
|
||||
// Determine if the ReticleClick Action is 1 and if so, fake include the LeftMouseButton
|
||||
|
@ -3350,7 +3342,7 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
|||
offscreenUi->unfocusWindows();
|
||||
|
||||
auto eventPosition = getApplicationCompositor().getMouseEventPosition(event);
|
||||
QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition, _glWidget);
|
||||
QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition);
|
||||
QMouseEvent mappedEvent(event->type(),
|
||||
transformedPos,
|
||||
event->screenPos(), event->button(),
|
||||
|
@ -3380,7 +3372,7 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
|||
void Application::mouseDoublePressEvent(QMouseEvent* event) {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
auto eventPosition = getApplicationCompositor().getMouseEventPosition(event);
|
||||
QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition, _glWidget);
|
||||
QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition);
|
||||
QMouseEvent mappedEvent(event->type(),
|
||||
transformedPos,
|
||||
event->screenPos(), event->button(),
|
||||
|
@ -3406,7 +3398,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event) {
|
|||
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
auto eventPosition = getApplicationCompositor().getMouseEventPosition(event);
|
||||
QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition, _glWidget);
|
||||
QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition);
|
||||
QMouseEvent mappedEvent(event->type(),
|
||||
transformedPos,
|
||||
event->screenPos(), event->button(),
|
||||
|
@ -7487,32 +7479,4 @@ void Application::setAvatarOverrideUrl(const QUrl& url, bool save) {
|
|||
_avatarOverrideUrl = url;
|
||||
_saveAvatarOverrideUrl = save;
|
||||
}
|
||||
|
||||
void Application::handleHUDPointerEvent(const QUuid& id, const PointerEvent& event) {
|
||||
QEvent::Type type = QEvent::Type::MouseMove;
|
||||
switch (event.getType()) {
|
||||
case PointerEvent::Press:
|
||||
type = QEvent::Type::MouseButtonPress;
|
||||
break;
|
||||
case PointerEvent::DoublePress:
|
||||
type = QEvent::Type::MouseButtonDblClick;
|
||||
break;
|
||||
case PointerEvent::Release:
|
||||
type = QEvent::Type::MouseButtonRelease;
|
||||
break;
|
||||
case PointerEvent::Move:
|
||||
type = QEvent::Type::MouseMove;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
QPointF screenPos(event.getPos2D().x, event.getPos2D().y);
|
||||
//QMouseEvent mouseEvent(type, screenPos, Qt::MouseButton(event.getButton()), Qt::MouseButtons(event.getButtons()), event.getKeyboardModifiers());
|
||||
QMouseEvent moveEvent(QEvent::Type::MouseMove, screenPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
|
||||
sendEvent(_glWidget, &moveEvent);
|
||||
QMouseEvent mouseEvent(type, screenPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
|
||||
sendEvent(_glWidget, &mouseEvent);
|
||||
}
|
||||
|
||||
#include "Application.moc"
|
||||
|
|
|
@ -434,8 +434,6 @@ private slots:
|
|||
|
||||
void handleSandboxStatus(QNetworkReply* reply);
|
||||
void switchDisplayMode();
|
||||
|
||||
void handleHUDPointerEvent(const QUuid& id, const PointerEvent& event);
|
||||
private:
|
||||
static void initDisplay();
|
||||
void init();
|
||||
|
|
|
@ -303,7 +303,7 @@ PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const Q
|
|||
} else if (target.type == HUD) {
|
||||
pos2D = DependencyManager::get<PickManager>()->calculatePos2DFromHUD(intersection);
|
||||
}
|
||||
return PointerEvent(PointerEvent::Move, 0, pos2D, intersection, surfaceNormal, direction, PointerEvent::NoButtons);
|
||||
return PointerEvent(pos2D, intersection, surfaceNormal, direction);
|
||||
}
|
||||
|
||||
glm::vec3 LaserPointer::intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat rotation, const glm::vec3& registration) const {
|
||||
|
|
|
@ -25,7 +25,7 @@ unsigned int PickScriptingInterface::createPick(const PickQuery::PickType type,
|
|||
case PickQuery::PickType::Ray:
|
||||
return createRayPick(properties);
|
||||
default:
|
||||
return 0;
|
||||
return PickManager::INVALID_PICK_ID;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ unsigned int PickScriptingInterface::createRayPick(const QVariant& properties) {
|
|||
return DependencyManager::get<PickManager>()->addPick(PickQuery::Ray, std::make_shared<StaticRayPick>(position, direction, filter, maxDistance, enabled));
|
||||
}
|
||||
|
||||
return 0;
|
||||
return PickManager::INVALID_PICK_ID;
|
||||
}
|
||||
|
||||
void PickScriptingInterface::enablePick(unsigned int uid) {
|
||||
|
|
|
@ -26,7 +26,7 @@ unsigned int PointerScriptingInterface::createPointer(const PickQuery::PickType&
|
|||
case PickQuery::PickType::Ray:
|
||||
return createLaserPointer(properties);
|
||||
default:
|
||||
return 0;
|
||||
return PointerEvent::INVALID_POINTER_ID;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -315,111 +315,17 @@ void WebEntityRenderer::loadSourceURL() {
|
|||
}
|
||||
|
||||
void WebEntityRenderer::hoverLeaveEntity(const PointerEvent& event) {
|
||||
if (!_lastLocked && _webSurface && _pressed && event.sendReleaseOnHoverLeave()) {
|
||||
PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(),
|
||||
event.getButton(), event.getButtons(), event.getKeyboardModifiers());
|
||||
handlePointerEvent(endEvent);
|
||||
// QML onReleased is only triggered if a click has happened first. We need to send this "fake" mouse move event to properly trigger an onExited.
|
||||
PointerEvent endMoveEvent(PointerEvent::Move, event.getID());
|
||||
handlePointerEvent(endMoveEvent);
|
||||
if (!_lastLocked && _webSurface) {
|
||||
_webSurface->hoverEndEvent(event, _touchDevice);
|
||||
}
|
||||
}
|
||||
|
||||
void WebEntityRenderer::handlePointerEvent(const PointerEvent& event) {
|
||||
void WebEntityRenderer::handlePointerEvent(PointerEvent& event) {
|
||||
event.setPos2D(event.getPos2D() * (METERS_TO_INCHES * _lastDPI));
|
||||
// Ignore mouse interaction if we're locked
|
||||
if (_lastLocked || !_webSurface) {
|
||||
return;
|
||||
if (!_lastLocked && _webSurface) {
|
||||
_webSurface->handlePointerEvent(event, _touchDevice);
|
||||
}
|
||||
|
||||
if (event.getType() == PointerEvent::Press) {
|
||||
_pressed = true;
|
||||
} else if (event.getType() == PointerEvent::Release) {
|
||||
_pressed = false;
|
||||
}
|
||||
|
||||
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _lastDPI);
|
||||
QPointF windowPoint(windowPos.x, windowPos.y);
|
||||
|
||||
Qt::TouchPointState state = Qt::TouchPointStationary;
|
||||
if (event.getType() == PointerEvent::Press && event.getButton() == PointerEvent::PrimaryButton) {
|
||||
state = Qt::TouchPointPressed;
|
||||
} else if (event.getType() == PointerEvent::Release) {
|
||||
state = Qt::TouchPointReleased;
|
||||
} else if (_activeTouchPoints.count(event.getID()) && windowPoint != _activeTouchPoints[event.getID()].pos()) {
|
||||
state = Qt::TouchPointMoved;
|
||||
}
|
||||
|
||||
QEvent::Type touchType = QEvent::TouchUpdate;
|
||||
if (_activeTouchPoints.empty()) {
|
||||
// If the first active touch point is being created, send a begin
|
||||
touchType = QEvent::TouchBegin;
|
||||
} if (state == Qt::TouchPointReleased && _activeTouchPoints.size() == 1 && _activeTouchPoints.count(event.getID())) {
|
||||
// If the last active touch point is being released, send an end
|
||||
touchType = QEvent::TouchEnd;
|
||||
}
|
||||
|
||||
{
|
||||
QTouchEvent::TouchPoint point;
|
||||
point.setId(event.getID());
|
||||
point.setState(state);
|
||||
point.setPos(windowPoint);
|
||||
point.setScreenPos(windowPoint);
|
||||
_activeTouchPoints[event.getID()] = point;
|
||||
}
|
||||
|
||||
QTouchEvent touchEvent(touchType, &_touchDevice, event.getKeyboardModifiers());
|
||||
{
|
||||
QList<QTouchEvent::TouchPoint> touchPoints;
|
||||
Qt::TouchPointStates touchPointStates;
|
||||
for (const auto& entry : _activeTouchPoints) {
|
||||
touchPointStates |= entry.second.state();
|
||||
touchPoints.push_back(entry.second);
|
||||
}
|
||||
|
||||
touchEvent.setWindow(_webSurface->getWindow());
|
||||
touchEvent.setDevice(&_touchDevice);
|
||||
touchEvent.setTarget(_webSurface->getRootItem());
|
||||
touchEvent.setTouchPoints(touchPoints);
|
||||
touchEvent.setTouchPointStates(touchPointStates);
|
||||
}
|
||||
|
||||
// Send mouse events to the Web surface so that HTML dialog elements work with mouse press and hover.
|
||||
//
|
||||
// In Qt 5.9 mouse events must be sent before touch events to make sure some QtQuick components will
|
||||
// receive mouse events
|
||||
Qt::MouseButton button = Qt::NoButton;
|
||||
Qt::MouseButtons buttons = Qt::NoButton;
|
||||
if (event.getButton() == PointerEvent::PrimaryButton) {
|
||||
button = Qt::LeftButton;
|
||||
}
|
||||
if (event.getButtons() & PointerEvent::PrimaryButton) {
|
||||
buttons |= Qt::LeftButton;
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
|
||||
if (event.getType() == PointerEvent::Move) {
|
||||
QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers());
|
||||
QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (touchType == QEvent::TouchBegin) {
|
||||
_touchBeginAccepted = QCoreApplication::sendEvent(_webSurface->getWindow(), &touchEvent);
|
||||
} else if (_touchBeginAccepted) {
|
||||
QCoreApplication::sendEvent(_webSurface->getWindow(), &touchEvent);
|
||||
}
|
||||
|
||||
// If this was a release event, remove the point from the active touch points
|
||||
if (state == Qt::TouchPointReleased) {
|
||||
_activeTouchPoints.erase(event.getID());
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 9, 0)
|
||||
if (event.getType() == PointerEvent::Move) {
|
||||
QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers());
|
||||
QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void WebEntityRenderer::setProxyWindow(QWindow* proxyWindow) {
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
#include <WebEntityItem.h>
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
#include <QTouchEvent>
|
||||
|
||||
class OffscreenQmlSurface;
|
||||
class PointerEvent;
|
||||
|
||||
|
@ -28,7 +26,7 @@ public:
|
|||
WebEntityRenderer(const EntityItemPointer& entity);
|
||||
|
||||
Q_INVOKABLE void hoverLeaveEntity(const PointerEvent& event);
|
||||
Q_INVOKABLE void handlePointerEvent(const PointerEvent& event);
|
||||
Q_INVOKABLE void handlePointerEvent(PointerEvent& event);
|
||||
|
||||
protected:
|
||||
virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override;
|
||||
|
@ -66,10 +64,6 @@ private:
|
|||
QTimer _timer;
|
||||
uint64_t _lastRenderTime { 0 };
|
||||
Transform _renderTransform;
|
||||
|
||||
bool _pressed{ false };
|
||||
bool _touchBeginAccepted{ false };
|
||||
std::map<uint32_t, QTouchEvent::TouchPoint> _activeTouchPoints;
|
||||
};
|
||||
|
||||
} } // namespace
|
||||
|
|
|
@ -206,4 +206,13 @@ public:
|
|||
virtual PickResultPointer getHUDIntersection(const T& pick) = 0;
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<PickQuery::PickType> {
|
||||
size_t operator()(const PickQuery::PickType& a) const {
|
||||
return a;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // hifi_Pick_h
|
||||
|
|
|
@ -37,7 +37,7 @@ template<typename T>
|
|||
class PickCacheOptimizer {
|
||||
|
||||
public:
|
||||
void update(QHash<unsigned int, std::shared_ptr<PickQuery>>& picks, bool shouldPickHUD);
|
||||
void update(std::unordered_map<unsigned int, std::shared_ptr<PickQuery>>& picks, bool shouldPickHUD);
|
||||
|
||||
protected:
|
||||
typedef std::unordered_map<T, std::unordered_map<PickCacheKey, PickResultPointer>> PickCache;
|
||||
|
@ -67,10 +67,11 @@ void PickCacheOptimizer<T>::cacheResult(const bool intersects, const PickResultP
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
void PickCacheOptimizer<T>::update(QHash<unsigned int, std::shared_ptr<PickQuery>>& picks, bool shouldPickHUD) {
|
||||
void PickCacheOptimizer<T>::update(std::unordered_map<unsigned int, std::shared_ptr<PickQuery>>& picks, bool shouldPickHUD) {
|
||||
PickCache results;
|
||||
for (const auto& uid : picks.keys()) {
|
||||
std::shared_ptr<Pick<T>> pick = std::static_pointer_cast<Pick<T>>(picks[uid]);
|
||||
for (const auto& pickPair : picks) {
|
||||
unsigned int uid = pickPair.first;
|
||||
std::shared_ptr<Pick<T>> pick = std::static_pointer_cast<Pick<T>>(pickPair.second);
|
||||
|
||||
T mathematicalPick = pick->getMathematicalPick();
|
||||
PickResultPointer res = pick->getDefaultResult(mathematicalPick.toVariantMap());
|
||||
|
|
|
@ -13,7 +13,7 @@ PickManager::PickManager() {
|
|||
}
|
||||
|
||||
unsigned int PickManager::addPick(PickQuery::PickType type, const std::shared_ptr<PickQuery> pick) {
|
||||
unsigned int id = 0;
|
||||
unsigned int id = INVALID_PICK_ID;
|
||||
withWriteLock([&] {
|
||||
// Don't let the pick IDs overflow
|
||||
if (_nextPickID < UINT32_MAX) {
|
||||
|
@ -29,7 +29,7 @@ std::shared_ptr<PickQuery> PickManager::findPick(unsigned int uid) const {
|
|||
return resultWithReadLock<std::shared_ptr<PickQuery>>([&] {
|
||||
auto type = _typeMap.find(uid);
|
||||
if (type != _typeMap.end()) {
|
||||
return _picks[type.value()][uid];
|
||||
return _picks.find(type->second)->second.find(uid)->second;
|
||||
}
|
||||
return std::shared_ptr<PickQuery>();
|
||||
});
|
||||
|
@ -39,8 +39,8 @@ void PickManager::removePick(unsigned int uid) {
|
|||
withWriteLock([&] {
|
||||
auto type = _typeMap.find(uid);
|
||||
if (type != _typeMap.end()) {
|
||||
_picks[type.value()].remove(uid);
|
||||
_typeMap.remove(uid);
|
||||
_picks[type->second].erase(uid);
|
||||
_typeMap.erase(uid);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ void PickManager::setIncludeItems(unsigned int uid, const QVector<QUuid>& includ
|
|||
}
|
||||
|
||||
void PickManager::update() {
|
||||
QHash<PickQuery::PickType, QHash<unsigned int, std::shared_ptr<PickQuery>>> cachedPicks;
|
||||
std::unordered_map<PickQuery::PickType, std::unordered_map<unsigned int, std::shared_ptr<PickQuery>>> cachedPicks;
|
||||
withReadLock([&] {
|
||||
cachedPicks = _picks;
|
||||
});
|
||||
|
|
|
@ -37,16 +37,16 @@ public:
|
|||
void setCalculatePos2DFromHUDOperator(std::function<glm::vec2(const glm::vec3&)> calculatePos2DFromHUDOperator) { _calculatePos2DFromHUDOperator = calculatePos2DFromHUDOperator; }
|
||||
glm::vec2 calculatePos2DFromHUD(const glm::vec3& intersection) { return _calculatePos2DFromHUDOperator(intersection); }
|
||||
|
||||
static const unsigned int INVALID_PICK_ID { 0 };
|
||||
|
||||
protected:
|
||||
std::function<bool()> _shouldPickHUDOperator;
|
||||
std::function<glm::vec2(const glm::vec3&)> _calculatePos2DFromHUDOperator;
|
||||
|
||||
std::shared_ptr<PickQuery> findPick(unsigned int uid) const;
|
||||
QHash<PickQuery::PickType, QHash<unsigned int, std::shared_ptr<PickQuery>>> _picks;
|
||||
QHash<unsigned int, PickQuery::PickType> _typeMap;
|
||||
// 0 = invalid
|
||||
const unsigned int FIRST_PICK_ID { 1 };
|
||||
unsigned int _nextPickID { FIRST_PICK_ID };
|
||||
std::unordered_map<PickQuery::PickType, std::unordered_map<unsigned int, std::shared_ptr<PickQuery>>> _picks;
|
||||
std::unordered_map<unsigned int, PickQuery::PickType> _typeMap;
|
||||
unsigned int _nextPickID { INVALID_PICK_ID + 1 };
|
||||
|
||||
PickCacheOptimizer<PickRay> _rayPickCacheOptimizer;
|
||||
};
|
||||
|
|
|
@ -95,7 +95,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p
|
|||
} else if (hoveredObject.type == OVERLAY) {
|
||||
emit pointerManager->hoverBeginOverlay(hoveredObject.objectID, hoveredEvent);
|
||||
} else if (hoveredObject.type == HUD) {
|
||||
emit pointerManager->hoverBeginHUD(hoveredObject.objectID, hoveredEvent);
|
||||
emit pointerManager->hoverBeginHUD(hoveredEvent);
|
||||
}
|
||||
} else if (_enabled && _hover && doHover) {
|
||||
if (hoveredObject.type == OVERLAY) {
|
||||
|
@ -114,7 +114,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p
|
|||
if (_prevHoveredObject.type == ENTITY) {
|
||||
emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent);
|
||||
} else if (_prevHoveredObject.type == HUD) {
|
||||
emit pointerManager->hoverEndHUD(_prevHoveredObject.objectID, hoveredEvent);
|
||||
emit pointerManager->hoverEndHUD(hoveredEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p
|
|||
if (_prevHoveredObject.type == OVERLAY) {
|
||||
emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent);
|
||||
} else if (_prevHoveredObject.type == HUD) {
|
||||
emit pointerManager->hoverEndHUD(_prevHoveredObject.objectID, hoveredEvent);
|
||||
emit pointerManager->hoverEndHUD(hoveredEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -144,9 +144,9 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p
|
|||
if (hoveredObject.type == HUD) {
|
||||
if (_prevHoveredObject.type == HUD) {
|
||||
// There's only one HUD
|
||||
emit pointerManager->hoverContinueHUD(hoveredObject.objectID, hoveredEvent);
|
||||
emit pointerManager->hoverContinueHUD(hoveredEvent);
|
||||
} else {
|
||||
emit pointerManager->hoverBeginHUD(hoveredObject.objectID, hoveredEvent);
|
||||
emit pointerManager->hoverBeginHUD(hoveredEvent);
|
||||
if (_prevHoveredObject.type == ENTITY) {
|
||||
emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent);
|
||||
} else if (_prevHoveredObject.type == OVERLAY) {
|
||||
|
@ -164,7 +164,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p
|
|||
} else if (_prevHoveredObject.type == OVERLAY) {
|
||||
emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent);
|
||||
} else if (_prevHoveredObject.type == HUD) {
|
||||
emit pointerManager->hoverEndHUD(_prevHoveredObject.objectID, hoveredEvent);
|
||||
emit pointerManager->hoverEndHUD(hoveredEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p
|
|||
} else if (hoveredObject.type == OVERLAY) {
|
||||
emit pointerManager->triggerBeginOverlay(hoveredObject.objectID, hoveredEvent);
|
||||
} else if (hoveredObject.type == HUD) {
|
||||
emit pointerManager->triggerBeginHUD(hoveredObject.objectID, hoveredEvent);
|
||||
emit pointerManager->triggerBeginHUD(hoveredEvent);
|
||||
}
|
||||
_triggeredObjects[button] = hoveredObject;
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p
|
|||
} else if (_triggeredObjects[button].type == OVERLAY) {
|
||||
emit pointerManager->triggerContinueOverlay(_triggeredObjects[button].objectID, triggeredEvent);
|
||||
} else if (_triggeredObjects[button].type == HUD) {
|
||||
emit pointerManager->triggerContinueHUD(_triggeredObjects[button].objectID, triggeredEvent);
|
||||
emit pointerManager->triggerContinueHUD(triggeredEvent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,7 +211,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p
|
|||
} else if (_triggeredObjects[button].type == OVERLAY) {
|
||||
emit pointerManager->triggerEndOverlay(_triggeredObjects[button].objectID, triggeredEvent);
|
||||
} else if (_triggeredObjects[button].type == HUD) {
|
||||
emit pointerManager->triggerEndHUD(_triggeredObjects[button].objectID, triggeredEvent);
|
||||
emit pointerManager->triggerEndHUD(triggeredEvent);
|
||||
}
|
||||
_triggeredObjects.erase(button);
|
||||
}
|
||||
|
|
|
@ -8,19 +8,21 @@
|
|||
|
||||
#include "PointerManager.h"
|
||||
|
||||
#include "PickManager.h"
|
||||
|
||||
std::shared_ptr<Pointer> PointerManager::find(unsigned int uid) const {
|
||||
return resultWithReadLock<std::shared_ptr<Pointer>>([&] {
|
||||
auto itr = _pointers.find(uid);
|
||||
if (itr != _pointers.end()) {
|
||||
return *itr;
|
||||
return itr->second;
|
||||
}
|
||||
return std::shared_ptr<Pointer>();
|
||||
});
|
||||
}
|
||||
|
||||
unsigned int PointerManager::addPointer(std::shared_ptr<Pointer> pointer) {
|
||||
unsigned int result = 0;
|
||||
if (pointer->getRayUID() > 0) {
|
||||
unsigned int result = PointerEvent::INVALID_POINTER_ID;
|
||||
if (pointer->getRayUID() != PickManager::INVALID_PICK_ID) {
|
||||
withWriteLock([&] {
|
||||
// Don't let the pointer IDs overflow
|
||||
if (_nextPointerID < UINT32_MAX) {
|
||||
|
@ -34,7 +36,7 @@ unsigned int PointerManager::addPointer(std::shared_ptr<Pointer> pointer) {
|
|||
|
||||
void PointerManager::removePointer(unsigned int uid) {
|
||||
withWriteLock([&] {
|
||||
_pointers.remove(uid);
|
||||
_pointers.erase(uid);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -75,12 +77,12 @@ const QVariantMap PointerManager::getPrevPickResult(unsigned int uid) const {
|
|||
}
|
||||
|
||||
void PointerManager::update() {
|
||||
auto cachedPointers = resultWithReadLock<QHash<unsigned int, std::shared_ptr<Pointer>>>([&] {
|
||||
auto cachedPointers = resultWithReadLock<std::unordered_map<unsigned int, std::shared_ptr<Pointer>>>([&] {
|
||||
return _pointers;
|
||||
});
|
||||
|
||||
for (const auto& uid : cachedPointers.keys()) {
|
||||
cachedPointers[uid]->update(uid);
|
||||
for (const auto& pointerPair : cachedPointers) {
|
||||
pointerPair.second->update(pointerPair.first);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,11 +40,12 @@ public:
|
|||
|
||||
void update();
|
||||
|
||||
static const unsigned int MOUSE_POINTER_ID { PointerEvent::INVALID_POINTER_ID + 1 };
|
||||
|
||||
private:
|
||||
std::shared_ptr<Pointer> find(unsigned int uid) const;
|
||||
QHash<unsigned int, std::shared_ptr<Pointer>> _pointers;
|
||||
// 0 = invalid, 1 = reserved for system mouse
|
||||
unsigned int _nextPointerID { 2 };
|
||||
std::unordered_map<unsigned int, std::shared_ptr<Pointer>> _pointers;
|
||||
unsigned int _nextPointerID { MOUSE_POINTER_ID + 1 };
|
||||
|
||||
signals:
|
||||
void triggerBeginOverlay(const QUuid& id, const PointerEvent& pointerEvent);
|
||||
|
@ -61,12 +62,12 @@ signals:
|
|||
void hoverContinueEntity(const QUuid& id, const PointerEvent& pointerEvent);
|
||||
void hoverEndEntity(const QUuid& id, const PointerEvent& pointerEvent);
|
||||
|
||||
void triggerBeginHUD(const QUuid& id, const PointerEvent& pointerEvent);
|
||||
void triggerContinueHUD(const QUuid& id, const PointerEvent& pointerEvent);
|
||||
void triggerEndHUD(const QUuid& id, const PointerEvent& pointerEvent);
|
||||
void hoverBeginHUD(const QUuid& id, const PointerEvent& pointerEvent);
|
||||
void hoverContinueHUD(const QUuid& id, const PointerEvent& pointerEvent);
|
||||
void hoverEndHUD(const QUuid& id, const PointerEvent& pointerEvent);
|
||||
void triggerBeginHUD(const PointerEvent& pointerEvent);
|
||||
void triggerContinueHUD(const PointerEvent& pointerEvent);
|
||||
void triggerEndHUD(const PointerEvent& pointerEvent);
|
||||
void hoverBeginHUD(const PointerEvent& pointerEvent);
|
||||
void hoverContinueHUD(const PointerEvent& pointerEvent);
|
||||
void hoverEndHUD(const PointerEvent& pointerEvent);
|
||||
};
|
||||
|
||||
#endif // hifi_pointers_PointerManager_h
|
||||
|
|
|
@ -20,8 +20,28 @@ static bool areFlagsSet(uint32_t flags, uint32_t mask) {
|
|||
return (flags & mask) != 0;
|
||||
}
|
||||
|
||||
PointerEvent::PointerEvent() {
|
||||
;
|
||||
PointerEvent::PointerEvent(EventType type, uint32_t id) :
|
||||
_type(type),
|
||||
_id(id)
|
||||
{
|
||||
}
|
||||
|
||||
PointerEvent::PointerEvent(EventType type, uint32_t id, const glm::vec2& pos2D, Button button, uint32_t buttons, Qt::KeyboardModifiers keyboardModifiers) :
|
||||
_type(type),
|
||||
_id(id),
|
||||
_pos2D(pos2D),
|
||||
_button(button),
|
||||
_buttons(buttons),
|
||||
_keyboardModifiers(keyboardModifiers)
|
||||
{
|
||||
}
|
||||
|
||||
PointerEvent::PointerEvent(const glm::vec2& pos2D, const glm::vec3& pos3D, const glm::vec3& normal, const glm::vec3& direction) :
|
||||
_pos2D(pos2D),
|
||||
_pos3D(pos3D),
|
||||
_normal(normal),
|
||||
_direction(direction)
|
||||
{
|
||||
}
|
||||
|
||||
PointerEvent::PointerEvent(EventType type, uint32_t id,
|
||||
|
@ -38,7 +58,6 @@ PointerEvent::PointerEvent(EventType type, uint32_t id,
|
|||
_buttons(buttons),
|
||||
_keyboardModifiers(keyboardModifiers)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void PointerEvent::setButton(Button button) {
|
||||
|
|
|
@ -35,11 +35,14 @@ public:
|
|||
NumEventTypes
|
||||
};
|
||||
|
||||
PointerEvent();
|
||||
PointerEvent() {}
|
||||
PointerEvent(EventType type, uint32_t id);
|
||||
PointerEvent(EventType type, uint32_t id, const glm::vec2& pos2D, Button button, uint32_t buttons, Qt::KeyboardModifiers keyboardModifiers);
|
||||
PointerEvent(const glm::vec2& pos2D, const glm::vec3& pos3D, const glm::vec3& normal, const glm::vec3& direction);
|
||||
PointerEvent(EventType type, uint32_t id,
|
||||
const glm::vec2& pos2D = glm::vec2(NAN), const glm::vec3& pos3D = glm::vec3(NAN),
|
||||
const glm::vec3& normal = glm::vec3(NAN), const glm::vec3& direction = glm::vec3(NAN),
|
||||
Button button = NoButtons, uint32_t buttons = NoButtons, Qt::KeyboardModifiers keyboardModifiers = Qt::KeyboardModifier::NoModifier);
|
||||
const glm::vec2& pos2D, const glm::vec3& pos3D,
|
||||
const glm::vec3& normal, const glm::vec3& direction,
|
||||
Button button, uint32_t buttons, Qt::KeyboardModifiers keyboardModifiers);
|
||||
|
||||
static QScriptValue toScriptValue(QScriptEngine* engine, const PointerEvent& event);
|
||||
static void fromScriptValue(const QScriptValue& object, PointerEvent& event);
|
||||
|
@ -63,18 +66,21 @@ public:
|
|||
void setButton(Button button);
|
||||
void setShouldFocus(bool focus) { _shouldFocus = focus; }
|
||||
void setReleaseOnHoverLeave(bool releaseOnHoverLeave) { _releaseOnHoverLeave = releaseOnHoverLeave; }
|
||||
void setPos2D(const glm::vec2& pos2D) { _pos2D = pos2D; }
|
||||
|
||||
static const unsigned int INVALID_POINTER_ID { 0 };
|
||||
|
||||
private:
|
||||
EventType _type;
|
||||
uint32_t _id; // used to identify the pointer. (left vs right hand, for example)
|
||||
glm::vec2 _pos2D; // (in meters) projected onto the xy plane of entities dimension box, (0, 0) is upper right hand corner
|
||||
glm::vec3 _pos3D; // surface location in world coordinates (in meters)
|
||||
glm::vec3 _normal; // surface normal
|
||||
glm::vec3 _direction; // incoming direction of pointer ray.
|
||||
uint32_t _id { INVALID_POINTER_ID }; // used to identify the pointer. (left vs right hand, for example)
|
||||
glm::vec2 _pos2D { glm::vec2(NAN) }; // (in meters) projected onto the xy plane of entities dimension box, (0, 0) is upper right hand corner
|
||||
glm::vec3 _pos3D { glm::vec3(NAN) }; // surface location in world coordinates (in meters)
|
||||
glm::vec3 _normal { glm::vec3(NAN) }; // surface normal
|
||||
glm::vec3 _direction { glm::vec3(NAN) }; // incoming direction of pointer ray.
|
||||
|
||||
Button _button { NoButtons }; // button associated with this event, (if type is Press, this will be the button that is pressed)
|
||||
uint32_t _buttons { NoButtons }; // the current state of all the buttons.
|
||||
Qt::KeyboardModifiers _keyboardModifiers; // set of keys held when event was generated
|
||||
Qt::KeyboardModifiers _keyboardModifiers { Qt::KeyboardModifier::NoModifier }; // set of keys held when event was generated
|
||||
|
||||
bool _shouldFocus { true };
|
||||
bool _releaseOnHoverLeave { true };
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
set(TARGET_NAME ui)
|
||||
setup_hifi_library(OpenGL Network Qml Quick Script WebChannel WebEngine WebSockets XmlPatterns)
|
||||
link_hifi_libraries(shared networking gl audio)
|
||||
link_hifi_libraries(shared networking gl audio pointers)
|
||||
include_hifi_library_headers(controllers)
|
||||
|
||||
# Required for some low level GL interaction in the OffscreenQMLSurface
|
||||
target_opengl()
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "ui/Logging.h"
|
||||
|
||||
#include <pointers/PointerManager.h>
|
||||
|
||||
// Needs to match the constants in resources/qml/Global.js
|
||||
class OffscreenFlags : public QObject {
|
||||
|
@ -84,7 +85,31 @@ bool OffscreenUi::shouldSwallowShortcut(QEvent* event) {
|
|||
return false;
|
||||
}
|
||||
|
||||
static QTouchDevice _touchDevice;
|
||||
OffscreenUi::OffscreenUi() {
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
_touchDevice.setCapabilities(QTouchDevice::Position);
|
||||
_touchDevice.setType(QTouchDevice::TouchScreen);
|
||||
_touchDevice.setName("OffscreenUiTouchDevice");
|
||||
_touchDevice.setMaximumTouchPoints(4);
|
||||
});
|
||||
|
||||
auto pointerManager = DependencyManager::get<PointerManager>();
|
||||
connect(pointerManager.data(), &PointerManager::hoverBeginHUD, this, &OffscreenUi::handlePointerEvent);
|
||||
connect(pointerManager.data(), &PointerManager::hoverContinueHUD, this, &OffscreenUi::handlePointerEvent);
|
||||
connect(pointerManager.data(), &PointerManager::hoverEndHUD, this, &OffscreenUi::hoverEndEvent);
|
||||
connect(pointerManager.data(), &PointerManager::triggerBeginHUD, this, &OffscreenUi::handlePointerEvent);
|
||||
connect(pointerManager.data(), &PointerManager::triggerContinueHUD, this, &OffscreenUi::handlePointerEvent);
|
||||
connect(pointerManager.data(), &PointerManager::triggerEndHUD, this, &OffscreenUi::handlePointerEvent);
|
||||
}
|
||||
|
||||
void OffscreenUi::hoverEndEvent(const PointerEvent& event) {
|
||||
OffscreenQmlSurface::hoverEndEvent(event, _touchDevice);
|
||||
}
|
||||
|
||||
void OffscreenUi::handlePointerEvent(const PointerEvent& event) {
|
||||
OffscreenQmlSurface::handlePointerEvent(event, _touchDevice);
|
||||
}
|
||||
|
||||
QObject* OffscreenUi::getFlags() {
|
||||
|
@ -1072,6 +1097,23 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) {
|
|||
// let the parent class do it's work
|
||||
bool result = OffscreenQmlSurface::eventFilter(originalDestination, event);
|
||||
|
||||
switch (event->type()) {
|
||||
// Fall through
|
||||
case QEvent::MouseButtonDblClick:
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::MouseMove: {
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
QPointF transformedPos = mapToVirtualScreen(mouseEvent->localPos());
|
||||
PointerEvent pointerEvent(choosePointerEventType(mouseEvent->type()), PointerManager::MOUSE_POINTER_ID, glm::vec2(transformedPos.x(), transformedPos.y()),
|
||||
PointerEvent::Button(mouseEvent->button()), mouseEvent->buttons(), mouseEvent->modifiers());
|
||||
result = OffscreenQmlSurface::handlePointerEvent(pointerEvent, _touchDevice);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// Check if this is a key press/release event that might need special attention
|
||||
auto type = event->type();
|
||||
|
|
|
@ -249,6 +249,10 @@ signals:
|
|||
public slots:
|
||||
void removeModalDialog(QObject* modal);
|
||||
|
||||
private slots:
|
||||
void hoverEndEvent(const PointerEvent& event);
|
||||
void handlePointerEvent(const PointerEvent& event);
|
||||
|
||||
private:
|
||||
QString fileDialog(const QVariantMap& properties);
|
||||
ModalDialogListener *fileDialogAsync(const QVariantMap &properties);
|
||||
|
|
|
@ -855,7 +855,7 @@ QPointF OffscreenQmlSurface::mapWindowToUi(const QPointF& sourcePosition, QObjec
|
|||
return QPointF(offscreenPosition.x, offscreenPosition.y);
|
||||
}
|
||||
|
||||
QPointF OffscreenQmlSurface::mapToVirtualScreen(const QPointF& originalPoint, QObject* originalWidget) {
|
||||
QPointF OffscreenQmlSurface::mapToVirtualScreen(const QPointF& originalPoint) {
|
||||
return _mouseTranslator(originalPoint);
|
||||
}
|
||||
|
||||
|
@ -909,7 +909,7 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even
|
|||
|
||||
case QEvent::Wheel: {
|
||||
QWheelEvent* wheelEvent = static_cast<QWheelEvent*>(event);
|
||||
QPointF transformedPos = mapToVirtualScreen(wheelEvent->pos(), originalDestination);
|
||||
QPointF transformedPos = mapToVirtualScreen(wheelEvent->pos());
|
||||
QWheelEvent mappedEvent(
|
||||
transformedPos,
|
||||
wheelEvent->delta(), wheelEvent->buttons(),
|
||||
|
@ -920,30 +920,6 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Fall through
|
||||
case QEvent::MouseButtonDblClick:
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::MouseMove: {
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
QPointF transformedPos = mapToVirtualScreen(mouseEvent->localPos(), originalDestination);
|
||||
QMouseEvent mappedEvent(mouseEvent->type(),
|
||||
transformedPos,
|
||||
mouseEvent->screenPos(), mouseEvent->button(),
|
||||
mouseEvent->buttons(), mouseEvent->modifiers());
|
||||
if (event->type() == QEvent::MouseMove) {
|
||||
// TODO - this line necessary for the QML Tooltop to work (which is not currently being used), but it causes interface to crash on launch on a fresh install
|
||||
// need to investigate into why this crash is happening.
|
||||
//_qmlContext->setContextProperty("lastMousePosition", mouseEvent.localPos());
|
||||
}
|
||||
mappedEvent.ignore();
|
||||
if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) {
|
||||
return mappedEvent.isAccepted();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -951,6 +927,141 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even
|
|||
return false;
|
||||
}
|
||||
|
||||
PointerEvent::EventType OffscreenQmlSurface::choosePointerEventType(QEvent::Type type) {
|
||||
switch (type) {
|
||||
case QEvent::MouseButtonDblClick:
|
||||
return PointerEvent::DoublePress;
|
||||
case QEvent::MouseButtonPress:
|
||||
return PointerEvent::Press;
|
||||
case QEvent::MouseButtonRelease:
|
||||
return PointerEvent::Release;
|
||||
case QEvent::MouseMove:
|
||||
return PointerEvent::Move;
|
||||
default:
|
||||
return PointerEvent::Move;
|
||||
}
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::hoverEndEvent(const PointerEvent& event, class QTouchDevice& device) {
|
||||
if (!_paused && _quickWindow && _pressed && event.sendReleaseOnHoverLeave()) {
|
||||
PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(),
|
||||
event.getButton(), event.getButtons(), event.getKeyboardModifiers());
|
||||
handlePointerEvent(endEvent, device);
|
||||
// QML onReleased is only triggered if a click has happened first. We need to send this "fake" mouse move event to properly trigger an onExited.
|
||||
PointerEvent endMoveEvent(PointerEvent::Move, event.getID());
|
||||
handlePointerEvent(endMoveEvent, device);
|
||||
}
|
||||
}
|
||||
|
||||
bool OffscreenQmlSurface::handlePointerEvent(const PointerEvent& event, class QTouchDevice& device) {
|
||||
// Ignore mouse interaction if we're paused
|
||||
if (_paused || !_quickWindow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.getType() == PointerEvent::Press) {
|
||||
_pressed = true;
|
||||
} else if (event.getType() == PointerEvent::Release) {
|
||||
_pressed = false;
|
||||
}
|
||||
|
||||
QPointF windowPoint(event.getPos2D().x, event.getPos2D().y);
|
||||
|
||||
Qt::TouchPointState state = Qt::TouchPointStationary;
|
||||
if (event.getType() == PointerEvent::Press && event.getButton() == PointerEvent::PrimaryButton) {
|
||||
state = Qt::TouchPointPressed;
|
||||
} else if (event.getType() == PointerEvent::Release) {
|
||||
state = Qt::TouchPointReleased;
|
||||
} else if (_activeTouchPoints.count(event.getID()) && windowPoint != _activeTouchPoints[event.getID()].pos()) {
|
||||
state = Qt::TouchPointMoved;
|
||||
}
|
||||
|
||||
QEvent::Type touchType = QEvent::TouchUpdate;
|
||||
if (_activeTouchPoints.empty()) {
|
||||
// If the first active touch point is being created, send a begin
|
||||
touchType = QEvent::TouchBegin;
|
||||
} if (state == Qt::TouchPointReleased && _activeTouchPoints.size() == 1 && _activeTouchPoints.count(event.getID())) {
|
||||
// If the last active touch point is being released, send an end
|
||||
touchType = QEvent::TouchEnd;
|
||||
}
|
||||
|
||||
{
|
||||
QTouchEvent::TouchPoint point;
|
||||
point.setId(event.getID());
|
||||
point.setState(state);
|
||||
point.setPos(windowPoint);
|
||||
point.setScreenPos(windowPoint);
|
||||
_activeTouchPoints[event.getID()] = point;
|
||||
}
|
||||
|
||||
QTouchEvent touchEvent(touchType, &device, event.getKeyboardModifiers());
|
||||
{
|
||||
QList<QTouchEvent::TouchPoint> touchPoints;
|
||||
Qt::TouchPointStates touchPointStates;
|
||||
for (const auto& entry : _activeTouchPoints) {
|
||||
touchPointStates |= entry.second.state();
|
||||
touchPoints.push_back(entry.second);
|
||||
}
|
||||
|
||||
touchEvent.setWindow(_quickWindow);
|
||||
touchEvent.setDevice(&device);
|
||||
touchEvent.setTarget(_rootItem);
|
||||
touchEvent.setTouchPoints(touchPoints);
|
||||
touchEvent.setTouchPointStates(touchPointStates);
|
||||
}
|
||||
|
||||
// Send mouse events to the surface so that HTML dialog elements work with mouse press and hover.
|
||||
//
|
||||
// In Qt 5.9 mouse events must be sent before touch events to make sure some QtQuick components will
|
||||
// receive mouse events
|
||||
Qt::MouseButton button = Qt::NoButton;
|
||||
Qt::MouseButtons buttons = Qt::NoButton;
|
||||
if (event.getButton() == PointerEvent::PrimaryButton) {
|
||||
button = Qt::LeftButton;
|
||||
}
|
||||
if (event.getButtons() & PointerEvent::PrimaryButton) {
|
||||
buttons |= Qt::LeftButton;
|
||||
}
|
||||
|
||||
bool eventsAccepted = false;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
|
||||
if (event.getType() == PointerEvent::Move) {
|
||||
QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers());
|
||||
// TODO - this line necessary for the QML Tooltop to work (which is not currently being used), but it causes interface to crash on launch on a fresh install
|
||||
// need to investigate into why this crash is happening.
|
||||
//_qmlContext->setContextProperty("lastMousePosition", windowPoint);
|
||||
QCoreApplication::sendEvent(_quickWindow, &mouseEvent);
|
||||
eventsAccepted &= mouseEvent.isAccepted();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (touchType == QEvent::TouchBegin) {
|
||||
_touchBeginAccepted = QCoreApplication::sendEvent(_quickWindow, &touchEvent);
|
||||
} else if (_touchBeginAccepted) {
|
||||
QCoreApplication::sendEvent(_quickWindow, &touchEvent);
|
||||
}
|
||||
eventsAccepted &= touchEvent.isAccepted();
|
||||
|
||||
// If this was a release event, remove the point from the active touch points
|
||||
if (state == Qt::TouchPointReleased) {
|
||||
_activeTouchPoints.erase(event.getID());
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 9, 0)
|
||||
if (event.getType() == PointerEvent::Move) {
|
||||
// TODO - this line necessary for the QML Tooltop to work (which is not currently being used), but it causes interface to crash on launch on a fresh install
|
||||
// need to investigate into why this crash is happening.
|
||||
//_qmlContext->setContextProperty("lastMousePosition", windowPoint);
|
||||
QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers());
|
||||
QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent);
|
||||
eventsAccepted &= mouseEvent.isAccepted();
|
||||
}
|
||||
#endif
|
||||
|
||||
return eventsAccepted;
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::pause() {
|
||||
_paused = true;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#include <GLMHelpers.h>
|
||||
#include <ThreadHelpers.h>
|
||||
|
||||
#include <QTouchEvent>
|
||||
#include "PointerEvent.h"
|
||||
|
||||
class QWindow;
|
||||
class QMyQuickRenderControl;
|
||||
class OffscreenGLCanvas;
|
||||
|
@ -79,7 +82,7 @@ public:
|
|||
QObject* getEventHandler();
|
||||
QQmlContext* getSurfaceContext();
|
||||
|
||||
QPointF mapToVirtualScreen(const QPointF& originalPoint, QObject* originalWidget);
|
||||
QPointF mapToVirtualScreen(const QPointF& originalPoint);
|
||||
bool eventFilter(QObject* originalDestination, QEvent* event) override;
|
||||
|
||||
void setKeyboardRaised(QObject* object, bool raised, bool numeric = false, bool passwordField = false);
|
||||
|
@ -95,6 +98,8 @@ public:
|
|||
static std::function<void(uint32_t, void*)> getDiscardLambda();
|
||||
static size_t getUsedTextureMemory();
|
||||
|
||||
PointerEvent::EventType choosePointerEventType(QEvent::Type type);
|
||||
|
||||
signals:
|
||||
void focusObjectChanged(QObject* newFocus);
|
||||
void focusTextChanged(bool focusText);
|
||||
|
@ -136,6 +141,10 @@ private slots:
|
|||
void updateQuick();
|
||||
void onFocusObjectChanged(QObject* newFocus);
|
||||
|
||||
public slots:
|
||||
void hoverEndEvent(const PointerEvent& event, class QTouchDevice& device);
|
||||
bool handlePointerEvent(const PointerEvent& event, class QTouchDevice& device);
|
||||
|
||||
private:
|
||||
QQuickWindow* _quickWindow { nullptr };
|
||||
QMyQuickRenderControl* _renderControl{ nullptr };
|
||||
|
@ -161,6 +170,10 @@ private:
|
|||
QWindow* _proxyWindow { nullptr };
|
||||
|
||||
QQuickItem* _currentFocusItem { nullptr };
|
||||
|
||||
bool _pressed { false };
|
||||
bool _touchBeginAccepted { false };
|
||||
std::map<uint32_t, QTouchEvent::TouchPoint> _activeTouchPoints;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue