blob: 21936c42669501d58266f4bd8b998c6c230c6375 [file] [log] [blame]
// Copyright 2017 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 <fbl/vector.h>
#include <hid/hid.h>
#include <hid/usages.h>
#include "garnet/lib/machina/hid_event_source.h"
#include "gtest/gtest.h"
// Yanked from system/ulib/hid/hid.c
#define KEYSET(bitmap, n) (bitmap[(n) >> 5] |= (1 << ((n)&31)))
#define KEYCLR(bitmap, n) (bitmap[(n) >> 5] &= ~(1 << ((n)&31)))
namespace machina {
namespace {
static constexpr size_t kInputQueueSize = 8;
static constexpr hid_keys_t kAllKeysUp = {};
// Utility class for performing verifications on the state of an
// InputDispatcher.
class InputDispatcherVerifier {
public:
InputDispatcherVerifier(InputDispatcher* dispatcher) { Reset(dispatcher); }
void Reset(InputDispatcher* dispatcher) {
queued_events_.reset();
while (dispatcher->Keyboard()->size() > 0) {
InputEvent event = dispatcher->Keyboard()->Wait();
queued_events_.push_back(event);
}
}
size_t events() { return queued_events_.size(); }
// Check for an evdev event between |min| and |max| inclusive in the
// output stream.
bool HasKeyEvent(size_t min, size_t max, uint32_t hid_usage, KeyState state) {
for (size_t i = min; i < max + 1 && i < queued_events_.size(); ++i) {
auto event = queued_events_[i];
if (event.type == InputEventType::KEYBOARD &&
event.key.hid_usage == hid_usage && event.key.state == state) {
return true;
}
}
return false;
}
bool HasKeyPress(size_t min, size_t max, uint32_t usage) {
return HasKeyEvent(min, max, usage, KeyState::PRESSED);
}
bool HasKeyRelease(size_t min, size_t max, uint32_t usage) {
return HasKeyEvent(min, max, usage, KeyState::RELEASED);
}
bool HasBarrier(size_t i) {
auto event = queued_events_[i];
return event.type == InputEventType::BARRIER;
}
private:
fbl::Vector<InputEvent> queued_events_;
};
TEST(HidEventSourceTest, HandleKeyPress) {
InputDispatcher dispatcher(kInputQueueSize);
HidInputDevice hid_device(&dispatcher);
// Set 'A' as pressed.
hid_keys_t keys = {};
KEYSET(keys.keymask, HID_USAGE_KEY_A);
ASSERT_EQ(hid_device.HandleHidKeys(keys), ZX_OK);
InputDispatcherVerifier verifier(&dispatcher);
ASSERT_EQ(verifier.events(), 2u);
EXPECT_TRUE(verifier.HasKeyPress(0, 0, HID_USAGE_KEY_A));
EXPECT_TRUE(verifier.HasBarrier(1));
}
TEST(HidEventSourceTest, HandleMultipleKeyPress) {
InputDispatcher dispatcher(kInputQueueSize);
HidInputDevice hid_device(&dispatcher);
// Set 'ABCD' as pressed.
hid_keys_t keys = {};
KEYSET(keys.keymask, HID_USAGE_KEY_A);
KEYSET(keys.keymask, HID_USAGE_KEY_B);
KEYSET(keys.keymask, HID_USAGE_KEY_C);
KEYSET(keys.keymask, HID_USAGE_KEY_D);
ASSERT_EQ(hid_device.HandleHidKeys(keys), ZX_OK);
InputDispatcherVerifier verifier(&dispatcher);
ASSERT_EQ(verifier.events(), 5u);
EXPECT_TRUE(verifier.HasKeyPress(0, 3, HID_USAGE_KEY_A));
EXPECT_TRUE(verifier.HasKeyPress(0, 3, HID_USAGE_KEY_B));
EXPECT_TRUE(verifier.HasKeyPress(0, 3, HID_USAGE_KEY_C));
EXPECT_TRUE(verifier.HasKeyPress(0, 3, HID_USAGE_KEY_D));
EXPECT_TRUE(verifier.HasBarrier(4));
}
TEST(HidEventSourceTest, HandleKeyRelease) {
InputDispatcher dispatcher(kInputQueueSize);
HidInputDevice hid_device(&dispatcher);
// Initialize with 'A' key pressed.
hid_keys_t key_pressed_keys = {};
KEYSET(key_pressed_keys.keymask, HID_USAGE_KEY_A);
ASSERT_EQ(hid_device.HandleHidKeys(key_pressed_keys), ZX_OK);
// Release all keys.
InputDispatcherVerifier verifier(&dispatcher);
ASSERT_EQ(hid_device.HandleHidKeys(kAllKeysUp), ZX_OK);
verifier.Reset(&dispatcher);
ASSERT_EQ(verifier.events(), 2u);
EXPECT_TRUE(verifier.HasKeyRelease(0, 0, HID_USAGE_KEY_A));
EXPECT_TRUE(verifier.HasBarrier(1));
}
TEST(HidEventSourceTest, HandleMultipleKeyRelease) {
InputDispatcher dispatcher(kInputQueueSize);
HidInputDevice hid_device(&dispatcher);
// Set 'ABCD' as pressed.
hid_keys_t keys = {};
KEYSET(keys.keymask, HID_USAGE_KEY_A);
KEYSET(keys.keymask, HID_USAGE_KEY_B);
KEYSET(keys.keymask, HID_USAGE_KEY_C);
KEYSET(keys.keymask, HID_USAGE_KEY_D);
ASSERT_EQ(hid_device.HandleHidKeys(keys), ZX_OK);
// Release all keys.
InputDispatcherVerifier verifier(&dispatcher);
ASSERT_EQ(hid_device.HandleHidKeys(kAllKeysUp), ZX_OK);
verifier.Reset(&dispatcher);
ASSERT_EQ(verifier.events(), 5u);
EXPECT_TRUE(verifier.HasKeyRelease(0, 3, HID_USAGE_KEY_A));
EXPECT_TRUE(verifier.HasKeyRelease(0, 3, HID_USAGE_KEY_B));
EXPECT_TRUE(verifier.HasKeyRelease(0, 3, HID_USAGE_KEY_C));
EXPECT_TRUE(verifier.HasKeyRelease(0, 3, HID_USAGE_KEY_D));
EXPECT_TRUE(verifier.HasBarrier(4));
}
// Test keys both being pressed and released in a single HID report.
TEST(HidEventSourceTest, HandleKeyPressAndRelease) {
InputDispatcher dispatcher(kInputQueueSize);
HidInputDevice hid_device(&dispatcher);
// Set 'AB' as pressed.
hid_keys_t keys_ab = {};
KEYSET(keys_ab.keymask, HID_USAGE_KEY_A);
KEYSET(keys_ab.keymask, HID_USAGE_KEY_B);
ASSERT_EQ(hid_device.HandleHidKeys(keys_ab), ZX_OK);
// Release 'AB' and press 'CD'.
hid_keys_t keys_cd = {};
KEYSET(keys_cd.keymask, HID_USAGE_KEY_C);
KEYSET(keys_cd.keymask, HID_USAGE_KEY_D);
InputDispatcherVerifier verifier(&dispatcher);
ASSERT_EQ(hid_device.HandleHidKeys(keys_cd), ZX_OK);
verifier.Reset(&dispatcher);
ASSERT_EQ(verifier.events(), 5u);
EXPECT_TRUE(verifier.HasKeyPress(0, 3, HID_USAGE_KEY_C));
EXPECT_TRUE(verifier.HasKeyPress(0, 3, HID_USAGE_KEY_D));
EXPECT_TRUE(verifier.HasKeyRelease(0, 3, HID_USAGE_KEY_A));
EXPECT_TRUE(verifier.HasKeyRelease(0, 3, HID_USAGE_KEY_B));
EXPECT_TRUE(verifier.HasBarrier(4));
}
} // namespace
} // namespace machina