blob: fca6c1df2a6cfef0f423927b0593dacf78463dc1 [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
106 // Open the clipboard
107 if (OpenClipboard(getHandle())) {
108 // Get the clipboard data
109 HGLOBAL cliphandle = GetClipboardData(CF_TEXT);
110 if (cliphandle) {
111 char* clipdata = (char*) GlobalLock(cliphandle);
112
113 // Notify clients
114 if (notifier) {
115 if (!clipdata) {
116 notifier->notifyClipboardChanged(0, 0);
117 } else {
Pierre Ossman546b2ad2019-05-02 12:32:03 +0200118 CharArray unix_text(convertLF(clipdata, strlen(clipdata)));
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000119 removeNonISOLatin1Chars(unix_text.buf);
120 notifier->notifyClipboardChanged(unix_text.buf, strlen(unix_text.buf));
121 }
122 } else {
123 vlog.debug("no clipboard notifier registered");
124 }
125
126 // Release the buffer and close the clipboard
127 GlobalUnlock(cliphandle);
128 }
129
130 CloseClipboard();
131 }
132 }
133 }
134 if (next_window)
135 SendMessage(next_window, msg, wParam, lParam);
136 return 0;
137
138 };
139 return MsgWindow::processMessage(msg, wParam, lParam);
140};
141
142void
143Clipboard::setClipText(const char* text) {
144 HANDLE clip_handle = 0;
145
146 try {
147
148 // - Firstly, we must open the clipboard
149 if (!OpenClipboard(getHandle()))
150 throw rdr::SystemException("unable to open Win32 clipboard", GetLastError());
151
152 // - Pre-process the supplied clipboard text into DOS format
153 CharArray dos_text;
154 dos_text.buf = unix2dos(text);
155 removeNonISOLatin1Chars(dos_text.buf);
156 int dos_text_len = strlen(dos_text.buf);
157
158 // - Allocate global memory for the data
159 clip_handle = ::GlobalAlloc(GMEM_MOVEABLE, dos_text_len+1);
160
161 char* data = (char*) GlobalLock(clip_handle);
162 memcpy(data, dos_text.buf, dos_text_len+1);
163 data[dos_text_len] = 0;
164 GlobalUnlock(clip_handle);
165
166 // - Next, we must clear out any existing data
167 if (!EmptyClipboard())
168 throw rdr::SystemException("unable to empty Win32 clipboard", GetLastError());
169
170 // - Set the new clipboard data
171 if (!SetClipboardData(CF_TEXT, clip_handle))
172 throw rdr::SystemException("unable to set Win32 clipboard", GetLastError());
173 clip_handle = 0;
174
175 vlog.debug("set clipboard");
176 } catch (rdr::Exception& e) {
Pierre Ossmanad8609a2012-04-26 09:04:14 +0000177 vlog.debug("%s", e.str());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000178 }
179
180 // - Close the clipboard
181 if (!CloseClipboard())
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100182 vlog.debug("unable to close Win32 clipboard: %lu", GetLastError());
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000183 else
184 vlog.debug("closed clipboard");
185 if (clip_handle) {
186 vlog.debug("freeing clipboard handle");
187 GlobalFree(clip_handle);
188 }
189}