blob: 1196367536dda9120e8712f036247799e5db9599 [file] [log] [blame]
Constantin Kaplinsky729598c2006-05-25 05:12:25 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Pierre Ossman546b2ad2019-05-02 12:32:03 +02002 * Copyright 2012-2019 Pierre Ossman for Cendio AB
Constantin Kaplinsky729598c2006-05-25 05:12:25 +00003 *
4 * This is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This software is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this software; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 * USA.
18 */
19
20// -=- Clipboard.cxx
21
22#include <rfb_win32/Clipboard.h>
23#include <rfb_win32/WMShatter.h>
24#include <rfb/util.h>
25
26#include <rfb/LogWriter.h>
27
28using namespace rfb;
29using namespace rfb::win32;
30
31static LogWriter vlog("Clipboard");
32
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000033//
34// -=- Clipboard object
35//
36
37Clipboard::Clipboard()
38 : MsgWindow(_T("Clipboard")), notifier(0), next_window(0) {
39 next_window = SetClipboardViewer(getHandle());
40 vlog.debug("registered clipboard handler");
41}
42
43Clipboard::~Clipboard() {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +010044 vlog.debug("removing %p from chain (next is %p)", getHandle(), next_window);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000045 ChangeClipboardChain(getHandle(), next_window);
46}
47
48LRESULT
49Clipboard::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
50 switch (msg) {
51
52 case WM_CHANGECBCHAIN:
Pierre Ossman40e3ceb2015-03-03 16:46:19 +010053 vlog.debug("change clipboard chain (%I64x, %I64x)",
54 (long long)wParam, (long long)lParam);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000055 if ((HWND) wParam == next_window)
56 next_window = (HWND) lParam;
57 else if (next_window != 0)
58 SendMessage(next_window, msg, wParam, lParam);
59 else
60 vlog.error("bad clipboard chain change!");
61 break;
62
63 case WM_DRAWCLIPBOARD:
64 {
65 HWND owner = GetClipboardOwner();
66 if (owner == getHandle()) {
67 vlog.debug("local clipboard changed by me");
68 } else {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +010069 vlog.debug("local clipboard changed by %p", owner);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000070
Pierre Ossman615d16b2019-05-03 10:53:06 +020071 if (notifier == NULL)
72 vlog.debug("no clipboard notifier registered");
73 else
Pierre Ossman5fbbe102019-05-10 11:44:19 +020074 notifier->notifyClipboardChanged(IsClipboardFormatAvailable(CF_UNICODETEXT));
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000075 }
76 }
77 if (next_window)
78 SendMessage(next_window, msg, wParam, lParam);
79 return 0;
80
81 };
82 return MsgWindow::processMessage(msg, wParam, lParam);
83};
84
Pierre Ossman615d16b2019-05-03 10:53:06 +020085char*
86Clipboard::getClipText() {
87 HGLOBAL cliphandle;
Pierre Ossman5fbbe102019-05-10 11:44:19 +020088 wchar_t* clipdata;
89 CharArray utf8;
Pierre Ossman615d16b2019-05-03 10:53:06 +020090
91 // Open the clipboard
92 if (!OpenClipboard(getHandle()))
93 return NULL;
94
95 // Get the clipboard data
Pierre Ossman5fbbe102019-05-10 11:44:19 +020096 cliphandle = GetClipboardData(CF_UNICODETEXT);
Pierre Ossman615d16b2019-05-03 10:53:06 +020097 if (!cliphandle) {
98 CloseClipboard();
99 return NULL;
100 }
101
Pierre Ossman5fbbe102019-05-10 11:44:19 +0200102 clipdata = (wchar_t*) GlobalLock(cliphandle);
Pierre Ossman615d16b2019-05-03 10:53:06 +0200103 if (!clipdata) {
104 CloseClipboard();
105 return NULL;
106 }
107
Pierre Ossman5fbbe102019-05-10 11:44:19 +0200108 // Convert it to UTF-8
109 utf8.replaceBuf(utf16ToUTF8(clipdata));
Pierre Ossman615d16b2019-05-03 10:53:06 +0200110
111 // Release the buffer and close the clipboard
112 GlobalUnlock(cliphandle);
113 CloseClipboard();
114
Pierre Ossman5fbbe102019-05-10 11:44:19 +0200115 return convertLF(utf8.buf);
Pierre Ossman615d16b2019-05-03 10:53:06 +0200116}
117
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000118void
119Clipboard::setClipText(const char* text) {
120 HANDLE clip_handle = 0;
121
122 try {
123
124 // - Firstly, we must open the clipboard
125 if (!OpenClipboard(getHandle()))
126 throw rdr::SystemException("unable to open Win32 clipboard", GetLastError());
127
Pierre Ossman5fbbe102019-05-10 11:44:19 +0200128 // - Convert the supplied clipboard text into UTF-16 format with CRLF
129 CharArray filtered(convertCRLF(text));
130 wchar_t* utf16;
131
132 utf16 = utf8ToUTF16(filtered.buf);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000133
134 // - Allocate global memory for the data
Pierre Ossman5fbbe102019-05-10 11:44:19 +0200135 clip_handle = ::GlobalAlloc(GMEM_MOVEABLE, (wcslen(utf16) + 1) * 2);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000136
Pierre Ossman5fbbe102019-05-10 11:44:19 +0200137 wchar_t* data = (wchar_t*) GlobalLock(clip_handle);
138 wcscpy(data, utf16);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000139 GlobalUnlock(clip_handle);
140
Pierre Ossman5fbbe102019-05-10 11:44:19 +0200141 strFree(utf16);
142
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000143 // - Next, we must clear out any existing data
144 if (!EmptyClipboard())
145 throw rdr::SystemException("unable to empty Win32 clipboard", GetLastError());
146
147 // - Set the new clipboard data
Pierre Ossman5fbbe102019-05-10 11:44:19 +0200148 if (!SetClipboardData(CF_UNICODETEXT, clip_handle))
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000149 throw rdr::SystemException("unable to set Win32 clipboard", GetLastError());
150 clip_handle = 0;
151
152 vlog.debug("set clipboard");
153 } catch (rdr::Exception& e) {
Pierre Ossmanad8609a2012-04-26 09:04:14 +0000154 vlog.debug("%s", e.str());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000155 }
156
157 // - Close the clipboard
158 if (!CloseClipboard())
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100159 vlog.debug("unable to close Win32 clipboard: %lu", GetLastError());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000160 else
161 vlog.debug("closed clipboard");
162 if (clip_handle) {
163 vlog.debug("freeing clipboard handle");
164 GlobalFree(clip_handle);
165 }
166}