blob: 388ce13bceb11cc3b932e3c2a91f682a4bc458b7 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/host/remote_input_filter.h"
#include <stdint.h>
#include "base/logging.h"
#include "remoting/proto/event.pb.h"
namespace {
// The number of remote mouse events to record for the purpose of eliminating
// "echoes" detected by the local input detector. The value should be large
// enough to cope with the fact that multiple events might be injected before
// any echoes are detected.
const unsigned int kNumRemoteMousePositions = 50;
// The number of milliseconds for which to block remote input when local input
// is received.
const int64_t kRemoteBlockTimeoutMillis = 2000;
} // namespace
namespace remoting {
RemoteInputFilter::RemoteInputFilter(protocol::InputEventTracker* event_tracker)
: event_tracker_(event_tracker),
expect_local_echo_(true) {
RemoteInputFilter::~RemoteInputFilter() = default;
bool RemoteInputFilter::LocalPointerMoved(const webrtc::DesktopVector& pos,
ui::EventType type) {
// If this is a genuine local input event (rather than an echo of a remote
// input event that we've just injected), then ignore remote inputs for a
// short time.
// Note that no platforms both inject and monitor for touch events, so echo
// suppression is only applied to mouse input.
if (expect_local_echo_ && type == ui::ET_MOUSE_MOVED) {
auto found_position = injected_mouse_positions_.begin();
while (found_position != injected_mouse_positions_.end() &&
!pos.equals(*found_position)) {
if (found_position != injected_mouse_positions_.end()) {
// Remove it from the list, and any positions that were added before it,
// if any. This is because the local input monitor is assumed to receive
// injected mouse position events in the order in which they were injected
// (if at all). If the position is found somewhere other than the front
// of the queue, this would be because the earlier positions weren't
// successfully injected (or the local input monitor might have skipped
// over some positions), and not because the events were out-of-sequence.
// These spurious positions should therefore be discarded.
return false;
// Release all pressed buttons or keys, disable inputs, and note the time.
latest_local_input_time_ = base::TimeTicks::Now();
return true;
void RemoteInputFilter::SetExpectLocalEcho(bool expect_local_echo) {
expect_local_echo_ = expect_local_echo;
if (!expect_local_echo_)
void RemoteInputFilter::InjectKeyEvent(const protocol::KeyEvent& event) {
if (ShouldIgnoreInput())
void RemoteInputFilter::InjectTextEvent(const protocol::TextEvent& event) {
if (ShouldIgnoreInput())
void RemoteInputFilter::InjectMouseEvent(const protocol::MouseEvent& event) {
if (ShouldIgnoreInput())
if (expect_local_echo_ && event.has_x() && event.has_y()) {
webrtc::DesktopVector(event.x(), event.y()));
if (injected_mouse_positions_.size() > kNumRemoteMousePositions) {
VLOG(1) << "Injected mouse positions queue full.";
void RemoteInputFilter::InjectTouchEvent(const protocol::TouchEvent& event) {
if (ShouldIgnoreInput())
bool RemoteInputFilter::ShouldIgnoreInput() const {
// Ignore remote events if the local mouse moved recently.
int64_t millis =
(base::TimeTicks::Now() - latest_local_input_time_).InMilliseconds();
if (millis < kRemoteBlockTimeoutMillis)
return true;
return false;
} // namespace remoting