A cross-platform C++23 library with a platform-neutral public API and runtime-selected backends: - Input: Wayland virtual pointer/keyboard (Hyprland, wlroots), libei via the RemoteDesktop portal (GNOME, KDE), uinput, and Win32 SendInput - Capture: ScreenCast portal + PipeWire, and Win32 GDI - Windows: Hyprland IPC and Win32 enumeration - Monitors via wl_output/xdg-output and EnumDisplayMonitors - Optional OpenCV template matching (alvin::vision) Also adds the `alvin` CLI, Catch2 unit tests, install rules with find_package(Alvin) support, API docs (docs/API.md and the Obsidian vault), and README instructions for both ways of consuming the library. Windows backends are written but not yet compiled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
67 lines
2.1 KiB
C++
67 lines
2.1 KiB
C++
#include <catch2/catch_test_macros.hpp>
|
|
|
|
#include "alvin/frame.hpp"
|
|
#include "alvin/keys.hpp"
|
|
#include "alvin/types.hpp"
|
|
|
|
using namespace alvin;
|
|
|
|
TEST_CASE("key names round-trip and aliases resolve") {
|
|
CHECK(keyFromName("A") == Key::A);
|
|
CHECK(keyFromName("ctrl") == Key::LeftCtrl);
|
|
CHECK(keyFromName("Control") == Key::LeftCtrl);
|
|
CHECK(keyFromName("esc") == Key::Escape);
|
|
CHECK(keyFromName("F12") == Key::F12);
|
|
CHECK_FALSE(keyFromName("nope"));
|
|
for (int k = 1; k < static_cast<int>(Key::Count_); ++k) {
|
|
auto key = static_cast<Key>(k);
|
|
INFO("key index " << k);
|
|
CHECK(keyFromName(keyName(key)) == key);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("chords parse in order") {
|
|
auto c = parseChord("ctrl+shift+t");
|
|
REQUIRE(c);
|
|
CHECK(*c == std::vector{Key::LeftCtrl, Key::LeftShift, Key::T});
|
|
|
|
CHECK(parseChord(" super + enter ") == std::vector{Key::LeftSuper, Key::Enter});
|
|
CHECK(parseChord("ctrl++") == std::vector{Key::LeftCtrl, Key::Equal});
|
|
CHECK_FALSE(parseChord("ctrl+"));
|
|
CHECK_FALSE(parseChord(""));
|
|
CHECK_FALSE(parseChord("ctrl+bogus"));
|
|
}
|
|
|
|
TEST_CASE("rect union ignores empty rects") {
|
|
Rect a{0, 0, 10, 10}, b{20, -5, 5, 5};
|
|
CHECK(a.united(b) == Rect{0, -5, 25, 15});
|
|
CHECK(Rect{}.united(a) == a);
|
|
CHECK(a.united(Rect{}) == a);
|
|
CHECK(a.contains({9, 9}));
|
|
CHECK_FALSE(a.contains({10, 0}));
|
|
}
|
|
|
|
TEST_CASE("frame maps between pixels and desktop coordinates") {
|
|
// A 1.5x scaled monitor: 300x150 pixels covering 200x100 logical at (1000, 50).
|
|
Frame f(300, 150);
|
|
f.setDesktopRect({1000, 50, 200, 100});
|
|
CHECK(f.toDesktop({0, 0}) == Point{1000, 50});
|
|
CHECK(f.toDesktop({150, 75}) == Point{1100, 100});
|
|
CHECK(f.fromDesktop({1100, 100}) == Point{150, 75});
|
|
|
|
Frame c = f.crop({150, 0, 1000, 75}); // clipped to the frame
|
|
CHECK(c.width() == 150);
|
|
CHECK(c.height() == 75);
|
|
CHECK(c.desktopRect() == Rect{1100, 50, 100, 50});
|
|
}
|
|
|
|
TEST_CASE("frame pixel reads BGRA") {
|
|
Frame f(2, 1);
|
|
f.data()[4] = 1; // B
|
|
f.data()[5] = 2; // G
|
|
f.data()[6] = 3; // R
|
|
f.data()[7] = 4; // A
|
|
CHECK(f.pixel(1, 0) == Color{3, 2, 1, 4});
|
|
CHECK(f.pixel(5, 5) == Color{});
|
|
}
|