commit
4d63056d07
69
frontend/src/components/clipboard.rs
Normal file
69
frontend/src/components/clipboard.rs
Normal file
@ -0,0 +1,69 @@
|
||||
use yew::prelude::*;
|
||||
|
||||
use crate::utils::WeakComponentLink;
|
||||
|
||||
pub enum ClipboardMsg {
|
||||
UpdateClipboard(String),
|
||||
SendClipboard,
|
||||
}
|
||||
|
||||
pub struct Clipboard {
|
||||
link: ComponentLink<Self>,
|
||||
onsubmit: Callback<String>,
|
||||
text: String,
|
||||
}
|
||||
|
||||
// Props
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct ClipboardProps {
|
||||
#[prop_or_default]
|
||||
pub weak_link: WeakComponentLink<Clipboard>,
|
||||
pub onsubmit: Callback<String>,
|
||||
}
|
||||
|
||||
impl Component for Clipboard {
|
||||
type Message = ClipboardMsg;
|
||||
type Properties = ClipboardProps;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
props.weak_link.borrow_mut().replace(link.clone());
|
||||
Clipboard {
|
||||
link,
|
||||
onsubmit: props.onsubmit,
|
||||
text: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
ClipboardMsg::UpdateClipboard(text) => {
|
||||
self.text = text;
|
||||
}
|
||||
ClipboardMsg::SendClipboard => {
|
||||
self.onsubmit.emit(self.text.clone());
|
||||
self.text.clear();
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let update_clipboard = self.link.callback(|e: ChangeData| match e {
|
||||
ChangeData::Value(v) => ClipboardMsg::UpdateClipboard(v),
|
||||
_ => panic!("unexpected message"),
|
||||
});
|
||||
let set_clipboard = self.link.callback(|_| ClipboardMsg::SendClipboard);
|
||||
html! {
|
||||
<>
|
||||
<textarea rows="5" cols="60" id="clipboard" onchange=update_clipboard value=self.text.clone()/>
|
||||
<br/>
|
||||
<button id="clipboard-send" onclick=set_clipboard> {"Send to peer"} </button>
|
||||
<br/>
|
||||
</>
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
pub mod auth;
|
||||
pub mod clipboard;
|
||||
pub mod host;
|
||||
pub mod input;
|
||||
pub mod ws;
|
||||
|
@ -26,7 +26,7 @@ pub struct PageRemote {
|
||||
fetch_task: Option<FetchTask>,
|
||||
connected: bool,
|
||||
handler: ProtocalHandler<VncHandler>,
|
||||
ws_link: WeakComponentLink<components::ws::WebsocketCtx>,
|
||||
websocket: WeakComponentLink<components::ws::WebsocketCtx>,
|
||||
request_username: bool,
|
||||
request_password: bool,
|
||||
username: String,
|
||||
@ -34,6 +34,7 @@ pub struct PageRemote {
|
||||
canvas: NodeRef,
|
||||
canvas_ctx: Option<CanvasRenderingContext2d>,
|
||||
interval: Option<Interval>,
|
||||
clipboard: WeakComponentLink<components::clipboard::Clipboard>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
@ -47,6 +48,7 @@ pub enum RemoteMsg {
|
||||
Send(Vec<u8>),
|
||||
UpdateUsername(String),
|
||||
UpdatePassword(String),
|
||||
UpdateClipboard(String),
|
||||
SendCredential,
|
||||
RequireFrame(u8),
|
||||
}
|
||||
@ -63,7 +65,7 @@ impl Component for PageRemote {
|
||||
fetch_task: None,
|
||||
connected: false,
|
||||
handler: ProtocalHandler::new(),
|
||||
ws_link: WeakComponentLink::default(),
|
||||
websocket: WeakComponentLink::default(),
|
||||
request_username: false,
|
||||
request_password: false,
|
||||
username: String::from(""),
|
||||
@ -71,6 +73,7 @@ impl Component for PageRemote {
|
||||
canvas: NodeRef::default(),
|
||||
canvas_ctx: None,
|
||||
interval: None,
|
||||
clipboard: WeakComponentLink::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,7 +132,7 @@ impl Component for PageRemote {
|
||||
self.protocal_out_handler()
|
||||
}
|
||||
RemoteMsg::Send(v) => {
|
||||
self.ws_link
|
||||
self.websocket
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
@ -160,6 +163,14 @@ impl Component for PageRemote {
|
||||
}
|
||||
self.protocal_out_handler()
|
||||
}
|
||||
RemoteMsg::UpdateClipboard(clipboard) => {
|
||||
if clipboard.len() > 0 {
|
||||
self.handler.set_clipboard(&clipboard);
|
||||
self.protocal_out_handler()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,7 +189,9 @@ impl Component for PageRemote {
|
||||
}
|
||||
} else {
|
||||
let recv_msg = self.link.callback(RemoteMsg::Recv);
|
||||
let ws_link = &self.ws_link;
|
||||
let clipboard_update = self.link.callback(RemoteMsg::UpdateClipboard);
|
||||
let websocket = &self.websocket;
|
||||
let clipboard = &self.clipboard;
|
||||
html! {
|
||||
<>
|
||||
<div class="horizontal-centre vertical-centre">
|
||||
@ -186,8 +199,10 @@ impl Component for PageRemote {
|
||||
{self.password_view()}
|
||||
{self.button_connect_view()}
|
||||
<components::ws::WebsocketCtx
|
||||
weak_link=ws_link onrecv=recv_msg/>
|
||||
weak_link=websocket onrecv=recv_msg/>
|
||||
<canvas id="remote-canvas" ref=self.canvas.clone()></canvas>
|
||||
<components::clipboard::Clipboard
|
||||
weak_link=clipboard onsubmit=clipboard_update/>
|
||||
{self.error_msg.clone()}
|
||||
</div>
|
||||
</>
|
||||
@ -212,7 +227,7 @@ impl PageRemote {
|
||||
match o {
|
||||
ProtocalHandlerOutput::Err(err) => {
|
||||
self.error_msg = err.clone();
|
||||
self.ws_link
|
||||
self.websocket
|
||||
.borrow_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
@ -220,7 +235,9 @@ impl PageRemote {
|
||||
should_render = true;
|
||||
}
|
||||
ProtocalHandlerOutput::WsBuf(out) => {
|
||||
self.link.send_message(RemoteMsg::Send(out));
|
||||
if out.len() > 0 {
|
||||
self.link.send_message(RemoteMsg::Send(out));
|
||||
}
|
||||
}
|
||||
ProtocalHandlerOutput::RequirePassword => {
|
||||
self.request_password = true;
|
||||
@ -273,9 +290,11 @@ impl PageRemote {
|
||||
should_render = true;
|
||||
}
|
||||
ProtocalHandlerOutput::SetClipboard(text) => {
|
||||
self.error_msg = format!("Clipboard get {}", text);
|
||||
ConsoleService::log(&self.error_msg);
|
||||
should_render = true;
|
||||
self.clipboard.borrow_mut().as_mut().unwrap().send_message(
|
||||
components::clipboard::ClipboardMsg::UpdateClipboard(text),
|
||||
);
|
||||
// ConsoleService::log(&self.error_msg);
|
||||
should_render = false;
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
@ -330,6 +349,7 @@ impl PageRemote {
|
||||
let window = web_sys::window().unwrap();
|
||||
let handler = self.handler.clone();
|
||||
let key_down = move |e: KeyboardEvent| {
|
||||
e.prevent_default();
|
||||
e.stop_propagation();
|
||||
handler.key_press(e, true);
|
||||
};
|
||||
@ -345,6 +365,7 @@ impl PageRemote {
|
||||
|
||||
let handler = self.handler.clone();
|
||||
let key_up = move |e: KeyboardEvent| {
|
||||
e.prevent_default();
|
||||
e.stop_propagation();
|
||||
handler.key_press(e, false);
|
||||
};
|
||||
|
@ -68,6 +68,10 @@ where
|
||||
.set_credential(username, password);
|
||||
}
|
||||
|
||||
pub fn set_clipboard(&mut self, text: &str) {
|
||||
self.inner.as_ref().lock().unwrap().set_clipboard(text);
|
||||
}
|
||||
|
||||
pub fn set_resolution(&self, width: u16, height: u16) {
|
||||
self.inner
|
||||
.as_ref()
|
||||
@ -100,6 +104,7 @@ pub trait ProtocalImpl {
|
||||
fn do_input(&mut self, input: Vec<u8>);
|
||||
fn get_output(&mut self) -> Vec<ProtocalHandlerOutput>;
|
||||
fn set_credential(&mut self, username: &str, password: &str);
|
||||
fn set_clipboard(&mut self, text: &str);
|
||||
fn set_resolution(&mut self, width: u16, height: u16);
|
||||
fn key_press(&mut self, key: web_sys::KeyboardEvent, down: bool);
|
||||
fn mouse_event(&mut self, mouse: web_sys::MouseEvent, et: MouseEventType);
|
||||
@ -233,18 +238,18 @@ impl<'a> StreamWriter<'a> {
|
||||
self.write_u32(b as u32);
|
||||
}
|
||||
|
||||
pub fn write_string_with_len(&mut self, s: &str) {
|
||||
pub fn write_string(&mut self, s: &str) {
|
||||
self.inner.extend_from_slice(s.as_bytes());
|
||||
}
|
||||
|
||||
pub fn write_string_l16(&mut self, s: &str) {
|
||||
self.write_u16(s.len() as u16);
|
||||
self.write_string_with_len(s);
|
||||
self.write_string(s);
|
||||
}
|
||||
|
||||
pub fn write_string_l32(&mut self, s: &str) {
|
||||
self.write_u32(s.len() as u32);
|
||||
self.write_string_with_len(s);
|
||||
self.write_string(s);
|
||||
}
|
||||
|
||||
pub fn write_slice(&mut self, s: &[u8]) {
|
||||
|
@ -123,16 +123,20 @@ impl ProtocalImpl for VncHandler {
|
||||
}
|
||||
|
||||
fn get_output(&mut self) -> Vec<ProtocalHandlerOutput> {
|
||||
let mut out = Vec::with_capacity(self.outs.len());
|
||||
// ConsoleService::log(&format!("Get {} output", self.outs.len()));
|
||||
for o in self.outs.drain(..) {
|
||||
out.push(o);
|
||||
if let ServerMessage::None = self.msg_handling {
|
||||
let mut out = Vec::with_capacity(self.outs.len());
|
||||
// ConsoleService::log(&format!("Get {} output", self.outs.len()));
|
||||
for o in self.outs.drain(..) {
|
||||
out.push(o);
|
||||
}
|
||||
if !self.outbuf.is_empty() {
|
||||
out.push(ProtocalHandlerOutput::WsBuf(self.outbuf.clone()));
|
||||
self.outbuf.clear();
|
||||
}
|
||||
return out;
|
||||
} else {
|
||||
return Vec::new();
|
||||
}
|
||||
if !self.outbuf.is_empty() {
|
||||
out.push(ProtocalHandlerOutput::WsBuf(self.outbuf.clone()));
|
||||
self.outbuf.clear();
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn set_credential(&mut self, _username: &str, password: &str) {
|
||||
@ -162,6 +166,10 @@ impl ProtocalImpl for VncHandler {
|
||||
self.require = 4; // the auth result message length
|
||||
}
|
||||
|
||||
fn set_clipboard(&mut self, text: &str) {
|
||||
self.send_client_cut_text(text);
|
||||
}
|
||||
|
||||
fn set_resolution(&mut self, _width: u16, _height: u16) {
|
||||
// VNC client doen't support resolution change
|
||||
}
|
||||
@ -171,9 +179,7 @@ impl ProtocalImpl for VncHandler {
|
||||
return;
|
||||
}
|
||||
let key = x11keyboard::KeyboardUtils::get_keysym(key);
|
||||
if let ServerMessage::None = self.msg_handling {
|
||||
self.send_key_event(key, down);
|
||||
}
|
||||
self.send_key_event(key, down);
|
||||
}
|
||||
|
||||
fn mouse_event(&mut self, mouse: web_sys::MouseEvent, et: MouseEventType) {
|
||||
@ -181,9 +187,7 @@ impl ProtocalImpl for VncHandler {
|
||||
return;
|
||||
}
|
||||
let (x, y, mask) = self.mouse.get_mouse_sym(mouse, et);
|
||||
if let ServerMessage::None = self.msg_handling {
|
||||
self.send_pointer_event(x, y, mask);
|
||||
}
|
||||
self.send_pointer_event(x, y, mask);
|
||||
}
|
||||
|
||||
fn require_frame(&mut self, incremental: u8) {
|
||||
@ -324,7 +328,29 @@ impl VncHandler {
|
||||
sw.write_u16(x); // x
|
||||
sw.write_u16(y); // y
|
||||
|
||||
ConsoleService::log(&format!("send mouse event {:x?} {:x?} {:#08b}", x, y, mask));
|
||||
// ConsoleService::log(&format!("send mouse event {:x?} {:x?} {:#08b}", x, y, mask));
|
||||
self.outbuf.extend_from_slice(&out);
|
||||
}
|
||||
|
||||
// +--------------+--------------+--------------+
|
||||
// | No. of bytes | Type [Value] | Description |
|
||||
// +--------------+--------------+--------------+
|
||||
// | 1 | U8 [6] | message-type |
|
||||
// | 3 | | padding |
|
||||
// | 4 | U32 | length |
|
||||
// | length | U8 array | text |
|
||||
// +--------------+--------------+--------------+
|
||||
fn send_client_cut_text(&mut self, text: &str) {
|
||||
let mut out = Vec::with_capacity(10);
|
||||
let mut sw = StreamWriter::new(&mut out);
|
||||
let len: u32 = text.len().try_into().unwrap_or(0);
|
||||
sw.write_u8(6); // message-type
|
||||
sw.write_u8(0); // padding
|
||||
sw.write_u16(0); // padding
|
||||
sw.write_u32(len); // length
|
||||
sw.write_string(text); // text
|
||||
|
||||
// ConsoleService::log(&format!("send client cut text {:?}", len));
|
||||
self.outbuf.extend_from_slice(&out);
|
||||
}
|
||||
|
||||
@ -546,8 +572,6 @@ impl VncHandler {
|
||||
self.require = 12; // the length of the next rectangle hdr
|
||||
}
|
||||
}
|
||||
|
||||
// ConsoleService::log(&format!("{} rects left", self.num_rects_left));
|
||||
}
|
||||
|
||||
// Currently there is little or no support for colour maps. Some preliminary work was done
|
||||
|
@ -3,7 +3,7 @@
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use yew::services::ConsoleService;
|
||||
|
||||
|
||||
// referring:
|
||||
// https://github.com/AltF02/x11-rs/blob/master/src/keysym.rs
|
||||
@ -1347,7 +1347,7 @@ impl KeyboardUtils {
|
||||
let capslock = event.get_modifier_state("CapsLock");
|
||||
let upper = capslock ^ shift;
|
||||
let which = event.which();
|
||||
ConsoleService::log(&format!("which {}, shift {}", which, shift));
|
||||
// ConsoleService::log(&format!("which {}, shift {}", which, shift));
|
||||
match which {
|
||||
8_u32 => {
|
||||
// Backspace
|
||||
@ -1359,7 +1359,7 @@ impl KeyboardUtils {
|
||||
}
|
||||
13_u32 => {
|
||||
// Enter
|
||||
XK_Linefeed
|
||||
XK_Return
|
||||
}
|
||||
16_u32 => {
|
||||
// ShiftLeft
|
||||
|
Loading…
Reference in New Issue
Block a user