Bring the browser window to the front when clicking on deprecated accelerator notific...
[chromium-blink-merge.git] / remoting / host / win / session_input_injector.cc
blobfa0d09cf2b9b67ee6f58f6d189b0b1c198f0f2c2
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 "remoting/protocol/usb_key_codes.h"
19 #include "third_party/webrtc/modules/desktop_capture/win/desktop.h"
20 #include "third_party/webrtc/modules/desktop_capture/win/scoped_thread_desktop.h"
22 namespace {
24 bool CheckCtrlAndAltArePressed(const std::set<uint32>& pressed_keys) {
25 size_t ctrl_keys = pressed_keys.count(kUsbLeftControl) +
26 pressed_keys.count(kUsbRightControl);
27 size_t alt_keys = pressed_keys.count(kUsbLeftAlt) +
28 pressed_keys.count(kUsbRightAlt);
29 return ctrl_keys != 0 && alt_keys != 0 &&
30 (ctrl_keys + alt_keys == pressed_keys.size());
33 } // namespace
35 namespace remoting {
37 using protocol::ClipboardEvent;
38 using protocol::KeyEvent;
39 using protocol::MouseEvent;
40 using protocol::TextEvent;
41 using protocol::TouchEvent;
43 class SessionInputInjectorWin::Core
44 : public base::RefCountedThreadSafe<SessionInputInjectorWin::Core>,
45 public InputInjector {
46 public:
47 Core(
48 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
49 scoped_ptr<InputInjector> nested_executor,
50 scoped_refptr<base::SingleThreadTaskRunner> inject_sas_task_runner,
51 const base::Closure& inject_sas);
53 // InputInjector implementation.
54 void Start(scoped_ptr<ClipboardStub> client_clipboard) override;
56 // protocol::ClipboardStub implementation.
57 void InjectClipboardEvent(const ClipboardEvent& event) override;
59 // protocol::InputStub implementation.
60 void InjectKeyEvent(const KeyEvent& event) override;
61 void InjectTextEvent(const TextEvent& event) override;
62 void InjectMouseEvent(const MouseEvent& event) override;
63 void InjectTouchEvent(const TouchEvent& event) override;
65 private:
66 friend class base::RefCountedThreadSafe<Core>;
67 ~Core() override;
69 // Switches to the desktop receiving a user input if different from
70 // the current one.
71 void SwitchToInputDesktop();
73 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner_;
75 // Pointer to the next event executor.
76 scoped_ptr<InputInjector> nested_executor_;
78 scoped_refptr<base::SingleThreadTaskRunner> inject_sas_task_runner_;
80 webrtc::ScopedThreadDesktop desktop_;
82 // Used to inject Secure Attention Sequence on Vista+.
83 base::Closure inject_sas_;
85 // Used to inject Secure Attention Sequence on XP.
86 scoped_ptr<SasInjector> sas_injector_;
88 // Keys currently pressed by the client, used to detect Ctrl-Alt-Del.
89 std::set<uint32> pressed_keys_;
91 DISALLOW_COPY_AND_ASSIGN(Core);
94 SessionInputInjectorWin::Core::Core(
95 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
96 scoped_ptr<InputInjector> nested_executor,
97 scoped_refptr<base::SingleThreadTaskRunner> inject_sas_task_runner,
98 const base::Closure& inject_sas)
99 : input_task_runner_(input_task_runner),
100 nested_executor_(nested_executor.Pass()),
101 inject_sas_task_runner_(inject_sas_task_runner),
102 inject_sas_(inject_sas) {
105 void SessionInputInjectorWin::Core::Start(
106 scoped_ptr<protocol::ClipboardStub> client_clipboard) {
107 if (!input_task_runner_->BelongsToCurrentThread()) {
108 input_task_runner_->PostTask(
109 FROM_HERE,
110 base::Bind(&Core::Start, this, base::Passed(&client_clipboard)));
111 return;
114 nested_executor_->Start(client_clipboard.Pass());
117 void SessionInputInjectorWin::Core::InjectClipboardEvent(
118 const ClipboardEvent& event) {
119 if (!input_task_runner_->BelongsToCurrentThread()) {
120 input_task_runner_->PostTask(
121 FROM_HERE, base::Bind(&Core::InjectClipboardEvent, this, event));
122 return;
125 nested_executor_->InjectClipboardEvent(event);
128 void SessionInputInjectorWin::Core::InjectKeyEvent(const KeyEvent& event) {
129 if (!input_task_runner_->BelongsToCurrentThread()) {
130 input_task_runner_->PostTask(
131 FROM_HERE, base::Bind(&Core::InjectKeyEvent, this, event));
132 return;
135 // HostEventDispatcher should drop events lacking the pressed field.
136 DCHECK(event.has_pressed());
138 if (event.has_usb_keycode()) {
139 if (event.pressed()) {
140 // Simulate secure attention sequence if Ctrl-Alt-Del was just pressed.
141 if (event.usb_keycode() == kUsbDelete &&
142 CheckCtrlAndAltArePressed(pressed_keys_)) {
143 VLOG(3) << "Sending Secure Attention Sequence to the session";
145 if (base::win::GetVersion() < base::win::VERSION_VISTA) {
146 if (!sas_injector_)
147 sas_injector_ = SasInjector::Create();
148 if (!sas_injector_->InjectSas())
149 LOG(ERROR) << "Failed to inject Secure Attention Sequence.";
150 } else {
151 inject_sas_task_runner_->PostTask(FROM_HERE, inject_sas_);
155 pressed_keys_.insert(event.usb_keycode());
156 } else {
157 pressed_keys_.erase(event.usb_keycode());
161 SwitchToInputDesktop();
162 nested_executor_->InjectKeyEvent(event);
165 void SessionInputInjectorWin::Core::InjectTextEvent(const TextEvent& event) {
166 if (!input_task_runner_->BelongsToCurrentThread()) {
167 input_task_runner_->PostTask(
168 FROM_HERE, base::Bind(&Core::InjectTextEvent, this, event));
169 return;
172 SwitchToInputDesktop();
173 nested_executor_->InjectTextEvent(event);
176 void SessionInputInjectorWin::Core::InjectMouseEvent(const MouseEvent& event) {
177 if (!input_task_runner_->BelongsToCurrentThread()) {
178 input_task_runner_->PostTask(
179 FROM_HERE, base::Bind(&Core::InjectMouseEvent, this, event));
180 return;
183 SwitchToInputDesktop();
184 nested_executor_->InjectMouseEvent(event);
187 void SessionInputInjectorWin::Core::InjectTouchEvent(const TouchEvent& event) {
188 if (!input_task_runner_->BelongsToCurrentThread()) {
189 input_task_runner_->PostTask(
190 FROM_HERE, base::Bind(&Core::InjectTouchEvent, this, event));
191 return;
194 SwitchToInputDesktop();
195 nested_executor_->InjectTouchEvent(event);
198 SessionInputInjectorWin::Core::~Core() {
201 void SessionInputInjectorWin::Core::SwitchToInputDesktop() {
202 // Switch to the desktop receiving user input if different from the current
203 // one.
204 scoped_ptr<webrtc::Desktop> input_desktop(
205 webrtc::Desktop::GetInputDesktop());
206 if (input_desktop.get() != nullptr && !desktop_.IsSame(*input_desktop)) {
207 // If SetThreadDesktop() fails, the thread is still assigned a desktop.
208 // So we can continue capture screen bits, just from a diffected desktop.
209 desktop_.SetThreadDesktop(input_desktop.release());
213 SessionInputInjectorWin::SessionInputInjectorWin(
214 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
215 scoped_ptr<InputInjector> nested_executor,
216 scoped_refptr<base::SingleThreadTaskRunner> inject_sas_task_runner,
217 const base::Closure& inject_sas) {
218 core_ = new Core(input_task_runner, nested_executor.Pass(),
219 inject_sas_task_runner, inject_sas);
222 SessionInputInjectorWin::~SessionInputInjectorWin() {
225 void SessionInputInjectorWin::Start(
226 scoped_ptr<protocol::ClipboardStub> client_clipboard) {
227 core_->Start(client_clipboard.Pass());
230 void SessionInputInjectorWin::InjectClipboardEvent(
231 const protocol::ClipboardEvent& event) {
232 core_->InjectClipboardEvent(event);
235 void SessionInputInjectorWin::InjectKeyEvent(const protocol::KeyEvent& event) {
236 core_->InjectKeyEvent(event);
239 void SessionInputInjectorWin::InjectTextEvent(
240 const protocol::TextEvent& event) {
241 core_->InjectTextEvent(event);
244 void SessionInputInjectorWin::InjectMouseEvent(
245 const protocol::MouseEvent& event) {
246 core_->InjectMouseEvent(event);
249 void SessionInputInjectorWin::InjectTouchEvent(
250 const protocol::TouchEvent& event) {
251 core_->InjectTouchEvent(event);
254 } // namespace remoting