Fix issue with mouse input for viewport camera (#3210)

* fix for drift accumulating in the viewport camera

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* fix typo and update how events are stored

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* respond to PR feedback and fix linux and windows build issues

Signed-off-by: hultonha <hultonha@amazon.co.uk>

* fix failing unit tests in camera input

Signed-off-by: hultonha <hultonha@amazon.co.uk>
This commit is contained in:
hultonha
2021-08-19 09:06:24 +01:00
committed by GitHub
parent 586678a5f9
commit 80e08dd947
18 changed files with 538 additions and 134 deletions
@@ -285,7 +285,7 @@ namespace AzToolsFramework
}
}
void QtEventToAzInputMapper::ProcessPendingMouseEvents()
void QtEventToAzInputMapper::ProcessPendingMouseEvents(const QPoint& cursorDelta)
{
auto systemCursorChannel =
GetInputChannel<AzFramework::InputChannelDeltaWithSharedPosition2D>(AzFramework::InputDeviceMouse::SystemCursorPosition);
@@ -297,14 +297,8 @@ namespace AzToolsFramework
GetInputChannel<AzFramework::InputChannelDeltaWithSharedPosition2D>(AzFramework::InputDeviceMouse::Movement::Z);
systemCursorChannel->ProcessRawInputEvent(m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta.GetLength());
// Generate movement events based on the pixel delta divided by the DPI scaling factor, to calculate a rough approximation
// of cursor movement velocity.
movementXChannel->ProcessRawInputEvent(
m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta.GetX() * aznumeric_cast<float>(m_sourceWidget->width()) /
m_sourceWidget->devicePixelRatioF());
movementYChannel->ProcessRawInputEvent(
m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta.GetY() * aznumeric_cast<float>(m_sourceWidget->height()) /
m_sourceWidget->devicePixelRatioF());
movementXChannel->ProcessRawInputEvent(cursorDelta.x());
movementYChannel->ProcessRawInputEvent(cursorDelta.y());
mouseWheelChannel->ProcessRawInputEvent(0.0f);
NotifyUpdateChannelIfNotIdle(systemCursorChannel, nullptr);
@@ -337,41 +331,43 @@ namespace AzToolsFramework
}
}
AZ::Vector2 QtEventToAzInputMapper::WidgetPositionToNormalizedPosition(QPoint position)
AZ::Vector2 QtEventToAzInputMapper::WidgetPositionToNormalizedPosition(const QPoint& position)
{
const float normalizedX = aznumeric_cast<float>(position.x()) / aznumeric_cast<float>(m_sourceWidget->width());
const float normalizedY = aznumeric_cast<float>(position.y()) / aznumeric_cast<float>(m_sourceWidget->height());
return AZ::Vector2{normalizedX, normalizedY};
return AZ::Vector2{ normalizedX, normalizedY };
}
QPoint QtEventToAzInputMapper::NormalizedPositionToWidgetPosition(AZ::Vector2 normalizedPosition)
QPoint QtEventToAzInputMapper::NormalizedPositionToWidgetPosition(const AZ::Vector2& normalizedPosition)
{
const int denormalizedX = aznumeric_cast<int>(normalizedPosition.GetX() * m_sourceWidget->width());
const int denormalizedY = aznumeric_cast<int>(normalizedPosition.GetY() * m_sourceWidget->height());
return QPoint{denormalizedX, denormalizedY};
return QPoint{ denormalizedX, denormalizedY };
}
void QtEventToAzInputMapper::HandleMouseMoveEvent(QMouseEvent* mouseEvent)
{
AZ::Vector2 lastCursorPosition = m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition;
const QPoint cursorPosition = mouseEvent->pos();
const QPoint cursorDelta = cursorPosition - m_previousCursorPosition;
const QPoint mousePos = mouseEvent->pos();
const AZ::Vector2 normalizedPosition = WidgetPositionToNormalizedPosition(mousePos);
m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta = normalizedPosition - m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition;
m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition = normalizedPosition;
ProcessPendingMouseEvents();
m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition = WidgetPositionToNormalizedPosition(cursorPosition);
m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta = WidgetPositionToNormalizedPosition(cursorDelta);
ProcessPendingMouseEvents(cursorDelta);
if (m_capturingCursor)
{
// Reset our cursor position to the previous point.
QPoint targetScreenPosition = m_sourceWidget->mapToGlobal(NormalizedPositionToWidgetPosition(lastCursorPosition));
const QPoint targetScreenPosition = m_sourceWidget->mapToGlobal(m_previousCursorPosition);
AzQtComponents::SetCursorPos(targetScreenPosition);
// Even though we just set the cursor position, there are edge cases such as remote desktop that will leave
// the cursor position unchanged. For safety, we re-cache our last cursor position for delta generation.
QPoint actualWidgetPosition = m_sourceWidget->mapFromGlobal(QCursor::pos());
const QPoint actualWidgetPosition = m_sourceWidget->mapFromGlobal(QCursor::pos());
m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition = WidgetPositionToNormalizedPosition(actualWidgetPosition);
}
m_previousCursorPosition = cursorPosition;
}
void QtEventToAzInputMapper::HandleKeyEvent(QKeyEvent* keyEvent)
@@ -21,6 +21,7 @@
#include <QEvent>
#include <QObject>
#include <QPoint>
#endif //! defined(Q_MOC_RUN)
class QWidget;
@@ -111,12 +112,12 @@ namespace AzToolsFramework
void NotifyUpdateChannelIfNotIdle(const AzFramework::InputChannel* channel, QEvent* event);
// Processes any pending mouse movement events, this allows mouse movement channels to close themselves.
void ProcessPendingMouseEvents();
void ProcessPendingMouseEvents(const QPoint& cursorDelta);
// Converts a point in logical source widget space [0..m_sourceWidget->size()] to normalized [0..1] space.
AZ::Vector2 WidgetPositionToNormalizedPosition(QPoint position);
AZ::Vector2 WidgetPositionToNormalizedPosition(const QPoint& position);
// Converts a point in normalized [0..1] space to logical source widget space [0..m_sourceWidget->size()].
QPoint NormalizedPositionToWidgetPosition(AZ::Vector2 normalizedPosition);
QPoint NormalizedPositionToWidgetPosition(const AZ::Vector2& normalizedPosition);
// Handle mouse click events.
void HandleMouseButtonEvent(QMouseEvent* mouseEvent);
@@ -148,6 +149,8 @@ namespace AzToolsFramework
AZStd::unordered_set<Qt::Key> m_highPriorityKeys;
// A lookup table for AZ input channel ID -> physical input channel on our mouse or keyboard device.
AZStd::unordered_map<AzFramework::InputChannelId, AzFramework::InputChannel*> m_channels;
// Where the position of the mouse cursor was at the last cursor event.
QPoint m_previousCursorPosition;
// The source widget to map events from, used to calculate the relative mouse position within the widget bounds.
QWidget* m_sourceWidget;
// Flags whether or not Qt events should currently be processed.
@@ -188,7 +188,7 @@ namespace AzToolsFramework
return false;
}
using namespace AzToolsFramework::ViewportInteraction;
using AzToolsFramework::ViewportInteraction::MouseEvent;
const auto& mouseInteraction = mouseInteractionEvent.m_mouseInteraction;
// store the current interaction for use in DrawManipulators
m_currentInteraction = mouseInteraction;
@@ -196,28 +196,19 @@ namespace AzToolsFramework
switch (mouseInteractionEvent.m_mouseEvent)
{
case MouseEvent::Down:
{
return m_manipulatorManager->ConsumeViewportMousePress(mouseInteraction);
}
return m_manipulatorManager->ConsumeViewportMousePress(mouseInteraction);
case MouseEvent::DoubleClick:
{
return false;
}
return false;
case MouseEvent::Move:
{
AzToolsFramework::ManipulatorManager::ConsumeMouseMoveResult mouseMoveResult =
AzToolsFramework::ManipulatorManager::ConsumeMouseMoveResult::None;
mouseMoveResult = m_manipulatorManager->ConsumeViewportMouseMove(mouseInteraction);
const AzToolsFramework::ManipulatorManager::ConsumeMouseMoveResult mouseMoveResult =
m_manipulatorManager->ConsumeViewportMouseMove(mouseInteraction);
return mouseMoveResult == AzToolsFramework::ManipulatorManager::ConsumeMouseMoveResult::Interacting;
}
case MouseEvent::Up:
{
return m_manipulatorManager->ConsumeViewportMouseRelease(mouseInteraction);
}
return m_manipulatorManager->ConsumeViewportMouseRelease(mouseInteraction);
case MouseEvent::Wheel:
{
return m_manipulatorManager->ConsumeViewportMouseWheel(mouseInteraction);
}
return m_manipulatorManager->ConsumeViewportMouseWheel(mouseInteraction);
default:
return false;
}