Commit 397923a7 authored by Jamie Walch's avatar Jamie Walch Committed by Commit Bot

Improve host-side wheel-tick detection algorithm.

Change-Id: I25172eeb7f589d1dea3480d322d4ed73f2213fe4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1633969Reviewed-by: default avatarJamie Walch <jamiewalch@chromium.org>
Reviewed-by: default avatarJoe Downing <joedow@chromium.org>
Auto-Submit: Jamie Walch <jamiewalch@chromium.org>
Commit-Queue: Joe Downing <joedow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#664103}
parent 22bbb760
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "base/optional.h" #include "base/optional.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversion_utils.h" #include "base/strings/utf_string_conversion_utils.h"
#include "base/time/time.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "remoting/base/logging.h" #include "remoting/base/logging.h"
#include "remoting/host/clipboard.h" #include "remoting/host/clipboard.h"
...@@ -44,6 +45,10 @@ using protocol::TextEvent; ...@@ -44,6 +45,10 @@ using protocol::TextEvent;
using protocol::MouseEvent; using protocol::MouseEvent;
using protocol::TouchEvent; using protocol::TouchEvent;
int sign(float num) {
return (num > 0) ? 1 : (num < 0) ? -1 : 0;
}
bool IsDomModifierKey(ui::DomCode dom_code) { bool IsDomModifierKey(ui::DomCode dom_code) {
return dom_code == ui::DomCode::CONTROL_LEFT || return dom_code == ui::DomCode::CONTROL_LEFT ||
dom_code == ui::DomCode::SHIFT_LEFT || dom_code == ui::DomCode::SHIFT_LEFT ||
...@@ -59,6 +64,10 @@ bool IsDomModifierKey(ui::DomCode dom_code) { ...@@ -59,6 +64,10 @@ bool IsDomModifierKey(ui::DomCode dom_code) {
// From third_party/WebKit/Source/web/gtk/WebInputEventFactory.cpp . // From third_party/WebKit/Source/web/gtk/WebInputEventFactory.cpp .
const float kWheelTicksPerPixel = 3.0f / 160.0f; const float kWheelTicksPerPixel = 3.0f / 160.0f;
// When the user is scrolling, generate at least one tick per time period.
const base::TimeDelta kContinuousScrollTimeout =
base::TimeDelta::FromMilliseconds(500);
// A class to generate events on X11. // A class to generate events on X11.
class InputInjectorX11 : public InputInjector { class InputInjectorX11 : public InputInjector {
public: public:
...@@ -138,6 +147,8 @@ class InputInjectorX11 : public InputInjector { ...@@ -138,6 +147,8 @@ class InputInjectorX11 : public InputInjector {
webrtc::DesktopVector latest_mouse_position_; webrtc::DesktopVector latest_mouse_position_;
float wheel_ticks_x_; float wheel_ticks_x_;
float wheel_ticks_y_; float wheel_ticks_y_;
base::Time latest_tick_y_event_;
int latest_tick_y_direction_;
// X11 graphics context. // X11 graphics context.
Display* display_; Display* display_;
...@@ -211,10 +222,10 @@ InputInjectorX11::Core::Core( ...@@ -211,10 +222,10 @@ InputInjectorX11::Core::Core(
latest_mouse_position_(-1, -1), latest_mouse_position_(-1, -1),
wheel_ticks_x_(0.0f), wheel_ticks_x_(0.0f),
wheel_ticks_y_(0.0f), wheel_ticks_y_(0.0f),
latest_tick_y_direction_(0),
display_(XOpenDisplay(nullptr)), display_(XOpenDisplay(nullptr)),
root_window_(BadValue), root_window_(BadValue),
saved_auto_repeat_enabled_(false) { saved_auto_repeat_enabled_(false) {}
}
bool InputInjectorX11::Core::Init() { bool InputInjectorX11::Core::Init() {
CHECK(display_); CHECK(display_);
...@@ -477,11 +488,8 @@ void InputInjectorX11::Core::InjectMouseEvent(const MouseEvent& event) { ...@@ -477,11 +488,8 @@ void InputInjectorX11::Core::InjectMouseEvent(const MouseEvent& event) {
x11::CurrentTime); x11::CurrentTime);
} }
// Older client plugins always send scroll events in pixels, which // remotedesktop.google.com currently sends scroll events in pixels, which
// must be accumulated host-side. Recent client plugins send both // are accumulated host-side.
// pixels and ticks with every scroll event, allowing the host to
// choose the best model on a per-platform basis. Since we can only
// inject ticks on Linux, use them if available.
int ticks_y = 0; int ticks_y = 0;
if (event.has_wheel_ticks_y()) { if (event.has_wheel_ticks_y()) {
ticks_y = event.wheel_ticks_y(); ticks_y = event.wheel_ticks_y();
...@@ -490,7 +498,44 @@ void InputInjectorX11::Core::InjectMouseEvent(const MouseEvent& event) { ...@@ -490,7 +498,44 @@ void InputInjectorX11::Core::InjectMouseEvent(const MouseEvent& event) {
ticks_y = static_cast<int>(wheel_ticks_y_); ticks_y = static_cast<int>(wheel_ticks_y_);
wheel_ticks_y_ -= ticks_y; wheel_ticks_y_ -= ticks_y;
} }
if (ticks_y == 0 && event.has_wheel_delta_y()) {
// For the y-direction only (the common case), try to ensure that a tick is
// injected when the user would expect one, regardless of how many pixels
// the client sends per tick (even if it accelerates wheel events). To do
// this, generate a tick if one has not occurred recently in the current
// scroll direction. The accumulated pixels are not reset in this case.
//
// The effect when a physical mouse is used is as follows:
//
// Client sends slightly too few pixels per tick (e.g. Linux):
// * First scroll in either direction synthesizes a tick.
// * Subsequent scrolls in the same direction are unaffected (their
// accumulated pixel deltas mostly meet the threshold for a regular
// tick; occasionally a tick will be dropped if the user is scrolling
// quickly).
//
// Client sends far too few pixels per tick, but applies acceleration
// (e.g. macOs, ChromeOS):
// * First scroll in either direction synthesizes a tick.
// * Slow scrolling will synthesize a tick a few times per second.
// * Fast scrolling is unaffected (acceleration means that enough pixels
// are accumulated naturally).
//
// Client sends too many pixels per tick (e.g. Windows):
// * Scrolling is unaffected (most scroll events generate one tick; every
// so often one generates two ticks).
//
// The effect when a trackpad is used is that the first tick in either
// direction occurs sooner; subsequent ticks are mostly unaffected.
const int current_tick_y_direction = sign(event.wheel_delta_y());
if ((base::Time::Now() - latest_tick_y_event_ > kContinuousScrollTimeout) ||
latest_tick_y_direction_ != current_tick_y_direction) {
ticks_y = current_tick_y_direction;
}
}
if (ticks_y != 0) { if (ticks_y != 0) {
latest_tick_y_direction_ = sign(ticks_y);
latest_tick_y_event_ = base::Time::Now();
InjectScrollWheelClicks(VerticalScrollWheelToX11ButtonNumber(ticks_y), InjectScrollWheelClicks(VerticalScrollWheelToX11ButtonNumber(ticks_y),
abs(ticks_y)); abs(ticks_y));
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment