blob: d1446b4f3404f3bec2ca06a8e84fea16b212f81a [file] [log] [blame]
// Copyright 2012 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <gtest/gtest.h>
#include "include/gestures.h"
#include "include/mouse_interpreter.h"
#include "include/unittest_util.h"
#include "include/util.h"
namespace gestures {
HardwareProperties make_hwprops_for_mouse(
unsigned has_wheel, unsigned wheel_is_hi_res) {
return {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // touch-specific properties
has_wheel,
wheel_is_hi_res,
0, // is_haptic_pad
};
}
class MouseInterpreterTest : public ::testing::Test {};
TEST(MouseInterpreterTest, SimpleTest) {
HardwareProperties hwprops = make_hwprops_for_mouse(1, 0);
MouseInterpreter mi(nullptr, nullptr);
TestInterpreterWrapper wrapper(&mi, &hwprops);
Gesture* gs;
HardwareState hwstates[] = {
{ 200000, 0, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
{ 210000, 0, 0, 0, nullptr, 9, -7, 0, 0, 0, 0.0 },
{ 220000, 1, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
{ 230000, 0, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
{ 240000, 0, 0, 0, nullptr, 0, 0, -3, -360, 4, 0.0 },
};
mi.output_mouse_wheel_gestures_.val_ = true;
gs = wrapper.SyncInterpret(hwstates[0], nullptr);
EXPECT_EQ(nullptr, gs);
gs = wrapper.SyncInterpret(hwstates[1], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMove, gs->type);
EXPECT_EQ(9, gs->details.move.dx);
EXPECT_EQ(-7, gs->details.move.dy);
EXPECT_EQ(200000, gs->start_time);
EXPECT_EQ(210000, gs->end_time);
gs = wrapper.SyncInterpret(hwstates[2], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeButtonsChange, gs->type);
EXPECT_EQ(1, gs->details.buttons.down);
EXPECT_EQ(0, gs->details.buttons.up);
EXPECT_EQ(210000, gs->start_time);
EXPECT_EQ(220000, gs->end_time);
gs = wrapper.SyncInterpret(hwstates[3], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeButtonsChange, gs->type);
EXPECT_EQ(0, gs->details.buttons.down);
EXPECT_EQ(1, gs->details.buttons.up);
EXPECT_EQ(220000, gs->start_time);
EXPECT_EQ(230000, gs->end_time);
gs = wrapper.SyncInterpret(hwstates[4], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
EXPECT_LT(-1, gs->details.wheel.dx);
EXPECT_GT(1, gs->details.wheel.dy);
EXPECT_EQ(240000, gs->start_time);
EXPECT_EQ(240000, gs->end_time);
}
TEST(MouseInterpreterTest, HighResolutionVerticalScrollTest) {
HardwareProperties hwprops = make_hwprops_for_mouse(1, 1);
MouseInterpreter mi(nullptr, nullptr);
TestInterpreterWrapper wrapper(&mi, &hwprops);
Gesture* gs;
HardwareState hwstates[] = {
{ 200000, 0, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
{ 210000, 0, 0, 0, nullptr, 0, 0, 0, -15, 0, 0.0 },
{ 220000, 0, 0, 0, nullptr, 0, 0, -1, -15, 0, 0.0 },
{ 230000, 0, 0, 0, nullptr, 0, 0, 0,-120, 0, 0.0 },
{ 240000, 0, 0, 0, nullptr, 0, 0, -1, 0, 0, 0.0 },
};
mi.output_mouse_wheel_gestures_.val_ = true;
mi.hi_res_scrolling_.val_ = 1;
gs = wrapper.SyncInterpret(hwstates[0], nullptr);
EXPECT_EQ(nullptr, gs);
gs = wrapper.SyncInterpret(hwstates[1], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
EXPECT_EQ(0, gs->details.wheel.dx);
float offset_of_8th_notch_scroll = gs->details.wheel.dy;
EXPECT_LT(1, offset_of_8th_notch_scroll);
gs = wrapper.SyncInterpret(hwstates[2], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
EXPECT_EQ(0, gs->details.wheel.dx);
// Having a low-res scroll event as well as the high-resolution one shouldn't
// change the output value.
EXPECT_NEAR(offset_of_8th_notch_scroll, gs->details.wheel.dy, 0.1);
gs = wrapper.SyncInterpret(hwstates[3], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
EXPECT_EQ(0, gs->details.wheel.dx);
float offset_of_high_res_scroll = gs->details.wheel.dy;
mi.hi_res_scrolling_.val_ = 0;
gs = wrapper.SyncInterpret(hwstates[4], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
EXPECT_EQ(0, gs->details.wheel.dx);
// A high-res scroll should yield the same offset as a low-res one with
// proper unit conversion.
EXPECT_NEAR(offset_of_high_res_scroll, gs->details.wheel.dy, 0.1);
}
TEST(MouseInterpreterTest, ScrollAccelerationOnAndOffTest) {
HardwareProperties hwprops = make_hwprops_for_mouse(1, 1);
MouseInterpreter mi(nullptr, nullptr);
TestInterpreterWrapper wrapper(&mi, &hwprops);
Gesture* gs;
HardwareState hwstates[] = {
{ 200000, 0, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
{ 210000, 0, 0, 0, nullptr, 0, 0, 5, 0, 0, 0.0 },
{ 220000, 0, 0, 0, nullptr, 0, 0, 5, 0, 0, 0.0 },
{ 230000, 0, 0, 0, nullptr, 0, 0, 10, 0, 0, 0.0 },
{ 240000, 0, 0, 0, nullptr, 0, 0, 10, 0, 0, 0.0 },
};
// Scroll acceleration is on.
mi.scroll_acceleration_.val_ = true;
mi.output_mouse_wheel_gestures_.val_ = true;
mi.hi_res_scrolling_.val_ = false;
gs = wrapper.SyncInterpret(hwstates[0], nullptr);
EXPECT_EQ(nullptr, gs);
gs = wrapper.SyncInterpret(hwstates[1], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
EXPECT_NE(0, gs->details.scroll.dy);
float offset_when_acceleration_on = gs->details.scroll.dy;
gs = wrapper.SyncInterpret(hwstates[2], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
EXPECT_NE(0, gs->details.scroll.dy);
// When acceleration is on, the offset is related to scroll speed. Though
// the wheel displacement are both 5, since the scroll speeds are different,
// the offset are different.
EXPECT_NE(offset_when_acceleration_on, gs->details.scroll.dy);
// Turn scroll acceleration off.
mi.scroll_acceleration_.val_ = false;
gs = wrapper.SyncInterpret(hwstates[3], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
EXPECT_NE(0, gs->details.scroll.dy);
float offset_when_acceleration_off = gs->details.scroll.dy;
gs = wrapper.SyncInterpret(hwstates[4], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
EXPECT_NE(0, gs->details.scroll.dy);
// When acceleration is off, the offset is not related to scroll speed.
// Same wheel displacement yields to same offset.
EXPECT_EQ(offset_when_acceleration_off, gs->details.scroll.dy);
}
TEST(MouseInterpreterTest, JankyScrollTest) {
HardwareProperties hwprops = make_hwprops_for_mouse(1, 0);
MouseInterpreter mi(nullptr, nullptr);
TestInterpreterWrapper wrapper(&mi, &hwprops);
Gesture* gs;
// Because we do not allow time deltas less than 8ms when calculating scroll
// acceleration, the last two scroll events should give the same dy
// (timestamp is in units of seconds)
HardwareState hwstates[] = {
{ 200000, 0, 0, 0, nullptr, 0, 0, -1, 0, 0, 0.0 },
{ 200000.008, 0, 0, 0, nullptr, 0, 0, -1, 0, 0, 0.0 },
{ 200000.0085, 0, 0, 0, nullptr, 0, 0, -1, 0, 0, 0.0 },
};
mi.output_mouse_wheel_gestures_.val_ = true;
gs = wrapper.SyncInterpret(hwstates[0], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
EXPECT_EQ(0, gs->details.wheel.dx);
// Ignore the dy from the first scroll event, as the gesture interpreter
// hardcodes that time delta to 1 second, making it invalid for this test.
gs = wrapper.SyncInterpret(hwstates[1], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
EXPECT_EQ(0, gs->details.wheel.dx);
float scroll_offset = gs->details.wheel.dy;
gs = wrapper.SyncInterpret(hwstates[2], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
EXPECT_EQ(0, gs->details.wheel.dx);
EXPECT_NEAR(scroll_offset, gs->details.wheel.dy, 0.1);
}
TEST(MouseInterpreterTest, WheelTickReportingHighResTest) {
HardwareProperties hwprops = make_hwprops_for_mouse(1, 1);
MouseInterpreter mi(nullptr, nullptr);
TestInterpreterWrapper wrapper(&mi, &hwprops);
Gesture* gs;
HardwareState hwstates[] = {
{ 200000, 0, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
{ 210000, 0, 0, 0, nullptr, 0, 0, 0, -30, 0, 0.0 },
};
mi.output_mouse_wheel_gestures_.val_ = true;
mi.hi_res_scrolling_.val_ = true;
gs = wrapper.SyncInterpret(hwstates[0], nullptr);
EXPECT_EQ(nullptr, gs);
gs = wrapper.SyncInterpret(hwstates[1], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
EXPECT_EQ( 0, gs->details.wheel.tick_120ths_dx);
EXPECT_EQ(30, gs->details.wheel.tick_120ths_dy);
}
TEST(MouseInterpreterTest, WheelTickReportingLowResTest) {
HardwareProperties hwprops = make_hwprops_for_mouse(1, 0);
MouseInterpreter mi(nullptr, nullptr);
TestInterpreterWrapper wrapper(&mi, &hwprops);
Gesture* gs;
HardwareState hwstates[] = {
{ 200000, 0, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
{ 210000, 0, 0, 0, nullptr, 0, 0, 1, 0, 0, 0.0 },
{ 210000, 0, 0, 0, nullptr, 0, 0, 0, 0, 1, 0.0 },
};
mi.output_mouse_wheel_gestures_.val_ = true;
mi.hi_res_scrolling_.val_ = false;
gs = wrapper.SyncInterpret(hwstates[0], nullptr);
EXPECT_EQ(nullptr, gs);
gs = wrapper.SyncInterpret(hwstates[1], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
EXPECT_EQ( 0, gs->details.wheel.tick_120ths_dx);
EXPECT_EQ(-120, gs->details.wheel.tick_120ths_dy);
gs = wrapper.SyncInterpret(hwstates[2], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMouseWheel, gs->type);
EXPECT_EQ(120, gs->details.wheel.tick_120ths_dx);
EXPECT_EQ( 0, gs->details.wheel.tick_120ths_dy);
}
TEST(MouseInterpreterTest, EmulateScrollWheelTest) {
HardwareProperties hwprops = make_hwprops_for_mouse(0, 0);
MouseInterpreter mi(nullptr, nullptr);
TestInterpreterWrapper wrapper(&mi, &hwprops);
Gesture* gs;
HardwareState hwstates[] = {
{ 200000, GESTURES_BUTTON_NONE, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
{ 210000, GESTURES_BUTTON_NONE, 0, 0, nullptr, 9, -7, 0, 0, 0, 0.0 },
{ 220000, GESTURES_BUTTON_LEFT, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
{ 230000, GESTURES_BUTTON_LEFT + GESTURES_BUTTON_RIGHT, 0, 0, nullptr,
0, 0, 0, 0, 0, 0.0 },
{ 240000, GESTURES_BUTTON_LEFT + GESTURES_BUTTON_RIGHT, 0, 0, nullptr,
2, 2, 0, 0, 0, 0.0 },
{ 250000, GESTURES_BUTTON_NONE, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
{ 260000, GESTURES_BUTTON_NONE, 0, 0, nullptr, 9, -7, 0, 0, 0, 0.0 },
{ 270000, GESTURES_BUTTON_MIDDLE, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
{ 280000, GESTURES_BUTTON_MIDDLE, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 },
{ 290000, GESTURES_BUTTON_NONE, 0, 0, nullptr, 0, 0, -3, -360, 4, 0.0 },
};
mi.output_mouse_wheel_gestures_.val_ = true;
gs = wrapper.SyncInterpret(hwstates[0], nullptr);
EXPECT_EQ(nullptr, gs);
gs = wrapper.SyncInterpret(hwstates[1], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMove, gs->type);
EXPECT_EQ(9, gs->details.move.dx);
EXPECT_EQ(-7, gs->details.move.dy);
EXPECT_EQ(200000, gs->start_time);
EXPECT_EQ(210000, gs->end_time);
gs = wrapper.SyncInterpret(hwstates[2], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeButtonsChange, gs->type);
EXPECT_EQ(1, gs->details.buttons.down);
EXPECT_EQ(0, gs->details.buttons.up);
EXPECT_EQ(210000, gs->start_time);
EXPECT_EQ(220000, gs->end_time);
gs = wrapper.SyncInterpret(hwstates[3], nullptr);
ASSERT_EQ(nullptr, gs);
// Temporarily adjust the threshold to force wheel_emulation_active_
auto thresh = mi.scroll_wheel_emulation_thresh_.val_;
mi.scroll_wheel_emulation_thresh_.val_ = 0.1;
EXPECT_FALSE(mi.wheel_emulation_active_);
gs = wrapper.SyncInterpret(hwstates[4], nullptr);
EXPECT_TRUE(mi.wheel_emulation_active_);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeScroll, gs->type);
EXPECT_EQ(200, gs->details.scroll.dx);
EXPECT_EQ(200, gs->details.scroll.dy);
EXPECT_EQ(240000, gs->start_time);
EXPECT_EQ(240000, gs->end_time);
mi.scroll_wheel_emulation_thresh_.val_ = thresh;
gs = wrapper.SyncInterpret(hwstates[5], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeButtonsChange, gs->type);
EXPECT_EQ(0, gs->details.buttons.down);
EXPECT_EQ(5, gs->details.buttons.up);
EXPECT_EQ(240000, gs->start_time);
EXPECT_EQ(250000, gs->end_time);
gs = wrapper.SyncInterpret(hwstates[6], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeMove, gs->type);
EXPECT_EQ(9, gs->details.move.dx);
EXPECT_EQ(-7, gs->details.move.dy);
EXPECT_EQ(250000, gs->start_time);
EXPECT_EQ(260000, gs->end_time);
gs = wrapper.SyncInterpret(hwstates[7], nullptr);
ASSERT_EQ(nullptr, gs);
gs = wrapper.SyncInterpret(hwstates[8], nullptr);
ASSERT_EQ(nullptr, gs);
gs = wrapper.SyncInterpret(hwstates[9], nullptr);
ASSERT_NE(nullptr, gs);
EXPECT_EQ(kGestureTypeButtonsChange, gs->type);
EXPECT_EQ(0, gs->details.buttons.down);
EXPECT_EQ(2, gs->details.buttons.up);
EXPECT_EQ(280000, gs->start_time);
EXPECT_EQ(290000, gs->end_time);
}
} // namespace gestures