OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "remoting/host/win/session_event_executor.h" | |
6 | |
7 #include <set> | |
8 #include <string> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/callback.h" | |
12 #include "base/compiler_specific.h" | |
13 #include "base/location.h" | |
14 #include "base/single_thread_task_runner.h" | |
15 #include "base/win/windows_version.h" | |
16 #include "media/video/capture/screen/win/desktop.h" | |
17 #include "media/video/capture/screen/win/scoped_thread_desktop.h" | |
18 #include "remoting/host/sas_injector.h" | |
19 #include "remoting/proto/event.pb.h" | |
20 | |
21 namespace { | |
22 | |
23 const uint32 kUsbLeftControl = 0x0700e0; | |
24 const uint32 kUsbRightControl = 0x0700e4; | |
25 const uint32 kUsbLeftAlt = 0x0700e2; | |
26 const uint32 kUsbRightAlt = 0x0700e6; | |
27 const uint32 kUsbDelete = 0x07004c; | |
28 | |
29 bool CheckCtrlAndAltArePressed(const std::set<uint32>& pressed_keys) { | |
30 size_t ctrl_keys = pressed_keys.count(kUsbLeftControl) + | |
31 pressed_keys.count(kUsbRightControl); | |
32 size_t alt_keys = pressed_keys.count(kUsbLeftAlt) + | |
33 pressed_keys.count(kUsbRightAlt); | |
34 return ctrl_keys != 0 && alt_keys != 0 && | |
35 (ctrl_keys + alt_keys == pressed_keys.size()); | |
36 } | |
37 | |
38 } // namespace | |
39 | |
40 namespace remoting { | |
41 | |
42 using protocol::ClipboardEvent; | |
43 using protocol::MouseEvent; | |
44 using protocol::KeyEvent; | |
45 | |
46 class SessionEventExecutorWin::Core | |
47 : public base::RefCountedThreadSafe<SessionEventExecutorWin::Core>, | |
48 public EventExecutor { | |
49 public: | |
50 Core( | |
51 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner, | |
52 scoped_ptr<EventExecutor> nested_executor, | |
53 scoped_refptr<base::SingleThreadTaskRunner> inject_sas_task_runner, | |
54 const base::Closure& inject_sas); | |
55 | |
56 // EventExecutor implementation. | |
57 virtual void Start( | |
58 scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE; | |
59 | |
60 // protocol::ClipboardStub implementation. | |
61 virtual void InjectClipboardEvent( | |
62 const protocol::ClipboardEvent& event) OVERRIDE; | |
63 | |
64 // protocol::InputStub implementation. | |
65 virtual void InjectKeyEvent(const protocol::KeyEvent& event) OVERRIDE; | |
66 virtual void InjectMouseEvent(const protocol::MouseEvent& event) OVERRIDE; | |
67 | |
68 private: | |
69 friend class base::RefCountedThreadSafe<Core>; | |
70 virtual ~Core(); | |
71 | |
72 // Switches to the desktop receiving a user input if different from | |
73 // the current one. | |
74 void SwitchToInputDesktop(); | |
75 | |
76 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner_; | |
77 | |
78 // Pointer to the next event executor. | |
79 scoped_ptr<EventExecutor> nested_executor_; | |
80 | |
81 scoped_refptr<base::SingleThreadTaskRunner> inject_sas_task_runner_; | |
82 | |
83 media::ScopedThreadDesktop desktop_; | |
84 | |
85 // Used to inject Secure Attention Sequence on Vista+. | |
86 base::Closure inject_sas_; | |
87 | |
88 // Used to inject Secure Attention Sequence on XP. | |
89 scoped_ptr<SasInjector> sas_injector_; | |
90 | |
91 // Keys currently pressed by the client, used to detect Ctrl-Alt-Del. | |
92 std::set<uint32> pressed_keys_; | |
93 | |
94 DISALLOW_COPY_AND_ASSIGN(Core); | |
95 }; | |
96 | |
97 SessionEventExecutorWin::Core::Core( | |
98 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner, | |
99 scoped_ptr<EventExecutor> nested_executor, | |
100 scoped_refptr<base::SingleThreadTaskRunner> inject_sas_task_runner, | |
101 const base::Closure& inject_sas) | |
102 : input_task_runner_(input_task_runner), | |
103 nested_executor_(nested_executor.Pass()), | |
104 inject_sas_task_runner_(inject_sas_task_runner), | |
105 inject_sas_(inject_sas) { | |
106 } | |
107 | |
108 void SessionEventExecutorWin::Core::Start( | |
109 scoped_ptr<protocol::ClipboardStub> client_clipboard) { | |
110 if (!input_task_runner_->BelongsToCurrentThread()) { | |
111 input_task_runner_->PostTask( | |
112 FROM_HERE, | |
113 base::Bind(&Core::Start, this, base::Passed(&client_clipboard))); | |
114 return; | |
115 } | |
116 | |
117 nested_executor_->Start(client_clipboard.Pass()); | |
118 } | |
119 | |
120 void SessionEventExecutorWin::Core::InjectClipboardEvent( | |
121 const ClipboardEvent& event) { | |
122 if (!input_task_runner_->BelongsToCurrentThread()) { | |
123 input_task_runner_->PostTask( | |
124 FROM_HERE, base::Bind(&Core::InjectClipboardEvent, this, event)); | |
125 return; | |
126 } | |
127 | |
128 nested_executor_->InjectClipboardEvent(event); | |
129 } | |
130 | |
131 void SessionEventExecutorWin::Core::InjectKeyEvent(const KeyEvent& event) { | |
132 if (!input_task_runner_->BelongsToCurrentThread()) { | |
133 input_task_runner_->PostTask( | |
134 FROM_HERE, base::Bind(&Core::InjectKeyEvent, this, event)); | |
135 return; | |
136 } | |
137 | |
138 // HostEventDispatcher should drop events lacking the pressed field. | |
139 DCHECK(event.has_pressed()); | |
140 | |
141 if (event.has_usb_keycode()) { | |
142 if (event.pressed()) { | |
143 // Simulate secure attention sequence if Ctrl-Alt-Del was just pressed. | |
144 if (event.usb_keycode() == kUsbDelete && | |
145 CheckCtrlAndAltArePressed(pressed_keys_)) { | |
146 VLOG(3) << "Sending Secure Attention Sequence to console"; | |
147 | |
148 if (base::win::GetVersion() < base::win::VERSION_VISTA) { | |
149 if (!sas_injector_) | |
150 sas_injector_ = SasInjector::Create(); | |
151 if (!sas_injector_->InjectSas()) | |
152 LOG(ERROR) << "Failed to inject Secure Attention Sequence."; | |
153 } else { | |
154 inject_sas_task_runner_->PostTask(FROM_HERE, inject_sas_); | |
155 } | |
156 } | |
157 | |
158 pressed_keys_.insert(event.usb_keycode()); | |
159 } else { | |
160 pressed_keys_.erase(event.usb_keycode()); | |
161 } | |
162 } | |
163 | |
164 SwitchToInputDesktop(); | |
165 nested_executor_->InjectKeyEvent(event); | |
166 } | |
167 | |
168 void SessionEventExecutorWin::Core::InjectMouseEvent(const MouseEvent& event) { | |
169 if (!input_task_runner_->BelongsToCurrentThread()) { | |
170 input_task_runner_->PostTask( | |
171 FROM_HERE, base::Bind(&Core::InjectMouseEvent, this, event)); | |
172 return; | |
173 } | |
174 | |
175 SwitchToInputDesktop(); | |
176 nested_executor_->InjectMouseEvent(event); | |
177 } | |
178 | |
179 SessionEventExecutorWin::Core::~Core() { | |
180 } | |
181 | |
182 void SessionEventExecutorWin::Core::SwitchToInputDesktop() { | |
183 // Switch to the desktop receiving user input if different from the current | |
184 // one. | |
185 scoped_ptr<media::Desktop> input_desktop = media::Desktop::GetInputDesktop(); | |
186 if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) { | |
187 // If SetThreadDesktop() fails, the thread is still assigned a desktop. | |
188 // So we can continue capture screen bits, just from a diffected desktop. | |
189 desktop_.SetThreadDesktop(input_desktop.Pass()); | |
190 } | |
191 } | |
192 | |
193 SessionEventExecutorWin::SessionEventExecutorWin( | |
194 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner, | |
195 scoped_ptr<EventExecutor> nested_executor, | |
196 scoped_refptr<base::SingleThreadTaskRunner> inject_sas_task_runner, | |
197 const base::Closure& inject_sas) { | |
198 core_ = new Core(input_task_runner, nested_executor.Pass(), | |
199 inject_sas_task_runner, inject_sas); | |
200 } | |
201 | |
202 SessionEventExecutorWin::~SessionEventExecutorWin() { | |
203 } | |
204 | |
205 void SessionEventExecutorWin::Start( | |
206 scoped_ptr<protocol::ClipboardStub> client_clipboard) { | |
207 core_->Start(client_clipboard.Pass()); | |
208 } | |
209 | |
210 void SessionEventExecutorWin::InjectClipboardEvent( | |
211 const protocol::ClipboardEvent& event) { | |
212 core_->InjectClipboardEvent(event); | |
213 } | |
214 | |
215 void SessionEventExecutorWin::InjectKeyEvent(const protocol::KeyEvent& event) { | |
216 core_->InjectKeyEvent(event); | |
217 } | |
218 | |
219 void SessionEventExecutorWin::InjectMouseEvent( | |
220 const protocol::MouseEvent& event) { | |
221 core_->InjectMouseEvent(event); | |
222 } | |
223 | |
224 } // namespace remoting | |
OLD | NEW |