diff --git a/README.md b/README.md index b171f36..2f5d1cc 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,7 @@ * VNC Clients: - Raw encoding support (Done) - + Clipboard support is limit - Other encoding support (WIP) - - Client to server message (WIP) * SSH Clients: - WIP diff --git a/frontend/src/pages/mod.rs b/frontend/src/pages/mod.rs index 58fc0a1..d2d582a 100644 --- a/frontend/src/pages/mod.rs +++ b/frontend/src/pages/mod.rs @@ -1,3 +1,3 @@ pub mod page_home; pub mod page_not_found; -pub mod page_remote; +pub mod page_vnc; diff --git a/frontend/src/pages/page_home.rs b/frontend/src/pages/page_home.rs index 30c837a..91648db 100644 --- a/frontend/src/pages/page_home.rs +++ b/frontend/src/pages/page_home.rs @@ -14,7 +14,7 @@ impl Component for PageHome { fn view(&self) -> Html { html! { - + } } diff --git a/frontend/src/pages/page_remote.rs b/frontend/src/pages/page_vnc.rs similarity index 82% rename from frontend/src/pages/page_remote.rs rename to frontend/src/pages/page_vnc.rs index bf7280a..f7fcf1d 100644 --- a/frontend/src/pages/page_remote.rs +++ b/frontend/src/pages/page_vnc.rs @@ -19,7 +19,7 @@ use crate::{ utils::WeakComponentLink, }; -pub struct PageRemote { +pub struct PageVnc { link: ComponentLink, target: (String, u16), error_msg: String, @@ -38,9 +38,9 @@ pub struct PageRemote { } #[derive(Clone, PartialEq, Properties)] -pub struct RemoteProps {} +pub struct VncProps {} -pub enum RemoteMsg { +pub enum VncMsg { Connect((String, u16)), ConnectResp(Result), Connected, @@ -53,12 +53,12 @@ pub enum RemoteMsg { RequireFrame(u8), } -impl Component for PageRemote { - type Message = RemoteMsg; - type Properties = RemoteProps; +impl Component for PageVnc { + type Message = VncMsg; + type Properties = VncProps; fn create(_: Self::Properties, link: ComponentLink) -> Self { - PageRemote { + PageVnc { link, target: (String::from(""), 0), error_msg: String::from(""), @@ -79,7 +79,7 @@ impl Component for PageRemote { fn update(&mut self, msg: Self::Message) -> ShouldRender { match msg { - RemoteMsg::Connect(target) => { + VncMsg::Connect(target) => { self.target = target; // ConsoleService::log(&self.target); let to_post = json!({ @@ -98,7 +98,7 @@ impl Component for PageRemote { .callback(|response: Response>>| { // ConsoleService::error(&format!("{:?}", response)); let Json(data) = response.into_body(); - RemoteMsg::ConnectResp(data) + VncMsg::ConnectResp(data) }); // 3. pass the request and callback to the fetch service let task = FetchService::fetch(request, callback).expect("failed to start request"); @@ -106,12 +106,12 @@ impl Component for PageRemote { self.fetch_task = Some(task); true } - RemoteMsg::ConnectResp(response) => { + VncMsg::ConnectResp(response) => { if let Ok(response) = response { self.error_msg = response["status"].to_string(); if "\"success\"" == self.error_msg { - self.link.send_message(RemoteMsg::Connected); + self.link.send_message(VncMsg::Connected); } else { self.error_msg = response["message"].to_string(); } @@ -123,15 +123,15 @@ impl Component for PageRemote { self.fetch_task = None; true } - RemoteMsg::Connected => { + VncMsg::Connected => { self.connected = true; true } - RemoteMsg::Recv(v) => { + VncMsg::Recv(v) => { self.handler.do_input(v); self.protocal_out_handler() } - RemoteMsg::Send(v) => { + VncMsg::Send(v) => { self.websocket .borrow() .as_ref() @@ -139,31 +139,31 @@ impl Component for PageRemote { .send_message(WebsocketMsg::Send(Ok(v))); false } - RemoteMsg::UpdateUsername(username) => { + VncMsg::UpdateUsername(username) => { self.username = username; true } - RemoteMsg::UpdatePassword(password) => { + VncMsg::UpdatePassword(password) => { self.password = password; true } - RemoteMsg::SendCredential => { + VncMsg::SendCredential => { self.request_username = false; self.request_password = false; self.handler.set_credential(&self.username, &self.password); self.protocal_out_handler() } - RemoteMsg::RequireFrame(incremental) => { + VncMsg::RequireFrame(incremental) => { self.handler.require_frame(incremental); if self.interval.is_none() { let link = self.link.clone(); let tick = - Interval::new(20, move || link.send_message(RemoteMsg::RequireFrame(1))); + Interval::new(20, move || link.send_message(VncMsg::RequireFrame(1))); self.interval = Some(tick); } self.protocal_out_handler() } - RemoteMsg::UpdateClipboard(clipboard) => { + VncMsg::UpdateClipboard(clipboard) => { if clipboard.len() > 0 { self.handler.set_clipboard(&clipboard); self.protocal_out_handler() @@ -180,7 +180,7 @@ impl Component for PageRemote { fn view(&self) -> Html { if !self.connected { - let connect_remote = self.link.callback(RemoteMsg::Connect); + let connect_remote = self.link.callback(VncMsg::Connect); html! { <> @@ -188,8 +188,8 @@ impl Component for PageRemote { } } else { - let recv_msg = self.link.callback(RemoteMsg::Recv); - let clipboard_update = self.link.callback(RemoteMsg::UpdateClipboard); + let recv_msg = self.link.callback(VncMsg::Recv); + let clipboard_update = self.link.callback(VncMsg::UpdateClipboard); let websocket = &self.websocket; let clipboard = &self.clipboard; html! { @@ -218,7 +218,7 @@ impl Component for PageRemote { } // impl PageRemote -impl PageRemote { +impl PageVnc { fn protocal_out_handler(&mut self) -> ShouldRender { let out = self.handler.get_output(); let mut should_render = false; @@ -236,7 +236,7 @@ impl PageRemote { } ProtocalHandlerOutput::WsBuf(out) => { if out.len() > 0 { - self.link.send_message(RemoteMsg::Send(out)); + self.link.send_message(VncMsg::Send(out)); } } ProtocalHandlerOutput::RequirePassword => { @@ -256,17 +256,40 @@ impl PageRemote { } }; - let data = ImageData::new_with_u8_clamped_array_and_sh( - Clamped(&cr.data), - cr.width as u32, - cr.height as u32, - ) - .unwrap(); - // ConsoleService::log(&format!( - // "renderring at ({}, {}), width {}, height {}", - // cr.x, cr.y, cr.width, cr.height - // )); - let _ = ctx.put_image_data(&data, cr.x as f64, cr.y as f64); + match cr.type_ { + 1 => { + //copy + let sx = (cr.data[0] as u16) << 8 | cr.data[1] as u16; + let sy = (cr.data[2] as u16) << 8 | cr.data[3] as u16; + + let _ = ctx. + draw_image_with_html_canvas_element_and_sw_and_sh_and_dx_and_dy_and_dw_and_dh( + &canvas, + sx as f64, + sy as f64, + cr.width as f64, + cr.height as f64, + cr.x as f64, + cr.y as f64, + cr.width as f64, + cr.height as f64 + ); + } + _ => { + let data = ImageData::new_with_u8_clamped_array_and_sh( + Clamped(&cr.data), + cr.width as u32, + cr.height as u32, + ) + .unwrap(); + // ConsoleService::log(&format!( + // "renderring at ({}, {}), width {}, height {}", + // cr.x, cr.y, cr.width, cr.height + // )); + let _ = ctx.put_image_data(&data, cr.x as f64, cr.y as f64); + } + } + should_render = true; } ProtocalHandlerOutput::SetCanvas(width, height) => { @@ -274,7 +297,7 @@ impl PageRemote { canvas.set_width(width as u32); canvas.set_height(height as u32); self.bind_mouse_and_key(&canvas); - self.link.send_message(RemoteMsg::RequireFrame(0)); + self.link.send_message(VncMsg::RequireFrame(0)); let ctx = match &self.canvas_ctx { Some(ctx) => ctx, None => { @@ -305,7 +328,7 @@ impl PageRemote { fn username_view(&self) -> Html { if self.request_username { - let update_username = self.link.callback(RemoteMsg::UpdateUsername); + let update_username = self.link.callback(VncMsg::UpdateUsername); html! { <> @@ -319,7 +342,7 @@ impl PageRemote { fn password_view(&self) -> Html { if self.request_password { - let update_password = self.link.callback(RemoteMsg::UpdatePassword); + let update_password = self.link.callback(VncMsg::UpdatePassword); html! { <> @@ -333,7 +356,7 @@ impl PageRemote { fn button_connect_view(&self) -> Html { if self.request_username || self.request_password { - let send_credential = self.link.callback(|_| RemoteMsg::SendCredential); + let send_credential = self.link.callback(|_| VncMsg::SendCredential); html! { <> diff --git a/frontend/src/protocal/common.rs b/frontend/src/protocal/common.rs index 18f7f46..e66dceb 100644 --- a/frontend/src/protocal/common.rs +++ b/frontend/src/protocal/common.rs @@ -1,6 +1,7 @@ use std::{rc::Rc, sync::Mutex}; pub struct CanvasData { + pub type_: u32, pub x: u16, pub y: u16, pub width: u16, diff --git a/frontend/src/protocal/vnc/vnc.rs b/frontend/src/protocal/vnc/vnc.rs index 51737e4..f587bc2 100644 --- a/frontend/src/protocal/vnc/vnc.rs +++ b/frontend/src/protocal/vnc/vnc.rs @@ -23,6 +23,7 @@ pub enum SecurityType { // VeNCrypt = 19, } +#[allow(dead_code)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(i32)] pub enum VncEncoding { @@ -79,7 +80,7 @@ impl ProtocalImpl for VncHandler { state: VncState::Init, supported_encodings: vec![ VncEncoding::Raw, - // VncEncoding::CopyRect, + VncEncoding::CopyRect, // VncEncoding::RRE, // VncEncoding::Hextile, // VncEncoding::TRLE, @@ -554,10 +555,15 @@ impl VncHandler { } } } + 1 => { + // copy rectangle + self.read_exact_vec(&mut image_data, 4); + } _ => unimplemented!(), } self.outs .push(ProtocalHandlerOutput::RenderCanvas(CanvasData { + type_: rect.encoding_type, x: rect.x, y: rect.y, width: rect.width, @@ -649,19 +655,31 @@ impl VncHandler { width, height, encoding_type: 0, - encoding_data: Vec::new(), // we donnot need to store the data }); } - fn handle_copy_rect_encoding(&mut self, _x: u16, _y: u16, _width: u16, _height: u16) { - unimplemented!() + fn handle_copy_rect_encoding(&mut self, x: u16, y: u16, width: u16, height: u16) { + ConsoleService::log(&format!("VNC: CopyRect {} {} {} {}", x, y, width, height)); + self.require = 4; + self.padding_rect = Some(VncRect { + x, + y, + width, + height, + encoding_type: 1, + }); } fn handle_rre_encoding(&mut self, _x: u16, _y: u16, _width: u16, _height: u16) { + // Note: RRE encoding is obsolescent. In general, ZRLE and TRLE + // encodings are more compact. + unimplemented!() } fn handle_hextile_encoding(&mut self, _x: u16, _y: u16, _width: u16, _height: u16) { + // Note: Hextile encoding is obsolescent. In general, ZRLE and TRLE + // encodings are more compact. unimplemented!() } @@ -800,5 +818,4 @@ struct VncRect { width: u16, height: u16, encoding_type: u32, - encoding_data: Vec, } diff --git a/frontend/src/protocal/vnc/x11keyboard.rs b/frontend/src/protocal/vnc/x11keyboard.rs index 0354440..9c51c98 100644 --- a/frontend/src/protocal/vnc/x11keyboard.rs +++ b/frontend/src/protocal/vnc/x11keyboard.rs @@ -3,8 +3,6 @@ #![allow(non_snake_case)] #![allow(non_upper_case_globals)] - - // referring: // https://github.com/AltF02/x11-rs/blob/master/src/keysym.rs