mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-04-06 01:51:28 +03:00
Feat: Follow remote cursor and window focus | Auto display switch (#7717)
* feat: auto switch display on follow remote cursor Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * feat: auto switch display on follow remote window focus Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix build and remove unused imports Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix build Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix build Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix linux get_focused_window_id Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * lock show remote cursor when follow remote cursor is enabled Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix config Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * prevent auto display switch on show all display and displays as individual windows Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix options Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix options Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * remove unused function Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * remove unwraps and improve iterations Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * set updateCursorPos to false to avoid interrupting remote cursor Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * update lang Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix web build Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * update checks for options and enable in view mode Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * use focused display index for window focus service Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * use window center for windows display focused Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * remove unused imports Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix build Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * use libxdo instead of xdotool Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix multi monitor check Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * enable show cursor when follow cursor is default Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * remove show_all_displays,use runtime state instead Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix show cursor lock state on default Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * remove view mode with follow options Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix build Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * use separate message for follow current display Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix options Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * sciter support for follow remote cursor and window Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * add check for ui session handlers count Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * use cached displays and remove peer info write Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * No follow options when show all displays Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * No follow options when multi ui session Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * turn off follow options when not used|prevent msgs Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * use window center for switch in linux Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * use subbed display count to prevent switch msgs Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix build Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix web build Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * move subbed displays count Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * fix build Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * add noperms for window focus Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * add subscribe for window focus Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * remove window_focus message and unsub on multi ui Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> * add multi ui session field Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> --------- Signed-off-by: Sahil Yeole <sahilyeole93@gmail.com> Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
This commit is contained in:
@@ -1456,6 +1456,22 @@ impl LoginConfigHandler {
|
||||
BoolOption::No
|
||||
})
|
||||
.into();
|
||||
} else if name == "follow-remote-cursor" {
|
||||
config.follow_remote_cursor.v = !config.follow_remote_cursor.v;
|
||||
option.follow_remote_cursor = (if config.follow_remote_cursor.v {
|
||||
BoolOption::Yes
|
||||
} else {
|
||||
BoolOption::No
|
||||
})
|
||||
.into();
|
||||
} else if name == "follow-remote-window" {
|
||||
config.follow_remote_window.v = !config.follow_remote_window.v;
|
||||
option.follow_remote_window = (if config.follow_remote_window.v {
|
||||
BoolOption::Yes
|
||||
} else {
|
||||
BoolOption::No
|
||||
})
|
||||
.into();
|
||||
} else if name == "disable-audio" {
|
||||
config.disable_audio.v = !config.disable_audio.v;
|
||||
option.disable_audio = (if config.disable_audio.v {
|
||||
@@ -1601,6 +1617,12 @@ impl LoginConfigHandler {
|
||||
if view_only || self.get_toggle_option("show-remote-cursor") {
|
||||
msg.show_remote_cursor = BoolOption::Yes.into();
|
||||
}
|
||||
if self.get_toggle_option("follow-remote-cursor") {
|
||||
msg.follow_remote_cursor = BoolOption::Yes.into();
|
||||
}
|
||||
if self.get_toggle_option("follow-remote-window") {
|
||||
msg.follow_remote_window = BoolOption::Yes.into();
|
||||
}
|
||||
if !view_only && self.get_toggle_option("lock-after-session-end") {
|
||||
msg.lock_after_session_end = BoolOption::Yes.into();
|
||||
}
|
||||
@@ -1692,6 +1714,10 @@ impl LoginConfigHandler {
|
||||
self.config.allow_swap_key.v
|
||||
} else if name == "view-only" {
|
||||
self.config.view_only.v
|
||||
} else if name == "follow-remote-cursor" {
|
||||
self.config.follow_remote_cursor.v
|
||||
} else if name == "follow-remote-window" {
|
||||
self.config.follow_remote_window.v
|
||||
} else {
|
||||
!self.get_option(name).is_empty()
|
||||
}
|
||||
|
||||
@@ -1504,7 +1504,9 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
log::info!("update supported encoding:{:?}", e);
|
||||
self.handler.lc.write().unwrap().supported_encoding = e;
|
||||
}
|
||||
|
||||
Some(misc::Union::FollowCurrentDisplay(d_idx)) => {
|
||||
self.handler.set_current_display(d_idx);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
Some(message::Union::TestDelay(t)) => {
|
||||
|
||||
@@ -882,6 +882,21 @@ impl InvokeUiSession for FlutterHandler {
|
||||
);
|
||||
}
|
||||
|
||||
fn is_multi_ui_session(&self) -> bool {
|
||||
self.session_handlers.read().unwrap().len() > 1
|
||||
}
|
||||
|
||||
fn set_current_display(&self, disp_idx: i32) {
|
||||
if self.is_multi_ui_session() {
|
||||
return;
|
||||
}
|
||||
self.push_event(
|
||||
"follow_current_display",
|
||||
&[("display_idx", &disp_idx.to_string())],
|
||||
&[],
|
||||
);
|
||||
}
|
||||
|
||||
fn on_connected(&self, _conn_type: ConnType) {}
|
||||
|
||||
fn msgbox(&self, msgtype: &str, title: &str, text: &str, link: &str, retry: bool) {
|
||||
|
||||
@@ -213,6 +213,14 @@ pub fn session_refresh(session_id: SessionID, display: usize) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn session_is_multi_ui_session(session_id: SessionID) -> SyncReturn<bool> {
|
||||
if let Some(session) = sessions::get_session_by_session_id(&session_id) {
|
||||
SyncReturn(session.is_multi_ui_session())
|
||||
} else {
|
||||
SyncReturn(false)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn session_record_screen(
|
||||
session_id: SessionID,
|
||||
start: bool,
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -604,5 +604,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", "打开 Web 控制台以执行更多操作"),
|
||||
("allow-only-conn-window-open-tip", "仅当 RustDesk 窗口打开时允许连接"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "没有物理显示器,没必要使用隐私模式。"),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", "Více na webové konzoli"),
|
||||
("allow-only-conn-window-open-tip", "Povolit připojení pouze v případě, že je otevřené okno RustDesk"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "Žádné fyzické displeje, není třeba používat režim soukromí."),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", "Mehr über Webkonsole"),
|
||||
("allow-only-conn-window-open-tip", "Verbindung nur zulassen, wenn das RustDesk-Fenster geöffnet ist"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "Keine physischen Bildschirme; keine Notwendigkeit, den Datenschutzmodus zu verwenden."),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -222,5 +222,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", "More on web console"),
|
||||
("allow-only-conn-window-open-tip", "Only allow connection if RustDesk window is open"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "No physical displays, no need to use the privacy mode."),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", "Más en consola web"),
|
||||
("allow-only-conn-window-open-tip", "Permitir la conexión solo si la ventana RusDesk está abierta"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "No hay pantallas físicas, no es necesario usar el modo privado."),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", "اطلاعات بیشتر در کنسول وب"),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -602,5 +602,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", "Više na web konzoli"),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", "Altre info sulla console web"),
|
||||
("allow-only-conn-window-open-tip", "Consenti la connessione solo se la finestra RustDesk è aperta"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "Nessun display fisico, nessuna necessità di usare la modalità privacy."),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", "Vairāk par tīmekļa konsoli"),
|
||||
("allow-only-conn-window-open-tip", "Atļaut savienojumu tikai tad, ja ir atvērts RustDesk logs"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "Nav fizisku displeju, nav jāizmanto privātuma režīms."),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", "Meer over de webconsole"),
|
||||
("allow-only-conn-window-open-tip", "Alleen verbindingen toestaan als het RustDesk-venster geopend is"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", "Więcej w konsoli web"),
|
||||
("allow-only-conn-window-open-tip", "Zezwalaj na połączenie tylko wtedy, gdy okno RustDesk jest otwarte"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", "Больше в веб-консоли"),
|
||||
("allow-only-conn-window-open-tip", "Разрешать подключение только при открытом окне RustDesk"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "Физические дисплеи отсутствуют, нет необходимости использовать режим конфиденциальности."),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", "Viac na webovej konzole"),
|
||||
("allow-only-conn-window-open-tip", "Povoliť pripojenie iba vtedy, ak je otvorené okno aplikácie RustDesk"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", "Žiadne fyzické displeje, nie je potrebné používať režim ochrany osobných údajov."),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", "打開 Web 控制台以進行更多操作"),
|
||||
("allow-only-conn-window-open-tip", "只在 RustDesk 視窗開啟時允許連接"),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", "Детальніше про веб-консоль"),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -603,5 +603,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("ab_web_console_tip", ""),
|
||||
("allow-only-conn-window-open-tip", ""),
|
||||
("no_need_privacy_mode_no_physical_displays_tip", ""),
|
||||
("Follow remote cursor", ""),
|
||||
("Follow remote window focus", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ mod keyboard;
|
||||
/// cbindgen:ignore
|
||||
pub mod platform;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
pub use platform::{get_cursor, get_cursor_data, get_cursor_pos, start_os_service};
|
||||
pub use platform::{
|
||||
get_cursor, get_cursor_data, get_cursor_pos, get_focused_display, start_os_service,
|
||||
};
|
||||
#[cfg(not(any(target_os = "ios")))]
|
||||
/// cbindgen:ignore
|
||||
mod server;
|
||||
@@ -36,15 +38,15 @@ pub mod flutter;
|
||||
#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))]
|
||||
pub mod flutter_ffi;
|
||||
use common::*;
|
||||
mod auth_2fa;
|
||||
#[cfg(feature = "cli")]
|
||||
pub mod cli;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios", feature = "cli")))]
|
||||
pub mod core_main;
|
||||
mod lang;
|
||||
mod custom_server;
|
||||
mod lang;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
mod port_forward;
|
||||
mod auth_2fa;
|
||||
|
||||
#[cfg(all(feature = "flutter", feature = "plugin_framework"))]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
|
||||
@@ -11,7 +11,7 @@ use hbb_common::{
|
||||
config::Config,
|
||||
libc::{c_char, c_int, c_long, c_void},
|
||||
log,
|
||||
message_proto::Resolution,
|
||||
message_proto::{DisplayInfo, Resolution},
|
||||
regex::{Captures, Regex},
|
||||
};
|
||||
use std::{
|
||||
@@ -53,6 +53,20 @@ extern "C" {
|
||||
screen_num: *mut c_int,
|
||||
) -> c_int;
|
||||
fn xdo_new(display: *const c_char) -> Xdo;
|
||||
fn xdo_get_active_window(xdo: Xdo, window: *mut *mut c_void) -> c_int;
|
||||
fn xdo_get_window_location(
|
||||
xdo: Xdo,
|
||||
window: *mut c_void,
|
||||
x: *mut c_int,
|
||||
y: *mut c_int,
|
||||
screen_num: *mut c_int,
|
||||
) -> c_int;
|
||||
fn xdo_get_window_size(
|
||||
xdo: Xdo,
|
||||
window: *mut c_void,
|
||||
width: *mut c_int,
|
||||
height: *mut c_int,
|
||||
) -> c_int;
|
||||
}
|
||||
|
||||
#[link(name = "X11")]
|
||||
@@ -119,6 +133,50 @@ pub fn get_cursor_pos() -> Option<(i32, i32)> {
|
||||
|
||||
pub fn reset_input_cache() {}
|
||||
|
||||
pub fn get_focused_display(displays: Vec<DisplayInfo>) -> Option<usize> {
|
||||
let mut res = None;
|
||||
XDO.with(|xdo| {
|
||||
if let Ok(xdo) = xdo.try_borrow_mut() {
|
||||
if xdo.is_null() {
|
||||
return;
|
||||
}
|
||||
let mut x: c_int = 0;
|
||||
let mut y: c_int = 0;
|
||||
let mut width: c_int = 0;
|
||||
let mut height: c_int = 0;
|
||||
let mut window: *mut c_void = std::ptr::null_mut();
|
||||
|
||||
unsafe {
|
||||
if xdo_get_active_window(*xdo, &mut window) != 0 {
|
||||
return;
|
||||
}
|
||||
if xdo_get_window_location(
|
||||
*xdo,
|
||||
window,
|
||||
&mut x as _,
|
||||
&mut y as _,
|
||||
std::ptr::null_mut(),
|
||||
) != 0
|
||||
{
|
||||
return;
|
||||
}
|
||||
if xdo_get_window_size(*xdo, window, &mut width as _, &mut height as _) != 0 {
|
||||
return;
|
||||
}
|
||||
let center_x = x + width / 2;
|
||||
let center_y = y + height / 2;
|
||||
res = displays.iter().position(|d| {
|
||||
center_x >= d.x
|
||||
&& center_x < d.x + d.width
|
||||
&& center_y >= d.y
|
||||
&& center_y < d.y + d.height
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
res
|
||||
}
|
||||
|
||||
pub fn get_cursor() -> ResultType<Option<u64>> {
|
||||
let mut res = None;
|
||||
DISPLAY.with(|conn| {
|
||||
@@ -1228,7 +1286,7 @@ mod desktop {
|
||||
if !home.is_empty() {
|
||||
assert_eq!(d.home, home);
|
||||
} else {
|
||||
//
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,13 @@ use core_graphics::{
|
||||
display::{kCGNullWindowID, kCGWindowListOptionOnScreenOnly, CGWindowListCopyWindowInfo},
|
||||
window::{kCGWindowName, kCGWindowOwnerPID},
|
||||
};
|
||||
use hbb_common::sysinfo::{Pid, Process, ProcessRefreshKind, System};
|
||||
use hbb_common::{anyhow::anyhow, bail, log, message_proto::Resolution};
|
||||
use hbb_common::{
|
||||
allow_err,
|
||||
anyhow::anyhow,
|
||||
bail, log,
|
||||
message_proto::{DisplayInfo, Resolution},
|
||||
sysinfo::{Pid, Process, ProcessRefreshKind, System},
|
||||
};
|
||||
use include_dir::{include_dir, Dir};
|
||||
use objc::{class, msg_send, sel, sel_impl};
|
||||
use scrap::{libc::c_void, quartz::ffi::*};
|
||||
@@ -302,6 +307,20 @@ pub fn get_cursor_pos() -> Option<(i32, i32)> {
|
||||
*/
|
||||
}
|
||||
|
||||
pub fn get_focused_display(displays: Vec<DisplayInfo>) -> Option<usize> {
|
||||
unsafe {
|
||||
let main_screen: id = msg_send![class!(NSScreen), mainScreen];
|
||||
let screen: id = msg_send![main_screen, deviceDescription];
|
||||
let id: id =
|
||||
msg_send![screen, objectForKey: NSString::alloc(nil).init_str("NSScreenNumber")];
|
||||
let display_name: u32 = msg_send![id, unsignedIntValue];
|
||||
|
||||
displays
|
||||
.iter()
|
||||
.position(|d| d.name == display_name.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_cursor() -> ResultType<Option<u64>> {
|
||||
unsafe {
|
||||
let seed = CGSCurrentCursorSeed();
|
||||
|
||||
@@ -12,7 +12,7 @@ use hbb_common::{
|
||||
bail,
|
||||
config::{self, Config},
|
||||
log,
|
||||
message_proto::{Resolution, WindowsSession},
|
||||
message_proto::{DisplayInfo, Resolution, WindowsSession},
|
||||
sleep, timeout, tokio,
|
||||
};
|
||||
use std::process::{Command, Stdio};
|
||||
@@ -65,6 +65,24 @@ use windows_service::{
|
||||
use winreg::enums::*;
|
||||
use winreg::RegKey;
|
||||
|
||||
pub fn get_focused_display(displays: Vec<DisplayInfo>) -> Option<usize> {
|
||||
unsafe {
|
||||
let hWnd = GetForegroundWindow();
|
||||
let mut rect: RECT = mem::zeroed();
|
||||
if GetWindowRect(hWnd, &mut rect as *mut RECT) == 0 {
|
||||
return None;
|
||||
}
|
||||
displays.iter().position(|display| {
|
||||
let center_x = rect.left + (rect.right - rect.left) / 2;
|
||||
let center_y = rect.top + (rect.bottom - rect.top) / 2;
|
||||
center_x >= display.x
|
||||
&& center_x <= display.x + display.width
|
||||
&& center_y >= display.y
|
||||
&& center_y <= display.y + display.height
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_cursor_pos() -> Option<(i32, i32)> {
|
||||
unsafe {
|
||||
#[allow(invalid_value)]
|
||||
|
||||
@@ -50,6 +50,7 @@ pub const NAME: &'static str = "";
|
||||
pub mod input_service {
|
||||
pub const NAME_CURSOR: &'static str = "";
|
||||
pub const NAME_POS: &'static str = "";
|
||||
pub const NAME_WINDOW_FOCUS: &'static str = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,6 +106,7 @@ pub fn new() -> ServerPtr {
|
||||
if !display_service::capture_cursor_embedded() {
|
||||
server.add_service(Box::new(input_service::new_cursor()));
|
||||
server.add_service(Box::new(input_service::new_pos()));
|
||||
server.add_service(Box::new(input_service::new_window_focus()));
|
||||
}
|
||||
}
|
||||
Arc::new(RwLock::new(server))
|
||||
@@ -354,6 +356,15 @@ impl Server {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_subbed_displays_count(&self, conn_id: i32) -> usize {
|
||||
self.services
|
||||
.keys()
|
||||
.filter(|k| {
|
||||
Self::is_video_service_name(k) && self.services.get(*k).unwrap().is_subed(conn_id)
|
||||
})
|
||||
.count()
|
||||
}
|
||||
|
||||
fn capture_displays(
|
||||
&mut self,
|
||||
conn: ConnInner,
|
||||
|
||||
@@ -31,8 +31,7 @@ use hbb_common::platform::linux::run_cmds;
|
||||
use hbb_common::protobuf::EnumOrUnknown;
|
||||
use hbb_common::{
|
||||
config::Config,
|
||||
fs,
|
||||
fs::can_enable_overwrite_detection,
|
||||
fs::{self, can_enable_overwrite_detection},
|
||||
futures::{SinkExt, StreamExt},
|
||||
get_time, get_version_number,
|
||||
message_proto::{option_message::BoolOption, permission_info::Permission},
|
||||
@@ -241,6 +240,9 @@ pub struct Connection {
|
||||
delayed_read_dir: Option<(String, bool)>,
|
||||
#[cfg(target_os = "macos")]
|
||||
retina: Retina,
|
||||
follow_remote_cursor: bool,
|
||||
follow_remote_window: bool,
|
||||
multi_ui_session: bool,
|
||||
}
|
||||
|
||||
impl ConnInner {
|
||||
@@ -348,6 +350,9 @@ impl Connection {
|
||||
network_delay: 0,
|
||||
lock_after_session_end: false,
|
||||
show_remote_cursor: false,
|
||||
follow_remote_cursor: false,
|
||||
follow_remote_window: false,
|
||||
multi_ui_session: false,
|
||||
ip: "".to_owned(),
|
||||
disable_audio: false,
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
@@ -666,8 +671,14 @@ impl Connection {
|
||||
#[cfg(target_os = "macos")]
|
||||
conn.retina.set_displays(&_pi.displays);
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
Some(message::Union::CursorPosition(pos)) => {
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
{
|
||||
if conn.follow_remote_cursor {
|
||||
conn.handle_cursor_switch_display(pos.clone()).await;
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
if let Some(new_msg) = conn.retina.on_cursor_pos(&pos, conn.display_idx) {
|
||||
msg = Arc::new(new_msg);
|
||||
}
|
||||
@@ -1308,6 +1319,9 @@ impl Connection {
|
||||
if !self.show_remote_cursor {
|
||||
noperms.push(NAME_POS);
|
||||
}
|
||||
if !self.follow_remote_window {
|
||||
noperms.push(NAME_WINDOW_FOCUS);
|
||||
}
|
||||
if !self.clipboard_enabled() || !self.peer_keyboard_enabled() {
|
||||
noperms.push(super::clipboard_service::NAME);
|
||||
}
|
||||
@@ -2581,6 +2595,14 @@ impl Connection {
|
||||
} else {
|
||||
lock.capture_displays(self.inner.clone(), set, true, true);
|
||||
}
|
||||
self.multi_ui_session = lock.get_subbed_displays_count(self.inner.id()) > 1;
|
||||
if self.follow_remote_window {
|
||||
lock.subscribe(
|
||||
NAME_WINDOW_FOCUS,
|
||||
self.inner.clone(),
|
||||
!self.multi_ui_session,
|
||||
);
|
||||
}
|
||||
drop(lock);
|
||||
}
|
||||
}
|
||||
@@ -2766,6 +2788,24 @@ impl Connection {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
if let Ok(q) = o.follow_remote_cursor.enum_value() {
|
||||
if q != BoolOption::NotSet {
|
||||
self.follow_remote_cursor = q == BoolOption::Yes;
|
||||
}
|
||||
}
|
||||
if let Ok(q) = o.follow_remote_window.enum_value() {
|
||||
if q != BoolOption::NotSet {
|
||||
self.follow_remote_window = q == BoolOption::Yes;
|
||||
if let Some(s) = self.server.upgrade() {
|
||||
s.write().unwrap().subscribe(
|
||||
NAME_WINDOW_FOCUS,
|
||||
self.inner.clone(),
|
||||
self.follow_remote_window,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Ok(q) = o.disable_audio.enum_value() {
|
||||
if q != BoolOption::NotSet {
|
||||
self.disable_audio = q == BoolOption::Yes;
|
||||
@@ -3126,6 +3166,30 @@ impl Connection {
|
||||
self.inner.send(msg.into());
|
||||
self.supported_encoding_flag = (true, not_use);
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
async fn handle_cursor_switch_display(&mut self, pos: CursorPosition) {
|
||||
if self.multi_ui_session {
|
||||
return;
|
||||
}
|
||||
let displays = super::display_service::get_sync_displays();
|
||||
let d_index = displays.iter().position(|d| {
|
||||
let scale = d.scale;
|
||||
pos.x >= d.x
|
||||
&& pos.y >= d.y
|
||||
&& (pos.x - d.x) as f64 * scale < d.width as f64
|
||||
&& (pos.y - d.y) as f64 * scale < d.height as f64
|
||||
});
|
||||
if let Some(d_index) = d_index {
|
||||
if self.display_idx != d_index {
|
||||
let mut misc = Misc::new();
|
||||
misc.set_follow_current_display(d_index as i32);
|
||||
let mut msg_out = Message::new();
|
||||
msg_out.set_misc(misc);
|
||||
self.send(msg_out).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_switch_sides_uuid(id: String, uuid: uuid::Uuid) {
|
||||
|
||||
@@ -258,7 +258,6 @@ pub(super) fn get_original_resolution(
|
||||
.into()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub(super) fn get_sync_displays() -> Vec<DisplayInfo> {
|
||||
SYNC_DISPLAYS.lock().unwrap().displays.clone()
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ use std::{
|
||||
use winapi::um::winuser::WHEEL_DELTA;
|
||||
|
||||
const INVALID_CURSOR_POS: i32 = i32::MIN;
|
||||
const INVALID_DISPLAY_IDX: i32 = -1;
|
||||
|
||||
#[derive(Default)]
|
||||
struct StateCursor {
|
||||
@@ -74,6 +75,29 @@ impl StatePos {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct StateWindowFocus {
|
||||
display_idx: i32,
|
||||
}
|
||||
|
||||
impl super::service::Reset for StateWindowFocus {
|
||||
fn reset(&mut self) {
|
||||
self.display_idx = INVALID_DISPLAY_IDX;
|
||||
}
|
||||
}
|
||||
|
||||
impl StateWindowFocus {
|
||||
#[inline]
|
||||
fn is_valid(&self) -> bool {
|
||||
self.display_idx != INVALID_DISPLAY_IDX
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_changed(&self, disp_idx: i32) -> bool {
|
||||
self.is_valid() && self.display_idx != disp_idx
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy)]
|
||||
struct Input {
|
||||
conn: i32,
|
||||
@@ -238,6 +262,7 @@ fn should_disable_numlock(evt: &KeyEvent) -> bool {
|
||||
|
||||
pub const NAME_CURSOR: &'static str = "mouse_cursor";
|
||||
pub const NAME_POS: &'static str = "mouse_pos";
|
||||
pub const NAME_WINDOW_FOCUS: &'static str = "window_focus";
|
||||
#[derive(Clone)]
|
||||
pub struct MouseCursorService {
|
||||
pub sp: ServiceTmpl<MouseCursorSub>,
|
||||
@@ -277,6 +302,12 @@ pub fn new_pos() -> GenericService {
|
||||
svc.sp
|
||||
}
|
||||
|
||||
pub fn new_window_focus() -> GenericService {
|
||||
let svc = EmptyExtraFieldService::new(NAME_WINDOW_FOCUS.to_owned(), false);
|
||||
GenericService::repeat::<StateWindowFocus, _, _>(&svc.clone(), 33, run_window_focus);
|
||||
svc.sp
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn update_last_cursor_pos(x: i32, y: i32) {
|
||||
let mut lock = LATEST_SYS_CURSOR_POS.lock().unwrap();
|
||||
@@ -352,6 +383,22 @@ fn run_cursor(sp: MouseCursorService, state: &mut StateCursor) -> ResultType<()>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_window_focus(sp: EmptyExtraFieldService, state: &mut StateWindowFocus) -> ResultType<()> {
|
||||
let displays = super::display_service::get_sync_displays();
|
||||
let disp_idx = crate::get_focused_display(displays);
|
||||
if let Some(disp_idx) = disp_idx.map(|id| id as i32) {
|
||||
if state.is_changed(disp_idx) {
|
||||
let mut misc = Misc::new();
|
||||
misc.set_follow_current_display(disp_idx as i32);
|
||||
let mut msg_out = Message::new();
|
||||
msg_out.set_misc(misc);
|
||||
sp.send(msg_out);
|
||||
}
|
||||
state.display_idx = disp_idx;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
enum KeysDown {
|
||||
RdevKey(RawKey),
|
||||
@@ -424,12 +471,15 @@ struct VirtualInputState {
|
||||
#[cfg(target_os = "macos")]
|
||||
impl VirtualInputState {
|
||||
fn new() -> Option<Self> {
|
||||
VirtualInput::new(CGEventSourceStateID::CombinedSessionState, CGEventTapLocation::Session)
|
||||
.map(|virtual_input| Self {
|
||||
virtual_input,
|
||||
capslock_down: false,
|
||||
})
|
||||
.ok()
|
||||
VirtualInput::new(
|
||||
CGEventSourceStateID::CombinedSessionState,
|
||||
CGEventTapLocation::Session,
|
||||
)
|
||||
.map(|virtual_input| Self {
|
||||
virtual_input,
|
||||
capslock_down: false,
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -194,6 +194,8 @@ class Header: Reactor.Component {
|
||||
</div> : ""}
|
||||
<div .separator />
|
||||
{!cursor_embedded && <li #show-remote-cursor .toggle-option><span>{svg_checkmark}</span>{translate('Show remote cursor')}</li>}
|
||||
{<li #follow-remote-cursor .toggle-option><span>{svg_checkmark}</span>{translate('Follow remote cursor')}</li>}
|
||||
{<li #follow-remote-window .toggle-option><span>{svg_checkmark}</span>{translate('Follow remote window focus')}</li>}
|
||||
<li #show-quality-monitor .toggle-option><span>{svg_checkmark}</span>{translate('Show quality monitor')}</li>
|
||||
{audio_enabled ? <li #disable-audio .toggle-option><span>{svg_checkmark}</span>{translate('Mute')}</li> : ""}
|
||||
{(is_win && pi.platform == "Windows") && file_enabled ? <li #enable-file-transfer .toggle-option><span>{svg_checkmark}</span>{translate('Enable file copy and paste')}</li> : ""}
|
||||
@@ -479,7 +481,7 @@ function toggleMenuState() {
|
||||
for (var el in $$(menu#keyboard-options>li)) {
|
||||
el.attributes.toggleClass("selected", values.indexOf(el.id) >= 0);
|
||||
}
|
||||
for (var id in ["show-remote-cursor", "show-quality-monitor", "disable-audio", "enable-file-transfer", "disable-clipboard", "lock-after-session-end", "allow_swap_key", "i444"]) {
|
||||
for (var id in ["show-remote-cursor", "follow-remote-cursor", "follow-remote-window", "show-quality-monitor", "disable-audio", "enable-file-transfer", "disable-clipboard", "lock-after-session-end", "allow_swap_key", "i444"]) {
|
||||
var el = self.select('#' + id);
|
||||
if (el) {
|
||||
var value = handler.get_toggle_option(id);
|
||||
@@ -538,6 +540,15 @@ handler.setMultipleWindowsSession = function(sessions) {
|
||||
});
|
||||
}
|
||||
|
||||
handler.setCurrentDisplay = function(v) {
|
||||
pi.current_display = v;
|
||||
handler.switch_display(v);
|
||||
header.update();
|
||||
if (is_port_forward) {
|
||||
view.windowState = View.WINDOW_MINIMIZED;
|
||||
}
|
||||
}
|
||||
|
||||
function updatePrivacyMode() {
|
||||
var el = $(li#privacy-mode);
|
||||
if (el) {
|
||||
|
||||
@@ -259,6 +259,10 @@ impl InvokeUiSession for SciterHandler {
|
||||
// Ignore for sciter version.
|
||||
}
|
||||
|
||||
fn set_current_display(&self, _disp_idx: i32) {
|
||||
self.call("setCurrentDisplay", &make_args!(_disp_idx));
|
||||
}
|
||||
|
||||
fn set_multiple_windows_session(&self, sessions: Vec<WindowsSession>) {
|
||||
let mut v = Value::array(0);
|
||||
let mut sessions = sessions;
|
||||
|
||||
@@ -192,6 +192,11 @@ impl<T: InvokeUiSession> Session<T> {
|
||||
self.lc.read().unwrap().conn_type.eq(&ConnType::RDP)
|
||||
}
|
||||
|
||||
#[cfg(feature = "flutter")]
|
||||
pub fn is_multi_ui_session(&self) -> bool {
|
||||
self.ui_handler.is_multi_ui_session()
|
||||
}
|
||||
|
||||
pub fn get_view_style(&self) -> String {
|
||||
self.lc.read().unwrap().view_style.clone()
|
||||
}
|
||||
@@ -1378,6 +1383,9 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
|
||||
#[cfg(all(feature = "vram", feature = "flutter"))]
|
||||
fn on_texture(&self, display: usize, texture: *mut c_void);
|
||||
fn set_multiple_windows_session(&self, sessions: Vec<WindowsSession>);
|
||||
fn set_current_display(&self, disp_idx: i32);
|
||||
#[cfg(feature = "flutter")]
|
||||
fn is_multi_ui_session(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<T: InvokeUiSession> Deref for Session<T> {
|
||||
|
||||
Reference in New Issue
Block a user