| 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 |