Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333#include "shortcuteventhandler.hpp"
#include <algorithm>#include <cassert>
#include <QEvent>#include <QKeyEvent>#include <QMouseEvent>#include <QWidget>
#include "shortcut.hpp"
namespace CSMPrefs{ ShortcutEventHandler::ShortcutEventHandler(QObject* parent) : QObject(parent) { }
void ShortcutEventHandler::addShortcut(Shortcut* shortcut) { // Enforced by shortcut class QWidget* widget = static_cast<QWidget*>(shortcut->parent());
// Check if widget setup is needed ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget); if (shortcutListIt == mWidgetShortcuts.end()) { // Create list shortcutListIt = mWidgetShortcuts.insert(std::make_pair(widget, ShortcutList())).first;
// Check if widget has a parent with shortcuts, unfortunately it is not typically set yet updateParent(widget);
// Intercept widget events widget->installEventFilter(this); connect(widget, &QWidget::destroyed, this, &ShortcutEventHandler::widgetDestroyed); }
// Add to list shortcutListIt->second.push_back(shortcut); }
void ShortcutEventHandler::removeShortcut(Shortcut* shortcut) { // Enforced by shortcut class QWidget* widget = static_cast<QWidget*>(shortcut->parent());
ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget); if (shortcutListIt != mWidgetShortcuts.end()) { shortcutListIt->second.erase( std::remove(shortcutListIt->second.begin(), shortcutListIt->second.end(), shortcut), shortcutListIt->second.end()); } }
bool ShortcutEventHandler::eventFilter(QObject* watched, QEvent* event) { // Process event if (event->type() == QEvent::KeyPress) { QWidget* widget = static_cast<QWidget*>(watched); QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (!keyEvent->isAutoRepeat()) return activate(widget, keyEvent->keyCombination()); } else if (event->type() == QEvent::KeyRelease) { QWidget* widget = static_cast<QWidget*>(watched); QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (!keyEvent->isAutoRepeat()) return deactivate(widget, keyEvent->keyCombination()); } else if (event->type() == QEvent::MouseButtonPress) { QWidget* widget = static_cast<QWidget*>(watched); QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
return activate(widget, QKeyCombination(mouseEvent->modifiers(), Qt::Key(mouseEvent->button()))); } else if (event->type() == QEvent::MouseButtonRelease) { QWidget* widget = static_cast<QWidget*>(watched); QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
return deactivate(widget, QKeyCombination(mouseEvent->modifiers(), Qt::Key(mouseEvent->button()))); } else if (event->type() == QEvent::FocusOut) { QWidget* widget = static_cast<QWidget*>(watched); ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget); assert(shortcutListIt != mWidgetShortcuts.end());
// Deactivate in case events are missed for (ShortcutList::iterator it = shortcutListIt->second.begin(); it != shortcutListIt->second.end(); ++it) { Shortcut* shortcut = *it;
shortcut->setPosition(0); shortcut->setModifierStatus(false);
if (shortcut->getActivationStatus() == Shortcut::AS_Regular) { shortcut->setActivationStatus(Shortcut::AS_Inactive); shortcut->signalActivated(false); } else if (shortcut->getActivationStatus() == Shortcut::AS_Secondary) { shortcut->setActivationStatus(Shortcut::AS_Inactive); shortcut->signalSecondary(false); } } } else if (event->type() == QEvent::FocusIn) { QWidget* widget = static_cast<QWidget*>(watched); updateParent(widget); }
return false; }
void ShortcutEventHandler::updateParent(QWidget* widget) { QWidget* parent = widget->parentWidget(); while (parent) { ShortcutMap::iterator parentIt = mWidgetShortcuts.find(parent); if (parentIt != mWidgetShortcuts.end()) { mChildParentRelations.insert(std::make_pair(widget, parent)); updateParent(parent); break; }
// Check next parent = parent->parentWidget(); } }
bool ShortcutEventHandler::activate(QWidget* widget, QKeyCombination keyCombination) { std::vector<std::pair<MatchResult, Shortcut*>> potentials; bool used = false;
while (widget) { ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget); assert(shortcutListIt != mWidgetShortcuts.end());
// Find potential activations for (ShortcutList::iterator it = shortcutListIt->second.begin(); it != shortcutListIt->second.end(); ++it) { Shortcut* shortcut = *it;
if (!shortcut->isEnabled()) continue;
if (checkModifier(keyCombination, shortcut, true)) used = true;
if (shortcut->getActivationStatus() != Shortcut::AS_Inactive) continue;
int pos = shortcut->getPosition(); int lastPos = shortcut->getLastPosition(); MatchResult result = match(keyCombination.keyboardModifiers(), keyCombination.key(), shortcut->getSequence()[pos].toCombined());
if (result == Matches_WithMod || result == Matches_NoMod) { if (pos < lastPos && (result == Matches_WithMod || pos > 0)) { shortcut->setPosition(pos + 1); } else if (pos == lastPos) { potentials.emplace_back(result, shortcut); } } }
// Move on to parent WidgetMap::iterator widgetIt = mChildParentRelations.find(widget); widget = (widgetIt != mChildParentRelations.end()) ? widgetIt->second : 0; }
// Only activate the best match; in exact conflicts, this will favor the first shortcut added. if (!potentials.empty()) { std::stable_sort(potentials.begin(), potentials.end(), ShortcutEventHandler::sort); Shortcut* shortcut = potentials.front().second;
if (shortcut->getModifierStatus() && shortcut->getSecondaryMode() == Shortcut::SM_Replace) { shortcut->setActivationStatus(Shortcut::AS_Secondary); shortcut->signalSecondary(true); shortcut->signalSecondary(); } else { shortcut->setActivationStatus(Shortcut::AS_Regular); shortcut->signalActivated(true); shortcut->signalActivated(); }
used = true; }
return used; }
bool ShortcutEventHandler::deactivate(QWidget* widget, QKeyCombination keyCombination) { bool used = false;
while (widget) { ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget); assert(shortcutListIt != mWidgetShortcuts.end());
for (ShortcutList::iterator it = shortcutListIt->second.begin(); it != shortcutListIt->second.end(); ++it) { Shortcut* shortcut = *it;
if (checkModifier(keyCombination, shortcut, false)) used = true;
int pos = shortcut->getPosition(); MatchResult result = match(0, keyCombination.key(), shortcut->getSequence()[pos].key());
if (result != Matches_Not) { shortcut->setPosition(0);
if (shortcut->getActivationStatus() == Shortcut::AS_Regular) { shortcut->setActivationStatus(Shortcut::AS_Inactive); shortcut->signalActivated(false); used = true; } else if (shortcut->getActivationStatus() == Shortcut::AS_Secondary) { shortcut->setActivationStatus(Shortcut::AS_Inactive); shortcut->signalSecondary(false); used = true; } } }
// Move on to parent WidgetMap::iterator widgetIt = mChildParentRelations.find(widget); widget = (widgetIt != mChildParentRelations.end()) ? widgetIt->second : 0; }
return used; }
bool ShortcutEventHandler::checkModifier(QKeyCombination keyCombination, Shortcut* shortcut, bool activate) { if (!shortcut->isEnabled() || !shortcut->getModifier() || shortcut->getSecondaryMode() == Shortcut::SM_Ignore || shortcut->getModifierStatus() == activate) return false;
MatchResult result = match(keyCombination.keyboardModifiers(), keyCombination.key(), shortcut->getModifier()); bool used = false;
if (result != Matches_Not) { shortcut->setModifierStatus(activate);
if (shortcut->getSecondaryMode() == Shortcut::SM_Detach) { if (activate) { shortcut->signalSecondary(true); shortcut->signalSecondary(); } else { shortcut->signalSecondary(false); } } else if (!activate && shortcut->getActivationStatus() == Shortcut::AS_Secondary) { shortcut->setActivationStatus(Shortcut::AS_Inactive); shortcut->setPosition(0); shortcut->signalSecondary(false); used = true; } }
return used; }
ShortcutEventHandler::MatchResult ShortcutEventHandler::match( unsigned int mod, unsigned int button, unsigned int value) { if ((mod | button) == value) { return Matches_WithMod; } else if (button == value) { return Matches_NoMod; } else { return Matches_Not; } }
bool ShortcutEventHandler::sort( const std::pair<MatchResult, Shortcut*>& left, const std::pair<MatchResult, Shortcut*>& right) { if (left.first == Matches_WithMod && right.first == Matches_NoMod) return true; else return left.second->getPosition() > right.second->getPosition(); }
void ShortcutEventHandler::widgetDestroyed() { QWidget* widget = static_cast<QWidget*>(sender());
mWidgetShortcuts.erase(widget); mChildParentRelations.erase(widget); }}