223 lines
5.8 KiB
C++
223 lines
5.8 KiB
C++
/*
|
|
* Deskflow -- mouse and keyboard sharing utility
|
|
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
|
* SPDX-FileCopyrightText: (C) 2004 Chris Schoeneman
|
|
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
|
*/
|
|
|
|
#include "platform/OSXClipboard.h"
|
|
|
|
#include "arch/ArchException.h"
|
|
#include "base/Log.h"
|
|
#include "deskflow/Clipboard.h"
|
|
#include "platform/OSXClipboardBMPConverter.h"
|
|
#include "platform/OSXClipboardHTMLConverter.h"
|
|
#include "platform/OSXClipboardTextConverter.h"
|
|
#include "platform/OSXClipboardUTF16Converter.h"
|
|
#include "platform/OSXClipboardUTF8Converter.h"
|
|
|
|
//
|
|
// OSXClipboard
|
|
//
|
|
|
|
OSXClipboard::OSXClipboard() : m_time(0), m_pboard(nullptr)
|
|
{
|
|
m_converters.push_back(new OSXClipboardHTMLConverter);
|
|
m_converters.push_back(new OSXClipboardBMPConverter);
|
|
m_converters.push_back(new OSXClipboardUTF8Converter);
|
|
m_converters.push_back(new OSXClipboardUTF16Converter);
|
|
m_converters.push_back(new OSXClipboardTextConverter);
|
|
|
|
OSStatus createErr = PasteboardCreate(kPasteboardClipboard, &m_pboard);
|
|
if (createErr != noErr) {
|
|
LOG_WARN("failed to create clipboard reference: error %i", createErr);
|
|
LOG_ERR("unable to connect to pasteboard, clipboard sharing disabled", createErr);
|
|
m_pboard = nullptr;
|
|
return;
|
|
}
|
|
|
|
OSStatus syncErr = PasteboardSynchronize(m_pboard);
|
|
if (syncErr != noErr) {
|
|
LOG_WARN("failed to syncronize clipboard: error %i", syncErr);
|
|
}
|
|
}
|
|
|
|
OSXClipboard::~OSXClipboard()
|
|
{
|
|
clearConverters();
|
|
}
|
|
|
|
bool OSXClipboard::empty()
|
|
{
|
|
LOG_DEBUG("emptying clipboard");
|
|
if (m_pboard == nullptr)
|
|
return false;
|
|
|
|
OSStatus err = PasteboardClear(m_pboard);
|
|
if (err != noErr) {
|
|
LOG_WARN("failed to clear clipboard: error %i", err);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OSXClipboard::synchronize()
|
|
{
|
|
if (m_pboard == nullptr)
|
|
return false;
|
|
|
|
PasteboardSyncFlags flags = PasteboardSynchronize(m_pboard);
|
|
LOG_DEBUG2("flags: %x", flags);
|
|
|
|
if (flags & kPasteboardModified) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void OSXClipboard::add(Format format, const std::string &data)
|
|
{
|
|
if (m_pboard == nullptr)
|
|
return;
|
|
|
|
LOG_DEBUG("add %d bytes to clipboard format: %d", data.size(), format);
|
|
if (format == IClipboard::Format::Text) {
|
|
LOG_DEBUG("format of data to be added to clipboard was kText");
|
|
} else if (format == IClipboard::Format::Bitmap) {
|
|
LOG_DEBUG("format of data to be added to clipboard was kBitmap");
|
|
} else if (format == IClipboard::Format::HTML) {
|
|
LOG_DEBUG("format of data to be added to clipboard was kHTML");
|
|
}
|
|
|
|
for (ConverterList::const_iterator index = m_converters.begin(); index != m_converters.end(); ++index) {
|
|
|
|
IOSXClipboardConverter *converter = *index;
|
|
|
|
// skip converters for other formats
|
|
if (converter->getFormat() == format) {
|
|
std::string osXData = converter->fromIClipboard(data);
|
|
CFStringRef flavorType = converter->getOSXFormat();
|
|
CFDataRef dataRef = CFDataCreate(kCFAllocatorDefault, (uint8_t *)osXData.data(), osXData.size());
|
|
PasteboardItemID itemID = 0;
|
|
|
|
if (dataRef) {
|
|
PasteboardPutItemFlavor(m_pboard, itemID, flavorType, dataRef, kPasteboardFlavorNoFlags);
|
|
|
|
CFRelease(dataRef);
|
|
LOG_DEBUG("added %d bytes to clipboard format: %d", data.size(), format);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool OSXClipboard::open(Time time) const
|
|
{
|
|
if (m_pboard == nullptr)
|
|
return false;
|
|
|
|
LOG_DEBUG("opening clipboard");
|
|
m_time = time;
|
|
return true;
|
|
}
|
|
|
|
void OSXClipboard::close() const
|
|
{
|
|
LOG_DEBUG("closing clipboard");
|
|
/* not needed */
|
|
}
|
|
|
|
IClipboard::Time OSXClipboard::getTime() const
|
|
{
|
|
return m_time;
|
|
}
|
|
|
|
bool OSXClipboard::has(Format format) const
|
|
{
|
|
if (m_pboard == nullptr)
|
|
return false;
|
|
|
|
PasteboardItemID item;
|
|
PasteboardGetItemIdentifier(m_pboard, (CFIndex)1, &item);
|
|
|
|
for (ConverterList::const_iterator index = m_converters.begin(); index != m_converters.end(); ++index) {
|
|
IOSXClipboardConverter *converter = *index;
|
|
if (converter->getFormat() == format) {
|
|
PasteboardFlavorFlags flags;
|
|
CFStringRef type = converter->getOSXFormat();
|
|
|
|
OSStatus res;
|
|
|
|
if ((res = PasteboardGetItemFlavorFlags(m_pboard, item, type, &flags)) == noErr) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
std::string OSXClipboard::get(Format format) const
|
|
{
|
|
CFStringRef type;
|
|
PasteboardItemID item;
|
|
std::string result;
|
|
|
|
if (m_pboard == nullptr)
|
|
return result;
|
|
|
|
PasteboardGetItemIdentifier(m_pboard, (CFIndex)1, &item);
|
|
|
|
// find the converter for the first clipboard format we can handle
|
|
IOSXClipboardConverter *converter = nullptr;
|
|
for (ConverterList::const_iterator index = m_converters.begin(); index != m_converters.end(); ++index) {
|
|
converter = *index;
|
|
|
|
PasteboardFlavorFlags flags;
|
|
type = converter->getOSXFormat();
|
|
|
|
if (converter->getFormat() == format && PasteboardGetItemFlavorFlags(m_pboard, item, type, &flags) == noErr) {
|
|
break;
|
|
}
|
|
converter = nullptr;
|
|
}
|
|
|
|
// if no converter then we don't recognize any formats
|
|
if (converter == nullptr) {
|
|
LOG_DEBUG("unable to find converter for data");
|
|
return result;
|
|
}
|
|
|
|
// get the clipboard data.
|
|
CFDataRef buffer = nullptr;
|
|
try {
|
|
OSStatus err = PasteboardCopyItemFlavorData(m_pboard, item, type, &buffer);
|
|
|
|
if (err != noErr) {
|
|
throw err;
|
|
}
|
|
|
|
result = std::string((char *)CFDataGetBytePtr(buffer), CFDataGetLength(buffer));
|
|
} catch (OSStatus err) {
|
|
LOG_DEBUG("exception thrown in OSXClipboard::get MacError (%d)", err);
|
|
} catch (...) {
|
|
LOG_DEBUG("unknown exception in OSXClipboard::get");
|
|
RETHROW_THREADEXCEPTION
|
|
}
|
|
|
|
if (buffer != nullptr)
|
|
CFRelease(buffer);
|
|
|
|
return converter->toIClipboard(result);
|
|
}
|
|
|
|
void OSXClipboard::clearConverters()
|
|
{
|
|
if (m_pboard == nullptr)
|
|
return;
|
|
|
|
for (ConverterList::iterator index = m_converters.begin(); index != m_converters.end(); ++index) {
|
|
delete *index;
|
|
}
|
|
m_converters.clear();
|
|
}
|