| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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.h" |
| 6 | 6 |
| 7 #include <X11/Xlib.h> | 7 #include <X11/Xlib.h> |
| 8 #include <X11/XF86keysym.h> | 8 #include <X11/XF86keysym.h> |
| 9 #include <X11/keysym.h> | 9 #include <X11/keysym.h> |
| 10 #include <X11/extensions/XTest.h> | 10 #include <X11/extensions/XTest.h> |
| 11 | 11 |
| 12 #include "base/basictypes.h" |
| 13 #include "base/compiler_specific.h" |
| 12 #include "base/logging.h" | 14 #include "base/logging.h" |
| 13 #include "base/message_loop.h" | 15 #include "base/message_loop.h" |
| 14 #include "base/task.h" | 16 #include "base/task.h" |
| 15 #include "remoting/proto/internal.pb.h" | 17 #include "remoting/proto/internal.pb.h" |
| 16 | 18 |
| 17 namespace remoting { | 19 namespace remoting { |
| 18 | 20 |
| 19 using protocol::MouseEvent; | 21 using protocol::MouseEvent; |
| 20 using protocol::KeyEvent; | 22 using protocol::KeyEvent; |
| 21 | 23 |
| 22 static int MouseButtonToX11ButtonNumber( | 24 namespace { |
| 23 protocol::MouseEvent::MouseButton button) { | 25 |
| 26 // A class to generate events on Linux. |
| 27 class EventExecutorLinux : public EventExecutor { |
| 28 public: |
| 29 EventExecutorLinux(MessageLoopForUI* message_loop, Capturer* capturer); |
| 30 virtual ~EventExecutorLinux() {}; |
| 31 |
| 32 virtual void InjectKeyEvent(const KeyEvent* event, Task* done) OVERRIDE; |
| 33 virtual void InjectMouseEvent(const MouseEvent* event, Task* done) OVERRIDE; |
| 34 |
| 35 private: |
| 36 bool Init(); |
| 37 MessageLoopForUI* message_loop_; |
| 38 Capturer* capturer_; |
| 39 |
| 40 // X11 graphics context. |
| 41 Display* display_; |
| 42 Window root_window_; |
| 43 int width_; |
| 44 int height_; |
| 45 |
| 46 int test_event_base_; |
| 47 int test_error_base_; |
| 48 |
| 49 DISALLOW_COPY_AND_ASSIGN(EventExecutorLinux); |
| 50 }; |
| 51 |
| 52 int MouseButtonToX11ButtonNumber(MouseEvent::MouseButton button) { |
| 24 switch (button) { | 53 switch (button) { |
| 25 case MouseEvent::BUTTON_LEFT: | 54 case MouseEvent::BUTTON_LEFT: |
| 26 return 1; | 55 return 1; |
| 27 | 56 |
| 28 case MouseEvent::BUTTON_RIGHT: | 57 case MouseEvent::BUTTON_RIGHT: |
| 29 return 3; | 58 return 3; |
| 30 | 59 |
| 31 case MouseEvent::BUTTON_MIDDLE: | 60 case MouseEvent::BUTTON_MIDDLE: |
| 32 return 2; | 61 return 2; |
| 33 | 62 |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 -1, -1, -1, -1, | 218 -1, -1, -1, -1, |
| 190 // 0xF4 - 0xF7 | 219 // 0xF4 - 0xF7 |
| 191 -1, -1, /* VKEY_ATTN */ -1, /* VKEY_CRSEL */ -1, | 220 -1, -1, /* VKEY_ATTN */ -1, /* VKEY_CRSEL */ -1, |
| 192 // 0xF8 - 0xFB | 221 // 0xF8 - 0xFB |
| 193 /* VKEY_EXSEL */ -1, /* VKEY_EREOF */ -1, /* VKEY_PLAY */ -1, | 222 /* VKEY_EXSEL */ -1, /* VKEY_EREOF */ -1, /* VKEY_PLAY */ -1, |
| 194 /* VKEY_ZOOM */ -1, | 223 /* VKEY_ZOOM */ -1, |
| 195 // 0xFC - 0xFF | 224 // 0xFC - 0xFF |
| 196 /* VKEY_NONAME */ -1, /* VKEY_PA1 */ -1, /* VKEY_OEM_CLEAR */ -1, -1 | 225 /* VKEY_NONAME */ -1, /* VKEY_PA1 */ -1, /* VKEY_OEM_CLEAR */ -1, -1 |
| 197 }; | 226 }; |
| 198 | 227 |
| 199 static int ChromotocolKeycodeToX11Keysym(int32_t keycode) { | 228 int ChromotocolKeycodeToX11Keysym(int32_t keycode) { |
| 200 if (keycode < 0 || keycode > 255) { | 229 if (keycode < 0 || keycode > 255) { |
| 201 return -1; | 230 return -1; |
| 202 } | 231 } |
| 203 | 232 |
| 204 return kUsVkeyToKeysym[keycode]; | 233 return kUsVkeyToKeysym[keycode]; |
| 205 } | 234 } |
| 206 | 235 |
| 207 class EventExecutorLinuxPimpl { | 236 EventExecutorLinux::EventExecutorLinux( |
| 208 public: | 237 MessageLoopForUI* message_loop, Capturer* capturer) |
| 209 explicit EventExecutorLinuxPimpl(EventExecutorLinux* executor, | 238 : message_loop_(message_loop), |
| 210 Display* display); | 239 capturer_(capturer), |
| 211 | 240 display_(message_loop->GetDisplay()), |
| 212 bool Init(); // TODO(ajwong): Do we really want this to be synchronous? | |
| 213 | |
| 214 void HandleMouse(const MouseEvent* message); | |
| 215 void HandleKey(const KeyEvent* key_event); | |
| 216 | |
| 217 private: | |
| 218 // Reference to containing class so we can access friend functions. | |
| 219 // Not owned. | |
| 220 EventExecutorLinux* executor_; | |
| 221 | |
| 222 // X11 graphics context. | |
| 223 Display* display_; | |
| 224 Window root_window_; | |
| 225 int width_; | |
| 226 int height_; | |
| 227 | |
| 228 int test_event_base_; | |
| 229 int test_error_base_; | |
| 230 }; | |
| 231 | |
| 232 EventExecutorLinuxPimpl::EventExecutorLinuxPimpl(EventExecutorLinux* executor, | |
| 233 Display* display) | |
| 234 : executor_(executor), | |
| 235 display_(display), | |
| 236 root_window_(BadValue), | 241 root_window_(BadValue), |
| 237 width_(0), | 242 width_(0), |
| 238 height_(0) { | 243 height_(0) { |
| 244 CHECK(Init()); |
| 239 } | 245 } |
| 240 | 246 |
| 241 bool EventExecutorLinuxPimpl::Init() { | 247 bool EventExecutorLinux::Init() { |
| 242 CHECK(display_); | 248 CHECK(display_); |
| 243 | 249 |
| 244 root_window_ = RootWindow(display_, DefaultScreen(display_)); | 250 root_window_ = RootWindow(display_, DefaultScreen(display_)); |
| 245 if (root_window_ == BadValue) { | 251 if (root_window_ == BadValue) { |
| 246 LOG(ERROR) << "Unable to get the root window"; | 252 LOG(ERROR) << "Unable to get the root window"; |
| 247 return false; | 253 return false; |
| 248 } | 254 } |
| 249 | 255 |
| 250 // TODO(ajwong): Do we want to check the major/minor version at all for XTest? | 256 // TODO(ajwong): Do we want to check the major/minor version at all for XTest? |
| 251 int major = 0; | 257 int major = 0; |
| 252 int minor = 0; | 258 int minor = 0; |
| 253 if (!XTestQueryExtension(display_, &test_event_base_, &test_error_base_, | 259 if (!XTestQueryExtension(display_, &test_event_base_, &test_error_base_, |
| 254 &major, &minor)) { | 260 &major, &minor)) { |
| 255 LOG(ERROR) << "Server does not support XTest."; | 261 LOG(ERROR) << "Server does not support XTest."; |
| 256 return false; | 262 return false; |
| 257 } | 263 } |
| 258 | 264 |
| 259 // Grab the width and height so we can figure out if mouse moves are out of | 265 // Grab the width and height so we can figure out if mouse moves are out of |
| 260 // range. | 266 // range. |
| 261 XWindowAttributes root_attr; | 267 XWindowAttributes root_attr; |
| 262 // TODO(ajwong): Handle resolution changes. | 268 // TODO(ajwong): Handle resolution changes. |
| 263 if (!XGetWindowAttributes(display_, root_window_, &root_attr)) { | 269 if (!XGetWindowAttributes(display_, root_window_, &root_attr)) { |
| 264 LOG(ERROR) << "Unable to get window attributes"; | 270 LOG(ERROR) << "Unable to get window attributes"; |
| 265 return false; | 271 return false; |
| 266 } | 272 } |
| 267 | 273 |
| 268 width_ = root_attr.width; | 274 width_ = root_attr.width; |
| 269 height_ = root_attr.height; | 275 height_ = root_attr.height; |
| 270 | |
| 271 return true; | 276 return true; |
| 272 } | 277 } |
| 273 | 278 |
| 274 void EventExecutorLinuxPimpl::HandleKey(const KeyEvent* key_event) { | 279 void EventExecutorLinux::InjectKeyEvent(const KeyEvent* event, Task* done) { |
| 280 if (MessageLoop::current() != message_loop_) { |
| 281 message_loop_->PostTask( |
| 282 FROM_HERE, |
| 283 NewRunnableMethod(this, &EventExecutorLinux::InjectKeyEvent, |
| 284 event, done)); |
| 285 return; |
| 286 } |
| 275 // TODO(ajwong): This will only work for QWERTY keyboards. | 287 // TODO(ajwong): This will only work for QWERTY keyboards. |
| 276 int keysym = ChromotocolKeycodeToX11Keysym(key_event->keycode()); | 288 int keysym = ChromotocolKeycodeToX11Keysym(event->keycode()); |
| 277 | 289 |
| 278 if (keysym == -1) { | 290 if (keysym == -1) { |
| 279 LOG(WARNING) << "Ignoring unknown key: " << key_event->keycode(); | 291 LOG(WARNING) << "Ignoring unknown key: " << event->keycode(); |
| 280 return; | 292 return; |
| 281 } | 293 } |
| 282 | 294 |
| 283 // Translate the keysym into a keycode understandable by the X display. | 295 // Translate the keysym into a keycode understandable by the X display. |
| 284 int keycode = XKeysymToKeycode(display_, keysym); | 296 int keycode = XKeysymToKeycode(display_, keysym); |
| 285 if (keycode == 0) { | 297 if (keycode == 0) { |
| 286 LOG(WARNING) << "Ignoring undefined keysym: " << keysym | 298 LOG(WARNING) << "Ignoring undefined keysym: " << keysym |
| 287 << " for key: " << key_event->keycode(); | 299 << " for key: " << event->keycode(); |
| 288 return; | 300 return; |
| 289 } | 301 } |
| 290 | 302 |
| 291 VLOG(3) << "Got pepper key: " << key_event->keycode() | 303 VLOG(3) << "Got pepper key: " << event->keycode() |
| 292 << " sending keysym: " << keysym | 304 << " sending keysym: " << keysym |
| 293 << " to keycode: " << keycode; | 305 << " to keycode: " << keycode; |
| 294 XTestFakeKeyEvent(display_, keycode, key_event->pressed(), CurrentTime); | 306 XTestFakeKeyEvent(display_, keycode, event->pressed(), CurrentTime); |
| 307 |
| 308 done->Run(); |
| 309 delete done; |
| 295 } | 310 } |
| 296 | 311 |
| 297 void EventExecutorLinuxPimpl::HandleMouse(const MouseEvent* event) { | 312 void EventExecutorLinux::InjectMouseEvent(const MouseEvent* event, |
| 313 Task* done) { |
| 314 if (MessageLoop::current() != message_loop_) { |
| 315 message_loop_->PostTask( |
| 316 FROM_HERE, |
| 317 NewRunnableMethod(this, &EventExecutorLinux::InjectMouseEvent, |
| 318 event, done)); |
| 319 return; |
| 320 } |
| 298 if (event->has_x() && event->has_y()) { | 321 if (event->has_x() && event->has_y()) { |
| 299 if (event->x() < 0 || event->y() < 0 || | 322 if (event->x() < 0 || event->y() < 0 || |
| 300 event->x() > width_ || event->y() > height_) { | 323 event->x() > width_ || event->y() > height_) { |
| 301 // A misbehaving client may send these. Drop events that are out of range. | 324 // A misbehaving client may send these. Drop events that are out of range. |
| 302 // TODO(ajwong): How can we log this sanely? We don't want to DOS the | 325 // TODO(ajwong): How can we log this sanely? We don't want to DOS the |
| 303 // server with a misbehaving client by logging like crazy. | 326 // server with a misbehaving client by logging like crazy. |
| 304 return; | 327 return; |
| 305 } | 328 } |
| 306 | 329 |
| 307 VLOG(3) << "Moving mouse to " << event->x() | 330 VLOG(3) << "Moving mouse to " << event->x() |
| (...skipping 14 matching lines...) Expand all Loading... |
| 322 | 345 |
| 323 VLOG(3) << "Button " << event->button() | 346 VLOG(3) << "Button " << event->button() |
| 324 << " received, sending down " << button_number; | 347 << " received, sending down " << button_number; |
| 325 XTestFakeButtonEvent(display_, button_number, event->button_down(), | 348 XTestFakeButtonEvent(display_, button_number, event->button_down(), |
| 326 CurrentTime); | 349 CurrentTime); |
| 327 } | 350 } |
| 328 | 351 |
| 329 if (event->has_wheel_offset_x() && event->has_wheel_offset_y()) { | 352 if (event->has_wheel_offset_x() && event->has_wheel_offset_y()) { |
| 330 NOTIMPLEMENTED() << "No scroll wheel support yet."; | 353 NOTIMPLEMENTED() << "No scroll wheel support yet."; |
| 331 } | 354 } |
| 332 } | |
| 333 | 355 |
| 334 EventExecutorLinux::EventExecutorLinux( | |
| 335 MessageLoopForUI* message_loop, Capturer* capturer) | |
| 336 : message_loop_(message_loop), | |
| 337 capturer_(capturer), | |
| 338 pimpl_(new EventExecutorLinuxPimpl(this, message_loop->GetDisplay())) { | |
| 339 CHECK(pimpl_->Init()); | |
| 340 } | |
| 341 | |
| 342 EventExecutorLinux::~EventExecutorLinux() { | |
| 343 } | |
| 344 | |
| 345 void EventExecutorLinux::InjectKeyEvent(const KeyEvent* event, Task* done) { | |
| 346 if (MessageLoop::current() != message_loop_) { | |
| 347 message_loop_->PostTask( | |
| 348 FROM_HERE, | |
| 349 NewRunnableMethod(this, &EventExecutorLinux::InjectKeyEvent, | |
| 350 event, done)); | |
| 351 return; | |
| 352 } | |
| 353 pimpl_->HandleKey(event); | |
| 354 done->Run(); | 356 done->Run(); |
| 355 delete done; | 357 delete done; |
| 356 } | 358 } |
| 357 | 359 |
| 358 void EventExecutorLinux::InjectMouseEvent(const MouseEvent* event, | 360 } // namespace |
| 359 Task* done) { | |
| 360 if (MessageLoop::current() != message_loop_) { | |
| 361 message_loop_->PostTask( | |
| 362 FROM_HERE, | |
| 363 NewRunnableMethod(this, &EventExecutorLinux::InjectMouseEvent, | |
| 364 event, done)); | |
| 365 return; | |
| 366 } | |
| 367 pimpl_->HandleMouse(event); | |
| 368 done->Run(); | |
| 369 delete done; | |
| 370 } | |
| 371 | 361 |
| 372 protocol::InputStub* CreateEventExecutor(MessageLoopForUI* message_loop, | 362 EventExecutor* EventExecutor::Create(MessageLoopForUI* message_loop, |
| 373 Capturer* capturer) { | 363 Capturer* capturer) { |
| 374 return new EventExecutorLinux(message_loop, capturer); | 364 return new EventExecutorLinux(message_loop, capturer); |
| 375 } | 365 } |
| 376 | 366 |
| 377 } // namespace remoting | 367 } // namespace remoting |
| 368 |
| 369 DISABLE_RUNNABLE_METHOD_REFCOUNT(remoting::EventExecutorLinux); |
| 370 |
| OLD | NEW |