OLD | NEW |
---|---|
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/event_executor.h" | 5 #include "remoting/host/event_executor.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 | 8 |
9 #include <X11/Xlib.h> | 9 #include <X11/Xlib.h> |
10 #include <X11/extensions/XTest.h> | 10 #include <X11/extensions/XTest.h> |
11 | 11 |
12 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
13 #include "base/bind.h" | 13 #include "base/bind.h" |
14 #include "base/compiler_specific.h" | 14 #include "base/compiler_specific.h" |
15 #include "base/location.h" | 15 #include "base/location.h" |
16 #include "base/logging.h" | 16 #include "base/logging.h" |
17 #include "base/single_thread_task_runner.h" | 17 #include "base/single_thread_task_runner.h" |
18 #include "remoting/host/clipboard.h" | |
18 #include "remoting/proto/internal.pb.h" | 19 #include "remoting/proto/internal.pb.h" |
19 #include "third_party/skia/include/core/SkPoint.h" | 20 #include "third_party/skia/include/core/SkPoint.h" |
20 | 21 |
21 namespace remoting { | 22 namespace remoting { |
22 | 23 |
23 namespace { | 24 namespace { |
24 | 25 |
25 using protocol::ClipboardEvent; | 26 using protocol::ClipboardEvent; |
26 using protocol::KeyEvent; | 27 using protocol::KeyEvent; |
27 using protocol::MouseEvent; | 28 using protocol::MouseEvent; |
(...skipping 18 matching lines...) Expand all Loading... | |
46 // InputStub interface. | 47 // InputStub interface. |
47 virtual void InjectKeyEvent(const KeyEvent& event) OVERRIDE; | 48 virtual void InjectKeyEvent(const KeyEvent& event) OVERRIDE; |
48 virtual void InjectMouseEvent(const MouseEvent& event) OVERRIDE; | 49 virtual void InjectMouseEvent(const MouseEvent& event) OVERRIDE; |
49 | 50 |
50 // EventExecutor interface. | 51 // EventExecutor interface. |
51 virtual void Start( | 52 virtual void Start( |
52 scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE; | 53 scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE; |
53 virtual void StopAndDelete() OVERRIDE; | 54 virtual void StopAndDelete() OVERRIDE; |
54 | 55 |
55 private: | 56 private: |
57 void InitClipboard(); | |
58 | |
56 // |mode| is one of the AutoRepeatModeOn, AutoRepeatModeOff, | 59 // |mode| is one of the AutoRepeatModeOn, AutoRepeatModeOff, |
57 // AutoRepeatModeDefault constants defined by the XChangeKeyboardControl() | 60 // AutoRepeatModeDefault constants defined by the XChangeKeyboardControl() |
58 // API. | 61 // API. |
59 void SetAutoRepeatForKey(int keycode, int mode); | 62 void SetAutoRepeatForKey(int keycode, int mode); |
60 void InjectScrollWheelClicks(int button, int count); | 63 void InjectScrollWheelClicks(int button, int count); |
61 | 64 |
62 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 65 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
63 | 66 |
64 std::set<int> pressed_keys_; | 67 std::set<int> pressed_keys_; |
65 SkIPoint latest_mouse_position_; | 68 SkIPoint latest_mouse_position_; |
66 | 69 |
67 // X11 graphics context. | 70 // X11 graphics context. |
68 Display* display_; | 71 Display* display_; |
69 Window root_window_; | 72 Window root_window_; |
70 | 73 |
71 int test_event_base_; | 74 int test_event_base_; |
72 int test_error_base_; | 75 int test_error_base_; |
73 | 76 |
77 scoped_ptr<Clipboard> clipboard_; | |
78 | |
74 DISALLOW_COPY_AND_ASSIGN(EventExecutorLinux); | 79 DISALLOW_COPY_AND_ASSIGN(EventExecutorLinux); |
75 }; | 80 }; |
76 | 81 |
77 int MouseButtonToX11ButtonNumber(MouseEvent::MouseButton button) { | 82 int MouseButtonToX11ButtonNumber(MouseEvent::MouseButton button) { |
78 switch (button) { | 83 switch (button) { |
79 case MouseEvent::BUTTON_LEFT: | 84 case MouseEvent::BUTTON_LEFT: |
80 return 1; | 85 return 1; |
81 | 86 |
82 case MouseEvent::BUTTON_RIGHT: | 87 case MouseEvent::BUTTON_RIGHT: |
83 return 3; | 88 return 3; |
(...skipping 17 matching lines...) Expand all Loading... | |
101 // are wheel scroll-down events (button 5). | 106 // are wheel scroll-down events (button 5). |
102 return (dy > 0 ? 4 : 5); | 107 return (dy > 0 ? 4 : 5); |
103 } | 108 } |
104 | 109 |
105 EventExecutorLinux::EventExecutorLinux( | 110 EventExecutorLinux::EventExecutorLinux( |
106 scoped_refptr<base::SingleThreadTaskRunner> task_runner) | 111 scoped_refptr<base::SingleThreadTaskRunner> task_runner) |
107 : task_runner_(task_runner), | 112 : task_runner_(task_runner), |
108 latest_mouse_position_(SkIPoint::Make(-1, -1)), | 113 latest_mouse_position_(SkIPoint::Make(-1, -1)), |
109 display_(XOpenDisplay(NULL)), | 114 display_(XOpenDisplay(NULL)), |
110 root_window_(BadValue) { | 115 root_window_(BadValue) { |
116 if (!task_runner_->BelongsToCurrentThread()) { | |
117 task_runner_->PostTask( | |
118 FROM_HERE, | |
119 base::Bind(&EventExecutorLinux::InitClipboard, base::Unretained(this))); | |
120 } | |
111 } | 121 } |
112 | 122 |
113 EventExecutorLinux::~EventExecutorLinux() { | 123 EventExecutorLinux::~EventExecutorLinux() { |
114 CHECK(pressed_keys_.empty()); | 124 CHECK(pressed_keys_.empty()); |
115 } | 125 } |
116 | 126 |
117 bool EventExecutorLinux::Init() { | 127 bool EventExecutorLinux::Init() { |
118 CHECK(display_); | 128 CHECK(display_); |
119 | 129 |
120 root_window_ = RootWindow(display_, DefaultScreen(display_)); | 130 root_window_ = RootWindow(display_, DefaultScreen(display_)); |
121 if (root_window_ == BadValue) { | 131 if (root_window_ == BadValue) { |
122 LOG(ERROR) << "Unable to get the root window"; | 132 LOG(ERROR) << "Unable to get the root window"; |
123 return false; | 133 return false; |
124 } | 134 } |
125 | 135 |
126 // TODO(ajwong): Do we want to check the major/minor version at all for XTest? | 136 // TODO(ajwong): Do we want to check the major/minor version at all for XTest? |
127 int major = 0; | 137 int major = 0; |
128 int minor = 0; | 138 int minor = 0; |
129 if (!XTestQueryExtension(display_, &test_event_base_, &test_error_base_, | 139 if (!XTestQueryExtension(display_, &test_event_base_, &test_error_base_, |
130 &major, &minor)) { | 140 &major, &minor)) { |
131 LOG(ERROR) << "Server does not support XTest."; | 141 LOG(ERROR) << "Server does not support XTest."; |
132 return false; | 142 return false; |
133 } | 143 } |
134 | 144 |
135 return true; | 145 return true; |
136 } | 146 } |
137 | 147 |
138 void EventExecutorLinux::InjectClipboardEvent(const ClipboardEvent& event) { | 148 void EventExecutorLinux::InjectClipboardEvent(const ClipboardEvent& event) { |
139 // TODO(simonmorris): Implement clipboard injection. | 149 if (!task_runner_->BelongsToCurrentThread()) { |
150 task_runner_->PostTask( | |
151 FROM_HERE, | |
152 base::Bind(&EventExecutorLinux::InjectClipboardEvent, | |
153 base::Unretained(this), event)); | |
154 return; | |
155 } | |
156 | |
157 clipboard_->InjectClipboardEvent(event); | |
140 } | 158 } |
141 | 159 |
142 void EventExecutorLinux::InjectKeyEvent(const KeyEvent& event) { | 160 void EventExecutorLinux::InjectKeyEvent(const KeyEvent& event) { |
143 // HostEventDispatcher should filter events missing the pressed field. | 161 // HostEventDispatcher should filter events missing the pressed field. |
144 DCHECK(event.has_pressed()); | 162 DCHECK(event.has_pressed()); |
145 DCHECK(event.has_usb_keycode()); | 163 DCHECK(event.has_usb_keycode()); |
146 | 164 |
147 if (!task_runner_->BelongsToCurrentThread()) { | 165 if (!task_runner_->BelongsToCurrentThread()) { |
148 task_runner_->PostTask( | 166 task_runner_->PostTask( |
149 FROM_HERE, | 167 FROM_HERE, |
(...skipping 29 matching lines...) Expand all Loading... | |
179 // case, this ensures that key-repeating will continue to work normally | 197 // case, this ensures that key-repeating will continue to work normally |
180 // for the local user of the host machine. "ModeDefault" is used instead | 198 // for the local user of the host machine. "ModeDefault" is used instead |
181 // of "ModeOn", since some keys (such as Shift) should not auto-repeat. | 199 // of "ModeOn", since some keys (such as Shift) should not auto-repeat. |
182 SetAutoRepeatForKey(keycode, AutoRepeatModeDefault); | 200 SetAutoRepeatForKey(keycode, AutoRepeatModeDefault); |
183 } | 201 } |
184 | 202 |
185 XTestFakeKeyEvent(display_, keycode, event.pressed(), CurrentTime); | 203 XTestFakeKeyEvent(display_, keycode, event.pressed(), CurrentTime); |
186 XFlush(display_); | 204 XFlush(display_); |
187 } | 205 } |
188 | 206 |
207 void EventExecutorLinux::InitClipboard() { | |
208 clipboard_ = Clipboard::Create(); | |
Sergey Ulanov
2012/09/14 19:35:01
thread DCHECK please.
Lambros
2012/09/14 21:35:13
Done.
| |
209 } | |
210 | |
189 void EventExecutorLinux::SetAutoRepeatForKey(int keycode, int mode) { | 211 void EventExecutorLinux::SetAutoRepeatForKey(int keycode, int mode) { |
190 XKeyboardControl control; | 212 XKeyboardControl control; |
191 control.key = keycode; | 213 control.key = keycode; |
192 control.auto_repeat_mode = mode; | 214 control.auto_repeat_mode = mode; |
193 XChangeKeyboardControl(display_, KBKey | KBAutoRepeatMode, &control); | 215 XChangeKeyboardControl(display_, KBKey | KBAutoRepeatMode, &control); |
194 } | 216 } |
195 | 217 |
196 void EventExecutorLinux::InjectScrollWheelClicks(int button, int count) { | 218 void EventExecutorLinux::InjectScrollWheelClicks(int button, int count) { |
197 for (int i = 0; i < count; i++) { | 219 for (int i = 0; i < count; i++) { |
198 // Generate a button-down and a button-up to simulate a wheel click. | 220 // Generate a button-down and a button-up to simulate a wheel click. |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
256 int dx = event.wheel_offset_x(); | 278 int dx = event.wheel_offset_x(); |
257 InjectScrollWheelClicks(HorizontalScrollWheelToX11ButtonNumber(dx), | 279 InjectScrollWheelClicks(HorizontalScrollWheelToX11ButtonNumber(dx), |
258 abs(dx)); | 280 abs(dx)); |
259 } | 281 } |
260 | 282 |
261 XFlush(display_); | 283 XFlush(display_); |
262 } | 284 } |
263 | 285 |
264 void EventExecutorLinux::Start( | 286 void EventExecutorLinux::Start( |
265 scoped_ptr<protocol::ClipboardStub> client_clipboard) { | 287 scoped_ptr<protocol::ClipboardStub> client_clipboard) { |
266 return; | 288 if (!task_runner_->BelongsToCurrentThread()) { |
289 task_runner_->PostTask( | |
290 FROM_HERE, | |
291 base::Bind(&EventExecutorLinux::Start, base::Unretained(this), | |
292 base::Passed(client_clipboard.Pass()))); | |
Sergey Ulanov
2012/09/14 19:35:01
FYI: alternative, slightly shorter syntax is base:
Lambros
2012/09/14 21:35:13
This got changed to the shorter syntax when I reba
| |
293 return; | |
294 } | |
295 | |
296 clipboard_->Start(client_clipboard.Pass()); | |
267 } | 297 } |
268 | 298 |
269 void EventExecutorLinux::StopAndDelete() { | 299 void EventExecutorLinux::StopAndDelete() { |
270 delete this; | 300 delete this; |
271 } | 301 } |
272 | 302 |
273 } // namespace | 303 } // namespace |
274 | 304 |
275 scoped_ptr<EventExecutor> EventExecutor::Create( | 305 scoped_ptr<EventExecutor> EventExecutor::Create( |
276 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, | 306 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, |
277 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { | 307 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { |
278 scoped_ptr<EventExecutorLinux> executor( | 308 scoped_ptr<EventExecutorLinux> executor( |
279 new EventExecutorLinux(main_task_runner)); | 309 new EventExecutorLinux(main_task_runner)); |
280 if (!executor->Init()) | 310 if (!executor->Init()) |
281 return scoped_ptr<EventExecutor>(NULL); | 311 return scoped_ptr<EventExecutor>(NULL); |
282 return executor.PassAs<EventExecutor>(); | 312 return executor.PassAs<EventExecutor>(); |
283 } | 313 } |
284 | 314 |
285 } // namespace remoting | 315 } // namespace remoting |
OLD | NEW |