Commit 5ae5e597 authored by Nicholas Hollingum's avatar Nicholas Hollingum Committed by Commit Bot

Propagate ordinal motion to Exo clients (if it is available)

On some platforms (including CrOS, as of crrev.com/c/2277694) ordinal
motion will be available as part of mouse motion events.

We use ordinal motion to provide unaccelerated motion in the
zwp_relative_pointer interface. In the event that ordinal motion is not
available, we default to the old behaviour (i.e. using accelerated
motion).

This behaviour is guarded by a flag, as the units it provides on CrOS
are disproportionately small (compared with the standard cursor
acceleration).

Bug: b/161755250
Change-Id: I774db6ef7db7460f1c5674fffdaca65e7fb170fa
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2371088
Commit-Queue: Nic Hollingum <hollingum@google.com>
Reviewed-by: default avatarJun Mukai <mukai@chromium.org>
Cr-Commit-Position: refs/heads/master@{#811137}
parent 83ded747
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/feature_list.h" #include "base/feature_list.h"
#include "base/optional.h"
#include "base/threading/sequenced_task_runner_handle.h" #include "base/threading/sequenced_task_runner_handle.h"
#include "components/exo/input_trace.h" #include "components/exo/input_trace.h"
#include "components/exo/pointer_constraint_delegate.h" #include "components/exo/pointer_constraint_delegate.h"
...@@ -33,7 +34,9 @@ ...@@ -33,7 +34,9 @@
#include "ui/display/manager/managed_display_info.h" #include "ui/display/manager/managed_display_info.h"
#include "ui/display/screen.h" #include "ui/display/screen.h"
#include "ui/events/event.h" #include "ui/events/event.h"
#include "ui/events/event_constants.h"
#include "ui/gfx/geometry/vector2d_conversions.h" #include "ui/gfx/geometry/vector2d_conversions.h"
#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/gfx/transform_util.h" #include "ui/gfx/transform_util.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
...@@ -409,9 +412,23 @@ void Pointer::OnMouseEvent(ui::MouseEvent* event) { ...@@ -409,9 +412,23 @@ void Pointer::OnMouseEvent(ui::MouseEvent* event) {
? SameLocation(location_in_root, location_) ? SameLocation(location_in_root, location_)
: gfx::ToFlooredPoint(location_in_root) == : gfx::ToFlooredPoint(location_in_root) ==
gfx::ToFlooredPoint(location_); gfx::ToFlooredPoint(location_);
// Ordinal motion is sent only on platforms that support it, which is
// indicated by the presence of a flag.
//
// TODO(b/161755250): the ifdef is only necessary because of the feature
// flag. This code should work fine on non-cros.
base::Optional<gfx::Vector2dF> ordinal_motion = base::nullopt;
#if defined(OS_CHROMEOS)
if (event->flags() & ui::EF_UNADJUSTED_MOUSE &&
base::FeatureList::IsEnabled(chromeos::features::kExoOrdinalMotion)) {
ordinal_motion = event->movement();
}
#endif
if (!same_location) { if (!same_location) {
bool needs_frame = bool needs_frame = HandleRelativePointerMotion(
HandleRelativePointerMotion(event->time_stamp(), location_in_root); event->time_stamp(), location_in_root, ordinal_motion);
if (capture_window_) { if (capture_window_) {
if (ShouldMoveToCenter()) if (ShouldMoveToCenter())
MoveCursorToCenterOfActiveDisplay(); MoveCursorToCenterOfActiveDisplay();
...@@ -803,8 +820,10 @@ void Pointer::MoveCursorToCenterOfActiveDisplay() { ...@@ -803,8 +820,10 @@ void Pointer::MoveCursorToCenterOfActiveDisplay() {
root->MoveCursorTo(p); root->MoveCursorTo(p);
} }
bool Pointer::HandleRelativePointerMotion(base::TimeTicks time_stamp, bool Pointer::HandleRelativePointerMotion(
gfx::PointF location_in_root) { base::TimeTicks time_stamp,
gfx::PointF location_in_root,
const base::Optional<gfx::Vector2dF>& ordinal_motion) {
if (!relative_pointer_delegate_) if (!relative_pointer_delegate_)
return false; return false;
...@@ -821,9 +840,10 @@ bool Pointer::HandleRelativePointerMotion(base::TimeTicks time_stamp, ...@@ -821,9 +840,10 @@ bool Pointer::HandleRelativePointerMotion(base::TimeTicks time_stamp,
} }
} }
gfx::PointF delta(location_in_root.x() - location_.x(), gfx::Vector2dF delta = location_in_root - location_;
location_in_root.y() - location_.y()); relative_pointer_delegate_->OnPointerRelativeMotion(
relative_pointer_delegate_->OnPointerRelativeMotion(time_stamp, delta); time_stamp, delta,
ordinal_motion.has_value() ? ordinal_motion.value() : delta);
return true; return true;
} }
......
...@@ -154,9 +154,13 @@ class Pointer : public SurfaceTreeHost, ...@@ -154,9 +154,13 @@ class Pointer : public SurfaceTreeHost,
void MoveCursorToCenterOfActiveDisplay(); void MoveCursorToCenterOfActiveDisplay();
// Process the delta for relative pointer motion. Returns true if relative // Process the delta for relative pointer motion. Returns true if relative
// motion was sent to the delegate, false otherwise. // motion was sent to the delegate, false otherwise. If |ordinal_motion| is
bool HandleRelativePointerMotion(base::TimeTicks time_stamp, // supplied, it will be used for determining physical motion, otherwise
gfx::PointF location_in_target); // physical motion will be the relative delta.
bool HandleRelativePointerMotion(
base::TimeTicks time_stamp,
gfx::PointF location_in_target,
const base::Optional<gfx::Vector2dF>& ordinal_motion);
// The delegate instance that all events are dispatched to. // The delegate instance that all events are dispatched to.
PointerDelegate* const delegate_; PointerDelegate* const delegate_;
......
...@@ -32,8 +32,12 @@ ...@@ -32,8 +32,12 @@
#include "ui/aura/client/focus_client.h" #include "ui/aura/client/focus_client.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h" #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h" #include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h" #include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h" #include "ui/events/test/event_generator.h"
#include "ui/events/types/event_type.h"
#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
...@@ -67,8 +71,10 @@ class MockRelativePointerDelegate : public RelativePointerDelegate { ...@@ -67,8 +71,10 @@ class MockRelativePointerDelegate : public RelativePointerDelegate {
// Overridden from RelativePointerDelegate: // Overridden from RelativePointerDelegate:
MOCK_METHOD1(OnPointerDestroying, void(Pointer*)); MOCK_METHOD1(OnPointerDestroying, void(Pointer*));
MOCK_METHOD2(OnPointerRelativeMotion, MOCK_METHOD3(OnPointerRelativeMotion,
void(base::TimeTicks, const gfx::PointF&)); void(base::TimeTicks,
const gfx::Vector2dF&,
const gfx::Vector2dF&));
}; };
class MockPointerConstraintDelegate : public PointerConstraintDelegate { class MockPointerConstraintDelegate : public PointerConstraintDelegate {
...@@ -987,14 +993,16 @@ TEST_F(PointerTest, OnPointerRelativeMotion) { ...@@ -987,14 +993,16 @@ TEST_F(PointerTest, OnPointerRelativeMotion) {
generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin()); generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
EXPECT_CALL(delegate, OnPointerMotion(testing::_, gfx::PointF(1, 1))); EXPECT_CALL(delegate, OnPointerMotion(testing::_, gfx::PointF(1, 1)));
EXPECT_CALL(relative_delegate, EXPECT_CALL(
OnPointerRelativeMotion(testing::_, gfx::PointF(1, 1))); relative_delegate,
OnPointerRelativeMotion(testing::_, gfx::Vector2dF(1, 1), testing::_));
generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin() + generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin() +
gfx::Vector2d(1, 1)); gfx::Vector2d(1, 1));
EXPECT_CALL(delegate, OnPointerMotion(testing::_, gfx::PointF(2, 2))); EXPECT_CALL(delegate, OnPointerMotion(testing::_, gfx::PointF(2, 2)));
EXPECT_CALL(relative_delegate, EXPECT_CALL(
OnPointerRelativeMotion(testing::_, gfx::PointF(1, 1))); relative_delegate,
OnPointerRelativeMotion(testing::_, gfx::Vector2dF(1, 1), testing::_));
generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin() + generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin() +
gfx::Vector2d(2, 2)); gfx::Vector2d(2, 2));
...@@ -1016,13 +1024,15 @@ TEST_F(PointerTest, OnPointerRelativeMotion) { ...@@ -1016,13 +1024,15 @@ TEST_F(PointerTest, OnPointerRelativeMotion) {
// OnPointerMotion will not be called, because the pointer location is already // OnPointerMotion will not be called, because the pointer location is already
// sent with OnPointerEnter, but we should still receive // sent with OnPointerEnter, but we should still receive
// OnPointerRelativeMotion. // OnPointerRelativeMotion.
EXPECT_CALL(relative_delegate, EXPECT_CALL(
OnPointerRelativeMotion(testing::_, gfx::PointF(3, 3))); relative_delegate,
OnPointerRelativeMotion(testing::_, gfx::Vector2dF(3, 3), testing::_));
generator.MoveMouseTo(sub_surface->window()->GetBoundsInScreen().origin()); generator.MoveMouseTo(sub_surface->window()->GetBoundsInScreen().origin());
EXPECT_CALL(delegate, OnPointerMotion(testing::_, gfx::PointF(1, 1))); EXPECT_CALL(delegate, OnPointerMotion(testing::_, gfx::PointF(1, 1)));
EXPECT_CALL(relative_delegate, EXPECT_CALL(
OnPointerRelativeMotion(testing::_, gfx::PointF(1, 1))); relative_delegate,
OnPointerRelativeMotion(testing::_, gfx::Vector2dF(1, 1), testing::_));
generator.MoveMouseTo(sub_surface->window()->GetBoundsInScreen().origin() + generator.MoveMouseTo(sub_surface->window()->GetBoundsInScreen().origin() +
gfx::Vector2d(1, 1)); gfx::Vector2d(1, 1));
...@@ -1049,13 +1059,15 @@ TEST_F(PointerTest, OnPointerRelativeMotion) { ...@@ -1049,13 +1059,15 @@ TEST_F(PointerTest, OnPointerRelativeMotion) {
// OnPointerMotion will not be called, because the pointer location is already // OnPointerMotion will not be called, because the pointer location is already
// sent with OnPointerEnter, but we should still receive // sent with OnPointerEnter, but we should still receive
// OnPointerRelativeMotion. // OnPointerRelativeMotion.
EXPECT_CALL(relative_delegate, EXPECT_CALL(
OnPointerRelativeMotion(testing::_, gfx::PointF(9, 9))); relative_delegate,
OnPointerRelativeMotion(testing::_, gfx::Vector2dF(9, 9), testing::_));
generator.MoveMouseTo(child_surface->window()->GetBoundsInScreen().origin()); generator.MoveMouseTo(child_surface->window()->GetBoundsInScreen().origin());
EXPECT_CALL(delegate, OnPointerMotion(testing::_, gfx::PointF(10, 10))); EXPECT_CALL(delegate, OnPointerMotion(testing::_, gfx::PointF(10, 10)));
EXPECT_CALL(relative_delegate, EXPECT_CALL(
OnPointerRelativeMotion(testing::_, gfx::PointF(10, 10))); relative_delegate,
OnPointerRelativeMotion(testing::_, gfx::Vector2dF(10, 10), testing::_));
generator.MoveMouseTo(child_surface->window()->GetBoundsInScreen().origin() + generator.MoveMouseTo(child_surface->window()->GetBoundsInScreen().origin() +
gfx::Vector2d(10, 10)); gfx::Vector2d(10, 10));
...@@ -1064,6 +1076,60 @@ TEST_F(PointerTest, OnPointerRelativeMotion) { ...@@ -1064,6 +1076,60 @@ TEST_F(PointerTest, OnPointerRelativeMotion) {
pointer.reset(); pointer.reset();
} }
TEST_F(PointerTest, OrdinalMotionOverridesRelativeMotion) {
auto surface = std::make_unique<Surface>();
auto shell_surface = std::make_unique<ShellSurface>(surface.get());
gfx::Size buffer_size(10, 10);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
surface->Attach(buffer.get());
surface->Commit();
// Set up the pointer and move it to the origin.
testing::NiceMock<MockPointerDelegate> delegate;
Seat seat;
auto pointer = std::make_unique<Pointer>(&delegate, &seat);
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
gfx::Point origin = surface->window()->GetBoundsInScreen().origin();
generator.MoveMouseTo(origin);
// Start sending relative motion events.
testing::StrictMock<MockRelativePointerDelegate> relative_delegate;
pointer->RegisterRelativePointerDelegate(&relative_delegate);
// By default, ordinal and relative are the same.
gfx::Point new_location = origin + gfx::Vector2d(1, 1);
ui::MouseEvent ev1(ui::ET_MOUSE_MOVED, new_location, new_location,
ui::EventTimeForNow(), generator.flags(), 0);
EXPECT_CALL(relative_delegate,
OnPointerRelativeMotion(testing::_, gfx::Vector2dF(1, 1),
gfx::Vector2dF(1, 1)));
generator.Dispatch(&ev1);
// When set, ordinal overrides the relative motion.
//
// TODO(b/161755250): the ifdef is only necessary because of the feature
// flag. This code should work fine on non-cros.
#if defined(OS_CHROMEOS)
new_location = new_location + gfx::Vector2d(1, 1);
ui::MouseEvent ev2(ui::ET_MOUSE_MOVED, new_location, new_location,
ui::EventTimeForNow(), generator.flags(), 0);
ui::MouseEvent::DispatcherApi(&ev2).set_movement(gfx::Vector2dF(99, 99));
EXPECT_CALL(relative_delegate,
OnPointerRelativeMotion(testing::_, gfx::Vector2dF(1, 1),
gfx::Vector2dF(99, 99)));
// This feature is gated behind a flag.
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
chromeos::features::kExoOrdinalMotion);
generator.Dispatch(&ev2);
#endif
pointer->UnregisterRelativePointerDelegate(&relative_delegate);
}
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
TEST_F(PointerTest, ConstrainPointer) { TEST_F(PointerTest, ConstrainPointer) {
auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>(); auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define COMPONENTS_EXO_RELATIVE_POINTER_DELEGATE_H_ #define COMPONENTS_EXO_RELATIVE_POINTER_DELEGATE_H_
#include "base/time/time.h" #include "base/time/time.h"
#include "ui/gfx/geometry/vector2d_f.h"
namespace exo { namespace exo {
class Pointer; class Pointer;
...@@ -17,8 +18,12 @@ class RelativePointerDelegate { ...@@ -17,8 +18,12 @@ class RelativePointerDelegate {
// chance to remove themselves. // chance to remove themselves.
virtual void OnPointerDestroying(Pointer* pointer) = 0; virtual void OnPointerDestroying(Pointer* pointer) = 0;
virtual void OnPointerRelativeMotion(base::TimeTicks time_stamp, // Called to indicate motion. |relative_motion| is given in screen-terms,
const gfx::PointF& relativeMotion) = 0; // whereas |ordinal_motion| comes from hardware and e.g. is not accelerated.
virtual void OnPointerRelativeMotion(
base::TimeTicks time_stamp,
const gfx::Vector2dF& relative_motion,
const gfx::Vector2dF& ordinal_motion) = 0;
protected: protected:
virtual ~RelativePointerDelegate() {} virtual ~RelativePointerDelegate() {}
......
...@@ -35,15 +35,16 @@ class WaylandRelativePointerDelegate : public RelativePointerDelegate { ...@@ -35,15 +35,16 @@ class WaylandRelativePointerDelegate : public RelativePointerDelegate {
} }
void OnPointerDestroying(Pointer* pointer) override { pointer_ = nullptr; } void OnPointerDestroying(Pointer* pointer) override { pointer_ = nullptr; }
void OnPointerRelativeMotion(base::TimeTicks time_stamp, void OnPointerRelativeMotion(base::TimeTicks time_stamp,
const gfx::PointF& relativeMotion) override { const gfx::Vector2dF& relative_motion,
const gfx::Vector2dF& ordinal_motion) override {
zwp_relative_pointer_v1_send_relative_motion( zwp_relative_pointer_v1_send_relative_motion(
resource_, // resource resource_, // resource
0, // utime_hi 0, // utime_hi
TimeTicksToMilliseconds(time_stamp), // utime_lo TimeTicksToMilliseconds(time_stamp), // utime_lo
wl_fixed_from_double(relativeMotion.x()), // dx wl_fixed_from_double(relative_motion.x()), // dx
wl_fixed_from_double(relativeMotion.y()), // dy wl_fixed_from_double(relative_motion.y()), // dy
wl_fixed_from_double(relativeMotion.x()), // dx_unaccel wl_fixed_from_double(ordinal_motion.x()), // dx_unaccel
wl_fixed_from_double(relativeMotion.y())); // dy_unaccel wl_fixed_from_double(ordinal_motion.y())); // dy_unaccel
} }
private: private:
......
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