/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or 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.GPL2 and 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-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qwinrtclipboard.h" #include #include #include #include #include using namespace ABI::Windows::ApplicationModel::DataTransfer; using namespace ABI::Windows::Foundation; using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; typedef IEventHandler ContentChangedHandler; #define RETURN_NULLPTR_IF_FAILED(msg) RETURN_IF_FAILED(msg, return nullptr) QT_BEGIN_NAMESPACE QWinRTClipboard::QWinRTClipboard() : m_mimeData(nullptr) { QEventDispatcherWinRT::runOnXamlThread([this]() { HRESULT hr; hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_Clipboard).Get(), &m_nativeClipBoard); Q_ASSERT_SUCCEEDED(hr); EventRegistrationToken tok; hr = m_nativeClipBoard->add_ContentChanged(Callback(this, &QWinRTClipboard::onContentChanged).Get(), &tok); Q_ASSERT_SUCCEEDED(hr); return hr; }); } QMimeData *QWinRTClipboard::mimeData(QClipboard::Mode mode) { if (!supportsMode(mode)) return nullptr; ComPtr view; HRESULT hr; hr = m_nativeClipBoard->GetContent(&view); RETURN_NULLPTR_IF_FAILED("Could not get clipboard content."); ComPtr> op; HString result; // This throws a security exception (WinRT originate error / 0x40080201. // Unfortunately there seems to be no way to avoid this, neither // running on the XAML thread, nor some other way. Stack Overflow // confirms this problem since Windows (Phone) 8.0. hr = view->GetTextAsync(&op); RETURN_NULLPTR_IF_FAILED("Could not get clipboard text."); hr = QWinRTFunctions::await(op, result.GetAddressOf()); RETURN_NULLPTR_IF_FAILED("Could not get clipboard text content"); quint32 size; const wchar_t *textStr = result.GetRawBuffer(&size); QString text = QString::fromWCharArray(textStr, int(size)); text.replace(QLatin1String("\r\n"), QLatin1String("\n")); if (m_mimeData) { if (m_mimeData->text() == text) return m_mimeData; delete m_mimeData; } m_mimeData = new QMimeData(); m_mimeData->setText(text); return m_mimeData; } // Inspired by QWindowsMimeText::convertFromMime inline QString convertToWindowsLineEnding(const QString &text) { const QChar *u = text.unicode(); QString res; const int s = text.length(); int maxsize = s + s / 40 + 3; res.resize(maxsize); int ri = 0; bool cr = false; for (int i = 0; i < s; ++i) { if (*u == QLatin1Char('\r')) cr = true; else { if (*u == QLatin1Char('\n') && !cr) res[ri++] = QLatin1Char('\r'); cr = false; } res[ri++] = *u; if (ri+3 >= maxsize) { maxsize += maxsize / 4; res.resize(maxsize); } ++u; } res.truncate(ri); return res; } void QWinRTClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) { if (!supportsMode(mode)) return; const bool newData = !m_mimeData || m_mimeData != data; if (newData) { if (m_mimeData) delete m_mimeData; m_mimeData = data; } const QString text = data ? data->text() : QString(); HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, text]() { HRESULT hr; ComPtr package; hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_DataPackage).Get(), &package); const QString nativeString = convertToWindowsLineEnding(text); HStringReference textRef(reinterpret_cast(nativeString.utf16()), uint(nativeString.length())); hr = package->SetText(textRef.Get()); RETURN_HR_IF_FAILED("Could not set text to clipboard data package."); hr = m_nativeClipBoard->SetContent(package.Get()); RETURN_HR_IF_FAILED("Could not set clipboard content."); return S_OK; }); RETURN_VOID_IF_FAILED("Could not set clipboard text."); } bool QWinRTClipboard::supportsMode(QClipboard::Mode mode) const { return mode == QClipboard::Clipboard; } HRESULT QWinRTClipboard::onContentChanged(IInspectable *, IInspectable *) { emitChanged(QClipboard::Clipboard); return S_OK; } QT_END_NAMESPACE