Use synthetic keyboard and mouse devices instead of synthetic input channels

Signed-off-by: nvsickle <nvsickle@amazon.com>
This commit is contained in:
nvsickle
2021-07-01 14:07:04 -07:00
parent 8dc59a13da
commit 52ae7433b3
8 changed files with 239 additions and 187 deletions
@@ -454,8 +454,8 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
InputDeviceKeyboard::InputDeviceKeyboard()
: InputDevice(Id)
InputDeviceKeyboard::InputDeviceKeyboard(AzFramework::InputDeviceId id)
: InputDevice(id)
, m_modifierKeyStates(AZStd::make_shared<ModifierKeyStates>())
, m_allChannelsById()
, m_keyChannelsById()
@@ -240,7 +240,7 @@ namespace AzFramework
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
InputDeviceKeyboard();
InputDeviceKeyboard(AzFramework::InputDeviceId id = Id);
////////////////////////////////////////////////////////////////////////////////////////////
// Disable copying
@@ -95,8 +95,8 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
InputDeviceMouse::InputDeviceMouse()
: InputDevice(Id)
InputDeviceMouse::InputDeviceMouse(AzFramework::InputDeviceId id)
: InputDevice(id)
, m_allChannelsById()
, m_buttonChannelsById()
, m_movementChannelsById()
@@ -111,7 +111,7 @@ namespace AzFramework
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
explicit InputDeviceMouse();
explicit InputDeviceMouse(AzFramework::InputDeviceId id = Id);
////////////////////////////////////////////////////////////////////////////////////////////
// Disable copying
@@ -17,9 +17,6 @@
#include <AzFramework/Input/Buses/Notifications/InputChannelNotificationBus.h>
#include <AzFramework/Input/Buses/Requests/InputChannelRequestBus.h>
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <QApplication>
#include <QCursor>
#include <QEvent>
@@ -30,159 +27,163 @@
namespace AzToolsFramework
{
// This asumes modifier keys (ctrl/shift/alt) map to the left control/shift/alt keys as Qt provides no way to disambiguate
// in a platform agnostic manner. This could be expanded later with a PAL mapping from native scan codes from QKeyEvents, if needed.
AZStd::array<AZStd::pair<Qt::Key, AzFramework::InputChannelId>, 91> QtEventToAzInputMapper::QtKeyMappings = { {
{ Qt::Key_0, AzFramework::InputDeviceKeyboard::Key::Alphanumeric0 },
{ Qt::Key_1, AzFramework::InputDeviceKeyboard::Key::Alphanumeric1 },
{ Qt::Key_2, AzFramework::InputDeviceKeyboard::Key::Alphanumeric2 },
{ Qt::Key_3, AzFramework::InputDeviceKeyboard::Key::Alphanumeric3 },
{ Qt::Key_4, AzFramework::InputDeviceKeyboard::Key::Alphanumeric4 },
{ Qt::Key_5, AzFramework::InputDeviceKeyboard::Key::Alphanumeric5 },
{ Qt::Key_6, AzFramework::InputDeviceKeyboard::Key::Alphanumeric6 },
{ Qt::Key_7, AzFramework::InputDeviceKeyboard::Key::Alphanumeric7 },
{ Qt::Key_8, AzFramework::InputDeviceKeyboard::Key::Alphanumeric8 },
{ Qt::Key_9, AzFramework::InputDeviceKeyboard::Key::Alphanumeric9 },
{ Qt::Key_A, AzFramework::InputDeviceKeyboard::Key::AlphanumericA },
{ Qt::Key_B, AzFramework::InputDeviceKeyboard::Key::AlphanumericB },
{ Qt::Key_C, AzFramework::InputDeviceKeyboard::Key::AlphanumericC },
{ Qt::Key_D, AzFramework::InputDeviceKeyboard::Key::AlphanumericD },
{ Qt::Key_E, AzFramework::InputDeviceKeyboard::Key::AlphanumericE },
{ Qt::Key_F, AzFramework::InputDeviceKeyboard::Key::AlphanumericF },
{ Qt::Key_G, AzFramework::InputDeviceKeyboard::Key::AlphanumericG },
{ Qt::Key_H, AzFramework::InputDeviceKeyboard::Key::AlphanumericH },
{ Qt::Key_I, AzFramework::InputDeviceKeyboard::Key::AlphanumericI },
{ Qt::Key_J, AzFramework::InputDeviceKeyboard::Key::AlphanumericJ },
{ Qt::Key_K, AzFramework::InputDeviceKeyboard::Key::AlphanumericK },
{ Qt::Key_L, AzFramework::InputDeviceKeyboard::Key::AlphanumericL },
{ Qt::Key_M, AzFramework::InputDeviceKeyboard::Key::AlphanumericM },
{ Qt::Key_N, AzFramework::InputDeviceKeyboard::Key::AlphanumericN },
{ Qt::Key_O, AzFramework::InputDeviceKeyboard::Key::AlphanumericO },
{ Qt::Key_P, AzFramework::InputDeviceKeyboard::Key::AlphanumericP },
{ Qt::Key_Q, AzFramework::InputDeviceKeyboard::Key::AlphanumericQ },
{ Qt::Key_R, AzFramework::InputDeviceKeyboard::Key::AlphanumericR },
{ Qt::Key_S, AzFramework::InputDeviceKeyboard::Key::AlphanumericS },
{ Qt::Key_T, AzFramework::InputDeviceKeyboard::Key::AlphanumericT },
{ Qt::Key_U, AzFramework::InputDeviceKeyboard::Key::AlphanumericU },
{ Qt::Key_V, AzFramework::InputDeviceKeyboard::Key::AlphanumericV },
{ Qt::Key_W, AzFramework::InputDeviceKeyboard::Key::AlphanumericW },
{ Qt::Key_X, AzFramework::InputDeviceKeyboard::Key::AlphanumericX },
{ Qt::Key_Y, AzFramework::InputDeviceKeyboard::Key::AlphanumericY },
{ Qt::Key_Z, AzFramework::InputDeviceKeyboard::Key::AlphanumericZ },
{ Qt::Key_Backspace, AzFramework::InputDeviceKeyboard::Key::EditBackspace },
{ Qt::Key_CapsLock, AzFramework::InputDeviceKeyboard::Key::EditCapsLock },
{ Qt::Key_Enter, AzFramework::InputDeviceKeyboard::Key::EditEnter },
{ Qt::Key_Space, AzFramework::InputDeviceKeyboard::Key::EditSpace },
{ Qt::Key_Tab, AzFramework::InputDeviceKeyboard::Key::EditTab },
{ Qt::Key_Escape, AzFramework::InputDeviceKeyboard::Key::Escape },
{ Qt::Key_F1, AzFramework::InputDeviceKeyboard::Key::Function01 },
{ Qt::Key_F2, AzFramework::InputDeviceKeyboard::Key::Function02 },
{ Qt::Key_F3, AzFramework::InputDeviceKeyboard::Key::Function03 },
{ Qt::Key_F4, AzFramework::InputDeviceKeyboard::Key::Function04 },
{ Qt::Key_F5, AzFramework::InputDeviceKeyboard::Key::Function05 },
{ Qt::Key_F6, AzFramework::InputDeviceKeyboard::Key::Function06 },
{ Qt::Key_F7, AzFramework::InputDeviceKeyboard::Key::Function07 },
{ Qt::Key_F8, AzFramework::InputDeviceKeyboard::Key::Function08 },
{ Qt::Key_F9, AzFramework::InputDeviceKeyboard::Key::Function09 },
{ Qt::Key_F10, AzFramework::InputDeviceKeyboard::Key::Function10 },
{ Qt::Key_F11, AzFramework::InputDeviceKeyboard::Key::Function11 },
{ Qt::Key_F12, AzFramework::InputDeviceKeyboard::Key::Function12 },
{ Qt::Key_F13, AzFramework::InputDeviceKeyboard::Key::Function13 },
{ Qt::Key_F14, AzFramework::InputDeviceKeyboard::Key::Function14 },
{ Qt::Key_F15, AzFramework::InputDeviceKeyboard::Key::Function15 },
{ Qt::Key_F16, AzFramework::InputDeviceKeyboard::Key::Function16 },
{ Qt::Key_F17, AzFramework::InputDeviceKeyboard::Key::Function17 },
{ Qt::Key_F18, AzFramework::InputDeviceKeyboard::Key::Function18 },
{ Qt::Key_F19, AzFramework::InputDeviceKeyboard::Key::Function19 },
{ Qt::Key_F20, AzFramework::InputDeviceKeyboard::Key::Function20 },
{ Qt::Key_Alt, AzFramework::InputDeviceKeyboard::Key::ModifierAltL },
{ Qt::Key_Control, AzFramework::InputDeviceKeyboard::Key::ModifierCtrlL },
{ Qt::Key_Shift, AzFramework::InputDeviceKeyboard::Key::ModifierShiftL },
{ Qt::Key_Super_L, AzFramework::InputDeviceKeyboard::Key::ModifierSuperL },
{ Qt::Key_Super_R, AzFramework::InputDeviceKeyboard::Key::ModifierSuperR },
{ Qt::Key_Down, AzFramework::InputDeviceKeyboard::Key::NavigationArrowDown },
{ Qt::Key_Left, AzFramework::InputDeviceKeyboard::Key::NavigationArrowLeft },
{ Qt::Key_Right, AzFramework::InputDeviceKeyboard::Key::NavigationArrowRight },
{ Qt::Key_Up, AzFramework::InputDeviceKeyboard::Key::NavigationArrowUp },
{ Qt::Key_Delete, AzFramework::InputDeviceKeyboard::Key::NavigationDelete },
{ Qt::Key_End, AzFramework::InputDeviceKeyboard::Key::NavigationEnd },
{ Qt::Key_Home, AzFramework::InputDeviceKeyboard::Key::NavigationHome },
{ Qt::Key_Insert, AzFramework::InputDeviceKeyboard::Key::NavigationInsert },
{ Qt::Key_PageDown, AzFramework::InputDeviceKeyboard::Key::NavigationPageDown },
{ Qt::Key_PageUp, AzFramework::InputDeviceKeyboard::Key::NavigationPageUp },
{ Qt::Key_Apostrophe, AzFramework::InputDeviceKeyboard::Key::PunctuationApostrophe },
{ Qt::Key_Backslash, AzFramework::InputDeviceKeyboard::Key::PunctuationBackslash },
{ Qt::Key_BracketLeft, AzFramework::InputDeviceKeyboard::Key::PunctuationBracketL },
{ Qt::Key_BracketRight, AzFramework::InputDeviceKeyboard::Key::PunctuationBracketR },
{ Qt::Key_Comma, AzFramework::InputDeviceKeyboard::Key::PunctuationComma },
{ Qt::Key_Equal, AzFramework::InputDeviceKeyboard::Key::PunctuationEquals },
{ Qt::Key_hyphen, AzFramework::InputDeviceKeyboard::Key::PunctuationHyphen },
{ Qt::Key_Period, AzFramework::InputDeviceKeyboard::Key::PunctuationPeriod },
{ Qt::Key_Semicolon, AzFramework::InputDeviceKeyboard::Key::PunctuationSemicolon },
{ Qt::Key_Slash, AzFramework::InputDeviceKeyboard::Key::PunctuationSlash },
{ Qt::Key_QuoteLeft, AzFramework::InputDeviceKeyboard::Key::PunctuationTilde },
{ Qt::Key_Pause, AzFramework::InputDeviceKeyboard::Key::WindowsSystemPause },
{ Qt::Key_Print, AzFramework::InputDeviceKeyboard::Key::WindowsSystemPrint },
{ Qt::Key_ScrollLock, AzFramework::InputDeviceKeyboard::Key::WindowsSystemScrollLock },
} };
void QtEventToAzInputMapper::InitializeKeyMappings()
{
// This asumes modifier keys (ctrl/shift/alt) map to the left control/shift/alt keys as Qt provides no way to disambiguate
// in a platform agnostic manner. This could be expanded later with a PAL mapping from native scan codes from QKeyEvents, if needed.
m_keyMappings = { {
{ Qt::Key_0, AzFramework::InputDeviceKeyboard::Key::Alphanumeric0 },
{ Qt::Key_1, AzFramework::InputDeviceKeyboard::Key::Alphanumeric1 },
{ Qt::Key_2, AzFramework::InputDeviceKeyboard::Key::Alphanumeric2 },
{ Qt::Key_3, AzFramework::InputDeviceKeyboard::Key::Alphanumeric3 },
{ Qt::Key_4, AzFramework::InputDeviceKeyboard::Key::Alphanumeric4 },
{ Qt::Key_5, AzFramework::InputDeviceKeyboard::Key::Alphanumeric5 },
{ Qt::Key_6, AzFramework::InputDeviceKeyboard::Key::Alphanumeric6 },
{ Qt::Key_7, AzFramework::InputDeviceKeyboard::Key::Alphanumeric7 },
{ Qt::Key_8, AzFramework::InputDeviceKeyboard::Key::Alphanumeric8 },
{ Qt::Key_9, AzFramework::InputDeviceKeyboard::Key::Alphanumeric9 },
{ Qt::Key_A, AzFramework::InputDeviceKeyboard::Key::AlphanumericA },
{ Qt::Key_B, AzFramework::InputDeviceKeyboard::Key::AlphanumericB },
{ Qt::Key_C, AzFramework::InputDeviceKeyboard::Key::AlphanumericC },
{ Qt::Key_D, AzFramework::InputDeviceKeyboard::Key::AlphanumericD },
{ Qt::Key_E, AzFramework::InputDeviceKeyboard::Key::AlphanumericE },
{ Qt::Key_F, AzFramework::InputDeviceKeyboard::Key::AlphanumericF },
{ Qt::Key_G, AzFramework::InputDeviceKeyboard::Key::AlphanumericG },
{ Qt::Key_H, AzFramework::InputDeviceKeyboard::Key::AlphanumericH },
{ Qt::Key_I, AzFramework::InputDeviceKeyboard::Key::AlphanumericI },
{ Qt::Key_J, AzFramework::InputDeviceKeyboard::Key::AlphanumericJ },
{ Qt::Key_K, AzFramework::InputDeviceKeyboard::Key::AlphanumericK },
{ Qt::Key_L, AzFramework::InputDeviceKeyboard::Key::AlphanumericL },
{ Qt::Key_M, AzFramework::InputDeviceKeyboard::Key::AlphanumericM },
{ Qt::Key_N, AzFramework::InputDeviceKeyboard::Key::AlphanumericN },
{ Qt::Key_O, AzFramework::InputDeviceKeyboard::Key::AlphanumericO },
{ Qt::Key_P, AzFramework::InputDeviceKeyboard::Key::AlphanumericP },
{ Qt::Key_Q, AzFramework::InputDeviceKeyboard::Key::AlphanumericQ },
{ Qt::Key_R, AzFramework::InputDeviceKeyboard::Key::AlphanumericR },
{ Qt::Key_S, AzFramework::InputDeviceKeyboard::Key::AlphanumericS },
{ Qt::Key_T, AzFramework::InputDeviceKeyboard::Key::AlphanumericT },
{ Qt::Key_U, AzFramework::InputDeviceKeyboard::Key::AlphanumericU },
{ Qt::Key_V, AzFramework::InputDeviceKeyboard::Key::AlphanumericV },
{ Qt::Key_W, AzFramework::InputDeviceKeyboard::Key::AlphanumericW },
{ Qt::Key_X, AzFramework::InputDeviceKeyboard::Key::AlphanumericX },
{ Qt::Key_Y, AzFramework::InputDeviceKeyboard::Key::AlphanumericY },
{ Qt::Key_Z, AzFramework::InputDeviceKeyboard::Key::AlphanumericZ },
{ Qt::Key_Backspace, AzFramework::InputDeviceKeyboard::Key::EditBackspace },
{ Qt::Key_CapsLock, AzFramework::InputDeviceKeyboard::Key::EditCapsLock },
{ Qt::Key_Enter, AzFramework::InputDeviceKeyboard::Key::EditEnter },
{ Qt::Key_Space, AzFramework::InputDeviceKeyboard::Key::EditSpace },
{ Qt::Key_Tab, AzFramework::InputDeviceKeyboard::Key::EditTab },
{ Qt::Key_Escape, AzFramework::InputDeviceKeyboard::Key::Escape },
{ Qt::Key_F1, AzFramework::InputDeviceKeyboard::Key::Function01 },
{ Qt::Key_F2, AzFramework::InputDeviceKeyboard::Key::Function02 },
{ Qt::Key_F3, AzFramework::InputDeviceKeyboard::Key::Function03 },
{ Qt::Key_F4, AzFramework::InputDeviceKeyboard::Key::Function04 },
{ Qt::Key_F5, AzFramework::InputDeviceKeyboard::Key::Function05 },
{ Qt::Key_F6, AzFramework::InputDeviceKeyboard::Key::Function06 },
{ Qt::Key_F7, AzFramework::InputDeviceKeyboard::Key::Function07 },
{ Qt::Key_F8, AzFramework::InputDeviceKeyboard::Key::Function08 },
{ Qt::Key_F9, AzFramework::InputDeviceKeyboard::Key::Function09 },
{ Qt::Key_F10, AzFramework::InputDeviceKeyboard::Key::Function10 },
{ Qt::Key_F11, AzFramework::InputDeviceKeyboard::Key::Function11 },
{ Qt::Key_F12, AzFramework::InputDeviceKeyboard::Key::Function12 },
{ Qt::Key_F13, AzFramework::InputDeviceKeyboard::Key::Function13 },
{ Qt::Key_F14, AzFramework::InputDeviceKeyboard::Key::Function14 },
{ Qt::Key_F15, AzFramework::InputDeviceKeyboard::Key::Function15 },
{ Qt::Key_F16, AzFramework::InputDeviceKeyboard::Key::Function16 },
{ Qt::Key_F17, AzFramework::InputDeviceKeyboard::Key::Function17 },
{ Qt::Key_F18, AzFramework::InputDeviceKeyboard::Key::Function18 },
{ Qt::Key_F19, AzFramework::InputDeviceKeyboard::Key::Function19 },
{ Qt::Key_F20, AzFramework::InputDeviceKeyboard::Key::Function20 },
{ Qt::Key_Alt, AzFramework::InputDeviceKeyboard::Key::ModifierAltL },
{ Qt::Key_Control, AzFramework::InputDeviceKeyboard::Key::ModifierCtrlL },
{ Qt::Key_Shift, AzFramework::InputDeviceKeyboard::Key::ModifierShiftL },
{ Qt::Key_Super_L, AzFramework::InputDeviceKeyboard::Key::ModifierSuperL },
{ Qt::Key_Super_R, AzFramework::InputDeviceKeyboard::Key::ModifierSuperR },
{ Qt::Key_Down, AzFramework::InputDeviceKeyboard::Key::NavigationArrowDown },
{ Qt::Key_Left, AzFramework::InputDeviceKeyboard::Key::NavigationArrowLeft },
{ Qt::Key_Right, AzFramework::InputDeviceKeyboard::Key::NavigationArrowRight },
{ Qt::Key_Up, AzFramework::InputDeviceKeyboard::Key::NavigationArrowUp },
{ Qt::Key_Delete, AzFramework::InputDeviceKeyboard::Key::NavigationDelete },
{ Qt::Key_End, AzFramework::InputDeviceKeyboard::Key::NavigationEnd },
{ Qt::Key_Home, AzFramework::InputDeviceKeyboard::Key::NavigationHome },
{ Qt::Key_Insert, AzFramework::InputDeviceKeyboard::Key::NavigationInsert },
{ Qt::Key_PageDown, AzFramework::InputDeviceKeyboard::Key::NavigationPageDown },
{ Qt::Key_PageUp, AzFramework::InputDeviceKeyboard::Key::NavigationPageUp },
{ Qt::Key_Apostrophe, AzFramework::InputDeviceKeyboard::Key::PunctuationApostrophe },
{ Qt::Key_Backslash, AzFramework::InputDeviceKeyboard::Key::PunctuationBackslash },
{ Qt::Key_BracketLeft, AzFramework::InputDeviceKeyboard::Key::PunctuationBracketL },
{ Qt::Key_BracketRight, AzFramework::InputDeviceKeyboard::Key::PunctuationBracketR },
{ Qt::Key_Comma, AzFramework::InputDeviceKeyboard::Key::PunctuationComma },
{ Qt::Key_Equal, AzFramework::InputDeviceKeyboard::Key::PunctuationEquals },
{ Qt::Key_hyphen, AzFramework::InputDeviceKeyboard::Key::PunctuationHyphen },
{ Qt::Key_Period, AzFramework::InputDeviceKeyboard::Key::PunctuationPeriod },
{ Qt::Key_Semicolon, AzFramework::InputDeviceKeyboard::Key::PunctuationSemicolon },
{ Qt::Key_Slash, AzFramework::InputDeviceKeyboard::Key::PunctuationSlash },
{ Qt::Key_QuoteLeft, AzFramework::InputDeviceKeyboard::Key::PunctuationTilde },
{ Qt::Key_Pause, AzFramework::InputDeviceKeyboard::Key::WindowsSystemPause },
{ Qt::Key_Print, AzFramework::InputDeviceKeyboard::Key::WindowsSystemPrint },
{ Qt::Key_ScrollLock, AzFramework::InputDeviceKeyboard::Key::WindowsSystemScrollLock },
} };
}
AZStd::array<AZStd::pair<Qt::MouseButton, AzFramework::InputChannelId>, 5> QtEventToAzInputMapper::QtMouseButtonMappings = { {
{ Qt::MouseButton::LeftButton, AzFramework::InputDeviceMouse::Button::Left },
{ Qt::MouseButton::RightButton, AzFramework::InputDeviceMouse::Button::Right },
{ Qt::MouseButton::MiddleButton, AzFramework::InputDeviceMouse::Button::Middle },
{ Qt::MouseButton::ExtraButton1, AzFramework::InputDeviceMouse::Button::Other1 },
{ Qt::MouseButton::ExtraButton2, AzFramework::InputDeviceMouse::Button::Other2 },
} };
void QtEventToAzInputMapper::InitializeMouseButtonMappings()
{
m_mouseButtonMappings = { {
{ Qt::MouseButton::LeftButton, AzFramework::InputDeviceMouse::Button::Left },
{ Qt::MouseButton::RightButton, AzFramework::InputDeviceMouse::Button::Right },
{ Qt::MouseButton::MiddleButton, AzFramework::InputDeviceMouse::Button::Middle },
{ Qt::MouseButton::ExtraButton1, AzFramework::InputDeviceMouse::Button::Other1 },
{ Qt::MouseButton::ExtraButton2, AzFramework::InputDeviceMouse::Button::Other2 },
} };
}
// Currently this is only set for modifier keys.
// This should only be expanded sparingly, any keys handled here will not be bubbled up to the shortcut system.
// ex: If Key_S was here, the viewport would consume S key presses before the application could process a QAction with a Ctrl+S
// shortcut.
AZStd::array<Qt::Key, 5> QtEventToAzInputMapper::HighPriorityKeys = { Qt::Key_Alt, Qt::Key_Control, Qt::Key_Shift, Qt::Key_Super_L,
Qt::Key_Super_R };
void QtEventToAzInputMapper::InitializeHighPriorityKeys()
{
m_highPriorityKeys = { Qt::Key_Alt, Qt::Key_Control, Qt::Key_Shift, Qt::Key_Super_L, Qt::Key_Super_R };
}
QtEventToAzInputMapper::QtEventToAzInputMapper(QWidget* sourceWidget)
QtEventToAzInputMapper::EditorQtKeyboardDevice::EditorQtKeyboardDevice(AzFramework::InputDeviceId id)
: AzFramework::InputDeviceKeyboard(id)
{
// Disable all platform native processing in favor of our Qt event handling
SetImplementation(nullptr);
}
QtEventToAzInputMapper::EditorQtMouseDevice::EditorQtMouseDevice(AzFramework::InputDeviceId id)
: AzFramework::InputDeviceMouse(id)
{
// Disable all platform native processing in favor of our Qt event handling
SetImplementation(nullptr);
}
QtEventToAzInputMapper::QtEventToAzInputMapper(QWidget* sourceWidget, int syntheticDeviceId)
: QObject(sourceWidget)
, m_sourceWidget(sourceWidget)
, m_keyboardModifiers(AZStd::make_shared<AzFramework::ModifierKeyStates>())
, m_cursorPosition(AZStd::make_shared<AzFramework::InputChannel::PositionData2D>())
, m_keyMappings(QtKeyMappings.begin(), QtKeyMappings.end())
, m_mouseButtonMappings(QtMouseButtonMappings.begin(), QtMouseButtonMappings.end())
{
AzFramework::InputDeviceRequests::InputDeviceByIdMap deviceMap;
AzFramework::InputDeviceRequestBus::Broadcast(&AzFramework::InputDeviceRequestBus::Events::GetInputDevicesById, deviceMap);
InitializeKeyMappings();
InitializeMouseButtonMappings();
InitializeHighPriorityKeys();
const AzFramework::InputDevice* keyboardDevice = deviceMap.find(AzFramework::InputDeviceKeyboard::Id)->second;
// Add an arbitrary offset to our device index to avoid collision with real physical device index.
// We still have to use the keyboard and mouse device channel names because input channels are only addressed
// by their own name and their device index, so overlapping input channels between devices would conflict.
constexpr AZ::u32 syntheticDeviceOffset = 1000;
const AzFramework::InputDeviceId keyboardDeviceId(
AzFramework::InputDeviceKeyboard::Id.GetName(), syntheticDeviceId + syntheticDeviceOffset);
const AzFramework::InputDeviceId mouseDeviceId(
AzFramework::InputDeviceMouse::Id.GetName(), syntheticDeviceId + syntheticDeviceOffset);
// Create synthetic keyboard input channels.
for (auto [_, id] : QtKeyMappings)
{
AZStd::unique_ptr<AzFramework::InputChannel> channel =
AZStd::make_unique<AzFramework::InputChannelDigitalWithSharedModifierKeyStates>(id, *keyboardDevice, m_keyboardModifiers);
channel->SetUpdateEventsEnabled(false);
m_channels.emplace(id, AZStd::move(channel));
}
m_keyboardDevice = AZStd::make_unique<EditorQtKeyboardDevice>(keyboardDeviceId);
m_mouseDevice = AZStd::make_unique<EditorQtMouseDevice>(mouseDeviceId);
const AzFramework::InputDevice* mouseDevice = deviceMap.find(AzFramework::InputDeviceMouse::Id)->second;
// Create synthetic mouse button input channels.
for (auto [_, id] : QtMouseButtonMappings)
{
AZStd::unique_ptr<AzFramework::InputChannel> channel =
AZStd::make_unique<AzFramework::InputChannelDigitalWithSharedPosition2D>(id, *mouseDevice, m_cursorPosition);
channel->SetUpdateEventsEnabled(false);
m_channels.emplace(id, AZStd::move(channel));
}
// Create synthetic mouse movement channels.
for (const auto& id : { AzFramework::InputDeviceMouse::Movement::X, AzFramework::InputDeviceMouse::Movement::Y,
AzFramework::InputDeviceMouse::Movement::Z, AzFramework::InputDeviceMouse::SystemCursorPosition })
{
AZStd::unique_ptr<AzFramework::InputChannel> channel =
AZStd::make_unique<AzFramework::InputChannelDeltaWithSharedPosition2D>(id, *mouseDevice, m_cursorPosition);
channel->SetUpdateEventsEnabled(false);
m_channels.emplace(id, AZStd::move(channel));
}
AddChannels(m_keyboardDevice->m_allChannelsById);
AddChannels(m_mouseDevice->m_allChannelsById);
// Install a global event filter to ensure we don't miss mouse and key release events.
QApplication::instance()->installEventFilter(this);
@@ -193,7 +194,8 @@ namespace AzToolsFramework
// We map keyboard and mouse events from Qt, so flag all events coming from those devices
// as handled by our synthetic event system.
const AzFramework::InputDeviceId& deviceId = channel.GetInputDevice().GetInputDeviceId();
return deviceId == AzFramework::InputDeviceMouse::Id || deviceId == AzFramework::InputDeviceKeyboard::Id;
return deviceId.GetNameCrc32() == AzFramework::InputDeviceMouse::Id.GetNameCrc32() ||
deviceId.GetNameCrc32() == AzFramework::InputDeviceKeyboard::Id.GetNameCrc32();
}
bool QtEventToAzInputMapper::eventFilter(QObject* object, QEvent* event)
@@ -222,7 +224,8 @@ namespace AzToolsFramework
// Map key events to input channels.
// ShortcutOverride is used in lieu of KeyPress for high priority input channels like Alt
// that need to be accepted and stopped before they bubble up and cause unintended behavior.
else if (event->type() == QEvent::Type::KeyPress || event->type() == QEvent::Type::KeyRelease ||
else if (
event->type() == QEvent::Type::KeyPress || event->type() == QEvent::Type::KeyRelease ||
event->type() == QEvent::Type::ShortcutOverride)
{
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
@@ -321,11 +324,16 @@ namespace AzToolsFramework
void QtEventToAzInputMapper::HandleKeyEvent(QKeyEvent* keyEvent)
{
// Ignore key repeat events, they're unrelated to actual physical button presses.
if (keyEvent->isAutoRepeat())
{
return;
}
const Qt::Key key = static_cast<Qt::Key>(keyEvent->key());
// For ShortcutEvent, only continue processing if we're in the HighPriorityKeys set.
if (keyEvent->type() != QEvent::Type::ShortcutOverride ||
AZStd::find(HighPriorityKeys.begin(), HighPriorityKeys.end(), key) != HighPriorityKeys.end())
if (keyEvent->type() != QEvent::Type::ShortcutOverride || m_highPriorityKeys.find(key) != m_highPriorityKeys.end())
{
if (auto keyIt = m_keyMappings.find(key); keyIt != m_keyMappings.end())
{
@@ -373,7 +381,7 @@ namespace AzToolsFramework
if (channelData.second->IsActive())
{
channelData.second->UpdateState(false);
NotifyUpdateChannelIfNotIdle(channelData.second.get(), event);
NotifyUpdateChannelIfNotIdle(channelData.second, event);
}
}
m_mouseChannelsNeedUpdate = false;
@@ -20,9 +20,12 @@
#include <AzFramework/Input/Channels/InputChannelDigitalWithSharedModifierKeyStates.h>
#include <AzFramework/Input/Channels/InputChannelDigitalWithSharedPosition2D.h>
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <QEvent>
#include <QObject>
#endif //!defined(Q_MOC_RUN)
#endif //! defined(Q_MOC_RUN)
class QWidget;
class QKeyEvent;
@@ -38,7 +41,7 @@ namespace AzToolsFramework
Q_OBJECT
public:
QtEventToAzInputMapper(QWidget* sourceWidget);
QtEventToAzInputMapper(QWidget* sourceWidget, int syntheticDeviceId = 0);
~QtEventToAzInputMapper() = default;
//! Queries whether a given input channel has a synthetic equivalent mapped
@@ -57,37 +60,71 @@ namespace AzToolsFramework
void InputChannelUpdated(const AzFramework::InputChannel* channel, QEvent* event);
private:
// Gets an input channel of the specified type by ID.
template<class TInputChannel>
TInputChannel* GetInputChannel(const AzFramework::InputChannelId& id)
{
auto channelIt = m_channels.find(id);
if (channelIt != m_channels.end())
{
return static_cast<TInputChannel*>(channelIt->second.get());
return static_cast<TInputChannel*>(channelIt->second);
}
return {};
}
// Adds channels from the specified channel container to our input channel ID -> input channel lookup table.
// Used for rapid lookup.
template <class TContainer>
void AddChannels(const TContainer& container)
{
for (const auto& channelData : container)
{
// Break const as we're taking these input channels from devices we own.
m_channels.emplace(channelData.first, const_cast<AzFramework::InputChannel*>(channelData.second));
}
}
// Our synthetic Keyboard device, does no internal keyboard handling and instead listens to this class for updates.
class EditorQtKeyboardDevice : public AzFramework::InputDeviceKeyboard
{
public:
EditorQtKeyboardDevice(AzFramework::InputDeviceId id);
friend class QtEventToAzInputMapper;
};
// Our synthetic Mouse device, does no internal keyboard handling and instead listens to this class for updates.
class EditorQtMouseDevice : public AzFramework::InputDeviceMouse
{
public:
EditorQtMouseDevice(AzFramework::InputDeviceId id);
friend class QtEventToAzInputMapper;
};
// Emits InputChannelUpdated if channel has transitioned in state (i.e. has gone from active to inactive or vice versa).
void NotifyUpdateChannelIfNotIdle(const AzFramework::InputChannel* channel, QEvent* event);
// Processes any pending mouse movement events, this allows mouse movement channels to close themselves.
void ProcessPendingMouseEvents();
// Handle mouse click events.
void HandleMouseButtonEvent(QMouseEvent* mouseEvent);
// Handle mouse move events.
void HandleMouseMoveEvent(QMouseEvent* mouseEvent);
// Handles key press / release events (or ShortcutOverride events for keys listed in m_highPriorityKeys).
void HandleKeyEvent(QKeyEvent* keyEvent);
// Handles mouse wheel events.
void HandleWheelEvent(QWheelEvent* wheelEvent);
// Handles focus change events.
void HandleFocusChange(QEvent* event);
// Mapping from Qt::Keys to InputChannelIds.
// Used to populate m_keyMappings.
static AZStd::array<AZStd::pair<Qt::Key, AzFramework::InputChannelId>, 91> QtKeyMappings;
// Mapping from Qt::MouseButtons to InputChannelIds.
// Used to populate m_mouseButtonMappings.
static AZStd::array<AZStd::pair<Qt::MouseButton, AzFramework::InputChannelId>, 5> QtMouseButtonMappings;
// A set of high priority keys that need to be processed at the ShortcutOverride level instead of the
// KeyEvent level. This prevents e.g. the main menu bar from processing a press of the "alt" key when the
// viewport consumes the event.
static AZStd::array<Qt::Key, 5> HighPriorityKeys;
// Populates m_keyMappings.
void InitializeKeyMappings();
// Populates m_mouseButtonMappings.
void InitializeMouseButtonMappings();
// Populates m_highPriorityKeys.
void InitializeHighPriorityKeys();
// The current keyboard modifier state used by our synthetic key input channels.
AZStd::shared_ptr<AzFramework::ModifierKeyStates> m_keyboardModifiers;
@@ -97,13 +134,19 @@ namespace AzToolsFramework
AZStd::unordered_map<Qt::Key, AzFramework::InputChannelId> m_keyMappings;
// A lookup table for Qt mouse button -> AZ input channel.
AZStd::unordered_map<Qt::MouseButton, AzFramework::InputChannelId> m_mouseButtonMappings;
// Our set of synthetic input channels that can be mapped by MapQtEventToAzInput.
// These channels do not broadcast state changes to the actual AZ input devices, as we're bypassing
// that system to integrate with Qt to allow coexistence with the platform native implementation.
AZStd::unordered_map<AzFramework::InputChannelId, AZStd::unique_ptr<AzFramework::InputChannel>> m_channels;
// A set of high priority keys that need to be processed at the ShortcutOverride level instead of the
// KeyEvent level. This prevents e.g. the main menu bar from processing a press of the "alt" key when the
// viewport consumes the event.
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;
// The source widget to map events from, used to calculate the relative mouse position within the widget bounds.
QWidget* m_sourceWidget;
// Flags when mouse movement channels have been opened and may need to be closed (as there are no movement ended events).
bool m_mouseChannelsNeedUpdate = false;
// Our viewport-specific AZ devices. We control their internal input channel states.
AZStd::unique_ptr<EditorQtMouseDevice> m_mouseDevice;
AZStd::unique_ptr<EditorQtKeyboardDevice> m_keyboardDevice;
};
} // namespace AzToolsFramework
@@ -131,7 +131,6 @@ namespace AtomToolsFramework
private:
void SendWindowResizeEvent();
bool CanInputGrantFocus(const AzFramework::InputChannel& inputChannel) const;
// The underlying ViewportContext, our entry-point to the Atom RPI.
AZ::RPI::ViewportContextPtr m_viewportContext;
@@ -159,6 +158,6 @@ namespace AtomToolsFramework
// 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);
AzToolsFramework::QtEventToAzInputMapper* m_inputChannelMapper = nullptr;
};
} //namespace AtomToolsFramework
@@ -38,21 +38,6 @@ namespace AtomToolsFramework
setUpdatesEnabled(false);
setFocusPolicy(Qt::FocusPolicy::WheelFocus);
setMouseTracking(true);
// Forward input events to our controller list.
QObject::connect(&m_inputChannelMapper, &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, this,
[this](const AzFramework::InputChannel* inputChannel, QEvent* event)
{
AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
if (m_controllerList->HandleInputChannelEvent({GetId(), windowId, *inputChannel}))
{
// If the controller handled the input event, mark the event as accepted so it doesn't continue to propagate.
if (event)
{
event->setAccepted(true);
}
}
});
}
bool RenderViewportWidget::InitializeViewportContext(AzFramework::ViewportId id)
@@ -96,6 +81,23 @@ namespace AtomToolsFramework
AZ::TickBus::Handler::BusConnect();
AzFramework::WindowRequestBus::Handler::BusConnect(params.windowHandle);
m_inputChannelMapper = new AzToolsFramework::QtEventToAzInputMapper(this, id);
// Forward input events to our controller list.
QObject::connect(m_inputChannelMapper, &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, this,
[this](const AzFramework::InputChannel* inputChannel, QEvent* event)
{
AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
if (m_controllerList->HandleInputChannelEvent({GetId(), windowId, *inputChannel}))
{
// If the controller handled the input event, mark the event as accepted so it doesn't continue to propagate.
if (event)
{
event->setAccepted(true);
}
}
});
return true;
}
@@ -172,7 +174,7 @@ namespace AtomToolsFramework
}
// Only forward channels that aren't covered by our Qt -> AZ event mapper
if (m_inputChannelMapper.HandlesInputEvent(inputChannel))
if (!m_inputChannelMapper || m_inputChannelMapper->HandlesInputEvent(inputChannel))
{
return false;
}