mirror of
https://github.com/LizardByte/Sunshine.git
synced 2026-11-05 19:58:24 +09:00
211 lines
7.5 KiB
C++
211 lines
7.5 KiB
C++
/**
|
|
* @file tests/unit/platform/windows/test_input.cpp
|
|
* @brief Tests for ViGEm rumble scaling and DualShock 4 report bytes.
|
|
*/
|
|
|
|
// test includes
|
|
#include "../../../tests_common.h"
|
|
|
|
#ifdef _WIN32
|
|
// standard includes
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <map>
|
|
#include <tuple>
|
|
|
|
// local includes
|
|
#include <src/platform/windows/input.h>
|
|
|
|
TEST(WindowsRumbleTest, PreservesTheEstablishedRangeForEveryAmplitude) {
|
|
for (unsigned strength = 0; strength <= 255; ++strength) {
|
|
EXPECT_EQ(platf::vigem::scale_rumble(static_cast<std::uint8_t>(strength)), strength * 256);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Driver-free DualShock 4 touch report and pointer state.
|
|
*/
|
|
class WindowsTouchTest: public testing::Test {
|
|
private:
|
|
DS4_REPORT_EX report_ {}; ///< Current device report.
|
|
std::map<std::uint32_t, std::uint8_t> pointers_; ///< Allocated client pointer IDs.
|
|
std::byte available_ {0x3}; ///< Both touch slots start available.
|
|
|
|
protected:
|
|
/**
|
|
* @brief Read the current DualShock 4 touch report.
|
|
*
|
|
* @return Const reference to the touch report.
|
|
*/
|
|
const DS4_TOUCH &report() const {
|
|
return report_.Report.sCurrentTouch;
|
|
}
|
|
|
|
/**
|
|
* @brief Read the allocated client pointer IDs.
|
|
*
|
|
* @return Const reference to the pointer-to-slot mapping.
|
|
*/
|
|
const std::map<std::uint32_t, std::uint8_t> &pointers() const {
|
|
return pointers_;
|
|
}
|
|
|
|
/**
|
|
* @brief Read the mask of free touch slots.
|
|
*
|
|
* @return Byte mask of available slots.
|
|
*/
|
|
std::byte available() const {
|
|
return available_;
|
|
}
|
|
|
|
/**
|
|
* @brief Set report counters before testing their byte wraparound.
|
|
*/
|
|
void prepare_counter_wraparound() {
|
|
report_.Report.sCurrentTouch.bPacketCounter = 0xFF;
|
|
report_.Report.sCurrentTouch.bIsUpTrackingNum1 = 0xFF;
|
|
}
|
|
|
|
/**
|
|
* @brief Mark both report slots up before each test.
|
|
*/
|
|
void SetUp() override {
|
|
report_.Report.sCurrentTouch.bIsUpTrackingNum1 = 0x80;
|
|
report_.Report.sCurrentTouch.bIsUpTrackingNum2 = 0x80;
|
|
}
|
|
|
|
/**
|
|
* @brief Apply a client touch event without submitting it to a driver.
|
|
*
|
|
* @param type Client event type.
|
|
* @param id Client pointer ID.
|
|
* @param x Normalized horizontal coordinate.
|
|
* @param y Normalized vertical coordinate.
|
|
* @return Whether the resulting report should be submitted.
|
|
*/
|
|
bool touch(std::uint8_t type, std::uint32_t id, float x = 0.0f, float y = 0.0f) {
|
|
return platf::vigem::update_touch(report_, pointers_, available_, {{0, 0}, type, id, x, y, 1.0f});
|
|
}
|
|
};
|
|
|
|
TEST_F(WindowsTouchTest, AllocatesBothSlotsAndPacksCoordinatesInWireOrder) {
|
|
ASSERT_TRUE(touch(LI_TOUCH_EVENT_DOWN, 10, 1.0f, 1.0f));
|
|
EXPECT_EQ(pointers().at(10), 0);
|
|
EXPECT_EQ(available(), std::byte {0x2});
|
|
EXPECT_EQ(report().bIsUpTrackingNum1, 1);
|
|
const std::array<std::uint8_t, 3> first {0x80, 0xF7, 0x3A};
|
|
EXPECT_TRUE(std::equal(first.begin(), first.end(), report().bTouchData1));
|
|
|
|
ASSERT_TRUE(touch(LI_TOUCH_EVENT_DOWN, 20, 0.5f, 0.5f));
|
|
EXPECT_EQ(pointers().at(20), 1);
|
|
EXPECT_EQ(available(), std::byte {0});
|
|
EXPECT_EQ(report().bIsUpTrackingNum2, 1);
|
|
const std::array<std::uint8_t, 3> second {0xC0, 0x73, 0x1D};
|
|
EXPECT_TRUE(std::equal(second.begin(), second.end(), report().bTouchData2));
|
|
EXPECT_EQ(report().bPacketCounter, 2);
|
|
|
|
EXPECT_FALSE(touch(LI_TOUCH_EVENT_DOWN, 30));
|
|
EXPECT_EQ(pointers().size(), 2U);
|
|
EXPECT_EQ(report().bPacketCounter, 2);
|
|
}
|
|
|
|
TEST_F(WindowsTouchTest, MovesReleasesCancelsAndReusesTheCorrectSlot) {
|
|
ASSERT_TRUE(touch(LI_TOUCH_EVENT_DOWN, 10));
|
|
ASSERT_TRUE(touch(LI_TOUCH_EVENT_DOWN, 20));
|
|
ASSERT_TRUE(touch(LI_TOUCH_EVENT_MOVE, 20, 1.0f, 1.0f));
|
|
EXPECT_EQ(report().bTouchData2[0], 0x80);
|
|
EXPECT_EQ(report().bTouchData1[0], 0);
|
|
EXPECT_EQ(available(), std::byte {0});
|
|
|
|
ASSERT_TRUE(touch(LI_TOUCH_EVENT_UP, 10));
|
|
EXPECT_EQ(report().bIsUpTrackingNum1, 0x81);
|
|
EXPECT_EQ(available(), std::byte {0x1});
|
|
EXPECT_FALSE(pointers().contains(10));
|
|
|
|
ASSERT_TRUE(touch(LI_TOUCH_EVENT_CANCEL, 20));
|
|
EXPECT_EQ(report().bIsUpTrackingNum2, 0x81);
|
|
EXPECT_EQ(available(), std::byte {0x3});
|
|
EXPECT_TRUE(pointers().empty());
|
|
|
|
ASSERT_TRUE(touch(LI_TOUCH_EVENT_DOWN, 30));
|
|
EXPECT_EQ(pointers().at(30), 0);
|
|
EXPECT_EQ(report().bIsUpTrackingNum1, 2);
|
|
}
|
|
|
|
TEST_F(WindowsTouchTest, CancelAllPreservesCoordinatesAndReleasesBothSlots) {
|
|
ASSERT_TRUE(touch(LI_TOUCH_EVENT_DOWN, 10, 1.0f, 1.0f));
|
|
ASSERT_TRUE(touch(LI_TOUCH_EVENT_DOWN, 20, 0.5f, 0.5f));
|
|
ASSERT_TRUE(touch(LI_TOUCH_EVENT_CANCEL_ALL, 0));
|
|
EXPECT_EQ(report().bIsUpTrackingNum1, 0x81);
|
|
EXPECT_EQ(report().bIsUpTrackingNum2, 0x81);
|
|
EXPECT_EQ(report().bTouchData1[0], 0x80);
|
|
EXPECT_EQ(report().bTouchData2[0], 0xC0);
|
|
EXPECT_EQ(report().bPacketCounter, 3);
|
|
EXPECT_EQ(available(), std::byte {0x3});
|
|
EXPECT_TRUE(pointers().empty());
|
|
}
|
|
|
|
TEST_F(WindowsTouchTest, RejectsUnknownPointersAndUnsupportedEventsWithoutUpdatingTheReport) {
|
|
EXPECT_FALSE(touch(LI_TOUCH_EVENT_MOVE, 10));
|
|
EXPECT_FALSE(touch(LI_TOUCH_EVENT_UP, 10));
|
|
ASSERT_TRUE(touch(LI_TOUCH_EVENT_DOWN, 10));
|
|
EXPECT_FALSE(touch(0xFF, 10));
|
|
EXPECT_EQ(report().bPacketCounter, 1);
|
|
EXPECT_EQ(report().bIsUpTrackingNum1, 1);
|
|
EXPECT_EQ(pointers().at(10), 0);
|
|
}
|
|
|
|
TEST_F(WindowsTouchTest, PreservesByteCounterWraparound) {
|
|
prepare_counter_wraparound();
|
|
ASSERT_TRUE(touch(LI_TOUCH_EVENT_DOWN, 10));
|
|
EXPECT_EQ(report().bPacketCounter, 0);
|
|
EXPECT_EQ(report().bIsUpTrackingNum1, 0x80);
|
|
}
|
|
|
|
/**
|
|
* @brief Initial status, client state, percentage, and expected status and level.
|
|
*/
|
|
using BatteryParam = std::tuple<std::uint8_t, std::uint8_t, std::uint8_t, std::uint8_t, std::uint8_t>;
|
|
|
|
/**
|
|
* @brief Battery report cases including special status and unknown percentage.
|
|
*/
|
|
struct WindowsBatteryTest: testing::TestWithParam<BatteryParam> {};
|
|
|
|
TEST_P(WindowsBatteryTest, PreservesTheExpectedStatusAndBatteryLevelBytes) {
|
|
const auto &[initial, state, percentage, expected_status, expected_level] = GetParam();
|
|
DS4_REPORT_EX report {};
|
|
report.Report.bBatteryLvlSpecial = initial;
|
|
report.Report.bBatteryLvl = 42;
|
|
platf::vigem::update_battery(report, {{0, 0}, state, percentage});
|
|
EXPECT_EQ(report.Report.bBatteryLvlSpecial, expected_status);
|
|
EXPECT_EQ(report.Report.bBatteryLvl, expected_level);
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
BatteryStates,
|
|
WindowsBatteryTest,
|
|
testing::Values(
|
|
BatteryParam {0x1F, LI_BATTERY_STATE_CHARGING, LI_BATTERY_PERCENTAGE_UNKNOWN, 0x15, 42},
|
|
BatteryParam {0x1F, LI_BATTERY_STATE_DISCHARGING, LI_BATTERY_PERCENTAGE_UNKNOWN, 0x05, 42},
|
|
BatteryParam {0x1F, LI_BATTERY_STATE_CHARGING, 75, 0x18, 191},
|
|
BatteryParam {0x1F, LI_BATTERY_STATE_DISCHARGING, 75, 0x05, 191},
|
|
BatteryParam {0x13, LI_BATTERY_STATE_CHARGING, 50, 0x15, 127},
|
|
BatteryParam {0x13, LI_BATTERY_STATE_DISCHARGING, LI_BATTERY_PERCENTAGE_UNKNOWN, 0x03, 42},
|
|
BatteryParam {0x13, LI_BATTERY_STATE_FULL, LI_BATTERY_PERCENTAGE_UNKNOWN, 0x1B, 255},
|
|
BatteryParam {0x13, LI_BATTERY_STATE_NOT_PRESENT, LI_BATTERY_PERCENTAGE_UNKNOWN, 0x1F, 42},
|
|
BatteryParam {0x13, LI_BATTERY_STATE_NOT_CHARGING, 50, 0x1F, 127},
|
|
BatteryParam {0x13, LI_BATTERY_STATE_UNKNOWN, LI_BATTERY_PERCENTAGE_UNKNOWN, 0x13, 42},
|
|
BatteryParam {0x03, LI_BATTERY_STATE_UNKNOWN, 50, 0x03, 127},
|
|
BatteryParam {0x1B, LI_BATTERY_STATE_UNKNOWN, 75, 0x1B, 191},
|
|
BatteryParam {0x13, LI_BATTERY_STATE_UNKNOWN, 0, 0x10, 0},
|
|
BatteryParam {0x13, LI_BATTERY_STATE_UNKNOWN, 4, 0x10, 10},
|
|
BatteryParam {0x13, LI_BATTERY_STATE_UNKNOWN, 5, 0x11, 12},
|
|
BatteryParam {0x13, LI_BATTERY_STATE_UNKNOWN, 95, 0x1A, 242},
|
|
BatteryParam {0x13, LI_BATTERY_STATE_UNKNOWN, 100, 0x1A, 255}
|
|
)
|
|
);
|
|
#endif
|