From d46e7964bf99db6d628b05fb000508ee11553230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 28 Mar 2024 21:18:17 +0400 Subject: [PATCH] feat(server): add pointer DisplayUpdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add DisplayUpdate API to set the pointer simply (no cache, with 32bpp RGBA etc) Signed-off-by: Marc-André Lureau --- crates/ironrdp-server/src/display.rs | 25 ++++++++++ crates/ironrdp-server/src/encoder/mod.rs | 58 +++++++++++++++++++++++- crates/ironrdp-server/src/server.rs | 5 ++ 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/crates/ironrdp-server/src/display.rs b/crates/ironrdp-server/src/display.rs index 97ac3132..ed165481 100644 --- a/crates/ironrdp-server/src/display.rs +++ b/crates/ironrdp-server/src/display.rs @@ -1,4 +1,5 @@ use anyhow::Result; +use ironrdp_pdu::pointer::PointerPositionAttribute; use std::num::NonZeroU16; pub use ironrdp_acceptor::DesktopSize; @@ -12,6 +13,11 @@ pub use ironrdp_graphics::image_processing::PixelFormat; #[derive(Debug, Clone)] pub enum DisplayUpdate { Bitmap(BitmapUpdate), + PointerPosition(PointerPositionAttribute), + ColorPointer(ColorPointer), + RGBAPointer(RGBAPointer), + HidePointer, + DefaultPointer, } #[derive(Debug, Clone, Copy)] @@ -20,6 +26,25 @@ pub enum PixelOrder { BottomToTop, } +#[derive(Debug, Clone)] +pub struct RGBAPointer { + pub width: u16, + pub height: u16, + pub hot_x: u16, + pub hot_y: u16, + pub data: Vec, +} + +#[derive(Debug, Clone)] +pub struct ColorPointer { + pub width: u16, + pub height: u16, + pub hot_x: u16, + pub hot_y: u16, + pub and_mask: Vec, + pub xor_mask: Vec, +} + /// Bitmap Display Update /// /// Bitmap updates are encoded using RDP 6.0 compression, fragmented and sent using diff --git a/crates/ironrdp-server/src/encoder/mod.rs b/crates/ironrdp-server/src/encoder/mod.rs index 1afba2dc..717d64f8 100644 --- a/crates/ironrdp-server/src/encoder/mod.rs +++ b/crates/ironrdp-server/src/encoder/mod.rs @@ -7,11 +7,12 @@ use std::{cmp, mem}; use ironrdp_pdu::cursor::WriteCursor; use ironrdp_pdu::fast_path::{EncryptionFlags, FastPathHeader, FastPathUpdatePdu, Fragmentation, UpdateCode}; use ironrdp_pdu::geometry::ExclusiveRectangle; +use ironrdp_pdu::pointer::{ColorPointerAttribute, Point16, PointerAttribute, PointerPositionAttribute}; use ironrdp_pdu::rdp::capability_sets::{CmdFlags, EntropyBits}; use ironrdp_pdu::surface_commands::{ExtendedBitmapDataPdu, SurfaceBitsPdu, SurfaceCommand}; use ironrdp_pdu::PduEncode; -use crate::PixelOrder; +use crate::{ColorPointer, PixelOrder, RGBAPointer}; use self::bitmap::BitmapEncoder; use self::rfx::RfxEncoder; @@ -70,6 +71,61 @@ impl UpdateEncoder { } } + pub(crate) fn rgba_pointer(&mut self, ptr: RGBAPointer) -> Result> { + let xor_mask = ptr.data; + + let hot_spot = Point16 { + x: ptr.hot_x, + y: ptr.hot_y, + }; + let color_pointer = ColorPointerAttribute { + cache_index: 0, + hot_spot, + width: ptr.width, + height: ptr.height, + xor_mask: &xor_mask, + and_mask: &[], + }; + let ptr = PointerAttribute { + xor_bpp: 32, + color_pointer, + }; + let len = self.encode_pdu(ptr)?; + Ok(UpdateFragmenter::new(UpdateCode::NewPointer, &self.buffer[..len])) + } + + pub(crate) fn color_pointer(&mut self, ptr: ColorPointer) -> Result> { + let hot_spot = Point16 { + x: ptr.hot_x, + y: ptr.hot_y, + }; + let ptr = ColorPointerAttribute { + cache_index: 0, + hot_spot, + width: ptr.width, + height: ptr.height, + xor_mask: &ptr.xor_mask, + and_mask: &ptr.and_mask, + }; + let len = self.encode_pdu(ptr)?; + Ok(UpdateFragmenter::new(UpdateCode::ColorPointer, &self.buffer[..len])) + } + + #[allow(clippy::unused_self)] + pub(crate) fn default_pointer(&mut self) -> Result> { + Ok(UpdateFragmenter::new(UpdateCode::DefaultPointer, &[])) + } + + #[allow(clippy::unused_self)] + pub(crate) fn hide_pointer(&mut self) -> Result> { + Ok(UpdateFragmenter::new(UpdateCode::HiddenPointer, &[])) + } + + pub(crate) fn pointer_position(&mut self, pos: PointerPositionAttribute) -> Result> { + let len = self.encode_pdu(pos)?; + Ok(UpdateFragmenter::new(UpdateCode::PositionPointer, &self.buffer[..len])) + } + pub(crate) fn bitmap(&mut self, bitmap: BitmapUpdate) -> Result> { let update = self.update; diff --git a/crates/ironrdp-server/src/server.rs b/crates/ironrdp-server/src/server.rs index c2100367..04a2c16f 100644 --- a/crates/ironrdp-server/src/server.rs +++ b/crates/ironrdp-server/src/server.rs @@ -348,6 +348,11 @@ impl RdpServer { Some(update) = display_updates.next_update() => { let fragmenter = match update { DisplayUpdate::Bitmap(bitmap) => encoder.bitmap(bitmap), + DisplayUpdate::PointerPosition(pos) => { encoder.pointer_position(pos) }, + DisplayUpdate::RGBAPointer(ptr) => { encoder.rgba_pointer(ptr) }, + DisplayUpdate::ColorPointer(ptr) => { encoder.color_pointer(ptr) }, + DisplayUpdate::HidePointer => { encoder.hide_pointer() }, + DisplayUpdate::DefaultPointer => { encoder.default_pointer() }, }; let mut fragmenter = match fragmenter {