summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/wasm
diff options
context:
space:
mode:
authorLorn Potter <lorn.potter@gmail.com>2018-02-22 04:35:25 +1000
committerMorten Johan Sørvig <morten.sorvig@qt.io>2019-02-15 12:46:57 +0000
commit2c6c724949374b17bd3da2938fe8747b480d575a (patch)
tree6a2f6dfb2e291a2d2fdcf9fd4883fce9efb8601f /src/plugins/platforms/wasm
parentef2ddcf551dec13215cb45cb000731f94b2f8e34 (diff)
wasm: add clipboard support
This feature uses the js Clipboard API and is supported only in Chrome, as Firefox only supports reading the clipboard in browser extensions. It also requires https or localhost access, otherwise access to the clipboard is blocked by chrome. Chrome users will be able to copy/paste text to and from the system clipbaord. Other browsers will be able to use the clipboard from within the same application. Currently only supports text and html. Task-number: QTBUG-64638 Change-Id: Ie6de9d10812b776519bd6115593b433fe77059fe Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
Diffstat (limited to 'src/plugins/platforms/wasm')
-rw-r--r--src/plugins/platforms/wasm/qwasmclipboard.cpp204
-rw-r--r--src/plugins/platforms/wasm/qwasmclipboard.h59
-rw-r--r--src/plugins/platforms/wasm/qwasmeventtranslator.cpp23
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.cpp18
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.h8
-rw-r--r--src/plugins/platforms/wasm/wasm.pro6
6 files changed, 307 insertions, 11 deletions
diff --git a/src/plugins/platforms/wasm/qwasmclipboard.cpp b/src/plugins/platforms/wasm/qwasmclipboard.cpp
new file mode 100644
index 0000000000..ec058f05dd
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmclipboard.cpp
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwasmclipboard.h"
+#include "qwasmwindow.h"
+
+#include <emscripten.h>
+#include <emscripten/html5.h>
+#include <emscripten/bind.h>
+
+#include <QCoreApplication>
+#include <qpa/qwindowsysteminterface.h>
+
+using namespace emscripten;
+
+// there has got to be a better way...
+static QByteArray g_clipboardArray;
+static QByteArray g_clipboardFormat;
+
+static val getClipboardData()
+{
+ return val(g_clipboardArray.constData());
+}
+
+static val getClipboardFormat()
+{
+ return val(g_clipboardFormat.constData());
+}
+
+static void pasteClipboardData(emscripten::val format, emscripten::val dataPtr)
+{
+ QString formatString = QString::fromStdString(format.as<std::string>());
+ QByteArray dataArray = QByteArray::fromStdString(dataPtr.as<std::string>());
+ QMimeData *mMimeData = new QMimeData;
+ mMimeData->setData(formatString, dataArray);
+ QWasmClipboard::qWasmClipboardPaste(mMimeData);
+}
+
+static void qClipboardPromiseResolve(emscripten::val something)
+{
+ pasteClipboardData(emscripten::val("text/plain"), something);
+}
+
+static void qClipboardCopyTo(val event)
+{
+ val target = event["target"];
+ val clipboard = event["clipboardData"];
+
+ val module = val::global("Module");
+ val clipdata = module.call<val>("getClipboardData");
+ val clipFormat = module.call<val>("getClipboardFormat");
+ clipboard.call<void>("setData", clipFormat, clipdata);
+ target.call<void>("preventDefault");
+}
+
+static void qClipboardPasteTo(val event)
+{
+ val target = event["clipboardData"];
+ val module = val::global("Module");
+ val clipdata = module.call<val>("getClipboardData");
+
+ const std::string data = clipdata.as<std::string>();
+ if (data.length() > 0) {
+ QString qstr = QString::fromStdString(data);
+ QMimeData *mMimeData = new QMimeData;
+ mMimeData->setText(qstr);
+ QWasmClipboard::qWasmClipboardPaste(mMimeData);
+ }
+}
+
+EMSCRIPTEN_BINDINGS(clipboard_module) {
+ function("getClipboardData", &getClipboardData);
+ function("getClipboardFormat", &getClipboardFormat);
+ function("pasteClipboardData", &pasteClipboardData);
+ function("qClipboardPromiseResolve", &qClipboardPromiseResolve);
+ function("qClipboardCopyTo", &qClipboardCopyTo);
+ function("qClipboardPasteTo", &qClipboardPasteTo);
+}
+
+QWasmClipboard::QWasmClipboard() :
+ hasClipboardApi(false)
+{
+ initClipboardEvents();
+}
+
+QWasmClipboard::~QWasmClipboard()
+{
+ g_clipboardArray.clear();
+ g_clipboardFormat.clear();
+}
+
+QMimeData* QWasmClipboard::mimeData(QClipboard::Mode mode)
+{
+ if (mode != QClipboard::Clipboard)
+ return nullptr;
+
+ return QPlatformClipboard::mimeData(mode);
+}
+
+void QWasmClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode)
+{
+ if (mimeData->hasText()) {
+ g_clipboardFormat = mimeData->formats().at(0).toUtf8();
+ g_clipboardArray = mimeData->text().toUtf8();
+ } else if (mimeData->hasHtml()) {
+ g_clipboardFormat =mimeData->formats().at(0).toUtf8();
+ g_clipboardArray = mimeData->html().toUtf8();
+ }
+
+ QPlatformClipboard::setMimeData(mimeData, mode);
+}
+
+bool QWasmClipboard::supportsMode(QClipboard::Mode mode) const
+{
+ return mode == QClipboard::Clipboard;
+}
+
+bool QWasmClipboard::ownsMode(QClipboard::Mode mode) const
+{
+ Q_UNUSED(mode);
+ return false;
+}
+
+void QWasmClipboard::qWasmClipboardPaste(QMimeData *mData)
+{
+ QWasmIntegration::get()->clipboard()->setMimeData(mData, QClipboard::Clipboard);
+
+ QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
+ 0, QEvent::KeyPress, Qt::Key_V, Qt::ControlModifier, "V");
+}
+
+void QWasmClipboard::initClipboardEvents()
+{
+ val navigator = val::global("navigator");
+ val permissions = navigator["permissions"];
+ val clipboard = navigator["clipboard"];
+
+ hasClipboardApi = (!clipboard.isUndefined());
+ if (hasClipboardApi) {
+ val readPermissionsMap = val::object();
+ readPermissionsMap.set("name", val("clipboard-read"));
+ permissions.call<val>("query", readPermissionsMap);
+
+ val writePermissionsMap = val::object();
+ writePermissionsMap.set("name", val("clipboard-write"));
+ permissions.call<val>("query", writePermissionsMap);
+
+ } else {
+
+ val window = val::global("window");
+ window.call<void>("addEventListener", std::string("paste"),
+ val::module_property("qClipboardPasteTo"));
+
+ window.call<void>("addEventListener", std::string("copy"),
+ val::module_property("qClipboardCopyTo"));
+ }
+}
+
+void QWasmClipboard::readTextFromClipboard()
+{
+ if (QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) {
+ val navigator = val::global("navigator");
+ val textPromise = navigator["clipboard"].call<val>("readText");
+ val readTextResolve = val::global("Module")["qClipboardPromiseResolve"];
+ textPromise.call<val>("then", readTextResolve);
+ }
+}
+
+void QWasmClipboard::writeTextToClipboard()
+{
+ if (QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) {
+ val module = val::global("Module");
+ val txt = module.call<val>("getClipboardData");
+ val format = module.call<val>("getClipboardFormat");
+ val navigator = val::global("navigator");
+ navigator["clipboard"].call<void>("writeText", txt.as<std::string>());
+ }
+}
diff --git a/src/plugins/platforms/wasm/qwasmclipboard.h b/src/plugins/platforms/wasm/qwasmclipboard.h
new file mode 100644
index 0000000000..e64b2e5007
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmclipboard.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWasmClipboard_H
+#define QWasmClipboard_H
+
+#include <QObject>
+
+#include <qpa/qplatformclipboard.h>
+#include <QMimeData>
+
+#include <emscripten/bind.h>
+
+class QWasmClipboard : public QObject, public QPlatformClipboard
+{
+public:
+ QWasmClipboard();
+ virtual ~QWasmClipboard();
+
+ // QPlatformClipboard methods.
+ QMimeData* mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override;
+ void setMimeData(QMimeData* data, QClipboard::Mode mode = QClipboard::Clipboard) override;
+ bool supportsMode(QClipboard::Mode mode) const override;
+ bool ownsMode(QClipboard::Mode mode) const override;
+
+ static void qWasmClipboardPaste(QMimeData *mData);
+ void initClipboardEvents();
+ bool hasClipboardApi;
+ void readTextFromClipboard();
+ void writeTextToClipboard();
+};
+
+#endif // QWASMCLIPBOARD_H
diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
index ea88ef59a0..df81413d5c 100644
--- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
+++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
@@ -31,6 +31,7 @@
#include "qwasmeventdispatcher.h"
#include "qwasmcompositor.h"
#include "qwasmintegration.h"
+#include "qwasmclipboard.h"
#include <QtGui/qevent.h>
#include <qpa/qwindowsysteminterface.h>
@@ -175,10 +176,26 @@ int QWasmEventTranslator::keyboard_cb(int eventType, const EmscriptenKeyboardEve
if (keyType == QEvent::None)
return 0;
- QString keyText = alphanumeric ? QString(keyEvent->key) : QString();
- bool accepted = QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
- 0, keyType, qtKey, translateKeyboardEventModifier(keyEvent), keyText);
+ QFlags<Qt::KeyboardModifier> mods = translateKeyboardEventModifier(keyEvent);
+ bool accepted = false;
+
+ if (keyType == QEvent::KeyPress &&
+ mods.testFlag(Qt::ControlModifier)
+ && qtKey == Qt::Key_V) {
+ QWasmIntegration::get()->getWasmClipboard()->readTextFromClipboard();
+ } else {
+ QString keyText = alphanumeric ? QString(keyEvent->key) : QString();
+ accepted = QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
+ 0, keyType, qtKey, translateKeyboardEventModifier(keyEvent), keyText);
+ }
+
+ if (keyType == QEvent::KeyPress &&
+ mods.testFlag(Qt::ControlModifier)
+ && qtKey == Qt::Key_C) {
+ QWasmIntegration::get()->getWasmClipboard()->writeTextToClipboard();
+ }
QWasmEventDispatcher::maintainTimers();
+
return accepted ? 1 : 0;
}
diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp
index 7a44c47893..6f96ec69da 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.cpp
+++ b/src/plugins/platforms/wasm/qwasmintegration.cpp
@@ -33,6 +33,7 @@
#include "qwasmcompositor.h"
#include "qwasmopenglcontext.h"
#include "qwasmtheme.h"
+#include "qwasmclipboard.h"
#include "qwasmwindow.h"
#ifndef QT_NO_OPENGL
@@ -65,17 +66,16 @@ EMSCRIPTEN_BINDINGS(my_module)
function("browserBeforeUnload", &browserBeforeUnload);
}
-static QWasmIntegration *globalHtml5Integration;
-QWasmIntegration *QWasmIntegration::get() { return globalHtml5Integration; }
+QWasmIntegration *QWasmIntegration::s_instance;
QWasmIntegration::QWasmIntegration()
: m_fontDb(nullptr),
m_compositor(new QWasmCompositor),
m_screen(new QWasmScreen(m_compositor)),
- m_eventDispatcher(nullptr)
+ m_eventDispatcher(nullptr),
+ m_clipboard(new QWasmClipboard)
{
-
- globalHtml5Integration = this;
+ s_instance = this;
updateQScreenAndCanvasRenderSize();
screenAdded(m_screen);
@@ -93,6 +93,7 @@ QWasmIntegration::~QWasmIntegration()
destroyScreen(m_screen);
delete m_fontDb;
delete m_eventTranslator;
+ s_instance = nullptr;
}
void QWasmIntegration::QWasmBrowserExit()
@@ -211,4 +212,11 @@ void QWasmIntegration::updateQScreenAndCanvasRenderSize()
QWasmIntegration::get()->m_compositor->redrawWindowContent();
}
+QPlatformClipboard* QWasmIntegration::clipboard() const
+{
+ if (!m_clipboard)
+ m_clipboard = new QWasmClipboard;
+ return m_clipboard;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h
index ebc3d9d431..4c5aeb4ebc 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.h
+++ b/src/plugins/platforms/wasm/qwasmintegration.h
@@ -49,6 +49,7 @@ class QWasmEventDispatcher;
class QWasmScreen;
class QWasmCompositor;
class QWasmBackingStore;
+class QWasmClipboard;
class QWasmIntegration : public QObject, public QPlatformIntegration
{
@@ -68,12 +69,14 @@ public:
QVariant styleHint(QPlatformIntegration::StyleHint hint) const override;
QStringList themeNames() const override;
QPlatformTheme *createPlatformTheme(const QString &name) const override;
+ QPlatformClipboard *clipboard() const override;
- static QWasmIntegration *get();
QWasmScreen *screen() { return m_screen; }
QWasmCompositor *compositor() { return m_compositor; }
QWasmEventTranslator *eventTranslator() { return m_eventTranslator; }
+ QWasmClipboard *getWasmClipboard() { return m_clipboard; }
+ static QWasmIntegration *get() { return s_instance; }
static void QWasmBrowserExit();
static void updateQScreenAndCanvasRenderSize();
@@ -85,6 +88,9 @@ private:
mutable QWasmEventDispatcher *m_eventDispatcher;
static int uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void *userData);
mutable QHash<QWindow *, QWasmBackingStore *> m_backingStores;
+
+ mutable QWasmClipboard *m_clipboard;
+ static QWasmIntegration *s_instance;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/wasm.pro b/src/plugins/platforms/wasm/wasm.pro
index eaaba53aa2..5aa6dfccf3 100644
--- a/src/plugins/platforms/wasm/wasm.pro
+++ b/src/plugins/platforms/wasm/wasm.pro
@@ -18,7 +18,8 @@ SOURCES = \
qwasmcompositor.cpp \
qwasmcursor.cpp \
qwasmopenglcontext.cpp \
- qwasmtheme.cpp
+ qwasmtheme.cpp \
+ qwasmclipboard.cpp
HEADERS = \
qwasmintegration.h \
@@ -31,7 +32,8 @@ HEADERS = \
qwasmstylepixmaps_p.h \
qwasmcursor.h \
qwasmopenglcontext.h \
- qwasmtheme.h
+ qwasmtheme.h \
+ qwasmclipboard.h
wasmfonts.files = \
../../../3rdparty/wasm/Vera.ttf \