Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions src/core/runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,9 +374,9 @@ namespace lvh {
});
}

void Gamepad::set_output_callback(OutputCallback callback) {
void Gamepad::set_output_callback(const OutputCallback &callback) {
with_device(device_, [&callback](auto &device) {
device.output_callback = std::move(callback);
device.output_callback = callback;
if (device.backend) {
device.backend->set_output_callback(device.output_callback);
}
Expand Down Expand Up @@ -999,7 +999,8 @@ namespace lvh {
state_->gamepads.emplace_back(device);
});

return {OperationStatus::success(), std::make_unique<Gamepad>(detail::RuntimeConstructionToken {}, std::move(device))};
auto gamepad = std::make_unique<Gamepad>(detail::RuntimeConstructionToken {}, std::move(device));
return {OperationStatus::success(), std::move(gamepad)};
}

KeyboardCreationResult Runtime::create_keyboard() {
Expand Down Expand Up @@ -1027,7 +1028,8 @@ namespace lvh {
state_->keyboards.emplace_back(device);
});

return {OperationStatus::success(), std::make_unique<Keyboard>(detail::RuntimeConstructionToken {}, std::move(device))};
auto keyboard = std::make_unique<Keyboard>(detail::RuntimeConstructionToken {}, std::move(device));
return {OperationStatus::success(), std::move(keyboard)};
}

MouseCreationResult Runtime::create_mouse() {
Expand Down Expand Up @@ -1055,7 +1057,8 @@ namespace lvh {
state_->mice.emplace_back(device);
});

return {OperationStatus::success(), std::make_unique<Mouse>(detail::RuntimeConstructionToken {}, std::move(device))};
auto mouse = std::make_unique<Mouse>(detail::RuntimeConstructionToken {}, std::move(device));
return {OperationStatus::success(), std::move(mouse)};
}

TouchscreenCreationResult Runtime::create_touchscreen() {
Expand Down Expand Up @@ -1083,7 +1086,8 @@ namespace lvh {
state_->touchscreens.emplace_back(device);
});

return {OperationStatus::success(), std::make_unique<Touchscreen>(detail::RuntimeConstructionToken {}, std::move(device))};
auto touchscreen = std::make_unique<Touchscreen>(detail::RuntimeConstructionToken {}, std::move(device));
return {OperationStatus::success(), std::move(touchscreen)};
}

TrackpadCreationResult Runtime::create_trackpad() {
Expand Down Expand Up @@ -1111,7 +1115,8 @@ namespace lvh {
state_->trackpads.emplace_back(device);
});

return {OperationStatus::success(), std::make_unique<Trackpad>(detail::RuntimeConstructionToken {}, std::move(device))};
auto trackpad = std::make_unique<Trackpad>(detail::RuntimeConstructionToken {}, std::move(device));
return {OperationStatus::success(), std::move(trackpad)};
}

PenTabletCreationResult Runtime::create_pen_tablet() {
Expand Down Expand Up @@ -1139,7 +1144,8 @@ namespace lvh {
state_->pen_tablets.emplace_back(device);
});

return {OperationStatus::success(), std::make_unique<PenTablet>(detail::RuntimeConstructionToken {}, std::move(device))};
auto pen_tablet = std::make_unique<PenTablet>(detail::RuntimeConstructionToken {}, std::move(device));
return {OperationStatus::success(), std::move(pen_tablet)};
}

std::size_t Runtime::active_device_count() const {
Expand Down
3 changes: 1 addition & 2 deletions src/core/types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
namespace lvh {

OperationStatus::OperationStatus():
code_ {ErrorCode::ok},
message_ {} {}
code_ {ErrorCode::ok} {}

OperationStatus::OperationStatus(ErrorCode code, std::string message):
code_ {code},
Expand Down
4 changes: 2 additions & 2 deletions src/include/libvirtualhid/runtime.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,9 @@ namespace lvh {
/**
* @brief Register a callback for backend output events.
*
* @param callback Output callback. Passing an empty callback clears it.
* @param callback Output callback copied into the handle. Passing an empty callback clears it.
*/
void set_output_callback(OutputCallback callback);
void set_output_callback(const OutputCallback &callback);

/**
* @brief Dispatch an output event to the registered callback.
Expand Down
25 changes: 12 additions & 13 deletions src/platform/linux/uhid_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,14 +338,14 @@ namespace lvh::detail {
}

template<std::size_t Size>
void copy_string(__u8 (&destination)[Size], const std::string &source) {
void copy_string(__u8 (&destination)[Size], std::string_view source) {
const auto length = std::min(source.size(), Size - 1);
std::memcpy(destination, source.data(), length);
destination[length] = 0;
}

template<std::size_t Size>
void copy_string(char (&destination)[Size], const std::string &source) {
void copy_string(char (&destination)[Size], std::string_view source) {
const auto length = std::min(source.size(), Size - 1);
std::memcpy(destination, source.data(), length);
destination[length] = 0;
Expand Down Expand Up @@ -373,17 +373,17 @@ namespace lvh::detail {
nodes.push_back({.kind = kind, .path = path.string()});
}

bool hidraw_name_matches(const std::filesystem::path &uevent_path, const std::string &name) {
bool hidraw_name_matches(const std::filesystem::path &uevent_path, std::string_view name) {
std::ifstream file {uevent_path};
if (!file) {
return false;
}

std::string line;
while (std::getline(file, line)) {
constexpr auto key = "HID_NAME=";
constexpr std::string_view key {"HID_NAME="};
if (line.starts_with(key)) {
return line.substr(std::char_traits<char>::length(key)) == name;
return line.size() == key.size() + name.size() && line.ends_with(name);
}
}

Expand Down Expand Up @@ -1451,7 +1451,7 @@ namespace lvh::detail {
}

const auto slot = slot_for_contact(contact.id);
if (!slot) {
if (!slot.has_value()) {
return OperationStatus::failure(ErrorCode::invalid_argument, "too many active touch contacts");
}

Expand Down Expand Up @@ -2398,17 +2398,17 @@ namespace lvh::detail {
event.u.get_report_reply.err = 0;
switch (report_number) {
case dualsense_calibration_report:
copy_get_report_payload(event, dualsense_calibration_info, sizeof(dualsense_calibration_info));
copy_get_report_payload(event, dualsense_calibration_info);
break;
case dualsense_pairing_report:
copy_get_report_payload(event, dualsense_pairing_info, sizeof(dualsense_pairing_info));
copy_get_report_payload(event, dualsense_pairing_info);
for (std::size_t index = 0; index < dualsense_mac_address_.size(); ++index) {
event.u.get_report_reply.data[1U + index] =
dualsense_mac_address_[dualsense_mac_address_.size() - 1U - index];
}
break;
case dualsense_firmware_report:
copy_get_report_payload(event, dualsense_firmware_info, sizeof(dualsense_firmware_info));
copy_get_report_payload(event, dualsense_firmware_info);
break;
default:
event.u.get_report_reply.err = EINVAL;
Expand All @@ -2429,10 +2429,9 @@ namespace lvh::detail {
static_cast<void>(write_event(event));
}

template<std::size_t Size>
void copy_get_report_payload(uhid_event &event, const std::uint8_t (&payload)[Size], std::size_t payload_size) {
event.u.get_report_reply.size = static_cast<std::uint16_t>(std::min<std::size_t>(payload_size, UHID_DATA_MAX));
std::memcpy(event.u.get_report_reply.data, payload, event.u.get_report_reply.size);
static void copy_get_report_payload(uhid_event &event, std::span<const std::uint8_t> payload) {
event.u.get_report_reply.size = static_cast<std::uint16_t>(std::min<std::size_t>(payload.size(), UHID_DATA_MAX));
std::memcpy(event.u.get_report_reply.data, payload.data(), event.u.get_report_reply.size);
}

void send_set_report_reply(std::uint32_t id, std::uint16_t error) {
Expand Down
15 changes: 6 additions & 9 deletions tests/fixtures/fixtures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,11 @@ void BaseTest::TearDown() {
}
}

void LinuxTest::SetUp() {
#if !defined(__linux__)
void LinuxTest::SetUp() {
GTEST_SKIP() << "Skipping, this test is for Linux only.";
#endif
BaseTest::SetUp();
}
#endif

::testing::AssertionResult LinuxTest::HasReadableWritableDeviceNode(const char *path) {
#if defined(__linux__)
Expand All @@ -57,16 +56,14 @@ ::testing::AssertionResult LinuxTest::HasReadableWritableDeviceNode(const char *
#endif
}

void MacOSTest::SetUp() {
#if !defined(__APPLE__) || !defined(__MACH__)
void MacOSTest::SetUp() {
GTEST_SKIP() << "Skipping, this test is for macOS only.";
#endif
BaseTest::SetUp();
}
#endif

void WindowsTest::SetUp() {
#if !defined(_WIN32)
void WindowsTest::SetUp() {
GTEST_SKIP() << "Skipping, this test is for Windows only.";
#endif
BaseTest::SetUp();
}
#endif
6 changes: 6 additions & 0 deletions tests/fixtures/include/fixtures/fixtures.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ class BaseTest: public ::testing::Test {
*/
class LinuxTest: public BaseTest {
protected:
#if !defined(__linux__)
/**
* @brief Set up the test.
*/
void SetUp() override;
#endif

/**
* @brief Check that a Linux device node is readable and writable.
Expand All @@ -55,21 +57,25 @@ class LinuxTest: public BaseTest {
*/
class MacOSTest: public BaseTest {
protected:
#if !defined(__APPLE__) || !defined(__MACH__)
/**
* @brief Set up the test.
*/
void SetUp() override;
#endif
};

/**
* @brief Base class for Windows-only tests.
*/
class WindowsTest: public BaseTest {
protected:
#if !defined(_WIN32)
/**
* @brief Set up the test.
*/
void SetUp() override;
#endif
};

// Undefine the original TEST macro.
Expand Down
7 changes: 4 additions & 3 deletions tests/fixtures/include/fixtures/linux_backend_test_hooks.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <cstddef>
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>

// local includes
Expand Down Expand Up @@ -418,15 +419,15 @@ namespace lvh::detail::test {
* @param expected Expected first line.
* @return `true` when the first line exists and matches.
*/
bool linux_first_line_matches(const std::string &path, const std::string &expected);
bool linux_first_line_matches(std::string_view path, std::string_view expected);

/**
* @brief Check whether reading the first line of a file fails.
*
* @param path File path to read.
* @return `true` when no first line could be read.
*/
bool linux_first_line_missing(const std::string &path);
bool linux_first_line_missing(std::string_view path);

/**
* @brief Check whether a hidraw uevent file advertises the expected HID name.
Expand All @@ -435,7 +436,7 @@ namespace lvh::detail::test {
* @param name Expected HID name.
* @return `true` when the HID name matches.
*/
bool linux_hidraw_name_matches(const std::string &path, const std::string &name);
bool linux_hidraw_name_matches(std::string_view path, std::string_view name);

/**
* @brief Discover Linux input nodes for a device name.
Expand Down
40 changes: 21 additions & 19 deletions tests/fixtures/linux_backend_test_hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <span>
#include <sstream>
#include <string>
#include <string_view>
#include <system_error>
#include <thread>
#include <utility>
Expand Down Expand Up @@ -347,20 +348,20 @@ extern "C" libevdev *lvh_linux_test_libevdev_new() {
return nullptr;
}
auto fake_device = std::make_unique<lvh::detail::test::FakeLibevdevDevice>();
auto *device = fake_device.get();
auto *created_device = fake_device.get();
lvh::detail::test::active_test_syscalls->owned_libevdev_devices.push_back(std::move(fake_device));
return lvh::detail::test::libevdev_handle(device);
return lvh::detail::test::libevdev_handle(created_device);
}
return ::libevdev_new();
}

extern "C" void lvh_linux_test_libevdev_free(libevdev *device) {
if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_libevdev) {
auto *fake_device = lvh::detail::test::fake_libevdev_device(device);
auto *fake_device_handle = lvh::detail::test::fake_libevdev_device(device);
static_cast<void>(std::erase_if(
lvh::detail::test::active_test_syscalls->owned_libevdev_devices,
[fake_device](const auto &owned_device) {
return owned_device.get() == fake_device;
[fake_device_handle](const auto &owned_device) {
return owned_device.get() == fake_device_handle;
}
));
return;
Expand Down Expand Up @@ -470,11 +471,12 @@ extern "C" int lvh_linux_test_libevdev_uinput_create_from_device(
return -EIO;
}

const auto &fake_device = *lvh::detail::test::fake_libevdev_device(device);
lvh::detail::test::active_test_syscalls->libevdev_devices.push_back(fake_device);
auto fake_uinput_device = std::make_unique<lvh::detail::test::FakeLibevdevUinput>(lvh::detail::test::FakeLibevdevUinput {fake_device});
auto *created_uinput_device = fake_uinput_device.get();
lvh::detail::test::active_test_syscalls->owned_libevdev_uinput_devices.push_back(std::move(fake_uinput_device));
const auto &source_device = *lvh::detail::test::fake_libevdev_device(device);
lvh::detail::test::active_test_syscalls->libevdev_devices.push_back(source_device);
auto owned_uinput_device =
std::make_unique<lvh::detail::test::FakeLibevdevUinput>(lvh::detail::test::FakeLibevdevUinput {source_device});
auto *created_uinput_device = owned_uinput_device.get();
lvh::detail::test::active_test_syscalls->owned_libevdev_uinput_devices.push_back(std::move(owned_uinput_device));
*uinput_device = lvh::detail::test::libevdev_uinput_handle(created_uinput_device);
return 0;
}
Expand All @@ -484,11 +486,11 @@ extern "C" int lvh_linux_test_libevdev_uinput_create_from_device(
extern "C" void lvh_linux_test_libevdev_uinput_destroy(libevdev_uinput *uinput_device) {
if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_libevdev) {
++lvh::detail::test::active_test_syscalls->libevdev_destroy_count;
auto *fake_uinput_device = lvh::detail::test::fake_libevdev_uinput(uinput_device);
auto *fake_uinput_handle = lvh::detail::test::fake_libevdev_uinput(uinput_device);
static_cast<void>(std::erase_if(
lvh::detail::test::active_test_syscalls->owned_libevdev_uinput_devices,
[fake_uinput_device](const auto &owned_device) {
return owned_device.get() == fake_uinput_device;
[fake_uinput_handle](const auto &owned_device) {
return owned_device.get() == fake_uinput_handle;
}
));
return;
Expand Down Expand Up @@ -859,17 +861,17 @@ namespace lvh::detail::test {
return format_mac_address(parse_mac_address(stable_id).value_or(generated_mac_address(id)));
}

bool linux_first_line_matches(const std::string &path, const std::string &expected) {
const auto line = read_first_line(path);
bool linux_first_line_matches(std::string_view path, std::string_view expected) {
const auto line = read_first_line(std::filesystem::path {std::string {path}});
return line && *line == expected;
}

bool linux_first_line_missing(const std::string &path) {
return !read_first_line(path);
bool linux_first_line_missing(std::string_view path) {
return !read_first_line(std::filesystem::path {std::string {path}});
}

bool linux_hidraw_name_matches(const std::string &path, const std::string &name) {
return hidraw_name_matches(path, name);
bool linux_hidraw_name_matches(std::string_view path, std::string_view name) {
return hidraw_name_matches(std::filesystem::path {std::string {path}}, name);
}

std::vector<DeviceNode> linux_discover_nodes_by_name(const std::string &name) {
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_gamepad_lifecycle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ TEST(GamepadLifecycleTest, ExercisesArrivalUpdateFeedbackAndRemoval) {
EXPECT_TRUE(created.gamepad->profile().capabilities.supports_touchpad);

bool feedback_received = false;
created.gamepad->set_output_callback([&](const lvh::GamepadOutput &output) {
created.gamepad->set_output_callback([&feedback_received](const lvh::GamepadOutput &output) {
feedback_received = output.kind == lvh::GamepadOutputKind::rumble &&
output.low_frequency_rumble == 0x4000 &&
output.high_frequency_rumble == 0x2000;
Expand Down
Loading