blob: 7c01aa72b254be8d44e4f3af25afe05c0dc78402 [file] [log] [blame]
// Copyright 2011 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <deque>
#include <math.h>
#include <utility>
#include <vector>
#include <gtest/gtest.h>
#include "include/accel_filter_interpreter.h"
#include "include/gestures.h"
#include "include/macros.h"
#include "include/unittest_util.h"
#include "include/util.h"
using std::deque;
using std::make_pair;
using std::pair;
using std::vector;
namespace gestures {
class AccelFilterInterpreterTest : public ::testing::Test {};
class AccelFilterInterpreterTestInterpreter : public Interpreter {
public:
AccelFilterInterpreterTestInterpreter() : Interpreter(NULL, NULL, false) {}
virtual void SyncInterpret(HardwareState* hwstate, stime_t* timeout) {
if (return_values_.empty())
return;
return_value_ = return_values_.front();
return_values_.pop_front();
if (return_value_.type == kGestureTypeNull)
return;
ProduceGesture(return_value_);
}
virtual void HandleTimer(stime_t now, stime_t* timeout) {
return SyncInterpret(NULL, NULL);
}
Gesture return_value_;
deque<Gesture> return_values_;
};
TEST(AccelFilterInterpreterTest, SimpleTest) {
AccelFilterInterpreterTestInterpreter* base_interpreter =
new AccelFilterInterpreterTestInterpreter;
AccelFilterInterpreter accel_interpreter(NULL, base_interpreter, NULL);
TestInterpreterWrapper interpreter(&accel_interpreter);
accel_interpreter.scroll_x_out_scale_.val_ =
accel_interpreter.scroll_y_out_scale_.val_ = 1.0;
float last_move_dx = 0.0;
float last_move_dy = 0.0;
float last_scroll_dx = 0.0;
float last_scroll_dy = 0.0;
float last_fling_vx = 0.0;
float last_fling_vy = 0.0;
for (int i = 1; i <= 5; ++i) {
accel_interpreter.pointer_sensitivity_.val_ = i;
accel_interpreter.scroll_sensitivity_.val_ = i;
base_interpreter->return_values_.push_back(Gesture()); // Null type
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
1, // start time
1.001, // end time
-4, // dx
2.8)); // dy
base_interpreter->return_values_.push_back(Gesture(kGestureScroll,
2, // start time
2.1, // end time
4.1, // dx
-10.3)); // dy
base_interpreter->return_values_.push_back(Gesture(kGestureFling,
3, // start time
3.1, // end time
100.1, // vx
-10.3, // vy
0)); // state
Gesture* out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_EQ(reinterpret_cast<Gesture*>(NULL), out);
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeMove, out->type);
if (i == 1) {
// Expect no acceleration
EXPECT_FLOAT_EQ(-4.0, out->details.move.dx) << "i = " << i;
EXPECT_FLOAT_EQ(2.8, out->details.move.dy);
} else {
// Expect increasing acceleration
EXPECT_GT(fabsf(out->details.move.dx), fabsf(last_move_dx));
EXPECT_GT(fabsf(out->details.move.dy), fabsf(last_move_dy));
}
last_move_dx = out->details.move.dx;
last_move_dy = out->details.move.dy;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeScroll, out->type);
if (i == 1) {
// Expect no acceleration
EXPECT_FLOAT_EQ(4.1, out->details.scroll.dx);
EXPECT_FLOAT_EQ(-10.3, out->details.scroll.dy);
} else if (i > 2) {
// Expect increasing acceleration
EXPECT_GT(fabsf(out->details.scroll.dx), fabsf(last_scroll_dx));
EXPECT_GT(fabsf(out->details.scroll.dy), fabsf(last_scroll_dy));
}
last_scroll_dx = out->details.scroll.dx;
last_scroll_dy = out->details.scroll.dy;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeFling, out->type);
if (i == 1) {
// Expect no acceleration
EXPECT_FLOAT_EQ(100.1, out->details.fling.vx);
EXPECT_FLOAT_EQ(-10.3, out->details.fling.vy);
} else if (i > 2) {
// Expect increasing acceleration
EXPECT_GT(fabsf(out->details.fling.vx), fabsf(last_fling_vx));
EXPECT_GT(fabsf(out->details.fling.vy), fabsf(last_fling_vy));
}
last_fling_vx = out->details.fling.vx;
last_fling_vy = out->details.fling.vy;
}
}
TEST(AccelFilterInterpreterTest, TinyMoveTest) {
AccelFilterInterpreterTestInterpreter* base_interpreter =
new AccelFilterInterpreterTestInterpreter;
AccelFilterInterpreter accel_interpreter(NULL, base_interpreter, NULL);
TestInterpreterWrapper interpreter(&accel_interpreter);
accel_interpreter.scroll_x_out_scale_.val_ =
accel_interpreter.scroll_y_out_scale_.val_ = 1.0;
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
1, // start time
2, // end time
4, // dx
0)); // dy
base_interpreter->return_values_.push_back(Gesture(kGestureScroll,
2, // start time
3, // end time
4, // dx
0)); // dy
base_interpreter->return_values_.push_back(Gesture(kGestureScroll,
2, // start time
3, // end time
4, // dx
0)); // dy
Gesture* out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeMove, out->type);
EXPECT_GT(fabsf(out->details.move.dx), 2);
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeScroll, out->type);
EXPECT_GT(fabsf(out->details.scroll.dx), 2);
float orig_x_scroll = out->details.scroll.dx;
accel_interpreter.scroll_x_out_scale_.val_ = 2.0;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeScroll, out->type);
EXPECT_FLOAT_EQ(orig_x_scroll * accel_interpreter.scroll_x_out_scale_.val_,
out->details.scroll.dx);
}
TEST(AccelFilterInterpreterTest, TimingTest) {
AccelFilterInterpreterTestInterpreter* base_interpreter =
new AccelFilterInterpreterTestInterpreter;
AccelFilterInterpreter accel_interpreter(NULL, base_interpreter, NULL);
TestInterpreterWrapper interpreter(&accel_interpreter);
accel_interpreter.scroll_x_out_scale_.val_ =
accel_interpreter.scroll_y_out_scale_.val_ = 1.0;
accel_interpreter.min_reasonable_dt_.val_ = 0.0;
accel_interpreter.max_reasonable_dt_.val_ = INFINITY;
accel_interpreter.pointer_sensitivity_.val_ = 3; // standard sensitivity
accel_interpreter.scroll_sensitivity_.val_ = 3; // standard sensitivity
float last_dx = 0.0;
float last_dy = 0.0;
base_interpreter->return_values_.push_back(Gesture()); // Null type
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
1, // start time
1.001, // end time
-4, // dx
2.8)); // dy
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
2, // start time
3, // end time
-4, // dx
2.8)); // dy
base_interpreter->return_values_.push_back(Gesture(kGestureScroll,
3, // start time
3.001, // end time
4.1, // dx
-10.3)); // dy
base_interpreter->return_values_.push_back(Gesture(kGestureScroll,
4, // start time
5, // end time
4.1, // dx
-10.3)); // dy
Gesture* out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_EQ(reinterpret_cast<Gesture*>(NULL), out);
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeMove, out->type);
// Expect less accel for same movement over more time
last_dx = out->details.move.dx;
last_dy = out->details.move.dy;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeMove, out->type);
EXPECT_GT(fabsf(last_dx), fabsf(out->details.move.dx));
EXPECT_GT(fabsf(last_dy), fabsf(out->details.move.dy));
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeScroll, out->type);
// Expect less accel for same movement over more time
last_dx = out->details.scroll.dx;
last_dy = out->details.scroll.dy;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeScroll, out->type);
EXPECT_GT(fabsf(last_dx), fabsf(out->details.scroll.dx));
EXPECT_GT(fabsf(last_dy), fabsf(out->details.scroll.dy));
}
TEST(AccelFilterInterpreterTest, NotSmoothingTest) {
AccelFilterInterpreterTestInterpreter* base_interpreter =
new AccelFilterInterpreterTestInterpreter;
AccelFilterInterpreter accel_interpreter(NULL, base_interpreter, NULL);
TestInterpreterWrapper interpreter(&accel_interpreter);
accel_interpreter.scroll_x_out_scale_.val_ =
accel_interpreter.scroll_y_out_scale_.val_ = 1.0;
accel_interpreter.min_reasonable_dt_.val_ = 0.0;
accel_interpreter.max_reasonable_dt_.val_ = INFINITY;
accel_interpreter.pointer_sensitivity_.val_ = 3; // standard sensitivity
accel_interpreter.scroll_sensitivity_.val_ = 3; // standard sensitivity
accel_interpreter.smooth_accel_.val_ = false;
float last_dx = 0.0;
float last_dy = 0.0;
base_interpreter->return_values_.push_back(Gesture()); // Null type
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
/*start=*/1,
/*end=*/1.001,
/*dx=*/-4,
/*dy=*/2.8));
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
/*start=*/2,
/*end=*/3,
/*dx=*/-4,
/*dy=*/2.8));
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
/*start=*/3,
/*end=*/3.001,
/*dx=*/4.1,
/*dy=*/-10.3));
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
/*start=*/4,
/*end=*/5,
/*dx=*/4.1,
/*dy=*/-10.3));
Gesture* out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_EQ(reinterpret_cast<Gesture*>(NULL), out);
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeMove, out->type);
// Expect less accel for same movement over more time
last_dx = out->details.move.dx;
last_dy = out->details.move.dy;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeMove, out->type);
EXPECT_GT(fabsf(last_dx), fabsf(out->details.move.dx));
EXPECT_GT(fabsf(last_dy), fabsf(out->details.move.dy));
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeMove, out->type);
// Expect less accel for same movement over more time
last_dx = out->details.move.dx;
last_dy = out->details.move.dy;
ASSERT_GT(fabsf(last_dx), 32.5780);
ASSERT_LT(fabsf(last_dx), 32.5782);
ASSERT_GT(fabsf(last_dy), 81.8424);
ASSERT_LT(fabsf(last_dy), 81.8426);
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeMove, out->type);
EXPECT_GT(fabsf(last_dx), fabsf(out->details.move.dx));
EXPECT_GT(fabsf(last_dy), fabsf(out->details.move.dy));
}
TEST(AccelFilterInterpreterTest, SmoothingTest) {
AccelFilterInterpreterTestInterpreter* base_interpreter =
new AccelFilterInterpreterTestInterpreter;
AccelFilterInterpreter accel_interpreter(NULL, base_interpreter, NULL);
TestInterpreterWrapper interpreter(&accel_interpreter);
accel_interpreter.scroll_x_out_scale_.val_ =
accel_interpreter.scroll_y_out_scale_.val_ = 1.0;
accel_interpreter.min_reasonable_dt_.val_ = 0.0;
accel_interpreter.max_reasonable_dt_.val_ = INFINITY;
accel_interpreter.pointer_sensitivity_.val_ = 3; // standard sensitivity
accel_interpreter.scroll_sensitivity_.val_ = 3; // standard sensitivity
accel_interpreter.smooth_accel_.val_ = true;
float last_dx = 0.0;
float last_dy = 0.0;
base_interpreter->return_values_.push_back(Gesture()); // Null type
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
/*start=*/1,
/*end=*/1.001,
/*dx=*/-4,
/*dy=*/2.8));
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
/*start=*/2,
/*end=*/3,
/*dx=*/-4,
/*dy=*/2.8));
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
/*start=*/3,
/*end=*/3.001,
/*dx=*/4.1,
/*dy=*/-10.3));
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
/*start=*/4,
/*end=*/5,
/*dx=*/4.1,
/*dy=*/-10.3));
Gesture* out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_EQ(reinterpret_cast<Gesture*>(NULL), out);
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeMove, out->type);
// Expect less accel for same movement over more time
last_dx = out->details.move.dx;
last_dy = out->details.move.dy;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeMove, out->type);
EXPECT_GT(fabsf(last_dx), fabsf(out->details.move.dx));
EXPECT_GT(fabsf(last_dy), fabsf(out->details.move.dy));
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeMove, out->type);
// Expect less accel for same movement over more time
last_dx = out->details.move.dx;
last_dy = out->details.move.dy;
ASSERT_GT(fabsf(last_dx), 32.3563);
ASSERT_LT(fabsf(last_dx), 32.3565);
ASSERT_GT(fabsf(last_dy), 81.2855);
ASSERT_LT(fabsf(last_dy), 81.2857);
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
EXPECT_EQ(kGestureTypeMove, out->type);
EXPECT_GT(fabsf(last_dx), fabsf(out->details.move.dx));
EXPECT_GT(fabsf(last_dy), fabsf(out->details.move.dy));
}
TEST(AccelFilterInterpreterTest, CurveSegmentInitializerTest) {
AccelFilterInterpreter::CurveSegment temp1 =
AccelFilterInterpreter::CurveSegment(INFINITY, 0.0, 2.0, -2.0);
AccelFilterInterpreter::CurveSegment temp2 =
AccelFilterInterpreter::CurveSegment(temp1);
ASSERT_EQ(temp1.x_, temp2.x_);
temp1 = AccelFilterInterpreter::CurveSegment(0.0, 0.0, 0.0, 0.0);
ASSERT_NE(temp1.x_, temp2.x_);
}
TEST(AccelFilterInterpreterTest, CustomAccelTest) {
AccelFilterInterpreterTestInterpreter* base_interpreter =
new AccelFilterInterpreterTestInterpreter;
AccelFilterInterpreter accel_interpreter(NULL, base_interpreter, NULL);
TestInterpreterWrapper interpreter(&accel_interpreter);
accel_interpreter.scroll_x_out_scale_.val_ =
accel_interpreter.scroll_y_out_scale_.val_ = 1.0;
accel_interpreter.min_reasonable_dt_.val_ = 0.0;
accel_interpreter.max_reasonable_dt_.val_ = INFINITY;
// custom sensitivity
accel_interpreter.use_custom_tp_point_curve_.val_ = 1;
accel_interpreter.use_custom_tp_scroll_curve_.val_ = 1;
accel_interpreter.tp_custom_point_[0] =
AccelFilterInterpreter::CurveSegment(2.0, 0.0, 0.5, 0.0);
accel_interpreter.tp_custom_point_[1] =
AccelFilterInterpreter::CurveSegment(3.0, 0.0, 2.0, -3.0);
accel_interpreter.tp_custom_point_[2] =
AccelFilterInterpreter::CurveSegment(INFINITY, 0.0, 0.0, 3.0);
accel_interpreter.tp_custom_scroll_[0] =
AccelFilterInterpreter::CurveSegment(0.5, 0.0, 2.0, 0.0);
accel_interpreter.tp_custom_scroll_[1] =
AccelFilterInterpreter::CurveSegment(1.0, 0.0, 2.0, 0.0);
accel_interpreter.tp_custom_scroll_[2] =
AccelFilterInterpreter::CurveSegment(2.0, 0.0, 0.0, 2.0);
accel_interpreter.tp_custom_scroll_[3] =
AccelFilterInterpreter::CurveSegment(INFINITY, 0.0, 2.0, -2.0);
float move_in[] = { 1.0, 2.5, 3.5, 5.0 };
float move_out[] = { 0.5, 2.0, 3.0, 3.0 };
for (size_t i = 0; i < arraysize(move_in); ++i) {
float dist = move_in[i];
float expected = move_out[i];
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
1, // start time
2, // end time
dist, // dx
0)); // dy
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
1, // start time
2, // end time
0, // dx
dist)); // dy
// half time, half distance = same speed
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
1, // start time
1.5, // end time
dist / 2.0, // dx
0)); // dy
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
1, // start time
1.5, // end time
0, // dx
dist / 2.0)); // dy
Gesture* out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out) << "i=" << i;
EXPECT_EQ(kGestureTypeMove, out->type) << "i=" << i;
EXPECT_FLOAT_EQ(expected, out->details.move.dx) << "i=" << i;
EXPECT_FLOAT_EQ(0, out->details.move.dy) << "i=" << i;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out) << "i=" << i;
EXPECT_EQ(kGestureTypeMove, out->type) << "i=" << i;
EXPECT_FLOAT_EQ(0, out->details.move.dx) << "i=" << i;
EXPECT_FLOAT_EQ(expected, out->details.move.dy) << "i=" << i;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out) << "i=" << i;
EXPECT_EQ(kGestureTypeMove, out->type) << "i=" << i;
EXPECT_FLOAT_EQ(expected / 2.0, out->details.move.dx) << "i=" << i;
EXPECT_FLOAT_EQ(0, out->details.move.dy) << "i=" << i;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out) << "i=" << i;
EXPECT_EQ(kGestureTypeMove, out->type) << "i=" << i;
EXPECT_FLOAT_EQ(0, out->details.move.dx) << "i=" << i;
EXPECT_FLOAT_EQ(expected / 2.0, out->details.move.dy) << "i=" << i;
}
float swipe_in[] = { 1.0, 2.5, 3.5, 5.0 };
float swipe_out[] = { 0.5, 2.0, 3.0, 3.0 };
for (size_t i = 0; i < arraysize(swipe_in); ++i) {
float dist = swipe_in[i];
float expected = swipe_out[i];
base_interpreter->return_values_.push_back(Gesture(kGestureSwipe,
1, // start time
2, // end time
dist, // dx
0)); // dy
base_interpreter->return_values_.push_back(Gesture(kGestureSwipe,
1, // start time
2, // end time
0, // dx
dist)); // dy
// half time, half distance = same speed
base_interpreter->return_values_.push_back(Gesture(kGestureSwipe,
1, // start time
1.5, // end time
dist / 2.0, // dx
0)); // dy
base_interpreter->return_values_.push_back(Gesture(kGestureSwipe,
1, // start time
1.5, // end time
0, // dx
dist / 2.0)); // dy
Gesture* out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out) << "i=" << i;
EXPECT_EQ(kGestureTypeSwipe, out->type) << "i=" << i;
EXPECT_FLOAT_EQ(expected, out->details.move.dx) << "i=" << i;
EXPECT_FLOAT_EQ(0, out->details.move.dy) << "i=" << i;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out) << "i=" << i;
EXPECT_EQ(kGestureTypeSwipe, out->type) << "i=" << i;
EXPECT_FLOAT_EQ(0, out->details.move.dx) << "i=" << i;
EXPECT_FLOAT_EQ(expected, out->details.move.dy) << "i=" << i;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out) << "i=" << i;
EXPECT_EQ(kGestureTypeSwipe, out->type) << "i=" << i;
EXPECT_FLOAT_EQ(expected / 2.0, out->details.move.dx) << "i=" << i;
EXPECT_FLOAT_EQ(0, out->details.move.dy) << "i=" << i;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out) << "i=" << i;
EXPECT_EQ(kGestureTypeSwipe, out->type) << "i=" << i;
EXPECT_FLOAT_EQ(0, out->details.move.dx) << "i=" << i;
EXPECT_FLOAT_EQ(expected / 2.0, out->details.move.dy) << "i=" << i;
}
float swipe4_in[] = { 1.0, 2.5, 3.5, 5.0 };
float swipe4_out[] = { 0.5, 2.0, 3.0, 3.0 };
for (size_t i = 0; i < arraysize(swipe4_in); ++i) {
float dist = swipe4_in[i];
float expected = swipe4_out[i];
base_interpreter->return_values_.push_back(Gesture(kGestureFourFingerSwipe,
1, // start time
2, // end time
dist, // dx
0)); // dy
base_interpreter->return_values_.push_back(Gesture(kGestureFourFingerSwipe,
1, // start time
2, // end time
0, // dx
dist)); // dy
// half time, half distance = same speed
base_interpreter->return_values_.push_back(Gesture(kGestureFourFingerSwipe,
1, // start time
1.5, // end time
dist / 2.0, // dx
0)); // dy
base_interpreter->return_values_.push_back(Gesture(kGestureFourFingerSwipe,
1, // start time
1.5, // end time
0, // dx
dist / 2.0)); // dy
Gesture* out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out) << "i=" << i;
EXPECT_EQ(kGestureTypeFourFingerSwipe, out->type) << "i=" << i;
EXPECT_FLOAT_EQ(expected, out->details.move.dx) << "i=" << i;
EXPECT_FLOAT_EQ(0, out->details.move.dy) << "i=" << i;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out) << "i=" << i;
EXPECT_EQ(kGestureTypeFourFingerSwipe, out->type) << "i=" << i;
EXPECT_FLOAT_EQ(0, out->details.move.dx) << "i=" << i;
EXPECT_FLOAT_EQ(expected, out->details.move.dy) << "i=" << i;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out) << "i=" << i;
EXPECT_EQ(kGestureTypeFourFingerSwipe, out->type) << "i=" << i;
EXPECT_FLOAT_EQ(expected / 2.0, out->details.move.dx) << "i=" << i;
EXPECT_FLOAT_EQ(0, out->details.move.dy) << "i=" << i;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out) << "i=" << i;
EXPECT_EQ(kGestureTypeFourFingerSwipe, out->type) << "i=" << i;
EXPECT_FLOAT_EQ(0, out->details.move.dx) << "i=" << i;
EXPECT_FLOAT_EQ(expected / 2.0, out->details.move.dy) << "i=" << i;
}
float scroll_in[] = { 0.25, 0.5, 0.75, 1.5, 2.5, 3.0, 3.5 };
float scroll_out[] = { 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0 };
for (size_t i = 0; i < arraysize(scroll_in); ++i) {
float dist = scroll_in[i];
float expected = scroll_out[i];
base_interpreter->return_values_.push_back(Gesture(kGestureScroll,
1, // start time
2, // end time
dist, // dx
0)); // dy
base_interpreter->return_values_.push_back(Gesture(kGestureScroll,
1, // start time
2, // end time
0, // dx
dist)); // dy
// half time, half distance = same speed
base_interpreter->return_values_.push_back(Gesture(kGestureScroll,
1, // start time
1.5, // end time
dist / 2.0, // dx
0)); // dy
base_interpreter->return_values_.push_back(Gesture(kGestureScroll,
1, // start time
1.5, // end time
0, // dx
dist / 2.0)); // dy
Gesture* out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out) << "i=" << i;
EXPECT_EQ(kGestureTypeScroll, out->type) << "i=" << i;
EXPECT_FLOAT_EQ(expected, out->details.scroll.dx) << "i=" << i;
EXPECT_FLOAT_EQ(0, out->details.scroll.dy) << "i=" << i;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out) << "i=" << i;
EXPECT_EQ(kGestureTypeScroll, out->type) << "i=" << i;
EXPECT_FLOAT_EQ(0, out->details.scroll.dx) << "i=" << i;
EXPECT_FLOAT_EQ(expected, out->details.scroll.dy) << "i=" << i;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out) << "i=" << i;
EXPECT_EQ(kGestureTypeScroll, out->type) << "i=" << i;
EXPECT_FLOAT_EQ(expected / 2.0, out->details.scroll.dx) << "i=" << i;
EXPECT_FLOAT_EQ(0, out->details.scroll.dy) << "i=" << i;
out = interpreter.SyncInterpret(NULL, NULL);
ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out) << "i=" << i;
EXPECT_EQ(kGestureTypeScroll, out->type) << "i=" << i;
EXPECT_FLOAT_EQ(0, out->details.scroll.dx) << "i=" << i;
EXPECT_FLOAT_EQ(expected / 2.0, out->details.scroll.dy) << "i=" << i;
}
}
TEST(AccelFilterInterpreterTest, UnacceleratedMouseTest) {
AccelFilterInterpreterTestInterpreter* base_interpreter =
new AccelFilterInterpreterTestInterpreter;
AccelFilterInterpreter accel_interpreter(NULL, base_interpreter, NULL);
TestInterpreterWrapper interpreter(&accel_interpreter);
accel_interpreter.use_mouse_point_curves_.val_ = true;
accel_interpreter.pointer_acceleration_.val_ = false;
const float dx = 3;
const float dy = 5;
const float unaccel_slopes[] = { 2.0, 4.0, 8.0, 16.0, 24.0 };
for (int i = 1; i <= 5; ++i) {
accel_interpreter.pointer_sensitivity_.val_ = i;
base_interpreter->return_values_.push_back(Gesture()); // Null type
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
1, // start time
1.001, // end time
dx, // dx
dy)); // dy
Gesture* out = interpreter.SyncInterpret(nullptr, nullptr);
ASSERT_EQ(nullptr, out);
out = interpreter.SyncInterpret(nullptr, nullptr);
ASSERT_NE(nullptr, out);
EXPECT_EQ(kGestureTypeMove, out->type);
// Output should be scaled by a constant value.
EXPECT_FLOAT_EQ(dx * unaccel_slopes[i - 1], out->details.move.dx);
EXPECT_FLOAT_EQ(dy * unaccel_slopes[i - 1], out->details.move.dy);
}
}
TEST(AccelFilterInterpreterTest, UnacceleratedTouchpadTest) {
AccelFilterInterpreterTestInterpreter* base_interpreter =
new AccelFilterInterpreterTestInterpreter;
AccelFilterInterpreter accel_interpreter(NULL, base_interpreter, NULL);
TestInterpreterWrapper interpreter(&accel_interpreter);
accel_interpreter.use_mouse_point_curves_.val_ = false;
accel_interpreter.pointer_acceleration_.val_ = false;
const float dx = 3;
const float dy = 5;
const float unaccel_slopes[] = { 1.0, 2.0, 3.0, 4.0, 5.0 };
for (int i = 1; i <= 5; ++i) {
accel_interpreter.pointer_sensitivity_.val_ = i;
base_interpreter->return_values_.push_back(Gesture()); // Null type
base_interpreter->return_values_.push_back(Gesture(kGestureMove,
1, // start time
1.001, // end time
dx, // dx
dy)); // dy
Gesture* out = interpreter.SyncInterpret(nullptr, nullptr);
ASSERT_EQ(nullptr, out);
out = interpreter.SyncInterpret(nullptr, nullptr);
ASSERT_NE(nullptr, out);
EXPECT_EQ(kGestureTypeMove, out->type);
// Output should be scaled by a constant value.
EXPECT_FLOAT_EQ(dx * unaccel_slopes[i - 1], out->details.move.dx);
EXPECT_FLOAT_EQ(dy * unaccel_slopes[i - 1], out->details.move.dy);
}
}
TEST(AccelFilterInterpreterTest, TouchpadPointAccelCurveTest) {
AccelFilterInterpreterTestInterpreter* base_interpreter =
new AccelFilterInterpreterTestInterpreter;
AccelFilterInterpreter accel_interpreter(NULL, base_interpreter, NULL);
TestInterpreterWrapper interpreter(&accel_interpreter);
size_t num_segs = AccelFilterInterpreter::kMaxCurveSegs;
AccelFilterInterpreter::CurveSegment* segs;
// x = input speed of movement (mm/s, always >= 0), y = output speed (mm/s)
// Sensitivity: 1 No Acceleration
segs = accel_interpreter.point_curves_[0];
float ratio = accel_interpreter.RatioFromAccelCurve(segs, num_segs, 0);
ASSERT_EQ(ratio, 0.0);
ASSERT_EQ(segs[0].x_, INFINITY);
ASSERT_EQ(segs[0].sqr_, 0.0);
ASSERT_EQ(segs[0].mul_, 1.0);
ASSERT_EQ(segs[0].int_, 0.0);
for (int x = 1; x < 1000; ++x) {
ratio = accel_interpreter.RatioFromAccelCurve(segs, num_segs, x);
float y = ratio * float(x);
ASSERT_EQ(x, y);
}
// Sensitivity 2-5
const float point_divisors[] = {0.0, // unused
60.0, 37.5, 30.0, 25.0 }; // used
for (int sensitivity = 2; sensitivity <= 5; ++sensitivity) {
segs = accel_interpreter.point_curves_[sensitivity - 1];
const float divisor = point_divisors[sensitivity - 1];
ratio = accel_interpreter.RatioFromAccelCurve(segs, num_segs, 0.0);
ASSERT_EQ(ratio, 0.0);
// y = 32x/divisor (x < 32)
const float linear_until_x = 32.0;
ASSERT_EQ(segs[0].x_, linear_until_x);
ASSERT_EQ(segs[0].sqr_, 0.0);
ASSERT_EQ(segs[0].mul_, linear_until_x / divisor);
ASSERT_EQ(segs[0].int_, 0.0);
for (int i = 1; i < 32; ++i) {
float x = float(i);
ratio = accel_interpreter.RatioFromAccelCurve(segs, num_segs, x);
float y = x * ratio;
float expected = (linear_until_x * x) / divisor;
ASSERT_LE(expected - 0.001, y);
ASSERT_GE(expected + 0.001, y);
}
// y = x^2/divisor (x < 150)
const float x_border = 150.0;
ASSERT_EQ(segs[1].x_, x_border);
ASSERT_EQ(segs[1].sqr_, 1 / divisor);
ASSERT_EQ(segs[1].mul_, 0.0);
ASSERT_EQ(segs[1].int_, 0.0);
for (int i = 33; i < 150; ++i) {
float x = float(i);
ratio = accel_interpreter.RatioFromAccelCurve(segs, num_segs, x);
float y = x * ratio;
float expected = (x * x) / divisor;
ASSERT_LE(expected - 0.001, y);
ASSERT_GE(expected + 0.001, y);
}
// linear with same slope after
const float slope = (x_border * 2) / divisor;
const float y_at_border = (x_border * x_border) / divisor;
const float intercept = y_at_border - (slope * x_border);
ASSERT_EQ(segs[2].x_, INFINITY);
ASSERT_EQ(segs[2].sqr_, 0.0);
ASSERT_EQ(segs[2].mul_, slope);
ASSERT_EQ(segs[2].int_, intercept);
for (int i = 150; i < 1000; ++i) {
float x = float(i);
// return seg.mul_ + seg.int_ / speed;;
ratio = accel_interpreter.RatioFromAccelCurve(segs, num_segs, x);
float y = x * ratio;
float expected = x * (slope + (intercept / x));
ASSERT_LE(expected - 0.001, y);
ASSERT_GE(expected + 0.001, y);
}
}
}
TEST(AccelFilterInterpreterTest, TouchpadScrollAccelCurveTest) {
AccelFilterInterpreterTestInterpreter* base_interpreter =
new AccelFilterInterpreterTestInterpreter;
AccelFilterInterpreter accel_interpreter(NULL, base_interpreter, NULL);
TestInterpreterWrapper interpreter(&accel_interpreter);
size_t num_segs = AccelFilterInterpreter::kMaxCurveSegs;
AccelFilterInterpreter::CurveSegment* segs;
// x = input speed of movement (mm/s, always >= 0), y = output speed (mm/s)
// Sensitivity: 1 No Acceleration
segs = accel_interpreter.scroll_curves_[0];
float ratio = accel_interpreter.RatioFromAccelCurve(segs, num_segs, 0);
ASSERT_EQ(ratio, 0.0);
ASSERT_EQ(segs[0].x_, INFINITY);
ASSERT_EQ(segs[0].sqr_, 0.0);
ASSERT_EQ(segs[0].mul_, 1.0);
ASSERT_EQ(segs[0].int_, 0.0);
for (int x = 1; x < 1000; ++x) {
ratio = accel_interpreter.RatioFromAccelCurve(segs, num_segs, x);
float y = ratio * float(x);
ASSERT_EQ(x, y);
}
// Sensitivity 2-5
const float scroll_divisors[] = {0.0, // unused
150, 75.0, 70.0, 65.0 }; // used
for (int sensitivity = 2; sensitivity <= 5; ++sensitivity) {
segs = accel_interpreter.scroll_curves_[sensitivity - 1];
const float divisor = scroll_divisors[sensitivity - 1];
ratio = accel_interpreter.RatioFromAccelCurve(segs, num_segs, 0.0);
ASSERT_EQ(ratio, 0.0);
// y = 75x/divisor (x < 75)
const float linear_until_x = 75.0;
ASSERT_EQ(segs[0].x_, linear_until_x);
ASSERT_EQ(segs[0].sqr_, 0.0);
ASSERT_EQ(segs[0].mul_, linear_until_x / divisor);
ASSERT_EQ(segs[0].int_, 0.0);
for (int i = 1; i < 75; ++i) {
float x = float(i);
ratio = accel_interpreter.RatioFromAccelCurve(segs, num_segs, x);
float y = x * ratio;
float expected = (linear_until_x * x) / divisor;
ASSERT_LE(expected - 0.001, y);
ASSERT_GE(expected + 0.001, y);
}
// y = x^2/divisor (x < 600)
const float x_border = 600.0;
ASSERT_EQ(segs[1].x_, x_border);
ASSERT_EQ(segs[1].sqr_, 1 / divisor);
ASSERT_EQ(segs[1].mul_, 0.0);
ASSERT_EQ(segs[1].int_, 0.0);
for (int i = 75; i < 600; ++i) {
float x = float(i);
ratio = accel_interpreter.RatioFromAccelCurve(segs, num_segs, x);
float y = x * ratio;
float expected = (x * x) / divisor;
ASSERT_LE(expected - 0.001, y);
ASSERT_GE(expected + 0.001, y);
}
// linear with same slope after
const float slope = linear_until_x / divisor;
const float y_at_border = (x_border * x_border) / divisor;
const float intercept = y_at_border - (slope * x_border);
ASSERT_EQ(segs[2].x_, INFINITY);
ASSERT_EQ(segs[2].sqr_, 0.0);
ASSERT_EQ(segs[2].mul_, slope);
ASSERT_EQ(segs[2].int_, intercept);
for (int i = 600; i < 1000; ++i) {
float x = float(i);
ratio = accel_interpreter.RatioFromAccelCurve(segs, num_segs, x);
float y = x * ratio;
float expected = x * (slope + (intercept / x));
ASSERT_LE(expected - 0.001, y);
ASSERT_GE(expected + 0.001, y);
}
}
}
} // namespace gestures