From c23f377039ff6962a458eacbe16cbf99404b8c3b Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 19 Nov 2023 15:26:02 +0800 Subject: [PATCH 1/7] feat, topmost window, exclude from capture Signed-off-by: fufesou --- build.py | 6 +- libs/portable/src/main.rs | 4 +- src/lang/ar.rs | 1 + src/lang/ca.rs | 1 + src/lang/cn.rs | 1 + src/lang/cs.rs | 1 + src/lang/da.rs | 1 + src/lang/de.rs | 1 + src/lang/el.rs | 1 + src/lang/en.rs | 1 + src/lang/eo.rs | 1 + src/lang/es.rs | 1 + src/lang/fa.rs | 1 + src/lang/fr.rs | 1 + src/lang/hu.rs | 1 + src/lang/id.rs | 1 + src/lang/it.rs | 1 + src/lang/ja.rs | 1 + src/lang/ko.rs | 1 + src/lang/kz.rs | 1 + src/lang/lt.rs | 1 + src/lang/lv.rs | 1 + src/lang/nl.rs | 1 + src/lang/pl.rs | 1 + src/lang/pt_PT.rs | 1 + src/lang/ptbr.rs | 1 + src/lang/ro.rs | 1 + src/lang/ru.rs | 1 + src/lang/sk.rs | 1 + src/lang/sl.rs | 1 + src/lang/sq.rs | 1 + src/lang/sr.rs | 1 + src/lang/sv.rs | 1 + src/lang/template.rs | 1 + src/lang/th.rs | 1 + src/lang/tr.rs | 1 + src/lang/tw.rs | 1 + src/lang/ua.rs | 1 + src/lang/vn.rs | 1 + src/platform/windows.rs | 19 +- src/privacy_mode.rs | 49 ++- src/privacy_mode/win_exclude_from_capture.rs | 3 + src/privacy_mode/win_mag.rs | 369 +----------------- src/privacy_mode/win_topmost_window.rs | 375 +++++++++++++++++++ 44 files changed, 468 insertions(+), 394 deletions(-) create mode 100644 src/privacy_mode/win_exclude_from_capture.rs create mode 100644 src/privacy_mode/win_topmost_window.rs diff --git a/build.py b/build.py index 741c1c095..2a79fc1d6 100755 --- a/build.py +++ b/build.py @@ -57,9 +57,9 @@ def parse_rc_features(feature): }, 'PrivacyMode': { 'platform': ['windows'], - 'zip_url': 'https://github.com/fufesou/RustDeskTempTopMostWindow/releases/download/v0.2' - '/TempTopMostWindow_x64_pic_en.zip', - 'checksum_url': 'https://github.com/fufesou/RustDeskTempTopMostWindow/releases/download/v0.2/checksum_md5', + 'zip_url': 'https://github.com/fufesou/RustDeskTempTopMostWindow/releases/download/v0.3' + '/TempTopMostWindow_x64.zip', + 'checksum_url': 'https://github.com/fufesou/RustDeskTempTopMostWindow/releases/download/v0.3/checksum_md5', 'include': ['WindowInjection.dll'], } } diff --git a/libs/portable/src/main.rs b/libs/portable/src/main.rs index dc6f7bc84..6e3648c4e 100644 --- a/libs/portable/src/main.rs +++ b/libs/portable/src/main.rs @@ -94,11 +94,11 @@ mod windows { // Used for privacy mode(magnifier impl). pub const RUNTIME_BROKER_EXE: &'static str = "C:\\Windows\\System32\\RuntimeBroker.exe"; - pub const WIN_MAG_INJECTED_PROCESS_EXE: &'static str = "RuntimeBroker_rustdesk.exe"; + pub const WIN_TOPMOST_INJECTED_PROCESS_EXE: &'static str = "RuntimeBroker_rustdesk.exe"; pub(super) fn copy_runtime_broker(dir: &PathBuf) { let src = RUNTIME_BROKER_EXE; - let tgt = WIN_MAG_INJECTED_PROCESS_EXE; + let tgt = WIN_TOPMOST_INJECTED_PROCESS_EXE; let target_file = dir.join(tgt); if target_file.exists() { if let (Ok(src_file), Ok(tgt_file)) = (fs::read(src), fs::read(&target_file)) { diff --git a/src/lang/ar.rs b/src/lang/ar.rs index 95f0a8a04..e1de2ae9d 100644 --- a/src/lang/ar.rs +++ b/src/lang/ar.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/ca.rs b/src/lang/ca.rs index 37ac295aa..48bf4b7d0 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/cn.rs b/src/lang/cn.rs index a838701d5..ee4d2a06a 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", "模式 1 (不推荐)"), ("privacy_mode_impl_virtual_display_tip", "模式 2 (推荐)"), + ("privacy_mode_impl_exclude_from_capture_tip", "模式 3"), ("Enter privacy mode", "进入隐私模式"), ("Exit privacy mode", "退出隐私模式"), ].iter().cloned().collect(); diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 993f136f4..6ca08ea32 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", "Můžete zadat ID, přímou IP adresu nebo doménu s portem (:).\nPokud chcete přistupovat k zařízení na jiném serveru, připojte adresu serveru (@?key=), například,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nPokud chcete přistupovat k zařízení na veřejném serveru, zadejte \"@public\", klíč není pro veřejný server potřeba."), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/da.rs b/src/lang/da.rs index 7cbe8d99d..f5f79e9f9 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/de.rs b/src/lang/de.rs index 9017a744a..4437d9612 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", "Sie können eine ID, eine direkte IP oder eine Domäne mit einem Port (:) eingeben.\nWenn Sie auf ein Gerät auf einem anderen Server zugreifen möchten, fügen Sie bitte die Serveradresse (@?key=) hinzu, zum Beispiel\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nWenn Sie auf ein Gerät auf einem öffentlichen Server zugreifen wollen, geben Sie bitte \"@public\" ein. Der Schlüssel wird für öffentliche Server nicht benötigt."), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/el.rs b/src/lang/el.rs index 46577ce90..f27284e81 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/en.rs b/src/lang/en.rs index 3afb27bc6..9a6eebe33 100644 --- a/src/lang/en.rs +++ b/src/lang/en.rs @@ -205,5 +205,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", "You can input an ID, a direct IP, or a domain with a port (:).\nIf you want to access a device on another server, please append the server address (@?key=), for example,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nIf you want to access a device on a public server, please input \"@public\", the key is not needed for public server"), ("privacy_mode_impl_mag_tip", "Mode 1 (deprecated)"), ("privacy_mode_impl_virtual_display_tip", "Mode 2 (recommended)"), + ("privacy_mode_impl_exclude_from_capture_tip", "Mode 3"), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 35230ccb1..00159bd0a 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/es.rs b/src/lang/es.rs index 5692ce9d3..8bf744ff2 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", "Puedes introducir una ID, una IP directa o un dominio con un puerto (:).\nSi quieres acceder a un dispositivo en otro servidor, por favor añade la ip del servidor (@?key=), por ejemplo,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nSi quieres acceder a un dispositivo en un servidor público, por favor, introduce \"@public\", la clave no es necesaria para un servidor público."), ("privacy_mode_impl_mag_tip", "Modo 1 (obsoleto)"), ("privacy_mode_impl_virtual_display_tip", "Modo 2 (recomendado)"), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", "Entrar al modo privado"), ("Exit privacy mode", "Salir del modo privado"), ].iter().cloned().collect(); diff --git a/src/lang/fa.rs b/src/lang/fa.rs index 0d8c8e356..3567e8d2e 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 7f840558e..a9297bd90 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 298a07d6e..daa21390d 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/id.rs b/src/lang/id.rs index 7e81282fc..841aaedf9 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", "Anda bisa memasukkan ID, IP langsung, atau domain dengan port kostum yang sudah ditentukan (:).\nJika anda ingin mengakses perangkat lain yang berbeda server, tambahkan alamat server setelah penulisan ID(@?key=), sebagai contoh,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nJika anda ingin mengakses perangkat yang menggunakan server publik, masukkan \"@public\", server public tidak memerlukan key khusus"), ("privacy_mode_impl_mag_tip", "Mode 1 (deprecated)"), ("privacy_mode_impl_virtual_display_tip", "Mode 2 (direkomendasikan)"), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", "Masuk mode privasi"), ("Exit privacy mode", "Keluar mode privasi"), ].iter().cloned().collect(); diff --git a/src/lang/it.rs b/src/lang/it.rs index 99613c4d2..c3c86b52f 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", "Puoi inserire un ID, un IP diretto o un dominio con una porta (:).\nSe vuoi accedere as un dispositivo in un altro server, aggiungi l'indirizzo del server (@?key=), ad esempio\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nSe vuoi accedere as un dispositivo in un server pubblico, inserisci \"@public\", per il server pubblico la chiave non è necessaria"), ("privacy_mode_impl_mag_tip", "Modo 1 (deprecato)"), ("privacy_mode_impl_virtual_display_tip", "Modo 2 (consigliato)"), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", "Entra in modalità privacy"), ("Exit privacy mode", "Esci dalla modalità privacy"), ].iter().cloned().collect(); diff --git a/src/lang/ja.rs b/src/lang/ja.rs index a5c0dff2f..da0a9f8fa 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 8d8981575..c4c24fa70 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", "입력된 ID, IP, 도메인과 포트(:)를 입력할 수 있습니다.\n다른 서버에 있는 장치에 접속하려면 서버 주소(@?key=)를 추가하세요"), ("privacy_mode_impl_mag_tip", "모드 1(더 이상 사용되지 않음)"), ("privacy_mode_impl_virtual_display_tip", "모드 2(권장)"), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", "개인정보 보호 모드 사용"), ("Exit privacy mode", "개인정보 보호 모드 종료"), ].iter().cloned().collect(); diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 5d9ec3f3a..0abe19562 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/lt.rs b/src/lang/lt.rs index 69b210311..d445f3964 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/lv.rs b/src/lang/lv.rs index 63b941d00..e44f337a1 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", "Varat ievadīt ID, tiešo IP vai domēnu ar portu (:).\nJa vēlaties piekļūt ierīcei citā serverī, lūdzu, pievienojiet servera adresi (@?key=), piemēram,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nJa vēlaties piekļūt ierīcei publiskajā serverī, lūdzu, ievadiet \"@public\", publiskajam serverim atslēga nav nepieciešama"), ("privacy_mode_impl_mag_tip", "1. režīms (novecojis)"), ("privacy_mode_impl_virtual_display_tip", "2. režīms (ieteicams)"), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", "Ieiet privātuma režīmā"), ("Exit privacy mode", "Iziet no privātuma režīma"), ].iter().cloned().collect(); diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 280f5e9a0..75abcdf34 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", "Je kunt een ID, een direct IP of een domein met een poort (:) invoeren. Als je toegang wilt als apparaat op een andere server, voeg dan het serveradres toe (@?key=), bijvoorbeeld \n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.Als je toegang wilt als apparaat op een openbare server, voer dan \"@public\" in, voor de openbare server is de sleutel niet nodig."), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 13ed8942d..4481a5dfc 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", "Możesz wprowadzić identyfikator, bezpośredni adres IP lub domenę z portem (:).\nJeżeli chcesz uzyskać dostęp do urządzenia na innym serwerze, dołącz adres serwera (@?key=, np. \n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nJeżeli chcesz uzyskać dostęp do urządzenia na serwerze publicznym, wpisz \"@public\", klucz nie jest potrzebny dla serwera publicznego."), ("privacy_mode_impl_mag_tip", "Tryb 1 (przestarzały)"), ("privacy_mode_impl_virtual_display_tip", "Tryb 2 (zalecany)"), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", "Wejdź w tryb prywatności"), ("Exit privacy mode", "Wyjdź z trybu prywatności"), ].iter().cloned().collect(); diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 8ca5a0b84..25b024a0e 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 708784c20..1c744f209 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/ro.rs b/src/lang/ro.rs index c1eac74f8..893053456 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 9e184cb89..89a234d5a 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", "Можно ввести идентификатор, прямой IP-адрес или домен с портом (<домен>:<порт>).\nЕсли необходимо получить доступ к устройству на другом сервере, добавьте адрес сервера (@<адрес_сервера>?key=<ключ_значение>), например:\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nЕсли необходимо получить доступ к устройству на общедоступном сервере, введите \"@public\", ключ для публичного сервера не требуется."), ("privacy_mode_impl_mag_tip", "Режим 1 (устаревший)"), ("privacy_mode_impl_virtual_display_tip", "Режим 2 (рекомендуемый)"), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", "Включить режим конфиденциальности"), ("Exit privacy mode", "Отключить режим конфиденциальности"), ].iter().cloned().collect(); diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 072b532e6..e6b4b9ff2 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", "Môžete zadať ID, priamu IP adresu alebo doménu s portom (:).\nAk chcete získať prístup k zariadeniu na inom serveri, doplňte adresu servera (@?key=), napríklad,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nAk chcete získať prístup k zariadeniu na verejnom serveri, zadajte \"@public\", kľúč nie je potrebný pre verejný server."), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/sl.rs b/src/lang/sl.rs index 382b8a89d..475394f5a 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/sq.rs b/src/lang/sq.rs index c47a154ca..d27e12199 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/sr.rs b/src/lang/sr.rs index 832e81283..4c95bc0ab 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/sv.rs b/src/lang/sv.rs index b2e42a291..71552b873 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/template.rs b/src/lang/template.rs index 027baebad..d481815ce 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/th.rs b/src/lang/th.rs index b81b77b0a..f90e4d771 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 3fc58963a..26214719f 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 4ea5bc250..828a72831 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/ua.rs b/src/lang/ua.rs index e1d301119..a8d5b5149 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -569,6 +569,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable blocking user input", "Блокувати введення для користувача"), ("id_input_tip", "Ви можете ввести ID, безпосередню IP, або ж домен з портом (<домен>:<порт>).\nЯкщо ви хочете отримати доступ до пристрою на іншому сервері, будь ласка, додайте адресу сервера (@<адреса_сервера>?key=<значення_ключа>), наприклад,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nЯкщо ви хочете отримати доступ до пристрою на публічному сервері, будь ласка, введіть \"@public\", ключ для публічного сервера не потрібен."), ("privacy_mode_impl_mag_tip", "Режим 1 (застарілий)"), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("privacy_mode_impl_virtual_display_tip", "Режим 2 (рекомендований)"), ("Enter privacy mode", "Увійти в режим конфіденційності"), ("Exit privacy mode", "Вийти з режиму конфіденційності"), diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 89b6a189f..b79939d9f 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -570,6 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), + ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 02c5490fd..c0c7e4fc3 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -3,7 +3,7 @@ use crate::common::PORTABLE_APPNAME_RUNTIME_ENV_KEY; use crate::{ ipc, license::*, - privacy_mode::win_mag::{self, WIN_MAG_INJECTED_PROCESS_EXE}, + privacy_mode::win_topmost_window::{self, WIN_TOPMOST_INJECTED_PROCESS_EXE}, }; use hbb_common::{ allow_err, @@ -848,8 +848,8 @@ fn get_default_install_path() -> String { } pub fn check_update_broker_process() -> ResultType<()> { - let process_exe = win_mag::INJECTED_PROCESS_EXE; - let origin_process_exe = win_mag::ORIGIN_PROCESS_EXE; + let process_exe = win_topmost_window::INJECTED_PROCESS_EXE; + let origin_process_exe = win_topmost_window::ORIGIN_PROCESS_EXE; let exe_file = std::env::current_exe()?; let Some(cur_dir) = exe_file.parent() else { @@ -926,8 +926,8 @@ pub fn copy_exe_cmd(src_exe: &str, exe: &str, path: &str) -> ResultType {main_exe} copy /Y \"{ORIGIN_PROCESS_EXE}\" \"{path}\\{broker_exe}\" ", - ORIGIN_PROCESS_EXE = win_mag::ORIGIN_PROCESS_EXE, - broker_exe = win_mag::INJECTED_PROCESS_EXE, + ORIGIN_PROCESS_EXE = win_topmost_window::ORIGIN_PROCESS_EXE, + broker_exe = win_topmost_window::INJECTED_PROCESS_EXE, )) } @@ -1157,7 +1157,7 @@ fn get_before_uninstall(kill_self: bool) -> String { reg delete HKEY_CLASSES_ROOT\\{ext} /f netsh advfirewall firewall delete rule name=\"{app_name} Service\" ", - broker_exe = WIN_MAG_INJECTED_PROCESS_EXE, + broker_exe = WIN_TOPMOST_INJECTED_PROCESS_EXE, ) } @@ -2164,7 +2164,7 @@ pub fn uninstall_service(show_new_window: bool) -> bool { taskkill /F /IM {app_name}.exe{filter} ", app_name = crate::get_app_name(), - broker_exe = WIN_MAG_INJECTED_PROCESS_EXE, + broker_exe = WIN_TOPMOST_INJECTED_PROCESS_EXE, ); if let Err(err) = run_cmds(cmds, false, "uninstall") { Config::set_option("stop-service".into(), "".into()); @@ -2279,7 +2279,10 @@ fn run_after_run_cmds(silent: bool) { pub fn try_kill_broker() { allow_err!(std::process::Command::new("cmd") .arg("/c") - .arg(&format!("taskkill /F /IM {}", WIN_MAG_INJECTED_PROCESS_EXE)) + .arg(&format!( + "taskkill /F /IM {}", + WIN_TOPMOST_INJECTED_PROCESS_EXE + )) .creation_flags(winapi::um::winbase::CREATE_NO_WINDOW) .spawn()); } diff --git a/src/privacy_mode.rs b/src/privacy_mode.rs index e8ec1fb53..811a96e3c 100644 --- a/src/privacy_mode.rs +++ b/src/privacy_mode.rs @@ -15,11 +15,14 @@ use std::{ sync::{Arc, Mutex}, }; +#[cfg(windows)] +pub mod win_exclude_from_capture; #[cfg(windows)] mod win_input; - #[cfg(windows)] pub mod win_mag; +#[cfg(windows)] +pub mod win_topmost_window; #[cfg(all(windows, feature = "virtual_display_driver"))] mod win_virtual_display; @@ -34,6 +37,9 @@ pub const NO_DISPLAYS: &'static str = "No displays"; #[cfg(windows)] pub const PRIVACY_MODE_IMPL_WIN_MAG: &str = win_mag::PRIVACY_MODE_IMPL; +#[cfg(windows)] +pub const PRIVACY_MODE_IMPL_WIN_EXCLUDE_FROM_CAPTURE: &str = + win_exclude_from_capture::PRIVACY_MODE_IMPL; #[cfg(all(windows, feature = "virtual_display_driver"))] pub const PRIVACY_MODE_IMPL_WIN_VIRTUAL_DISPLAY: &str = win_virtual_display::PRIVACY_MODE_IMPL; @@ -84,22 +90,23 @@ lazy_static::lazy_static! { pub static ref DEFAULT_PRIVACY_MODE_IMPL: String = { #[cfg(windows)] { - if display_service::is_privacy_mode_mag_supported() { - PRIVACY_MODE_IMPL_WIN_MAG - } else { - #[cfg(feature = "virtual_display_driver")] - { - if is_installed() { - PRIVACY_MODE_IMPL_WIN_VIRTUAL_DISPLAY - } else { - "" - } - } - #[cfg(not(feature = "virtual_display_driver"))] - { - "" - } - }.to_owned() + PRIVACY_MODE_IMPL_WIN_EXCLUDE_FROM_CAPTURE.to_owned() + // if display_service::is_privacy_mode_mag_supported() { + // PRIVACY_MODE_IMPL_WIN_MAG + // } else { + // #[cfg(feature = "virtual_display_driver")] + // { + // if is_installed() { + // PRIVACY_MODE_IMPL_WIN_VIRTUAL_DISPLAY + // } else { + // "" + // } + // } + // #[cfg(not(feature = "virtual_display_driver"))] + // { + // "" + // } + // }.to_owned() } #[cfg(not(windows))] { @@ -137,6 +144,10 @@ lazy_static::lazy_static! { Box::new(win_mag::PrivacyModeImpl::default()) }); + map.insert(win_exclude_from_capture::PRIVACY_MODE_IMPL, || { + Box::new(win_exclude_from_capture::PrivacyModeImpl::default()) + }); + #[cfg(feature = "virtual_display_driver")] map.insert(win_virtual_display::PRIVACY_MODE_IMPL, || { Box::new(win_virtual_display::PrivacyModeImpl::default()) @@ -272,6 +283,10 @@ pub fn get_supported_privacy_mode_impl() -> Vec<(&'static str, &'static str)> { if display_service::is_privacy_mode_mag_supported() { vec_impls.push((PRIVACY_MODE_IMPL_WIN_MAG, "privacy_mode_impl_mag_tip")); } + vec_impls.push(( + PRIVACY_MODE_IMPL_WIN_EXCLUDE_FROM_CAPTURE, + "privacy_mode_impl_exclude_from_capture_tip", + )); #[cfg(feature = "virtual_display_driver")] if is_installed() { vec_impls.push(( diff --git a/src/privacy_mode/win_exclude_from_capture.rs b/src/privacy_mode/win_exclude_from_capture.rs new file mode 100644 index 000000000..2ef752c5b --- /dev/null +++ b/src/privacy_mode/win_exclude_from_capture.rs @@ -0,0 +1,3 @@ +pub use super::win_topmost_window::PrivacyModeImpl; + +pub(super) const PRIVACY_MODE_IMPL: &str = "privacy_mode_impl_exclude_from_capture"; diff --git a/src/privacy_mode/win_mag.rs b/src/privacy_mode/win_mag.rs index 1df92a32d..a93dce350 100644 --- a/src/privacy_mode/win_mag.rs +++ b/src/privacy_mode/win_mag.rs @@ -1,370 +1,11 @@ -use super::{PrivacyMode, INVALID_PRIVACY_MODE_CONN_ID}; -use crate::{platform::windows::get_user_token, privacy_mode::PrivacyModeState}; -use hbb_common::{allow_err, bail, log, ResultType}; -use std::{ - ffi::CString, - time::{Duration, Instant}, -}; -use winapi::{ - shared::{ - minwindef::FALSE, - ntdef::{HANDLE, NULL}, - windef::HWND, - }, - um::{ - errhandlingapi::GetLastError, - handleapi::CloseHandle, - libloaderapi::{GetModuleHandleA, GetProcAddress}, - memoryapi::{VirtualAllocEx, WriteProcessMemory}, - processthreadsapi::{ - CreateProcessAsUserW, QueueUserAPC, ResumeThread, TerminateProcess, - PROCESS_INFORMATION, STARTUPINFOW, - }, - winbase::{WTSGetActiveConsoleSessionId, CREATE_SUSPENDED, DETACHED_PROCESS}, - winnt::{MEM_COMMIT, PAGE_READWRITE}, - winuser::*, - }, -}; +use super::win_topmost_window::PRIVACY_WINDOW_NAME; +use hbb_common::{bail, log, ResultType}; +use std::time::Instant; + +pub use super::win_topmost_window::PrivacyModeImpl; pub(super) const PRIVACY_MODE_IMPL: &str = "privacy_mode_impl_mag"; -pub const ORIGIN_PROCESS_EXE: &'static str = "C:\\Windows\\System32\\RuntimeBroker.exe"; -pub const WIN_MAG_INJECTED_PROCESS_EXE: &'static str = "RuntimeBroker_rustdesk.exe"; -pub const INJECTED_PROCESS_EXE: &'static str = WIN_MAG_INJECTED_PROCESS_EXE; -const PRIVACY_WINDOW_NAME: &'static str = "RustDeskPrivacyWindow"; - -struct WindowHandlers { - hthread: u64, - hprocess: u64, -} - -impl Drop for WindowHandlers { - fn drop(&mut self) { - self.reset(); - } -} - -impl WindowHandlers { - fn reset(&mut self) { - unsafe { - if self.hprocess != 0 { - let _res = TerminateProcess(self.hprocess as _, 0); - CloseHandle(self.hprocess as _); - } - self.hprocess = 0; - if self.hthread != 0 { - CloseHandle(self.hthread as _); - } - self.hthread = 0; - } - } - - fn is_default(&self) -> bool { - self.hthread == 0 && self.hprocess == 0 - } -} - -pub struct PrivacyModeImpl { - conn_id: i32, - handlers: WindowHandlers, -} - -impl Default for PrivacyModeImpl { - fn default() -> Self { - Self { - conn_id: INVALID_PRIVACY_MODE_CONN_ID, - handlers: WindowHandlers { - hthread: 0, - hprocess: 0, - }, - } - } -} - -impl PrivacyMode for PrivacyModeImpl { - fn init(&self) -> ResultType<()> { - Ok(()) - } - - fn clear(&mut self) { - allow_err!(self.turn_off_privacy(self.conn_id, None)); - } - - fn turn_on_privacy(&mut self, conn_id: i32) -> ResultType { - if self.check_on_conn_id(conn_id)? { - log::debug!("Privacy mode of conn {} is already on", conn_id); - return Ok(true); - } - - let exe_file = std::env::current_exe()?; - if let Some(cur_dir) = exe_file.parent() { - if !cur_dir.join("WindowInjection.dll").exists() { - return Ok(false); - } - } else { - bail!( - "Invalid exe parent for {}", - exe_file.to_string_lossy().as_ref() - ); - } - - if self.handlers.is_default() { - log::info!("turn_on_privacy, dll not found when started, try start"); - self.start()?; - std::thread::sleep(std::time::Duration::from_millis(1_000)); - } - - let hwnd = wait_find_privacy_hwnd(0)?; - if hwnd.is_null() { - bail!("No privacy window created"); - } - super::win_input::hook()?; - unsafe { - ShowWindow(hwnd as _, SW_SHOW); - } - self.conn_id = conn_id; - Ok(true) - } - - fn turn_off_privacy( - &mut self, - conn_id: i32, - state: Option, - ) -> ResultType<()> { - self.check_off_conn_id(conn_id)?; - super::win_input::unhook()?; - - unsafe { - let hwnd = wait_find_privacy_hwnd(0)?; - if !hwnd.is_null() { - ShowWindow(hwnd, SW_HIDE); - } - } - - if self.conn_id != INVALID_PRIVACY_MODE_CONN_ID { - if let Some(state) = state { - allow_err!(super::set_privacy_mode_state( - conn_id, - state, - PRIVACY_MODE_IMPL.to_string(), - 1_000 - )); - } - self.conn_id = INVALID_PRIVACY_MODE_CONN_ID.to_owned(); - } - - Ok(()) - } - - #[inline] - fn pre_conn_id(&self) -> i32 { - self.conn_id - } -} - -impl PrivacyModeImpl { - pub fn start(&mut self) -> ResultType<()> { - if self.handlers.hprocess != 0 { - return Ok(()); - } - - log::info!("Start privacy mode window broker, check_update_broker_process"); - if let Err(e) = crate::platform::windows::check_update_broker_process() { - log::warn!( - "Failed to check update broker process. Privacy mode may not work properly. {}", - e - ); - } - - let exe_file = std::env::current_exe()?; - let Some(cur_dir) = exe_file.parent() else { - bail!("Cannot get parent of current exe file"); - }; - - let dll_file = cur_dir.join("WindowInjection.dll"); - if !dll_file.exists() { - bail!( - "Failed to find required file {}", - dll_file.to_string_lossy().as_ref() - ); - } - - let hwnd = wait_find_privacy_hwnd(1_000)?; - if !hwnd.is_null() { - log::info!("Privacy window is ready"); - return Ok(()); - } - - // let cmdline = cur_dir.join("MiniBroker.exe").to_string_lossy().to_string(); - let cmdline = cur_dir - .join(INJECTED_PROCESS_EXE) - .to_string_lossy() - .to_string(); - - unsafe { - let cmd_utf16: Vec = cmdline.encode_utf16().chain(Some(0).into_iter()).collect(); - - let mut start_info = STARTUPINFOW { - cb: 0, - lpReserved: NULL as _, - lpDesktop: NULL as _, - lpTitle: NULL as _, - dwX: 0, - dwY: 0, - dwXSize: 0, - dwYSize: 0, - dwXCountChars: 0, - dwYCountChars: 0, - dwFillAttribute: 0, - dwFlags: 0, - wShowWindow: 0, - cbReserved2: 0, - lpReserved2: NULL as _, - hStdInput: NULL as _, - hStdOutput: NULL as _, - hStdError: NULL as _, - }; - let mut proc_info = PROCESS_INFORMATION { - hProcess: NULL as _, - hThread: NULL as _, - dwProcessId: 0, - dwThreadId: 0, - }; - - let session_id = WTSGetActiveConsoleSessionId(); - let token = get_user_token(session_id, true); - if token.is_null() { - bail!("Failed to get token of current user"); - } - - let create_res = CreateProcessAsUserW( - token, - NULL as _, - cmd_utf16.as_ptr() as _, - NULL as _, - NULL as _, - FALSE, - CREATE_SUSPENDED | DETACHED_PROCESS, - NULL, - NULL as _, - &mut start_info, - &mut proc_info, - ); - CloseHandle(token); - if 0 == create_res { - bail!( - "Failed to create privacy window process {}, code {}", - cmdline, - GetLastError() - ); - }; - - inject_dll( - proc_info.hProcess, - proc_info.hThread, - dll_file.to_string_lossy().as_ref(), - )?; - - if 0xffffffff == ResumeThread(proc_info.hThread) { - // CloseHandle - CloseHandle(proc_info.hThread); - CloseHandle(proc_info.hProcess); - - bail!( - "Failed to create privacy window process, {}", - GetLastError() - ); - } - - self.handlers.hthread = proc_info.hThread as _; - self.handlers.hprocess = proc_info.hProcess as _; - - let hwnd = wait_find_privacy_hwnd(1_000)?; - if hwnd.is_null() { - bail!("Failed to get hwnd after started"); - } - } - - Ok(()) - } - - #[inline] - pub fn stop(&mut self) { - self.handlers.reset(); - } -} - -impl Drop for PrivacyModeImpl { - fn drop(&mut self) { - if self.conn_id != INVALID_PRIVACY_MODE_CONN_ID { - allow_err!(self.turn_off_privacy(self.conn_id, None)); - } - } -} - -unsafe fn inject_dll<'a>(hproc: HANDLE, hthread: HANDLE, dll_file: &'a str) -> ResultType<()> { - let dll_file_utf16: Vec = dll_file.encode_utf16().chain(Some(0).into_iter()).collect(); - - let buf = VirtualAllocEx( - hproc, - NULL as _, - dll_file_utf16.len() * 2, - MEM_COMMIT, - PAGE_READWRITE, - ); - if buf.is_null() { - bail!("Failed VirtualAllocEx"); - } - - let mut written: usize = 0; - if 0 == WriteProcessMemory( - hproc, - buf, - dll_file_utf16.as_ptr() as _, - dll_file_utf16.len() * 2, - &mut written, - ) { - bail!("Failed WriteProcessMemory"); - } - - let kernel32_modulename = CString::new("kernel32")?; - let hmodule = GetModuleHandleA(kernel32_modulename.as_ptr() as _); - if hmodule.is_null() { - bail!("Failed GetModuleHandleA"); - } - - let load_librarya_name = CString::new("LoadLibraryW")?; - let load_librarya = GetProcAddress(hmodule, load_librarya_name.as_ptr() as _); - if load_librarya.is_null() { - bail!("Failed GetProcAddress of LoadLibraryW"); - } - - if 0 == QueueUserAPC(Some(std::mem::transmute(load_librarya)), hthread, buf as _) { - bail!("Failed QueueUserAPC"); - } - - Ok(()) -} - -fn wait_find_privacy_hwnd(msecs: u128) -> ResultType { - let tm_begin = Instant::now(); - let wndname = CString::new(PRIVACY_WINDOW_NAME)?; - loop { - unsafe { - let hwnd = FindWindowA(NULL as _, wndname.as_ptr() as _); - if !hwnd.is_null() { - return Ok(hwnd); - } - } - - if msecs == 0 || tm_begin.elapsed().as_millis() > msecs { - return Ok(NULL as _); - } - - std::thread::sleep(Duration::from_millis(100)); - } -} - pub fn create_capturer( privacy_mode_id: i32, origin: (i32, i32), diff --git a/src/privacy_mode/win_topmost_window.rs b/src/privacy_mode/win_topmost_window.rs new file mode 100644 index 000000000..6b94d58f1 --- /dev/null +++ b/src/privacy_mode/win_topmost_window.rs @@ -0,0 +1,375 @@ +use super::{PrivacyMode, INVALID_PRIVACY_MODE_CONN_ID}; +use crate::{platform::windows::get_user_token, privacy_mode::PrivacyModeState}; +use hbb_common::{allow_err, bail, log, ResultType}; +use std::{ + ffi::CString, + time::{Duration, Instant}, +}; +use winapi::{ + shared::{ + minwindef::FALSE, + ntdef::{HANDLE, NULL}, + windef::HWND, + }, + um::{ + errhandlingapi::GetLastError, + handleapi::CloseHandle, + libloaderapi::{GetModuleHandleA, GetProcAddress}, + memoryapi::{VirtualAllocEx, WriteProcessMemory}, + processthreadsapi::{ + CreateProcessAsUserW, QueueUserAPC, ResumeThread, TerminateProcess, + PROCESS_INFORMATION, STARTUPINFOW, + }, + winbase::{WTSGetActiveConsoleSessionId, CREATE_SUSPENDED, DETACHED_PROCESS}, + winnt::{MEM_COMMIT, PAGE_READWRITE}, + winuser::*, + }, +}; + +pub(super) const PRIVACY_MODE_IMPL: &str = "privacy_mode_impl_mag"; + +pub const ORIGIN_PROCESS_EXE: &'static str = "C:\\Windows\\System32\\RuntimeBroker.exe"; +pub const WIN_TOPMOST_INJECTED_PROCESS_EXE: &'static str = "RuntimeBroker_rustdesk.exe"; +pub const INJECTED_PROCESS_EXE: &'static str = WIN_TOPMOST_INJECTED_PROCESS_EXE; +pub(super) const PRIVACY_WINDOW_NAME: &'static str = "RustDeskPrivacyWindow"; + +struct WindowHandlers { + hthread: u64, + hprocess: u64, +} + +impl Drop for WindowHandlers { + fn drop(&mut self) { + self.reset(); + } +} + +impl WindowHandlers { + fn reset(&mut self) { + unsafe { + if self.hprocess != 0 { + let _res = TerminateProcess(self.hprocess as _, 0); + CloseHandle(self.hprocess as _); + } + self.hprocess = 0; + if self.hthread != 0 { + CloseHandle(self.hthread as _); + } + self.hthread = 0; + } + } + + fn is_default(&self) -> bool { + self.hthread == 0 && self.hprocess == 0 + } +} + +pub struct PrivacyModeImpl { + conn_id: i32, + handlers: WindowHandlers, + hwnd: u64, +} + +impl Default for PrivacyModeImpl { + fn default() -> Self { + Self { + conn_id: INVALID_PRIVACY_MODE_CONN_ID, + handlers: WindowHandlers { + hthread: 0, + hprocess: 0, + }, + hwnd: 0, + } + } +} + +impl PrivacyMode for PrivacyModeImpl { + fn init(&self) -> ResultType<()> { + Ok(()) + } + + fn clear(&mut self) { + allow_err!(self.turn_off_privacy(self.conn_id, None)); + } + + fn turn_on_privacy(&mut self, conn_id: i32) -> ResultType { + if self.check_on_conn_id(conn_id)? { + log::debug!("Privacy mode of conn {} is already on", conn_id); + return Ok(true); + } + + let exe_file = std::env::current_exe()?; + if let Some(cur_dir) = exe_file.parent() { + if !cur_dir.join("WindowInjection.dll").exists() { + return Ok(false); + } + } else { + bail!( + "Invalid exe parent for {}", + exe_file.to_string_lossy().as_ref() + ); + } + + if self.handlers.is_default() { + log::info!("turn_on_privacy, dll not found when started, try start"); + self.start()?; + std::thread::sleep(std::time::Duration::from_millis(1_000)); + } + + let hwnd = wait_find_privacy_hwnd(0)?; + if hwnd.is_null() { + bail!("No privacy window created"); + } + super::win_input::hook()?; + unsafe { + ShowWindow(hwnd as _, SW_SHOW); + } + self.conn_id = conn_id; + self.hwnd = hwnd as _; + Ok(true) + } + + fn turn_off_privacy( + &mut self, + conn_id: i32, + state: Option, + ) -> ResultType<()> { + self.check_off_conn_id(conn_id)?; + super::win_input::unhook()?; + + unsafe { + let hwnd = wait_find_privacy_hwnd(0)?; + if !hwnd.is_null() { + ShowWindow(hwnd, SW_HIDE); + } + } + + if self.conn_id != INVALID_PRIVACY_MODE_CONN_ID { + if let Some(state) = state { + allow_err!(super::set_privacy_mode_state( + conn_id, + state, + PRIVACY_MODE_IMPL.to_string(), + 1_000 + )); + } + self.conn_id = INVALID_PRIVACY_MODE_CONN_ID.to_owned(); + } + + Ok(()) + } + + #[inline] + fn pre_conn_id(&self) -> i32 { + self.conn_id + } +} + +impl PrivacyModeImpl { + #[inline] + pub fn get_hwnd(&self) -> u64 { + self.hwnd + } + + pub fn start(&mut self) -> ResultType<()> { + if self.handlers.hprocess != 0 { + return Ok(()); + } + + log::info!("Start privacy mode window broker, check_update_broker_process"); + if let Err(e) = crate::platform::windows::check_update_broker_process() { + log::warn!( + "Failed to check update broker process. Privacy mode may not work properly. {}", + e + ); + } + + let exe_file = std::env::current_exe()?; + let Some(cur_dir) = exe_file.parent() else { + bail!("Cannot get parent of current exe file"); + }; + + let dll_file = cur_dir.join("WindowInjection.dll"); + if !dll_file.exists() { + bail!( + "Failed to find required file {}", + dll_file.to_string_lossy().as_ref() + ); + } + + let hwnd = wait_find_privacy_hwnd(1_000)?; + if !hwnd.is_null() { + log::info!("Privacy window is ready"); + return Ok(()); + } + + // let cmdline = cur_dir.join("MiniBroker.exe").to_string_lossy().to_string(); + let cmdline = cur_dir + .join(INJECTED_PROCESS_EXE) + .to_string_lossy() + .to_string(); + + unsafe { + let cmd_utf16: Vec = cmdline.encode_utf16().chain(Some(0).into_iter()).collect(); + + let mut start_info = STARTUPINFOW { + cb: 0, + lpReserved: NULL as _, + lpDesktop: NULL as _, + lpTitle: NULL as _, + dwX: 0, + dwY: 0, + dwXSize: 0, + dwYSize: 0, + dwXCountChars: 0, + dwYCountChars: 0, + dwFillAttribute: 0, + dwFlags: 0, + wShowWindow: 0, + cbReserved2: 0, + lpReserved2: NULL as _, + hStdInput: NULL as _, + hStdOutput: NULL as _, + hStdError: NULL as _, + }; + let mut proc_info = PROCESS_INFORMATION { + hProcess: NULL as _, + hThread: NULL as _, + dwProcessId: 0, + dwThreadId: 0, + }; + + let session_id = WTSGetActiveConsoleSessionId(); + let token = get_user_token(session_id, true); + if token.is_null() { + bail!("Failed to get token of current user"); + } + + let create_res = CreateProcessAsUserW( + token, + NULL as _, + cmd_utf16.as_ptr() as _, + NULL as _, + NULL as _, + FALSE, + CREATE_SUSPENDED | DETACHED_PROCESS, + NULL, + NULL as _, + &mut start_info, + &mut proc_info, + ); + CloseHandle(token); + if 0 == create_res { + bail!( + "Failed to create privacy window process {}, code {}", + cmdline, + GetLastError() + ); + }; + + inject_dll( + proc_info.hProcess, + proc_info.hThread, + dll_file.to_string_lossy().as_ref(), + )?; + + if 0xffffffff == ResumeThread(proc_info.hThread) { + // CloseHandle + CloseHandle(proc_info.hThread); + CloseHandle(proc_info.hProcess); + + bail!( + "Failed to create privacy window process, {}", + GetLastError() + ); + } + + self.handlers.hthread = proc_info.hThread as _; + self.handlers.hprocess = proc_info.hProcess as _; + + let hwnd = wait_find_privacy_hwnd(1_000)?; + if hwnd.is_null() { + bail!("Failed to get hwnd after started"); + } + } + + Ok(()) + } + + #[inline] + pub fn stop(&mut self) { + self.handlers.reset(); + } +} + +impl Drop for PrivacyModeImpl { + fn drop(&mut self) { + if self.conn_id != INVALID_PRIVACY_MODE_CONN_ID { + allow_err!(self.turn_off_privacy(self.conn_id, None)); + } + } +} + +unsafe fn inject_dll<'a>(hproc: HANDLE, hthread: HANDLE, dll_file: &'a str) -> ResultType<()> { + let dll_file_utf16: Vec = dll_file.encode_utf16().chain(Some(0).into_iter()).collect(); + + let buf = VirtualAllocEx( + hproc, + NULL as _, + dll_file_utf16.len() * 2, + MEM_COMMIT, + PAGE_READWRITE, + ); + if buf.is_null() { + bail!("Failed VirtualAllocEx"); + } + + let mut written: usize = 0; + if 0 == WriteProcessMemory( + hproc, + buf, + dll_file_utf16.as_ptr() as _, + dll_file_utf16.len() * 2, + &mut written, + ) { + bail!("Failed WriteProcessMemory"); + } + + let kernel32_modulename = CString::new("kernel32")?; + let hmodule = GetModuleHandleA(kernel32_modulename.as_ptr() as _); + if hmodule.is_null() { + bail!("Failed GetModuleHandleA"); + } + + let load_librarya_name = CString::new("LoadLibraryW")?; + let load_librarya = GetProcAddress(hmodule, load_librarya_name.as_ptr() as _); + if load_librarya.is_null() { + bail!("Failed GetProcAddress of LoadLibraryW"); + } + + if 0 == QueueUserAPC(Some(std::mem::transmute(load_librarya)), hthread, buf as _) { + bail!("Failed QueueUserAPC"); + } + + Ok(()) +} + +pub(super) fn wait_find_privacy_hwnd(msecs: u128) -> ResultType { + let tm_begin = Instant::now(); + let wndname = CString::new(PRIVACY_WINDOW_NAME)?; + loop { + unsafe { + let hwnd = FindWindowA(NULL as _, wndname.as_ptr() as _); + if !hwnd.is_null() { + return Ok(hwnd); + } + } + + if msecs == 0 || tm_begin.elapsed().as_millis() > msecs { + return Ok(NULL as _); + } + + std::thread::sleep(Duration::from_millis(100)); + } +} + From 7c98bfd3639e96122522084018ac740ea69f281f Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 19 Nov 2023 19:23:10 +0800 Subject: [PATCH 2/7] check if WDA_EXCLUDEFROMCAPTURE is supported Signed-off-by: fufesou --- src/lang/cn.rs | 2 +- src/lang/en.rs | 2 +- src/platform/windows.cc | 42 +++++++++++- src/platform/windows.rs | 26 ++++++++ src/privacy_mode.rs | 68 ++++++++++++-------- src/privacy_mode/win_exclude_from_capture.rs | 6 ++ 6 files changed, 114 insertions(+), 32 deletions(-) diff --git a/src/lang/cn.rs b/src/lang/cn.rs index ee4d2a06a..60c257606 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -570,7 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", "模式 1 (不推荐)"), ("privacy_mode_impl_virtual_display_tip", "模式 2 (推荐)"), - ("privacy_mode_impl_exclude_from_capture_tip", "模式 3"), + ("privacy_mode_impl_exclude_from_capture_tip", "模式 1"), ("Enter privacy mode", "进入隐私模式"), ("Exit privacy mode", "退出隐私模式"), ].iter().cloned().collect(); diff --git a/src/lang/en.rs b/src/lang/en.rs index 9a6eebe33..5c2d039b5 100644 --- a/src/lang/en.rs +++ b/src/lang/en.rs @@ -205,6 +205,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", "You can input an ID, a direct IP, or a domain with a port (:).\nIf you want to access a device on another server, please append the server address (@?key=), for example,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nIf you want to access a device on a public server, please input \"@public\", the key is not needed for public server"), ("privacy_mode_impl_mag_tip", "Mode 1 (deprecated)"), ("privacy_mode_impl_virtual_display_tip", "Mode 2 (recommended)"), - ("privacy_mode_impl_exclude_from_capture_tip", "Mode 3"), + ("privacy_mode_impl_exclude_from_capture_tip", "Mode 1"), ].iter().cloned().collect(); } diff --git a/src/platform/windows.cc b/src/platform/windows.cc index 4ffa6eeeb..b76fca2fd 100644 --- a/src/platform/windows.cc +++ b/src/platform/windows.cc @@ -628,8 +628,46 @@ extern "C" return bSystem; } - void alloc_console_and_redirect() { + void alloc_console_and_redirect() + { AllocConsole(); freopen("CONOUT$", "w", stdout); } -} // end of extern "C" \ No newline at end of file +} // end of extern "C" + +extern "C" +{ + // https://github.com/nodejs/node-convergence-archive/blob/e11fe0c2777561827cdb7207d46b0917ef3c42a7/deps/uv/src/win/util.c#L780 + BOOL IsWindowsVersionOrGreater(DWORD os_major, + DWORD os_minor, + DWORD build_number, + WORD service_pack_major, + WORD service_pack_minor) + { + OSVERSIONINFOEX osvi; + DWORDLONG condition_mask = 0; + int op = VER_GREATER_EQUAL; + + /* Initialize the OSVERSIONINFOEX structure. */ + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + osvi.dwMajorVersion = os_major; + osvi.dwMinorVersion = os_minor; + osvi.dwBuildNumber = build_number; + osvi.wServicePackMajor = service_pack_major; + osvi.wServicePackMinor = service_pack_minor; + + /* Initialize the condition mask. */ + VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op); + VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op); + VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op); + VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op); + + /* Perform the test. */ + return VerifyVersionInfo( + &osvi, + VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, + condition_mask); + } +} diff --git a/src/platform/windows.rs b/src/platform/windows.rs index c0c7e4fc3..4e88ea99c 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -460,6 +460,13 @@ extern "C" { fn is_win_down() -> BOOL; fn is_local_system() -> BOOL; fn alloc_console_and_redirect(); + fn IsWindowsVersionOrGreater( + os_major: DWORD, + os_minor: DWORD, + build_number: DWORD, + service_pack_major: WORD, + service_pack_minor: WORD, + ) -> BOOL; } extern "system" { @@ -1283,6 +1290,25 @@ pub fn block_input(v: bool) -> (bool, String) { } } +#[inline] +pub fn is_windows_version_or_greater( + os_major: u32, + os_minor: u32, + build_number: u32, + service_pack_major: u32, + service_pack_minor: u32, +) -> bool { + unsafe { + IsWindowsVersionOrGreater( + os_major as _, + os_minor as _, + build_number as _, + service_pack_major as _, + service_pack_minor as _, + ) == TRUE + } +} + pub fn add_recent_document(path: &str) { extern "C" { fn AddRecentDocument(path: *const u16); diff --git a/src/privacy_mode.rs b/src/privacy_mode.rs index 811a96e3c..c3ff04de7 100644 --- a/src/privacy_mode.rs +++ b/src/privacy_mode.rs @@ -90,23 +90,26 @@ lazy_static::lazy_static! { pub static ref DEFAULT_PRIVACY_MODE_IMPL: String = { #[cfg(windows)] { - PRIVACY_MODE_IMPL_WIN_EXCLUDE_FROM_CAPTURE.to_owned() - // if display_service::is_privacy_mode_mag_supported() { - // PRIVACY_MODE_IMPL_WIN_MAG - // } else { - // #[cfg(feature = "virtual_display_driver")] - // { - // if is_installed() { - // PRIVACY_MODE_IMPL_WIN_VIRTUAL_DISPLAY - // } else { - // "" - // } - // } - // #[cfg(not(feature = "virtual_display_driver"))] - // { - // "" - // } - // }.to_owned() + if win_exclude_from_capture::is_supported() { + PRIVACY_MODE_IMPL_WIN_EXCLUDE_FROM_CAPTURE + } else { + if display_service::is_privacy_mode_mag_supported() { + PRIVACY_MODE_IMPL_WIN_MAG + } else { + #[cfg(feature = "virtual_display_driver")] + { + if is_installed() { + PRIVACY_MODE_IMPL_WIN_VIRTUAL_DISPLAY + } else { + "" + } + } + #[cfg(not(feature = "virtual_display_driver"))] + { + "" + } + } + }.to_owned() } #[cfg(not(windows))] { @@ -140,13 +143,15 @@ lazy_static::lazy_static! { let mut map: HashMap<&'static str, PrivacyModeCreator> = HashMap::new(); #[cfg(windows)] { - map.insert(win_mag::PRIVACY_MODE_IMPL, || { - Box::new(win_mag::PrivacyModeImpl::default()) - }); - - map.insert(win_exclude_from_capture::PRIVACY_MODE_IMPL, || { + if win_exclude_from_capture::is_supported() { + map.insert(win_exclude_from_capture::PRIVACY_MODE_IMPL, || { Box::new(win_exclude_from_capture::PrivacyModeImpl::default()) }); + } else { + map.insert(win_mag::PRIVACY_MODE_IMPL, || { + Box::new(win_mag::PrivacyModeImpl::default()) + }); + } #[cfg(feature = "virtual_display_driver")] map.insert(win_virtual_display::PRIVACY_MODE_IMPL, || { @@ -280,13 +285,18 @@ pub fn get_supported_privacy_mode_impl() -> Vec<(&'static str, &'static str)> { #[cfg(target_os = "windows")] { let mut vec_impls = Vec::new(); - if display_service::is_privacy_mode_mag_supported() { - vec_impls.push((PRIVACY_MODE_IMPL_WIN_MAG, "privacy_mode_impl_mag_tip")); + + if win_exclude_from_capture::is_supported() { + vec_impls.push(( + PRIVACY_MODE_IMPL_WIN_EXCLUDE_FROM_CAPTURE, + "privacy_mode_impl_exclude_from_capture_tip", + )); + } else { + if display_service::is_privacy_mode_mag_supported() { + vec_impls.push((PRIVACY_MODE_IMPL_WIN_MAG, "privacy_mode_impl_mag_tip")); + } } - vec_impls.push(( - PRIVACY_MODE_IMPL_WIN_EXCLUDE_FROM_CAPTURE, - "privacy_mode_impl_exclude_from_capture_tip", - )); + #[cfg(feature = "virtual_display_driver")] if is_installed() { vec_impls.push(( @@ -294,6 +304,7 @@ pub fn get_supported_privacy_mode_impl() -> Vec<(&'static str, &'static str)> { "privacy_mode_impl_virtual_display_tip", )); } + vec_impls } #[cfg(not(target_os = "windows"))] @@ -324,6 +335,7 @@ pub fn check_privacy_mode_err( display_idx: usize, timeout_millis: u64, ) -> String { + // win magnifier implementation requires a test of creating a capturer. if is_current_privacy_mode_impl(PRIVACY_MODE_IMPL_WIN_MAG) { crate::video_service::test_create_capturer(privacy_mode_id, display_idx, timeout_millis) } else { diff --git a/src/privacy_mode/win_exclude_from_capture.rs b/src/privacy_mode/win_exclude_from_capture.rs index 2ef752c5b..0bb81f693 100644 --- a/src/privacy_mode/win_exclude_from_capture.rs +++ b/src/privacy_mode/win_exclude_from_capture.rs @@ -1,3 +1,9 @@ pub use super::win_topmost_window::PrivacyModeImpl; pub(super) const PRIVACY_MODE_IMPL: &str = "privacy_mode_impl_exclude_from_capture"; + +pub(super) fn is_supported() -> bool { + // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowdisplayaffinity + // https://en.wikipedia.org/wiki/Windows_10_version_history + crate::platform::windows::is_windows_version_or_greater(10, 0, 19041, 0, 0) +} From 85ddfc0739f052cab0029c46b899b959ee94eeb8 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 19 Nov 2023 23:48:18 +0800 Subject: [PATCH 3/7] remove redundent global variables Signed-off-by: fufesou --- src/privacy_mode.rs | 83 ++++++++++++++++++------- src/privacy_mode/win_topmost_window.rs | 32 +++++----- src/privacy_mode/win_virtual_display.rs | 27 ++++---- src/server/connection.rs | 40 +++++++----- src/server/video_service.rs | 29 ++++----- 5 files changed, 130 insertions(+), 81 deletions(-) diff --git a/src/privacy_mode.rs b/src/privacy_mode.rs index c3ff04de7..1caa4ee46 100644 --- a/src/privacy_mode.rs +++ b/src/privacy_mode.rs @@ -61,6 +61,8 @@ pub trait PrivacyMode: Sync + Send { fn pre_conn_id(&self) -> i32; + fn get_impl_key(&self) -> &str; + #[inline] fn check_on_conn_id(&self, conn_id: i32) -> ResultType { let pre_conn_id = self.pre_conn_id(); @@ -117,24 +119,21 @@ lazy_static::lazy_static! { } }; - static ref CUR_PRIVACY_MODE_IMPL: Arc> = { + static ref PRIVACY_MODE: Arc>>> = { let mut cur_impl = get_option("privacy-mode-impl-key".to_owned()); if !get_supported_privacy_mode_impl().iter().any(|(k, _)| k == &cur_impl) { cur_impl = DEFAULT_PRIVACY_MODE_IMPL.to_owned(); } - Arc::new(Mutex::new(cur_impl)) - }; - static ref PRIVACY_MODE: Arc>>> = { - let cur_impl = (*CUR_PRIVACY_MODE_IMPL.lock().unwrap()).clone(); + let privacy_mode = match PRIVACY_MODE_CREATOR.lock().unwrap().get(&(&cur_impl as &str)) { - Some(creator) => Some(creator()), + Some(creator) => Some(creator(&cur_impl)), None => None, }; Arc::new(Mutex::new(privacy_mode)) }; } -pub type PrivacyModeCreator = fn() -> Box; +pub type PrivacyModeCreator = fn(impl_key: &str) -> Box; lazy_static::lazy_static! { static ref PRIVACY_MODE_CREATOR: Arc>> = { #[cfg(not(windows))] @@ -144,18 +143,18 @@ lazy_static::lazy_static! { #[cfg(windows)] { if win_exclude_from_capture::is_supported() { - map.insert(win_exclude_from_capture::PRIVACY_MODE_IMPL, || { - Box::new(win_exclude_from_capture::PrivacyModeImpl::default()) + map.insert(win_exclude_from_capture::PRIVACY_MODE_IMPL, |impl_key: &str| { + Box::new(win_exclude_from_capture::PrivacyModeImpl::new(impl_key)) }); } else { - map.insert(win_mag::PRIVACY_MODE_IMPL, || { - Box::new(win_mag::PrivacyModeImpl::default()) + map.insert(win_mag::PRIVACY_MODE_IMPL, |impl_key: &str| { + Box::new(win_mag::PrivacyModeImpl::new(impl_key)) }); } #[cfg(feature = "virtual_display_driver")] - map.insert(win_virtual_display::PRIVACY_MODE_IMPL, || { - Box::new(win_virtual_display::PrivacyModeImpl::default()) + map.insert(win_virtual_display::PRIVACY_MODE_IMPL, |impl_key: &str| { + Box::new(win_virtual_display::PrivacyModeImpl::new(impl_key)) }); } Arc::new(Mutex::new(map)) @@ -174,13 +173,15 @@ pub fn clear() -> Option<()> { #[inline] pub fn switch(impl_key: &str) { - let mut cur_impl_lock = CUR_PRIVACY_MODE_IMPL.lock().unwrap(); - if *cur_impl_lock == impl_key { - return; + let mut privacy_mode_lock = PRIVACY_MODE.lock().unwrap(); + if let Some(privacy_mode) = privacy_mode_lock.as_ref() { + if privacy_mode.get_impl_key() == impl_key { + return; + } } + if let Some(creator) = PRIVACY_MODE_CREATOR.lock().unwrap().get(impl_key) { - *PRIVACY_MODE.lock().unwrap() = Some(creator()); - *cur_impl_lock = impl_key.to_owned(); + *privacy_mode_lock = Some(creator(impl_key)); } } @@ -208,13 +209,15 @@ pub fn turn_on_privacy(impl_key: &str, conn_id: i32) -> Option> // Check or switch privacy mode implementation let impl_key = get_supported_impl(impl_key); - let mut cur_impl_lock = CUR_PRIVACY_MODE_IMPL.lock().unwrap(); + let mut cur_impl_key = "".to_string(); if let Some(privacy_mode) = privacy_mode_lock.as_ref() { + cur_impl_key = privacy_mode.get_impl_key().to_string(); let check_on_conn_id = privacy_mode.check_on_conn_id(conn_id); match check_on_conn_id.as_ref() { Ok(true) => { - if *cur_impl_lock == impl_key { + if cur_impl_key == impl_key { + // Same peer, same implementation. return Some(Ok(true)); } else { // Same peer, switch to new implementation. @@ -225,7 +228,7 @@ pub fn turn_on_privacy(impl_key: &str, conn_id: i32) -> Option> } } - if *cur_impl_lock != impl_key { + if cur_impl_key != impl_key { if let Some(creator) = PRIVACY_MODE_CREATOR .lock() .unwrap() @@ -235,8 +238,7 @@ pub fn turn_on_privacy(impl_key: &str, conn_id: i32) -> Option> privacy_mode.clear(); } - *privacy_mode_lock = Some(creator()); - *cur_impl_lock = impl_key.to_owned(); + *privacy_mode_lock = Some(creator(&impl_key)); } else { return Some(Err(anyhow!("Unsupported privacy mode: {}", impl_key))); } @@ -313,9 +315,23 @@ pub fn get_supported_privacy_mode_impl() -> Vec<(&'static str, &'static str)> { } } +#[inline] +pub fn get_cur_impl_key() -> Option { + PRIVACY_MODE + .lock() + .unwrap() + .as_ref() + .map(|pm| pm.get_impl_key().to_owned()) +} + #[inline] pub fn is_current_privacy_mode_impl(impl_key: &str) -> bool { - *CUR_PRIVACY_MODE_IMPL.lock().unwrap() == impl_key + PRIVACY_MODE + .lock() + .unwrap() + .as_ref() + .map(|pm| pm.get_impl_key() == impl_key) + .unwrap_or(false) } #[inline] @@ -347,3 +363,22 @@ pub fn check_privacy_mode_err( pub fn is_privacy_mode_supported() -> bool { !DEFAULT_PRIVACY_MODE_IMPL.is_empty() } + +#[inline] +pub fn get_privacy_mode_conn_id() -> Option { + PRIVACY_MODE + .lock() + .unwrap() + .as_ref() + .map(|pm| pm.pre_conn_id()) +} + +#[inline] +pub fn is_in_privacy_mode() -> bool { + PRIVACY_MODE + .lock() + .unwrap() + .as_ref() + .map(|pm| pm.pre_conn_id() != INVALID_PRIVACY_MODE_CONN_ID) + .unwrap_or(false) +} diff --git a/src/privacy_mode/win_topmost_window.rs b/src/privacy_mode/win_topmost_window.rs index 6b94d58f1..687f59155 100644 --- a/src/privacy_mode/win_topmost_window.rs +++ b/src/privacy_mode/win_topmost_window.rs @@ -65,24 +65,12 @@ impl WindowHandlers { } pub struct PrivacyModeImpl { + impl_key: String, conn_id: i32, handlers: WindowHandlers, hwnd: u64, } -impl Default for PrivacyModeImpl { - fn default() -> Self { - Self { - conn_id: INVALID_PRIVACY_MODE_CONN_ID, - handlers: WindowHandlers { - hthread: 0, - hprocess: 0, - }, - hwnd: 0, - } - } -} - impl PrivacyMode for PrivacyModeImpl { fn init(&self) -> ResultType<()> { Ok(()) @@ -163,9 +151,26 @@ impl PrivacyMode for PrivacyModeImpl { fn pre_conn_id(&self) -> i32 { self.conn_id } + + #[inline] + fn get_impl_key(&self) -> &str { + &self.impl_key + } } impl PrivacyModeImpl { + pub fn new(impl_key: &str) -> Self { + Self { + impl_key: impl_key.to_owned(), + conn_id: INVALID_PRIVACY_MODE_CONN_ID, + handlers: WindowHandlers { + hthread: 0, + hprocess: 0, + }, + hwnd: 0, + } + } + #[inline] pub fn get_hwnd(&self) -> u64 { self.hwnd @@ -372,4 +377,3 @@ pub(super) fn wait_find_privacy_hwnd(msecs: u128) -> ResultType { std::thread::sleep(Duration::from_millis(100)); } } - diff --git a/src/privacy_mode/win_virtual_display.rs b/src/privacy_mode/win_virtual_display.rs index 1d3ffa30e..8183d3275 100644 --- a/src/privacy_mode/win_virtual_display.rs +++ b/src/privacy_mode/win_virtual_display.rs @@ -35,23 +35,13 @@ struct Display { } pub struct PrivacyModeImpl { + impl_key: String, conn_id: i32, displays: Vec, virtual_displays: Vec, virtual_displays_added: Vec, } -impl Default for PrivacyModeImpl { - fn default() -> Self { - Self { - conn_id: INVALID_PRIVACY_MODE_CONN_ID, - displays: Vec::new(), - virtual_displays: Vec::new(), - virtual_displays_added: Vec::new(), - } - } -} - struct TurnOnGuard<'a> { privacy_mode: &'a mut PrivacyModeImpl, succeeded: bool, @@ -82,6 +72,16 @@ impl<'a> Drop for TurnOnGuard<'a> { } impl PrivacyModeImpl { + pub fn new(impl_key: &str) -> Self { + Self { + impl_key: impl_key.to_owned(), + conn_id: INVALID_PRIVACY_MODE_CONN_ID, + displays: Vec::new(), + virtual_displays: Vec::new(), + virtual_displays_added: Vec::new(), + } + } + // mainly from https://github.com/fufesou/rustdesk/blob/44c3a52ca8502cf53b58b59db130611778d34dbe/libs/scrap/src/dxgi/mod.rs#L365 fn set_displays(&mut self) { self.displays.clear(); @@ -431,6 +431,11 @@ impl PrivacyMode for PrivacyModeImpl { fn pre_conn_id(&self) -> i32 { self.conn_id } + + #[inline] + fn get_impl_key(&self) -> &str { + &self.impl_key + } } impl Drop for PrivacyModeImpl { diff --git a/src/server/connection.rs b/src/server/connection.rs index 419592821..12e52afba 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -508,21 +508,18 @@ impl Connection { ipc::Data::PrivacyModeState((_, state, impl_key)) => { let msg_out = match state { privacy_mode::PrivacyModeState::OffSucceeded => { - video_service::set_privacy_mode_conn_id(0); crate::common::make_privacy_mode_msg( back_notification::PrivacyModeState::PrvOffSucceeded, impl_key, ) } privacy_mode::PrivacyModeState::OffByPeer => { - video_service::set_privacy_mode_conn_id(0); crate::common::make_privacy_mode_msg( back_notification::PrivacyModeState::PrvOffByPeer, impl_key, ) } privacy_mode::PrivacyModeState::OffUnknown => { - video_service::set_privacy_mode_conn_id(0); crate::common::make_privacy_mode_msg( back_notification::PrivacyModeState::PrvOffUnknown, impl_key, @@ -682,10 +679,10 @@ impl Connection { } } - let video_privacy_conn_id = video_service::get_privacy_mode_conn_id(); - if video_privacy_conn_id == id { - video_service::set_privacy_mode_conn_id(0); - let _ = Self::turn_off_privacy_to_msg(id); + if let Some(video_privacy_conn_id) = privacy_mode::get_privacy_mode_conn_id() { + if video_privacy_conn_id == id { + let _ = Self::turn_off_privacy_to_msg(id); + } } #[cfg(all(feature = "flutter", feature = "plugin_framework"))] #[cfg(not(any(target_os = "android", target_os = "ios")))] @@ -880,7 +877,7 @@ impl Connection { } async fn check_privacy_mode_on(&mut self) -> bool { - if video_service::get_privacy_mode_conn_id() > 0 { + if privacy_mode::is_in_privacy_mode() { self.send_login_error("Someone turns on privacy mode, exit") .await; false @@ -2610,7 +2607,23 @@ impl Connection { impl_key, ) } else { - match privacy_mode::turn_on_privacy(&impl_key, self.inner.id) { + let is_pre_privacy_on = privacy_mode::is_in_privacy_mode(); + let pre_impl_key = privacy_mode::get_cur_impl_key(); + let turn_on_res = privacy_mode::turn_on_privacy(&impl_key, self.inner.id); + + if is_pre_privacy_on { + if let Some(pre_impl_key) = pre_impl_key { + if !privacy_mode::is_current_privacy_mode_impl(&pre_impl_key) { + let off_msg = crate::common::make_privacy_mode_msg( + back_notification::PrivacyModeState::PrvOffSucceeded, + pre_impl_key, + ); + self.send(off_msg).await; + } + } + } + + match turn_on_res { Some(Ok(res)) => { if res { let err_msg = privacy_mode::check_privacy_mode_err( @@ -2619,7 +2632,6 @@ impl Connection { 5_000, ); if err_msg.is_empty() { - video_service::set_privacy_mode_conn_id(self.inner.id); crate::common::make_privacy_mode_msg( back_notification::PrivacyModeState::PrvOnSucceeded, impl_key, @@ -2629,7 +2641,6 @@ impl Connection { "Check privacy mode failed: {}, turn off privacy mode.", &err_msg ); - video_service::set_privacy_mode_conn_id(0); let _ = Self::turn_off_privacy_to_msg(self.inner.id); crate::common::make_privacy_mode_msg_with_details( back_notification::PrivacyModeState::PrvOnFailed, @@ -2646,8 +2657,10 @@ impl Connection { } Some(Err(e)) => { log::error!("Failed to turn on privacy mode. {}", e); - if video_service::get_privacy_mode_conn_id() == 0 { - let _ = Self::turn_off_privacy_to_msg(0); + if !privacy_mode::is_in_privacy_mode() { + let _ = Self::turn_off_privacy_to_msg( + privacy_mode::INVALID_PRIVACY_MODE_CONN_ID, + ); } crate::common::make_privacy_mode_msg_with_details( back_notification::PrivacyModeState::PrvOnFailed, @@ -2674,7 +2687,6 @@ impl Connection { impl_key, ) } else { - video_service::set_privacy_mode_conn_id(0); Self::turn_off_privacy_to_msg(self.inner.id) }; self.send(msg_out).await; diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 509db74b0..c36c6b90d 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -28,6 +28,7 @@ use super::{ use crate::common::SimpleCallOnReturn; #[cfg(target_os = "linux")] use crate::platform::linux::is_x11; +use crate::privacy_mode::{get_privacy_mode_conn_id, INVALID_PRIVACY_MODE_CONN_ID}; #[cfg(windows)] use crate::{ platform::windows::is_process_consent_running, @@ -68,7 +69,6 @@ lazy_static::lazy_static! { let (tx, rx) = unbounded_channel(); (tx, Arc::new(TokioMutex::new(rx))) }; - static ref PRIVACY_MODE_CONN_ID: Mutex = Mutex::new(0); pub static ref VIDEO_QOS: Arc> = Default::default(); pub static ref IS_UAC_RUNNING: Arc> = Default::default(); pub static ref IS_FOREGROUND_WINDOW_ELEVATED: Arc> = Default::default(); @@ -79,16 +79,6 @@ pub fn notify_video_frame_fetched(conn_id: i32, frame_tm: Option) { FRAME_FETCHED_NOTIFIER.0.send((conn_id, frame_tm)).ok(); } -#[inline] -pub fn set_privacy_mode_conn_id(conn_id: i32) { - *PRIVACY_MODE_CONN_ID.lock().unwrap() = conn_id -} - -#[inline] -pub fn get_privacy_mode_conn_id() -> i32 { - *PRIVACY_MODE_CONN_ID.lock().unwrap() -} - struct VideoFrameController { cur: Instant, send_conn_ids: HashSet, @@ -251,7 +241,9 @@ pub fn test_create_capturer( // Note: This function is extremely expensive, do not call it frequently. #[cfg(windows)] fn check_uac_switch(privacy_mode_id: i32, capturer_privacy_mode_id: i32) -> ResultType<()> { - if capturer_privacy_mode_id != 0 && is_current_privacy_mode_impl(PRIVACY_MODE_IMPL_WIN_MAG) { + if capturer_privacy_mode_id != INVALID_PRIVACY_MODE_CONN_ID + && is_current_privacy_mode_impl(PRIVACY_MODE_IMPL_WIN_MAG) + { if !is_installed() { if privacy_mode_id != capturer_privacy_mode_id { if !is_process_consent_running()? { @@ -323,18 +315,19 @@ fn get_capturer(current: usize, portable_service_running: bool) -> ResultType ResultType ResultType<()> { - let privacy_mode_id_2 = *PRIVACY_MODE_CONN_ID.lock().unwrap(); + let privacy_mode_id_2 = get_privacy_mode_conn_id().unwrap_or(INVALID_PRIVACY_MODE_CONN_ID); if privacy_mode_id != privacy_mode_id_2 { - if privacy_mode_id_2 != 0 { + if privacy_mode_id_2 != INVALID_PRIVACY_MODE_CONN_ID { let msg_out = crate::common::make_privacy_mode_msg( back_notification::PrivacyModeState::PrvOnByOther, "".to_owned(), From 5649fcc9ca69659020b90ba79c385c0eba9216f9 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 20 Nov 2023 10:28:57 +0800 Subject: [PATCH 4/7] win, is version equal or greater, build number Signed-off-by: fufesou --- src/platform/windows.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/platform/windows.cc b/src/platform/windows.cc index b76fca2fd..3a3ed437d 100644 --- a/src/platform/windows.cc +++ b/src/platform/windows.cc @@ -660,13 +660,14 @@ extern "C" /* Initialize the condition mask. */ VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op); VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op); + VER_SET_CONDITION(condition_mask, VER_BUILDNUMBER, op); VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op); VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op); /* Perform the test. */ return VerifyVersionInfo( &osvi, - VER_MAJORVERSION | VER_MINORVERSION | + VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, condition_mask); } From 060dfedb74c14eaa99f422c95397c9e576072279 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 20 Nov 2023 10:57:01 +0800 Subject: [PATCH 5/7] topmost_window_exclude_from_capture, change label text Signed-off-by: fufesou --- src/lang/ar.rs | 1 - src/lang/ca.rs | 1 - src/lang/cn.rs | 3 +-- src/lang/cs.rs | 1 - src/lang/da.rs | 1 - src/lang/de.rs | 1 - src/lang/el.rs | 1 - src/lang/en.rs | 3 +-- src/lang/eo.rs | 1 - src/lang/es.rs | 3 +-- src/lang/fa.rs | 1 - src/lang/fr.rs | 1 - src/lang/hu.rs | 1 - src/lang/id.rs | 3 +-- src/lang/it.rs | 3 +-- src/lang/ja.rs | 1 - src/lang/ko.rs | 3 +-- src/lang/kz.rs | 1 - src/lang/lt.rs | 1 - src/lang/lv.rs | 3 +-- src/lang/nl.rs | 1 - src/lang/pl.rs | 3 +-- src/lang/pt_PT.rs | 1 - src/lang/ptbr.rs | 1 - src/lang/ro.rs | 1 - src/lang/ru.rs | 3 +-- src/lang/sk.rs | 1 - src/lang/sl.rs | 1 - src/lang/sq.rs | 1 - src/lang/sr.rs | 1 - src/lang/sv.rs | 1 - src/lang/template.rs | 1 - src/lang/th.rs | 1 - src/lang/tr.rs | 1 - src/lang/tw.rs | 1 - src/lang/ua.rs | 3 +-- src/lang/vn.rs | 1 - src/privacy_mode.rs | 2 +- src/privacy_mode/win_exclude_from_capture.rs | 8 ++++++++ 39 files changed, 19 insertions(+), 48 deletions(-) diff --git a/src/lang/ar.rs b/src/lang/ar.rs index e1de2ae9d..95f0a8a04 100644 --- a/src/lang/ar.rs +++ b/src/lang/ar.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/ca.rs b/src/lang/ca.rs index 48bf4b7d0..37ac295aa 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 60c257606..78db71aa6 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -568,9 +568,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("True color (4:4:4)", "真彩模式(4:4:4)"), ("Enable blocking user input", "允许阻止用户输入"), ("id_input_tip", ""), - ("privacy_mode_impl_mag_tip", "模式 1 (不推荐)"), + ("privacy_mode_impl_mag_tip", "模式 1"), ("privacy_mode_impl_virtual_display_tip", "模式 2 (推荐)"), - ("privacy_mode_impl_exclude_from_capture_tip", "模式 1"), ("Enter privacy mode", "进入隐私模式"), ("Exit privacy mode", "退出隐私模式"), ].iter().cloned().collect(); diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 6ca08ea32..993f136f4 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", "Můžete zadat ID, přímou IP adresu nebo doménu s portem (:).\nPokud chcete přistupovat k zařízení na jiném serveru, připojte adresu serveru (@?key=), například,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nPokud chcete přistupovat k zařízení na veřejném serveru, zadejte \"@public\", klíč není pro veřejný server potřeba."), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/da.rs b/src/lang/da.rs index f5f79e9f9..7cbe8d99d 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/de.rs b/src/lang/de.rs index 4437d9612..9017a744a 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", "Sie können eine ID, eine direkte IP oder eine Domäne mit einem Port (:) eingeben.\nWenn Sie auf ein Gerät auf einem anderen Server zugreifen möchten, fügen Sie bitte die Serveradresse (@?key=) hinzu, zum Beispiel\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nWenn Sie auf ein Gerät auf einem öffentlichen Server zugreifen wollen, geben Sie bitte \"@public\" ein. Der Schlüssel wird für öffentliche Server nicht benötigt."), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/el.rs b/src/lang/el.rs index f27284e81..46577ce90 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/en.rs b/src/lang/en.rs index 5c2d039b5..c416abee9 100644 --- a/src/lang/en.rs +++ b/src/lang/en.rs @@ -203,8 +203,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", "Switch to the primary display because multiple displays are not supported in elevated mode."), ("selinux_tip", "SELinux is enabled on your device, which may prevent RustDesk from running properly as controlled side."), ("id_input_tip", "You can input an ID, a direct IP, or a domain with a port (:).\nIf you want to access a device on another server, please append the server address (@?key=), for example,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nIf you want to access a device on a public server, please input \"@public\", the key is not needed for public server"), - ("privacy_mode_impl_mag_tip", "Mode 1 (deprecated)"), + ("privacy_mode_impl_mag_tip", "Mode 1"), ("privacy_mode_impl_virtual_display_tip", "Mode 2 (recommended)"), - ("privacy_mode_impl_exclude_from_capture_tip", "Mode 1"), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 00159bd0a..35230ccb1 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/es.rs b/src/lang/es.rs index 8bf744ff2..514bf1d5c 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -568,9 +568,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("True color (4:4:4)", "Color real (4:4:4)"), ("Enable blocking user input", "Habilitar el bloqueo de la entrada del usuario"), ("id_input_tip", "Puedes introducir una ID, una IP directa o un dominio con un puerto (:).\nSi quieres acceder a un dispositivo en otro servidor, por favor añade la ip del servidor (@?key=), por ejemplo,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nSi quieres acceder a un dispositivo en un servidor público, por favor, introduce \"@public\", la clave no es necesaria para un servidor público."), - ("privacy_mode_impl_mag_tip", "Modo 1 (obsoleto)"), + ("privacy_mode_impl_mag_tip", "Modo 1"), ("privacy_mode_impl_virtual_display_tip", "Modo 2 (recomendado)"), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", "Entrar al modo privado"), ("Exit privacy mode", "Salir del modo privado"), ].iter().cloned().collect(); diff --git a/src/lang/fa.rs b/src/lang/fa.rs index 3567e8d2e..0d8c8e356 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/fr.rs b/src/lang/fr.rs index a9297bd90..7f840558e 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/hu.rs b/src/lang/hu.rs index daa21390d..298a07d6e 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/id.rs b/src/lang/id.rs index 841aaedf9..b3adcef11 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -568,9 +568,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("True color (4:4:4)", ""), ("Enable blocking user input", "Aktifkan pemblokiran input pengguna"), ("id_input_tip", "Anda bisa memasukkan ID, IP langsung, atau domain dengan port kostum yang sudah ditentukan (:).\nJika anda ingin mengakses perangkat lain yang berbeda server, tambahkan alamat server setelah penulisan ID(@?key=), sebagai contoh,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nJika anda ingin mengakses perangkat yang menggunakan server publik, masukkan \"@public\", server public tidak memerlukan key khusus"), - ("privacy_mode_impl_mag_tip", "Mode 1 (deprecated)"), + ("privacy_mode_impl_mag_tip", "Mode 1"), ("privacy_mode_impl_virtual_display_tip", "Mode 2 (direkomendasikan)"), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", "Masuk mode privasi"), ("Exit privacy mode", "Keluar mode privasi"), ].iter().cloned().collect(); diff --git a/src/lang/it.rs b/src/lang/it.rs index c3c86b52f..93acb97a0 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -568,9 +568,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("True color (4:4:4)", "Colore reale (4:4:4)"), ("Enable blocking user input", "Abilita blocco input utente"), ("id_input_tip", "Puoi inserire un ID, un IP diretto o un dominio con una porta (:).\nSe vuoi accedere as un dispositivo in un altro server, aggiungi l'indirizzo del server (@?key=), ad esempio\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nSe vuoi accedere as un dispositivo in un server pubblico, inserisci \"@public\", per il server pubblico la chiave non è necessaria"), - ("privacy_mode_impl_mag_tip", "Modo 1 (deprecato)"), + ("privacy_mode_impl_mag_tip", "Modo 1"), ("privacy_mode_impl_virtual_display_tip", "Modo 2 (consigliato)"), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", "Entra in modalità privacy"), ("Exit privacy mode", "Esci dalla modalità privacy"), ].iter().cloned().collect(); diff --git a/src/lang/ja.rs b/src/lang/ja.rs index da0a9f8fa..a5c0dff2f 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/ko.rs b/src/lang/ko.rs index c4c24fa70..6195995ef 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -568,9 +568,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("True color (4:4:4)", "트루컬러(4:4:4)"), ("Enable blocking user input", "사용자 입력 차단 허용"), ("id_input_tip", "입력된 ID, IP, 도메인과 포트(:)를 입력할 수 있습니다.\n다른 서버에 있는 장치에 접속하려면 서버 주소(@?key=)를 추가하세요"), - ("privacy_mode_impl_mag_tip", "모드 1(더 이상 사용되지 않음)"), + ("privacy_mode_impl_mag_tip", "모드 1"), ("privacy_mode_impl_virtual_display_tip", "모드 2(권장)"), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", "개인정보 보호 모드 사용"), ("Exit privacy mode", "개인정보 보호 모드 종료"), ].iter().cloned().collect(); diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 0abe19562..5d9ec3f3a 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/lt.rs b/src/lang/lt.rs index d445f3964..69b210311 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/lv.rs b/src/lang/lv.rs index e44f337a1..182de54de 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -568,9 +568,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("True color (4:4:4)", "Īstā krāsa (4:4:4)"), ("Enable blocking user input", "Iespējot lietotāja ievades bloķēšanu"), ("id_input_tip", "Varat ievadīt ID, tiešo IP vai domēnu ar portu (:).\nJa vēlaties piekļūt ierīcei citā serverī, lūdzu, pievienojiet servera adresi (@?key=), piemēram,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nJa vēlaties piekļūt ierīcei publiskajā serverī, lūdzu, ievadiet \"@public\", publiskajam serverim atslēga nav nepieciešama"), - ("privacy_mode_impl_mag_tip", "1. režīms (novecojis)"), + ("privacy_mode_impl_mag_tip", "1. režīms"), ("privacy_mode_impl_virtual_display_tip", "2. režīms (ieteicams)"), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", "Ieiet privātuma režīmā"), ("Exit privacy mode", "Iziet no privātuma režīma"), ].iter().cloned().collect(); diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 75abcdf34..280f5e9a0 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", "Je kunt een ID, een direct IP of een domein met een poort (:) invoeren. Als je toegang wilt als apparaat op een andere server, voeg dan het serveradres toe (@?key=), bijvoorbeeld \n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.Als je toegang wilt als apparaat op een openbare server, voer dan \"@public\" in, voor de openbare server is de sleutel niet nodig."), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 4481a5dfc..a30e059a4 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -568,9 +568,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("True color (4:4:4)", "True color (4:4:4)"), ("Enable blocking user input", "Zablokuj wprowadzanie danych przez użytkownika"), ("id_input_tip", "Możesz wprowadzić identyfikator, bezpośredni adres IP lub domenę z portem (:).\nJeżeli chcesz uzyskać dostęp do urządzenia na innym serwerze, dołącz adres serwera (@?key=, np. \n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nJeżeli chcesz uzyskać dostęp do urządzenia na serwerze publicznym, wpisz \"@public\", klucz nie jest potrzebny dla serwera publicznego."), - ("privacy_mode_impl_mag_tip", "Tryb 1 (przestarzały)"), + ("privacy_mode_impl_mag_tip", "Tryb 1"), ("privacy_mode_impl_virtual_display_tip", "Tryb 2 (zalecany)"), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", "Wejdź w tryb prywatności"), ("Exit privacy mode", "Wyjdź z trybu prywatności"), ].iter().cloned().collect(); diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 25b024a0e..8ca5a0b84 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 1c744f209..708784c20 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/ro.rs b/src/lang/ro.rs index 893053456..c1eac74f8 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 89a234d5a..5990d9ed2 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -568,9 +568,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("True color (4:4:4)", "True color (4:4:4)"), ("Enable blocking user input", "Блокировать ввод пользователя"), ("id_input_tip", "Можно ввести идентификатор, прямой IP-адрес или домен с портом (<домен>:<порт>).\nЕсли необходимо получить доступ к устройству на другом сервере, добавьте адрес сервера (@<адрес_сервера>?key=<ключ_значение>), например:\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nЕсли необходимо получить доступ к устройству на общедоступном сервере, введите \"@public\", ключ для публичного сервера не требуется."), - ("privacy_mode_impl_mag_tip", "Режим 1 (устаревший)"), + ("privacy_mode_impl_mag_tip", "Режим 1"), ("privacy_mode_impl_virtual_display_tip", "Режим 2 (рекомендуемый)"), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", "Включить режим конфиденциальности"), ("Exit privacy mode", "Отключить режим конфиденциальности"), ].iter().cloned().collect(); diff --git a/src/lang/sk.rs b/src/lang/sk.rs index e6b4b9ff2..072b532e6 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", "Môžete zadať ID, priamu IP adresu alebo doménu s portom (:).\nAk chcete získať prístup k zariadeniu na inom serveri, doplňte adresu servera (@?key=), napríklad,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nAk chcete získať prístup k zariadeniu na verejnom serveri, zadajte \"@public\", kľúč nie je potrebný pre verejný server."), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/sl.rs b/src/lang/sl.rs index 475394f5a..382b8a89d 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/sq.rs b/src/lang/sq.rs index d27e12199..c47a154ca 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/sr.rs b/src/lang/sr.rs index 4c95bc0ab..832e81283 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/sv.rs b/src/lang/sv.rs index 71552b873..b2e42a291 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/template.rs b/src/lang/template.rs index d481815ce..027baebad 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/th.rs b/src/lang/th.rs index f90e4d771..b81b77b0a 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 26214719f..3fc58963a 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 828a72831..4ea5bc250 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/lang/ua.rs b/src/lang/ua.rs index a8d5b5149..ca9c52688 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -568,8 +568,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("True color (4:4:4)", "Спражній колір (4:4:4)"), ("Enable blocking user input", "Блокувати введення для користувача"), ("id_input_tip", "Ви можете ввести ID, безпосередню IP, або ж домен з портом (<домен>:<порт>).\nЯкщо ви хочете отримати доступ до пристрою на іншому сервері, будь ласка, додайте адресу сервера (@<адреса_сервера>?key=<значення_ключа>), наприклад,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nЯкщо ви хочете отримати доступ до пристрою на публічному сервері, будь ласка, введіть \"@public\", ключ для публічного сервера не потрібен."), - ("privacy_mode_impl_mag_tip", "Режим 1 (застарілий)"), - ("privacy_mode_impl_exclude_from_capture_tip", ""), + ("privacy_mode_impl_mag_tip", "Режим 1"), ("privacy_mode_impl_virtual_display_tip", "Режим 2 (рекомендований)"), ("Enter privacy mode", "Увійти в режим конфіденційності"), ("Exit privacy mode", "Вийти з режиму конфіденційності"), diff --git a/src/lang/vn.rs b/src/lang/vn.rs index b79939d9f..89b6a189f 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -570,7 +570,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", ""), ("privacy_mode_impl_virtual_display_tip", ""), - ("privacy_mode_impl_exclude_from_capture_tip", ""), ("Enter privacy mode", ""), ("Exit privacy mode", ""), ].iter().cloned().collect(); diff --git a/src/privacy_mode.rs b/src/privacy_mode.rs index 1caa4ee46..d0781d993 100644 --- a/src/privacy_mode.rs +++ b/src/privacy_mode.rs @@ -291,7 +291,7 @@ pub fn get_supported_privacy_mode_impl() -> Vec<(&'static str, &'static str)> { if win_exclude_from_capture::is_supported() { vec_impls.push(( PRIVACY_MODE_IMPL_WIN_EXCLUDE_FROM_CAPTURE, - "privacy_mode_impl_exclude_from_capture_tip", + "privacy_mode_impl_mag_tip", )); } else { if display_service::is_privacy_mode_mag_supported() { diff --git a/src/privacy_mode/win_exclude_from_capture.rs b/src/privacy_mode/win_exclude_from_capture.rs index 0bb81f693..2f73f49b9 100644 --- a/src/privacy_mode/win_exclude_from_capture.rs +++ b/src/privacy_mode/win_exclude_from_capture.rs @@ -7,3 +7,11 @@ pub(super) fn is_supported() -> bool { // https://en.wikipedia.org/wiki/Windows_10_version_history crate::platform::windows::is_windows_version_or_greater(10, 0, 19041, 0, 0) } + +#[cfg(test)] +mod tests { + #[test] + fn test_is_support() { + println!("is exclude from capture supported: {}", super::is_supported()); + } +} From 7f29c7a6013dfb967280abc77308bb48b0d0425c Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 20 Nov 2023 11:07:18 +0800 Subject: [PATCH 6/7] add comment Signed-off-by: fufesou --- src/platform/windows.cc | 1 + src/privacy_mode/win_exclude_from_capture.rs | 8 -------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/platform/windows.cc b/src/platform/windows.cc index 3a3ed437d..25372b218 100644 --- a/src/platform/windows.cc +++ b/src/platform/windows.cc @@ -637,6 +637,7 @@ extern "C" extern "C" { + // https://learn.microsoft.com/en-us/windows/win32/sysinfo/targeting-your-application-at-windows-8-1 // https://github.com/nodejs/node-convergence-archive/blob/e11fe0c2777561827cdb7207d46b0917ef3c42a7/deps/uv/src/win/util.c#L780 BOOL IsWindowsVersionOrGreater(DWORD os_major, DWORD os_minor, diff --git a/src/privacy_mode/win_exclude_from_capture.rs b/src/privacy_mode/win_exclude_from_capture.rs index 2f73f49b9..0bb81f693 100644 --- a/src/privacy_mode/win_exclude_from_capture.rs +++ b/src/privacy_mode/win_exclude_from_capture.rs @@ -7,11 +7,3 @@ pub(super) fn is_supported() -> bool { // https://en.wikipedia.org/wiki/Windows_10_version_history crate::platform::windows::is_windows_version_or_greater(10, 0, 19041, 0, 0) } - -#[cfg(test)] -mod tests { - #[test] - fn test_is_support() { - println!("is exclude from capture supported: {}", super::is_supported()); - } -} From 60e96b637d21dc9ac27cbc79af046628473f8c27 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 20 Nov 2023 11:50:53 +0800 Subject: [PATCH 7/7] privacy mode, remove 'recommended' Signed-off-by: fufesou --- src/lang/cn.rs | 2 +- src/lang/en.rs | 2 +- src/lang/es.rs | 2 +- src/lang/id.rs | 2 +- src/lang/it.rs | 2 +- src/lang/ko.rs | 2 +- src/lang/lv.rs | 2 +- src/lang/pl.rs | 2 +- src/lang/ru.rs | 2 +- src/lang/ua.rs | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 78db71aa6..be59faecb 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -569,7 +569,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable blocking user input", "允许阻止用户输入"), ("id_input_tip", ""), ("privacy_mode_impl_mag_tip", "模式 1"), - ("privacy_mode_impl_virtual_display_tip", "模式 2 (推荐)"), + ("privacy_mode_impl_virtual_display_tip", "模式 2"), ("Enter privacy mode", "进入隐私模式"), ("Exit privacy mode", "退出隐私模式"), ].iter().cloned().collect(); diff --git a/src/lang/en.rs b/src/lang/en.rs index c416abee9..a5f494b74 100644 --- a/src/lang/en.rs +++ b/src/lang/en.rs @@ -204,6 +204,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("selinux_tip", "SELinux is enabled on your device, which may prevent RustDesk from running properly as controlled side."), ("id_input_tip", "You can input an ID, a direct IP, or a domain with a port (:).\nIf you want to access a device on another server, please append the server address (@?key=), for example,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nIf you want to access a device on a public server, please input \"@public\", the key is not needed for public server"), ("privacy_mode_impl_mag_tip", "Mode 1"), - ("privacy_mode_impl_virtual_display_tip", "Mode 2 (recommended)"), + ("privacy_mode_impl_virtual_display_tip", "Mode 2"), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index 514bf1d5c..a2dcd53ba 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -569,7 +569,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable blocking user input", "Habilitar el bloqueo de la entrada del usuario"), ("id_input_tip", "Puedes introducir una ID, una IP directa o un dominio con un puerto (:).\nSi quieres acceder a un dispositivo en otro servidor, por favor añade la ip del servidor (@?key=), por ejemplo,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nSi quieres acceder a un dispositivo en un servidor público, por favor, introduce \"@public\", la clave no es necesaria para un servidor público."), ("privacy_mode_impl_mag_tip", "Modo 1"), - ("privacy_mode_impl_virtual_display_tip", "Modo 2 (recomendado)"), + ("privacy_mode_impl_virtual_display_tip", "Modo 2"), ("Enter privacy mode", "Entrar al modo privado"), ("Exit privacy mode", "Salir del modo privado"), ].iter().cloned().collect(); diff --git a/src/lang/id.rs b/src/lang/id.rs index b3adcef11..3455ddab4 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -569,7 +569,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable blocking user input", "Aktifkan pemblokiran input pengguna"), ("id_input_tip", "Anda bisa memasukkan ID, IP langsung, atau domain dengan port kostum yang sudah ditentukan (:).\nJika anda ingin mengakses perangkat lain yang berbeda server, tambahkan alamat server setelah penulisan ID(@?key=), sebagai contoh,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nJika anda ingin mengakses perangkat yang menggunakan server publik, masukkan \"@public\", server public tidak memerlukan key khusus"), ("privacy_mode_impl_mag_tip", "Mode 1"), - ("privacy_mode_impl_virtual_display_tip", "Mode 2 (direkomendasikan)"), + ("privacy_mode_impl_virtual_display_tip", "Mode 2"), ("Enter privacy mode", "Masuk mode privasi"), ("Exit privacy mode", "Keluar mode privasi"), ].iter().cloned().collect(); diff --git a/src/lang/it.rs b/src/lang/it.rs index 93acb97a0..70fbe1c4e 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -569,7 +569,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable blocking user input", "Abilita blocco input utente"), ("id_input_tip", "Puoi inserire un ID, un IP diretto o un dominio con una porta (:).\nSe vuoi accedere as un dispositivo in un altro server, aggiungi l'indirizzo del server (@?key=), ad esempio\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nSe vuoi accedere as un dispositivo in un server pubblico, inserisci \"@public\", per il server pubblico la chiave non è necessaria"), ("privacy_mode_impl_mag_tip", "Modo 1"), - ("privacy_mode_impl_virtual_display_tip", "Modo 2 (consigliato)"), + ("privacy_mode_impl_virtual_display_tip", "Modo 2"), ("Enter privacy mode", "Entra in modalità privacy"), ("Exit privacy mode", "Esci dalla modalità privacy"), ].iter().cloned().collect(); diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 6195995ef..26a666d53 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -569,7 +569,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable blocking user input", "사용자 입력 차단 허용"), ("id_input_tip", "입력된 ID, IP, 도메인과 포트(:)를 입력할 수 있습니다.\n다른 서버에 있는 장치에 접속하려면 서버 주소(@?key=)를 추가하세요"), ("privacy_mode_impl_mag_tip", "모드 1"), - ("privacy_mode_impl_virtual_display_tip", "모드 2(권장)"), + ("privacy_mode_impl_virtual_display_tip", "모드 2"), ("Enter privacy mode", "개인정보 보호 모드 사용"), ("Exit privacy mode", "개인정보 보호 모드 종료"), ].iter().cloned().collect(); diff --git a/src/lang/lv.rs b/src/lang/lv.rs index 182de54de..100d701fb 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -569,7 +569,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable blocking user input", "Iespējot lietotāja ievades bloķēšanu"), ("id_input_tip", "Varat ievadīt ID, tiešo IP vai domēnu ar portu (:).\nJa vēlaties piekļūt ierīcei citā serverī, lūdzu, pievienojiet servera adresi (@?key=), piemēram,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nJa vēlaties piekļūt ierīcei publiskajā serverī, lūdzu, ievadiet \"@public\", publiskajam serverim atslēga nav nepieciešama"), ("privacy_mode_impl_mag_tip", "1. režīms"), - ("privacy_mode_impl_virtual_display_tip", "2. režīms (ieteicams)"), + ("privacy_mode_impl_virtual_display_tip", "2. režīms"), ("Enter privacy mode", "Ieiet privātuma režīmā"), ("Exit privacy mode", "Iziet no privātuma režīma"), ].iter().cloned().collect(); diff --git a/src/lang/pl.rs b/src/lang/pl.rs index a30e059a4..aa91e8e9a 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -569,7 +569,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable blocking user input", "Zablokuj wprowadzanie danych przez użytkownika"), ("id_input_tip", "Możesz wprowadzić identyfikator, bezpośredni adres IP lub domenę z portem (:).\nJeżeli chcesz uzyskać dostęp do urządzenia na innym serwerze, dołącz adres serwera (@?key=, np. \n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nJeżeli chcesz uzyskać dostęp do urządzenia na serwerze publicznym, wpisz \"@public\", klucz nie jest potrzebny dla serwera publicznego."), ("privacy_mode_impl_mag_tip", "Tryb 1"), - ("privacy_mode_impl_virtual_display_tip", "Tryb 2 (zalecany)"), + ("privacy_mode_impl_virtual_display_tip", "Tryb 2"), ("Enter privacy mode", "Wejdź w tryb prywatności"), ("Exit privacy mode", "Wyjdź z trybu prywatności"), ].iter().cloned().collect(); diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 5990d9ed2..abca158c9 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -569,7 +569,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable blocking user input", "Блокировать ввод пользователя"), ("id_input_tip", "Можно ввести идентификатор, прямой IP-адрес или домен с портом (<домен>:<порт>).\nЕсли необходимо получить доступ к устройству на другом сервере, добавьте адрес сервера (@<адрес_сервера>?key=<ключ_значение>), например:\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nЕсли необходимо получить доступ к устройству на общедоступном сервере, введите \"@public\", ключ для публичного сервера не требуется."), ("privacy_mode_impl_mag_tip", "Режим 1"), - ("privacy_mode_impl_virtual_display_tip", "Режим 2 (рекомендуемый)"), + ("privacy_mode_impl_virtual_display_tip", "Режим 2"), ("Enter privacy mode", "Включить режим конфиденциальности"), ("Exit privacy mode", "Отключить режим конфиденциальности"), ].iter().cloned().collect(); diff --git a/src/lang/ua.rs b/src/lang/ua.rs index ca9c52688..b0b193f94 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -569,7 +569,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable blocking user input", "Блокувати введення для користувача"), ("id_input_tip", "Ви можете ввести ID, безпосередню IP, або ж домен з портом (<домен>:<порт>).\nЯкщо ви хочете отримати доступ до пристрою на іншому сервері, будь ласка, додайте адресу сервера (@<адреса_сервера>?key=<значення_ключа>), наприклад,\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nЯкщо ви хочете отримати доступ до пристрою на публічному сервері, будь ласка, введіть \"@public\", ключ для публічного сервера не потрібен."), ("privacy_mode_impl_mag_tip", "Режим 1"), - ("privacy_mode_impl_virtual_display_tip", "Режим 2 (рекомендований)"), + ("privacy_mode_impl_virtual_display_tip", "Режим 2"), ("Enter privacy mode", "Увійти в режим конфіденційності"), ("Exit privacy mode", "Вийти з режиму конфіденційності"), ].iter().cloned().collect();