#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "ui/events/event.h"
#include <stddef.h>
#include <stdint.h>
#include <limits>
#include <memory>
#include <string>
#include "base/strings/strcat.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/cleanup/cleanup.h"
#include "ui/base/ui_base_features.h"
#include "ui/events/event_constants.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
#include "ui/events/test/events_test_utils.h"
#include "ui/events/test/keyboard_layout.h"
#include "ui/events/test/test_event_target.h"
#include "ui/gfx/geometry/transform.h"
#if BUILDFLAG(IS_WIN)
#include "ui/events/win/events_win_utils.h"
#endif
namespace ui {
TEST(EventTest, NoNativeEvent) { … }
TEST(EventTest, NativeEvent) { … }
TEST(EventTest, GetCharacter) { … }
TEST(EventTest, ClickCount) { … }
TEST(EventTest, RepeatedClick) { … }
TEST(EventTest, RepeatedKeyEvent) { … }
TEST(EventTest, NoRepeatedKeyEvent) { … }
TEST(EventTest, DoubleClickRequiresUniqueTimestamp) { … }
TEST(EventTest, SingleClickRightLeft) { … }
TEST(EventTest, KeyEvent) { … }
TEST(EventTest, KeyEventDirectUnicode) { … }
TEST(EventTest, NormalizeKeyEventFlags) { … }
TEST(EventTest, KeyEventCopy) { … }
TEST(EventTest, KeyEventCode) { … }
TEST(EventTest, TouchEventRadiusDefaultsToOtherAxis) { … }
TEST(EventTest, TouchEventRotationAngleFixing) { … }
TEST(EventTest, PointerDetailsTouch) { … }
TEST(EventTest, PointerDetailsMouse) { … }
TEST(EventTest, PointerDetailsStylus) { … }
TEST(EventTest, PointerDetailsCustomTouch) { … }
TEST(EventTest, MouseEventLatencyUIComponentExists) { … }
TEST(EventTest, MouseWheelEventLatencyUIComponentExists) { … }
TEST(EventTest, MouseWheelEventLinearTickCalculation) { … }
TEST(EventTest, OrdinalMotionConversion) { … }
TEST(EventTest, EventLatencyOSMouseWheelHistogram) { … }
TEST(EventTest, UpdateForRootTransformation) { … }
TEST(EventTest, OperatorEqual) { … }
TEST(EventTest, ToStringNotEmpty) { … }
#if BUILDFLAG(IS_WIN)
namespace {
const struct AltGraphEventTestCase {
KeyboardCode key_code;
KeyboardLayout layout;
std::vector<KeyboardCode> modifier_key_codes;
int expected_flags;
} kAltGraphEventTestCases[] = {
{VKEY_C,
KEYBOARD_LAYOUT_ENGLISH_US,
{VKEY_RMENU, VKEY_LCONTROL, VKEY_MENU, VKEY_CONTROL},
EF_ALT_DOWN | EF_CONTROL_DOWN},
{VKEY_E,
KEYBOARD_LAYOUT_ENGLISH_US,
{VKEY_RMENU, VKEY_LCONTROL, VKEY_MENU, VKEY_CONTROL},
EF_ALT_DOWN | EF_CONTROL_DOWN},
{VKEY_C,
KEYBOARD_LAYOUT_FRENCH,
{VKEY_RMENU, VKEY_LCONTROL, VKEY_MENU, VKEY_CONTROL},
EF_ALTGR_DOWN},
{VKEY_E,
KEYBOARD_LAYOUT_FRENCH,
{VKEY_RMENU, VKEY_LCONTROL, VKEY_MENU, VKEY_CONTROL},
EF_ALTGR_DOWN},
{VKEY_C,
KEYBOARD_LAYOUT_FRENCH,
{VKEY_LMENU, VKEY_LCONTROL, VKEY_MENU, VKEY_CONTROL},
EF_ALT_DOWN | EF_CONTROL_DOWN},
{VKEY_E,
KEYBOARD_LAYOUT_FRENCH,
{VKEY_LMENU, VKEY_LCONTROL, VKEY_MENU, VKEY_CONTROL},
EF_ALTGR_DOWN},
};
class AltGraphEventTest
: public testing::TestWithParam<std::tuple<UINT, AltGraphEventTestCase>> {
public:
AltGraphEventTest()
: msg_({nullptr, message_type(),
static_cast<WPARAM>(test_case().key_code)}) {
CHECK(GetKeyboardState(original_keyboard_state_));
original_keyboard_layout_ = GetKeyboardLayout(0);
CHECK(ActivateKeyboardLayout(GetPlatformKeyboardLayout(test_case().layout),
0));
BYTE test_keyboard_state[256] = {};
for (const auto& key_code : test_case().modifier_key_codes)
test_keyboard_state[key_code] = 0x80;
CHECK(SetKeyboardState(test_keyboard_state));
}
~AltGraphEventTest() {
CHECK(ActivateKeyboardLayout(original_keyboard_layout_, 0));
CHECK(SetKeyboardState(original_keyboard_state_));
}
protected:
UINT message_type() const { return std::get<0>(GetParam()); }
const AltGraphEventTestCase& test_case() const {
return std::get<1>(GetParam());
}
const CHROME_MSG msg_;
BYTE original_keyboard_state_[256] = {};
HKL original_keyboard_layout_ = nullptr;
};
}
TEST_P(AltGraphEventTest, KeyEventAltGraphModifer) {
KeyEvent event(msg_);
if (message_type() == WM_CHAR) {
EXPECT_EQ(event.flags() & (EF_CONTROL_DOWN | EF_ALT_DOWN | EF_ALTGR_DOWN),
EF_ALTGR_DOWN);
} else {
EXPECT_EQ(event.flags() & (EF_CONTROL_DOWN | EF_ALT_DOWN | EF_ALTGR_DOWN),
test_case().expected_flags);
}
}
INSTANTIATE_TEST_SUITE_P(
WM_KEY,
AltGraphEventTest,
::testing::Combine(::testing::Values(WM_KEYDOWN, WM_KEYUP),
::testing::ValuesIn(kAltGraphEventTestCases)));
INSTANTIATE_TEST_SUITE_P(
WM_CHAR,
AltGraphEventTest,
::testing::Combine(::testing::Values(WM_CHAR),
::testing::ValuesIn(kAltGraphEventTestCases)));
class EventLatencyTest : public ::testing::Test {
public:
EventLatencyTest() { SetEventLatencyTickClockForTesting(&tick_clock_); }
~EventLatencyTest() override { SetEventLatencyTickClockForTesting(nullptr); }
protected:
void UpdateTickClock(DWORD timestamp) {
tick_clock_.SetNowTicks(base::TimeTicks() + base::Milliseconds(timestamp));
}
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
base::SimpleTestTickClock tick_clock_;
};
TEST_F(EventLatencyTest, ComputeEventLatencyOSFromTickCount) {
constexpr base::TimeDelta kTickInterval = base::Milliseconds(16);
constexpr DWORD timestamp_msec =
std::numeric_limits<DWORD>::max() -
(std::numeric_limits<DWORD>::max() % kTickInterval.InMilliseconds()) -
4 * kTickInterval.InMilliseconds();
constexpr TOUCHINPUT touch_input = {
.dwTime = timestamp_msec,
};
constexpr POINTER_INFO pointer_info = {
.dwTime = timestamp_msec,
.PerformanceCount = 0UL,
};
UpdateTickClock(timestamp_msec);
{
base::HistogramTester histogram_tester;
ComputeEventLatencyOSFromTOUCHINPUT(EventType::kTouchPressed, touch_input,
base::TimeTicks::Now());
ComputeEventLatencyOSFromPOINTER_INFO(EventType::kTouchPressed,
pointer_info, base::TimeTicks::Now());
histogram_tester.ExpectUniqueTimeSample("Event.Latency.OS2.TOUCH_PRESSED",
base::Milliseconds(0), 2);
}
UpdateTickClock(timestamp_msec + kTickInterval.InMilliseconds());
{
base::HistogramTester histogram_tester;
ComputeEventLatencyOSFromTOUCHINPUT(EventType::kTouchPressed, touch_input,
base::TimeTicks::Now());
ComputeEventLatencyOSFromPOINTER_INFO(EventType::kTouchPressed,
pointer_info, base::TimeTicks::Now());
histogram_tester.ExpectUniqueTimeSample("Event.Latency.OS2.TOUCH_PRESSED",
base::Milliseconds(0), 2);
}
UpdateTickClock(timestamp_msec + 2 * kTickInterval.InMilliseconds());
{
base::HistogramTester histogram_tester;
ComputeEventLatencyOSFromTOUCHINPUT(EventType::kTouchPressed, touch_input,
base::TimeTicks::Now());
ComputeEventLatencyOSFromPOINTER_INFO(EventType::kTouchPressed,
pointer_info, base::TimeTicks::Now());
histogram_tester.ExpectUniqueTimeSample("Event.Latency.OS2.TOUCH_PRESSED",
base::Milliseconds(16), 2);
}
constexpr DWORD kTickIntervalLowEnd = base::Hertz(64).InMilliseconds();
static_assert(kTickIntervalLowEnd == 15);
UpdateTickClock(timestamp_msec + 2 * kTickIntervalLowEnd);
{
base::HistogramTester histogram_tester;
ComputeEventLatencyOSFromTOUCHINPUT(EventType::kTouchPressed, touch_input,
base::TimeTicks::Now());
ComputeEventLatencyOSFromPOINTER_INFO(EventType::kTouchPressed,
pointer_info, base::TimeTicks::Now());
histogram_tester.ExpectUniqueTimeSample("Event.Latency.OS2.TOUCH_PRESSED",
base::Milliseconds(16), 2);
}
constexpr DWORD wrapped_timestamp_msec =
timestamp_msec + 5 * static_cast<DWORD>(kTickInterval.InMilliseconds());
static_assert(wrapped_timestamp_msec == 0,
"timestamp should have wrapped around");
UpdateTickClock(wrapped_timestamp_msec);
{
base::HistogramTester histogram_tester;
ComputeEventLatencyOSFromTOUCHINPUT(EventType::kTouchPressed, touch_input,
base::TimeTicks::Now());
ComputeEventLatencyOSFromPOINTER_INFO(EventType::kTouchPressed,
pointer_info, base::TimeTicks::Now());
histogram_tester.ExpectUniqueTimeSample("Event.Latency.OS2.TOUCH_PRESSED",
4 * kTickInterval, 2);
}
constexpr DWORD wrapped_timestamp_msec2 =
timestamp_msec + 15 * static_cast<DWORD>(kTickInterval.InMilliseconds());
static_assert(wrapped_timestamp_msec2 == 10 * kTickInterval.InMilliseconds(),
"timestamp should have wrapped around");
UpdateTickClock(wrapped_timestamp_msec2);
{
base::HistogramTester histogram_tester;
ComputeEventLatencyOSFromTOUCHINPUT(EventType::kTouchPressed, touch_input,
base::TimeTicks::Now());
ComputeEventLatencyOSFromPOINTER_INFO(EventType::kTouchPressed,
pointer_info, base::TimeTicks::Now());
histogram_tester.ExpectUniqueTimeSample("Event.Latency.OS2.TOUCH_PRESSED",
14 * kTickInterval, 2);
}
UpdateTickClock(timestamp_msec - kTickInterval.InMilliseconds());
{
base::HistogramTester histogram_tester;
ComputeEventLatencyOSFromTOUCHINPUT(EventType::kTouchPressed, touch_input,
base::TimeTicks::Now());
ComputeEventLatencyOSFromPOINTER_INFO(EventType::kTouchPressed,
pointer_info, base::TimeTicks::Now());
histogram_tester.ExpectUniqueTimeSample("Event.Latency.OS2.TOUCH_PRESSED",
base::TimeDelta(), 2);
}
UpdateTickClock(timestamp_msec + 300 * 1000);
{
base::HistogramTester histogram_tester;
ComputeEventLatencyOSFromTOUCHINPUT(EventType::kTouchPressed, touch_input,
base::TimeTicks::Now());
ComputeEventLatencyOSFromPOINTER_INFO(EventType::kTouchPressed,
pointer_info, base::TimeTicks::Now());
histogram_tester.ExpectUniqueTimeSample("Event.Latency.OS2.TOUCH_PRESSED",
base::TimeDelta(), 2);
}
}
TEST_F(EventLatencyTest, ComputeEventLatencyOSFromPerformanceCounter) {
task_environment_.AdvanceClock(base::Minutes(5));
LARGE_INTEGER ticks_per_sec = {};
if (!::QueryPerformanceFrequency(&ticks_per_sec) ||
ticks_per_sec.QuadPart <= 0 || !base::TimeTicks::IsHighResolution()) {
return;
}
const auto ticks_per_second = ticks_per_sec.QuadPart;
UINT64 current_timestamp =
base::TimeTicks::Now().since_origin().InSecondsF() * ticks_per_second;
{
const POINTER_INFO pointer_info = {
.dwTime = 0U,
.PerformanceCount = current_timestamp - ticks_per_second,
};
base::HistogramTester histogram_tester;
ComputeEventLatencyOSFromPOINTER_INFO(EventType::kTouchPressed,
pointer_info, base::TimeTicks::Now());
histogram_tester.ExpectUniqueTimeSample("Event.Latency.OS2.TOUCH_PRESSED",
base::Seconds(1), 1);
}
{
const POINTER_INFO pointer_info = {
.dwTime = 0U,
.PerformanceCount = current_timestamp - 5 * 60 * ticks_per_second,
};
base::HistogramTester histogram_tester;
ComputeEventLatencyOSFromPOINTER_INFO(EventType::kTouchPressed,
pointer_info, base::TimeTicks::Now());
histogram_tester.ExpectUniqueTimeSample("Event.Latency.OS2.TOUCH_PRESSED",
base::TimeDelta(), 1);
}
{
const POINTER_INFO pointer_info = {
.dwTime = 0U,
.PerformanceCount = current_timestamp + ticks_per_second,
};
base::HistogramTester histogram_tester;
ComputeEventLatencyOSFromPOINTER_INFO(EventType::kTouchPressed,
pointer_info, base::TimeTicks::Now());
histogram_tester.ExpectUniqueTimeSample("Event.Latency.OS2.TOUCH_PRESSED",
base::TimeDelta(), 1);
}
{
const POINTER_INFO pointer_info = {
.dwTime = 0U,
.PerformanceCount = 0UL,
};
base::HistogramTester histogram_tester;
ComputeEventLatencyOSFromPOINTER_INFO(EventType::kTouchPressed,
pointer_info, base::TimeTicks::Now());
histogram_tester.ExpectTotalCount("Event.Latency.OS2.TOUCH_PRESSED", 0);
}
{
const DWORD now_msec = 1000;
UpdateTickClock(now_msec);
const POINTER_INFO pointer_info = {
.dwTime = now_msec - 10,
.PerformanceCount = current_timestamp - ticks_per_second,
};
base::HistogramTester histogram_tester;
ComputeEventLatencyOSFromPOINTER_INFO(EventType::kTouchPressed,
pointer_info, base::TimeTicks::Now());
histogram_tester.ExpectUniqueTimeSample("Event.Latency.OS2.TOUCH_PRESSED",
base::Seconds(1), 1);
}
}
#endif
TEST(EventTest, NeverCopyTarget) { … }
TEST(EventTest, CreateCharcterEvent) { … }
}