Handle EMotionFX hotkeys with QActions instead of in keyPressEvent (#514)

EMotionFX has user-customizable hotkeys. These hotkeys are registered by
individual plugins, and then the user can set what they want the hotkey to
be. The way this was implemented was by reimplementing `keyPressEvent` and
`keyReleaseEvent` for each widget that used customizable hotkeys, and in
there call `KeyboardShortcutManager::Check` to see if key press matched any
existing hotkey mapping.

However, the main Editor has behavior that prevents events from reaching
EMotionFX's `keyPressEvent` method, if a keypress matches a hotkey that is
also used by the main Editor. This is due to the global event filter
defined in `ShortcutDispatcher::eventFilter`. This event filter takes a Qt
`Shortcut` event, and will re-dispatch that event to all parent widgets of
a given receiver. So if a parent widget, like the main Editor, *does* have
a QAction that matches a given key sequence, that widget will receive the
event, the event is marked as processed, and no `KeyPress` event is ever
sent to the original widget where the event occurred.

All this means that processing hotkeys in a `keyPressEvent` won't work
reliably. The main editor defines a hotkey for the `delete` key, so that
can never be received in a `keyPressEvent` by any child widget of the
Editor.

This change removes all the hotkey logic from the `keyPressEvent` methods,
and replaces them with `QAction` instances. Hotkeys are defined with
`QAction::setShortcut`, and added to each widget that they apply to.

In addition, the `KeyboardShortcutManager` class had to be adjusted to suit
this new way of defining the hotkeys. It now has a pointer to each
`QAction*` that can have a customizable hotkey. It has also been greatly
simplified, since it can use a `QKeySequence` instead of separate variables
for `int key; bool hasCtrlModifier; bool hasAltModifier`.

Applying user-defined hotkeys now has to be done after the hotkeys are
registered from a plugin. It is the plugin's responsibility to reload the
user-defined hotkeys after registering all of its actions.
This commit is contained in:
Chris Burel
2021-05-03 15:00:40 -07:00
committed by GitHub
parent 53d47736c6
commit 13c7b06308
29 changed files with 703 additions and 1095 deletions
@@ -18,6 +18,7 @@
#include <EMotionFX/Source/AnimGraphMotionNode.h>
#include <EMotionFX/Source/AnimGraphStateMachine.h>
#include <EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphPlugin.h>
#include <EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphViewWidget.h>
#include <QApplication>
#include <QtTest>
#include "qtestsystem.h"
@@ -80,9 +81,8 @@ namespace EMotionFX
ASSERT_TRUE(modelIndex.isValid()) << "Anim graph transition has an invalid model index.";
animGraphModel.GetSelectionModel().select(QItemSelection(modelIndex, modelIndex), QItemSelectionModel::Current | QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
// Delete key pressed.
EMStudio::BlendGraphWidget* blendGraphWidget = animGraphPlugin->GetGraphWidget();
QTest::keyClick((QWidget*)blendGraphWidget, Qt::Key_Delete);
EMStudio::BlendGraphViewWidget* blendGraphViewWidget = animGraphPlugin->GetViewWidget();
blendGraphViewWidget->GetAction(EMStudio::BlendGraphViewWidget::EDIT_DELETE)->trigger();
// Check if the transition get deleted.
ASSERT_EQ(0, m_animGraph->GetRootStateMachine()->GetNumTransitions()) << " Anim Graph transition should be removed";