Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: remoting/host/clipboard_win.cc

Issue 10381115: [Chromoting] The Windows IT2Me host gets any new text items it finds on the clipboard. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Sync. Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « remoting/host/clipboard.h ('k') | remoting/host/desktop_environment.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/host/clipboard.h" 5 #include "remoting/host/clipboard.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 8
9 #include "base/basictypes.h" 9 #include "base/basictypes.h"
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/process_util.h" 12 #include "base/process_util.h"
13 #include "base/string16.h" 13 #include "base/string16.h"
14 #include "base/utf_string_conversions.h" 14 #include "base/utf_string_conversions.h"
15 #include "base/win/scoped_hglobal.h"
16 #include "base/win/windows_version.h"
15 #include "base/win/wrapped_window_proc.h" 17 #include "base/win/wrapped_window_proc.h"
16 #include "remoting/base/constants.h" 18 #include "remoting/base/constants.h"
17 #include "remoting/proto/event.pb.h" 19 #include "remoting/proto/event.pb.h"
18 20
19 namespace { 21 namespace {
20 22
21 const WCHAR kWindowClassName[] = L"clipboardWindowClass"; 23 const WCHAR kWindowClassName[] = L"clipboardWindowClass";
22 const WCHAR kWindowName[] = L"clipboardWindow"; 24 const WCHAR kWindowName[] = L"clipboardWindow";
23 25
24 // A scoper class that opens and closes the clipboard. 26 // A scoper class that opens and closes the clipboard.
(...skipping 13 matching lines...) Expand all
38 bool Init(HWND owner) { 40 bool Init(HWND owner) {
39 const int kMaxAttemptsToOpenClipboard = 5; 41 const int kMaxAttemptsToOpenClipboard = 5;
40 const base::TimeDelta kSleepTimeBetweenAttempts = 42 const base::TimeDelta kSleepTimeBetweenAttempts =
41 base::TimeDelta::FromMilliseconds(5); 43 base::TimeDelta::FromMilliseconds(5);
42 44
43 if (opened_) { 45 if (opened_) {
44 NOTREACHED(); 46 NOTREACHED();
45 return true; 47 return true;
46 } 48 }
47 49
48 // This code runs on the desktop thread, so blocking briefly is acceptable. 50 // This code runs on the UI thread, so we can block only very briefly.
49 for (int attempt = 0; attempt < kMaxAttemptsToOpenClipboard; ++attempt) { 51 for (int attempt = 0; attempt < kMaxAttemptsToOpenClipboard; ++attempt) {
50 if (attempt > 0) { 52 if (attempt > 0) {
51 base::PlatformThread::Sleep(kSleepTimeBetweenAttempts); 53 base::PlatformThread::Sleep(kSleepTimeBetweenAttempts);
52 } 54 }
53 if (::OpenClipboard(owner)) { 55 if (::OpenClipboard(owner)) {
54 opened_ = true; 56 opened_ = true;
55 return true; 57 return true;
56 } 58 }
57 } 59 }
58 return false; 60 return false;
59 } 61 }
60 62
61 BOOL Empty() { 63 BOOL Empty() {
62 if (!opened_) { 64 if (!opened_) {
63 NOTREACHED(); 65 NOTREACHED();
64 return false; 66 return false;
65 } 67 }
66 return ::EmptyClipboard(); 68 return ::EmptyClipboard();
67 } 69 }
68 70
69 void SetData(UINT uFormat, HANDLE hMem) { 71 void SetData(UINT uFormat, HANDLE hMem) {
70 if (!opened_) { 72 if (!opened_) {
71 NOTREACHED(); 73 NOTREACHED();
72 return; 74 return;
73 } 75 }
74 // The caller must not close the handle that ::SetClipboardData returns. 76 // The caller must not close the handle that ::SetClipboardData returns.
75 ::SetClipboardData(uFormat, hMem); 77 ::SetClipboardData(uFormat, hMem);
76 } 78 }
77 79
80 // The caller must not free the handle. The caller should lock the handle,
81 // copy the clipboard data, and unlock the handle. All this must be done
82 // before this ScopedClipboard is destroyed.
83 HANDLE GetData(UINT format) {
84 if (!opened_) {
85 NOTREACHED();
86 return NULL;
87 }
88 return ::GetClipboardData(format);
89 }
90
78 private: 91 private:
79 bool opened_; 92 bool opened_;
80 }; 93 };
81 94
95 typedef BOOL (WINAPI AddClipboardFormatListenerFn)(HWND);
96 typedef BOOL (WINAPI RemoveClipboardFormatListenerFn)(HWND);
97
82 } // namespace 98 } // namespace
83 99
84 namespace remoting { 100 namespace remoting {
85 101
86 class ClipboardWin : public Clipboard { 102 class ClipboardWin : public Clipboard {
87 public: 103 public:
88 ClipboardWin(); 104 ClipboardWin();
89 105
90 virtual void Start() OVERRIDE; 106 virtual void Start() OVERRIDE;
91 virtual void InjectClipboardEvent( 107 virtual void InjectClipboardEvent(
92 const protocol::ClipboardEvent& event) OVERRIDE; 108 const protocol::ClipboardEvent& event) OVERRIDE;
93 virtual void Stop() OVERRIDE; 109 virtual void Stop() OVERRIDE;
94 110
95 private: 111 private:
112 void OnClipboardUpdate();
113 bool HaveClipboardListenerApi();
114
115 static bool RegisterWindowClass();
96 static LRESULT CALLBACK WndProc(HWND hwmd, UINT msg, WPARAM wParam, 116 static LRESULT CALLBACK WndProc(HWND hwmd, UINT msg, WPARAM wParam,
97 LPARAM lParam); 117 LPARAM lParam);
98 118
99 static bool RegisterWindowClass();
100
101 HWND hwnd_; 119 HWND hwnd_;
120 AddClipboardFormatListenerFn* add_clipboard_format_listener_;
121 RemoveClipboardFormatListenerFn* remove_clipboard_format_listener_;
122 bool load_functions_tried_;
102 123
103 DISALLOW_COPY_AND_ASSIGN(ClipboardWin); 124 DISALLOW_COPY_AND_ASSIGN(ClipboardWin);
104 }; 125 };
105 126
106 ClipboardWin::ClipboardWin() : hwnd_(NULL) { 127 ClipboardWin::ClipboardWin()
128 : hwnd_(NULL),
129 add_clipboard_format_listener_(NULL),
130 remove_clipboard_format_listener_(NULL),
131 load_functions_tried_(false) {
107 } 132 }
108 133
109 void ClipboardWin::Start() { 134 void ClipboardWin::Start() {
135 if (!load_functions_tried_) {
136 load_functions_tried_ = true;
137 HMODULE user32_module = ::GetModuleHandle(L"user32.dll");
138 if (!user32_module) {
139 LOG(WARNING) << "Couldn't find user32.dll.";
140 } else {
141 add_clipboard_format_listener_ =
142 reinterpret_cast<AddClipboardFormatListenerFn*>(
143 ::GetProcAddress(user32_module, "AddClipboardFormatListener"));
144 remove_clipboard_format_listener_ =
145 reinterpret_cast<RemoveClipboardFormatListenerFn*>(
146 ::GetProcAddress(user32_module, "RemoveClipboardFormatListener"));
147 if (!HaveClipboardListenerApi()) {
148 LOG(WARNING) << "Couldn't load AddClipboardFormatListener or "
149 << "RemoveClipboardFormatListener.";
150 }
151 }
152 }
153
110 if (!RegisterWindowClass()) { 154 if (!RegisterWindowClass()) {
111 LOG(FATAL) << "Couldn't register clipboard window class."; 155 LOG(FATAL) << "Couldn't register clipboard window class.";
112 return; 156 return;
113 } 157 }
114 hwnd_ = ::CreateWindow(kWindowClassName, 158 hwnd_ = ::CreateWindow(kWindowClassName,
115 kWindowName, 159 kWindowName,
116 0, 0, 0, 0, 0, 160 0, 0, 0, 0, 0,
117 HWND_MESSAGE, 161 HWND_MESSAGE,
118 NULL, 162 NULL,
119 base::GetModuleFromAddress(&WndProc), 163 base::GetModuleFromAddress(&WndProc),
120 this); 164 this);
121 if (!hwnd_) { 165 if (!hwnd_) {
122 LOG(FATAL) << "Couldn't create clipboard window."; 166 LOG(FATAL) << "Couldn't create clipboard window.";
123 return; 167 return;
124 } 168 }
169
170 if (HaveClipboardListenerApi()) {
171 if (!(*add_clipboard_format_listener_)(hwnd_)) {
172 LOG(WARNING) << "AddClipboardFormatListener() failed: " << GetLastError();
173 }
174 }
125 } 175 }
126 176
127 void ClipboardWin::Stop() { 177 void ClipboardWin::Stop() {
128 if (hwnd_) { 178 if (hwnd_) {
179 if (HaveClipboardListenerApi()) {
180 (*remove_clipboard_format_listener_)(hwnd_);
181 }
129 ::DestroyWindow(hwnd_); 182 ::DestroyWindow(hwnd_);
130 hwnd_ = NULL; 183 hwnd_ = NULL;
131 } 184 }
132 } 185 }
133 186
134 void ClipboardWin::InjectClipboardEvent( 187 void ClipboardWin::InjectClipboardEvent(
135 const protocol::ClipboardEvent& event) { 188 const protocol::ClipboardEvent& event) {
136 if (!hwnd_) { 189 if (!hwnd_) {
137 return; 190 return;
138 } 191 }
(...skipping 20 matching lines...) Expand all
159 212
160 LPWSTR text_global_locked = 213 LPWSTR text_global_locked =
161 reinterpret_cast<LPWSTR>(::GlobalLock(text_global)); 214 reinterpret_cast<LPWSTR>(::GlobalLock(text_global));
162 memcpy(text_global_locked, text.data(), text.size() * sizeof(WCHAR)); 215 memcpy(text_global_locked, text.data(), text.size() * sizeof(WCHAR));
163 text_global_locked[text.size()] = (WCHAR)0; 216 text_global_locked[text.size()] = (WCHAR)0;
164 ::GlobalUnlock(text_global); 217 ::GlobalUnlock(text_global);
165 218
166 clipboard.SetData(CF_UNICODETEXT, text_global); 219 clipboard.SetData(CF_UNICODETEXT, text_global);
167 } 220 }
168 221
169 LRESULT CALLBACK ClipboardWin::WndProc(HWND hwnd, UINT msg, WPARAM wParam, 222 void ClipboardWin::OnClipboardUpdate() {
170 LPARAM lParam) { 223 DCHECK(hwnd_);
171 return ::DefWindowProc(hwnd, msg, wParam, lParam); 224
225 if (::IsClipboardFormatAvailable(CF_UNICODETEXT)) {
226 string16 text;
227 // Add a scope, so that we keep the clipboard open for as short a time as
228 // possible.
229 {
230 ScopedClipboard clipboard;
231 if (!clipboard.Init(hwnd_)) {
232 LOG(WARNING) << "Couldn't open the clipboard." << GetLastError();
233 return;
234 }
235
236 HGLOBAL text_global = clipboard.GetData(CF_UNICODETEXT);
237 if (!text_global) {
238 LOG(WARNING) << "Couldn't get data from the clipboard: "
239 << GetLastError();
240 return;
241 }
242
243 base::win::ScopedHGlobal<WCHAR> text_lock(text_global);
244 if (!text_lock.get()) {
245 LOG(WARNING) << "Couldn't lock clipboard data: " << GetLastError();
246 return;
247 }
248 text.assign(text_lock.get());
249 }
250
251 protocol::ClipboardEvent event;
252 event.set_mime_type(kMimeTypeTextUtf8);
253 event.set_data(UTF16ToUTF8(text));
254
255 // TODO(simonmorris): Send the event to the client.
256 }
257 }
258
259 bool ClipboardWin::HaveClipboardListenerApi() {
260 return add_clipboard_format_listener_ && remove_clipboard_format_listener_;
172 } 261 }
173 262
174 bool ClipboardWin::RegisterWindowClass() { 263 bool ClipboardWin::RegisterWindowClass() {
175 // This method is only called on the desktop thread, so it doesn't matter 264 // This method is only called on the UI thread, so it doesn't matter
176 // that the following test is not thread-safe. 265 // that the following test is not thread-safe.
177 static bool registered = false; 266 static bool registered = false;
178 if (registered) { 267 if (registered) {
179 return true; 268 return true;
180 } 269 }
181 270
182 WNDCLASSEX window_class; 271 WNDCLASSEX window_class;
183 base::win::InitializeWindowClass( 272 base::win::InitializeWindowClass(
184 kWindowClassName, 273 kWindowClassName,
185 base::win::WrappedWindowProc<WndProc>, 274 base::win::WrappedWindowProc<WndProc>,
186 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 275 0, 0, 0, NULL, NULL, NULL, NULL, NULL,
187 &window_class); 276 &window_class);
188 if (!::RegisterClassEx(&window_class)) { 277 if (!::RegisterClassEx(&window_class)) {
189 return false; 278 return false;
190 } 279 }
191 280
192 registered = true; 281 registered = true;
193 return true; 282 return true;
194 } 283 }
195 284
285 LRESULT CALLBACK ClipboardWin::WndProc(HWND hwnd, UINT msg, WPARAM wparam,
286 LPARAM lparam) {
287 if (msg == WM_CREATE) {
288 CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lparam);
289 ::SetWindowLongPtr(hwnd,
290 GWLP_USERDATA,
291 reinterpret_cast<LONG_PTR>(cs->lpCreateParams));
292 return 0;
293 }
294 ClipboardWin* clipboard =
295 reinterpret_cast<ClipboardWin*>(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
296 switch (msg) {
297 case WM_CLIPBOARDUPDATE:
298 clipboard->OnClipboardUpdate();
299 return 0;
300 }
301 return ::DefWindowProc(hwnd, msg, wparam, lparam);
302 }
303
196 scoped_ptr<Clipboard> Clipboard::Create() { 304 scoped_ptr<Clipboard> Clipboard::Create() {
197 return scoped_ptr<Clipboard>(new ClipboardWin()); 305 return scoped_ptr<Clipboard>(new ClipboardWin());
198 } 306 }
199 307
200 } // namespace remoting 308 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/clipboard.h ('k') | remoting/host/desktop_environment.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698