Roll src/third_party/WebKit f36d5e0:68b67cd (svn 193299:193303)
[chromium-blink-merge.git] / remoting / host / win / session_input_injector.cc
blobbf8158ee1b7580f973efca7f46efc80971ce1135
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.
5 #include "remoting/host/win/session_input_injector.h"
7 #include <set>
8 #include <string>
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 "remoting/host/sas_injector.h"
17 #include "remoting/proto/event.pb.h"
18 #include "third_party/webrtc/modules/desktop_capture/win/desktop.h"
19 #include "third_party/webrtc/modules/desktop_capture/win/scoped_thread_desktop.h"
21 namespace {
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;
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());
38 } // namespace
40 namespace remoting {
42 using protocol::ClipboardEvent;
43 using protocol::KeyEvent;
44 using protocol::MouseEvent;
45 using protocol::TextEvent;
46 using protocol::TouchEvent;
48 class SessionInputInjectorWin::Core
49 : public base::RefCountedThreadSafe<SessionInputInjectorWin::Core>,
50 public InputInjector {
51 public:
52 Core(
53 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
54 scoped_ptr<InputInjector> nested_executor,
55 scoped_refptr<base::SingleThreadTaskRunner> inject_sas_task_runner,
56 const base::Closure& inject_sas);
58 // InputInjector implementation.
59 virtual void Start(scoped_ptr<ClipboardStub> client_clipboard) override;
61 // protocol::ClipboardStub implementation.
62 virtual void InjectClipboardEvent(const ClipboardEvent& event) override;
64 // protocol::InputStub implementation.
65 virtual void InjectKeyEvent(const KeyEvent& event) override;
66 virtual void InjectTextEvent(const TextEvent& event) override;
67 virtual void InjectMouseEvent(const MouseEvent& event) override;
68 virtual void InjectTouchEvent(const TouchEvent& event) override;
70 private:
71 friend class base::RefCountedThreadSafe<Core>;
72 virtual ~Core();
74 // Switches to the desktop receiving a user input if different from
75 // the current one.
76 void SwitchToInputDesktop();
78 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner_;
80 // Pointer to the next event executor.
81 scoped_ptr<InputInjector> nested_executor_;
83 scoped_refptr<base::SingleThreadTaskRunner> inject_sas_task_runner_;
85 webrtc::ScopedThreadDesktop desktop_;
87 // Used to inject Secure Attention Sequence on Vista+.
88 base::Closure inject_sas_;
90 // Used to inject Secure Attention Sequence on XP.
91 scoped_ptr<SasInjector> sas_injector_;
93 // Keys currently pressed by the client, used to detect Ctrl-Alt-Del.
94 std::set<uint32> pressed_keys_;
96 DISALLOW_COPY_AND_ASSIGN(Core);
99 SessionInputInjectorWin::Core::Core(
100 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
101 scoped_ptr<InputInjector> nested_executor,
102 scoped_refptr<base::SingleThreadTaskRunner> inject_sas_task_runner,
103 const base::Closure& inject_sas)
104 : input_task_runner_(input_task_runner),
105 nested_executor_(nested_executor.Pass()),
106 inject_sas_task_runner_(inject_sas_task_runner),
107 inject_sas_(inject_sas) {
110 void SessionInputInjectorWin::Core::Start(
111 scoped_ptr<protocol::ClipboardStub> client_clipboard) {
112 if (!input_task_runner_->BelongsToCurrentThread()) {
113 input_task_runner_->PostTask(
114 FROM_HERE,
115 base::Bind(&Core::Start, this, base::Passed(&client_clipboard)));
116 return;
119 nested_executor_->Start(client_clipboard.Pass());
122 void SessionInputInjectorWin::Core::InjectClipboardEvent(
123 const ClipboardEvent& event) {
124 if (!input_task_runner_->BelongsToCurrentThread()) {
125 input_task_runner_->PostTask(
126 FROM_HERE, base::Bind(&Core::InjectClipboardEvent, this, event));
127 return;
130 nested_executor_->InjectClipboardEvent(event);
133 void SessionInputInjectorWin::Core::InjectKeyEvent(const KeyEvent& event) {
134 if (!input_task_runner_->BelongsToCurrentThread()) {
135 input_task_runner_->PostTask(
136 FROM_HERE, base::Bind(&Core::InjectKeyEvent, this, event));
137 return;
140 // HostEventDispatcher should drop events lacking the pressed field.
141 DCHECK(event.has_pressed());
143 if (event.has_usb_keycode()) {
144 if (event.pressed()) {
145 // Simulate secure attention sequence if Ctrl-Alt-Del was just pressed.
146 if (event.usb_keycode() == kUsbDelete &&
147 CheckCtrlAndAltArePressed(pressed_keys_)) {
148 VLOG(3) << "Sending Secure Attention Sequence to the session";
150 if (base::win::GetVersion() < base::win::VERSION_VISTA) {
151 if (!sas_injector_)
152 sas_injector_ = SasInjector::Create();
153 if (!sas_injector_->InjectSas())
154 LOG(ERROR) << "Failed to inject Secure Attention Sequence.";
155 } else {
156 inject_sas_task_runner_->PostTask(FROM_HERE, inject_sas_);
160 pressed_keys_.insert(event.usb_keycode());
161 } else {
162 pressed_keys_.erase(event.usb_keycode());
166 SwitchToInputDesktop();
167 nested_executor_->InjectKeyEvent(event);
170 void SessionInputInjectorWin::Core::InjectTextEvent(const TextEvent& event) {
171 if (!input_task_runner_->BelongsToCurrentThread()) {
172 input_task_runner_->PostTask(
173 FROM_HERE, base::Bind(&Core::InjectTextEvent, this, event));
174 return;
177 SwitchToInputDesktop();
178 nested_executor_->InjectTextEvent(event);
181 void SessionInputInjectorWin::Core::InjectMouseEvent(const MouseEvent& event) {
182 if (!input_task_runner_->BelongsToCurrentThread()) {
183 input_task_runner_->PostTask(
184 FROM_HERE, base::Bind(&Core::InjectMouseEvent, this, event));
185 return;
188 SwitchToInputDesktop();
189 nested_executor_->InjectMouseEvent(event);
192 void SessionInputInjectorWin::Core::InjectTouchEvent(const TouchEvent& event) {
193 if (!input_task_runner_->BelongsToCurrentThread()) {
194 input_task_runner_->PostTask(
195 FROM_HERE, base::Bind(&Core::InjectTouchEvent, this, event));
196 return;
199 SwitchToInputDesktop();
200 nested_executor_->InjectTouchEvent(event);
203 SessionInputInjectorWin::Core::~Core() {
206 void SessionInputInjectorWin::Core::SwitchToInputDesktop() {
207 // Switch to the desktop receiving user input if different from the current
208 // one.
209 scoped_ptr<webrtc::Desktop> input_desktop(
210 webrtc::Desktop::GetInputDesktop());
211 if (input_desktop.get() != nullptr && !desktop_.IsSame(*input_desktop)) {
212 // If SetThreadDesktop() fails, the thread is still assigned a desktop.
213 // So we can continue capture screen bits, just from a diffected desktop.
214 desktop_.SetThreadDesktop(input_desktop.release());
218 SessionInputInjectorWin::SessionInputInjectorWin(
219 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
220 scoped_ptr<InputInjector> nested_executor,
221 scoped_refptr<base::SingleThreadTaskRunner> inject_sas_task_runner,
222 const base::Closure& inject_sas) {
223 core_ = new Core(input_task_runner, nested_executor.Pass(),
224 inject_sas_task_runner, inject_sas);
227 SessionInputInjectorWin::~SessionInputInjectorWin() {
230 void SessionInputInjectorWin::Start(
231 scoped_ptr<protocol::ClipboardStub> client_clipboard) {
232 core_->Start(client_clipboard.Pass());
235 void SessionInputInjectorWin::InjectClipboardEvent(
236 const protocol::ClipboardEvent& event) {
237 core_->InjectClipboardEvent(event);
240 void SessionInputInjectorWin::InjectKeyEvent(const protocol::KeyEvent& event) {
241 core_->InjectKeyEvent(event);
244 void SessionInputInjectorWin::InjectTextEvent(
245 const protocol::TextEvent& event) {
246 core_->InjectTextEvent(event);
249 void SessionInputInjectorWin::InjectMouseEvent(
250 const protocol::MouseEvent& event) {
251 core_->InjectMouseEvent(event);
254 void SessionInputInjectorWin::InjectTouchEvent(
255 const protocol::TouchEvent& event) {
256 core_->InjectTouchEvent(event);
259 } // namespace remoting