Qt: Properly handle modifier keys for input
This commit is contained in:
parent
6d5eca13a6
commit
87889a13e0
|
@ -15,36 +15,52 @@ InputButtonBindingWidget::InputButtonBindingWidget(QtHostInterface* host_interfa
|
|||
connect(this, &QPushButton::pressed, this, &InputButtonBindingWidget::onPressed);
|
||||
}
|
||||
|
||||
InputButtonBindingWidget::~InputButtonBindingWidget() = default;
|
||||
|
||||
void InputButtonBindingWidget::keyPressEvent(QKeyEvent* event)
|
||||
InputButtonBindingWidget::~InputButtonBindingWidget()
|
||||
{
|
||||
// ignore the key press if we're listening for input
|
||||
if (isListeningForInput())
|
||||
return;
|
||||
|
||||
QPushButton::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void InputButtonBindingWidget::keyReleaseEvent(QKeyEvent* event)
|
||||
{
|
||||
if (!isListeningForInput())
|
||||
{
|
||||
QPushButton::keyReleaseEvent(event);
|
||||
return;
|
||||
}
|
||||
|
||||
QString key_name = QtUtils::GetKeyIdentifier(event->key());
|
||||
if (!key_name.isEmpty())
|
||||
{
|
||||
// TODO: Update input map
|
||||
m_current_binding_value = QStringLiteral("Keyboard/%1").arg(key_name);
|
||||
m_host_interface->getQSettings().setValue(m_setting_name, m_current_binding_value);
|
||||
}
|
||||
|
||||
stopListeningForInput();
|
||||
}
|
||||
|
||||
bool InputButtonBindingWidget::eventFilter(QObject* watched, QEvent* event)
|
||||
{
|
||||
const QEvent::Type event_type = event->type();
|
||||
|
||||
// if the key is being released, set the input
|
||||
if (event_type == QEvent::KeyRelease)
|
||||
{
|
||||
setNewBinding();
|
||||
stopListeningForInput();
|
||||
return true;
|
||||
}
|
||||
else if (event_type == QEvent::KeyPress)
|
||||
{
|
||||
QString binding = QtUtils::KeyEventToString(static_cast<QKeyEvent*>(event));
|
||||
if (!binding.isEmpty())
|
||||
m_new_binding_value = QStringLiteral("Keyboard/%1").arg(binding);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (event_type == QEvent::MouseButtonPress || event_type == QEvent::MouseButtonRelease ||
|
||||
event_type == QEvent::MouseButtonDblClick)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void InputButtonBindingWidget::setNewBinding()
|
||||
{
|
||||
if (m_new_binding_value.isEmpty())
|
||||
return;
|
||||
|
||||
m_host_interface->getQSettings().setValue(m_setting_name, m_new_binding_value);
|
||||
m_host_interface->updateInputMap();
|
||||
|
||||
m_current_binding_value = std::move(m_new_binding_value);
|
||||
m_new_binding_value.clear();
|
||||
}
|
||||
|
||||
void InputButtonBindingWidget::onPressed()
|
||||
{
|
||||
if (isListeningForInput())
|
||||
|
@ -75,6 +91,10 @@ void InputButtonBindingWidget::startListeningForInput()
|
|||
&InputButtonBindingWidget::onInputListenTimerTimeout);
|
||||
m_input_listen_remaining_seconds = 5;
|
||||
setText(tr("Push Button... [%1]").arg(m_input_listen_remaining_seconds));
|
||||
|
||||
installEventFilter(this);
|
||||
grabKeyboard();
|
||||
grabMouse();
|
||||
}
|
||||
|
||||
void InputButtonBindingWidget::stopListeningForInput()
|
||||
|
@ -82,4 +102,8 @@ void InputButtonBindingWidget::stopListeningForInput()
|
|||
setText(m_current_binding_value);
|
||||
delete m_input_listen_timer;
|
||||
m_input_listen_timer = nullptr;
|
||||
|
||||
releaseMouse();
|
||||
releaseKeyboard();
|
||||
removeEventFilter(this);
|
||||
}
|
||||
|
|
|
@ -15,8 +15,7 @@ public:
|
|||
~InputButtonBindingWidget();
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
void keyReleaseEvent(QKeyEvent* event) override;
|
||||
bool eventFilter(QObject* watched, QEvent* event) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void onPressed();
|
||||
|
@ -26,10 +25,12 @@ private:
|
|||
bool isListeningForInput() const { return m_input_listen_timer != nullptr; }
|
||||
void startListeningForInput();
|
||||
void stopListeningForInput();
|
||||
void setNewBinding();
|
||||
|
||||
QtHostInterface* m_host_interface;
|
||||
QString m_setting_name;
|
||||
QString m_current_binding_value;
|
||||
QString m_new_binding_value;
|
||||
QTimer* m_input_listen_timer = nullptr;
|
||||
u32 m_input_listen_remaining_seconds = 0;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "qtdisplaywindow.h"
|
||||
#include "imgui.h"
|
||||
#include "qtutils.h"
|
||||
#include "qthostinterface.h"
|
||||
#include <QtGui/QKeyEvent>
|
||||
|
||||
|
@ -75,7 +76,7 @@ void QtDisplayWindow::keyPressEvent(QKeyEvent* event)
|
|||
if (event->isAutoRepeat())
|
||||
return;
|
||||
|
||||
m_host_interface->handleKeyEvent(event->key(), true);
|
||||
m_host_interface->handleKeyEvent(QtUtils::KeyEventToInt(event), true);
|
||||
}
|
||||
|
||||
void QtDisplayWindow::keyReleaseEvent(QKeyEvent* event)
|
||||
|
@ -83,7 +84,7 @@ void QtDisplayWindow::keyReleaseEvent(QKeyEvent* event)
|
|||
if (event->isAutoRepeat())
|
||||
return;
|
||||
|
||||
m_host_interface->handleKeyEvent(event->key(), false);
|
||||
m_host_interface->handleKeyEvent(QtUtils::KeyEventToInt(event), false);
|
||||
}
|
||||
|
||||
void QtDisplayWindow::resizeEvent(QResizeEvent* event)
|
||||
|
|
|
@ -297,7 +297,7 @@ void QtHostInterface::addButtonToInputMap(const QString& binding, InputButtonHan
|
|||
const QString button = binding.section('/', 1, 1);
|
||||
if (device == QStringLiteral("Keyboard"))
|
||||
{
|
||||
std::optional<int> key_id = QtUtils::GetKeyIdForIdentifier(button);
|
||||
std::optional<int> key_id = QtUtils::ParseKeyString(button);
|
||||
if (!key_id.has_value())
|
||||
{
|
||||
qWarning() << "Unknown keyboard key " << button;
|
||||
|
|
|
@ -1,10 +1,32 @@
|
|||
#include "qtutils.h"
|
||||
#include <QtGui/QKeyEvent>
|
||||
#include <QtWidgets/QDialog>
|
||||
#include <QtWidgets/QMainWindow>
|
||||
#include <QtWidgets/QTableView>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
namespace QtUtils {
|
||||
|
||||
QWidget* GetRootWidget(QWidget* widget, bool stop_at_window_or_dialog)
|
||||
{
|
||||
QWidget* next_parent = widget->parentWidget();
|
||||
while (next_parent)
|
||||
{
|
||||
if (stop_at_window_or_dialog && (widget->metaObject()->inherits(&QMainWindow::staticMetaObject) ||
|
||||
widget->metaObject()->inherits(&QDialog::staticMetaObject)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
widget = next_parent;
|
||||
next_parent = widget->parentWidget();
|
||||
}
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
void ResizeColumnsForTableView(QTableView* view, const std::initializer_list<int>& widths)
|
||||
{
|
||||
const int total_width =
|
||||
|
@ -461,6 +483,22 @@ static const std::map<int, QString> s_qt_key_names = {
|
|||
{Qt::Key_Camera, QStringLiteral("Camera")},
|
||||
{Qt::Key_CameraFocus, QStringLiteral("CameraFocus")}};
|
||||
|
||||
struct QtKeyModifierEntry
|
||||
{
|
||||
Qt::KeyboardModifier mod;
|
||||
Qt::Key key;
|
||||
QString name;
|
||||
};
|
||||
|
||||
static const std::array<QtKeyModifierEntry, 5> s_qt_key_modifiers = {
|
||||
{{Qt::ShiftModifier, Qt::Key_Shift, QStringLiteral("Shift")},
|
||||
{Qt::ControlModifier, Qt::Key_Control, QStringLiteral("Control")},
|
||||
{Qt::AltModifier, Qt::Key_Alt, QStringLiteral("Alt")},
|
||||
{Qt::MetaModifier, Qt::Key_Meta, QStringLiteral("Meta")},
|
||||
{Qt::KeypadModifier, static_cast<Qt::Key>(0), QStringLiteral("Keypad")}}};
|
||||
static const Qt::KeyboardModifiers s_qt_modifier_mask =
|
||||
Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier | Qt::KeypadModifier;
|
||||
|
||||
QString GetKeyIdentifier(int key)
|
||||
{
|
||||
const auto it = s_qt_key_names.find(key);
|
||||
|
@ -478,4 +516,59 @@ std::optional<int> GetKeyIdForIdentifier(const QString& key_identifier)
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
QString KeyEventToString(const QKeyEvent* ke)
|
||||
{
|
||||
const int key = ke->key();
|
||||
QString key_name = GetKeyIdentifier(key);
|
||||
if (key_name.isEmpty())
|
||||
return {};
|
||||
|
||||
QString ret;
|
||||
const Qt::KeyboardModifiers mods = ke->modifiers();
|
||||
for (const QtKeyModifierEntry& mod : s_qt_key_modifiers)
|
||||
{
|
||||
if (mods & mod.mod && key != mod.key)
|
||||
{
|
||||
ret.append(mod.name);
|
||||
ret.append('+');
|
||||
}
|
||||
}
|
||||
|
||||
ret.append(key_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::optional<int> ParseKeyString(const QString& key_str)
|
||||
{
|
||||
const QStringList sections = key_str.split('+');
|
||||
std::optional<int> key_id = GetKeyIdForIdentifier(sections.last());
|
||||
if (!key_id)
|
||||
return std::nullopt;
|
||||
|
||||
int ret = key_id.value();
|
||||
|
||||
if (sections.size() > 1)
|
||||
{
|
||||
const int num_modifiers = sections.size() - 1;
|
||||
for (int i = 0; i < num_modifiers; i++)
|
||||
{
|
||||
for (const QtKeyModifierEntry& mod : s_qt_key_modifiers)
|
||||
{
|
||||
if (sections[i] == mod.name)
|
||||
{
|
||||
ret |= static_cast<int>(mod.mod);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int KeyEventToInt(const QKeyEvent* ke)
|
||||
{
|
||||
return static_cast<int>(ke->modifiers() & s_qt_modifier_mask) | ke->key();
|
||||
}
|
||||
|
||||
} // namespace QtUtils
|
|
@ -3,10 +3,15 @@
|
|||
#include <initializer_list>
|
||||
#include <optional>
|
||||
|
||||
class QKeyEvent;
|
||||
class QTableView;
|
||||
class QWidget;
|
||||
|
||||
namespace QtUtils {
|
||||
|
||||
/// Returns the greatest parent of a widget, i.e. its dialog/window.
|
||||
QWidget* GetRootWidget(QWidget* widget, bool stop_at_window_or_dialog = true);
|
||||
|
||||
/// Resizes columns of the table view to at the specified widths. A width of -1 will stretch the column to use the
|
||||
/// remaining space.
|
||||
void ResizeColumnsForTableView(QTableView* view, const std::initializer_list<int>& widths);
|
||||
|
@ -17,4 +22,13 @@ QString GetKeyIdentifier(int key);
|
|||
/// Returns the integer Qt key ID for an identifier.
|
||||
std::optional<int> GetKeyIdForIdentifier(const QString& key_identifier);
|
||||
|
||||
/// Stringizes a key event.
|
||||
QString KeyEventToString(const QKeyEvent* ke);
|
||||
|
||||
/// Returns an integer id for a stringized key event. Modifiers are in the upper bits.
|
||||
std::optional<int> ParseKeyString(const QString& key_str);
|
||||
|
||||
/// Returns a key id for a key event, including any modifiers.
|
||||
int KeyEventToInt(const QKeyEvent* ke);
|
||||
|
||||
} // namespace QtUtils
|
Loading…
Reference in New Issue