mirror of
https://github.com/Devolutions/IronRDP.git
synced 2025-08-04 15:18:17 +00:00
feat(web): allow dynamic resize for web (#550)
This commit is contained in:
parent
3d3d9f2c56
commit
c04bc2d29c
11 changed files with 354 additions and 7 deletions
|
@ -30,6 +30,7 @@ ironrdp = { workspace = true, features = [
|
|||
"dvc",
|
||||
"cliprdr",
|
||||
"svc",
|
||||
"displaycontrol"
|
||||
] }
|
||||
ironrdp-core.workspace = true
|
||||
ironrdp-cliprdr-format = { workspace = true }
|
||||
|
|
|
@ -36,6 +36,11 @@ impl Canvas {
|
|||
Ok(Self { width, surface })
|
||||
}
|
||||
|
||||
pub(crate) fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) {
|
||||
self.surface.resize(width, height).expect("surface resize");
|
||||
self.width = width.get();
|
||||
}
|
||||
|
||||
pub(crate) fn draw(&mut self, buffer: &[u8], region: InclusiveRectangle) -> anyhow::Result<()> {
|
||||
let region_width = region.width();
|
||||
let region_height = region.height();
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
use core::cell::RefCell;
|
||||
use std::borrow::Cow;
|
||||
use std::num::NonZeroU32;
|
||||
use std::rc::Rc;
|
||||
use std::time::Duration;
|
||||
|
||||
|
@ -18,6 +19,8 @@ use ironrdp::cliprdr::CliprdrClient;
|
|||
use ironrdp::connector::connection_activation::ConnectionActivationState;
|
||||
use ironrdp::connector::credssp::KerberosConfig;
|
||||
use ironrdp::connector::{self, ClientConnector, Credentials};
|
||||
use ironrdp::displaycontrol::client::DisplayControlClient;
|
||||
use ironrdp::dvc::DrdynvcClient;
|
||||
use ironrdp::graphics::image_processing::PixelFormat;
|
||||
use ironrdp::pdu::input::fast_path::FastPathInputEvent;
|
||||
use ironrdp::pdu::rdp::client_info::PerformanceFlags;
|
||||
|
@ -64,6 +67,8 @@ struct SessionBuilderInner {
|
|||
remote_clipboard_changed_callback: Option<js_sys::Function>,
|
||||
remote_received_format_list_callback: Option<js_sys::Function>,
|
||||
force_clipboard_update_callback: Option<js_sys::Function>,
|
||||
|
||||
use_display_control: bool,
|
||||
}
|
||||
|
||||
impl Default for SessionBuilderInner {
|
||||
|
@ -89,6 +94,8 @@ impl Default for SessionBuilderInner {
|
|||
remote_clipboard_changed_callback: None,
|
||||
remote_received_format_list_callback: None,
|
||||
force_clipboard_update_callback: None,
|
||||
|
||||
use_display_control: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -209,6 +216,12 @@ impl SessionBuilder {
|
|||
self.clone()
|
||||
}
|
||||
|
||||
/// Optional
|
||||
pub fn use_display_control(&self) -> SessionBuilder {
|
||||
self.0.borrow_mut().use_display_control = true;
|
||||
self.clone()
|
||||
}
|
||||
|
||||
pub async fn connect(&self) -> Result<Session, IronRdpError> {
|
||||
let (
|
||||
username,
|
||||
|
@ -301,15 +314,18 @@ impl SessionBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
let (connection_result, ws) = connect(
|
||||
let use_display_control = self.0.borrow().use_display_control;
|
||||
|
||||
let (connection_result, ws) = connect(ConnectParams {
|
||||
ws,
|
||||
config,
|
||||
auth_token,
|
||||
proxy_auth_token: auth_token,
|
||||
destination,
|
||||
pcb,
|
||||
kdc_proxy_url,
|
||||
clipboard.as_ref().map(|clip| clip.backend()),
|
||||
)
|
||||
clipboard_backend: clipboard.as_ref().map(|clip| clip.backend()),
|
||||
use_display_control,
|
||||
})
|
||||
.await?;
|
||||
|
||||
info!("Connected!");
|
||||
|
@ -345,6 +361,12 @@ pub(crate) enum RdpInputEvent {
|
|||
Cliprdr(ClipboardMessage),
|
||||
ClipboardBackend(WasmClipboardBackendMessage),
|
||||
FastPath(FastPathInputEvents),
|
||||
Resize {
|
||||
width: u32,
|
||||
height: u32,
|
||||
scale_factor: Option<u32>,
|
||||
physical_size: Option<(u32, u32)>,
|
||||
},
|
||||
TerminateSession,
|
||||
}
|
||||
|
||||
|
@ -489,6 +511,21 @@ impl Session {
|
|||
active_stage.process_fastpath_input(&mut image, &events)
|
||||
.context("fast path input events processing")?
|
||||
}
|
||||
RdpInputEvent::Resize { width, height, scale_factor, physical_size } => {
|
||||
debug!(width, height, scale_factor, "Resize event received");
|
||||
if width == 0 || height == 0 {
|
||||
warn!("Resize event ignored: width or height is zero");
|
||||
Vec::new()
|
||||
} else if let Some(response_frame) = active_stage.encode_resize(width, height, scale_factor, physical_size) {
|
||||
self.render_canvas.set_width(width);
|
||||
self.render_canvas.set_height(height);
|
||||
gui.resize(NonZeroU32::new(width).unwrap(), NonZeroU32::new(height).unwrap());
|
||||
vec![ActiveStageOutput::ResponseFrame(response_frame?)]
|
||||
} else {
|
||||
debug!("Resize event ignored");
|
||||
Vec::new()
|
||||
}
|
||||
},
|
||||
RdpInputEvent::TerminateSession => {
|
||||
active_stage.graceful_shutdown()
|
||||
.context("graceful shutdown")?
|
||||
|
@ -757,6 +794,24 @@ impl Session {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn resize(
|
||||
&self,
|
||||
width: u32,
|
||||
height: u32,
|
||||
scale_factor: Option<u32>,
|
||||
physical_width: Option<u32>,
|
||||
physical_height: Option<u32>,
|
||||
) {
|
||||
self.input_events_tx
|
||||
.unbounded_send(RdpInputEvent::Resize {
|
||||
width,
|
||||
height,
|
||||
scale_factor,
|
||||
physical_size: physical_width.and_then(|width| physical_height.map(|height| (width, height))),
|
||||
})
|
||||
.expect("send resize event to writer task");
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_self)]
|
||||
pub fn supports_unicode_keyboard_shortcuts(&self) -> bool {
|
||||
// RDP does not support Unicode keyboard shortcuts (When key combinations are executed, only
|
||||
|
@ -832,7 +887,7 @@ async fn writer_task(rx: mpsc::UnboundedReceiver<Vec<u8>>, rdp_writer: WriteHalf
|
|||
}
|
||||
}
|
||||
|
||||
async fn connect(
|
||||
struct ConnectParams {
|
||||
ws: WebSocket,
|
||||
config: connector::Config,
|
||||
proxy_auth_token: String,
|
||||
|
@ -840,6 +895,20 @@ async fn connect(
|
|||
pcb: Option<String>,
|
||||
kdc_proxy_url: Option<String>,
|
||||
clipboard_backend: Option<WasmClipboardBackend>,
|
||||
use_display_control: bool,
|
||||
}
|
||||
|
||||
async fn connect(
|
||||
ConnectParams {
|
||||
ws,
|
||||
config,
|
||||
proxy_auth_token,
|
||||
destination,
|
||||
pcb,
|
||||
kdc_proxy_url,
|
||||
clipboard_backend,
|
||||
use_display_control,
|
||||
}: ConnectParams,
|
||||
) -> Result<(connector::ConnectionResult, WebSocket), IronRdpError> {
|
||||
let mut framed = ironrdp_futures::LocalFuturesFramed::new(ws);
|
||||
|
||||
|
@ -849,6 +918,12 @@ async fn connect(
|
|||
connector.attach_static_channel(CliprdrClient::new(Box::new(clipboard_backend)));
|
||||
}
|
||||
|
||||
if use_display_control {
|
||||
connector.attach_static_channel(
|
||||
DrdynvcClient::new().with_dynamic_channel(DisplayControlClient::new(|_| Ok(Vec::new()))),
|
||||
);
|
||||
}
|
||||
|
||||
let (upgraded, server_public_key) =
|
||||
connect_rdcleanpath(&mut framed, &mut connector, destination.clone(), proxy_auth_token, pcb).await?;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue