diff --git a/testing/KeyboardReport.cpp b/testing/KeyboardReport.cpp index 8b290eae..31e87de3 100644 --- a/testing/KeyboardReport.cpp +++ b/testing/KeyboardReport.cpp @@ -28,13 +28,38 @@ KeyboardReport::KeyboardReport(const void* data) { } std::vector KeyboardReport::ActiveKeycodes() const { - std::vector active_keys; + auto keycodes = ActiveNonModifierKeycodes(); + auto mods = ActiveModifierKeycodes(); + keycodes.insert(keycodes.end(), mods.begin(), mods.end()); + return keycodes; +} + +std::vector KeyboardReport::ActiveModifierKeycodes() const { + constexpr uint8_t modifier_keycode_offset{HID_KEYBOARD_FIRST_MODIFIER}; + + std::vector active_modifiers; + + uint8_t modifiers{report_data_.modifiers}, mask{1}; + + for (uint8_t i{0}; modifiers != 0; ++i, modifiers >>= 1) { + if (modifiers & mask) { + active_modifiers.push_back(i + modifier_keycode_offset); + } + } + + return active_modifiers; +} + +std::vector KeyboardReport::ActiveNonModifierKeycodes() const { + std::vector active_keycodes; + for (uint8_t i = 0; i < HID_LAST_KEY; ++i) { uint8_t bit = 1 << (uint8_t(i) % 8); - uint8_t key_code = report_data_.keys[i / 8] & bit; - if (key_code) active_keys.push_back(i); + uint8_t keycode = report_data_.keys[i / 8] & bit; + if (keycode) active_keycodes.push_back(i); } - return active_keys; + + return active_keycodes; } } // namespace testing diff --git a/testing/KeyboardReport.h b/testing/KeyboardReport.h index a17ab1d0..3654d6c4 100644 --- a/testing/KeyboardReport.h +++ b/testing/KeyboardReport.h @@ -34,6 +34,8 @@ class KeyboardReport { KeyboardReport(const void* data); std::vector ActiveKeycodes() const; + std::vector ActiveModifierKeycodes() const; + std::vector ActiveNonModifierKeycodes() const; private: ReportData report_data_; diff --git a/tests/features/keycodes/sketch.ino b/tests/features/keycodes/sketch.ino new file mode 100644 index 00000000..bb9beb2b --- /dev/null +++ b/tests/features/keycodes/sketch.ino @@ -0,0 +1,36 @@ +// -*- mode: c++ -*- +// Copyright 2016 Keyboardio, inc. +// See "LICENSE" for license details + +// The Kaleidoscope core +#include "Kaleidoscope.h" + +// *INDENT-OFF* + +KEYMAPS( + KEYMAP_STACKED + (___, Key_1, Key_2, Key_3, Key_4, Key_5, ___, + Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab, + Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G, + Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape, + Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift, + ___, + + ___, Key_6, Key_7, Key_8, Key_9, Key_0, ___, + Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals, + Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote, + Key_RightAlt, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus, + Key_RightShift, Key_LeftAlt, Key_Spacebar, Key_RightControl, + ___) + +) // KEYMAPS( + +// *INDENT-ON* + +void setup() { + Kaleidoscope.setup(); +} + +void loop() { + Kaleidoscope.loop(); +} diff --git a/tests/features/keycodes/test/testcase.cpp b/tests/features/keycodes/test/testcase.cpp new file mode 100644 index 00000000..9353e28b --- /dev/null +++ b/tests/features/keycodes/test/testcase.cpp @@ -0,0 +1,89 @@ +/* -*- mode: c++ -*- + * Copyright (C) 2020 Keyboard.io, Inc. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "testing/setup-googletest.h" + +SETUP_GOOGLETEST(); + +namespace kaleidoscope { +namespace testing { +namespace { + +constexpr KeyAddr key_addr_A{2, 1}; +constexpr KeyAddr key_addr_S{2, 2}; +constexpr KeyAddr key_addr_LeftShift{3, 7}; +constexpr uint8_t keycode_LeftShift{Key_LeftShift.getKeyCode()}; + +class Keycodes : public VirtualDeviceTest {}; + +TEST_F(Keycodes, KeyboardNonModifier) { + + std::set expected_keycodes{}; + + // Press `A` + sim_.Press(key_addr_A); + expected_keycodes.insert(Key_A.getKeyCode()); + + auto state = VirtualDeviceTest::RunCycle(); + + ASSERT_EQ(state->HIDReports()->Keyboard().size(), 1); + EXPECT_THAT(state->HIDReports()->Keyboard(0).ActiveNonModifierKeycodes(), + ::testing::ElementsAreArray(expected_keycodes)); + EXPECT_THAT(state->HIDReports()->Keyboard(0).ActiveKeycodes(), + ::testing::ElementsAreArray(expected_keycodes)); + + sim_.Release(key_addr_A); + expected_keycodes.erase(Key_A.getKeyCode()); + + state = VirtualDeviceTest::RunCycle(); + + ASSERT_EQ(state->HIDReports()->Keyboard().size(), 1); + EXPECT_THAT(state->HIDReports()->Keyboard(0).ActiveKeycodes(), + ::testing::ElementsAreArray(expected_keycodes)); +} + +TEST_F(Keycodes, KeyboardModifier) { + + std::set expected_keycodes{}; + + // Press `LeftShift` + sim_.Press(key_addr_LeftShift); + expected_keycodes.insert(keycode_LeftShift); + + auto state = VirtualDeviceTest::RunCycle(); + + ASSERT_EQ(state->HIDReports()->Keyboard().size(), 1); + EXPECT_THAT(state->HIDReports()->Keyboard(0).ActiveModifierKeycodes(), + ::testing::ElementsAreArray(expected_keycodes)); + EXPECT_THAT(state->HIDReports()->Keyboard(0).ActiveKeycodes(), + ::testing::ElementsAreArray(expected_keycodes)); + + uint8_t bit_LeftShift = keycode_LeftShift - HID_KEYBOARD_FIRST_MODIFIER; + uint8_t expected_modifiers = 1 << bit_LeftShift; + + sim_.Release(key_addr_LeftShift); + expected_keycodes.erase(Key_LeftShift.getKeyCode()); + + state = VirtualDeviceTest::RunCycle(); + + ASSERT_EQ(state->HIDReports()->Keyboard().size(), 1); + EXPECT_THAT(state->HIDReports()->Keyboard(0).ActiveKeycodes(), + ::testing::ElementsAreArray(expected_keycodes)); +} + +} // namespace +} // namespace testing +} // namespace kaleidoscope