| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <set> |
| |
| #include <hid/usages.h> |
| |
| #include "garnet/bin/ui/input_reader/input_reader.h" |
| #include "garnet/bin/ui/input_reader/tests/mock_device_watcher.h" |
| #include "garnet/bin/ui/input_reader/tests/mock_hid_decoder.h" |
| #include "gtest/gtest.h" |
| #include "lib/gtest/test_loop_fixture.h" |
| #include "lib/ui/tests/mocks/mock_input_device.h" |
| #include "lib/ui/tests/mocks/mock_input_device_registry.h" |
| |
| namespace mozart { |
| |
| namespace { |
| |
| using MockInputDevice = mozart::test::MockInputDevice; |
| using MockInputDeviceRegistry = mozart::test::MockInputDeviceRegistry; |
| |
| // This fixture sets up a |MockDeviceWatcher| so that tests can add mock |
| // devices. |
| class ReaderInterpreterTest : public gtest::TestLoopFixture { |
| protected: |
| // Starts an |InputReader| with a |MockDeviceWatcher| and saves it locally so |
| // that |MockHidDecoder|s can be added to it. |
| void StartInputReader(InputReader* input_reader) { |
| auto device_watcher = std::make_unique<MockDeviceWatcher>(); |
| device_watcher_ = device_watcher->GetWeakPtr(); |
| input_reader->Start(std::move(device_watcher)); |
| } |
| |
| // Creates a |MockHidDecoder| with the supplied |args| and adds it to the |
| // |MockDeviceWatcher|, returning an |fxl::WeakPtr| to the new |
| // |MockHidDecoder|. |
| template <class... Args> |
| fxl::WeakPtr<MockHidDecoder> AddDevice(Args&&... args) { |
| auto device = std::make_unique<MockHidDecoder>(std::forward<Args>(args)...); |
| auto weak_device = device->GetWeakPtr(); |
| device_watcher_->AddDevice(std::move(device)); |
| return weak_device; |
| } |
| |
| private: |
| fxl::WeakPtr<MockDeviceWatcher> device_watcher_; |
| }; |
| |
| // This fixture sets up a |MockInputDeviceRegistry| and an |InputReader| in |
| // addition to the |MockDeviceWatcher| provided by |ReaderInterpreterTest| so |
| // that tests can additionally verify the reports seen by the registry. |
| class ReaderInterpreterInputTest : public ReaderInterpreterTest { |
| protected: |
| ReaderInterpreterInputTest() |
| : registry_(nullptr, |
| [this](fuchsia::ui::input::InputReport report) { |
| ++report_count_; |
| last_report_ = std::move(report); |
| }), |
| input_reader_(®istry_) {} |
| |
| int report_count_ = 0; |
| fuchsia::ui::input::InputReport last_report_; |
| |
| private: |
| void SetUp() override { StartInputReader(&input_reader_); } |
| |
| MockInputDeviceRegistry registry_; |
| InputReader input_reader_; |
| }; |
| |
| } // namespace |
| |
| TEST_F(ReaderInterpreterTest, RegisterKeyboardTest) { |
| int registration_count = 0; |
| |
| MockInputDeviceRegistry registry( |
| [&](MockInputDevice* client_device) { |
| EXPECT_EQ(0, registration_count++); |
| EXPECT_TRUE(client_device->descriptor()->keyboard); |
| }, |
| nullptr); |
| InputReader input_reader(®istry); |
| |
| StartInputReader(&input_reader); |
| |
| bool did_init = false; |
| AddDevice([&] { |
| did_init = true; |
| return std::make_pair<HidDecoder::Protocol, bool>( |
| HidDecoder::Protocol::Keyboard, true); |
| }); |
| EXPECT_TRUE(did_init); |
| EXPECT_EQ(1, registration_count); |
| } |
| |
| TEST_F(ReaderInterpreterTest, DISABLED_RemoveKeyboardTest) { |
| MockInputDeviceRegistry registry(nullptr, nullptr); |
| InputReader input_reader(®istry); |
| StartInputReader(&input_reader); |
| |
| fxl::WeakPtr<MockHidDecoder> device = |
| AddDevice(HidDecoder::Protocol::Keyboard); |
| |
| device->Close(); |
| RunLoopUntilIdle(); |
| EXPECT_FALSE(device); |
| } |
| |
| TEST_F(ReaderInterpreterInputTest, KeyboardTest) { |
| fxl::WeakPtr<MockHidDecoder> device = |
| AddDevice(HidDecoder::Protocol::Keyboard); |
| |
| RunLoopUntilIdle(); |
| EXPECT_EQ(0, report_count_); |
| |
| // A keyboard report is 8 bytes long, with bytes 3-8 containing HID usage |
| // codes. |
| device->Send({0, 0, HID_USAGE_KEY_A, 0, 0, 0, 0, 0}, 8); |
| |
| RunLoopUntilIdle(); |
| EXPECT_EQ(1, report_count_); |
| ASSERT_TRUE(last_report_.keyboard); |
| EXPECT_EQ(std::vector<uint32_t>{HID_USAGE_KEY_A}, |
| last_report_.keyboard->pressed_keys); |
| |
| device->Send({0, 0, HID_USAGE_KEY_A, HID_USAGE_KEY_Z, 0, 0, 0, 0}, 8); |
| RunLoopUntilIdle(); |
| EXPECT_EQ(2, report_count_); |
| EXPECT_EQ(std::multiset<uint32_t>({HID_USAGE_KEY_A, HID_USAGE_KEY_Z}), |
| std::multiset<uint32_t>(last_report_.keyboard->pressed_keys.begin(), |
| last_report_.keyboard->pressed_keys.end())); |
| |
| device->Send({0, 0, HID_USAGE_KEY_Z, 0, 0, 0, 0, 0}, 8); |
| RunLoopUntilIdle(); |
| EXPECT_EQ(std::vector<uint32_t>{HID_USAGE_KEY_Z}, |
| last_report_.keyboard->pressed_keys); |
| } |
| |
| TEST_F(ReaderInterpreterInputTest, LightSensorTest) { |
| fxl::WeakPtr<MockHidDecoder> device = |
| AddDevice(HidDecoder::Protocol::LightSensor); |
| |
| RunLoopUntilIdle(); |
| EXPECT_EQ(0, report_count_); |
| |
| { |
| HidDecoder::HidAmbientLightSimple light{/* int16_t illuminance */ 42}; |
| device->Send(light); |
| } |
| |
| RunLoopUntilIdle(); |
| EXPECT_EQ(1, report_count_); |
| ASSERT_TRUE(last_report_.sensor); |
| EXPECT_TRUE(last_report_.sensor->is_scalar()); |
| EXPECT_EQ(42, last_report_.sensor->scalar()); |
| } |
| |
| TEST_F(ReaderInterpreterInputTest, TouchpadTest) { |
| fxl::WeakPtr<MockHidDecoder> device = |
| AddDevice(HidDecoder::Protocol::Touchpad); |
| |
| RunLoopUntilIdle(); |
| EXPECT_EQ(0, report_count_); |
| |
| { |
| // Touchpads use the touchscreen driver behind the scenes, so we |
| // must send touchscreen reports. |
| Touchscreen::Report touchpad_rpt{}; |
| touchpad_rpt.contact_count = 1; |
| touchpad_rpt.contacts[0].id = 1; |
| touchpad_rpt.contacts[0].x = 10; |
| touchpad_rpt.contacts[0].y = 20; |
| device->Send(touchpad_rpt); |
| RunLoopUntilIdle(); |
| |
| touchpad_rpt.contacts[0].x = 15; |
| touchpad_rpt.contacts[0].y = 10; |
| device->Send(touchpad_rpt); |
| RunLoopUntilIdle(); |
| } |
| |
| EXPECT_EQ(2, report_count_); |
| ASSERT_TRUE(last_report_.mouse); |
| EXPECT_TRUE(last_report_.mouse->rel_x = 5); |
| EXPECT_TRUE(last_report_.mouse->rel_y = -10); |
| } |
| |
| TEST_F(ReaderInterpreterInputTest, TouchscreenTest) { |
| fxl::WeakPtr<MockHidDecoder> device = AddDevice(HidDecoder::Protocol::Touch); |
| |
| RunLoopUntilIdle(); |
| EXPECT_EQ(0, report_count_); |
| |
| { |
| Touchscreen::Report touchscreen_rpt{}; |
| touchscreen_rpt.contact_count = 1; |
| touchscreen_rpt.contacts[0].id = 1; |
| touchscreen_rpt.contacts[0].x = 10; |
| touchscreen_rpt.contacts[0].y = 20; |
| device->Send(touchscreen_rpt); |
| RunLoopUntilIdle(); |
| } |
| |
| EXPECT_EQ(1, report_count_); |
| ASSERT_TRUE(last_report_.touchscreen); |
| fuchsia::ui::input::Touch touch = last_report_.touchscreen->touches.at(0); |
| EXPECT_TRUE(touch.finger_id = 1); |
| EXPECT_TRUE(touch.x = 10); |
| EXPECT_TRUE(touch.y = 20); |
| } |
| } // namespace mozart |