deskflow/src/lib/platform/MSWindowsClipboard.cpp
Chris Rizzitello ed1217e9cc
Use Deskflow Name (#7519)
* Use Deskflow Name

* Remove business-oriented options from issue templates

* Remove business-oriented workflow

* Bump version to 3.0.0 (to avoid confusion with previously used version numbers 1.x & 2.x)

* Update readme to reflect new project name and goals

* Found some more "synergy" to rename

* Rename `synlib` to `app`

* Rename `syntool` to `deskflow-legacy`

* Rename `synwinhk` to `dfwhook`

* Rename dirs from synergy to deskflow

* Rename more "Synergy" files

* Rename app bundle ID

* Fixed copyright typo

* Rename only title in serial key dialog (to be moved downstream later)

* Preserve original serial key window for moving downstream

* Restore dialogs ready for moving downstream

* Rename `QDeskflowApplication` to `DeskflowApplication` (the Q is confusing)

* Restore Volker's original project name

* Fixed mimetype

* Fixed weird grammar

* Fixed (more) weird grammar

* Broken link, restoring (but we should move all links out of source)

* Broken link, restoring (but we should move all links out of source)

* Add write permission to valgrind-analysis.yml

* Restore AUR conflicts

* Apply Clang format

* Update ChangeLog

* Back out version change

---------

Co-authored-by: Nick Bolton <nick@symless.com>
2024-09-17 20:00:25 +01:00

214 lines
6.3 KiB
C++

/*
* Deskflow -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
*
* 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/>.
*/
#include "platform/MSWindowsClipboard.h"
#include "arch/win32/ArchMiscWindows.h"
#include "base/Log.h"
#include "platform/MSWindowsClipboardBitmapConverter.h"
#include "platform/MSWindowsClipboardFacade.h"
#include "platform/MSWindowsClipboardHTMLConverter.h"
#include "platform/MSWindowsClipboardTextConverter.h"
#include "platform/MSWindowsClipboardUTF16Converter.h"
//
// MSWindowsClipboard
//
UINT MSWindowsClipboard::s_ownershipFormat = 0;
MSWindowsClipboard::MSWindowsClipboard(HWND window)
: m_window(window),
m_time(0),
m_facade(new MSWindowsClipboardFacade()),
m_deleteFacade(true) {
// add converters, most desired first
m_converters.push_back(new MSWindowsClipboardUTF16Converter);
m_converters.push_back(new MSWindowsClipboardBitmapConverter);
m_converters.push_back(new MSWindowsClipboardHTMLConverter);
}
MSWindowsClipboard::~MSWindowsClipboard() {
clearConverters();
// dependency injection causes confusion over ownership, so we need
// logic to decide whether or not we delete the facade. there must
// be a more elegant way of doing this.
if (m_deleteFacade)
delete m_facade;
}
void MSWindowsClipboard::setFacade(IMSWindowsClipboardFacade &facade) {
delete m_facade;
m_facade = &facade;
m_deleteFacade = false;
}
bool MSWindowsClipboard::emptyUnowned() {
LOG((CLOG_DEBUG "empty clipboard"));
// empty the clipboard (and take ownership)
if (!EmptyClipboard()) {
// unable to cause this in integ tests, but this error has never
// actually been reported by users.
LOG((CLOG_DEBUG "failed to grab clipboard"));
return false;
}
return true;
}
bool MSWindowsClipboard::empty() {
if (!emptyUnowned()) {
return false;
}
// mark clipboard as being owned by deskflow
HGLOBAL data = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, 1);
if (NULL == SetClipboardData(getOwnershipFormat(), data)) {
LOG((CLOG_DEBUG "failed to set clipboard data"));
GlobalFree(data);
return false;
}
return true;
}
void MSWindowsClipboard::add(EFormat format, const String &data) {
bool isSucceeded = false;
// convert data to win32 form
for (ConverterList::const_iterator index = m_converters.begin();
index != m_converters.end(); ++index) {
IMSWindowsClipboardConverter *converter = *index;
// skip converters for other formats
if (converter->getFormat() == format) {
HANDLE win32Data = converter->fromIClipboard(data);
if (win32Data != NULL) {
LOG(
(CLOG_DEBUG "add %d bytes to clipboard format: %d", data.size(),
format));
m_facade->write(win32Data, converter->getWin32Format());
isSucceeded = true;
break;
} else {
LOG((CLOG_DEBUG "failed to convert clipboard data to platform format"));
}
}
}
if (!isSucceeded) {
LOG((CLOG_DEBUG "missed clipboard data convert for format: %d", format));
}
}
bool MSWindowsClipboard::open(Time time) const {
LOG((CLOG_DEBUG "open clipboard"));
if (!OpenClipboard(m_window)) {
// unable to cause this in integ tests; but this can happen!
// * http://symless.com/pm/issues/86
// * http://symless.com/pm/issues/1256
// logging improved to see if we can catch more info next time.
LOG((CLOG_WARN "failed to open clipboard: %d", GetLastError()));
return false;
}
m_time = time;
return true;
}
void MSWindowsClipboard::close() const {
LOG((CLOG_DEBUG "close clipboard"));
CloseClipboard();
}
IClipboard::Time MSWindowsClipboard::getTime() const { return m_time; }
bool MSWindowsClipboard::has(EFormat format) const {
for (ConverterList::const_iterator index = m_converters.begin();
index != m_converters.end(); ++index) {
IMSWindowsClipboardConverter *converter = *index;
if (converter->getFormat() == format) {
if (IsClipboardFormatAvailable(converter->getWin32Format())) {
return true;
}
}
}
return false;
}
String MSWindowsClipboard::get(EFormat format) const {
// find the converter for the first clipboard format we can handle
IMSWindowsClipboardConverter *converter = NULL;
for (ConverterList::const_iterator index = m_converters.begin();
index != m_converters.end(); ++index) {
converter = *index;
if (converter->getFormat() == format) {
break;
}
converter = NULL;
}
// if no converter then we don't recognize any formats
if (converter == NULL) {
LOG((CLOG_WARN "no converter for format %d", format));
return String();
}
// get a handle to the clipboard data
HANDLE win32Data = GetClipboardData(converter->getWin32Format());
if (win32Data == NULL) {
// nb: can't cause this using integ tests; this is only caused when
// the selected converter returns an invalid format -- which you
// cannot cause using public functions.
return String();
}
// convert
return converter->toIClipboard(win32Data);
}
void MSWindowsClipboard::clearConverters() {
for (ConverterList::iterator index = m_converters.begin();
index != m_converters.end(); ++index) {
delete *index;
}
m_converters.clear();
}
bool MSWindowsClipboard::isOwnedByDeskflow() {
// create ownership format if we haven't yet
if (s_ownershipFormat == 0) {
s_ownershipFormat = RegisterClipboardFormat(TEXT("DeskflowOwnership"));
}
return (IsClipboardFormatAvailable(getOwnershipFormat()) != 0);
}
UINT MSWindowsClipboard::getOwnershipFormat() {
// create ownership format if we haven't yet
if (s_ownershipFormat == 0) {
s_ownershipFormat = RegisterClipboardFormat(TEXT("DeskflowOwnership"));
}
// return the format
return s_ownershipFormat;
}