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