blob: a06b19b138610b3d1de882df48de26a2732be23c [file] [log] [blame]
Avi Drissmand6cdf9b2022-09-15 19:52:531// Copyright 2012 The Chromium Authors
[email protected]c2b374402012-03-12 19:23:072// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]b0b72f112013-03-24 03:42:425#include "remoting/host/win/session_input_injector.h"
[email protected]c2b374402012-03-12 19:23:076
avic5960f32015-12-22 22:49:487#include <stddef.h>
8
[email protected]764b6f42012-11-06 03:25:259#include <set>
[email protected]c2b374402012-03-12 19:23:0710#include <string>
sergeyu1417e0132015-12-23 19:01:2211#include <utility>
[email protected]c2b374402012-03-12 19:23:0712
[email protected]c2b374402012-03-12 19:23:0713#include "base/compiler_specific.h"
Avi Drissman135261e2023-01-11 22:43:1514#include "base/functional/bind.h"
15#include "base/functional/callback.h"
[email protected]56c59012012-08-18 23:25:3216#include "base/location.h"
Hans Wennborg22e28d6a2020-06-17 17:17:2117#include "base/logging.h"
Patrick Monette643cdf62021-10-15 19:13:4218#include "base/task/single_thread_task_runner.h"
[email protected]b9a06b32012-08-17 23:52:1319#include "remoting/host/sas_injector.h"
[email protected]efad0072012-07-30 22:05:1220#include "remoting/proto/event.pb.h"
[email protected]3aef7222013-06-07 22:39:5021#include "third_party/webrtc/modules/desktop_capture/win/desktop.h"
22#include "third_party/webrtc/modules/desktop_capture/win/scoped_thread_desktop.h"
jamiewalchaadc22f2015-10-12 23:25:5023#include "ui/events/keycodes/dom/dom_code.h"
[email protected]c2b374402012-03-12 19:23:0724
25namespace {
26
jamiewalchaadc22f2015-10-12 23:25:5027bool CheckCtrlAndAltArePressed(const std::set<ui::DomCode>& pressed_keys) {
28 size_t ctrl_keys = pressed_keys.count(ui::DomCode::CONTROL_LEFT) +
29 pressed_keys.count(ui::DomCode::CONTROL_RIGHT);
30 size_t alt_keys = pressed_keys.count(ui::DomCode::ALT_LEFT) +
31 pressed_keys.count(ui::DomCode::ALT_RIGHT);
[email protected]3ac30fdc2012-04-06 07:41:2132 return ctrl_keys != 0 && alt_keys != 0 &&
33 (ctrl_keys + alt_keys == pressed_keys.size());
34}
35
joedow83eff382016-04-29 16:51:1436bool IsWinKeyPressed(const std::set<ui::DomCode>& pressed_keys) {
37 size_t win_keys = pressed_keys.count(ui::DomCode::META_LEFT) +
38 pressed_keys.count(ui::DomCode::META_RIGHT);
39 return win_keys != 0 && win_keys == pressed_keys.size();
40}
41
[email protected]c2b374402012-03-12 19:23:0742} // namespace
43
44namespace remoting {
45
[email protected]9febc5082012-03-17 00:50:2846using protocol::ClipboardEvent;
[email protected]c2b374402012-03-12 19:23:0747using protocol::KeyEvent;
[email protected]529bbd12014-03-27 20:25:3948using protocol::MouseEvent;
49using protocol::TextEvent;
rkuroiwa0e68803f2015-02-26 19:41:4250using protocol::TouchEvent;
[email protected]c2b374402012-03-12 19:23:0751
[email protected]b0b72f112013-03-24 03:42:4252class SessionInputInjectorWin::Core
53 : public base::RefCountedThreadSafe<SessionInputInjectorWin::Core>,
54 public InputInjector {
[email protected]764b6f42012-11-06 03:25:2555 public:
dcheng0765c492016-04-06 22:41:5356 Core(scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
57 std::unique_ptr<InputInjector> nested_executor,
58 scoped_refptr<base::SingleThreadTaskRunner> inject_sas_task_runner,
Evan Stadeaf37ba32020-06-26 20:36:3759 const base::RepeatingClosure& inject_sas,
60 const base::RepeatingClosure& lock_workstation);
[email protected]764b6f42012-11-06 03:25:2561
Peter Boström7c0127b2021-10-05 18:39:5662 Core(const Core&) = delete;
63 Core& operator=(const Core&) = delete;
64
[email protected]b0b72f112013-03-24 03:42:4265 // InputInjector implementation.
dcheng0765c492016-04-06 22:41:5366 void Start(std::unique_ptr<ClipboardStub> client_clipboard) override;
[email protected]764b6f42012-11-06 03:25:2567
68 // protocol::ClipboardStub implementation.
nick697f4292015-04-23 18:22:3169 void InjectClipboardEvent(const ClipboardEvent& event) override;
[email protected]764b6f42012-11-06 03:25:2570
71 // protocol::InputStub implementation.
nick697f4292015-04-23 18:22:3172 void InjectKeyEvent(const KeyEvent& event) override;
73 void InjectTextEvent(const TextEvent& event) override;
74 void InjectMouseEvent(const MouseEvent& event) override;
75 void InjectTouchEvent(const TouchEvent& event) override;
[email protected]764b6f42012-11-06 03:25:2576
77 private:
78 friend class base::RefCountedThreadSafe<Core>;
nick697f4292015-04-23 18:22:3179 ~Core() override;
[email protected]764b6f42012-11-06 03:25:2580
81 // Switches to the desktop receiving a user input if different from
82 // the current one.
83 void SwitchToInputDesktop();
84
85 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner_;
86
87 // Pointer to the next event executor.
dcheng0765c492016-04-06 22:41:5388 std::unique_ptr<InputInjector> nested_executor_;
[email protected]764b6f42012-11-06 03:25:2589
joedow83eff382016-04-29 16:51:1490 scoped_refptr<base::SingleThreadTaskRunner> execute_action_task_runner_;
[email protected]764b6f42012-11-06 03:25:2591
[email protected]3aef7222013-06-07 22:39:5092 webrtc::ScopedThreadDesktop desktop_;
[email protected]764b6f42012-11-06 03:25:2593
joedow7da94602016-06-07 00:18:0494 // Used to inject Secure Attention Sequence.
Evan Stadeaf37ba32020-06-26 20:36:3795 base::RepeatingClosure inject_sas_;
[email protected]764b6f42012-11-06 03:25:2596
joedow83eff382016-04-29 16:51:1497 // Used to lock the current session on non-home SKUs of Windows.
Evan Stadeaf37ba32020-06-26 20:36:3798 base::RepeatingClosure lock_workstation_;
joedow83eff382016-04-29 16:51:1499
joedow83eff382016-04-29 16:51:14100 // Keys currently pressed by the client, used to detect key sequences.
jamiewalchaadc22f2015-10-12 23:25:50101 std::set<ui::DomCode> pressed_keys_;
[email protected]764b6f42012-11-06 03:25:25102};
103
[email protected]b0b72f112013-03-24 03:42:42104SessionInputInjectorWin::Core::Core(
[email protected]e8f8dcee2012-11-02 00:16:05105 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
dcheng0765c492016-04-06 22:41:53106 std::unique_ptr<InputInjector> nested_executor,
joedow83eff382016-04-29 16:51:14107 scoped_refptr<base::SingleThreadTaskRunner> execute_action_task_runner,
Evan Stadeaf37ba32020-06-26 20:36:37108 const base::RepeatingClosure& inject_sas,
109 const base::RepeatingClosure& lock_workstation)
[email protected]764b6f42012-11-06 03:25:25110 : input_task_runner_(input_task_runner),
sergeyu1417e0132015-12-23 19:01:22111 nested_executor_(std::move(nested_executor)),
joedow83eff382016-04-29 16:51:14112 execute_action_task_runner_(execute_action_task_runner),
113 inject_sas_(inject_sas),
114 lock_workstation_(lock_workstation) {}
[email protected]c2b374402012-03-12 19:23:07115
[email protected]b0b72f112013-03-24 03:42:42116void SessionInputInjectorWin::Core::Start(
dcheng0765c492016-04-06 22:41:53117 std::unique_ptr<protocol::ClipboardStub> client_clipboard) {
[email protected]e8f8dcee2012-11-02 00:16:05118 if (!input_task_runner_->BelongsToCurrentThread()) {
119 input_task_runner_->PostTask(
[email protected]3f9c39432012-06-02 01:05:32120 FROM_HERE,
kylechar2caf4d62019-02-15 20:03:42121 base::BindOnce(&Core::Start, this, std::move(client_clipboard)));
[email protected]3f9c39432012-06-02 01:05:32122 return;
123 }
124
sergeyu1417e0132015-12-23 19:01:22125 nested_executor_->Start(std::move(client_clipboard));
[email protected]6d17db92012-05-11 17:03:14126}
127
[email protected]b0b72f112013-03-24 03:42:42128void SessionInputInjectorWin::Core::InjectClipboardEvent(
[email protected]9febc5082012-03-17 00:50:28129 const ClipboardEvent& event) {
[email protected]e8f8dcee2012-11-02 00:16:05130 if (!input_task_runner_->BelongsToCurrentThread()) {
131 input_task_runner_->PostTask(
kylechar2caf4d62019-02-15 20:03:42132 FROM_HERE, base::BindOnce(&Core::InjectClipboardEvent, this, event));
[email protected]3f9c39432012-06-02 01:05:32133 return;
134 }
135
136 nested_executor_->InjectClipboardEvent(event);
[email protected]9febc5082012-03-17 00:50:28137}
138
[email protected]b0b72f112013-03-24 03:42:42139void SessionInputInjectorWin::Core::InjectKeyEvent(const KeyEvent& event) {
[email protected]e8f8dcee2012-11-02 00:16:05140 if (!input_task_runner_->BelongsToCurrentThread()) {
141 input_task_runner_->PostTask(
kylechar2caf4d62019-02-15 20:03:42142 FROM_HERE, base::BindOnce(&Core::InjectKeyEvent, this, event));
[email protected]c2b374402012-03-12 19:23:07143 return;
144 }
145
[email protected]3ac30fdc2012-04-06 07:41:21146 // HostEventDispatcher should drop events lacking the pressed field.
147 DCHECK(event.has_pressed());
148
149 if (event.has_usb_keycode()) {
jamiewalchaadc22f2015-10-12 23:25:50150 ui::DomCode dom_code = static_cast<ui::DomCode>(event.usb_keycode());
[email protected]c2b374402012-03-12 19:23:07151 if (event.pressed()) {
[email protected]3ac30fdc2012-04-06 07:41:21152 // Simulate secure attention sequence if Ctrl-Alt-Del was just pressed.
jamiewalchaadc22f2015-10-12 23:25:50153 if (dom_code == ui::DomCode::DEL &&
[email protected]3c8cfbe72012-07-03 00:24:15154 CheckCtrlAndAltArePressed(pressed_keys_)) {
[email protected]97328ee2013-06-04 06:46:59155 VLOG(3) << "Sending Secure Attention Sequence to the session";
joedow7da94602016-06-07 00:18:04156 execute_action_task_runner_->PostTask(FROM_HERE, inject_sas_);
joedow83eff382016-04-29 16:51:14157 } else if (dom_code == ui::DomCode::US_L &&
158 IsWinKeyPressed(pressed_keys_)) {
159 execute_action_task_runner_->PostTask(FROM_HERE, lock_workstation_);
[email protected]c2b374402012-03-12 19:23:07160 }
[email protected]3ac30fdc2012-04-06 07:41:21161
jamiewalchaadc22f2015-10-12 23:25:50162 pressed_keys_.insert(dom_code);
[email protected]3ac30fdc2012-04-06 07:41:21163 } else {
jamiewalchaadc22f2015-10-12 23:25:50164 pressed_keys_.erase(dom_code);
[email protected]c2b374402012-03-12 19:23:07165 }
[email protected]c2b374402012-03-12 19:23:07166 }
167
[email protected]5ae4da12012-03-17 20:03:57168 SwitchToInputDesktop();
[email protected]c2b374402012-03-12 19:23:07169 nested_executor_->InjectKeyEvent(event);
170}
171
[email protected]529bbd12014-03-27 20:25:39172void SessionInputInjectorWin::Core::InjectTextEvent(const TextEvent& event) {
173 if (!input_task_runner_->BelongsToCurrentThread()) {
174 input_task_runner_->PostTask(
kylechar2caf4d62019-02-15 20:03:42175 FROM_HERE, base::BindOnce(&Core::InjectTextEvent, this, event));
[email protected]529bbd12014-03-27 20:25:39176 return;
177 }
178
179 SwitchToInputDesktop();
180 nested_executor_->InjectTextEvent(event);
181}
182
[email protected]b0b72f112013-03-24 03:42:42183void SessionInputInjectorWin::Core::InjectMouseEvent(const MouseEvent& event) {
[email protected]e8f8dcee2012-11-02 00:16:05184 if (!input_task_runner_->BelongsToCurrentThread()) {
185 input_task_runner_->PostTask(
kylechar2caf4d62019-02-15 20:03:42186 FROM_HERE, base::BindOnce(&Core::InjectMouseEvent, this, event));
[email protected]c2b374402012-03-12 19:23:07187 return;
188 }
189
[email protected]5ae4da12012-03-17 20:03:57190 SwitchToInputDesktop();
[email protected]c2b374402012-03-12 19:23:07191 nested_executor_->InjectMouseEvent(event);
192}
193
rkuroiwa0e68803f2015-02-26 19:41:42194void SessionInputInjectorWin::Core::InjectTouchEvent(const TouchEvent& event) {
rkuroiwa883da7e2015-03-25 05:22:12195 if (!input_task_runner_->BelongsToCurrentThread()) {
196 input_task_runner_->PostTask(
kylechar2caf4d62019-02-15 20:03:42197 FROM_HERE, base::BindOnce(&Core::InjectTouchEvent, this, event));
rkuroiwa883da7e2015-03-25 05:22:12198 return;
199 }
200
201 SwitchToInputDesktop();
202 nested_executor_->InjectTouchEvent(event);
rkuroiwa0e68803f2015-02-26 19:41:42203}
204
[email protected]b0b72f112013-03-24 03:42:42205SessionInputInjectorWin::Core::~Core() {
[email protected]764b6f42012-11-06 03:25:25206}
207
[email protected]b0b72f112013-03-24 03:42:42208void SessionInputInjectorWin::Core::SwitchToInputDesktop() {
[email protected]5ae4da12012-03-17 20:03:57209 // Switch to the desktop receiving user input if different from the current
210 // one.
dcheng0765c492016-04-06 22:41:53211 std::unique_ptr<webrtc::Desktop> input_desktop(
[email protected]3aef7222013-06-07 22:39:50212 webrtc::Desktop::GetInputDesktop());
sergeyuc5f104b2015-01-09 19:33:24213 if (input_desktop.get() != nullptr && !desktop_.IsSame(*input_desktop)) {
[email protected]5ae4da12012-03-17 20:03:57214 // If SetThreadDesktop() fails, the thread is still assigned a desktop.
215 // So we can continue capture screen bits, just from a diffected desktop.
[email protected]3aef7222013-06-07 22:39:50216 desktop_.SetThreadDesktop(input_desktop.release());
[email protected]5ae4da12012-03-17 20:03:57217 }
218}
219
[email protected]b0b72f112013-03-24 03:42:42220SessionInputInjectorWin::SessionInputInjectorWin(
[email protected]764b6f42012-11-06 03:25:25221 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
dcheng0765c492016-04-06 22:41:53222 std::unique_ptr<InputInjector> nested_executor,
[email protected]764b6f42012-11-06 03:25:25223 scoped_refptr<base::SingleThreadTaskRunner> inject_sas_task_runner,
Evan Stadeaf37ba32020-06-26 20:36:37224 const base::RepeatingClosure& inject_sas,
225 const base::RepeatingClosure& lock_workstation) {
sergeyu1417e0132015-12-23 19:01:22226 core_ = new Core(input_task_runner, std::move(nested_executor),
joedow83eff382016-04-29 16:51:14227 inject_sas_task_runner, inject_sas, lock_workstation);
[email protected]764b6f42012-11-06 03:25:25228}
229
[email protected]b0b72f112013-03-24 03:42:42230SessionInputInjectorWin::~SessionInputInjectorWin() {
[email protected]764b6f42012-11-06 03:25:25231}
232
[email protected]b0b72f112013-03-24 03:42:42233void SessionInputInjectorWin::Start(
dcheng0765c492016-04-06 22:41:53234 std::unique_ptr<protocol::ClipboardStub> client_clipboard) {
sergeyu1417e0132015-12-23 19:01:22235 core_->Start(std::move(client_clipboard));
[email protected]764b6f42012-11-06 03:25:25236}
237
[email protected]b0b72f112013-03-24 03:42:42238void SessionInputInjectorWin::InjectClipboardEvent(
[email protected]764b6f42012-11-06 03:25:25239 const protocol::ClipboardEvent& event) {
240 core_->InjectClipboardEvent(event);
241}
242
[email protected]b0b72f112013-03-24 03:42:42243void SessionInputInjectorWin::InjectKeyEvent(const protocol::KeyEvent& event) {
[email protected]764b6f42012-11-06 03:25:25244 core_->InjectKeyEvent(event);
245}
246
[email protected]529bbd12014-03-27 20:25:39247void SessionInputInjectorWin::InjectTextEvent(
248 const protocol::TextEvent& event) {
249 core_->InjectTextEvent(event);
250}
251
[email protected]b0b72f112013-03-24 03:42:42252void SessionInputInjectorWin::InjectMouseEvent(
[email protected]764b6f42012-11-06 03:25:25253 const protocol::MouseEvent& event) {
254 core_->InjectMouseEvent(event);
255}
256
rkuroiwa0e68803f2015-02-26 19:41:42257void SessionInputInjectorWin::InjectTouchEvent(
258 const protocol::TouchEvent& event) {
259 core_->InjectTouchEvent(event);
260}
261
[email protected]c2b374402012-03-12 19:23:07262} // namespace remoting