From 497ecf3719edc84b2aaf54347cfeb3f88e541849 Mon Sep 17 00:00:00 2001 From: shenleban tongying Date: Fri, 17 Feb 2023 21:09:56 -0500 Subject: [PATCH] fix: use alternative clipboard change monitor on macOS QClipboard cannot monitor data changes on mac unless an application is focused --- CMakeLists.txt | 2 ++ goldendict.pro | 6 ++++-- mainwindow.cc | 34 +++++++++++++++++++++++-------- mainwindow.hh | 8 ++++++++ src/platform/gd_clipboard.cpp | 36 +++++++++++++++++++++++++++++++++ src/platform/gd_clipboard.h | 38 +++++++++++++++++++++++++++++++++++ 6 files changed, 114 insertions(+), 10 deletions(-) create mode 100644 src/platform/gd_clipboard.cpp create mode 100644 src/platform/gd_clipboard.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cb9fed2..f26d0525 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -174,6 +174,8 @@ if (APPLE) texttospeechsource.cc texttospeechsource.hh texttospeechsource.ui + src/platform/gd_clipboard.cpp + src/platform/gd_clipboard.h ) endif () diff --git a/goldendict.pro b/goldendict.pro index 7c6c2239..cc17ea5e 100644 --- a/goldendict.pro +++ b/goldendict.pro @@ -559,9 +559,11 @@ win32 { mac { HEADERS += macmouseover.hh \ texttospeechsource.hh \ - speechclient.hh + speechclient.hh \ + src/platform/gd_clipboard.h FORMS += texttospeechsource.ui - SOURCES += texttospeechsource.cc + SOURCES += texttospeechsource.cc \ + src/platform/gd_clipboard.cpp } unix:!mac { diff --git a/mainwindow.cc b/mainwindow.cc index 96fc109a..ba9cc366 100644 --- a/mainwindow.cc +++ b/mainwindow.cc @@ -14,8 +14,6 @@ #include "mruqmenu.hh" #include "gestures.hh" #include "dictheadwords.hh" -#include -#include #include #include #include @@ -36,7 +34,6 @@ #include #include -#include #include #include #include "gddebug.hh" @@ -859,7 +856,26 @@ MainWindow::MainWindow( Config::Class & cfg_ ): inspector.reset( new ArticleInspector( this )); - connect( QApplication::clipboard(), &QClipboard::changed, this, &MainWindow::clipboardChange ); + // Clipboard related +#ifdef Q_OS_MAC + macClipboard = new gd_clipboard(); + connect(macClipboard, &gd_clipboard::changed, this, &MainWindow::clipboardChange ); + connect(enableScanningAction,&QAction::changed,[this](){ + if (enableScanningAction->isChecked()){ + macClipboard->start(); + } else { + macClipboard->stop(); + } + }); +#else + connect(enableScanningAction,&QAction::changed,[this](){ + if (enableScanningAction->isChecked()){ + connect( QApplication::clipboard(), &QClipboard::changed, this, &MainWindow::clipboardChange ); + } else { + disconnect(QApplication::clipboard(), &QClipboard::changed, this, &MainWindow::clipboardChange); + } + }); +#endif #ifdef Q_OS_WIN // Regiser and update URL Scheme for windows @@ -879,9 +895,9 @@ MainWindow::MainWindow( Config::Class & cfg_ ): void MainWindow::clipboardChange( QClipboard::Mode m) { - if( scanPopup && enableScanningAction->isChecked() ) + if( scanPopup ) { -#ifdef HAVE_X11 +#if defined(HAVE_X11) if(m == QClipboard::Clipboard){ if(!cfg.preferences.trackClipboardScan) return; scanPopup->translateWordFromClipboard(); @@ -918,10 +934,12 @@ void MainWindow::clipboardChange( QClipboard::Mode m) // Use delay show to prevent multiple popups while selection in progress scanPopup->selectionDelayTimer.start(); } +#elif defined(Q_OS_MAC) + scanPopup->translateWord(macClipboard->text()); #else - scanPopup ->translateWordFromClipboard(); + scanPopup->translateWordFromClipboard(); #endif - } + } } void MainWindow::ctrlTabPressed() diff --git a/mainwindow.hh b/mainwindow.hh index f7457ed0..be67d1f8 100644 --- a/mainwindow.hh +++ b/mainwindow.hh @@ -40,6 +40,10 @@ #include #endif +#if defined(Q_OS_MAC) +#include "platform/gd_clipboard.h" +#endif + using std::string; using std::vector; @@ -182,6 +186,10 @@ private: IframeSchemeHandler * iframeSchemeHandler; ResourceSchemeHandler * resourceSchemeHandler; +#ifdef Q_OS_MAC + gd_clipboard * macClipboard; +#endif + /// Applies the custom Qt stylesheet void applyQtStyleSheet( QString const & addonStyle, QString const & displayStyle ,bool const & darkMode ); diff --git a/src/platform/gd_clipboard.cpp b/src/platform/gd_clipboard.cpp new file mode 100644 index 00000000..8145d7c4 --- /dev/null +++ b/src/platform/gd_clipboard.cpp @@ -0,0 +1,36 @@ +#include "gd_clipboard.h" +#include + +gd_clipboard::gd_clipboard(QObject *parent) + : QObject{parent}, + sysClipboard(QGuiApplication::clipboard()) { + + connect(&m_monitoringTimer, &QTimer::timeout, this, [this]() { + updateClipboard(); + }); +} + +QString gd_clipboard::text() const { + return m_currentContent; +} + +void gd_clipboard::updateClipboard() { + const QString newContent = this->sysClipboard->text().trimmed(); + + // get rid of change if new clipboard content is equal to previous version + if (newContent == m_currentContent || + newContent.length() == 0) { // avoid spaces + return; + } + + m_currentContent = newContent; + emit changed(QClipboard::Clipboard); +} + +void gd_clipboard::stop() { + m_monitoringTimer.stop(); +} + +void gd_clipboard::start() { + m_monitoringTimer.start(1000); // 1s +} \ No newline at end of file diff --git a/src/platform/gd_clipboard.h b/src/platform/gd_clipboard.h new file mode 100644 index 00000000..5f7da917 --- /dev/null +++ b/src/platform/gd_clipboard.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include + +/** +A custom clipboard monitor that read keep reading clipboard in background. +QClipboard on macOS only triggers when the app is focused. +Code was inspired by +https://github.com/KDE/kdeconnect-kde/blob/v22.12.2/plugins/clipboard/clipboardlistener.cpp +*/ + +class gd_clipboard : public QObject { +Q_OBJECT +public: + explicit gd_clipboard(QObject * parent = nullptr); + + [[nodiscard]] QString text() const; + + void stop(); + + void start(); + +private: + + QClipboard * sysClipboard; + QString curClipboardContent; + + QTimer m_monitoringTimer; + QString m_currentContent; + void updateClipboard(); + +signals: + void changed(QClipboard::Mode mode); +}; +