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/remote_input_filter.h" 6 7 #include <algorithm> 8 9 #include "base/logging.h" 10 #include "remoting/proto/event.pb.h" 11 12 namespace { 13 14 // The number of remote mouse events to record for the purpose of eliminating 15 // "echoes" detected by the local input detector. The value should be large 16 // enough to cope with the fact that multiple events might be injected before 17 // any echoes are detected. 18 const unsigned int kNumRemoteMousePositions = 50; 19 20 // The number of milliseconds for which to block remote input when local input 21 // is received. 22 const int64 kRemoteBlockTimeoutMillis = 2000; 23 24 } // namespace 25 26 namespace remoting { 27 28 RemoteInputFilter::RemoteInputFilter(protocol::InputEventTracker* event_tracker) 29 : event_tracker_(event_tracker), 30 expect_local_echo_(true) { 31 } 32 33 RemoteInputFilter::~RemoteInputFilter() { 34 } 35 36 void RemoteInputFilter::LocalMouseMoved(const SkIPoint& mouse_pos) { 37 // If this is a genuine local input event (rather than an echo of a remote 38 // input event that we've just injected), then ignore remote inputs for a 39 // short time. 40 if (expect_local_echo_) { 41 std::list<SkIPoint>::iterator found_position = 42 std::find(injected_mouse_positions_.begin(), 43 injected_mouse_positions_.end(), mouse_pos); 44 if (found_position != injected_mouse_positions_.end()) { 45 // Remove it from the list, and any positions that were added before it, 46 // if any. This is because the local input monitor is assumed to receive 47 // injected mouse position events in the order in which they were injected 48 // (if at all). If the position is found somewhere other than the front 49 // of the queue, this would be because the earlier positions weren't 50 // successfully injected (or the local input monitor might have skipped 51 // over some positions), and not because the events were out-of-sequence. 52 // These spurious positions should therefore be discarded. 53 injected_mouse_positions_.erase(injected_mouse_positions_.begin(), 54 ++found_position); 55 return; 56 } 57 } 58 59 // Release all pressed buttons or keys, disable inputs, and note the time. 60 event_tracker_->ReleaseAll(); 61 latest_local_input_time_ = base::TimeTicks::Now(); 62 } 63 64 void RemoteInputFilter::SetExpectLocalEcho(bool expect_local_echo) { 65 expect_local_echo_ = expect_local_echo; 66 if (!expect_local_echo_) 67 injected_mouse_positions_.clear(); 68 } 69 70 void RemoteInputFilter::InjectKeyEvent(const protocol::KeyEvent& event) { 71 if (ShouldIgnoreInput()) 72 return; 73 event_tracker_->InjectKeyEvent(event); 74 } 75 76 void RemoteInputFilter::InjectMouseEvent(const protocol::MouseEvent& event) { 77 if (ShouldIgnoreInput()) 78 return; 79 if (expect_local_echo_ && event.has_x() && event.has_y()) { 80 injected_mouse_positions_.push_back(SkIPoint::Make(event.x(), event.y())); 81 if (injected_mouse_positions_.size() > kNumRemoteMousePositions) { 82 VLOG(1) << "Injected mouse positions queue full."; 83 injected_mouse_positions_.pop_front(); 84 } 85 } 86 event_tracker_->InjectMouseEvent(event); 87 } 88 89 bool RemoteInputFilter::ShouldIgnoreInput() const { 90 // Ignore remote events if the local mouse moved recently. 91 int64 millis = 92 (base::TimeTicks::Now() - latest_local_input_time_).InMilliseconds(); 93 if (millis < kRemoteBlockTimeoutMillis) 94 return true; 95 return false; 96 } 97 98 } // namespace remoting 99