From 43e4b8073445d147be353013e3a7e081e11653ba Mon Sep 17 00:00:00 2001 From: Guillaume MM Date: Fri, 12 Jan 2018 10:58:31 +0100 Subject: [PATCH] Install a new compressor A brand new event compressor based on Kuba Ober's cleverly simple solution: . Fix #9362, #9461, #9933: Lyx suddenly gets keyboard keys wrong, and deadlocks Fix #9790: LyX should perform key event compression (for improving the remote X connections one would also need to implement Qt::WA_KeyCompression) Fix #10516: slowness on repeated arrow keys with IBus and Qt5 Patch pulled from https://github.com/gadmm/lyx-unstable/commit/bf5a1efb0db5bfc2b Signed-off-by: Juergen Spitzmueller --- src/frontends/qt4/GuiWorkArea.cpp | 87 ++++++++++++++++++------------- src/frontends/qt4/GuiWorkArea.h | 20 +++++++ 2 files changed, 71 insertions(+), 36 deletions(-) diff --git a/src/frontends/qt4/GuiWorkArea.cpp b/src/frontends/qt4/GuiWorkArea.cpp index 3d169d02ee..be1b4d4dcc 100644 --- a/src/frontends/qt4/GuiWorkArea.cpp +++ b/src/frontends/qt4/GuiWorkArea.cpp @@ -276,6 +276,7 @@ GuiWorkArea::GuiWorkArea(QWidget * /* w */) GuiWorkArea::GuiWorkArea(Buffer & buffer, GuiView & gv) : d(new Private(this)) { + new CompressorProxy(this); // not a leak setGuiView(gv); buffer.params().display_pixel_ratio = theGuiApp()->pixelRatio(); setBuffer(buffer); @@ -1033,6 +1034,37 @@ void GuiWorkArea::generateSyntheticMouseEvent() } +// CompressorProxy adapted from Kuba Ober https://stackoverflow.com/a/21006207 +CompressorProxy::CompressorProxy(GuiWorkArea * wa) : QObject(wa) +{ + qRegisterMetaType("KeySymbol"); + qRegisterMetaType("KeyModifier"); + connect(wa, &GuiWorkArea::compressKeySym, this, &CompressorProxy::slot, + Qt::QueuedConnection); + connect(this, &CompressorProxy::signal, wa, &GuiWorkArea::processKeySym); +} + + +bool CompressorProxy::emitCheck(bool isAutoRepeat) +{ + flag_ = true; + if (isAutoRepeat) + QCoreApplication::sendPostedEvents(this, QEvent::MetaCall); // recurse + bool result = flag_; + flag_ = false; + return result; +} + + +void CompressorProxy::slot(KeySymbol sym, KeyModifier mod, bool isAutoRepeat) +{ + if (emitCheck(isAutoRepeat)) + Q_EMIT signal(sym, mod); + else + LYXERR(Debug::KEY, "system is busy: autoRepeat key event ignored"); +} + + void GuiWorkArea::keyPressEvent(QKeyEvent * ev) { // this is also called for ShortcutOverride events. In this case, one must @@ -1040,13 +1072,16 @@ void GuiWorkArea::keyPressEvent(QKeyEvent * ev) bool const act = (ev->type() != QEvent::ShortcutOverride); // Do not process here some keys if dialog_mode_ is set - if (d->dialog_mode_ + bool const for_dialog_mode = d->dialog_mode_ && (ev->modifiers() == Qt::NoModifier || ev->modifiers() == Qt::ShiftModifier) && (ev->key() == Qt::Key_Escape || ev->key() == Qt::Key_Enter - || ev->key() == Qt::Key_Return) - ) { + || ev->key() == Qt::Key_Return); + // also do not use autoRepeat to input shortcuts + bool const autoRepeat = ev->isAutoRepeat(); + + if (for_dialog_mode || (!act && autoRepeat)) { ev->ignore(); return; } @@ -1063,51 +1098,31 @@ void GuiWorkArea::keyPressEvent(QKeyEvent * ev) } } - // do nothing if there are other events - // (the auto repeated events come too fast) - // it looks like this is only needed on X11 -#if defined(Q_WS_X11) || defined(QPA_XCB) - // FIXME: this is a weird way to implement event compression. Also, this is - // broken with IBus. - if (act && qApp->hasPendingEvents() && ev->isAutoRepeat()) { - switch (ev->key()) { - case Qt::Key_PageDown: - case Qt::Key_PageUp: - case Qt::Key_Left: - case Qt::Key_Right: - case Qt::Key_Up: - case Qt::Key_Down: - LYXERR(Debug::KEY, "system is busy: scroll key event ignored"); - ev->ignore(); - return; - } - } -#endif - KeyModifier const m = q_key_state(ev->modifiers()); - std::string str; - if (m & ShiftModifier) - str += "Shift-"; - if (m & ControlModifier) - str += "Control-"; - if (m & AltModifier) - str += "Alt-"; - if (m & MetaModifier) - str += "Meta-"; - - if (act) + if (act && lyxerr.debugging(Debug::KEY)) { + std::string str; + if (m & ShiftModifier) + str += "Shift-"; + if (m & ControlModifier) + str += "Control-"; + if (m & AltModifier) + str += "Alt-"; + if (m & MetaModifier) + str += "Meta-"; LYXERR(Debug::KEY, " count: " << ev->count() << " text: " << ev->text() << " isAutoRepeat: " << ev->isAutoRepeat() << " key: " << ev->key() << " keyState: " << str); + } KeySymbol sym; setKeySymbol(&sym, ev); if (sym.isOK()) { if (act) { - processKeySym(sym, m); + Q_EMIT compressKeySym(sym, m, autoRepeat); ev->accept(); } else + // here, !autoRepeat, as determined at the beginning ev->setAccepted(queryKeySym(sym, m)); } else { ev->ignore(); diff --git a/src/frontends/qt4/GuiWorkArea.h b/src/frontends/qt4/GuiWorkArea.h index 4fd524909c..806aefd161 100644 --- a/src/frontends/qt4/GuiWorkArea.h +++ b/src/frontends/qt4/GuiWorkArea.h @@ -16,6 +16,7 @@ #include "ui_WorkAreaUi.h" #include "frontends/WorkArea.h" +#include "frontends/KeySymbol.h" #include #include @@ -97,6 +98,8 @@ Q_SIGNALS: void busy(bool); /// void bufferViewChanged(); + /// send key event to CompressorProxy + void compressKeySym(KeySymbol sym, KeyModifier mod, bool isAutoRepeat); private Q_SLOTS: /// Scroll the BufferView. @@ -157,6 +160,23 @@ private: }; // GuiWorkArea +/// CompressorProxy adapted from Kuba Ober https://stackoverflow.com/a/21006207 +class CompressorProxy : public QObject +{ + Q_OBJECT + bool emitCheck(bool isAutoRepeat); + bool flag_; + // input: event to compress + Q_SLOT void slot(KeySymbol sym, KeyModifier mod, bool isAutoRepeat); + // output: compressed event + Q_SIGNAL void signal(KeySymbol sym, KeyModifier mod); +public: + // No default constructor, since the proxy must be a child of the + // target object. + explicit CompressorProxy(GuiWorkArea * wa); +}; + + class EmbeddedWorkArea : public GuiWorkArea { Q_OBJECT