Improvement for click detection when clicking quickly between mouse moves (#5786)

* improvement for click detection when clicking quickly between mouse moves

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>

* remove magic number and introduce constant

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>

* add missing update from camera test

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>
This commit is contained in:
Tom Hulton-Harrop
2021-11-19 16:52:44 +00:00
committed by GitHub
parent 11f41a4467
commit ebb24d2285
7 changed files with 142 additions and 20 deletions
@@ -24,11 +24,12 @@ namespace AzFramework
ClickDetector::ClickOutcome ClickDetector::DetectClick(const ClickEvent clickEvent, const ScreenVector& cursorDelta)
{
m_moveAccumulator += ScreenVectorLength(cursorDelta);
const auto previousDetectionState = m_detectionState;
if (previousDetectionState == DetectionState::WaitingForMove)
{
// only allow the action to begin if the mouse has been moved a small amount
m_moveAccumulator += ScreenVectorLength(cursorDelta);
if (m_moveAccumulator > m_deadZone)
{
m_detectionState = DetectionState::Moved;
@@ -43,7 +44,7 @@ namespace AzFramework
using FloatingPointSeconds = AZStd::chrono::duration<float, AZStd::chrono::seconds::period>;
const auto diff = now - m_tryBeginTime.value();
if (FloatingPointSeconds(diff).count() < m_doubleClickInterval)
if (FloatingPointSeconds(diff).count() < m_doubleClickInterval && m_moveAccumulator < m_deadZone)
{
return ClickOutcome::Nil;
}
@@ -15,6 +15,10 @@
namespace AzFramework
{
//! Default value to use for detecting if the mouse has moved far enough after a mouse down to no longer
//! register a click when a mouse up occurs.
inline constexpr float DefaultMouseMoveDeadZone = 2.0f;
struct ScreenVector;
//! Utility class to help detect different types of mouse click (mouse down and up with
@@ -66,7 +70,7 @@ namespace AzFramework
};
float m_moveAccumulator = 0.0f; //!< How far the mouse has moved after mouse down.
float m_deadZone = 2.0f; //!< How far to move before a click is cancelled (when Move will fire).
float m_deadZone = DefaultMouseMoveDeadZone; //!< How far to move before a click is cancelled (when Move will fire).
float m_doubleClickInterval = 0.4f; //!< Default double click interval, can be overridden.
DetectionState m_detectionState; //!< Internal state of ClickDetector.
//! Mouse down time (happens each mouse down, helps with double click handling).
@@ -144,12 +144,45 @@ namespace UnitTest
{
using ::testing::Eq;
const ClickDetector::ClickOutcome downOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
const ClickDetector::ClickOutcome upOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(50, 50));
const ClickDetector::ClickOutcome downOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
const ClickDetector::ClickOutcome upOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(50, 50));
EXPECT_THAT(downOutcome, Eq(ClickDetector::ClickOutcome::Nil));
EXPECT_THAT(upOutcome, Eq(ClickDetector::ClickOutcome::Release));
}
//! note: ClickDetector does not explicitly return double clicks but if one occurs the ClickOutcome will be Nil
TEST_F(ClickDetectorFixture, DoubleClickIsRegisteredIfMouseDeltaHasMovedLessThanDeadzoneInClickInterval)
{
using ::testing::Eq;
const ClickDetector::ClickOutcome firstDownOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
const ClickDetector::ClickOutcome firstUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0));
const ClickDetector::ClickOutcome secondDownOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
const ClickDetector::ClickOutcome secondUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0));
EXPECT_THAT(firstDownOutcome, Eq(ClickDetector::ClickOutcome::Nil));
EXPECT_THAT(firstUpOutcome, Eq(ClickDetector::ClickOutcome::Click));
EXPECT_THAT(secondDownOutcome, Eq(ClickDetector::ClickOutcome::Nil));
EXPECT_THAT(secondUpOutcome, Eq(ClickDetector::ClickOutcome::Nil));
}
TEST_F(ClickDetectorFixture, DoubleClickIsNotRegisteredIfMouseDeltaHasMovedMoreThanDeadzoneInClickInterval)
{
using ::testing::Eq;
const ClickDetector::ClickOutcome firstDownOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
const ClickDetector::ClickOutcome firstUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0));
const ClickDetector::ClickOutcome secondDownOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(10, 10));
const ClickDetector::ClickOutcome secondUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0));
EXPECT_THAT(firstDownOutcome, Eq(ClickDetector::ClickOutcome::Nil));
EXPECT_THAT(firstUpOutcome, Eq(ClickDetector::ClickOutcome::Click));
EXPECT_THAT(secondDownOutcome, Eq(ClickDetector::ClickOutcome::Nil));
EXPECT_THAT(secondUpOutcome, Eq(ClickDetector::ClickOutcome::Click));
}
} // namespace UnitTest