Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(208)

Side by Side Diff: remoting/host/client_session.cc

Issue 9465035: Move ClientSession's input logic into separate components. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merge authenticated and awaiting-continue states. Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/host/client_session.h" 5 #include "remoting/host/client_session.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/message_loop_proxy.h" 9 #include "base/message_loop_proxy.h"
10 #include "remoting/host/capturer.h" 10 #include "remoting/host/capturer.h"
(...skipping 15 matching lines...) Expand all
26 using protocol::MouseEvent; 26 using protocol::MouseEvent;
27 27
28 ClientSession::ClientSession( 28 ClientSession::ClientSession(
29 EventHandler* event_handler, 29 EventHandler* event_handler,
30 protocol::ConnectionToClient* connection, 30 protocol::ConnectionToClient* connection,
31 protocol::InputStub* input_stub, 31 protocol::InputStub* input_stub,
32 Capturer* capturer) 32 Capturer* capturer)
33 : event_handler_(event_handler), 33 : event_handler_(event_handler),
34 connection_(connection), 34 connection_(connection),
35 client_jid_(connection->session()->jid()), 35 client_jid_(connection->session()->jid()),
36 input_stub_(input_stub), 36 key_tracker_(input_stub),
37 capturer_(capturer), 37 capturer_(capturer),
38 authenticated_(false), 38 disable_inputs_(true),
39 awaiting_continue_approval_(false),
40 remote_mouse_button_state_(0) { 39 remote_mouse_button_state_(0) {
41 connection_->SetEventHandler(this); 40 connection_->SetEventHandler(this);
42 41
43 // TODO(sergeyu): Currently ConnectionToClient expects stubs to be 42 // TODO(sergeyu): Currently ConnectionToClient expects stubs to be
44 // set before channels are connected. Make it possible to set stubs 43 // set before channels are connected. Make it possible to set stubs
45 // later and set them only when connection is authenticated. 44 // later and set them only when connection is authenticated.
46 connection_->set_host_stub(this); 45 connection_->set_host_stub(this);
47 connection_->set_input_stub(this); 46 connection_->set_input_stub(this);
48 } 47 }
49 48
50 ClientSession::~ClientSession() { 49 ClientSession::~ClientSession() {
51 } 50 }
52 51
53 void ClientSession::InjectKeyEvent(const KeyEvent& event) { 52 void ClientSession::InjectKeyEvent(const KeyEvent& event) {
54 DCHECK(CalledOnValidThread()); 53 DCHECK(CalledOnValidThread());
55 54
56 if (authenticated_ && !ShouldIgnoreRemoteKeyboardInput(event)) { 55 if (ShouldIgnoreInput())
57 RecordKeyEvent(event); 56 return;
58 input_stub_->InjectKeyEvent(event); 57
59 } 58 key_tracker_.InjectKeyEvent(event);
60 } 59 }
61 60
62 void ClientSession::InjectMouseEvent(const MouseEvent& event) { 61 void ClientSession::InjectMouseEvent(const MouseEvent& event) {
63 DCHECK(CalledOnValidThread()); 62 DCHECK(CalledOnValidThread());
64 63
65 if (authenticated_ && !ShouldIgnoreRemoteMouseInput(event)) { 64 if (ShouldIgnoreInput())
66 RecordMouseButtonState(event); 65 return;
67 MouseEvent event_to_inject = event;
68 if (event.has_x() && event.has_y()) {
69 // In case the client sends events with off-screen coordinates, modify
70 // the event to lie within the current screen area. This is better than
71 // simply discarding the event, which might lose a button-up event at the
72 // end of a drag'n'drop (or cause other related problems).
73 SkIPoint pos(SkIPoint::Make(event.x(), event.y()));
74 const SkISize& screen = capturer_->size_most_recent();
75 pos.setX(std::max(0, std::min(screen.width() - 1, pos.x())));
76 pos.setY(std::max(0, std::min(screen.height() - 1, pos.y())));
77 event_to_inject.set_x(pos.x());
78 event_to_inject.set_y(pos.y());
79 66
80 // Record the mouse position so we can use it if we need to inject 67 RecordMouseButtonState(event);
81 // fake mouse button events. Note that we need to do this after we 68 MouseEvent event_to_inject = event;
82 // clamp the values to the screen area. 69 if (event.has_x() && event.has_y()) {
83 remote_mouse_pos_ = pos; 70 // In case the client sends events with off-screen coordinates, modify
71 // the event to lie within the current screen area. This is better than
72 // simply discarding the event, which might lose a button-up event at the
73 // end of a drag'n'drop (or cause other related problems).
74 SkIPoint pos(SkIPoint::Make(event.x(), event.y()));
75 const SkISize& screen = capturer_->size_most_recent();
76 pos.setX(std::max(0, std::min(screen.width() - 1, pos.x())));
77 pos.setY(std::max(0, std::min(screen.height() - 1, pos.y())));
78 event_to_inject.set_x(pos.x());
79 event_to_inject.set_y(pos.y());
84 80
85 injected_mouse_positions_.push_back(pos); 81 // Record the mouse position so we can use it if we need to inject
86 if (injected_mouse_positions_.size() > kNumRemoteMousePositions) { 82 // fake mouse button events. Note that we need to do this after we
87 VLOG(1) << "Injected mouse positions queue full."; 83 // clamp the values to the screen area.
88 injected_mouse_positions_.pop_front(); 84 remote_mouse_pos_ = pos;
89 } 85
86 injected_mouse_positions_.push_back(pos);
87 if (injected_mouse_positions_.size() > kNumRemoteMousePositions) {
88 VLOG(1) << "Injected mouse positions queue full.";
89 injected_mouse_positions_.pop_front();
90 } 90 }
91 input_stub_->InjectMouseEvent(event_to_inject);
92 } 91 }
92 key_tracker_.InjectMouseEvent(event_to_inject);
93 } 93 }
94 94
95 void ClientSession::OnConnectionOpened( 95 void ClientSession::OnConnectionOpened(
96 protocol::ConnectionToClient* connection) { 96 protocol::ConnectionToClient* connection) {
97 DCHECK(CalledOnValidThread()); 97 DCHECK(CalledOnValidThread());
98 DCHECK_EQ(connection_.get(), connection); 98 DCHECK_EQ(connection_.get(), connection);
99 authenticated_ = true; 99 SetDisableInputs(false);
100 event_handler_->OnSessionAuthenticated(this); 100 event_handler_->OnSessionAuthenticated(this);
101 } 101 }
102 102
103 void ClientSession::OnConnectionClosed( 103 void ClientSession::OnConnectionClosed(
104 protocol::ConnectionToClient* connection) { 104 protocol::ConnectionToClient* connection) {
105 DCHECK(CalledOnValidThread()); 105 DCHECK(CalledOnValidThread());
106 DCHECK_EQ(connection_.get(), connection); 106 DCHECK_EQ(connection_.get(), connection);
107 event_handler_->OnSessionClosed(this); 107 event_handler_->OnSessionClosed(this);
108 } 108 }
109 109
(...skipping 22 matching lines...) Expand all
132 const net::IPEndPoint& local_end_point) { 132 const net::IPEndPoint& local_end_point) {
133 DCHECK(CalledOnValidThread()); 133 DCHECK(CalledOnValidThread());
134 DCHECK_EQ(connection_.get(), connection); 134 DCHECK_EQ(connection_.get(), connection);
135 event_handler_->OnSessionRouteChange(this, channel_name, remote_end_point, 135 event_handler_->OnSessionRouteChange(this, channel_name, remote_end_point,
136 local_end_point); 136 local_end_point);
137 } 137 }
138 138
139 void ClientSession::Disconnect() { 139 void ClientSession::Disconnect() {
140 DCHECK(CalledOnValidThread()); 140 DCHECK(CalledOnValidThread());
141 DCHECK(connection_.get()); 141 DCHECK(connection_.get());
142 authenticated_ = false; 142
143 RestoreEventState(); 143 // SetDisableInputs(true) implicitly restores the input event state.
Jamie 2012/03/15 18:38:56 Are you talking about modifier keys here? This com
Wez 2012/03/15 22:25:29 In principle no, we won't. This is host-side code
144 SetDisableInputs(true);
144 145
145 // This triggers OnSessionClosed() and the session may be destroyed 146 // This triggers OnSessionClosed() and the session may be destroyed
146 // as the result, so this call must be the last in this method. 147 // as the result, so this call must be the last in this method.
147 connection_->Disconnect(); 148 connection_->Disconnect();
148 } 149 }
149 150
150 void ClientSession::LocalMouseMoved(const SkIPoint& mouse_pos) { 151 void ClientSession::LocalMouseMoved(const SkIPoint& mouse_pos) {
151 DCHECK(CalledOnValidThread()); 152 DCHECK(CalledOnValidThread());
152 153
153 // If this is a genuine local input event (rather than an echo of a remote 154 // If this is a genuine local input event (rather than an echo of a remote
(...skipping 11 matching lines...) Expand all
165 // successfully injected (or the local input monitor might have skipped over 166 // successfully injected (or the local input monitor might have skipped over
166 // some positions), and not because the events were out-of-sequence. These 167 // some positions), and not because the events were out-of-sequence. These
167 // spurious positions should therefore be discarded. 168 // spurious positions should therefore be discarded.
168 injected_mouse_positions_.erase(injected_mouse_positions_.begin(), 169 injected_mouse_positions_.erase(injected_mouse_positions_.begin(),
169 ++found_position); 170 ++found_position);
170 } else { 171 } else {
171 latest_local_input_time_ = base::Time::Now(); 172 latest_local_input_time_ = base::Time::Now();
172 } 173 }
173 } 174 }
174 175
175 bool ClientSession::ShouldIgnoreRemoteMouseInput( 176 void ClientSession::SetDisableInputs(bool disable_inputs) {
176 const protocol::MouseEvent& event) const {
177 DCHECK(CalledOnValidThread()); 177 DCHECK(CalledOnValidThread());
178 178
179 // If the last remote input event was a click or a drag, then it's not safe 179 disable_inputs_ = disable_inputs;
180 // to block remote mouse events. For example, it might result in the host 180
181 // missing the mouse-up event and being stuck with the button pressed. 181 if (disable_inputs_)
182 if (remote_mouse_button_state_ != 0) 182 RestoreEventState();
183 return false; 183 }
184 // Otherwise, if the host user has not yet approved the continuation of the 184
185 // connection, then ignore remote mouse events. 185 bool ClientSession::ShouldIgnoreInput() const {
186 if (awaiting_continue_approval_) 186 DCHECK(CalledOnValidThread());
187
188 // Ignore events if input from this client is disabled.
189 if (disable_inputs_)
187 return true; 190 return true;
188 // Otherwise, ignore remote mouse events if the local mouse moved recently. 191
192 // Ignore remote events if the local mouse moved recently.
189 int64 millis = (base::Time::Now() - latest_local_input_time_) 193 int64 millis = (base::Time::Now() - latest_local_input_time_)
190 .InMilliseconds(); 194 .InMilliseconds();
191 if (millis < kRemoteBlockTimeoutMillis) 195 if (millis < kRemoteBlockTimeoutMillis)
192 return true; 196 return true;
193 return false; 197 return false;
194 } 198 }
195 199
196 bool ClientSession::ShouldIgnoreRemoteKeyboardInput(
197 const KeyEvent& event) const {
198 DCHECK(CalledOnValidThread());
199
200 // If the host user has not yet approved the continuation of the connection,
201 // then all remote keyboard input is ignored, except to release keys that
202 // were already pressed.
203 if (awaiting_continue_approval_) {
204 return event.pressed() ||
205 (pressed_keys_.find(event.keycode()) == pressed_keys_.end());
206 }
207 return false;
208 }
209
210 void ClientSession::RecordKeyEvent(const KeyEvent& event) {
211 DCHECK(CalledOnValidThread());
212
213 if (event.pressed()) {
214 pressed_keys_.insert(event.keycode());
215 } else {
216 pressed_keys_.erase(event.keycode());
217 }
218 }
219
220 void ClientSession::RecordMouseButtonState(const MouseEvent& event) { 200 void ClientSession::RecordMouseButtonState(const MouseEvent& event) {
221 DCHECK(CalledOnValidThread()); 201 DCHECK(CalledOnValidThread());
222 202
223 if (event.has_button() && event.has_button_down()) { 203 if (event.has_button() && event.has_button_down()) {
224 // Button values are defined in remoting/proto/event.proto. 204 // Button values are defined in remoting/proto/event.proto.
225 if (event.button() >= 1 && event.button() < MouseEvent::BUTTON_MAX) { 205 if (event.button() >= 1 && event.button() < MouseEvent::BUTTON_MAX) {
226 uint32 button_change = 1 << (event.button() - 1); 206 uint32 button_change = 1 << (event.button() - 1);
227 if (event.button_down()) { 207 if (event.button_down()) {
228 remote_mouse_button_state_ |= button_change; 208 remote_mouse_button_state_ |= button_change;
229 } else { 209 } else {
230 remote_mouse_button_state_ &= ~button_change; 210 remote_mouse_button_state_ &= ~button_change;
231 } 211 }
232 } 212 }
233 } 213 }
234 } 214 }
235 215
236 void ClientSession::RestoreEventState() { 216 void ClientSession::RestoreEventState() {
237 DCHECK(CalledOnValidThread()); 217 DCHECK(CalledOnValidThread());
238 218
239 // Undo any currently pressed keys. 219 // Undo any currently pressed keys.
240 std::set<int>::iterator i; 220 key_tracker_.ReleaseAllKeys();
241 for (i = pressed_keys_.begin(); i != pressed_keys_.end(); ++i) {
242 KeyEvent key;
243 key.set_keycode(*i);
244 key.set_pressed(false);
245 input_stub_->InjectKeyEvent(key);
246 }
247 pressed_keys_.clear();
248 221
249 // Undo any currently pressed mouse buttons. 222 // Undo any currently pressed mouse buttons.
250 for (int i = 1; i < MouseEvent::BUTTON_MAX; i++) { 223 for (int i = 1; i < MouseEvent::BUTTON_MAX; i++) {
251 if (remote_mouse_button_state_ & (1 << (i - 1))) { 224 if (remote_mouse_button_state_ & (1 << (i - 1))) {
252 MouseEvent mouse; 225 MouseEvent mouse;
253 // TODO(wez): Shouldn't [need to] set position here. 226 // TODO(wez): Shouldn't [need to] set position here.
254 mouse.set_x(remote_mouse_pos_.x()); 227 mouse.set_x(remote_mouse_pos_.x());
255 mouse.set_y(remote_mouse_pos_.y()); 228 mouse.set_y(remote_mouse_pos_.y());
256 mouse.set_button((MouseEvent::MouseButton)i); 229 mouse.set_button((MouseEvent::MouseButton)i);
257 mouse.set_button_down(false); 230 mouse.set_button_down(false);
258 input_stub_->InjectMouseEvent(mouse); 231 key_tracker_.InjectMouseEvent(mouse);
259 } 232 }
260 } 233 }
261 remote_mouse_button_state_ = 0; 234 remote_mouse_button_state_ = 0;
262 } 235 }
263 236
264 } // namespace remoting 237 } // namespace remoting
OLDNEW
« remoting/host/client_session.h ('K') | « remoting/host/client_session.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698