[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [ktexteditor] src: Annoyingly, in Qt 5.5 we can no longer trigger shortcuts by replaying
From:       Simon St James <kdedevel () etotheipiplusone ! com>
Date:       2016-06-18 8:35:36
Message-ID: E1bEBj6-0002HX-6I () code ! kde ! org
[Download RAW message or body]

Git commit 025edb11ca9b0fa3685802e6c9cb608a4daa7911 by Simon St James.
Committed on 18/06/2016 at 08:35.
Pushed by sstjames into branch 'master'.

Annoyingly, in Qt 5.5 we can no longer trigger shortcuts by replaying \
QKeyEvents (something that the Vi Mode - which stores and swallows all key \
events by default in case they are part of a Mapping and replays them if it \
turns out they weren't - depends on), so if we are stealing shortcuts, they \
will no longer be triggered e.g. pressing Ctrl+S will not save! This patch \
reworks the whole mechanism, moving from "swallow all QKeyEvents and maybe \
replay later" to "decide whether to swallow shortcuts, but if not, let Qt's \
shortcut handling system despatch the QShortcutOverride itself". This \
mostly fixes things, though we can't e.g. create a mapping that, when \
triggered, saves the document or triggers any of Kate's shortcuts, plus \
some other small edge cases :(

BUG:35333
REVIEW:D1894

M  +1    -1    src/inputmode/kateabstractinputmode.h
M  +1    -1    src/inputmode/katenormalinputmode.cpp
M  +1    -1    src/inputmode/katenormalinputmode.h
M  +25   -22   src/inputmode/kateviinputmode.cpp
M  +3    -1    src/inputmode/kateviinputmode.h
M  +4    -2    src/vimode/emulatedcommandbar/emulatedcommandbar.cpp
M  +2    -1    src/vimode/emulatedcommandbar/emulatedcommandbar.h
M  +1    -1    src/vimode/inputmodemanager.cpp
M  +28   -2    src/vimode/keymapper.cpp
M  +7    -2    src/vimode/modes/normalvimode.cpp

http://commits.kde.org/ktexteditor/025edb11ca9b0fa3685802e6c9cb608a4daa7911

diff --git a/src/inputmode/kateabstractinputmode.h \
b/src/inputmode/kateabstractinputmode.h index 70d9512..c34f3ba 100644
--- a/src/inputmode/kateabstractinputmode.h
+++ b/src/inputmode/kateabstractinputmode.h
@@ -53,7 +53,7 @@ public:
     virtual bool overwrite() const = 0;
     virtual void overwrittenChar(const QChar &) = 0;
     virtual void clearSelection() = 0;
-    virtual bool stealKey(const QKeyEvent *) const = 0;
+    virtual bool stealKey(QKeyEvent* k) = 0;
 
     virtual void gotFocus() = 0;
     virtual void lostFocus() = 0;
diff --git a/src/inputmode/katenormalinputmode.cpp \
b/src/inputmode/katenormalinputmode.cpp index 4990892..bc18f65 100644
--- a/src/inputmode/katenormalinputmode.cpp
+++ b/src/inputmode/katenormalinputmode.cpp
@@ -67,7 +67,7 @@ void KateNormalInputMode::clearSelection()
     view()->clearSelection();
 }
 
-bool KateNormalInputMode::stealKey(const QKeyEvent *) const
+bool KateNormalInputMode::stealKey( QKeyEvent *)
 {
     return false;
 }
diff --git a/src/inputmode/katenormalinputmode.h \
b/src/inputmode/katenormalinputmode.h index fcb4e7f..7baaad0 100644
--- a/src/inputmode/katenormalinputmode.h
+++ b/src/inputmode/katenormalinputmode.h
@@ -46,7 +46,7 @@ public:
     void overwrittenChar(const QChar &) Q_DECL_OVERRIDE;
 
     void clearSelection() Q_DECL_OVERRIDE;
-    bool stealKey(const QKeyEvent *) const Q_DECL_OVERRIDE;
+    bool stealKey(QKeyEvent *) Q_DECL_OVERRIDE;
 
     void gotFocus() Q_DECL_OVERRIDE;
     void lostFocus() Q_DECL_OVERRIDE;
diff --git a/src/inputmode/kateviinputmode.cpp \
b/src/inputmode/kateviinputmode.cpp index 557cec1..a7609cd 100644
--- a/src/inputmode/kateviinputmode.cpp
+++ b/src/inputmode/kateviinputmode.cpp
@@ -65,6 +65,7 @@ KateViInputMode::KateViInputMode(KateViewInternal \
*viewInternal, KateVi::GlobalS  , m_viModeEmulatedCommandBar(0)
     , m_viGlobal(global)
     , m_caret(KateRenderer::Block)
+    , m_nextKeypressIsOverriddenShortCut(false)
     , m_activated(false)
 {
     m_relLineNumbers = KateViewConfig::global()->viRelativeLineNumbers();
@@ -131,11 +132,22 @@ void KateViInputMode::clearSelection()
     // do nothing, handled elsewhere
 }
 
-bool KateViInputMode::stealKey(const QKeyEvent *k) const
+bool KateViInputMode::stealKey(QKeyEvent *k)
 {
-    const bool steal = KateViewConfig::global()->viInputModeStealKeys();
-    return steal && (m_viModeManager->getCurrentViMode() != \
                KateVi::ViMode::InsertMode ||
-                        k->modifiers() == Qt::ControlModifier || k->key() \
== Qt::Key_Insert); +    if \
(!KateViewConfig::global()->viInputModeStealKeys()) +    {
+        return false;
+    }
+
+    // Actually see if we can make use of this key - if so, we've stolen \
it; if not, +    // let Qt's shortcut handling system deal with it.
+    const bool stolen = keyPress(k);
+    if (stolen)
+    {
+        // Qt will replay this QKeyEvent, next time as an ordinary \
KeyPress. +        m_nextKeypressIsOverriddenShortCut = true;
+    }
+    return stolen;
 }
 
 KTextEditor::View::InputMode KateViInputMode::viewInputMode() const
@@ -255,7 +267,7 @@ void KateViInputMode::showViModeEmulatedCommandBar()
 KateVi::EmulatedCommandBar *KateViInputMode::viModeEmulatedCommandBar()
 {
     if (!m_viModeEmulatedCommandBar) {
-        m_viModeEmulatedCommandBar = new \
KateVi::EmulatedCommandBar(m_viModeManager, view()); +        \
m_viModeEmulatedCommandBar = new KateVi::EmulatedCommandBar(this, \
m_viModeManager, view());  m_viModeEmulatedCommandBar->hide();
     }
 
@@ -269,24 +281,15 @@ void KateViInputMode::updateRendererConfig()
 
 bool KateViInputMode::keyPress(QKeyEvent *e)
 {
-    if (m_viModeManager->getCurrentViMode() == KateVi::InsertMode ||
-        m_viModeManager->getCurrentViMode() == KateVi::ReplaceMode) {
+    if (m_nextKeypressIsOverriddenShortCut)
+    {
+        // This is just the replay of a shortcut that we stole, this time \
as a QKeyEvent. +        // Ignore it, as we'll have already handled it via \
stealKey()! +        m_nextKeypressIsOverriddenShortCut = false;
+        return true;
+    }
 
-        if (m_viModeManager->handleKeypress(e)) {
-            return true;
-        } else if (e->modifiers() != Qt::NoModifier && e->modifiers() != \
                Qt::ShiftModifier) {
-            // re-post key events not handled if they have a modifier \
                other than shift
-            QEvent *copy = new QKeyEvent(e->type(), e->key(), \
                e->modifiers(), e->text(),
-                                         e->isAutoRepeat(), e->count());
-            QCoreApplication::postEvent(viewInternal()->parent(), copy);
-        }
-    } else { // !InsertMode
-        if (!m_viModeManager->handleKeypress(e)) {
-            // we didn't need that keypress, un-steal it :-)
-            QEvent *copy = new QKeyEvent(e->type(), e->key(), \
                e->modifiers(), e->text(),
-                                            e->isAutoRepeat(), \
                e->count());
-            QCoreApplication::postEvent(viewInternal()->parent(), copy);
-        }
+    if (m_viModeManager->handleKeypress(e)) {
         emit view()->viewModeChanged(view(), viewMode());
         return true;
     }
diff --git a/src/inputmode/kateviinputmode.h \
b/src/inputmode/kateviinputmode.h index 21f95cb..330148f 100644
--- a/src/inputmode/kateviinputmode.h
+++ b/src/inputmode/kateviinputmode.h
@@ -49,7 +49,7 @@ public:
     void overwrittenChar(const QChar &) Q_DECL_OVERRIDE;
 
     void clearSelection() Q_DECL_OVERRIDE;
-    bool stealKey(const QKeyEvent *) const Q_DECL_OVERRIDE;
+    bool stealKey(QKeyEvent *) Q_DECL_OVERRIDE;
 
     void gotFocus() Q_DECL_OVERRIDE;
     void lostFocus() Q_DECL_OVERRIDE;
@@ -92,6 +92,8 @@ private:
     KateVi::GlobalState *m_viGlobal;
     KateRenderer::caretStyles m_caret;
 
+    bool m_nextKeypressIsOverriddenShortCut;
+
     // configs
     bool m_relLineNumbers;
     bool m_activated;
diff --git a/src/vimode/emulatedcommandbar/emulatedcommandbar.cpp \
b/src/vimode/emulatedcommandbar/emulatedcommandbar.cpp index \
                818ec95..3197981 100644
--- a/src/vimode/emulatedcommandbar/emulatedcommandbar.cpp
+++ b/src/vimode/emulatedcommandbar/emulatedcommandbar.cpp
@@ -27,6 +27,7 @@
 #include "../globalstate.h"
 #include <vimode/keyparser.h>
 #include <vimode/inputmodemanager.h>
+#include <inputmode/kateviinputmode.h>
 #include <vimode/modes/normalvimode.h>
 #include "matchhighlighter.h"
 #include "interactivesedreplacemode.h"
@@ -69,8 +70,9 @@ QString escapedForSearchingAsLiteral(const QString \
&originalQtRegex)  }
 }
 
-EmulatedCommandBar::EmulatedCommandBar(InputModeManager \
*viInputModeManager, QWidget *parent) \
+EmulatedCommandBar::EmulatedCommandBar(KateViInputMode* viInputMode, \
InputModeManager *viInputModeManager, QWidget *parent)  : \
KateViewBarWidget(false, parent), +      m_viInputMode(viInputMode),
       m_viInputModeManager(viInputModeManager),
       m_view(viInputModeManager->view())
 {
@@ -230,7 +232,7 @@ bool EmulatedCommandBar::eventFilter(QObject *object, \
QEvent *event)  if (event->type() == QEvent::KeyPress) {
         // Re-route this keypress through Vim's central keypress handling \
area, so that we can use the keypress in e.g.  // mappings and macros.
-        return m_viInputModeManager->handleKeypress(static_cast<QKeyEvent \
*>(event)); +        return m_viInputMode->keyPress(static_cast<QKeyEvent \
*>(event));  }
     return false;
 }
diff --git a/src/vimode/emulatedcommandbar/emulatedcommandbar.h \
b/src/vimode/emulatedcommandbar/emulatedcommandbar.h index 2751cae..3704662 \
                100644
--- a/src/vimode/emulatedcommandbar/emulatedcommandbar.h
+++ b/src/vimode/emulatedcommandbar/emulatedcommandbar.h
@@ -56,7 +56,7 @@ class KTEXTEDITOR_EXPORT EmulatedCommandBar : public \
KateViewBarWidget  
 public:
     enum Mode { NoMode, SearchForward, SearchBackward, Command };
-    explicit EmulatedCommandBar(InputModeManager *viInputModeManager, \
QWidget *parent = 0); +    explicit EmulatedCommandBar(KateViInputMode* \
viInputMode, InputModeManager *viInputModeManager, QWidget *parent = 0);  \
virtual ~EmulatedCommandBar();  void init(Mode mode, const QString \
&initialText = QString());  bool isActive();
@@ -71,6 +71,7 @@ public:
 
 private:
 
+    KateViInputMode *m_viInputMode;
     InputModeManager *m_viInputModeManager;
     bool m_isActive = false;
     bool m_wasAborted = true;
diff --git a/src/vimode/inputmodemanager.cpp \
b/src/vimode/inputmodemanager.cpp index db06acf..650c09e 100644
--- a/src/vimode/inputmodemanager.cpp
+++ b/src/vimode/inputmodemanager.cpp
@@ -118,7 +118,7 @@ bool InputModeManager::handleKeypress(const QKeyEvent \
                *e)
     // of a mapping, we don't want to record them when they are played \
                back by m_keyMapper, hence
     // the "!isPlayingBackRejectedKeys()". And obviously, since we're \
                recording keys before they are mapped, we don't
     // want to also record the executed mapping, as when we replayed the \
                macro, we'd get duplication!
-    if (m_macroRecorder->isRecording() && !m_macroRecorder->isReplaying() \
&& !isSyntheticSearchCompletedKeyPress && \
!keyMapper()->isExecutingMapping() && \
!keyMapper()->isPlayingBackRejectedKeys()) { +    if \
(m_macroRecorder->isRecording() && !m_macroRecorder->isReplaying() && \
!isSyntheticSearchCompletedKeyPress && !keyMapper()->isExecutingMapping() \
&& !keyMapper()->isPlayingBackRejectedKeys() && \
!lastChangeRecorder()->isReplaying()) {  m_macroRecorder->record(*e);
     }
 
diff --git a/src/vimode/keymapper.cpp b/src/vimode/keymapper.cpp
index 10091de..887b3f6 100644
--- a/src/vimode/keymapper.cpp
+++ b/src/vimode/keymapper.cpp
@@ -26,6 +26,7 @@
 #include <vimode/keymapper.h>
 #include <vimode/keyparser.h>
 #include <vimode/inputmodemanager.h>
+#include "macrorecorder.h"
 
 #include <QTimer>
 
@@ -119,8 +120,33 @@ bool KeyMapper::handleKeypress(QChar key)
         // We've been swallowing all the keypresses meant for m_keys for \
our mapping keys; now that we know  // this cannot be a mapping, restore \
them.  Q_ASSERT(!isPartialMapping && !isFullMapping);
-        playBackRejectedKeys();
-        return true;
+        const bool isUserKeypress = \
!m_viInputModeManager->macroRecorder()->isReplaying() && \
!isExecutingMapping(); +        if (isUserKeypress && m_mappingKeys.size() \
== 1) +        {
+            // Ugh - unpleasant complication starting with Qt 5.5-ish - it \
is no +            // longer possible to replay QKeyEvents in such a way \
that shortcuts +            // are triggered, so if we want to correctly \
handle a shortcut (e.g. +            // ctrl+s for e.g. Save), we can no \
longer pop it into m_mappingKeys +            // then immediately \
playBackRejectedKeys() (as this will not trigger +            // the e.g. \
Save shortcut) - the best we can do is, if e.g. ctrl+s is +            // \
not part of any mapping, immediately return false, *not* calling +          \
// playBackRejectedKeys() and clearing m_mappingKeys ourselves. +           \
// If e.g. ctrl+s *is* part of a mapping, then if the mapping is +          \
// rejected, the played back e.g. ctrl+s does not trigger the e.g. +        \
// Save shortcut. Likewise, we can no longer have e.g. ctrl+s inside +      \
// mappings or macros - the e.g. Save shortcut will not be triggered! +     \
// Altogether, a pretty disastrous change from Qt's old behaviour - +       \
// either they "fix" it (although it could be argued that being able +      \
// to trigger shortcuts from QKeyEvents was never the desired behaviour) +  \
// or we try to emulate Shortcut-handling ourselves :( +            \
m_mappingKeys.clear(); +            return false;
+        }
+        else
+        {
+            playBackRejectedKeys();
+            return true;
+        }
     }
     m_doNotMapNextKeypress = false;
     return false;
diff --git a/src/vimode/modes/normalvimode.cpp \
b/src/vimode/modes/normalvimode.cpp index b306376..e8dbb4f 100644
--- a/src/vimode/modes/normalvimode.cpp
+++ b/src/vimode/modes/normalvimode.cpp
@@ -426,11 +426,16 @@ bool NormalViMode::handleKeypress(const QKeyEvent *e)
         }
     } else if (m_matchingCommands.size() == 0 && m_matchingMotions.size() \
== 0) {  resetParser();
-        return false;
+        // A bit ugly:  we haven't made use of the key event,
+        // but don't want "typeable" keypresses (e.g. a, b, 3, etc) to be \
marked +        // as unused as they will then be added to the document, \
but we don't +        // want to swallow all keys in case this was a \
shortcut. +        // So say we made use of it if and only if it was *not* \
a shortcut. +        return e->type() != QEvent::ShortcutOverride;
     }
 
     m_matchingMotions.clear();
-    return false;
+    return true; // TODO - need to check this - it's currently required \
for making tests pass, but seems odd.  }
 
 /**


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic