Merge pull request #16 from HsuJv/dev

add support for copyRect encoding
This commit is contained in:
Jovi Hsu 2021-11-29 09:50:19 +08:00 committed by GitHub
commit bfc9968d21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 88 additions and 51 deletions

View File

@ -18,9 +18,7 @@
* VNC Clients: * VNC Clients:
- Raw encoding support (Done) - Raw encoding support (Done)
+ Clipboard support is limit
- Other encoding support (WIP) - Other encoding support (WIP)
- Client to server message (WIP)
* SSH Clients: * SSH Clients:
- WIP - WIP

View File

@ -1,3 +1,3 @@
pub mod page_home; pub mod page_home;
pub mod page_not_found; pub mod page_not_found;
pub mod page_remote; pub mod page_vnc;

View File

@ -14,7 +14,7 @@ impl Component for PageHome {
fn view(&self) -> Html { fn view(&self) -> Html {
html! { html! {
<crate::pages::page_remote::PageRemote/> <crate::pages::page_vnc::PageVnc/>
} }
} }

View File

@ -19,7 +19,7 @@ use crate::{
utils::WeakComponentLink, utils::WeakComponentLink,
}; };
pub struct PageRemote { pub struct PageVnc {
link: ComponentLink<Self>, link: ComponentLink<Self>,
target: (String, u16), target: (String, u16),
error_msg: String, error_msg: String,
@ -38,9 +38,9 @@ pub struct PageRemote {
} }
#[derive(Clone, PartialEq, Properties)] #[derive(Clone, PartialEq, Properties)]
pub struct RemoteProps {} pub struct VncProps {}
pub enum RemoteMsg { pub enum VncMsg {
Connect((String, u16)), Connect((String, u16)),
ConnectResp(Result<Value, anyhow::Error>), ConnectResp(Result<Value, anyhow::Error>),
Connected, Connected,
@ -53,12 +53,12 @@ pub enum RemoteMsg {
RequireFrame(u8), RequireFrame(u8),
} }
impl Component for PageRemote { impl Component for PageVnc {
type Message = RemoteMsg; type Message = VncMsg;
type Properties = RemoteProps; type Properties = VncProps;
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self { fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
PageRemote { PageVnc {
link, link,
target: (String::from(""), 0), target: (String::from(""), 0),
error_msg: String::from(""), error_msg: String::from(""),
@ -79,7 +79,7 @@ impl Component for PageRemote {
fn update(&mut self, msg: Self::Message) -> ShouldRender { fn update(&mut self, msg: Self::Message) -> ShouldRender {
match msg { match msg {
RemoteMsg::Connect(target) => { VncMsg::Connect(target) => {
self.target = target; self.target = target;
// ConsoleService::log(&self.target); // ConsoleService::log(&self.target);
let to_post = json!({ let to_post = json!({
@ -98,7 +98,7 @@ impl Component for PageRemote {
.callback(|response: Response<Json<Result<Value, anyhow::Error>>>| { .callback(|response: Response<Json<Result<Value, anyhow::Error>>>| {
// ConsoleService::error(&format!("{:?}", response)); // ConsoleService::error(&format!("{:?}", response));
let Json(data) = response.into_body(); let Json(data) = response.into_body();
RemoteMsg::ConnectResp(data) VncMsg::ConnectResp(data)
}); });
// 3. pass the request and callback to the fetch service // 3. pass the request and callback to the fetch service
let task = FetchService::fetch(request, callback).expect("failed to start request"); let task = FetchService::fetch(request, callback).expect("failed to start request");
@ -106,12 +106,12 @@ impl Component for PageRemote {
self.fetch_task = Some(task); self.fetch_task = Some(task);
true true
} }
RemoteMsg::ConnectResp(response) => { VncMsg::ConnectResp(response) => {
if let Ok(response) = response { if let Ok(response) = response {
self.error_msg = response["status"].to_string(); self.error_msg = response["status"].to_string();
if "\"success\"" == self.error_msg { if "\"success\"" == self.error_msg {
self.link.send_message(RemoteMsg::Connected); self.link.send_message(VncMsg::Connected);
} else { } else {
self.error_msg = response["message"].to_string(); self.error_msg = response["message"].to_string();
} }
@ -123,15 +123,15 @@ impl Component for PageRemote {
self.fetch_task = None; self.fetch_task = None;
true true
} }
RemoteMsg::Connected => { VncMsg::Connected => {
self.connected = true; self.connected = true;
true true
} }
RemoteMsg::Recv(v) => { VncMsg::Recv(v) => {
self.handler.do_input(v); self.handler.do_input(v);
self.protocal_out_handler() self.protocal_out_handler()
} }
RemoteMsg::Send(v) => { VncMsg::Send(v) => {
self.websocket self.websocket
.borrow() .borrow()
.as_ref() .as_ref()
@ -139,31 +139,31 @@ impl Component for PageRemote {
.send_message(WebsocketMsg::Send(Ok(v))); .send_message(WebsocketMsg::Send(Ok(v)));
false false
} }
RemoteMsg::UpdateUsername(username) => { VncMsg::UpdateUsername(username) => {
self.username = username; self.username = username;
true true
} }
RemoteMsg::UpdatePassword(password) => { VncMsg::UpdatePassword(password) => {
self.password = password; self.password = password;
true true
} }
RemoteMsg::SendCredential => { VncMsg::SendCredential => {
self.request_username = false; self.request_username = false;
self.request_password = false; self.request_password = false;
self.handler.set_credential(&self.username, &self.password); self.handler.set_credential(&self.username, &self.password);
self.protocal_out_handler() self.protocal_out_handler()
} }
RemoteMsg::RequireFrame(incremental) => { VncMsg::RequireFrame(incremental) => {
self.handler.require_frame(incremental); self.handler.require_frame(incremental);
if self.interval.is_none() { if self.interval.is_none() {
let link = self.link.clone(); let link = self.link.clone();
let tick = 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.interval = Some(tick);
} }
self.protocal_out_handler() self.protocal_out_handler()
} }
RemoteMsg::UpdateClipboard(clipboard) => { VncMsg::UpdateClipboard(clipboard) => {
if clipboard.len() > 0 { if clipboard.len() > 0 {
self.handler.set_clipboard(&clipboard); self.handler.set_clipboard(&clipboard);
self.protocal_out_handler() self.protocal_out_handler()
@ -180,7 +180,7 @@ impl Component for PageRemote {
fn view(&self) -> Html { fn view(&self) -> Html {
if !self.connected { if !self.connected {
let connect_remote = self.link.callback(RemoteMsg::Connect); let connect_remote = self.link.callback(VncMsg::Connect);
html! { html! {
<> <>
<components::host::Host onsubmit=connect_remote/> <components::host::Host onsubmit=connect_remote/>
@ -188,8 +188,8 @@ impl Component for PageRemote {
</> </>
} }
} else { } else {
let recv_msg = self.link.callback(RemoteMsg::Recv); let recv_msg = self.link.callback(VncMsg::Recv);
let clipboard_update = self.link.callback(RemoteMsg::UpdateClipboard); let clipboard_update = self.link.callback(VncMsg::UpdateClipboard);
let websocket = &self.websocket; let websocket = &self.websocket;
let clipboard = &self.clipboard; let clipboard = &self.clipboard;
html! { html! {
@ -218,7 +218,7 @@ impl Component for PageRemote {
} }
// impl PageRemote // impl PageRemote
impl PageRemote { impl PageVnc {
fn protocal_out_handler(&mut self) -> ShouldRender { fn protocal_out_handler(&mut self) -> ShouldRender {
let out = self.handler.get_output(); let out = self.handler.get_output();
let mut should_render = false; let mut should_render = false;
@ -236,7 +236,7 @@ impl PageRemote {
} }
ProtocalHandlerOutput::WsBuf(out) => { ProtocalHandlerOutput::WsBuf(out) => {
if out.len() > 0 { if out.len() > 0 {
self.link.send_message(RemoteMsg::Send(out)); self.link.send_message(VncMsg::Send(out));
} }
} }
ProtocalHandlerOutput::RequirePassword => { ProtocalHandlerOutput::RequirePassword => {
@ -256,6 +256,26 @@ impl PageRemote {
} }
}; };
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( let data = ImageData::new_with_u8_clamped_array_and_sh(
Clamped(&cr.data), Clamped(&cr.data),
cr.width as u32, cr.width as u32,
@ -267,6 +287,9 @@ impl PageRemote {
// cr.x, cr.y, cr.width, cr.height // cr.x, cr.y, cr.width, cr.height
// )); // ));
let _ = ctx.put_image_data(&data, cr.x as f64, cr.y as f64); let _ = ctx.put_image_data(&data, cr.x as f64, cr.y as f64);
}
}
should_render = true; should_render = true;
} }
ProtocalHandlerOutput::SetCanvas(width, height) => { ProtocalHandlerOutput::SetCanvas(width, height) => {
@ -274,7 +297,7 @@ impl PageRemote {
canvas.set_width(width as u32); canvas.set_width(width as u32);
canvas.set_height(height as u32); canvas.set_height(height as u32);
self.bind_mouse_and_key(&canvas); 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 { let ctx = match &self.canvas_ctx {
Some(ctx) => ctx, Some(ctx) => ctx,
None => { None => {
@ -305,7 +328,7 @@ impl PageRemote {
fn username_view(&self) -> Html { fn username_view(&self) -> Html {
if self.request_username { if self.request_username {
let update_username = self.link.callback(RemoteMsg::UpdateUsername); let update_username = self.link.callback(VncMsg::UpdateUsername);
html! { html! {
<> <>
<Input id="username" type_="text" placeholder="username" on_change={update_username}/> <Input id="username" type_="text" placeholder="username" on_change={update_username}/>
@ -319,7 +342,7 @@ impl PageRemote {
fn password_view(&self) -> Html { fn password_view(&self) -> Html {
if self.request_password { if self.request_password {
let update_password = self.link.callback(RemoteMsg::UpdatePassword); let update_password = self.link.callback(VncMsg::UpdatePassword);
html! { html! {
<> <>
<Input id="password" type_="password" placeholder="password" on_change={update_password}/> <Input id="password" type_="password" placeholder="password" on_change={update_password}/>
@ -333,7 +356,7 @@ impl PageRemote {
fn button_connect_view(&self) -> Html { fn button_connect_view(&self) -> Html {
if self.request_username || self.request_password { if self.request_username || self.request_password {
let send_credential = self.link.callback(|_| RemoteMsg::SendCredential); let send_credential = self.link.callback(|_| VncMsg::SendCredential);
html! { html! {
<> <>
<button type="submit" onclick={send_credential}>{"Connect"}</button> <button type="submit" onclick={send_credential}>{"Connect"}</button>

View File

@ -1,6 +1,7 @@
use std::{rc::Rc, sync::Mutex}; use std::{rc::Rc, sync::Mutex};
pub struct CanvasData { pub struct CanvasData {
pub type_: u32,
pub x: u16, pub x: u16,
pub y: u16, pub y: u16,
pub width: u16, pub width: u16,

View File

@ -23,6 +23,7 @@ pub enum SecurityType {
// VeNCrypt = 19, // VeNCrypt = 19,
} }
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)] #[repr(i32)]
pub enum VncEncoding { pub enum VncEncoding {
@ -79,7 +80,7 @@ impl ProtocalImpl for VncHandler {
state: VncState::Init, state: VncState::Init,
supported_encodings: vec![ supported_encodings: vec![
VncEncoding::Raw, VncEncoding::Raw,
// VncEncoding::CopyRect, VncEncoding::CopyRect,
// VncEncoding::RRE, // VncEncoding::RRE,
// VncEncoding::Hextile, // VncEncoding::Hextile,
// VncEncoding::TRLE, // VncEncoding::TRLE,
@ -554,10 +555,15 @@ impl VncHandler {
} }
} }
} }
1 => {
// copy rectangle
self.read_exact_vec(&mut image_data, 4);
}
_ => unimplemented!(), _ => unimplemented!(),
} }
self.outs self.outs
.push(ProtocalHandlerOutput::RenderCanvas(CanvasData { .push(ProtocalHandlerOutput::RenderCanvas(CanvasData {
type_: rect.encoding_type,
x: rect.x, x: rect.x,
y: rect.y, y: rect.y,
width: rect.width, width: rect.width,
@ -649,19 +655,31 @@ impl VncHandler {
width, width,
height, height,
encoding_type: 0, 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) { fn handle_copy_rect_encoding(&mut self, x: u16, y: u16, width: u16, height: u16) {
unimplemented!() 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) { 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!() unimplemented!()
} }
fn handle_hextile_encoding(&mut self, _x: u16, _y: u16, _width: u16, _height: u16) { 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!() unimplemented!()
} }
@ -800,5 +818,4 @@ struct VncRect {
width: u16, width: u16,
height: u16, height: u16,
encoding_type: u32, encoding_type: u32,
encoding_data: Vec<u8>,
} }

View File

@ -3,8 +3,6 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
#![allow(non_upper_case_globals)] #![allow(non_upper_case_globals)]
// referring: // referring:
// https://github.com/AltF02/x11-rs/blob/master/src/keysym.rs // https://github.com/AltF02/x11-rs/blob/master/src/keysym.rs