Home | History | Annotate | Download | only in host
      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