OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/event_executor_linux.h" | 5 #include "remoting/host/event_executor_linux.h" |
6 | 6 |
7 #include <X11/Xlib.h> | 7 #include <X11/Xlib.h> |
8 #include <X11/keysym.h> | 8 #include <X11/keysym.h> |
9 #include <X11/extensions/XTest.h> | 9 #include <X11/extensions/XTest.h> |
10 | 10 |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
13 #include "base/task.h" | 13 #include "base/task.h" |
14 #include "remoting/proto/internal.pb.h" | 14 #include "remoting/proto/internal.pb.h" |
15 | 15 |
16 // TODO(jamiewalch): Class to ensure that XFlush is called regardless of what | |
17 // fields are set in the MouseEvent. It's not worth refactoring HandleMouse to | |
18 // avoid the early returns because calling XFlush is not really the correct | |
19 // way of flushing the XTest requests; instead we should dispatch the requests | |
20 // to a suitable UI thread. | |
21 namespace { | |
22 class ScopedXFlusher { | |
23 public: | |
24 explicit ScopedXFlusher(Display* display) | |
25 : display_(display), needs_flush_(false) { | |
26 } | |
27 | |
28 ~ScopedXFlusher() { | |
29 if (needs_flush_) | |
30 XFlush(display_); | |
31 } | |
32 | |
33 void SignalFlush() { | |
34 needs_flush_ = true; | |
35 } | |
36 | |
37 private: | |
38 Display* display_; | |
39 bool needs_flush_; | |
40 }; | |
41 } | |
42 | |
43 namespace remoting { | 16 namespace remoting { |
44 | 17 |
45 using protocol::MouseEvent; | 18 using protocol::MouseEvent; |
46 using protocol::KeyEvent; | 19 using protocol::KeyEvent; |
47 | 20 |
48 static int MouseButtonToX11ButtonNumber( | 21 static int MouseButtonToX11ButtonNumber( |
49 protocol::MouseEvent::MouseButton button) { | 22 protocol::MouseEvent::MouseButton button) { |
50 switch (button) { | 23 switch (button) { |
51 case MouseEvent::BUTTON_LEFT: | 24 case MouseEvent::BUTTON_LEFT: |
52 return 1; | 25 return 1; |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 static int ChromotocolKeycodeToX11Keysym(int32_t keycode) { | 195 static int ChromotocolKeycodeToX11Keysym(int32_t keycode) { |
223 if (keycode < 0 || keycode > 255) { | 196 if (keycode < 0 || keycode > 255) { |
224 return -1; | 197 return -1; |
225 } | 198 } |
226 | 199 |
227 return kPepperToX11Keysym[keycode]; | 200 return kPepperToX11Keysym[keycode]; |
228 } | 201 } |
229 | 202 |
230 class EventExecutorLinuxPimpl { | 203 class EventExecutorLinuxPimpl { |
231 public: | 204 public: |
232 explicit EventExecutorLinuxPimpl(EventExecutorLinux* executor); | 205 explicit EventExecutorLinuxPimpl(EventExecutorLinux* executor, |
| 206 Display* display); |
233 ~EventExecutorLinuxPimpl(); | 207 ~EventExecutorLinuxPimpl(); |
234 | 208 |
235 bool Init(); // TODO(ajwong): Do we really want this to be synchronous? | 209 bool Init(); // TODO(ajwong): Do we really want this to be synchronous? |
236 | 210 |
237 void HandleMouse(const MouseEvent* message); | 211 void HandleMouse(const MouseEvent* message); |
238 void HandleKey(const KeyEvent* key_event); | 212 void HandleKey(const KeyEvent* key_event); |
239 | 213 |
240 private: | 214 private: |
241 void DeinitXlib(); | 215 void DeinitXlib(); |
242 | 216 |
243 // Reference to containing class so we can access friend functions. | 217 // Reference to containing class so we can access friend functions. |
244 // Not owned. | 218 // Not owned. |
245 EventExecutorLinux* executor_; | 219 EventExecutorLinux* executor_; |
246 | 220 |
247 // X11 graphics context. | 221 // X11 graphics context. |
248 Display* display_; | 222 Display* display_; |
249 Window root_window_; | 223 Window root_window_; |
250 int width_; | 224 int width_; |
251 int height_; | 225 int height_; |
252 | 226 |
253 int test_event_base_; | 227 int test_event_base_; |
254 int test_error_base_; | 228 int test_error_base_; |
255 }; | 229 }; |
256 | 230 |
257 EventExecutorLinuxPimpl::EventExecutorLinuxPimpl(EventExecutorLinux* executor) | 231 EventExecutorLinuxPimpl::EventExecutorLinuxPimpl(EventExecutorLinux* executor, |
| 232 Display* display) |
258 : executor_(executor), | 233 : executor_(executor), |
259 display_(NULL), | 234 display_(display), |
260 root_window_(BadValue), | 235 root_window_(BadValue), |
261 width_(0), | 236 width_(0), |
262 height_(0) { | 237 height_(0) { |
263 } | 238 } |
264 | 239 |
265 EventExecutorLinuxPimpl::~EventExecutorLinuxPimpl() { | 240 EventExecutorLinuxPimpl::~EventExecutorLinuxPimpl() { |
266 DeinitXlib(); | 241 DeinitXlib(); |
267 } | 242 } |
268 | 243 |
269 bool EventExecutorLinuxPimpl::Init() { | 244 bool EventExecutorLinuxPimpl::Init() { |
270 // TODO(ajwong): We should specify the display string we are attaching to | |
271 // in the constructor. | |
272 display_ = XOpenDisplay(NULL); | |
273 if (!display_) { | 245 if (!display_) { |
274 LOG(ERROR) << "Unable to open display"; | 246 LOG(ERROR) << "Unable to open display"; |
275 return false; | 247 return false; |
276 } | 248 } |
277 | 249 |
278 root_window_ = RootWindow(display_, DefaultScreen(display_)); | 250 root_window_ = RootWindow(display_, DefaultScreen(display_)); |
279 if (root_window_ == BadValue) { | 251 if (root_window_ == BadValue) { |
280 LOG(ERROR) << "Unable to get the root window"; | 252 LOG(ERROR) << "Unable to get the root window"; |
281 DeinitXlib(); | 253 DeinitXlib(); |
282 return false; | 254 return false; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 if (keycode == 0) { | 294 if (keycode == 0) { |
323 LOG(WARNING) << "Ignoring undefined keysym: " << keysym | 295 LOG(WARNING) << "Ignoring undefined keysym: " << keysym |
324 << " for key: " << key_event->keycode(); | 296 << " for key: " << key_event->keycode(); |
325 return; | 297 return; |
326 } | 298 } |
327 | 299 |
328 VLOG(3) << "Got pepper key: " << key_event->keycode() | 300 VLOG(3) << "Got pepper key: " << key_event->keycode() |
329 << " sending keysym: " << keysym | 301 << " sending keysym: " << keysym |
330 << " to keycode: " << keycode; | 302 << " to keycode: " << keycode; |
331 XTestFakeKeyEvent(display_, keycode, key_event->pressed(), CurrentTime); | 303 XTestFakeKeyEvent(display_, keycode, key_event->pressed(), CurrentTime); |
332 | |
333 // TODO(jamiewalch): Get rid of this once we're dispatching to the UI thread. | |
334 XFlush(display_); | |
335 } | 304 } |
336 | 305 |
337 void EventExecutorLinuxPimpl::HandleMouse(const MouseEvent* event) { | 306 void EventExecutorLinuxPimpl::HandleMouse(const MouseEvent* event) { |
338 ScopedXFlusher flusher(display_); | |
339 if (event->has_x() && event->has_y()) { | 307 if (event->has_x() && event->has_y()) { |
340 if (event->x() < 0 || event->y() < 0 || | 308 if (event->x() < 0 || event->y() < 0 || |
341 event->x() > width_ || event->y() > height_) { | 309 event->x() > width_ || event->y() > height_) { |
342 // A misbehaving client may send these. Drop events that are out of range. | 310 // A misbehaving client may send these. Drop events that are out of range. |
343 // TODO(ajwong): How can we log this sanely? We don't want to DOS the | 311 // TODO(ajwong): How can we log this sanely? We don't want to DOS the |
344 // server with a misbehaving client by logging like crazy. | 312 // server with a misbehaving client by logging like crazy. |
345 return; | 313 return; |
346 } | 314 } |
347 | 315 |
348 VLOG(3) << "Moving mouse to " << event->x() | 316 VLOG(3) << "Moving mouse to " << event->x() |
349 << "," << event->y(); | 317 << "," << event->y(); |
350 flusher.SignalFlush(); | |
351 XTestFakeMotionEvent(display_, DefaultScreen(display_), | 318 XTestFakeMotionEvent(display_, DefaultScreen(display_), |
352 event->x(), event->y(), | 319 event->x(), event->y(), |
353 CurrentTime); | 320 CurrentTime); |
354 } | 321 } |
355 | 322 |
356 if (event->has_button() && event->has_button_down()) { | 323 if (event->has_button() && event->has_button_down()) { |
357 int button_number = MouseButtonToX11ButtonNumber(event->button()); | 324 int button_number = MouseButtonToX11ButtonNumber(event->button()); |
358 | 325 |
359 if (button_number < 0) { | 326 if (button_number < 0) { |
360 LOG(WARNING) << "Ignoring unknown button type: " | 327 LOG(WARNING) << "Ignoring unknown button type: " |
361 << event->button(); | 328 << event->button(); |
362 return; | 329 return; |
363 } | 330 } |
364 | 331 |
365 VLOG(3) << "Button " << event->button() | 332 VLOG(3) << "Button " << event->button() |
366 << " received, sending down " << button_number; | 333 << " received, sending down " << button_number; |
367 flusher.SignalFlush(); | |
368 XTestFakeButtonEvent(display_, button_number, event->button_down(), | 334 XTestFakeButtonEvent(display_, button_number, event->button_down(), |
369 CurrentTime); | 335 CurrentTime); |
370 } | 336 } |
371 | 337 |
372 if (event->has_wheel_offset_x() && event->has_wheel_offset_y()) { | 338 if (event->has_wheel_offset_x() && event->has_wheel_offset_y()) { |
373 NOTIMPLEMENTED() << "No scroll wheel support yet."; | 339 NOTIMPLEMENTED() << "No scroll wheel support yet."; |
374 } | 340 } |
375 } | 341 } |
376 | 342 |
377 void EventExecutorLinuxPimpl::DeinitXlib() { | 343 void EventExecutorLinuxPimpl::DeinitXlib() { |
378 // TODO(ajwong): We should expose a "close" or "shutdown" method. | 344 // TODO(ajwong): We should expose a "close" or "shutdown" method. |
379 if (display_) { | 345 if (display_) { |
380 if (!XCloseDisplay(display_)) { | 346 if (!XCloseDisplay(display_)) { |
381 LOG(ERROR) << "Unable to close the Xlib Display."; | 347 LOG(ERROR) << "Unable to close the Xlib Display."; |
382 } | 348 } |
383 display_ = NULL; | 349 display_ = NULL; |
384 } | 350 } |
385 } | 351 } |
386 | 352 |
387 EventExecutorLinux::EventExecutorLinux( | 353 EventExecutorLinux::EventExecutorLinux( |
388 MessageLoop* message_loop, Capturer* capturer) | 354 MessageLoopForUI* message_loop, Capturer* capturer) |
389 : message_loop_(message_loop), | 355 : message_loop_(message_loop), |
390 capturer_(capturer), | 356 capturer_(capturer), |
391 pimpl_(new EventExecutorLinuxPimpl(this)) { | 357 pimpl_(new EventExecutorLinuxPimpl(this, message_loop->get_display())) { |
392 CHECK(pimpl_->Init()); | 358 CHECK(pimpl_->Init()); |
393 } | 359 } |
394 | 360 |
395 EventExecutorLinux::~EventExecutorLinux() { | 361 EventExecutorLinux::~EventExecutorLinux() { |
396 } | 362 } |
397 | 363 |
398 void EventExecutorLinux::InjectKeyEvent(const KeyEvent* event, Task* done) { | 364 void EventExecutorLinux::InjectKeyEvent(const KeyEvent* event, Task* done) { |
399 if (MessageLoop::current() != message_loop_) { | 365 if (MessageLoop::current() != message_loop_) { |
400 message_loop_->PostTask( | 366 message_loop_->PostTask( |
401 FROM_HERE, | 367 FROM_HERE, |
(...skipping 13 matching lines...) Expand all Loading... |
415 FROM_HERE, | 381 FROM_HERE, |
416 NewRunnableMethod(this, &EventExecutorLinux::InjectMouseEvent, | 382 NewRunnableMethod(this, &EventExecutorLinux::InjectMouseEvent, |
417 event, done)); | 383 event, done)); |
418 return; | 384 return; |
419 } | 385 } |
420 pimpl_->HandleMouse(event); | 386 pimpl_->HandleMouse(event); |
421 done->Run(); | 387 done->Run(); |
422 delete done; | 388 delete done; |
423 } | 389 } |
424 | 390 |
425 protocol::InputStub* CreateEventExecutor(MessageLoop* message_loop, | 391 protocol::InputStub* CreateEventExecutor(MessageLoopForUI* message_loop, |
426 Capturer* capturer) { | 392 Capturer* capturer) { |
427 return new EventExecutorLinux(message_loop, capturer); | 393 return new EventExecutorLinux(message_loop, capturer); |
428 } | 394 } |
429 | 395 |
430 } // namespace remoting | 396 } // namespace remoting |
OLD | NEW |