blob: 306cfbadcb1241cca3ba5c17c573aabf97d726e6 [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
33
34//
35// -=- CR/LF handlers
36//
37
38char*
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000039unix2dos(const char* text) {
40 int len = strlen(text)+1;
41 char* dos = new char[strlen(text)*2+1];
42 int i, j=0;
43 for (i=0; i<len; i++) {
44 if (text[i] == '\x0a')
45 dos[j++] = '\x0d';
46 dos[j++] = text[i];
47 }
48 return dos;
49}
50
51
52//
53// -=- ISO-8859-1 (Latin 1) filter (in-place)
54//
55
56void
57removeNonISOLatin1Chars(char* text) {
58 int len = strlen(text);
59 int i=0, j=0;
60 for (; i<len; i++) {
61 if (((text[i] >= 1) && (text[i] <= 127)) ||
62 ((text[i] >= 160) && (text[i] <= 255)))
63 text[j++] = text[i];
64 }
65 text[j] = 0;
66}
67
68//
69// -=- Clipboard object
70//
71
72Clipboard::Clipboard()
73 : MsgWindow(_T("Clipboard")), notifier(0), next_window(0) {
74 next_window = SetClipboardViewer(getHandle());
75 vlog.debug("registered clipboard handler");
76}
77
78Clipboard::~Clipboard() {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +010079 vlog.debug("removing %p from chain (next is %p)", getHandle(), next_window);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000080 ChangeClipboardChain(getHandle(), next_window);
81}
82
83LRESULT
84Clipboard::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
85 switch (msg) {
86
87 case WM_CHANGECBCHAIN:
Pierre Ossman40e3ceb2015-03-03 16:46:19 +010088 vlog.debug("change clipboard chain (%I64x, %I64x)",
89 (long long)wParam, (long long)lParam);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000090 if ((HWND) wParam == next_window)
91 next_window = (HWND) lParam;
92 else if (next_window != 0)
93 SendMessage(next_window, msg, wParam, lParam);
94 else
95 vlog.error("bad clipboard chain change!");
96 break;
97
98 case WM_DRAWCLIPBOARD:
99 {
100 HWND owner = GetClipboardOwner();
101 if (owner == getHandle()) {
102 vlog.debug("local clipboard changed by me");
103 } else {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100104 vlog.debug("local clipboard changed by %p", owner);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000105
Pierre Ossman615d16b2019-05-03 10:53:06 +0200106 if (notifier == NULL)
107 vlog.debug("no clipboard notifier registered");
108 else
109 notifier->notifyClipboardChanged(IsClipboardFormatAvailable(CF_TEXT));
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000110 }
111 }
112 if (next_window)
113 SendMessage(next_window, msg, wParam, lParam);
114 return 0;
115
116 };
117 return MsgWindow::processMessage(msg, wParam, lParam);
118};
119
Pierre Ossman615d16b2019-05-03 10:53:06 +0200120char*
121Clipboard::getClipText() {
122 HGLOBAL cliphandle;
123 char* clipdata;
124 char* filtered;
125
126 // Open the clipboard
127 if (!OpenClipboard(getHandle()))
128 return NULL;
129
130 // Get the clipboard data
131 cliphandle = GetClipboardData(CF_TEXT);
132 if (!cliphandle) {
133 CloseClipboard();
134 return NULL;
135 }
136
137 clipdata = (char*) GlobalLock(cliphandle);
138 if (!clipdata) {
139 CloseClipboard();
140 return NULL;
141 }
142
143 // Filter out anything unwanted
144 filtered = convertLF(clipdata, strlen(clipdata));
145 removeNonISOLatin1Chars(filtered);
146
147 // Release the buffer and close the clipboard
148 GlobalUnlock(cliphandle);
149 CloseClipboard();
150
151 return filtered;
152}
153
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000154void
155Clipboard::setClipText(const char* text) {
156 HANDLE clip_handle = 0;
157
158 try {
159
160 // - Firstly, we must open the clipboard
161 if (!OpenClipboard(getHandle()))
162 throw rdr::SystemException("unable to open Win32 clipboard", GetLastError());
163
164 // - Pre-process the supplied clipboard text into DOS format
165 CharArray dos_text;
166 dos_text.buf = unix2dos(text);
167 removeNonISOLatin1Chars(dos_text.buf);
168 int dos_text_len = strlen(dos_text.buf);
169
170 // - Allocate global memory for the data
171 clip_handle = ::GlobalAlloc(GMEM_MOVEABLE, dos_text_len+1);
172
173 char* data = (char*) GlobalLock(clip_handle);
174 memcpy(data, dos_text.buf, dos_text_len+1);
175 data[dos_text_len] = 0;
176 GlobalUnlock(clip_handle);
177
178 // - Next, we must clear out any existing data
179 if (!EmptyClipboard())
180 throw rdr::SystemException("unable to empty Win32 clipboard", GetLastError());
181
182 // - Set the new clipboard data
183 if (!SetClipboardData(CF_TEXT, clip_handle))
184 throw rdr::SystemException("unable to set Win32 clipboard", GetLastError());
185 clip_handle = 0;
186
187 vlog.debug("set clipboard");
188 } catch (rdr::Exception& e) {
Pierre Ossmanad8609a2012-04-26 09:04:14 +0000189 vlog.debug("%s", e.str());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000190 }
191
192 // - Close the clipboard
193 if (!CloseClipboard())
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100194 vlog.debug("unable to close Win32 clipboard: %lu", GetLastError());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000195 else
196 vlog.debug("closed clipboard");
197 if (clip_handle) {
198 vlog.debug("freeing clipboard handle");
199 GlobalFree(clip_handle);
200 }
201}