3
0
mirror of https://github.com/hyprwm/Hyprland.git synced 2026-08-18 11:02:10 +00:00
Files
Hyprland/tests/keybinds/InputState.cpp

124 lines
4.2 KiB
C++

#include <keybinds/InputState.hpp>
#include <gtest/gtest.h>
using namespace Keybinds;
using namespace Input;
class CTestHID final : public IHID {
public:
uint32_t getCapabilities() override {
return HID_INPUT_CAPABILITY_KEYBOARD;
}
};
TEST(KeybindsInputState, TracksSameKeyPerDevice) {
CInputState state;
const auto FIRST = makeShared<CTestHID>();
const auto SECOND = makeShared<CTestHID>();
const auto KEY = SResolvedKey{.sym = XKB_KEY_k, .code = 45};
EXPECT_TRUE(state.press({.key = KEY, .device = FIRST}));
EXPECT_TRUE(state.press({.key = KEY, .device = SECOND}));
EXPECT_EQ(state.pressed().size(), 2);
EXPECT_EQ(state.heldKeys().size(), 1);
const auto RELEASED = state.release(KEY, FIRST);
ASSERT_TRUE(RELEASED.has_value());
EXPECT_EQ(RELEASED->device.lock(), FIRST);
EXPECT_EQ(state.pressed().size(), 1);
EXPECT_EQ(state.heldKeys().size(), 1);
EXPECT_TRUE(state.isKeycodeDown(45));
EXPECT_TRUE(state.release(KEY, SECOND).has_value());
EXPECT_TRUE(state.heldKeys().empty());
}
TEST(KeybindsInputState, IgnoresDuplicatePress) {
CInputState state;
const auto DEVICE = makeShared<CTestHID>();
const auto KEY = SResolvedKey{.sym = XKB_KEY_k, .code = 45};
EXPECT_TRUE(state.press({.key = KEY, .device = DEVICE}));
EXPECT_FALSE(state.press({.key = KEY, .device = DEVICE}));
EXPECT_EQ(state.pressed().size(), 1);
}
TEST(KeybindsInputState, DoesNotRetainDevice) {
CInputState state;
auto device = makeShared<CTestHID>();
const auto KEY = SResolvedKey{.sym = XKB_KEY_k, .code = 45};
WP<IHID> weak = device;
EXPECT_TRUE(state.press({.key = KEY, .device = device}));
device.reset();
EXPECT_TRUE(weak.expired());
EXPECT_TRUE(state.pressed().front().device.expired());
}
TEST(KeybindsInputState, PreservesDifferentSymbolsForSameCode) {
CInputState state;
const auto FIRST = makeShared<CTestHID>();
const auto SECOND = makeShared<CTestHID>();
EXPECT_TRUE(state.press({.key = {.sym = XKB_KEY_k, .code = 45}, .device = FIRST}));
EXPECT_TRUE(state.press({.key = {.sym = XKB_KEY_a, .code = 45}, .device = SECOND}));
EXPECT_EQ(state.heldKeys().size(), 2);
}
TEST(KeybindsInputState, PreservesPressMetadata) {
CInputState state;
const auto DEVICE = makeShared<CTestHID>();
const auto KEY = SResolvedKey{.sym = XKB_KEY_k, .code = 45};
state.press({
.key = KEY,
.modifiersAtPress = HL_MODIFIER_META,
.forwarded = false,
.submapAtPress = "resize",
.positionAtPress = {10, 20},
.device = DEVICE,
});
const auto RELEASED = state.release(KEY, DEVICE);
ASSERT_TRUE(RELEASED.has_value());
EXPECT_EQ(RELEASED->modifiersAtPress, HL_MODIFIER_META);
EXPECT_FALSE(RELEASED->forwarded);
EXPECT_EQ(RELEASED->submapAtPress, "resize");
EXPECT_EQ(RELEASED->positionAtPress, Vector2D(10, 20));
}
TEST(KeybindsInputState, ClearsOneDevice) {
CInputState state;
const auto FIRST = makeShared<CTestHID>();
const auto SECOND = makeShared<CTestHID>();
state.press({.key = {.sym = XKB_KEY_k, .code = 45}, .device = FIRST});
state.press({.key = {.sym = XKB_KEY_a, .code = 38}, .device = SECOND});
state.clearDevice(FIRST);
EXPECT_FALSE(state.isKeycodeDown(45));
EXPECT_TRUE(state.isKeycodeDown(38));
EXPECT_EQ(state.heldKeys().size(), 1);
}
TEST(KeybindsInputState, TakesReleaseCallbacksWithOriginalActionContext) {
CInputState state;
const auto DEVICE = makeShared<CTestHID>();
const auto KEY = SResolvedKey{.sym = XKB_KEY_k, .code = 45};
auto made = CBind::make({"K"}, 0, [] { return SBindResult{}; });
ASSERT_TRUE(made.has_value());
const auto BIND = makeShared<CBind>(std::move(*made));
state.press({.key = KEY, .actionCode = 45, .actionTimeMs = 123, .device = DEVICE});
state.find(KEY, DEVICE)->releaseCallbacks.emplace_back(BIND);
const auto RELEASES = state.takeReleaseCallbacks(KEY, DEVICE);
ASSERT_EQ(RELEASES.size(), 1);
EXPECT_EQ(RELEASES.front().bind, BIND);
EXPECT_EQ(RELEASES.front().actionCode, 45);
EXPECT_EQ(RELEASES.front().actionTimeMs, 123);
EXPECT_TRUE(state.find(KEY, DEVICE)->releaseCallbacks.empty());
}