mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	input_common/udp: Port various changes from yuzu (#5133)
This commit is contained in:
		
							parent
							
								
									026a63bcf7
								
							
						
					
					
						commit
						32cbb1bc77
					
				
					 6 changed files with 102 additions and 82 deletions
				
			
		|  | @ -32,8 +32,16 @@ public: | |||
|                     SocketCallback callback) | ||||
|         : callback(std::move(callback)), timer(io_service), | ||||
|           socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(client_id), | ||||
|           pad_index(pad_index), | ||||
|           send_endpoint(udp::endpoint(boost::asio::ip::make_address_v4(host), port)) {} | ||||
|           pad_index(pad_index) { | ||||
|         boost::system::error_code ec{}; | ||||
|         auto ipv4 = boost::asio::ip::make_address_v4(host, ec); | ||||
|         if (ec.value() != boost::system::errc::success) { | ||||
|             LOG_ERROR(Input, "Invalid IPv4 address \"{}\" provided to socket", host); | ||||
|             ipv4 = boost::asio::ip::address_v4{}; | ||||
|         } | ||||
| 
 | ||||
|         send_endpoint = {udp::endpoint(ipv4, port)}; | ||||
|     } | ||||
| 
 | ||||
|     void Stop() { | ||||
|         io_service.stop(); | ||||
|  | @ -85,17 +93,18 @@ private: | |||
|     } | ||||
| 
 | ||||
|     void HandleSend(const boost::system::error_code& error) { | ||||
|         boost::system::error_code _ignored{}; | ||||
|         // Send a request for getting port info for the pad
 | ||||
|         Request::PortInfo port_info{1, {pad_index, 0, 0, 0}}; | ||||
|         auto port_message = Request::Create(port_info, client_id); | ||||
|         const auto port_message = Request::Create(port_info, client_id); | ||||
|         std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE); | ||||
|         std::size_t len = socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint); | ||||
|         socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored); | ||||
| 
 | ||||
|         // Send a request for getting pad data for the pad
 | ||||
|         Request::PadData pad_data{Request::PadData::Flags::Id, pad_index, EMPTY_MAC_ADDRESS}; | ||||
|         auto pad_message = Request::Create(pad_data, client_id); | ||||
|         const auto pad_message = Request::Create(pad_data, client_id); | ||||
|         std::memcpy(send_buffer2.data(), &pad_message, PAD_DATA_SIZE); | ||||
|         std::size_t len2 = socket.send_to(boost::asio::buffer(send_buffer2), send_endpoint); | ||||
|         socket.send_to(boost::asio::buffer(send_buffer2), send_endpoint, {}, _ignored); | ||||
|         StartSend(timer.expiry()); | ||||
|     } | ||||
| 
 | ||||
|  | @ -104,8 +113,8 @@ private: | |||
|     boost::asio::basic_waitable_timer<clock> timer; | ||||
|     udp::socket socket; | ||||
| 
 | ||||
|     u32 client_id; | ||||
|     u8 pad_index; | ||||
|     u32 client_id{}; | ||||
|     u8 pad_index{}; | ||||
| 
 | ||||
|     static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>); | ||||
|     static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message<Request::PadData>); | ||||
|  | @ -170,16 +179,16 @@ void Client::OnPadData(Response::PadData data) { | |||
| 
 | ||||
|         // TODO: add a setting for "click" touch. Click touch refers to a device that differentiates
 | ||||
|         // between a simple "tap" and a hard press that causes the touch screen to click.
 | ||||
|         bool is_active = data.touch_1.is_active != 0; | ||||
|         const bool is_active = data.touch_1.is_active != 0; | ||||
| 
 | ||||
|         float x = 0; | ||||
|         float y = 0; | ||||
| 
 | ||||
|         if (is_active && status->touch_calibration) { | ||||
|             u16 min_x = status->touch_calibration->min_x; | ||||
|             u16 max_x = status->touch_calibration->max_x; | ||||
|             u16 min_y = status->touch_calibration->min_y; | ||||
|             u16 max_y = status->touch_calibration->max_y; | ||||
|             const u16 min_x = status->touch_calibration->min_x; | ||||
|             const u16 max_x = status->touch_calibration->max_x; | ||||
|             const u16 min_y = status->touch_calibration->min_y; | ||||
|             const u16 max_y = status->touch_calibration->max_y; | ||||
| 
 | ||||
|             x = (std::clamp(static_cast<u16>(data.touch_1.x), min_x, max_x) - min_x) / | ||||
|                 static_cast<float>(max_x - min_x); | ||||
|  | @ -212,10 +221,11 @@ void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 clie | |||
|         bool result = success_event.WaitFor(std::chrono::seconds(8)); | ||||
|         socket.Stop(); | ||||
|         worker_thread.join(); | ||||
|         if (result) | ||||
|         if (result) { | ||||
|             success_callback(); | ||||
|         else | ||||
|         } else { | ||||
|             failure_callback(); | ||||
|         } | ||||
|     }) | ||||
|         .detach(); | ||||
| } | ||||
|  | @ -228,8 +238,10 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( | |||
|     std::thread([=] { | ||||
|         constexpr u16 CALIBRATION_THRESHOLD = 100; | ||||
| 
 | ||||
|         u16 min_x{UINT16_MAX}, min_y{UINT16_MAX}; | ||||
|         u16 max_x, max_y; | ||||
|         u16 min_x{UINT16_MAX}; | ||||
|         u16 min_y{UINT16_MAX}; | ||||
|         u16 max_x{}; | ||||
|         u16 max_y{}; | ||||
| 
 | ||||
|         Status current_status{Status::Initialized}; | ||||
|         SocketCallback callback{[](Response::Version version) {}, [](Response::PortInfo info) {}, | ||||
|  | @ -239,8 +251,9 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( | |||
|                                         current_status = Status::Ready; | ||||
|                                         status_callback(current_status); | ||||
|                                     } | ||||
|                                     if (!data.touch_1.is_active) | ||||
|                                     if (!data.touch_1.is_active) { | ||||
|                                         return; | ||||
|                                     } | ||||
|                                     LOG_DEBUG(Input, "Current touch: {} {}", data.touch_1.x, | ||||
|                                               data.touch_1.y); | ||||
|                                     min_x = std::min(min_x, static_cast<u16>(data.touch_1.x)); | ||||
|  |  | |||
|  | @ -17,8 +17,8 @@ | |||
| 
 | ||||
| namespace InputCommon::CemuhookUDP { | ||||
| 
 | ||||
| static constexpr u16 DEFAULT_PORT = 26760; | ||||
| static constexpr const char* DEFAULT_ADDR = "127.0.0.1"; | ||||
| constexpr u16 DEFAULT_PORT = 26760; | ||||
| constexpr char DEFAULT_ADDR[] = "127.0.0.1"; | ||||
| 
 | ||||
| class Socket; | ||||
| 
 | ||||
|  | @ -35,10 +35,10 @@ struct DeviceStatus { | |||
| 
 | ||||
|     // calibration data for scaling the device's touch area to 3ds
 | ||||
|     struct CalibrationData { | ||||
|         u16 min_x; | ||||
|         u16 min_y; | ||||
|         u16 max_x; | ||||
|         u16 max_y; | ||||
|         u16 min_x{}; | ||||
|         u16 min_y{}; | ||||
|         u16 max_x{}; | ||||
|         u16 max_y{}; | ||||
|     }; | ||||
|     std::optional<CalibrationData> touch_calibration; | ||||
| }; | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ | |||
| 
 | ||||
| namespace InputCommon::CemuhookUDP { | ||||
| 
 | ||||
| static const std::size_t GetSizeOfResponseType(Type t) { | ||||
| static constexpr std::size_t GetSizeOfResponseType(Type t) { | ||||
|     switch (t) { | ||||
|     case Type::Version: | ||||
|         return sizeof(Response::Version); | ||||
|  | @ -31,22 +31,21 @@ namespace Response { | |||
|  */ | ||||
| std::optional<Type> Validate(u8* data, std::size_t size) { | ||||
|     if (size < sizeof(Header)) { | ||||
|         LOG_DEBUG(Input, "Invalid UDP packet received"); | ||||
|         return {}; | ||||
|         return std::nullopt; | ||||
|     } | ||||
|     Header header; | ||||
|     Header header{}; | ||||
|     std::memcpy(&header, data, sizeof(Header)); | ||||
|     if (header.magic != SERVER_MAGIC) { | ||||
|         LOG_ERROR(Input, "UDP Packet has an unexpected magic value"); | ||||
|         return {}; | ||||
|         return std::nullopt; | ||||
|     } | ||||
|     if (header.protocol_version != PROTOCOL_VERSION) { | ||||
|         LOG_ERROR(Input, "UDP Packet protocol mismatch"); | ||||
|         return {}; | ||||
|         return std::nullopt; | ||||
|     } | ||||
|     if (header.type < Type::Version || header.type > Type::PadData) { | ||||
|         LOG_ERROR(Input, "UDP Packet is an unknown type"); | ||||
|         return {}; | ||||
|         return std::nullopt; | ||||
|     } | ||||
| 
 | ||||
|     // Packet size must equal sizeof(Header) + sizeof(Data)
 | ||||
|  | @ -59,7 +58,7 @@ std::optional<Type> Validate(u8* data, std::size_t size) { | |||
|             Input, | ||||
|             "UDP Packet payload length doesn't match. Received: {} PayloadLength: {} Expected: {}", | ||||
|             size, header.payload_length, data_len + sizeof(Type)); | ||||
|         return {}; | ||||
|         return std::nullopt; | ||||
|     } | ||||
| 
 | ||||
|     const u32 crc32 = header.crc; | ||||
|  | @ -70,7 +69,7 @@ std::optional<Type> Validate(u8* data, std::size_t size) { | |||
|     result.process_bytes(data, data_len + sizeof(Header)); | ||||
|     if (crc32 != result.checksum()) { | ||||
|         LOG_ERROR(Input, "UDP Packet CRC check failed. Offset: {}", offsetof(Header, crc)); | ||||
|         return {}; | ||||
|         return std::nullopt; | ||||
|     } | ||||
|     return header.type; | ||||
| } | ||||
|  |  | |||
|  | @ -25,15 +25,15 @@ enum class Type : u32 { | |||
| }; | ||||
| 
 | ||||
| struct Header { | ||||
|     u32_le magic; | ||||
|     u16_le protocol_version; | ||||
|     u16_le payload_length; | ||||
|     u32_le crc; | ||||
|     u32_le id; | ||||
|     u32_le magic{}; | ||||
|     u16_le protocol_version{}; | ||||
|     u16_le payload_length{}; | ||||
|     u32_le crc{}; | ||||
|     u32_le id{}; | ||||
|     ///> In the protocol, the type of the packet is not part of the header, but its convenient to
 | ||||
|     ///> include in the header so the callee doesn't have to duplicate the type twice when building
 | ||||
|     ///> the data
 | ||||
|     Type type; | ||||
|     Type type{}; | ||||
| }; | ||||
| static_assert(sizeof(Header) == 20, "UDP Message Header struct has wrong size"); | ||||
| static_assert(std::is_trivially_copyable_v<Header>, "UDP Message Header is not trivially copyable"); | ||||
|  | @ -44,7 +44,7 @@ constexpr MacAddress EMPTY_MAC_ADDRESS = {0, 0, 0, 0, 0, 0}; | |||
| #pragma pack(push, 1) | ||||
| template <typename T> | ||||
| struct Message { | ||||
|     Header header; | ||||
|     Header header{}; | ||||
|     T data; | ||||
| }; | ||||
| #pragma pack(pop) | ||||
|  | @ -63,7 +63,7 @@ struct Version {}; | |||
|  */ | ||||
| constexpr u32 MAX_PORTS = 4; | ||||
| struct PortInfo { | ||||
|     u32_le pad_count; ///> Number of ports to request data for
 | ||||
|     u32_le pad_count{}; ///> Number of ports to request data for
 | ||||
|     std::array<u8, MAX_PORTS> port; | ||||
| }; | ||||
| static_assert(std::is_trivially_copyable_v<PortInfo>, | ||||
|  | @ -81,9 +81,9 @@ struct PadData { | |||
|         Mac, | ||||
|     }; | ||||
|     /// Determines which method will be used as a look up for the controller
 | ||||
|     Flags flags; | ||||
|     Flags flags{}; | ||||
|     /// Index of the port of the controller to retrieve data about
 | ||||
|     u8 port_id; | ||||
|     u8 port_id{}; | ||||
|     /// Mac address of the controller to retrieve data about
 | ||||
|     MacAddress mac; | ||||
| }; | ||||
|  | @ -112,20 +112,20 @@ Message<T> Create(const T data, const u32 client_id = 0) { | |||
| namespace Response { | ||||
| 
 | ||||
| struct Version { | ||||
|     u16_le version; | ||||
|     u16_le version{}; | ||||
| }; | ||||
| static_assert(sizeof(Version) == 2, "UDP Response Version struct has wrong size"); | ||||
| static_assert(std::is_trivially_copyable_v<Version>, | ||||
|               "UDP Response Version is not trivially copyable"); | ||||
| 
 | ||||
| struct PortInfo { | ||||
|     u8 id; | ||||
|     u8 state; | ||||
|     u8 model; | ||||
|     u8 connection_type; | ||||
|     u8 id{}; | ||||
|     u8 state{}; | ||||
|     u8 model{}; | ||||
|     u8 connection_type{}; | ||||
|     MacAddress mac; | ||||
|     u8 battery; | ||||
|     u8 is_pad_active; | ||||
|     u8 battery{}; | ||||
|     u8 is_pad_active{}; | ||||
| }; | ||||
| static_assert(sizeof(PortInfo) == 12, "UDP Response PortInfo struct has wrong size"); | ||||
| static_assert(std::is_trivially_copyable_v<PortInfo>, | ||||
|  | @ -133,10 +133,10 @@ static_assert(std::is_trivially_copyable_v<PortInfo>, | |||
| 
 | ||||
| #pragma pack(push, 1) | ||||
| struct PadData { | ||||
|     PortInfo info; | ||||
|     u32_le packet_counter; | ||||
|     PortInfo info{}; | ||||
|     u32_le packet_counter{}; | ||||
| 
 | ||||
|     u16_le digital_button; | ||||
|     u16_le digital_button{}; | ||||
|     // The following union isn't trivially copyable but we don't use this input anyway.
 | ||||
|     // union DigitalButton {
 | ||||
|     //     u16_le button;
 | ||||
|  | @ -160,46 +160,46 @@ struct PadData { | |||
| 
 | ||||
|     u8 home; | ||||
|     /// If the device supports a "click" on the touchpad, this will change to 1 when a click happens
 | ||||
|     u8 touch_hard_press; | ||||
|     u8 left_stick_x; | ||||
|     u8 left_stick_y; | ||||
|     u8 right_stick_x; | ||||
|     u8 right_stick_y; | ||||
|     u8 touch_hard_press{}; | ||||
|     u8 left_stick_x{}; | ||||
|     u8 left_stick_y{}; | ||||
|     u8 right_stick_x{}; | ||||
|     u8 right_stick_y{}; | ||||
| 
 | ||||
|     struct AnalogButton { | ||||
|         u8 button_8; | ||||
|         u8 button_7; | ||||
|         u8 button_6; | ||||
|         u8 button_5; | ||||
|         u8 button_12; | ||||
|         u8 button_11; | ||||
|         u8 button_10; | ||||
|         u8 button_9; | ||||
|         u8 button_16; | ||||
|         u8 button_15; | ||||
|         u8 button_14; | ||||
|         u8 button_13; | ||||
|         u8 button_8{}; | ||||
|         u8 button_7{}; | ||||
|         u8 button_6{}; | ||||
|         u8 button_5{}; | ||||
|         u8 button_12{}; | ||||
|         u8 button_11{}; | ||||
|         u8 button_10{}; | ||||
|         u8 button_9{}; | ||||
|         u8 button_16{}; | ||||
|         u8 button_15{}; | ||||
|         u8 button_14{}; | ||||
|         u8 button_13{}; | ||||
|     } analog_button; | ||||
| 
 | ||||
|     struct TouchPad { | ||||
|         u8 is_active; | ||||
|         u8 id; | ||||
|         u16_le x; | ||||
|         u16_le y; | ||||
|         u8 is_active{}; | ||||
|         u8 id{}; | ||||
|         u16_le x{}; | ||||
|         u16_le y{}; | ||||
|     } touch_1, touch_2; | ||||
| 
 | ||||
|     u64_le motion_timestamp; | ||||
| 
 | ||||
|     struct Accelerometer { | ||||
|         float x; | ||||
|         float y; | ||||
|         float z; | ||||
|         float x{}; | ||||
|         float y{}; | ||||
|         float z{}; | ||||
|     } accel; | ||||
| 
 | ||||
|     struct Gyroscope { | ||||
|         float pitch; | ||||
|         float yaw; | ||||
|         float roll; | ||||
|         float pitch{}; | ||||
|         float yaw{}; | ||||
|         float roll{}; | ||||
|     } gyro; | ||||
| }; | ||||
| #pragma pack(pop) | ||||
|  | @ -211,6 +211,13 @@ static_assert(std::is_trivially_copyable_v<PadData>, | |||
| static_assert(sizeof(Message<PadData>) == MAX_PACKET_SIZE, | ||||
|               "UDP MAX_PACKET_SIZE is no longer larger than Message<PadData>"); | ||||
| 
 | ||||
| static_assert(sizeof(PadData::AnalogButton) == 12, | ||||
|               "UDP Response AnalogButton struct has wrong size "); | ||||
| static_assert(sizeof(PadData::TouchPad) == 6, "UDP Response TouchPad struct has wrong size "); | ||||
| static_assert(sizeof(PadData::Accelerometer) == 12, | ||||
|               "UDP Response Accelerometer struct has wrong size "); | ||||
| static_assert(sizeof(PadData::Gyroscope) == 12, "UDP Response Gyroscope struct has wrong size "); | ||||
| 
 | ||||
| /**
 | ||||
|  * Create a Response Message from the data | ||||
|  * @param data array of bytes sent from the server | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ | |||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <mutex> | ||||
| #include <optional> | ||||
| #include <tuple> | ||||
| #include "common/param_package.h" | ||||
| #include "core/frontend/input.h" | ||||
|  | @ -43,7 +44,7 @@ public: | |||
|     std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override { | ||||
|         { | ||||
|             std::lock_guard guard(status->update_mutex); | ||||
|             status->touch_calibration.emplace(); | ||||
|             status->touch_calibration = DeviceStatus::CalibrationData{}; | ||||
|             // These default values work well for DS4 but probably not other touch inputs
 | ||||
|             status->touch_calibration->min_x = params.Get("min_x", 100); | ||||
|             status->touch_calibration->min_y = params.Get("min_y", 50); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue