2012-06-10 16:50:54 +00:00
|
|
|
/*
|
2024-09-17 19:00:25 +00:00
|
|
|
* Deskflow -- mouse and keyboard sharing utility
|
2016-09-07 14:24:00 +00:00
|
|
|
* Copyright (C) 2012-2016 Symless Ltd.
|
2012-09-04 02:09:56 +00:00
|
|
|
* Copyright (C) 2004 Chris Schoeneman
|
2024-07-02 19:07:06 +00:00
|
|
|
*
|
2012-06-10 16:50:54 +00:00
|
|
|
* This package is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
2015-05-03 02:33:52 +00:00
|
|
|
* found in the file LICENSE that should have accompanied this file.
|
2024-07-02 19:07:06 +00:00
|
|
|
*
|
2012-06-10 16:50:54 +00:00
|
|
|
* This package 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 <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2014-02-28 12:36:45 +00:00
|
|
|
#include "platform/OSXClipboard.h"
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
#include "arch/XArch.h"
|
|
|
|
|
#include "base/Log.h"
|
2024-09-17 19:00:25 +00:00
|
|
|
#include "deskflow/Clipboard.h"
|
2014-05-13 12:31:05 +00:00
|
|
|
#include "platform/OSXClipboardBMPConverter.h"
|
|
|
|
|
#include "platform/OSXClipboardHTMLConverter.h"
|
2024-07-02 19:07:06 +00:00
|
|
|
#include "platform/OSXClipboardTextConverter.h"
|
|
|
|
|
#include "platform/OSXClipboardUTF16Converter.h"
|
|
|
|
|
#include "platform/OSXClipboardUTF8Converter.h"
|
2012-06-10 16:50:54 +00:00
|
|
|
|
|
|
|
|
//
|
2014-11-11 13:51:47 +00:00
|
|
|
// OSXClipboard
|
2012-06-10 16:50:54 +00:00
|
|
|
//
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
OSXClipboard::OSXClipboard() : m_time(0), m_pboard(NULL)
|
|
|
|
|
{
|
2024-07-02 19:07:06 +00:00
|
|
|
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) {
|
2024-10-17 18:04:35 +00:00
|
|
|
LOG((CLOG_DEBUG "failed to create clipboard reference: error %i", createErr));
|
|
|
|
|
LOG((CLOG_ERR "unable to connect to pasteboard, clipboard sharing disabled", createErr));
|
2024-07-02 19:07:06 +00:00
|
|
|
m_pboard = NULL;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OSStatus syncErr = PasteboardSynchronize(m_pboard);
|
|
|
|
|
if (syncErr != noErr) {
|
|
|
|
|
LOG((CLOG_DEBUG "failed to syncronize clipboard: error %i", syncErr));
|
|
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
OSXClipboard::~OSXClipboard()
|
|
|
|
|
{
|
|
|
|
|
clearConverters();
|
|
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
bool OSXClipboard::empty()
|
|
|
|
|
{
|
2024-07-02 19:07:06 +00:00
|
|
|
LOG((CLOG_DEBUG "emptying clipboard"));
|
|
|
|
|
if (m_pboard == NULL)
|
|
|
|
|
return false;
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
OSStatus err = PasteboardClear(m_pboard);
|
|
|
|
|
if (err != noErr) {
|
|
|
|
|
LOG((CLOG_DEBUG "failed to clear clipboard: error %i", err));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
return true;
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
bool OSXClipboard::synchronize()
|
|
|
|
|
{
|
2024-07-02 19:07:06 +00:00
|
|
|
if (m_pboard == NULL)
|
2016-12-28 11:50:32 +00:00
|
|
|
return false;
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
PasteboardSyncFlags flags = PasteboardSynchronize(m_pboard);
|
|
|
|
|
LOG((CLOG_DEBUG2 "flags: %x", flags));
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
if (flags & kPasteboardModified) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2025-01-06 00:55:07 +00:00
|
|
|
void OSXClipboard::add(EFormat format, const std::string &data)
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2024-07-02 19:07:06 +00:00
|
|
|
if (m_pboard == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
LOG((CLOG_DEBUG "add %d bytes to clipboard format: %d", data.size(), format));
|
|
|
|
|
if (format == IClipboard::kText) {
|
|
|
|
|
LOG((CLOG_DEBUG "format of data to be added to clipboard was kText"));
|
|
|
|
|
} else if (format == IClipboard::kBitmap) {
|
|
|
|
|
LOG((CLOG_DEBUG "format of data to be added to clipboard was kBitmap"));
|
|
|
|
|
} else if (format == IClipboard::kHTML) {
|
|
|
|
|
LOG((CLOG_DEBUG "format of data to be added to clipboard was kHTML"));
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
for (ConverterList::const_iterator index = m_converters.begin(); index != m_converters.end(); ++index) {
|
2024-07-02 19:07:06 +00:00
|
|
|
|
|
|
|
|
IOSXClipboardConverter *converter = *index;
|
|
|
|
|
|
|
|
|
|
// skip converters for other formats
|
|
|
|
|
if (converter->getFormat() == format) {
|
2025-01-06 00:55:07 +00:00
|
|
|
std::string osXData = converter->fromIClipboard(data);
|
2024-07-02 19:07:06 +00:00
|
|
|
CFStringRef flavorType = converter->getOSXFormat();
|
2025-01-11 00:09:43 +00:00
|
|
|
CFDataRef dataRef = CFDataCreate(kCFAllocatorDefault, (uint8_t *)osXData.data(), osXData.size());
|
2024-07-02 19:07:06 +00:00
|
|
|
PasteboardItemID itemID = 0;
|
|
|
|
|
|
|
|
|
|
if (dataRef) {
|
2024-10-17 18:04:35 +00:00
|
|
|
PasteboardPutItemFlavor(m_pboard, itemID, flavorType, dataRef, kPasteboardFlavorNoFlags);
|
2024-07-02 19:07:06 +00:00
|
|
|
|
|
|
|
|
CFRelease(dataRef);
|
2024-10-17 18:04:35 +00:00
|
|
|
LOG((CLOG_DEBUG "added %d bytes to clipboard format: %d", data.size(), format));
|
2024-07-02 19:07:06 +00:00
|
|
|
}
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
2024-07-02 19:07:06 +00:00
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
bool OSXClipboard::open(Time time) const
|
|
|
|
|
{
|
2024-07-02 19:07:06 +00:00
|
|
|
if (m_pboard == NULL)
|
|
|
|
|
return false;
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
LOG((CLOG_DEBUG "opening clipboard"));
|
|
|
|
|
m_time = time;
|
|
|
|
|
return true;
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void OSXClipboard::close() const
|
|
|
|
|
{
|
2024-07-02 19:07:06 +00:00
|
|
|
LOG((CLOG_DEBUG "closing clipboard"));
|
|
|
|
|
/* not needed */
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
IClipboard::Time OSXClipboard::getTime() const
|
|
|
|
|
{
|
|
|
|
|
return m_time;
|
|
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
bool OSXClipboard::has(EFormat format) const
|
|
|
|
|
{
|
2024-07-02 19:07:06 +00:00
|
|
|
if (m_pboard == NULL)
|
|
|
|
|
return false;
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
PasteboardItemID item;
|
|
|
|
|
PasteboardGetItemIdentifier(m_pboard, (CFIndex)1, &item);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
for (ConverterList::const_iterator index = m_converters.begin(); index != m_converters.end(); ++index) {
|
2024-07-02 19:07:06 +00:00
|
|
|
IOSXClipboardConverter *converter = *index;
|
|
|
|
|
if (converter->getFormat() == format) {
|
|
|
|
|
PasteboardFlavorFlags flags;
|
|
|
|
|
CFStringRef type = converter->getOSXFormat();
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
OSStatus res;
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
if ((res = PasteboardGetItemFlavorFlags(m_pboard, item, type, &flags)) == noErr) {
|
2024-07-02 19:07:06 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
2024-07-02 19:07:06 +00:00
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
return false;
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-06 00:55:07 +00:00
|
|
|
std::string OSXClipboard::get(EFormat format) const
|
2024-10-17 18:04:35 +00:00
|
|
|
{
|
2024-07-02 19:07:06 +00:00
|
|
|
CFStringRef type;
|
|
|
|
|
PasteboardItemID item;
|
2025-01-06 00:55:07 +00:00
|
|
|
std::string result;
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
if (m_pboard == NULL)
|
|
|
|
|
return result;
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
PasteboardGetItemIdentifier(m_pboard, (CFIndex)1, &item);
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// find the converter for the first clipboard format we can handle
|
|
|
|
|
IOSXClipboardConverter *converter = NULL;
|
2024-10-17 18:04:35 +00:00
|
|
|
for (ConverterList::const_iterator index = m_converters.begin(); index != m_converters.end(); ++index) {
|
2024-07-02 19:07:06 +00:00
|
|
|
converter = *index;
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
PasteboardFlavorFlags flags;
|
|
|
|
|
type = converter->getOSXFormat();
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
if (converter->getFormat() == format && PasteboardGetItemFlavorFlags(m_pboard, item, type, &flags) == noErr) {
|
2024-07-02 19:07:06 +00:00
|
|
|
break;
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
2024-07-02 19:07:06 +00:00
|
|
|
converter = NULL;
|
|
|
|
|
}
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// if no converter then we don't recognize any formats
|
|
|
|
|
if (converter == NULL) {
|
|
|
|
|
LOG((CLOG_DEBUG "unable to find converter for data"));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// get the clipboard data.
|
|
|
|
|
CFDataRef buffer = NULL;
|
|
|
|
|
try {
|
|
|
|
|
OSStatus err = PasteboardCopyItemFlavorData(m_pboard, item, type, &buffer);
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
if (err != noErr) {
|
|
|
|
|
throw err;
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-06 00:55:07 +00:00
|
|
|
result = std::string((char *)CFDataGetBytePtr(buffer), CFDataGetLength(buffer));
|
2024-07-02 19:07:06 +00:00
|
|
|
} catch (OSStatus err) {
|
2024-10-17 18:04:35 +00:00
|
|
|
LOG((CLOG_DEBUG "exception thrown in OSXClipboard::get MacError (%d)", err));
|
2024-07-02 19:07:06 +00:00
|
|
|
} catch (...) {
|
|
|
|
|
LOG((CLOG_DEBUG "unknown exception in OSXClipboard::get"));
|
|
|
|
|
RETHROW_XTHREAD
|
|
|
|
|
}
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
if (buffer != NULL)
|
|
|
|
|
CFRelease(buffer);
|
|
|
|
|
|
|
|
|
|
return converter->toIClipboard(result);
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
void OSXClipboard::clearConverters()
|
|
|
|
|
{
|
2024-07-02 19:07:06 +00:00
|
|
|
if (m_pboard == NULL)
|
|
|
|
|
return;
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
for (ConverterList::iterator index = m_converters.begin(); index != m_converters.end(); ++index) {
|
2024-07-02 19:07:06 +00:00
|
|
|
delete *index;
|
|
|
|
|
}
|
|
|
|
|
m_converters.clear();
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|