2018-02-21 18:35:25 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
|
|
|
** 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"
|
2020-01-17 09:32:27 +00:00
|
|
|
#include "qwasmstring.h"
|
2018-02-21 18:35:25 +00:00
|
|
|
|
|
|
|
#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...
|
2020-01-17 09:32:27 +00:00
|
|
|
static QString g_clipboardText;
|
|
|
|
static QString g_clipboardFormat;
|
2018-02-21 18:35:25 +00:00
|
|
|
|
|
|
|
static val getClipboardData()
|
|
|
|
{
|
2020-01-17 09:32:27 +00:00
|
|
|
return QWasmString::fromQString(g_clipboardText);
|
2018-02-21 18:35:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static val getClipboardFormat()
|
|
|
|
{
|
2020-01-17 09:32:27 +00:00
|
|
|
return QWasmString::fromQString(g_clipboardFormat);
|
2018-02-21 18:35:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void pasteClipboardData(emscripten::val format, emscripten::val dataPtr)
|
|
|
|
{
|
2020-01-17 09:32:27 +00:00
|
|
|
QString formatString = QWasmString::toQString(format);
|
2018-02-21 18:35:25 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-02-23 08:40:30 +00:00
|
|
|
static void qClipboardCutTo(val event)
|
2018-02-21 18:35:25 +00:00
|
|
|
{
|
2019-02-23 08:40:30 +00:00
|
|
|
if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) {
|
|
|
|
// Send synthetic Ctrl+X to make the app cut data to Qt's clipboard
|
|
|
|
QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
|
|
|
|
0, QEvent::KeyPress, Qt::Key_X, Qt::ControlModifier, "X");
|
|
|
|
}
|
2018-02-21 18:35:25 +00:00
|
|
|
|
|
|
|
val module = val::global("Module");
|
2019-03-15 14:04:59 +00:00
|
|
|
val clipdata = module.call<val>("qtGetClipboardData");
|
|
|
|
val clipFormat = module.call<val>("qtGetClipboardFormat");
|
2019-02-23 08:40:30 +00:00
|
|
|
event["clipboardData"].call<void>("setData", clipFormat, clipdata);
|
|
|
|
event.call<void>("preventDefault");
|
2018-02-21 18:35:25 +00:00
|
|
|
}
|
|
|
|
|
2019-02-23 08:40:30 +00:00
|
|
|
static void qClipboardCopyTo(val event)
|
2018-02-21 18:35:25 +00:00
|
|
|
{
|
2019-02-23 08:40:30 +00:00
|
|
|
if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) {
|
|
|
|
// Send synthetic Ctrl+C to make the app copy data to Qt's clipboard
|
|
|
|
QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
|
|
|
|
0, QEvent::KeyPress, Qt::Key_C, Qt::ControlModifier, "C");
|
|
|
|
}
|
|
|
|
|
2018-02-21 18:35:25 +00:00
|
|
|
val module = val::global("Module");
|
2019-03-15 14:04:59 +00:00
|
|
|
val clipdata = module.call<val>("qtGetClipboardData");
|
|
|
|
val clipFormat = module.call<val>("qtGetClipboardFormat");
|
2019-02-23 08:40:30 +00:00
|
|
|
event["clipboardData"].call<void>("setData", clipFormat, clipdata);
|
|
|
|
event.call<void>("preventDefault");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void qClipboardPasteTo(val event)
|
|
|
|
{
|
|
|
|
bool hasClipboardApi = QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi;
|
|
|
|
val clipdata = hasClipboardApi ?
|
2019-03-15 14:04:59 +00:00
|
|
|
val::global("Module").call<val>("qtGetClipboardData") :
|
2020-01-17 09:32:27 +00:00
|
|
|
event["clipboardData"].call<val>("getData", val("text"));
|
2018-02-21 18:35:25 +00:00
|
|
|
|
2020-01-17 09:32:27 +00:00
|
|
|
const QString qstr = QWasmString::toQString(clipdata);
|
|
|
|
if (qstr.length() > 0) {
|
2018-02-21 18:35:25 +00:00
|
|
|
QMimeData *mMimeData = new QMimeData;
|
|
|
|
mMimeData->setText(qstr);
|
|
|
|
QWasmClipboard::qWasmClipboardPaste(mMimeData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-15 14:04:59 +00:00
|
|
|
EMSCRIPTEN_BINDINGS(qtClipboardModule) {
|
|
|
|
function("qtGetClipboardData", &getClipboardData);
|
|
|
|
function("qtGetClipboardFormat", &getClipboardFormat);
|
|
|
|
function("qtPasteClipboardData", &pasteClipboardData);
|
|
|
|
function("qtClipboardPromiseResolve", &qClipboardPromiseResolve);
|
|
|
|
function("qtClipboardCutTo", &qClipboardCutTo);
|
|
|
|
function("qtClipboardCopyTo", &qClipboardCopyTo);
|
|
|
|
function("qtClipboardPasteTo", &qClipboardPasteTo);
|
2018-02-21 18:35:25 +00:00
|
|
|
}
|
|
|
|
|
2019-02-15 21:04:09 +00:00
|
|
|
QWasmClipboard::QWasmClipboard()
|
2018-02-21 18:35:25 +00:00
|
|
|
{
|
2019-02-15 21:04:09 +00:00
|
|
|
val clipboard = val::global("navigator")["clipboard"];
|
|
|
|
hasClipboardApi = (!clipboard.isUndefined() && !clipboard["readText"].isUndefined());
|
|
|
|
|
2018-02-21 18:35:25 +00:00
|
|
|
initClipboardEvents();
|
|
|
|
}
|
|
|
|
|
|
|
|
QWasmClipboard::~QWasmClipboard()
|
|
|
|
{
|
2020-01-17 09:32:27 +00:00
|
|
|
g_clipboardText.clear();
|
2018-02-21 18:35:25 +00:00
|
|
|
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()) {
|
2020-01-17 09:32:27 +00:00
|
|
|
g_clipboardFormat = mimeData->formats().at(0);
|
|
|
|
g_clipboardText = mimeData->text();
|
2018-02-21 18:35:25 +00:00
|
|
|
} else if (mimeData->hasHtml()) {
|
2020-01-17 09:32:27 +00:00
|
|
|
g_clipboardFormat = mimeData->formats().at(0);
|
|
|
|
g_clipboardText = mimeData->html();
|
2018-02-21 18:35:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
|
|
|
{
|
2019-02-15 21:04:09 +00:00
|
|
|
if (!hasClipboardApi)
|
|
|
|
return;
|
2018-02-21 18:35:25 +00:00
|
|
|
|
2019-02-15 21:04:09 +00:00
|
|
|
val permissions = val::global("navigator")["permissions"];
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
void QWasmClipboard::installEventHandlers(const QString &canvasId)
|
|
|
|
{
|
|
|
|
if (hasClipboardApi)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Fallback path for browsers which do not support direct clipboard access
|
2019-12-30 11:40:03 +00:00
|
|
|
val document = val::global("document");
|
2020-01-17 09:32:27 +00:00
|
|
|
val canvas = document.call<val>("getElementById", QWasmString::fromQString(canvasId));
|
2019-12-30 11:40:03 +00:00
|
|
|
|
2020-01-17 09:32:27 +00:00
|
|
|
canvas.call<void>("addEventListener", val("cut"),
|
2019-03-15 14:04:59 +00:00
|
|
|
val::module_property("qtClipboardCutTo"));
|
2020-01-17 09:32:27 +00:00
|
|
|
canvas.call<void>("addEventListener", val("copy"),
|
2019-03-15 14:04:59 +00:00
|
|
|
val::module_property("qtClipboardCopyTo"));
|
2020-01-17 09:32:27 +00:00
|
|
|
canvas.call<void>("addEventListener", val("paste"),
|
2019-03-15 14:04:59 +00:00
|
|
|
val::module_property("qtClipboardPasteTo"));
|
2018-02-21 18:35:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QWasmClipboard::readTextFromClipboard()
|
|
|
|
{
|
|
|
|
if (QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) {
|
|
|
|
val navigator = val::global("navigator");
|
|
|
|
val textPromise = navigator["clipboard"].call<val>("readText");
|
2019-03-15 14:04:59 +00:00
|
|
|
val readTextResolve = val::global("Module")["qtClipboardPromiseResolve"];
|
2018-02-21 18:35:25 +00:00
|
|
|
textPromise.call<val>("then", readTextResolve);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QWasmClipboard::writeTextToClipboard()
|
|
|
|
{
|
|
|
|
if (QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) {
|
|
|
|
val module = val::global("Module");
|
2019-03-15 14:04:59 +00:00
|
|
|
val txt = module.call<val>("qtGetClipboardData");
|
|
|
|
val format = module.call<val>("qtGetClipboardFormat");
|
2018-02-21 18:35:25 +00:00
|
|
|
val navigator = val::global("navigator");
|
2020-01-17 09:32:27 +00:00
|
|
|
navigator["clipboard"].call<void>("writeText", txt);
|
2018-02-21 18:35:25 +00:00
|
|
|
}
|
|
|
|
}
|