fix: use alternative clipboard change monitor on macOS

QClipboard cannot monitor data changes on mac unless an application is focused
This commit is contained in:
shenleban tongying 2023-02-17 21:09:56 -05:00
parent 737d4421f5
commit 497ecf3719
6 changed files with 114 additions and 10 deletions

View file

@ -174,6 +174,8 @@ if (APPLE)
texttospeechsource.cc
texttospeechsource.hh
texttospeechsource.ui
src/platform/gd_clipboard.cpp
src/platform/gd_clipboard.h
)
endif ()

View file

@ -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 {

View file

@ -14,8 +14,6 @@
#include "mruqmenu.hh"
#include "gestures.hh"
#include "dictheadwords.hh"
#include <limits.h>
#include <QDebug>
#include <QTextStream>
#include <QDir>
#include <QUrl>
@ -36,7 +34,6 @@
#include <QThreadPool>
#include <QSslConfiguration>
#include <limits.h>
#include <set>
#include <map>
#include "gddebug.hh"
@ -859,7 +856,26 @@ MainWindow::MainWindow( Config::Class & cfg_ ):
inspector.reset( new ArticleInspector( this ));
// 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,8 +934,10 @@ 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
}
}

View file

@ -40,6 +40,10 @@
#include <fixx11h.h>
#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 );

View file

@ -0,0 +1,36 @@
#include "gd_clipboard.h"
#include <QGuiApplication>
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
}

View file

@ -0,0 +1,38 @@
#pragma once
#include <QClipboard>
#include <QObject>
#include <QString>
#include <QTimer>
/**
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);
};