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

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: Move mouse state tracking to InputEventTracker. 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 input_tracker_(input_stub),
37 capturer_(capturer), 37 capturer_(capturer) {
38 authenticated_(false),
39 awaiting_continue_approval_(false),
40 remote_mouse_button_state_(0) {
41 connection_->SetEventHandler(this); 38 connection_->SetEventHandler(this);
42 39
43 // TODO(sergeyu): Currently ConnectionToClient expects stubs to be 40 // TODO(sergeyu): Currently ConnectionToClient expects stubs to be
44 // set before channels are connected. Make it possible to set stubs 41 // set before channels are connected. Make it possible to set stubs
45 // later and set them only when connection is authenticated. 42 // later and set them only when connection is authenticated.
46 connection_->set_host_stub(this); 43 connection_->set_host_stub(this);
47 connection_->set_input_stub(this); 44 connection_->set_input_stub(&input_filter_);
48 } 45 }
49 46
50 ClientSession::~ClientSession() { 47 ClientSession::~ClientSession() {
51 } 48 }
52 49
53 void ClientSession::InjectKeyEvent(const KeyEvent& event) { 50 void ClientSession::InjectKeyEvent(const KeyEvent& event) {
54 DCHECK(CalledOnValidThread()); 51 DCHECK(CalledOnValidThread());
55 52
56 if (authenticated_ && !ShouldIgnoreRemoteKeyboardInput(event)) { 53 if (ShouldIgnoreInput())
57 RecordKeyEvent(event); 54 return;
58 input_stub_->InjectKeyEvent(event); 55
59 } 56 input_tracker_.InjectKeyEvent(event);
60 } 57 }
61 58
62 void ClientSession::InjectMouseEvent(const MouseEvent& event) { 59 void ClientSession::InjectMouseEvent(const MouseEvent& event) {
63 DCHECK(CalledOnValidThread()); 60 DCHECK(CalledOnValidThread());
64 61
65 if (authenticated_ && !ShouldIgnoreRemoteMouseInput(event)) { 62 if (ShouldIgnoreInput())
66 RecordMouseButtonState(event); 63 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 64
80 // Record the mouse position so we can use it if we need to inject 65 MouseEvent event_to_inject = event;
81 // fake mouse button events. Note that we need to do this after we 66 if (event.has_x() && event.has_y()) {
82 // clamp the values to the screen area. 67 // In case the client sends events with off-screen coordinates, modify
83 remote_mouse_pos_ = pos; 68 // the event to lie within the current screen area. This is better than
69 // simply discarding the event, which might lose a button-up event at the
70 // end of a drag'n'drop (or cause other related problems).
71 SkIPoint pos(SkIPoint::Make(event.x(), event.y()));
72 const SkISize& screen = capturer_->size_most_recent();
73 pos.setX(std::max(0, std::min(screen.width() - 1, pos.x())));
74 pos.setY(std::max(0, std::min(screen.height() - 1, pos.y())));
75 event_to_inject.set_x(pos.x());
76 event_to_inject.set_y(pos.y());
84 77
85 injected_mouse_positions_.push_back(pos); 78 injected_mouse_positions_.push_back(pos);
86 if (injected_mouse_positions_.size() > kNumRemoteMousePositions) { 79 if (injected_mouse_positions_.size() > kNumRemoteMousePositions) {
87 VLOG(1) << "Injected mouse positions queue full."; 80 VLOG(1) << "Injected mouse positions queue full.";
88 injected_mouse_positions_.pop_front(); 81 injected_mouse_positions_.pop_front();
89 }
90 } 82 }
91 input_stub_->InjectMouseEvent(event_to_inject);
92 } 83 }
84 input_tracker_.InjectMouseEvent(event_to_inject);
93 } 85 }
94 86
95 void ClientSession::OnConnectionOpened( 87 void ClientSession::OnConnectionOpened(
96 protocol::ConnectionToClient* connection) { 88 protocol::ConnectionToClient* connection) {
97 DCHECK(CalledOnValidThread()); 89 DCHECK(CalledOnValidThread());
98 DCHECK_EQ(connection_.get(), connection); 90 DCHECK_EQ(connection_.get(), connection);
99 authenticated_ = true; 91 SetDisableInputs(false);
100 event_handler_->OnSessionAuthenticated(this); 92 event_handler_->OnSessionAuthenticated(this);
101 } 93 }
102 94
103 void ClientSession::OnConnectionClosed( 95 void ClientSession::OnConnectionClosed(
104 protocol::ConnectionToClient* connection) { 96 protocol::ConnectionToClient* connection) {
105 DCHECK(CalledOnValidThread()); 97 DCHECK(CalledOnValidThread());
106 DCHECK_EQ(connection_.get(), connection); 98 DCHECK_EQ(connection_.get(), connection);
107 event_handler_->OnSessionClosed(this); 99 event_handler_->OnSessionClosed(this);
108 } 100 }
109 101
(...skipping 22 matching lines...) Expand all
132 const net::IPEndPoint& local_end_point) { 124 const net::IPEndPoint& local_end_point) {
133 DCHECK(CalledOnValidThread()); 125 DCHECK(CalledOnValidThread());
134 DCHECK_EQ(connection_.get(), connection); 126 DCHECK_EQ(connection_.get(), connection);
135 event_handler_->OnSessionRouteChange(this, channel_name, remote_end_point, 127 event_handler_->OnSessionRouteChange(this, channel_name, remote_end_point,
136 local_end_point); 128 local_end_point);
137 } 129 }
138 130
139 void ClientSession::Disconnect() { 131 void ClientSession::Disconnect() {
140 DCHECK(CalledOnValidThread()); 132 DCHECK(CalledOnValidThread());
141 DCHECK(connection_.get()); 133 DCHECK(connection_.get());
142 authenticated_ = false; 134
143 RestoreEventState(); 135 // SetDisableInputs(true) implicitly restores the input event state.
136 SetDisableInputs(true);
144 137
145 // This triggers OnSessionClosed() and the session may be destroyed 138 // This triggers OnSessionClosed() and the session may be destroyed
146 // as the result, so this call must be the last in this method. 139 // as the result, so this call must be the last in this method.
147 connection_->Disconnect(); 140 connection_->Disconnect();
148 } 141 }
149 142
150 void ClientSession::LocalMouseMoved(const SkIPoint& mouse_pos) { 143 void ClientSession::LocalMouseMoved(const SkIPoint& mouse_pos) {
151 DCHECK(CalledOnValidThread()); 144 DCHECK(CalledOnValidThread());
152 145
153 // If this is a genuine local input event (rather than an echo of a remote 146 // 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 158 // successfully injected (or the local input monitor might have skipped over
166 // some positions), and not because the events were out-of-sequence. These 159 // some positions), and not because the events were out-of-sequence. These
167 // spurious positions should therefore be discarded. 160 // spurious positions should therefore be discarded.
168 injected_mouse_positions_.erase(injected_mouse_positions_.begin(), 161 injected_mouse_positions_.erase(injected_mouse_positions_.begin(),
169 ++found_position); 162 ++found_position);
170 } else { 163 } else {
171 latest_local_input_time_ = base::Time::Now(); 164 latest_local_input_time_ = base::Time::Now();
172 } 165 }
173 } 166 }
174 167
175 bool ClientSession::ShouldIgnoreRemoteMouseInput( 168 void ClientSession::SetDisableInputs(bool disable_inputs) {
176 const protocol::MouseEvent& event) const {
177 DCHECK(CalledOnValidThread()); 169 DCHECK(CalledOnValidThread());
178 170
179 // If the last remote input event was a click or a drag, then it's not safe 171 if (disable_inputs) {
180 // to block remote mouse events. For example, it might result in the host 172 input_filter_.set_input_stub(NULL);
181 // missing the mouse-up event and being stuck with the button pressed. 173 input_tracker_.ReleaseAll();
182 if (remote_mouse_button_state_ != 0) 174 } else {
183 return false; 175 input_filter_.set_input_stub(this);
184 // Otherwise, if the host user has not yet approved the continuation of the 176 }
185 // connection, then ignore remote mouse events. 177 }
186 if (awaiting_continue_approval_) 178
187 return true; 179 bool ClientSession::ShouldIgnoreInput() const {
188 // Otherwise, ignore remote mouse events if the local mouse moved recently. 180 DCHECK(CalledOnValidThread());
181
182 // Ignore remote events if the local mouse moved recently.
189 int64 millis = (base::Time::Now() - latest_local_input_time_) 183 int64 millis = (base::Time::Now() - latest_local_input_time_)
190 .InMilliseconds(); 184 .InMilliseconds();
191 if (millis < kRemoteBlockTimeoutMillis) 185 if (millis < kRemoteBlockTimeoutMillis)
192 return true; 186 return true;
193 return false; 187 return false;
Jamie 2012/03/15 18:38:56 Presumably you could get rid of ShouldIgnoreInput
Wez 2012/03/15 22:25:29 This moved into RemoteInputFilter.
194 } 188 }
195 189
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) {
221 DCHECK(CalledOnValidThread());
222
223 if (event.has_button() && event.has_button_down()) {
224 // Button values are defined in remoting/proto/event.proto.
225 if (event.button() >= 1 && event.button() < MouseEvent::BUTTON_MAX) {
226 uint32 button_change = 1 << (event.button() - 1);
227 if (event.button_down()) {
228 remote_mouse_button_state_ |= button_change;
229 } else {
230 remote_mouse_button_state_ &= ~button_change;
231 }
232 }
233 }
234 }
235
236 void ClientSession::RestoreEventState() {
237 DCHECK(CalledOnValidThread());
238
239 // Undo any currently pressed keys.
240 std::set<int>::iterator i;
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
249 // Undo any currently pressed mouse buttons.
250 for (int i = 1; i < MouseEvent::BUTTON_MAX; i++) {
251 if (remote_mouse_button_state_ & (1 << (i - 1))) {
252 MouseEvent mouse;
253 // TODO(wez): Shouldn't [need to] set position here.
254 mouse.set_x(remote_mouse_pos_.x());
255 mouse.set_y(remote_mouse_pos_.y());
256 mouse.set_button((MouseEvent::MouseButton)i);
257 mouse.set_button_down(false);
258 input_stub_->InjectMouseEvent(mouse);
259 }
260 }
261 remote_mouse_button_state_ = 0;
262 }
263
264 } // namespace remoting 190 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698