Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / remoting / host / win / session_input_injector.cc
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_input_injector.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 "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"
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::KeyEvent;
44 using protocol::MouseEvent;
45 using protocol::TextEvent;
46
47 class SessionInputInjectorWin::Core
48     : public base::RefCountedThreadSafe<SessionInputInjectorWin::Core>,
49       public InputInjector {
50  public:
51   Core(
52       scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
53       scoped_ptr<InputInjector> nested_executor,
54       scoped_refptr<base::SingleThreadTaskRunner> inject_sas_task_runner,
55       const base::Closure& inject_sas);
56
57   // InputInjector implementation.
58   virtual void Start(
59       scoped_ptr<protocol::ClipboardStub> client_clipboard) override;
60
61   // protocol::ClipboardStub implementation.
62   virtual void InjectClipboardEvent(
63       const protocol::ClipboardEvent& event) override;
64
65   // protocol::InputStub implementation.
66   virtual void InjectKeyEvent(const protocol::KeyEvent& event) override;
67   virtual void InjectTextEvent(const protocol::TextEvent& event) override;
68   virtual void InjectMouseEvent(const protocol::MouseEvent& event) override;
69
70  private:
71   friend class base::RefCountedThreadSafe<Core>;
72   virtual ~Core();
73
74   // Switches to the desktop receiving a user input if different from
75   // the current one.
76   void SwitchToInputDesktop();
77
78   scoped_refptr<base::SingleThreadTaskRunner> input_task_runner_;
79
80   // Pointer to the next event executor.
81   scoped_ptr<InputInjector> nested_executor_;
82
83   scoped_refptr<base::SingleThreadTaskRunner> inject_sas_task_runner_;
84
85   webrtc::ScopedThreadDesktop desktop_;
86
87   // Used to inject Secure Attention Sequence on Vista+.
88   base::Closure inject_sas_;
89
90   // Used to inject Secure Attention Sequence on XP.
91   scoped_ptr<SasInjector> sas_injector_;
92
93   // Keys currently pressed by the client, used to detect Ctrl-Alt-Del.
94   std::set<uint32> pressed_keys_;
95
96   DISALLOW_COPY_AND_ASSIGN(Core);
97 };
98
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) {
108 }
109
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;
117   }
118
119   nested_executor_->Start(client_clipboard.Pass());
120 }
121
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;
128   }
129
130   nested_executor_->InjectClipboardEvent(event);
131 }
132
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;
138   }
139
140   // HostEventDispatcher should drop events lacking the pressed field.
141   DCHECK(event.has_pressed());
142
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";
149
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_);
157         }
158       }
159
160       pressed_keys_.insert(event.usb_keycode());
161     } else {
162       pressed_keys_.erase(event.usb_keycode());
163     }
164   }
165
166   SwitchToInputDesktop();
167   nested_executor_->InjectKeyEvent(event);
168 }
169
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;
175   }
176
177   SwitchToInputDesktop();
178   nested_executor_->InjectTextEvent(event);
179 }
180
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;
186   }
187
188   SwitchToInputDesktop();
189   nested_executor_->InjectMouseEvent(event);
190 }
191
192 SessionInputInjectorWin::Core::~Core() {
193 }
194
195 void SessionInputInjectorWin::Core::SwitchToInputDesktop() {
196   // Switch to the desktop receiving user input if different from the current
197   // one.
198   scoped_ptr<webrtc::Desktop> input_desktop(
199       webrtc::Desktop::GetInputDesktop());
200   if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) {
201     // If SetThreadDesktop() fails, the thread is still assigned a desktop.
202     // So we can continue capture screen bits, just from a diffected desktop.
203     desktop_.SetThreadDesktop(input_desktop.release());
204   }
205 }
206
207 SessionInputInjectorWin::SessionInputInjectorWin(
208     scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
209     scoped_ptr<InputInjector> nested_executor,
210     scoped_refptr<base::SingleThreadTaskRunner> inject_sas_task_runner,
211     const base::Closure& inject_sas) {
212   core_ = new Core(input_task_runner, nested_executor.Pass(),
213                    inject_sas_task_runner, inject_sas);
214 }
215
216 SessionInputInjectorWin::~SessionInputInjectorWin() {
217 }
218
219 void SessionInputInjectorWin::Start(
220     scoped_ptr<protocol::ClipboardStub> client_clipboard) {
221   core_->Start(client_clipboard.Pass());
222 }
223
224 void SessionInputInjectorWin::InjectClipboardEvent(
225     const protocol::ClipboardEvent& event) {
226   core_->InjectClipboardEvent(event);
227 }
228
229 void SessionInputInjectorWin::InjectKeyEvent(const protocol::KeyEvent& event) {
230   core_->InjectKeyEvent(event);
231 }
232
233 void SessionInputInjectorWin::InjectTextEvent(
234     const protocol::TextEvent& event) {
235   core_->InjectTextEvent(event);
236 }
237
238 void SessionInputInjectorWin::InjectMouseEvent(
239     const protocol::MouseEvent& event) {
240   core_->InjectMouseEvent(event);
241 }
242
243 }  // namespace remoting