|
|
@@ -14,13 +14,10 @@ extern VConfigManager *g_config;
|
|
|
VCaptain::VCaptain(QWidget *p_parent)
|
|
|
: QWidget(p_parent),
|
|
|
m_mode(CaptainMode::Normal),
|
|
|
- m_widgetBeforeNavigation(NULL),
|
|
|
+ m_widgetBeforeCaptain(NULL),
|
|
|
m_nextMajorKey('a'),
|
|
|
- m_ignoreFocusChange(false),
|
|
|
- m_leaderKey(g_config->getShortcutKeySequence("CaptainMode"))
|
|
|
+ m_ignoreFocusChange(false)
|
|
|
{
|
|
|
- Q_ASSERT(!m_leaderKey.isEmpty());
|
|
|
-
|
|
|
connect(qApp, &QApplication::focusChanged,
|
|
|
this, &VCaptain::handleFocusChanged);
|
|
|
|
|
|
@@ -30,6 +27,14 @@ VCaptain::VCaptain(QWidget *p_parent)
|
|
|
// of VMainWindow.
|
|
|
resize(1, 1);
|
|
|
|
|
|
+ // Register Captain mode leader key.
|
|
|
+ // This can fix the Input Method blocking issue.
|
|
|
+ QShortcut *shortcut = new QShortcut(QKeySequence(g_config->getShortcutKeySequence("CaptainMode")),
|
|
|
+ this);
|
|
|
+ shortcut->setContext(Qt::ApplicationShortcut);
|
|
|
+ connect(shortcut, &QShortcut::activated,
|
|
|
+ this, &VCaptain::trigger);
|
|
|
+
|
|
|
// Register Navigation mode as Captain mode target.
|
|
|
registerCaptainTarget(tr("NavigationMode"),
|
|
|
g_config->getCaptainShortcutKeySequence("NavigationMode"),
|
|
|
@@ -61,11 +66,21 @@ void VCaptain::handleFocusChanged(QWidget *p_old, QWidget * p_now)
|
|
|
{
|
|
|
Q_UNUSED(p_now);
|
|
|
|
|
|
- if (!m_ignoreFocusChange
|
|
|
- && !checkMode(CaptainMode::Normal)
|
|
|
- && p_old == this) {
|
|
|
- exitNavigationMode();
|
|
|
+ if (p_old == this
|
|
|
+ && !m_ignoreFocusChange
|
|
|
+ && !checkMode(CaptainMode::Normal)) {
|
|
|
+ exitCaptainMode();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void VCaptain::trigger()
|
|
|
+{
|
|
|
+ if (!checkMode(CaptainMode::Normal)) {
|
|
|
+ exitCaptainMode();
|
|
|
+ return;
|
|
|
}
|
|
|
+
|
|
|
+ triggerCaptainMode();
|
|
|
}
|
|
|
|
|
|
void VCaptain::keyPressEvent(QKeyEvent *p_event)
|
|
|
@@ -73,7 +88,9 @@ void VCaptain::keyPressEvent(QKeyEvent *p_event)
|
|
|
int key = p_event->key();
|
|
|
Qt::KeyboardModifiers modifiers = p_event->modifiers();
|
|
|
|
|
|
- if (key == Qt::Key_Control || key == Qt::Key_Shift) {
|
|
|
+ Q_ASSERT(!checkMode(CaptainMode::Normal));
|
|
|
+
|
|
|
+ if (VUtils::isMetaKey(key)) {
|
|
|
QWidget::keyPressEvent(p_event);
|
|
|
return;
|
|
|
}
|
|
|
@@ -87,18 +104,19 @@ void VCaptain::keyPressEvent(QKeyEvent *p_event)
|
|
|
|
|
|
bool VCaptain::handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers)
|
|
|
{
|
|
|
- if (!checkMode(CaptainMode::Navigation)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
+ bool ret = true;
|
|
|
|
|
|
- if (p_key == Qt::Key_Escape
|
|
|
- || (p_key == Qt::Key_BracketLeft
|
|
|
- && p_modifiers == Qt::ControlModifier)) {
|
|
|
- exitNavigationMode();
|
|
|
- return true;
|
|
|
+ m_ignoreFocusChange = true;
|
|
|
+
|
|
|
+ if (checkMode(CaptainMode::Navigation)) {
|
|
|
+ ret = handleKeyPressNavigationMode(p_key, p_modifiers);
|
|
|
+ m_ignoreFocusChange = false;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
- return handleKeyPressNavigationMode(p_key, p_modifiers);
|
|
|
+ ret = handleKeyPressCaptainMode(p_key, p_modifiers);
|
|
|
+ m_ignoreFocusChange = false;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
bool VCaptain::handleKeyPressNavigationMode(int p_key,
|
|
|
@@ -107,7 +125,6 @@ bool VCaptain::handleKeyPressNavigationMode(int p_key,
|
|
|
Q_ASSERT(m_mode == CaptainMode::Navigation);
|
|
|
bool hasConsumed = false;
|
|
|
bool pending = false;
|
|
|
- m_ignoreFocusChange = true;
|
|
|
for (auto &target : m_naviTargets) {
|
|
|
if (hasConsumed) {
|
|
|
target.m_available = false;
|
|
|
@@ -122,7 +139,7 @@ bool VCaptain::handleKeyPressNavigationMode(int p_key,
|
|
|
hasConsumed = true;
|
|
|
if (succeed) {
|
|
|
// Exit.
|
|
|
- m_widgetBeforeNavigation = NULL;
|
|
|
+ m_widgetBeforeCaptain = NULL;
|
|
|
} else {
|
|
|
// Consumed but not succeed. Need more keys.
|
|
|
pending = true;
|
|
|
@@ -135,21 +152,18 @@ bool VCaptain::handleKeyPressNavigationMode(int p_key,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- m_ignoreFocusChange = false;
|
|
|
if (pending) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- exitNavigationMode();
|
|
|
+ exitCaptainMode();
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
void VCaptain::triggerNavigationMode()
|
|
|
{
|
|
|
setMode(CaptainMode::Navigation);
|
|
|
- m_widgetBeforeNavigation = QApplication::focusWidget();
|
|
|
- // Focus to listen pending key press.
|
|
|
- setFocus();
|
|
|
+
|
|
|
for (auto &target : m_naviTargets) {
|
|
|
target.m_available = true;
|
|
|
target.m_target->showNavigation();
|
|
|
@@ -164,17 +178,30 @@ void VCaptain::exitNavigationMode()
|
|
|
target.m_available = true;
|
|
|
target.m_target->hideNavigation();
|
|
|
}
|
|
|
-
|
|
|
- restoreFocus();
|
|
|
}
|
|
|
|
|
|
void VCaptain::restoreFocus()
|
|
|
{
|
|
|
- if (m_widgetBeforeNavigation) {
|
|
|
- m_widgetBeforeNavigation->setFocus();
|
|
|
+ if (m_widgetBeforeCaptain) {
|
|
|
+ m_widgetBeforeCaptain->setFocus();
|
|
|
+ m_widgetBeforeCaptain = NULL;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void VCaptain::exitCaptainMode()
|
|
|
+{
|
|
|
+ if (checkMode(CaptainMode::Navigation)) {
|
|
|
+ exitNavigationMode();
|
|
|
+ }
|
|
|
+
|
|
|
+ setMode(CaptainMode::Normal);
|
|
|
+ m_ignoreFocusChange = false;
|
|
|
+
|
|
|
+ restoreFocus();
|
|
|
+
|
|
|
+ qDebug() << "exit Captain mode";
|
|
|
+}
|
|
|
+
|
|
|
bool VCaptain::registerCaptainTarget(const QString &p_name,
|
|
|
const QString &p_key,
|
|
|
void *p_target,
|
|
|
@@ -184,48 +211,72 @@ bool VCaptain::registerCaptainTarget(const QString &p_name,
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- QString lowerKey = p_key.toLower();
|
|
|
+ QString normKey = QKeySequence(p_key).toString();
|
|
|
|
|
|
- if (m_captainTargets.contains(lowerKey)) {
|
|
|
+ if (m_captainTargets.contains(normKey)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- // Register shortcuts.
|
|
|
- QString sequence = QString("%1,%2").arg(m_leaderKey).arg(p_key);
|
|
|
- QShortcut *shortcut = new QShortcut(QKeySequence(sequence),
|
|
|
- this);
|
|
|
- shortcut->setContext(Qt::ApplicationShortcut);
|
|
|
-
|
|
|
- connect(shortcut, &QShortcut::activated,
|
|
|
- this, std::bind(&VCaptain::triggerCaptainTarget, this, p_key));
|
|
|
-
|
|
|
-
|
|
|
CaptainModeTarget target(p_name,
|
|
|
- p_key,
|
|
|
+ normKey,
|
|
|
p_target,
|
|
|
- p_func,
|
|
|
- shortcut);
|
|
|
- m_captainTargets.insert(lowerKey, target);
|
|
|
+ p_func);
|
|
|
+ m_captainTargets.insert(normKey, target);
|
|
|
|
|
|
- qDebug() << "registered:" << target.toString() << sequence;
|
|
|
+ qDebug() << "registered:" << target.toString() << normKey;
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
void VCaptain::triggerCaptainTarget(const QString &p_key)
|
|
|
{
|
|
|
- auto it = m_captainTargets.find(p_key.toLower());
|
|
|
- Q_ASSERT(it != m_captainTargets.end());
|
|
|
+ auto it = m_captainTargets.find(p_key);
|
|
|
+ if (it == m_captainTargets.end()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
const CaptainModeTarget &target = it.value();
|
|
|
|
|
|
qDebug() << "triggered:" << target.toString();
|
|
|
|
|
|
- target.m_function(target.m_target, nullptr);
|
|
|
+ CaptainData data(m_widgetBeforeCaptain);
|
|
|
+ if (!target.m_function(target.m_target, (void *)&data)) {
|
|
|
+ m_widgetBeforeCaptain = NULL;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-void VCaptain::navigationModeByCaptain(void *p_target, void *p_data)
|
|
|
+bool VCaptain::navigationModeByCaptain(void *p_target, void *p_data)
|
|
|
{
|
|
|
Q_UNUSED(p_data);
|
|
|
VCaptain *obj = static_cast<VCaptain *>(p_target);
|
|
|
obj->triggerNavigationMode();
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+void VCaptain::triggerCaptainMode()
|
|
|
+{
|
|
|
+ qDebug() << "trigger Captain mode";
|
|
|
+
|
|
|
+ m_widgetBeforeCaptain = QApplication::focusWidget();
|
|
|
+
|
|
|
+ m_ignoreFocusChange = false;
|
|
|
+
|
|
|
+ setMode(CaptainMode::Pending);
|
|
|
+
|
|
|
+ // Focus to listen pending key press.
|
|
|
+ setFocus();
|
|
|
+}
|
|
|
+
|
|
|
+bool VCaptain::handleKeyPressCaptainMode(int p_key,
|
|
|
+ Qt::KeyboardModifiers p_modifiers)
|
|
|
+{
|
|
|
+ Q_ASSERT(checkMode(CaptainMode::Pending));
|
|
|
+ QString normKey = QKeySequence(p_key | p_modifiers).toString();
|
|
|
+ triggerCaptainTarget(normKey);
|
|
|
+
|
|
|
+ if (!checkMode(CaptainMode::Navigation)) {
|
|
|
+ exitCaptainMode();
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
}
|