diff --git a/CMakeLists.txt b/CMakeLists.txt index 396889c..0e0fc9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project(libvirtualhid VERSION 0.0.0 LANGUAGES CXX) set(PROJECT_LICENSE "MIT") -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 79df68a..53d9c0a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -51,7 +51,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") -target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_20) +target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23) set_target_properties(${PROJECT_NAME} PROPERTIES EXPORT_NAME libvirtualhid OUTPUT_NAME virtualhid) diff --git a/src/core/runtime.cpp b/src/core/runtime.cpp index fa3f3ab..bacdaba 100644 --- a/src/core/runtime.cpp +++ b/src/core/runtime.cpp @@ -305,7 +305,12 @@ namespace lvh { Gamepad::Gamepad(Gamepad &&) noexcept = default; Gamepad &Gamepad::operator=(Gamepad &&) noexcept = default; - Gamepad::~Gamepad() = default; + + Gamepad::~Gamepad() { + if (device_) { + static_cast(close()); + } + } DeviceId Gamepad::device_id() const { return device_->id; @@ -425,7 +430,12 @@ namespace lvh { Keyboard::Keyboard(Keyboard &&) noexcept = default; Keyboard &Keyboard::operator=(Keyboard &&) noexcept = default; - Keyboard::~Keyboard() = default; + + Keyboard::~Keyboard() { + if (device_) { + static_cast(close()); + } + } DeviceId Keyboard::device_id() const { return device_->id; @@ -531,7 +541,12 @@ namespace lvh { Mouse::Mouse(Mouse &&) noexcept = default; Mouse &Mouse::operator=(Mouse &&) noexcept = default; - Mouse::~Mouse() = default; + + Mouse::~Mouse() { + if (device_) { + static_cast(close()); + } + } DeviceId Mouse::device_id() const { return device_->id; @@ -641,7 +656,12 @@ namespace lvh { Touchscreen::Touchscreen(Touchscreen &&) noexcept = default; Touchscreen &Touchscreen::operator=(Touchscreen &&) noexcept = default; - Touchscreen::~Touchscreen() = default; + + Touchscreen::~Touchscreen() { + if (device_) { + static_cast(close()); + } + } DeviceId Touchscreen::device_id() const { return device_->id; @@ -743,7 +763,12 @@ namespace lvh { Trackpad::Trackpad(Trackpad &&) noexcept = default; Trackpad &Trackpad::operator=(Trackpad &&) noexcept = default; - Trackpad::~Trackpad() = default; + + Trackpad::~Trackpad() { + if (device_) { + static_cast(close()); + } + } DeviceId Trackpad::device_id() const { return device_->id; @@ -862,7 +887,12 @@ namespace lvh { PenTablet::PenTablet(PenTablet &&) noexcept = default; PenTablet &PenTablet::operator=(PenTablet &&) noexcept = default; - PenTablet::~PenTablet() = default; + + PenTablet::~PenTablet() { + if (device_) { + static_cast(close()); + } + } DeviceId PenTablet::device_id() const { return device_->id; diff --git a/src/core/types.cpp b/src/core/types.cpp index 077e735..d397e2e 100644 --- a/src/core/types.cpp +++ b/src/core/types.cpp @@ -42,7 +42,7 @@ namespace lvh { } void ButtonSet::set(GamepadButton button, bool pressed) { - const auto mask = 1U << static_cast(button); + const auto mask = 1U << std::to_underlying(button); if (pressed) { bits_ |= mask; } else { @@ -59,7 +59,7 @@ namespace lvh { } bool ButtonSet::test(GamepadButton button) const { - return (bits_ & (1U << static_cast(button))) != 0; + return (bits_ & (1U << std::to_underlying(button))) != 0; } std::uint32_t ButtonSet::raw_bits() const { diff --git a/src/include/libvirtualhid/runtime.hpp b/src/include/libvirtualhid/runtime.hpp index 5be54d2..1294fa7 100644 --- a/src/include/libvirtualhid/runtime.hpp +++ b/src/include/libvirtualhid/runtime.hpp @@ -123,7 +123,7 @@ namespace lvh { Gamepad(detail::RuntimeConstructionToken token, std::shared_ptr device); /** - * @brief Destroy the gamepad handle. + * @brief Destroy the gamepad handle and close the virtual device if it is still open. */ ~Gamepad() override; @@ -248,7 +248,7 @@ namespace lvh { Keyboard(detail::RuntimeConstructionToken token, std::shared_ptr device); /** - * @brief Destroy the keyboard handle. + * @brief Destroy the keyboard handle and close the virtual device if it is still open. */ ~Keyboard() override; @@ -368,7 +368,7 @@ namespace lvh { Mouse(detail::RuntimeConstructionToken token, std::shared_ptr device); /** - * @brief Destroy the mouse handle. + * @brief Destroy the mouse handle and close the virtual device if it is still open. */ ~Mouse() override; @@ -509,7 +509,7 @@ namespace lvh { Touchscreen(detail::RuntimeConstructionToken token, std::shared_ptr device); /** - * @brief Destroy the touchscreen handle. + * @brief Destroy the touchscreen handle and close the virtual device if it is still open. */ ~Touchscreen() override; @@ -613,7 +613,7 @@ namespace lvh { Trackpad(detail::RuntimeConstructionToken token, std::shared_ptr device); /** - * @brief Destroy the trackpad handle. + * @brief Destroy the trackpad handle and close the virtual device if it is still open. */ ~Trackpad() override; @@ -725,7 +725,7 @@ namespace lvh { PenTablet(detail::RuntimeConstructionToken token, std::shared_ptr device); /** - * @brief Destroy the pen tablet handle. + * @brief Destroy the pen tablet handle and close the virtual device if it is still open. */ ~PenTablet() override; diff --git a/src/platform/linux/uhid_backend.cpp b/src/platform/linux/uhid_backend.cpp index ce24e4c..a6d8633 100644 --- a/src/platform/linux/uhid_backend.cpp +++ b/src/platform/linux/uhid_backend.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -63,7 +64,7 @@ #include namespace lvh::detail { - namespace { + namespace { // NOSONAR(cpp:S1000): Linux backend internals need internal linkage; tests include this file with syscall overrides. constexpr auto uhid_path = "/dev/uhid"; constexpr auto uinput_path = "/dev/uinput"; @@ -227,8 +228,8 @@ namespace lvh::detail { return ::close(fd); } - std::ptrdiff_t system_write(int fd, const void *buffer, std::size_t size) { - return static_cast(::write(fd, buffer, size)); + std::ptrdiff_t system_write(int fd, std::span buffer) { + return static_cast(::write(fd, buffer.data(), buffer.size())); } int system_ioctl(int fd, unsigned long request, unsigned long argument = 0) { @@ -239,8 +240,8 @@ namespace lvh::detail { return ::poll(descriptors, descriptor_count, timeout); } - std::ptrdiff_t system_read(int fd, void *buffer, std::size_t size) { - return static_cast(::read(fd, buffer, size)); + std::ptrdiff_t system_read(int fd, std::span buffer) { + return static_cast(::read(fd, buffer.data(), buffer.size())); } std::string errno_message(int error) { @@ -303,10 +304,10 @@ namespace lvh::detail { return stream.str(); } - std::uint32_t crc32(const std::uint8_t *buffer, std::size_t length, std::uint32_t seed = 0) { + std::uint32_t crc32(std::span buffer, std::uint32_t seed = 0) { auto crc = seed ^ 0xFFFFFFFFU; - for (std::size_t index = 0; index < length; ++index) { - crc ^= buffer[index]; + for (const auto byte : buffer) { + crc ^= byte; for (auto bit = 0; bit < 8; ++bit) { const auto mask = 0U - (crc & 1U); crc = (crc >> 1U) ^ (0xEDB88320U & mask); @@ -316,7 +317,7 @@ namespace lvh::detail { } std::uint32_t dualsense_crc_seed(std::uint8_t seed) { - return crc32(&seed, 1U); + return crc32(std::span {&seed, 1U}); } void write_u32_le(std::uint8_t *buffer, std::uint32_t value) { @@ -446,91 +447,73 @@ namespace lvh::detail { return system_error_status(ErrorCode::backend_failure, operation, errno); } + template + std::optional mapped_keyboard_code( + KeyboardKeyCode key_code, + const std::array, Size> &mappings + ) { + const auto it = std::ranges::find_if(mappings, [key_code](const auto &mapping) { + return mapping.first == key_code; + }); + if (it == mappings.end()) { + return std::nullopt; + } + return it->second; + } + int key_code_to_linux(KeyboardKeyCode key_code) { - switch (key_code) { - case 0x08: - return KEY_BACKSPACE; - case 0x09: - return KEY_TAB; - case 0x0D: - return KEY_ENTER; - case 0x10: - case 0xA0: - return KEY_LEFTSHIFT; - case 0x11: - case 0xA2: - return KEY_LEFTCTRL; - case 0x12: - case 0xA4: - return KEY_LEFTALT; - case 0x14: - return KEY_CAPSLOCK; - case 0x1B: - return KEY_ESC; - case 0x20: - return KEY_SPACE; - case 0x21: - return KEY_PAGEUP; - case 0x22: - return KEY_PAGEDOWN; - case 0x23: - return KEY_END; - case 0x24: - return KEY_HOME; - case 0x25: - return KEY_LEFT; - case 0x26: - return KEY_UP; - case 0x27: - return KEY_RIGHT; - case 0x28: - return KEY_DOWN; - case 0x2C: - return KEY_SYSRQ; - case 0x2D: - return KEY_INSERT; - case 0x2E: - return KEY_DELETE; - case 0x5B: - return KEY_LEFTMETA; - case 0x5C: - return KEY_RIGHTMETA; - case 0x90: - return KEY_NUMLOCK; - case 0x91: - return KEY_SCROLLLOCK; - case 0xA1: - return KEY_RIGHTSHIFT; - case 0xA3: - return KEY_RIGHTCTRL; - case 0xA5: - return KEY_RIGHTALT; - case 0xBA: - return KEY_SEMICOLON; - case 0xBB: - return KEY_EQUAL; - case 0xBC: - return KEY_COMMA; - case 0xBD: - return KEY_MINUS; - case 0xBE: - return KEY_DOT; - case 0xBF: - return KEY_SLASH; - case 0xC0: - return KEY_GRAVE; - case 0xDB: - return KEY_LEFTBRACE; - case 0xDC: - return KEY_BACKSLASH; - case 0xDD: - return KEY_RIGHTBRACE; - case 0xDE: - return KEY_APOSTROPHE; - case 0xE2: - return KEY_102ND; - default: - break; + static constexpr std::array, 47> special_keys {{ + {0x08, KEY_BACKSPACE}, + {0x09, KEY_TAB}, + {0x0D, KEY_ENTER}, + {0x10, KEY_LEFTSHIFT}, + {0xA0, KEY_LEFTSHIFT}, + {0x11, KEY_LEFTCTRL}, + {0xA2, KEY_LEFTCTRL}, + {0x12, KEY_LEFTALT}, + {0xA4, KEY_LEFTALT}, + {0x14, KEY_CAPSLOCK}, + {0x1B, KEY_ESC}, + {0x20, KEY_SPACE}, + {0x21, KEY_PAGEUP}, + {0x22, KEY_PAGEDOWN}, + {0x23, KEY_END}, + {0x24, KEY_HOME}, + {0x25, KEY_LEFT}, + {0x26, KEY_UP}, + {0x27, KEY_RIGHT}, + {0x28, KEY_DOWN}, + {0x2C, KEY_SYSRQ}, + {0x2D, KEY_INSERT}, + {0x2E, KEY_DELETE}, + {0x5B, KEY_LEFTMETA}, + {0x5C, KEY_RIGHTMETA}, + {0x6A, KEY_KPASTERISK}, + {0x6B, KEY_KPPLUS}, + {0x6D, KEY_KPMINUS}, + {0x6E, KEY_KPDOT}, + {0x6F, KEY_KPSLASH}, + {0x90, KEY_NUMLOCK}, + {0x91, KEY_SCROLLLOCK}, + {0xA1, KEY_RIGHTSHIFT}, + {0xA3, KEY_RIGHTCTRL}, + {0xA5, KEY_RIGHTALT}, + {0xBA, KEY_SEMICOLON}, + {0xBB, KEY_EQUAL}, + {0xBC, KEY_COMMA}, + {0xBD, KEY_MINUS}, + {0xBE, KEY_DOT}, + {0xBF, KEY_SLASH}, + {0xC0, KEY_GRAVE}, + {0xDB, KEY_LEFTBRACE}, + {0xDC, KEY_BACKSLASH}, + {0xDD, KEY_RIGHTBRACE}, + {0xDE, KEY_APOSTROPHE}, + {0xE2, KEY_102ND}, + }}; + + if (const auto linux_key = mapped_keyboard_code(key_code, special_keys); linux_key.has_value()) { + return linux_key.value(); } if (key_code >= 0x30 && key_code <= 0x39) { @@ -594,21 +577,6 @@ namespace lvh::detail { }; return keypad_digit_keys[key_code - 0x60]; } - if (key_code == 0x6A) { - return KEY_KPASTERISK; - } - if (key_code == 0x6B) { - return KEY_KPPLUS; - } - if (key_code == 0x6D) { - return KEY_KPMINUS; - } - if (key_code == 0x6E) { - return KEY_KPDOT; - } - if (key_code == 0x6F) { - return KEY_KPSLASH; - } if (key_code >= 0x70 && key_code <= 0x87) { static constexpr std::array function_keys { KEY_F1, @@ -735,9 +703,7 @@ namespace lvh::detail { } std::string uppercase_hex(std::uint32_t codepoint) { - std::ostringstream stream; - stream << std::uppercase << std::hex << codepoint; - return stream.str(); + return std::format("{:X}", codepoint); } KeyboardKeyCode hex_digit_key_code(char digit) { @@ -828,7 +794,8 @@ namespace lvh::detail { event.code = code; event.value = value; - const auto result = system_write(fd_, &event, sizeof(event)); + const auto event_buffer = std::as_bytes(std::span {&event, 1U}); + const auto result = system_write(fd_, event_buffer); if (result < 0) { return system_error_status(ErrorCode::backend_failure, "failed to write uinput event", errno); } @@ -894,7 +861,7 @@ namespace lvh::detail { ) { return libevdev_status( libevdev_enable_event_code(device, type, code, absinfo), - "failed to enable " + description + " " + std::to_string(code) + std::format("failed to enable {} {}", description, code) ); } @@ -1138,7 +1105,7 @@ namespace lvh::detail { return { OperationStatus::failure( ErrorCode::backend_failure, - "failed to create uinput device " + std::to_string(id) + ": " + errno_message(-result) + std::format("failed to create uinput device {}: {}", id, errno_message(-result)) ), nullptr, }; @@ -1730,54 +1697,19 @@ namespace lvh::detail { return OperationStatus::failure(ErrorCode::device_closed, "uinput pen tablet is closed"); } - if (state.tool != PenToolType::unchanged && state.tool != last_tool_) { - const auto tool_code = pen_tool_to_linux(state.tool); - if (tool_code >= 0) { - if (const auto status = emit_event(EV_KEY, static_cast(tool_code), 1); !status.ok()) { - return status; - } - } - const auto last_tool_code = pen_tool_to_linux(last_tool_); - if (last_tool_code >= 0) { - if (const auto status = emit_event(EV_KEY, static_cast(last_tool_code), 0); !status.ok()) { - return status; - } - } - last_tool_ = state.tool; - } - - if (const auto status = emit_event(EV_ABS, ABS_X, scale_normalized_axis(state.x, touch_axis_max_x)); !status.ok()) { + if (const auto status = update_pen_tool(state.tool); !status.ok()) { return status; } - if (const auto status = emit_event(EV_ABS, ABS_Y, scale_normalized_axis(state.y, touch_axis_max_y)); !status.ok()) { + if (const auto status = emit_pen_position(state); !status.ok()) { return status; } - if (state.pressure >= 0.0F) { - if (const auto status = emit_event(EV_ABS, ABS_PRESSURE, scale_normalized_axis(state.pressure, tablet_pressure_max)); !status.ok()) { - return status; - } - if (const auto status = emit_event(EV_ABS, ABS_DISTANCE, 0); !status.ok()) { - return status; - } - if (const auto status = emit_event(EV_KEY, BTN_TOUCH, state.pressure > 0.0F ? 1 : 0); !status.ok()) { - return status; - } - } - if (state.distance >= 0.0F) { - if (const auto status = emit_event(EV_ABS, ABS_DISTANCE, scale_normalized_axis(state.distance, tablet_distance_max)); !status.ok()) { - return status; - } - if (const auto status = emit_event(EV_ABS, ABS_PRESSURE, 0); !status.ok()) { - return status; - } - if (const auto status = emit_event(EV_KEY, BTN_TOUCH, 0); !status.ok()) { - return status; - } + if (const auto status = emit_pen_pressure(state.pressure); !status.ok()) { + return status; } - if (const auto status = emit_event(EV_ABS, ABS_TILT_X, tablet_tilt_units(state.tilt_x)); !status.ok()) { + if (const auto status = emit_pen_distance(state.distance); !status.ok()) { return status; } - if (const auto status = emit_event(EV_ABS, ABS_TILT_Y, tablet_tilt_units(state.tilt_y)); !status.ok()) { + if (const auto status = emit_pen_tilt(state); !status.ok()) { return status; } return sync(); @@ -1802,92 +1734,124 @@ namespace lvh::detail { } private: + OperationStatus emit_pen_tool(PenToolType tool, std::int32_t value) { + const auto tool_code = pen_tool_to_linux(tool); + if (tool_code < 0) { + return OperationStatus::success(); + } + return emit_event(EV_KEY, static_cast(tool_code), value); + } + + OperationStatus update_pen_tool(PenToolType tool) { + if (tool == PenToolType::unchanged || tool == last_tool_) { + return OperationStatus::success(); + } + if (const auto status = emit_pen_tool(tool, 1); !status.ok()) { + return status; + } + if (const auto status = emit_pen_tool(last_tool_, 0); !status.ok()) { + return status; + } + last_tool_ = tool; + return OperationStatus::success(); + } + + OperationStatus emit_pen_position(const PenToolState &state) { + if (const auto status = emit_event(EV_ABS, ABS_X, scale_normalized_axis(state.x, touch_axis_max_x)); !status.ok()) { + return status; + } + return emit_event(EV_ABS, ABS_Y, scale_normalized_axis(state.y, touch_axis_max_y)); + } + + OperationStatus emit_pen_pressure(float pressure) { + if (pressure < 0.0F) { + return OperationStatus::success(); + } + if (const auto status = emit_event(EV_ABS, ABS_PRESSURE, scale_normalized_axis(pressure, tablet_pressure_max)); !status.ok()) { + return status; + } + if (const auto status = emit_event(EV_ABS, ABS_DISTANCE, 0); !status.ok()) { + return status; + } + return emit_event(EV_KEY, BTN_TOUCH, pressure > 0.0F ? 1 : 0); + } + + OperationStatus emit_pen_distance(float distance) { + if (distance < 0.0F) { + return OperationStatus::success(); + } + if (const auto status = emit_event(EV_ABS, ABS_DISTANCE, scale_normalized_axis(distance, tablet_distance_max)); !status.ok()) { + return status; + } + if (const auto status = emit_event(EV_ABS, ABS_PRESSURE, 0); !status.ok()) { + return status; + } + return emit_event(EV_KEY, BTN_TOUCH, 0); + } + + OperationStatus emit_pen_tilt(const PenToolState &state) { + if (const auto status = emit_event(EV_ABS, ABS_TILT_X, tablet_tilt_units(state.tilt_x)); !status.ok()) { + return status; + } + return emit_event(EV_ABS, ABS_TILT_Y, tablet_tilt_units(state.tilt_y)); + } + std::string device_name_; PenToolType last_tool_ = PenToolType::unchanged; }; #if defined(LIBVIRTUALHID_HAVE_XTEST) KeySym key_code_to_keysym(KeyboardKeyCode key_code) { - switch (key_code) { - case 0x08: - return XK_BackSpace; - case 0x09: - return XK_Tab; - case 0x0D: - return XK_Return; - case 0x10: - case 0xA0: - return XK_Shift_L; - case 0x11: - case 0xA2: - return XK_Control_L; - case 0x12: - case 0xA4: - return XK_Alt_L; - case 0x14: - return XK_Caps_Lock; - case 0x1B: - return XK_Escape; - case 0x20: - return XK_space; - case 0x21: - return XK_Page_Up; - case 0x22: - return XK_Page_Down; - case 0x23: - return XK_End; - case 0x24: - return XK_Home; - case 0x25: - return XK_Left; - case 0x26: - return XK_Up; - case 0x27: - return XK_Right; - case 0x28: - return XK_Down; - case 0x2D: - return XK_Insert; - case 0x2E: - return XK_Delete; - case 0x5B: - return XK_Super_L; - case 0x5C: - return XK_Super_R; - case 0x90: - return XK_Num_Lock; - case 0x91: - return XK_Scroll_Lock; - case 0xA1: - return XK_Shift_R; - case 0xA3: - return XK_Control_R; - case 0xA5: - return XK_Alt_R; - case 0xBA: - return XK_semicolon; - case 0xBB: - return XK_equal; - case 0xBC: - return XK_comma; - case 0xBD: - return XK_minus; - case 0xBE: - return XK_period; - case 0xBF: - return XK_slash; - case 0xC0: - return XK_grave; - case 0xDB: - return XK_bracketleft; - case 0xDC: - return XK_backslash; - case 0xDD: - return XK_bracketright; - case 0xDE: - return XK_apostrophe; - default: - break; + static constexpr std::array, 45> special_keysyms {{ + {0x08, XK_BackSpace}, + {0x09, XK_Tab}, + {0x0D, XK_Return}, + {0x10, XK_Shift_L}, + {0xA0, XK_Shift_L}, + {0x11, XK_Control_L}, + {0xA2, XK_Control_L}, + {0x12, XK_Alt_L}, + {0xA4, XK_Alt_L}, + {0x14, XK_Caps_Lock}, + {0x1B, XK_Escape}, + {0x20, XK_space}, + {0x21, XK_Page_Up}, + {0x22, XK_Page_Down}, + {0x23, XK_End}, + {0x24, XK_Home}, + {0x25, XK_Left}, + {0x26, XK_Up}, + {0x27, XK_Right}, + {0x28, XK_Down}, + {0x2D, XK_Insert}, + {0x2E, XK_Delete}, + {0x5B, XK_Super_L}, + {0x5C, XK_Super_R}, + {0x6A, XK_KP_Multiply}, + {0x6B, XK_KP_Add}, + {0x6D, XK_KP_Subtract}, + {0x6E, XK_KP_Decimal}, + {0x6F, XK_KP_Divide}, + {0x90, XK_Num_Lock}, + {0x91, XK_Scroll_Lock}, + {0xA1, XK_Shift_R}, + {0xA3, XK_Control_R}, + {0xA5, XK_Alt_R}, + {0xBA, XK_semicolon}, + {0xBB, XK_equal}, + {0xBC, XK_comma}, + {0xBD, XK_minus}, + {0xBE, XK_period}, + {0xBF, XK_slash}, + {0xC0, XK_grave}, + {0xDB, XK_bracketleft}, + {0xDC, XK_backslash}, + {0xDD, XK_bracketright}, + {0xDE, XK_apostrophe}, + }}; + + if (const auto keysym = mapped_keyboard_code(key_code, special_keysyms); keysym.has_value()) { + return keysym.value(); } if (key_code >= 0x30 && key_code <= 0x39) { @@ -1899,21 +1863,6 @@ namespace lvh::detail { if (key_code >= 0x60 && key_code <= 0x69) { return XK_KP_0 + static_cast(key_code - 0x60); } - if (key_code == 0x6A) { - return XK_KP_Multiply; - } - if (key_code == 0x6B) { - return XK_KP_Add; - } - if (key_code == 0x6D) { - return XK_KP_Subtract; - } - if (key_code == 0x6E) { - return XK_KP_Decimal; - } - if (key_code == 0x6F) { - return XK_KP_Divide; - } if (key_code >= 0x70 && key_code <= 0x87) { return XK_F1 + static_cast(key_code - 0x70); } @@ -2178,7 +2127,7 @@ namespace lvh::detail { } copy_string(request.name, options.profile.name); - copy_string(request.phys, "libvirtualhid/uhid/" + std::to_string(id)); + copy_string(request.phys, std::format("libvirtualhid/uhid/{}", id)); copy_string(request.uniq, unique_id); request.rd_size = static_cast(options.profile.report_descriptor.size()); request.bus = to_uhid_bus(options.profile.bus_type); @@ -2285,7 +2234,8 @@ namespace lvh::detail { return OperationStatus::failure(device_closed, "UHID file descriptor is closed"); } - const auto result = system_write(fd_, &event, sizeof(event)); + const auto event_buffer = std::as_bytes(std::span {&event, 1U}); + const auto result = system_write(fd_, event_buffer); if (result < 0) { return system_error_status(backend_failure, "failed to write UHID event", errno); } @@ -2320,7 +2270,7 @@ namespace lvh::detail { } uhid_event event {}; - const auto read_result = system_read(fd_, &event, sizeof(event)); + const auto read_result = system_read(fd_, std::as_writable_bytes(std::span {&event, 1U})); if (read_result < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { continue; @@ -2418,8 +2368,7 @@ namespace lvh::detail { if (profile_.bus_type == BusType::bluetooth && event.u.get_report_reply.err == 0 && event.u.get_report_reply.size >= 4U) { const auto crc_offset = static_cast(event.u.get_report_reply.size) - 4U; const auto crc = crc32( - event.u.get_report_reply.data, - crc_offset, + std::span {event.u.get_report_reply.data, crc_offset}, dualsense_crc_seed(dualsense_feature_crc_seed) ); write_u32_le(event.u.get_report_reply.data + crc_offset, crc); diff --git a/tests/fixtures/linux_backend_test_hooks.cpp b/tests/fixtures/linux_backend_test_hooks.cpp index 01886cc..eba1d36 100644 --- a/tests/fixtures/linux_backend_test_hooks.cpp +++ b/tests/fixtures/linux_backend_test_hooks.cpp @@ -115,7 +115,7 @@ namespace lvh::detail::test { } #endif - struct LinuxTestSyscalls { + struct LinuxTestSyscalls { // NOSONAR(cpp:S1820): Test-only fake syscall state keeps related Linux hook controls visible at call sites. bool override_access = false; int access_result = 0; bool override_open = false; @@ -155,13 +155,16 @@ namespace lvh::detail::test { std::size_t libevdev_destroy_count = 0; }; - LinuxTestSyscalls *active_test_syscalls = nullptr; + LinuxTestSyscalls *&active_test_syscalls() { + static LinuxTestSyscalls *syscalls = nullptr; + return syscalls; + } class ScopedLinuxTestSyscalls { public: explicit ScopedLinuxTestSyscalls(LinuxTestSyscalls &syscalls): - previous_ {active_test_syscalls} { - active_test_syscalls = &syscalls; + previous_ {active_test_syscalls()} { + active_test_syscalls() = &syscalls; } ScopedLinuxTestSyscalls(const ScopedLinuxTestSyscalls &) = delete; @@ -170,7 +173,7 @@ namespace lvh::detail::test { ScopedLinuxTestSyscalls &operator=(ScopedLinuxTestSyscalls &&) noexcept = delete; ~ScopedLinuxTestSyscalls() { - active_test_syscalls = previous_; + active_test_syscalls() = previous_; } private: @@ -180,21 +183,28 @@ namespace lvh::detail::test { } // namespace } // namespace lvh::detail::test +namespace { + + constexpr auto free_real_libevdev = &::libevdev_free; + constexpr auto destroy_real_libevdev_uinput = &::libevdev_uinput_destroy; + +} // namespace + int lvh_linux_test_access(const char *path, int mode) { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_access) { - if (lvh::detail::test::active_test_syscalls->access_result < 0) { + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_access) { + if (lvh::detail::test::active_test_syscalls()->access_result < 0) { errno = EACCES; } - return lvh::detail::test::active_test_syscalls->access_result; + return lvh::detail::test::active_test_syscalls()->access_result; } return ::access(path, mode); } int lvh_linux_test_open(const char *path, int flags) { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_open) { - if (lvh::detail::test::active_test_syscalls->open_result < 0) { + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_open) { + if (lvh::detail::test::active_test_syscalls()->open_result < 0) { errno = ENOENT; - return lvh::detail::test::active_test_syscalls->open_result; + return lvh::detail::test::active_test_syscalls()->open_result; } const auto fd = ::open("/dev/null", O_RDWR); if (fd < 0) { @@ -205,15 +215,15 @@ int lvh_linux_test_open(const char *path, int flags) { return ::open(path, flags); } -std::ptrdiff_t lvh_linux_test_write(int fd, const void *buffer, std::size_t size) { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_write) { - const auto call_count = ++lvh::detail::test::active_test_syscalls->write_call_count; - if (lvh::detail::test::active_test_syscalls->fail_write_call == call_count) { +std::ptrdiff_t lvh_linux_test_write(int fd, const std::byte *buffer, std::size_t size) { + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_write) { + const auto call_count = ++lvh::detail::test::active_test_syscalls()->write_call_count; + if (lvh::detail::test::active_test_syscalls()->fail_write_call == call_count) { errno = EIO; return -1; } - if (lvh::detail::test::active_test_syscalls->short_write_call == call_count) { - return static_cast(lvh::detail::test::active_test_syscalls->short_write_size); + if (lvh::detail::test::active_test_syscalls()->short_write_call == call_count) { + return static_cast(lvh::detail::test::active_test_syscalls()->short_write_size); } return static_cast(size); } @@ -221,9 +231,9 @@ std::ptrdiff_t lvh_linux_test_write(int fd, const void *buffer, std::size_t size } int lvh_linux_test_ioctl(int fd, unsigned long request, unsigned long argument) { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_ioctl) { - if (const auto call_count = ++lvh::detail::test::active_test_syscalls->ioctl_call_count; - lvh::detail::test::active_test_syscalls->fail_ioctl_call == call_count) { + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_ioctl) { + if (const auto call_count = ++lvh::detail::test::active_test_syscalls()->ioctl_call_count; + lvh::detail::test::active_test_syscalls()->fail_ioctl_call == call_count) { errno = EINVAL; return -1; } @@ -233,23 +243,23 @@ int lvh_linux_test_ioctl(int fd, unsigned long request, unsigned long argument) } int lvh_linux_test_poll(pollfd *descriptors, nfds_t descriptor_count, int timeout) { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_poll) { - const auto call_index = static_cast(lvh::detail::test::active_test_syscalls->poll_call_count++); + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_poll) { + const auto call_index = static_cast(lvh::detail::test::active_test_syscalls()->poll_call_count++); auto result = 0; - if (call_index < lvh::detail::test::active_test_syscalls->poll_results.size()) { - result = lvh::detail::test::active_test_syscalls->poll_results[call_index]; + if (call_index < lvh::detail::test::active_test_syscalls()->poll_results.size()) { + result = lvh::detail::test::active_test_syscalls()->poll_results[call_index]; } if (descriptor_count > 0) { descriptors[0].revents = 0; - if (result > 0 && call_index < lvh::detail::test::active_test_syscalls->poll_revents.size()) { - descriptors[0].revents = lvh::detail::test::active_test_syscalls->poll_revents[call_index]; + if (result > 0 && call_index < lvh::detail::test::active_test_syscalls()->poll_revents.size()) { + descriptors[0].revents = lvh::detail::test::active_test_syscalls()->poll_revents[call_index]; } } if (result < 0) { - errno = call_index < lvh::detail::test::active_test_syscalls->poll_errors.size() ? - lvh::detail::test::active_test_syscalls->poll_errors[call_index] : + errno = call_index < lvh::detail::test::active_test_syscalls()->poll_errors.size() ? + lvh::detail::test::active_test_syscalls()->poll_errors[call_index] : EIO; } return result; @@ -257,24 +267,24 @@ int lvh_linux_test_poll(pollfd *descriptors, nfds_t descriptor_count, int timeou return ::poll(descriptors, descriptor_count, timeout); } -std::ptrdiff_t lvh_linux_test_read(int fd, void *buffer, std::size_t size) { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_read) { - const auto call_index = static_cast(lvh::detail::test::active_test_syscalls->read_call_count++); +std::ptrdiff_t lvh_linux_test_read(int fd, std::byte *buffer, std::size_t size) { + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_read) { + const auto call_index = static_cast(lvh::detail::test::active_test_syscalls()->read_call_count++); auto result = std::ptrdiff_t {0}; - if (call_index < lvh::detail::test::active_test_syscalls->read_results.size()) { - result = lvh::detail::test::active_test_syscalls->read_results[call_index]; + if (call_index < lvh::detail::test::active_test_syscalls()->read_results.size()) { + result = lvh::detail::test::active_test_syscalls()->read_results[call_index]; } if (result < 0) { - errno = call_index < lvh::detail::test::active_test_syscalls->read_errors.size() ? - lvh::detail::test::active_test_syscalls->read_errors[call_index] : + errno = call_index < lvh::detail::test::active_test_syscalls()->read_errors.size() ? + lvh::detail::test::active_test_syscalls()->read_errors[call_index] : EIO; return result; } if (result > 0) { const auto bytes = std::min(static_cast(result), std::min(size, sizeof(uhid_event))); - std::memcpy(buffer, &lvh::detail::test::active_test_syscalls->read_event, bytes); + std::memcpy(buffer, &lvh::detail::test::active_test_syscalls()->read_event, bytes); return static_cast(bytes); } @@ -293,16 +303,16 @@ int lvh_linux_test_x_close_display(Display *) { } Bool lvh_linux_test_xtest_query_extension(Display *, int *, int *, int *, int *) { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_xtest_query) { - return lvh::detail::test::active_test_syscalls->xtest_query_result ? True : False; + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_xtest_query) { + return lvh::detail::test::active_test_syscalls()->xtest_query_result ? True : False; } return True; } KeyCode lvh_linux_test_x_keysym_to_keycode(Display *, KeySym keysym) { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_x_keycode) { - const auto call_count = ++lvh::detail::test::active_test_syscalls->x_keycode_call_count; - if (lvh::detail::test::active_test_syscalls->fail_x_keycode_call == call_count) { + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_x_keycode) { + const auto call_count = ++lvh::detail::test::active_test_syscalls()->x_keycode_call_count; + if (lvh::detail::test::active_test_syscalls()->fail_x_keycode_call == call_count) { return 0; } } @@ -343,34 +353,34 @@ int lvh_linux_test_xtest_fake_relative_motion_event(Display *, int, int, unsigne #endif extern "C" libevdev *lvh_linux_test_libevdev_new() { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_libevdev) { - if (lvh::detail::test::active_test_syscalls->libevdev_new_returns_null) { + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_libevdev) { + if (lvh::detail::test::active_test_syscalls()->libevdev_new_returns_null) { return nullptr; } auto fake_device = std::make_unique(); auto *created_device = fake_device.get(); - lvh::detail::test::active_test_syscalls->owned_libevdev_devices.push_back(std::move(fake_device)); + lvh::detail::test::active_test_syscalls()->owned_libevdev_devices.push_back(std::move(fake_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_handle = lvh::detail::test::fake_libevdev_device(device); +extern "C" void lvh_linux_test_libevdev_free(libevdev *raw_libevdev_handle) { + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_libevdev) { + auto *fake_device_handle = lvh::detail::test::fake_libevdev_device(raw_libevdev_handle); static_cast(std::erase_if( - lvh::detail::test::active_test_syscalls->owned_libevdev_devices, + lvh::detail::test::active_test_syscalls()->owned_libevdev_devices, [fake_device_handle](const auto &owned_device) { return owned_device.get() == fake_device_handle; } )); return; } - ::libevdev_free(device); + free_real_libevdev(raw_libevdev_handle); } extern "C" void lvh_linux_test_libevdev_set_name(libevdev *device, const char *name) { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_libevdev) { + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_libevdev) { lvh::detail::test::fake_libevdev_device(device)->name = name == nullptr ? "" : name; return; } @@ -378,7 +388,7 @@ extern "C" void lvh_linux_test_libevdev_set_name(libevdev *device, const char *n } extern "C" void lvh_linux_test_libevdev_set_id_bustype(libevdev *device, int bustype) { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_libevdev) { + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_libevdev) { lvh::detail::test::fake_libevdev_device(device)->bustype = static_cast(bustype); return; } @@ -386,7 +396,7 @@ extern "C" void lvh_linux_test_libevdev_set_id_bustype(libevdev *device, int bus } extern "C" void lvh_linux_test_libevdev_set_id_vendor(libevdev *device, int vendor) { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_libevdev) { + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_libevdev) { lvh::detail::test::fake_libevdev_device(device)->vendor = static_cast(vendor); return; } @@ -394,7 +404,7 @@ extern "C" void lvh_linux_test_libevdev_set_id_vendor(libevdev *device, int vend } extern "C" void lvh_linux_test_libevdev_set_id_product(libevdev *device, int product) { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_libevdev) { + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_libevdev) { lvh::detail::test::fake_libevdev_device(device)->product = static_cast(product); return; } @@ -402,7 +412,7 @@ extern "C" void lvh_linux_test_libevdev_set_id_product(libevdev *device, int pro } extern "C" void lvh_linux_test_libevdev_set_id_version(libevdev *device, int version) { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_libevdev) { + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_libevdev) { lvh::detail::test::fake_libevdev_device(device)->version = static_cast(version); return; } @@ -410,8 +420,8 @@ extern "C" void lvh_linux_test_libevdev_set_id_version(libevdev *device, int ver } extern "C" int lvh_linux_test_libevdev_enable_event_type(libevdev *device, unsigned int type) { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_libevdev) { - if (lvh::detail::test::active_test_syscalls->fail_libevdev_event_type) { + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_libevdev) { + if (lvh::detail::test::active_test_syscalls()->fail_libevdev_event_type) { return -EIO; } lvh::detail::test::fake_libevdev_device(device)->event_types.push_back(type); @@ -426,8 +436,8 @@ extern "C" int lvh_linux_test_libevdev_enable_event_code( unsigned int code, const void *data ) { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_libevdev) { - if (lvh::detail::test::active_test_syscalls->fail_libevdev_event_code) { + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_libevdev) { + if (lvh::detail::test::active_test_syscalls()->fail_libevdev_event_code) { return -EIO; } @@ -451,8 +461,8 @@ extern "C" int lvh_linux_test_libevdev_enable_event_code( } extern "C" int lvh_linux_test_libevdev_enable_property(libevdev *device, unsigned int property) { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_libevdev) { - if (lvh::detail::test::active_test_syscalls->fail_libevdev_property) { + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_libevdev) { + if (lvh::detail::test::active_test_syscalls()->fail_libevdev_property) { return -EIO; } lvh::detail::test::fake_libevdev_device(device)->properties.push_back(property); @@ -466,36 +476,36 @@ extern "C" int lvh_linux_test_libevdev_uinput_create_from_device( int uinput_fd, libevdev_uinput **uinput_device ) { - if (lvh::detail::test::active_test_syscalls != nullptr && lvh::detail::test::active_test_syscalls->override_libevdev) { - if (lvh::detail::test::active_test_syscalls->fail_libevdev_create || uinput_fd < 0) { + if (lvh::detail::test::active_test_syscalls() != nullptr && lvh::detail::test::active_test_syscalls()->override_libevdev) { + if (lvh::detail::test::active_test_syscalls()->fail_libevdev_create || uinput_fd < 0) { return -EIO; } const auto &source_device = *lvh::detail::test::fake_libevdev_device(device); - lvh::detail::test::active_test_syscalls->libevdev_devices.push_back(source_device); + lvh::detail::test::active_test_syscalls()->libevdev_devices.push_back(source_device); auto owned_uinput_device = std::make_unique(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)); + 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; } return ::libevdev_uinput_create_from_device(device, uinput_fd, uinput_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_handle = lvh::detail::test::fake_libevdev_uinput(uinput_device); +extern "C" void lvh_linux_test_libevdev_uinput_destroy(libevdev_uinput *raw_uinput_handle) { + 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_handle = lvh::detail::test::fake_libevdev_uinput(raw_uinput_handle); static_cast(std::erase_if( - lvh::detail::test::active_test_syscalls->owned_libevdev_uinput_devices, + lvh::detail::test::active_test_syscalls()->owned_libevdev_uinput_devices, [fake_uinput_handle](const auto &owned_device) { return owned_device.get() == fake_uinput_handle; } )); return; } - ::libevdev_uinput_destroy(uinput_device); + destroy_real_libevdev_uinput(raw_uinput_handle); } #define access lvh_linux_test_access @@ -519,13 +529,13 @@ extern "C" void lvh_linux_test_libevdev_uinput_destroy(libevdev_uinput *uinput_d #if defined(LIBVIRTUALHID_HAVE_XTEST) #if defined(DefaultScreen) - #undef DefaultScreen + #undef DefaultScreen // NOSONAR(cpp:S959): X11 exposes this as a macro; the test hook replaces it while including the backend. #endif #if defined(DisplayHeight) - #undef DisplayHeight + #undef DisplayHeight // NOSONAR(cpp:S959): X11 exposes this as a macro; the test hook replaces it while including the backend. #endif #if defined(DisplayWidth) - #undef DisplayWidth + #undef DisplayWidth // NOSONAR(cpp:S959): X11 exposes this as a macro; the test hook replaces it while including the backend. #endif #define DefaultScreen lvh_linux_test_default_screen @@ -768,15 +778,11 @@ namespace lvh::detail::test { return OperationStatus::failure(ErrorCode::unsupported_profile, "unsupported fake uinput device type"); } - LinuxLibevdevCreationResult create_fake_libevdev_device( - DeviceType device_type, - void (*configure_failure)(LinuxTestSyscalls &) = nullptr - ) { + template + LinuxLibevdevCreationResult create_fake_libevdev_device(DeviceType device_type, ConfigureFailure configure_failure) { LinuxTestSyscalls syscalls; syscalls.override_libevdev = true; - if (configure_failure != nullptr) { - configure_failure(syscalls); - } + configure_failure(syscalls); ScopedLinuxTestSyscalls scoped_syscalls {syscalls}; LinuxLibevdevCreationResult result; @@ -805,6 +811,14 @@ namespace lvh::detail::test { return result; } + void keep_fake_libevdev_successful(const LinuxTestSyscalls &syscalls) { + static_cast(syscalls); + } + + LinuxLibevdevCreationResult create_fake_libevdev_device(DeviceType device_type) { + return create_fake_libevdev_device(device_type, keep_fake_libevdev_successful); + } + } // namespace std::string linux_copy_string_char_buffer(const std::string &source) { @@ -1364,7 +1378,7 @@ namespace lvh::detail::test { const auto report_size = static_cast(event.u.input2.size); if (report_size == options.profile.input_report_size && event.u.input2.data[0] == 0x31) { const auto crc_offset = report_size - 4U; - const auto expected_crc = crc32(event.u.input2.data, crc_offset, dualsense_crc_seed(0xA1)); + const auto expected_crc = crc32(std::span {event.u.input2.data, crc_offset}, dualsense_crc_seed(0xA1)); const auto actual_crc = read_u32_le(event.u.input2.data + crc_offset); result.saw_dualsense_bluetooth_input = expected_crc == actual_crc; } @@ -1384,8 +1398,7 @@ namespace lvh::detail::test { if (report_size >= 4U) { const auto crc_offset = report_size - 4U; const auto expected_crc = crc32( - event.u.get_report_reply.data, - crc_offset, + std::span {event.u.get_report_reply.data, crc_offset}, dualsense_crc_seed(dualsense_feature_crc_seed) ); const auto actual_crc = read_u32_le(event.u.get_report_reply.data + crc_offset); diff --git a/tests/unit/test_linux_backend.cpp b/tests/unit/test_linux_backend.cpp index b03b1e4..0ab9778 100644 --- a/tests/unit/test_linux_backend.cpp +++ b/tests/unit/test_linux_backend.cpp @@ -171,7 +171,9 @@ TEST_F(LinuxBackendTest, CoversLinuxDiscoveryAndIdentityHelpers) { EXPECT_EQ(lvh::detail::test::linux_dualsense_mac_address("02-03-04-05-06-07", 0x1020304), "02:00:01:02:03:04"); EXPECT_EQ(lvh::detail::test::linux_dualsense_mac_address("ff:00:100:00:00:00", 0x1020304), "02:00:01:02:03:04"); - const auto temp_dir = std::filesystem::temp_directory_path(); + const auto temp_dir = std::filesystem::current_path() / "cmake-build-linux-backend-test-scratch"; + std::filesystem::remove_all(temp_dir); + std::filesystem::create_directories(temp_dir); const auto first_line_path = temp_dir / "libvirtualhid-linux-first-line-test.txt"; const auto uevent_path = temp_dir / "libvirtualhid-linux-hidraw-uevent-test.txt"; @@ -251,9 +253,7 @@ TEST_F(LinuxBackendTest, CoversLinuxDiscoveryAndIdentityHelpers) { return node.kind == lvh::DeviceNodeKind::sysfs && node.path.starts_with(sysfs_root.string()); })); - std::filesystem::remove(first_line_path); - std::filesystem::remove(uevent_path); - std::filesystem::remove_all(sysfs_root); + std::filesystem::remove_all(temp_dir); } TEST_F(LinuxBackendTest, HandlesUhidInvalidFileDescriptorPaths) { diff --git a/tests/unit/test_linux_consumers.cpp b/tests/unit/test_linux_consumers.cpp index d48f65f..27f3498 100644 --- a/tests/unit/test_linux_consumers.cpp +++ b/tests/unit/test_linux_consumers.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -103,7 +104,7 @@ namespace { }; std::string unique_device_name(std::string_view suffix) { - return "libvirtualhid " + std::string {suffix} + " " + std::to_string(::getpid()); + return std::format("libvirtualhid {} {}", suffix, ::getpid()); } std::optional read_first_line(const std::filesystem::path &path) { @@ -464,14 +465,14 @@ namespace { } } - int open_restricted(const char *path, int flags, void *user_data) { + int open_restricted(const char *path, int flags, void *user_data) { // NOSONAR(cpp:S5008): libinput_interface is a C callback ABI with void* user data. static_cast(user_data); const auto fd = ::open(path, flags); return fd < 0 ? -errno : fd; } - void close_restricted(int fd, void *user_data) { + void close_restricted(int fd, void *user_data) { // NOSONAR(cpp:S5008): libinput_interface is a C callback ABI with void* user data. static_cast(user_data); ::close(fd); }