diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 092a2102..24742ede 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -155,6 +155,8 @@ if(APPLE) set(keepassx_SOURCES ${keepassx_SOURCES} core/ScreenLockListenerMac.h core/ScreenLockListenerMac.cpp + core/MacPasteboard.h + core/MacPasteboard.cpp ) endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") diff --git a/src/core/MacPasteboard.cpp b/src/core/MacPasteboard.cpp new file mode 100644 index 00000000..98dc6f7a --- /dev/null +++ b/src/core/MacPasteboard.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2017 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "MacPasteboard.h" + +QString MacPasteboard::convertorName() { return QLatin1String("MacPasteboard"); } + +QString MacPasteboard::flavorFor(const QString& mimetype) { + if (mimetype == QLatin1String("text/plain")) { + return QLatin1String("public.utf8-plain-text"); + } else if (mimetype == QLatin1String("application/x-nspasteboard-concealed-type")) { + return QLatin1String("org.nspasteboard.ConcealedType"); + } + + int i = mimetype.indexOf(QLatin1String("charset=")); + + if (i >= 0) { + QString cs(mimetype.mid(i + 8).toLower()); + i = cs.indexOf(QLatin1Char(';')); + + if (i >= 0) { + cs = cs.left(i); + } + + if (cs == QLatin1String("system")) { + return QLatin1String("public.utf8-plain-text"); + } else if (cs == QLatin1String("iso-10646-ucs-2") || + cs == QLatin1String("utf16")) { + return QLatin1String("public.utf16-plain-text"); + } + } + return QString(); +} + +QString MacPasteboard::mimeFor(QString flavor) { + if (flavor == QLatin1String("public.utf8-plain-text")) + return QLatin1String("text/plain"); + if (flavor == QLatin1String("org.nspasteboard.ConcealedType")) + return QLatin1String("application/x-nspasteboard-concealed-type"); + if (flavor == QLatin1String("public.utf16-plain-text")) + return QLatin1String("text/plain;charset=utf16"); + return QString(); +} + +bool MacPasteboard::canConvert(const QString& mimetype, QString flavor) { + Q_UNUSED(mimetype); + Q_UNUSED(flavor); + return true; +} + +QVariant MacPasteboard::convertToMime(const QString& mimetype, QList data, QString flavor) { + if (data.count() > 1) + qWarning("QMime::convertToMime: Cannot handle multiple member data"); + const QByteArray& firstData = data.first(); + QVariant ret; + if (flavor == QLatin1String("public.utf8-plain-text")) { + ret = QString::fromUtf8(firstData); + } else if (flavor == QLatin1String("org.nspasteboard.ConcealedType")) { + ret = QString::fromUtf8(firstData); + } else if (flavor == QLatin1String("public.utf16-plain-text")) { + ret = QTextCodec::codecForName("UTF-16")->toUnicode(firstData); + } else { + qWarning("QMime::convertToMime: unhandled mimetype: %s", + qPrintable(mimetype)); + } + return ret; +} + +QList MacPasteboard::convertFromMime(const QString&, QVariant data, QString flavor) { + QList ret; + QString string = data.toString(); + if (flavor == QLatin1String("public.utf8-plain-text")) + ret.append(string.toUtf8()); + else if (flavor == QLatin1String("org.nspasteboard.ConcealedType")) + ret.append(string.toUtf8()); + else if (flavor == QLatin1String("public.utf16-plain-text")) + ret.append(QTextCodec::codecForName("UTF-16")->fromUnicode(string)); + return ret; +} + diff --git a/src/core/MacPasteboard.h b/src/core/MacPasteboard.h new file mode 100644 index 00000000..8461cbc5 --- /dev/null +++ b/src/core/MacPasteboard.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2017 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_MACPASTEBOARD_H +#define KEEPASSXC_MACPASTEBOARD_H + +#include +#include + +class MacPasteboard : public QMacPasteboardMime +{ +public: + explicit MacPasteboard() : QMacPasteboardMime(MIME_ALL) {} + + QString convertorName() override; + bool canConvert(const QString &mime, QString flav) override; + QString mimeFor(QString flav) override; + QString flavorFor(const QString &mime) override; + QVariant convertToMime(const QString &mime, QList data, QString flav) override; + QList convertFromMime(const QString &mime, QVariant data, QString flav) override; +}; + +#endif // KEEPASSXC_MACPASTEBOARD_H diff --git a/src/gui/Clipboard.cpp b/src/gui/Clipboard.cpp index bf4db8ff..78bad273 100644 --- a/src/gui/Clipboard.cpp +++ b/src/gui/Clipboard.cpp @@ -28,6 +28,9 @@ Clipboard* Clipboard::m_instance(nullptr); Clipboard::Clipboard(QObject* parent) : QObject(parent) , m_timer(new QTimer(this)) +#ifdef Q_OS_MAC + , m_pasteboard(new MacPasteboard) +#endif { m_timer->setSingleShot(true); connect(m_timer, SIGNAL(timeout()), SLOT(clearClipboard())); @@ -38,10 +41,17 @@ void Clipboard::setText(const QString& text) { QClipboard* clipboard = QApplication::clipboard(); +#ifdef Q_OS_MAC + QMimeData* mime = new QMimeData; + mime->setText(text); + mime->setData("application/x-nspasteboard-concealed-type", text.toUtf8()); + clipboard->setMimeData(mime, QClipboard::Clipboard); +#else clipboard->setText(text, QClipboard::Clipboard); if (clipboard->supportsSelection()) { clipboard->setText(text, QClipboard::Selection); } +#endif if (config()->get("security/clearclipboard").toBool()) { int timeout = config()->get("security/clearclipboardtimeout").toInt(); diff --git a/src/gui/Clipboard.h b/src/gui/Clipboard.h index e0a16d26..6f8ff9ac 100644 --- a/src/gui/Clipboard.h +++ b/src/gui/Clipboard.h @@ -19,6 +19,9 @@ #define KEEPASSX_CLIPBOARD_H #include +#ifdef Q_OS_MAC +#include "core/MacPasteboard.h" +#endif class QTimer; @@ -43,6 +46,9 @@ private: static Clipboard* m_instance; QTimer* m_timer; +#ifdef Q_OS_MAC + QScopedPointer m_pasteboard; +#endif QString m_lastCopied; };