Switch RenderViewportWidget to using Qt events instead of AzFramework input events

Signed-off-by: nvsickle <nvsickle@amazon.com>
This commit is contained in:
nvsickle
2021-06-17 15:35:14 -07:00
parent 15248e7c12
commit a4a038cb28
2 changed files with 25 additions and 82 deletions
@@ -11,6 +11,7 @@
#include <QElapsedTimer>
#include <Atom/RPI.Public/Base.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
#include <AzToolsFramework/Input/QtEventToAzInputManager.h>
#include <AzFramework/Input/Events/InputChannelEventListener.h>
#include <AzFramework/Scene/Scene.h>
#include <AzFramework/Viewport/ViewportControllerInterface.h>
@@ -157,5 +158,7 @@ namespace AtomToolsFramework
AZStd::optional<QPoint> m_lastCursorPosition;
// The viewport settings (e.g. grid snapping, grid size) for this viewport.
const AzToolsFramework::ViewportInteraction::ViewportSettings* m_viewportSettings = nullptr;
// Maps our internal Qt events into AzFramework InputChannels for our ViewportControllerList.
AzToolsFramework::QtEventToAzInputMapper m_inputChannelMapper = AzToolsFramework::QtEventToAzInputMapper(this);
};
} //namespace AtomToolsFramework
@@ -149,86 +149,24 @@ namespace AtomToolsFramework
return m_defaultCamera;
}
static bool IsMouseButtonEvent(const AzFramework::InputChannel& inputChannel)
{
const auto& mouseButtons = AzFramework::InputDeviceMouse::Button::All;
return AZStd::find(mouseButtons.begin(), mouseButtons.end(), inputChannel.GetInputChannelId()) != mouseButtons.end();
}
static bool IsMouseMoveEvent(const AzFramework::InputChannel& inputChannel)
{
return inputChannel.GetInputChannelId() == AzFramework::InputDeviceMouse::SystemCursorPosition;
}
static bool IsMouseButtonOrWheelEvent(const AzFramework::InputChannel& inputChannel)
{
return IsMouseButtonEvent(inputChannel) || inputChannel.GetInputChannelId() == AzFramework::InputDeviceMouse::Movement::Z;
}
bool RenderViewportWidget::CanInputGrantFocus(const AzFramework::InputChannel& inputChannel) const
{
// Only take focus from a mouse event if the cursor is currently within the viewport
if (!m_mouseOver)
{
return false;
}
// Only mouse button down events (clicks) can grant focus
if (inputChannel.GetState() != AzFramework::InputChannel::State::Began)
{
return false;
}
// Only mouse button events can grant focus
return IsMouseButtonEvent(inputChannel);
}
bool RenderViewportWidget::OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel)
{
bool shouldConsumeEvent = true;
// Grab keyboard focus if we've been clicked on.
// Qt normally handles this for us, but we're filtering native events before they get
// synthesized into QMouseEvents.
if (!hasFocus() && CanInputGrantFocus(inputChannel))
{
setFocus();
}
// Don't consume new input events if we don't currently have focus.
// We do forward Ended events, as they may be relevant to our current state
// (e.g. a key gets released after we lose focus, it shouldn't remain "stuck").
if (!hasFocus())
{
if (inputChannel.GetState() == AzFramework::InputChannel::State::Ended)
{
// Forward the input ended event to our controllers, but don't prevent other viewports from receiving it.
shouldConsumeEvent = false;
}
else
{
// Not an event we should listen to, abort.
return false;
}
return false;
}
// If we receive a mouse button event from outside of our viewport, ignore it even if we have focus.
if (!m_mouseOver
&& inputChannel.GetState() == AzFramework::InputChannel::State::Began
&& IsMouseButtonOrWheelEvent(inputChannel))
// Only forward channels that aren't covered by our Qt -> AZ event mapper
if (m_inputChannelMapper.HandlesInputEvent(inputChannel))
{
return false;
}
// Don't forward system cursor position updates, we'll do that ourselves for in-window movements once the result of
// ViewportCursorScreenPosition is guaranteed to be correct (see mouseMoveEvent).
if (IsMouseMoveEvent(inputChannel))
{
return false;
}
bool shouldConsumeEvent = true;
AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
const bool eventHandled = m_controllerList->HandleInputChannelEvent({GetId(), windowId, inputChannel});
// If our controllers handled the event and it's one we can safely consume (i.e. it's not an Ended event that other viewports might need), consume it.
return eventHandled && shouldConsumeEvent;
}
@@ -262,7 +200,23 @@ namespace AtomToolsFramework
{
SendWindowResizeEvent();
}
return QWidget::event(event);
bool eventHandled = false;
for(AzFramework::InputChannel* mappedInputChannel : m_inputChannelMapper.MapQtEventToAzInput(event))
{
AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
if (m_controllerList->HandleInputChannelEvent({GetId(), windowId, *mappedInputChannel}))
{
eventHandled = true;
}
}
if (eventHandled)
{
event->setAccepted(true);
}
return QWidget::event(event) || eventHandled;
}
void RenderViewportWidget::enterEvent([[maybe_unused]] QEvent* event)
@@ -279,20 +233,6 @@ namespace AtomToolsFramework
{
m_mousePosition = event->localPos();
// Now that we've looked a viewport local mouse position,
// we can go ahead and broadcast the system cursor input event to the controllers.
// This allows any controllers not listening to pure mouse deltas to consistently
// look up the mouse position in viewport screen coordinates.
const AzFramework::InputDevice* mouseInputDevice = nullptr;
if (AzFramework::InputDeviceRequestBus::EventResult(
mouseInputDevice, AzFramework::InputDeviceMouse::Id, &AzFramework::InputDeviceRequests::GetInputDevice);
mouseInputDevice != nullptr)
{
const AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
AzFramework::InputChannel syntheticInput(AzFramework::InputDeviceMouse::SystemCursorPosition, *mouseInputDevice);
m_controllerList->HandleInputChannelEvent({GetId(), windowId, syntheticInput});
}
if (m_capturingCursor && m_lastCursorPosition.has_value())
{
AzQtComponents::SetCursorPos(m_lastCursorPosition.value());