mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
@@ -826,7 +826,7 @@ impl LoginConfigHandler {
|
||||
msg.lock_after_session_end = BoolOption::Yes.into();
|
||||
n += 1;
|
||||
}
|
||||
if self.get_toggle_option("privacy_mode") {
|
||||
if self.get_toggle_option("privacy-mode") {
|
||||
msg.privacy_mode = BoolOption::Yes.into();
|
||||
n += 1;
|
||||
}
|
||||
|
||||
@@ -600,12 +600,13 @@ pub fn lock_screen() {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn toggle_privacy_mode(_v: bool) {
|
||||
pub fn toggle_blank_screen(_v: bool) {
|
||||
// https://unix.stackexchange.com/questions/17170/disable-keyboard-mouse-input-on-unix-under-x
|
||||
}
|
||||
|
||||
pub fn block_input(_v: bool) {
|
||||
pub fn block_input(_v: bool) -> bool {
|
||||
//
|
||||
true
|
||||
}
|
||||
|
||||
pub fn is_installed() -> bool {
|
||||
|
||||
@@ -398,12 +398,13 @@ pub fn start_os_service() {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_privacy_mode(_v: bool) {
|
||||
pub fn toggle_blank_screen(_v: bool) {
|
||||
// https://unix.stackexchange.com/questions/17115/disable-keyboard-mouse-temporarily
|
||||
}
|
||||
|
||||
pub fn block_input(_v: bool) {
|
||||
pub fn block_input(_v: bool) -> bool {
|
||||
//
|
||||
true
|
||||
}
|
||||
|
||||
pub fn is_installed() -> bool {
|
||||
|
||||
@@ -1020,11 +1020,9 @@ pub fn toggle_blank_screen(v: bool) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn block_input(v: bool) {
|
||||
pub fn block_input(v: bool) -> bool {
|
||||
let v = if v { TRUE } else { FALSE };
|
||||
unsafe {
|
||||
BlockInput(v);
|
||||
}
|
||||
unsafe { BlockInput(v) == TRUE }
|
||||
}
|
||||
|
||||
pub fn add_recent_document(path: &str) {
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
use super::input_service::*;
|
||||
use super::*;
|
||||
use crate::common::update_clipboard;
|
||||
use crate::ipc;
|
||||
use super::{input_service::*, *};
|
||||
use crate::{common::update_clipboard, ipc};
|
||||
use hbb_common::{
|
||||
config::Config,
|
||||
fs,
|
||||
futures::{SinkExt, StreamExt},
|
||||
sleep, timeout,
|
||||
protobuf, sleep, timeout,
|
||||
tokio::{
|
||||
net::TcpStream,
|
||||
sync::mpsc,
|
||||
@@ -30,6 +28,15 @@ pub struct ConnInner {
|
||||
tx_video: Option<Sender>,
|
||||
}
|
||||
|
||||
enum MessageInput {
|
||||
InputFunc(Box<dyn Send + FnMut()>),
|
||||
BlockOn,
|
||||
BlockOff,
|
||||
PrivacyOn,
|
||||
PrivacyOff,
|
||||
Exit,
|
||||
}
|
||||
|
||||
pub struct Connection {
|
||||
inner: ConnInner,
|
||||
stream: super::Stream,
|
||||
@@ -51,8 +58,10 @@ pub struct Connection {
|
||||
show_remote_cursor: bool, // by peer
|
||||
privacy_mode: bool,
|
||||
ip: String,
|
||||
disable_clipboard: bool, // by peer
|
||||
disable_audio: bool, // by peer
|
||||
disable_clipboard: bool, // by peer
|
||||
disable_audio: bool, // by peer
|
||||
tx_input: SyncSender<MessageInput>, // handle input messages
|
||||
rx_input_res: Receiver<bool>,
|
||||
}
|
||||
|
||||
impl Subscriber for ConnInner {
|
||||
@@ -85,14 +94,6 @@ const MILLI1: Duration = Duration::from_millis(1);
|
||||
const SEND_TIMEOUT_VIDEO: u64 = 12_000;
|
||||
const SEND_TIMEOUT_OTHER: u64 = SEND_TIMEOUT_VIDEO * 10;
|
||||
|
||||
type SyncFunc = Box<dyn Send + FnMut()>;
|
||||
|
||||
enum BlankChannelMsg {
|
||||
On,
|
||||
Off,
|
||||
Exit,
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
pub async fn start(
|
||||
addr: SocketAddr,
|
||||
@@ -109,6 +110,9 @@ impl Connection {
|
||||
let (tx_to_cm, rx_to_cm) = mpsc::unbounded_channel::<ipc::Data>();
|
||||
let (tx, mut rx) = mpsc::unbounded_channel::<(Instant, Arc<Message>)>();
|
||||
let (tx_video, mut rx_video) = mpsc::unbounded_channel::<(Instant, Arc<Message>)>();
|
||||
let (tx_input, rx_input) = sync_channel(1);
|
||||
let (tx_input_res, rx_input_res) = sync_channel(1);
|
||||
|
||||
let mut conn = Self {
|
||||
inner: ConnInner {
|
||||
id,
|
||||
@@ -136,6 +140,8 @@ impl Connection {
|
||||
ip: "".to_owned(),
|
||||
disable_audio: false,
|
||||
disable_clipboard: false,
|
||||
tx_input,
|
||||
rx_input_res,
|
||||
};
|
||||
tokio::spawn(async move {
|
||||
if let Err(err) = start_ipc(rx_to_cm, tx_from_cm).await {
|
||||
@@ -166,11 +172,7 @@ impl Connection {
|
||||
},
|
||||
);
|
||||
|
||||
let (input_sender, input_receiver) = sync_channel(1);
|
||||
|
||||
let (blank_sender, blank_receiver) = sync_channel(1);
|
||||
let _ = std::thread::spawn(move || Self::handle_input(input_receiver));
|
||||
let blank_handler = std::thread::spawn(move || Self::handle_blank(blank_receiver));
|
||||
let handler_input = std::thread::spawn(move || Self::handle_input(rx_input, tx_input_res));
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
@@ -247,7 +249,7 @@ impl Connection {
|
||||
Ok(bytes) => {
|
||||
last_recv_time = Instant::now();
|
||||
if let Ok(msg_in) = Message::parse_from_bytes(&bytes) {
|
||||
if !conn.on_message(msg_in, input_sender.clone(), blank_sender.clone()).await {
|
||||
if !conn.on_message(msg_in).await {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -312,12 +314,14 @@ impl Connection {
|
||||
}
|
||||
}
|
||||
|
||||
blank_sender.send(BlankChannelMsg::Exit).unwrap();
|
||||
if let Err(e) = blank_handler.join() {
|
||||
log::error!("Failed to join blank thread, {:?}", e);
|
||||
};
|
||||
conn.tx_input.send(MessageInput::Exit).unwrap();
|
||||
if let Err(e) = handler_input.join() {
|
||||
log::error!("Failed to join input thread, {:?}", e);
|
||||
} else {
|
||||
log::info!("Blank thread exited");
|
||||
}
|
||||
|
||||
crate::platform::block_input(false);
|
||||
let _ = crate::platform::block_input(false);
|
||||
crate::platform::toggle_blank_screen(false);
|
||||
|
||||
video_service::notify_video_frame_feched(id, None);
|
||||
@@ -328,30 +332,80 @@ impl Connection {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// 1. Send "Block Input" and "Privacy Mode" when connection established.
|
||||
// 2. Ctrl + Alt + Del will break "Block Input"
|
||||
fn handle_input(receiver: Receiver<SyncFunc>) {
|
||||
fn handle_input(receiver: Receiver<MessageInput>, tx_input_res: SyncSender<bool>) {
|
||||
let mut block_input_mode = false;
|
||||
let (tx_blank, rx_blank) = sync_channel(1);
|
||||
|
||||
let handler_blank = std::thread::spawn(|| Self::handle_blank(rx_blank));
|
||||
|
||||
loop {
|
||||
match receiver.recv() {
|
||||
Ok(mut f) => {
|
||||
f();
|
||||
match receiver.recv_timeout(std::time::Duration::from_millis(500)) {
|
||||
Ok(v) => match v {
|
||||
MessageInput::InputFunc(mut f) => {
|
||||
f();
|
||||
}
|
||||
MessageInput::BlockOn => {
|
||||
if crate::platform::block_input(true) {
|
||||
block_input_mode = true;
|
||||
tx_input_res.send(true).unwrap();
|
||||
} else {
|
||||
tx_input_res.send(false).unwrap();
|
||||
}
|
||||
}
|
||||
MessageInput::BlockOff => {
|
||||
if crate::platform::block_input(false) {
|
||||
block_input_mode = false;
|
||||
tx_input_res.send(true).unwrap();
|
||||
} else {
|
||||
tx_input_res.send(false).unwrap();
|
||||
}
|
||||
}
|
||||
MessageInput::PrivacyOn => {
|
||||
if crate::platform::block_input(true) {
|
||||
block_input_mode = true;
|
||||
tx_input_res.send(true).unwrap();
|
||||
} else {
|
||||
tx_input_res.send(false).unwrap();
|
||||
}
|
||||
tx_blank.send(MessageInput::PrivacyOn).unwrap();
|
||||
}
|
||||
MessageInput::PrivacyOff => {
|
||||
if crate::platform::block_input(false) {
|
||||
block_input_mode = false;
|
||||
tx_input_res.send(true).unwrap();
|
||||
} else {
|
||||
tx_input_res.send(false).unwrap();
|
||||
}
|
||||
tx_blank.send(MessageInput::PrivacyOff).unwrap();
|
||||
}
|
||||
MessageInput::Exit => break,
|
||||
},
|
||||
_ => {
|
||||
if block_input_mode {
|
||||
let _ = crate::platform::block_input(true);
|
||||
}
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
|
||||
tx_blank.send(MessageInput::Exit).unwrap();
|
||||
if let Err(_) = handler_blank.join() {
|
||||
log::error!("Failed to join blank thread handler");
|
||||
} else {
|
||||
log::info!("Blank thread exited");
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_blank(receiver: Receiver<BlankChannelMsg>) {
|
||||
fn handle_blank(receiver: Receiver<MessageInput>) {
|
||||
let mut last_privacy = false;
|
||||
loop {
|
||||
match receiver.recv_timeout(std::time::Duration::from_millis(500)) {
|
||||
Ok(v) => match v {
|
||||
BlankChannelMsg::On => {
|
||||
MessageInput::PrivacyOn => {
|
||||
crate::platform::toggle_blank_screen(true);
|
||||
last_privacy = true;
|
||||
}
|
||||
BlankChannelMsg::Off => {
|
||||
MessageInput::PrivacyOff => {
|
||||
crate::platform::toggle_blank_screen(false);
|
||||
last_privacy = false;
|
||||
}
|
||||
@@ -597,15 +651,22 @@ impl Connection {
|
||||
self.send(msg_out).await;
|
||||
}
|
||||
|
||||
async fn on_message(
|
||||
&mut self,
|
||||
msg: Message,
|
||||
input_sender: SyncSender<SyncFunc>,
|
||||
blank_sender: SyncSender<BlankChannelMsg>,
|
||||
) -> bool {
|
||||
async fn send_option_error<T: std::string::ToString>(&mut self, err: T, opt: OptionMessage) {
|
||||
let mut msg_out = Message::new();
|
||||
let mut res = OptionResponse::new();
|
||||
let mut misc = Misc::new();
|
||||
res.opt = protobuf::MessageField::some(opt);
|
||||
res.error = err.to_string();
|
||||
|
||||
misc.set_option_response(res);
|
||||
msg_out.set_misc(misc);
|
||||
self.send(msg_out).await;
|
||||
}
|
||||
|
||||
async fn on_message(&mut self, msg: Message) -> bool {
|
||||
if let Some(message::Union::login_request(lr)) = msg.union {
|
||||
if let Some(o) = lr.option.as_ref() {
|
||||
self.update_option(o, input_sender, blank_sender);
|
||||
self.update_option(o).await;
|
||||
}
|
||||
if self.authorized {
|
||||
return true;
|
||||
@@ -721,7 +782,11 @@ impl Connection {
|
||||
Some(message::Union::mouse_event(me)) => {
|
||||
if self.keyboard {
|
||||
let conn_id = self.inner.id();
|
||||
input_sender.send(Box::new(move || handle_mouse(&me, conn_id))).unwrap();
|
||||
self.tx_input
|
||||
.send(MessageInput::InputFunc(Box::new(move || {
|
||||
handle_mouse(&me, conn_id)
|
||||
})))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
Some(message::Union::key_event(mut me)) => {
|
||||
@@ -736,19 +801,31 @@ impl Connection {
|
||||
};
|
||||
if is_press {
|
||||
if let Some(key_event::Union::unicode(_)) = me.union {
|
||||
input_sender.send(Box::new(move || handle_key(&me))).unwrap();
|
||||
self.tx_input
|
||||
.send(MessageInput::InputFunc(Box::new(move || {
|
||||
handle_key(&me)
|
||||
})))
|
||||
.unwrap();
|
||||
} else if let Some(key_event::Union::seq(_)) = me.union {
|
||||
input_sender.send(Box::new(move || handle_key(&me))).unwrap();
|
||||
self.tx_input
|
||||
.send(MessageInput::InputFunc(Box::new(move || {
|
||||
handle_key(&me)
|
||||
})))
|
||||
.unwrap();
|
||||
} else {
|
||||
input_sender.send(Box::new(move || {
|
||||
me.down = true;
|
||||
handle_key(&me);
|
||||
me.down = false;
|
||||
handle_key(&me);
|
||||
})).unwrap();
|
||||
self.tx_input
|
||||
.send(MessageInput::InputFunc(Box::new(move || {
|
||||
me.down = true;
|
||||
handle_key(&me);
|
||||
me.down = false;
|
||||
handle_key(&me);
|
||||
})))
|
||||
.unwrap();
|
||||
}
|
||||
} else {
|
||||
input_sender.send(Box::new(move || handle_key(&me))).unwrap();
|
||||
self.tx_input
|
||||
.send(MessageInput::InputFunc(Box::new(move || handle_key(&me))))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -851,7 +928,7 @@ impl Connection {
|
||||
self.send_to_cm(ipc::Data::ChatMessage { text: c.text });
|
||||
}
|
||||
Some(misc::Union::option(o)) => {
|
||||
self.update_option(&o, input_sender, blank_sender);
|
||||
self.update_option(&o).await;
|
||||
}
|
||||
Some(misc::Union::refresh_video(r)) => {
|
||||
if r {
|
||||
@@ -866,12 +943,7 @@ impl Connection {
|
||||
true
|
||||
}
|
||||
|
||||
fn update_option(
|
||||
&mut self,
|
||||
o: &OptionMessage,
|
||||
input_sender: SyncSender<SyncFunc>,
|
||||
blank_sender: SyncSender<BlankChannelMsg>,
|
||||
) {
|
||||
async fn update_option(&mut self, o: &OptionMessage) {
|
||||
log::info!("Option update: {:?}", o);
|
||||
if let Ok(q) = o.image_quality.enum_value() {
|
||||
self.image_quality = q.value();
|
||||
@@ -929,25 +1001,54 @@ impl Connection {
|
||||
}
|
||||
}
|
||||
if let Ok(q) = o.privacy_mode.enum_value() {
|
||||
if q != BoolOption::NotSet {
|
||||
self.privacy_mode = q == BoolOption::Yes;
|
||||
if self.keyboard {
|
||||
if self.privacy_mode {
|
||||
input_sender.send(Box::new(move||{crate::platform::block_input(true)})).unwrap();
|
||||
blank_sender.send(BlankChannelMsg::On).unwrap();
|
||||
} else {
|
||||
input_sender.send(Box::new(move||{crate::platform::block_input(false)})).unwrap();
|
||||
blank_sender.send(BlankChannelMsg::Off).unwrap();
|
||||
if self.keyboard {
|
||||
match q {
|
||||
BoolOption::Yes => {
|
||||
self.privacy_mode = true;
|
||||
self.tx_input.send(MessageInput::PrivacyOn).unwrap();
|
||||
if self.rx_input_res.recv().unwrap() {
|
||||
log::info!("Privacy mode on");
|
||||
} else {
|
||||
log::error!("Failed to trun on privacy mode");
|
||||
self.send_option_error("Failed to turn on privacy mode", o.clone())
|
||||
.await;
|
||||
}
|
||||
}
|
||||
BoolOption::No => {
|
||||
self.privacy_mode = false;
|
||||
self.tx_input.send(MessageInput::PrivacyOff).unwrap();
|
||||
if self.rx_input_res.recv().unwrap() {
|
||||
log::info!("Privacy mode off");
|
||||
} else {
|
||||
log::warn!("Failed to trun off privacy mode")
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.keyboard {
|
||||
if let Ok(q) = o.block_input.enum_value() {
|
||||
if q != BoolOption::NotSet {
|
||||
input_sender.send(Box::new(move || {
|
||||
crate::platform::block_input(q == BoolOption::Yes)
|
||||
})).unwrap();
|
||||
match q {
|
||||
BoolOption::Yes => {
|
||||
self.tx_input.send(MessageInput::BlockOn).unwrap();
|
||||
if self.rx_input_res.recv().unwrap() {
|
||||
log::info!("Block input mode on");
|
||||
} else {
|
||||
log::error!("Failed to trun on block input mode");
|
||||
self.send_option_error("Failed to turn on block input mode", o.clone())
|
||||
.await;
|
||||
}
|
||||
}
|
||||
BoolOption::No => {
|
||||
self.tx_input.send(MessageInput::BlockOff).unwrap();
|
||||
if self.rx_input_res.recv().unwrap() {
|
||||
log::info!("Block input mode off");
|
||||
} else {
|
||||
log::error!("Failed to trun off block input mode");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ class Header: Reactor.Component {
|
||||
{keyboard_enabled && (pi.platform == "Linux" || pi.sas_enabled) ? <li #ctrl-alt-del>{translate('Insert')} Ctrl + Alt + Del</li> : ""}
|
||||
<div .separator />
|
||||
{keyboard_enabled ? <li #lock-screen>{translate('Insert Lock')}</li> : ""}
|
||||
{pi.platform == "Windows" ? <li #block-input>Block user input </li> : ""}
|
||||
{false && pi.platform == "Windows" ? <li #block-input>Block user input </li> : ""}
|
||||
{handler.support_refresh() ? <li #refresh>{translate('Refresh')}</li> : ""}
|
||||
</menu>
|
||||
</popup>;
|
||||
|
||||
@@ -1727,6 +1727,9 @@ impl Remote {
|
||||
self.handler.msgbox("error", "Connection Error", &c);
|
||||
return false;
|
||||
}
|
||||
Some(misc::Union::option_response(resp)) => {
|
||||
self.handler.msgbox("warn", "Option Error", &resp.error);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
Some(message::Union::test_delay(t)) => {
|
||||
|
||||
Reference in New Issue
Block a user