Compare commits

...

321 Commits

Author SHA1 Message Date
RustDesk
d716e2b40c Merge pull request #474 from ripp2003/patch-1
Update fr.rs
2022-05-02 16:07:54 +08:00
ripp2003
c9cd57e178 Update fr.rs
Do you accept was not trad
2022-05-02 07:45:10 +02:00
rustdesk
388dcbeb6d comments 2022-05-02 04:41:45 +08:00
rustdesk
a8ad9e9c46 fix format 2022-05-02 03:03:15 +08:00
rustdesk
8a3da687c1 help on mac permissons 2022-05-02 02:44:16 +08:00
rustdesk
0e4e7fcb9b fix cm 2022-05-02 00:02:41 +08:00
rustdesk
663c5bc355 code sign mac 2022-05-01 23:39:03 +08:00
rustdesk
7235756603 fix config sync 2022-05-01 00:50:54 +08:00
rustdesk
f6612d39bf Merge branch 'master' of github.com-rustdesk:rustdesk/rustdesk 2022-04-30 16:43:01 +08:00
rustdesk
a9ada68bfc workaround for shit sciter about style 2022-04-30 16:42:49 +08:00
rustdesk
f21788b967 fix compile warn on win 2022-04-30 14:59:21 +08:00
rustdesk
f90f83fbda more friendly to 0 connections if any unknow happend 2022-04-29 23:32:10 +08:00
rustdesk
1235edb239 found one blank cm, still not find reason 2022-04-29 19:40:53 +08:00
rustdesk
e2c9b78254 mac tray work 2022-04-29 16:21:18 +08:00
rustdesk
8df1e42977 hide icon after initialization before close is useless 2022-04-29 10:40:00 +08:00
rustdesk
69b3f6660a fix ci 2022-04-28 21:54:27 +08:00
rustdesk
c1f5c20e94 https://github.com/rustdesk/rustdesk/issues/77 mac tray, still no find good way to open rustdesk from finder after tray
shown
2022-04-28 21:32:44 +08:00
rustdesk
de44e45ed6 small tweak 2022-04-28 12:10:14 +08:00
rustdesk
0b6155bab8 looks robust now 2022-04-28 04:22:46 +08:00
rustdesk
8995011d45 still not robust 2022-04-28 03:25:39 +08:00
rustdesk
bbe902d92e improve mac service 2022-04-27 19:21:38 +08:00
rustdesk
33c6095eca autofocus chat box input 2022-04-27 01:07:00 +08:00
rustdesk
e66ccdca9d comment for another service implementation 2022-04-26 14:09:47 +08:00
rustdesk
36607bf8b0 fix snap CI 2022-04-26 11:43:16 +08:00
rustdesk
4dfd57ea19 missed file 2022-04-26 11:20:02 +08:00
rustdesk
3566b0ee7a new mac service and local config 2022-04-26 11:19:45 +08:00
rustdesk
05ac26e5fe fix long remote-id style 2022-04-26 00:46:21 +08:00
rustdesk
f1d187739c https://github.com/rustdesk/rustdesk/issues/461 2022-04-24 23:54:05 +08:00
rustdesk
e2161bcc43 fix last PR 2022-04-24 18:11:52 +08:00
RustDesk
ec700ad37d Merge pull request #456 from xxrlzzz/optimize_appbar
Optimize appbar for macos
2022-04-24 17:21:21 +08:00
xxrl
81cd079faa Fix ui issue 2022-04-24 17:15:20 +08:00
RustDesk
7854ad5ee1 Merge pull request #460 from Redion/patch-2
Update README-RU.md
2022-04-24 15:08:01 +08:00
Radion Mynayev
65b335177a Update README-RU.md 2022-04-24 03:04:16 -04:00
rustdesk
eaa481cbea fix transparent cursor 2022-04-24 14:53:19 +08:00
rustdesk
4d5d0a4c62 improve video, ignore same image 2022-04-24 02:50:28 +08:00
rustdesk
264db496ff fix video service 2022-04-24 02:43:00 +08:00
rustdesk
f42a77ad22 fix lock screen for mac and linux 2022-04-24 02:37:27 +08:00
rustdesk
6bc0c3ce98 fix CI 2022-04-23 02:51:54 +08:00
rustdesk
ae74570ab8 fix CI 2022-04-23 02:29:11 +08:00
rustdesk
5bf8e8f001 change linux audio playback from cpal to pulse, because stupid cpal 100% cpu usage problem 2022-04-23 02:17:33 +08:00
xxrl
cfa0c1039c Optimize appbar for macos 2022-04-22 23:41:12 +08:00
rustdesk
aa7779bcf7 pynput version 2022-04-22 12:16:25 +08:00
rustdesk
5d143f57d7 SystemTime::now not work stable on my win7 32, change to Instant 2022-04-22 02:05:11 +08:00
rustdesk
f8fe47d53f fix snap CI 2022-04-21 22:16:15 +08:00
rustdesk
1e120eef18 async logger holder 2022-04-21 21:51:53 +08:00
rustdesk
ccffa14450 fix chat window focus problem and update version number https://github.com/rustdesk/rustdesk/issues/443 2022-04-20 20:44:48 +08:00
rustdesk
d858790170 trans 2022-04-20 17:53:43 +08:00
rustdesk
19468cdbcd wordy 2022-04-20 17:46:21 +08:00
rustdesk
c79c55d643 fix trans 2022-04-20 15:53:13 +08:00
rustdesk
4829b87546 trans 2022-04-20 15:45:33 +08:00
rustdesk
605a52aebb snap readme 2022-04-19 18:45:19 +08:00
RustDesk
da166223bc Merge pull request #450 from Kingtous/master
Feat: Build RustDesk by Snap
2022-04-19 17:00:26 +08:00
kingtous
fef8b0f246 opt: README.md snap connect pulseaudio 2022-04-19 16:45:03 +08:00
kingtous
11086ffa49 fix: libsciter download url 2022-04-19 15:18:52 +08:00
kingtous
f000d0c4ca fix: override pull to inline sciter 2022-04-19 15:10:15 +08:00
kingtous
88107f342d fix: change loginctl priviledge 2022-04-19 14:57:37 +08:00
kingtous
9dff6ee649 add: snap info 2022-04-19 14:46:46 +08:00
kingtous
8f4adab3c8 feat: snapcraft files 2022-04-19 14:46:18 +08:00
kingtous
92be77cf88 add: snap stage deps 2022-04-19 13:56:03 +08:00
rustdesk
885d3a6651 desktop 2022-04-19 12:29:24 +08:00
rustdesk
c0af51e1bd fix wrong link 2022-04-19 10:17:44 +08:00
rustdesk
f95f9e408a workaround for wrong password input hanging 2022-04-18 23:41:43 +08:00
rustdesk
915edf49ab alternative libsciter.so path 2022-04-18 15:45:12 +08:00
rustdesk
4e2a44e392 package script 2022-04-18 15:37:35 +08:00
rustdesk
bbdf3fc9a3 fix mouse out for android 2022-04-17 23:35:53 +08:00
rustdesk
110d63f526 comment out biased 2022-04-16 12:12:34 +08:00
rustdesk
75c9a8c561 remote min size, android icon and scrap memory safety 2022-04-14 20:44:43 +08:00
rustdesk
609996005f STRIDE_ALIGN 16 -> 64 2022-04-12 23:31:42 +08:00
RustDesk
aeb2846d15 Merge pull request #445 from Redion/patch-1
Update ru.rs
2022-04-11 10:26:46 +08:00
Radion Mynayev
f915ab3e79 Update ru.rs
Corrected some Russian translations
2022-04-11 11:23:24 +09:00
rustdesk
8d1f1a9ab4 TouchPad -> Mouse 2022-04-08 18:29:40 +08:00
rustdesk
fa2407d857 fix remote_dir 2022-04-07 22:13:30 +08:00
rustdesk
840413db5f more trans 2022-04-06 10:51:24 +08:00
RustDesk
f370c60d06 Update lang.rs 2022-04-06 10:26:09 +08:00
RustDesk
0a9a7e3090 Merge pull request #441 from mateusauler/translate-ptbr
Translate to Portuguese (Brazil)
2022-04-06 10:18:58 +08:00
Mateus Auler
f7f0146c85 Translate README to Portuguese (Brazil)
Signed-off-by: Mateus Auler <mateusauler@protonmail.com>
2022-04-05 20:31:32 -03:00
Mateus Auler
a29de132a3 Translate UI to Portuguese (Brazil)
Signed-off-by: Mateus Auler <mateusauler@protonmail.com>
2022-04-05 19:05:13 -03:00
rustdesk
6d122d8aef smaller letter size 2022-04-04 15:00:26 +08:00
rustdesk
fb98209008 trans 2022-04-04 14:09:54 +08:00
rustdesk
a56aa08a66 fix file delete bugs 2022-03-28 19:05:12 +08:00
rustdesk
3ea33f7203 improve file write to cm 2022-03-26 03:05:15 +08:00
rustdesk
75c9bbb30f refactor IdPk 2022-03-26 00:06:06 +08:00
rustdesk
1c84fc3786 default relay_server 2022-03-25 18:39:06 +08:00
rustdesk
08330cdaeb longer test_nat timeout 2022-03-25 17:32:32 +08:00
rustdesk
908a7071a7 fix trans 2022-03-24 15:27:06 +08:00
rustdesk
3cd2892bdd skip en and unchanged 2022-03-24 00:09:55 +08:00
rustdesk
f964827f00 add src/lang/template.rs 2022-03-23 23:58:18 +08:00
rustdesk
16ba58aad3 lang.py for auto translate complete 2022-03-23 23:54:04 +08:00
rustdesk
176045468f Merge branch 'master' of github.com-rustdesk:rustdesk/rustdesk 2022-03-23 12:44:19 +08:00
rustdesk
bb58d7f69a Purslane Ltd. 2022-03-23 12:40:22 +08:00
RustDesk
7824fe1f18 Merge pull request #435 from gengteng/master
use vcpkg to find package
2022-03-22 18:07:42 +08:00
rustdesk
0dd4087408 fix file transfer hanging if disabled, and add trans 2022-03-22 17:09:45 +08:00
gengteng
cc42fee9ea Merge remote-tracking branch 'origin/master'
# Conflicts:
#	libs/scrap/build.rs
2022-03-22 16:34:56 +08:00
gengteng
82f2431eb8 use vcpkg to find package 2022-03-22 16:34:27 +08:00
gengteng
e1c9b607fb use vcpkg to find package 2022-03-22 16:19:01 +08:00
rustdesk
9136b3e3f8 fix style 2022-03-21 14:40:36 +08:00
rustdesk
c03c49d482 bug 2022-03-21 00:53:35 +08:00
rustdesk
3cba56c809 fix id_pk 2022-03-20 21:30:04 +08:00
rustdesk
1e0a347893 refactor signed_pk 2022-03-20 20:20:32 +08:00
RustDesk
7c5d260738 Add files via upload 2022-03-18 15:09:33 +08:00
RustDesk
b31eea0279 Merge pull request #432 from fufesou/virtual_display
Virtual display
2022-03-17 21:05:51 +08:00
fufesou
561a0d20ed virtual display: win10 auto install and uninstall virtual display
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-03-17 20:43:27 +08:00
fufesou
117bbb3409 virtual display: plugout monitor on disconnecting, debug failed, may crash...
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-03-17 20:43:27 +08:00
fufesou
974c259a3d virtual display: win10 trivial refactor
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-03-17 20:43:27 +08:00
fufesou
957eabcef0 virtual display: win10 debug windows.
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-03-17 20:43:27 +08:00
fufesou
1eb696356e virtual display: idd add uninstall && example1
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-03-17 20:43:27 +08:00
fufesou
b734e8aee9 add virtual display
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-03-17 20:43:26 +08:00
fufesou
e6bf858ae1 virtual display: compile example ok, not debug yet
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-03-17 20:42:11 +08:00
rustdesk
b350fbdb9c stupid bug 2022-03-15 12:17:07 +08:00
rustdesk
eaeceeac29 https://github.com/rustdesk/rustdesk/issues/406#issuecomment-1064011977 2022-03-15 12:13:46 +08:00
rustdesk
3f57604891 missed port forward check 2022-03-12 12:38:41 +08:00
rustdesk
565e81d329 fix linux lock screen 2022-03-11 12:41:19 +08:00
rustdesk
362aa9a8ff fix show_progress 2022-03-09 21:43:50 +08:00
rustdesk
4f0a58a691 disable privacy mode (not work well), and disable block input if sas not
enabled (not installed version)
2022-03-09 10:55:13 +08:00
rustdesk
88ac9e9d11 more pynput startup try 2022-03-08 17:59:26 +08:00
rustdesk
ffb0fa4349 pynput run as user 2022-03-08 15:42:58 +08:00
rustdesk
6c5b7b3b89 update rdev 2022-03-08 12:14:52 +08:00
rustdesk
74c3f1d7cc linux AltGr ok 2022-03-08 12:08:18 +08:00
rustdesk
617f87a797 fix wrong format of mac 2022-03-08 01:07:59 +08:00
rustdesk
c632b0e8fb scale cursor 2022-03-08 00:27:12 +08:00
rustdesk
dfd128c817 refactor blank thread exit 2022-03-07 22:26:34 +08:00
rustdesk
71fb27fe4b AltGr works on >10, but not on win7, even with pynput 2022-03-07 20:52:12 +08:00
rustdesk
dcad90e073 more on AltGr 2022-03-07 20:16:28 +08:00
rustdesk
b8f7e347c3 fixing AltGr 2022-03-07 16:19:10 +08:00
rustdesk
ab1805281f basically work, but AltGr not handle well, because confused with Alt_R,
and no idea how to get AltGr state. And on Windows, AltGr (some
keyboard, like br) trigger two key down: Left Control and Alt, how to
handle?
2022-03-07 00:48:20 +08:00
rustdesk
1758aa0f1e try out pynput 2022-03-06 03:10:16 +08:00
rustdesk
bcda7d3193 refactor fix_key_down_timeout 2022-03-05 15:16:10 +08:00
rustdesk
3a7647f48b rdev update for https://github.com/rustdesk/rustdesk/issues/406#issuecomment-1058447377 2022-03-04 13:08:51 +08:00
rustdesk
bf0270323c fix show_progress 2022-03-04 00:52:59 +08:00
rustdesk
488b2455b7 another possible cpu burning 2022-03-03 20:46:27 +08:00
rustdesk
db6f46f165 fix cpu burning issue 2022-03-03 20:25:23 +08:00
rustdesk
c4491b0248 https://github.com/rustdesk/rustdesk/issues/421 2022-03-01 11:19:13 +08:00
rustdesk
cd7b7cc555 fix audio exit bug 2022-03-01 10:38:31 +08:00
RustDesk
e2eef09373 Merge pull request #420 from fy2462/fix_audio_sample_exit_when_mute
Fix audio sample exit when mute
2022-03-01 10:36:18 +08:00
yanfeng
ce46fe7d80 Fix audio sample exit when mute 2022-03-01 10:28:53 +08:00
rustdesk
064879d9d2 revert back because big noise on mac 2022-02-28 18:35:40 +08:00
rustdesk
8648c70df4 refactor 2022-02-28 12:36:32 +08:00
RustDesk
9cc3cf92ab Merge pull request #419 from fy2462/fix_audio_switch_on_linux
Fix audio switch on linux
2022-02-28 12:08:44 +08:00
yanfeng
b19d3f5a1c rename function. 2022-02-28 12:03:24 +08:00
yanfeng
2bcc08f084 Miss the checking code. 2022-02-28 12:00:51 +08:00
yanfeng
aa5c7cc38e Fix switch audio input device failed in index page on Linux. 2022-02-28 11:45:02 +08:00
open-trade
8460c1ac42 format 2022-02-24 14:40:33 +08:00
RustDesk
944fde15a4 Merge pull request #417 from fufesou/copy_paste
remove remote conn id
2022-02-24 11:48:27 +08:00
fufesou
5a07701b90 remove remote conn id
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-02-24 11:32:14 +08:00
rustdesk
8770552448 refactor cm for clipboardfile 2022-02-24 10:38:17 +08:00
RustDesk
4fb8de9b68 Merge pull request #416 from fufesou/copy_paste
Move clipboard service to cm module
2022-02-24 08:51:34 +08:00
fufesou
01591d1abf fix hang up
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-02-24 02:46:47 +08:00
fufesou
128a4aca69 fix crash on windows clipboard
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-02-24 00:26:19 +08:00
fufesou
555ff0085a empty clipboard, debug crash & failed to copy
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-02-24 00:26:19 +08:00
fufesou
2f6b457b3f better control of clipboard file transfer
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-02-24 00:26:19 +08:00
fufesou
8834251eec move clipboard file service to cm module
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-02-24 00:26:19 +08:00
RustDesk
69769cc123 Merge pull request #413 from Heap-Hop/master
try to fix audio play noise;improve audio performance
2022-02-22 20:52:36 +08:00
csf
82d5924401 try to fix audio play noise;improve audio performance 2022-02-22 20:45:49 +08:00
rustdesk
4a03c60ac1 Merge branch 'master' of github.com-rustdesk:rustdesk/rustdesk 2022-02-21 09:39:21 +08:00
rustdesk
f11ca64eac handling IME 2022-02-21 09:39:01 +08:00
RustDesk
9f238bd7ff Merge pull request #410 from victorbnl/master
Fix esperanto README
2022-02-21 08:03:52 +08:00
Victor B
0ce67973f6 Fix esperanto README 2022-02-20 18:58:02 +01:00
rustdesk
6fa8138568 fix CI 2022-02-20 10:12:28 +08:00
RustDesk
270c927d2f Merge pull request #408 from victorbnl/fix-french
Fix french translation
2022-02-20 10:06:29 +08:00
RustDesk
c117eaee2e Merge pull request #407 from victorbnl/esperanto
Add esperanto translation
2022-02-20 10:05:32 +08:00
Victor B
a4fcb8d7c1 Fix french README 2022-02-19 20:18:37 +01:00
Victor B
100daf4031 Fix french translation 2022-02-19 20:14:41 +01:00
Victor B
3b3958ed20 Add esperanto translation 2022-02-19 20:01:28 +01:00
rustdesk
4e9a96dad9 direct access port editable 2022-02-19 15:30:09 +08:00
rustdesk
1c7f9b6f45 https://github.com/rustdesk/rustdesk/issues/264 2022-02-18 11:15:40 +08:00
RustDesk
2786fc97e9 Merge pull request #405 from WoozyMasta/russian
Added localization into Russian
2022-02-17 08:56:55 +08:00
RustDesk
d7becdfa9f Merge branch 'master' into russian 2022-02-17 08:56:47 +08:00
RustDesk
df4ecf9339 Merge pull request #404 from WoozyMasta/fix_de
Fixed loading of German language file
2022-02-17 08:55:57 +08:00
WoozyMasta
a4ba033284 docs: translate community servers table 2022-02-17 02:27:29 +03:00
WoozyMasta
57722c950a fix: load German language 2022-02-17 02:08:18 +03:00
WoozyMasta
691b85b3fc feat: added Russian l18n 2022-02-17 02:05:24 +03:00
rustdesk
c7191023cb test_nat_type sleep time 2022-02-16 20:12:33 +08:00
RustDesk
3aa111b16c Merge pull request #403 from MarcelKuesters/master
Update README-DE.md
2022-02-16 19:37:59 +08:00
Marcel Küsters
2b64375ab0 Update README-DE.md
Did some grammar corrections for German with LanguageTool.org.
2022-02-16 12:24:59 +01:00
RustDesk
b7c1222ce1 Merge pull request #402 from rizlas/master
README translation
2022-02-16 18:57:23 +08:00
rizlas
3dbd62f867 Removed linked README-RU. 2022-02-16 11:53:39 +01:00
rizlas
78be555931 Update header of the other translation 2022-02-16 11:46:57 +01:00
rizlas
c31830f7c4 Update README-IT.md 2022-02-16 11:31:02 +01:00
rizlas
ed0c234b03 Italian translation. Main readme update 2022-02-16 11:27:36 +01:00
rustdesk
52919fd77b remove CLIPRDR_NAME 2022-02-15 22:33:44 +08:00
rustdesk
104c022b26 check_clipboard_file_context later 2022-02-15 22:20:28 +08:00
RustDesk
9b22ee765d Merge pull request #401 from fufesou/copy_paste_3
Windows clipboard -- fix memory leak
2022-02-15 21:33:06 +08:00
fufesou
e80869af67 fix memory leak
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-02-15 21:28:41 +08:00
rustdesk
0b182b9acd more trans 2022-02-15 19:08:29 +08:00
RustDesk
1ca94d7f81 Merge pull request #400 from MarcelKuesters/master
Added German translation.
2022-02-15 18:58:39 +08:00
Marcel Küsters
b0e6a59ded Update lang.rs
Added German language.

Regards.
Marcel Küsters
2022-02-15 11:52:00 +01:00
Marcel Küsters
2f4d02c2bf Create de.rs
Added German translation.

Regards.
Marcel Küsters
2022-02-15 11:42:08 +01:00
rustdesk
835db29c3f fix cliprdr for windows after refactory 2022-02-15 15:35:19 +08:00
rustdesk
933969d1fe refactor cliprdr, not tested on windows yet 2022-02-15 14:46:08 +08:00
RustDesk
e407ba3a33 Merge pull request #399 from fufesou/copy_paste_2
windows clipboard
2022-02-15 13:14:35 +08:00
fufesou
6672087f7c windows clipboard
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-02-15 11:18:53 +08:00
RustDesk
8bb4183098 Update CONTRIBUTING.md 2022-02-14 09:52:43 +08:00
RustDesk
db2b912b3e Merge pull request #397 from FahimFBA/fba
added the Code of Conduct
2022-02-14 09:52:00 +08:00
FahimFBA
fc159fa1f1 added the Code of Conduct 2022-02-14 01:42:34 +06:00
rustdesk
d87f29c679 traditional chinese 2022-02-12 11:50:39 +08:00
RustDesk
a4d34aacea Merge pull request #392 from SiderealArt/patch-1
Add Traditional Chinese translation
2022-02-12 11:44:31 +08:00
SiderealArt
e92700f3f9 Add Traditional Chinese translation 2022-02-12 11:42:39 +08:00
open-trade
8ce94e04b6 fix block_input hanging issue 2022-02-11 14:39:41 +08:00
open-trade
3c29b8a58a fix style 2022-02-10 16:08:50 +08:00
rustdesk
08fdeb7d4b remove old back-compatibility code 2022-02-10 11:32:16 +08:00
rustdesk
4df09f4aec fix style 2022-02-09 20:35:50 +08:00
open-trade
4945605009 fix on cm (connectin not closed somehow) and refactor isEnterKey 2022-02-09 16:06:44 +08:00
open-trade
d313fa92e1 fix clipboard initial sync issue introduced in the PR 2022-02-08 20:34:10 +08:00
open-trade
aa1c0df08f typo 2022-02-08 18:10:32 +08:00
open-trade
dddbae4eb1 fix on should_exit 2022-02-08 18:09:45 +08:00
open-trade
6143a3c649 fix style 2022-02-08 13:58:42 +08:00
open-trade
6c05f72d90 refactor should_exit 2022-02-07 18:39:49 +08:00
rustdesk
809c220eaf stupid workaround for https://sciter.com/forums/topic/crash-on-latest-tis-mac-sdk-sometimes/ 2022-02-06 18:19:06 +08:00
rustdesk
3ec69b6d97 refactor video_ack_required 2022-02-05 01:19:24 +08:00
rustdesk
5a0f8d008e video_ack_required for web 2022-02-04 22:18:48 +08:00
rustdesk
eb49af843c tmp solution for msgbox in scrollable 2022-02-04 11:20:01 +08:00
rustdesk
9c6715f95e reset input_blocked after reconnection 2022-02-01 23:43:42 +08:00
rustdesk
39ea73657d typo 2022-02-01 21:52:07 +08:00
rustdesk
7d14ce98e1 fix style 2022-02-01 18:33:18 +08:00
rustdesk
3112792b7b fix new msgbox when wrong password 2022-02-01 16:32:56 +08:00
rustdesk
cd62d7024b new msgbox 2022-02-01 02:38:52 +08:00
rustdesk
bc3d3bd0ec refactor server keyboard/clipboard enabled 2022-01-31 18:00:57 +08:00
rustdesk
484f50811d no privacy mode if keyboard disabled 2022-01-31 17:27:21 +08:00
rustdesk
2a11bc63ce more trans and format 2022-01-31 01:54:49 +08:00
rustdesk
64071943fc change to async channel 2022-01-30 21:37:46 +08:00
rustdesk
29ca2ed14d format 2022-01-30 21:34:34 +08:00
rustdesk
e23a6805e3 move audio/video decoder in seperate thread 2022-01-30 21:16:08 +08:00
rustdesk
5a9803c2c8 format lang 2022-01-30 03:41:18 +08:00
rustdesk
b5f056c0c0 missed options init 2022-01-29 21:30:14 +08:00
rustdesk
495cc9056e Merge branch 'master' of github.com-rustdesk:rustdesk/rustdesk 2022-01-29 16:56:39 +08:00
rustdesk
6a19b8caa1 refactor msgbox 2022-01-29 16:56:24 +08:00
open-trade
2719936ea9 change tab padding to 8 2022-01-28 17:55:09 +08:00
open-trade
4108635b34 refactor tab responsive size again 2022-01-28 17:48:49 +08:00
open-trade
9118511bbd min 3 chars 2022-01-28 17:13:56 +08:00
open-trade
7b06dab4ee improve responsive tab size 2022-01-28 16:58:32 +08:00
open-trade
ea2fe3eff0 https://github.com/rustdesk/rustdesk/issues/366 2022-01-24 15:51:29 +08:00
rustdesk
1cda704628 more test_nat_type 2022-01-24 03:15:01 +08:00
rustdesk
a3511d9157 update crates, and set new default #cpu 2022-01-24 02:26:07 +08:00
rustdesk
98aa410683 more set_nodelay 2022-01-24 01:50:22 +08:00
rustdesk
bf578e768b set_nodelay 2022-01-23 20:53:55 +08:00
open-trade
372b715162 bug fix on file transfer window 2022-01-21 15:13:29 +08:00
rustdesk
b0ddd3d543 fix on file type (after protobuf change), improve current row select,
still has bug for detecting file type under Windows
2022-01-21 12:52:08 +08:00
rustdesk
a474f904b1 for back compatibility 2022-01-21 02:06:33 +08:00
rustdesk
cd9faf48f3 new pk 2022-01-20 12:48:55 +08:00
rustdesk
b76a1d36cb typo 2022-01-20 00:25:01 +08:00
rustdesk
893d8b39c9 fix style on linux 2022-01-19 23:30:21 +08:00
open-trade
326eed5ee0 make tcp sync 2022-01-19 16:40:05 +08:00
rustdesk
a1b9e1b229 https://github.com/rustdesk/rustdesk/issues/356 2022-01-19 11:18:12 +08:00
rustdesk
4b51fffc96 update rdev for kp8/9 bug on mac 2022-01-18 12:24:07 +08:00
rustdesk
3485d2ddc7 fix css style 2022-01-17 20:50:48 +08:00
open-trade
92a1bb04e9 make proto compatible to c++ 2022-01-17 16:53:17 +08:00
open-trade
02cbc0d407 fix style 2022-01-17 15:05:33 +08:00
rustdesk
e0637f966a sync config if enable mac service 2022-01-17 12:38:44 +08:00
rustdesk
5af1258454 refactor mac service 2022-01-17 12:05:06 +08:00
rustdesk
a12f24bf16 remove InputFunc 2022-01-15 22:03:17 +08:00
rustdesk
9651666d41 code refactory 2022-01-15 21:33:20 +08:00
rustdesk
6bd730bc67 unwrap -> ok to avoid unintended crash 2022-01-15 19:11:19 +08:00
rustdesk
35816d4fbb polish block input 2022-01-15 18:27:15 +08:00
RustDesk
647721a37e Merge pull request #373 from fufesou/privacy_mode
Privacy mode
2022-01-15 17:22:11 +08:00
fufesou
25492c815c simple privacy mode
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-01-15 16:57:07 +08:00
fufesou
a1c4b08535 simple privacy demo
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-01-15 16:32:55 +08:00
rustdesk
8f998771c9 refactor process id 2022-01-15 14:08:24 +08:00
rustdesk
f47dcd1a8b remove psutil which is too old 2022-01-15 13:47:57 +08:00
rustdesk
d069b73303 refactor 2022-01-15 02:16:00 +08:00
RustDesk
6fe4344cb0 Merge pull request #370 from Heasn/master
Fix some macOS new services issues
2022-01-14 23:22:08 +08:00
rustdesk
4fe5d2cf02 no lan discovery if no install 2022-01-14 23:21:30 +08:00
rustdesk
95239fc148 change back to broadcast, because multicast has big problem if multiple
interface with 0.0.0.0 binding
2022-01-14 23:02:08 +08:00
Chen Baiyu
5fb613d4b2 Merge branch 'rustdesk:master' into master 2022-01-14 18:31:18 +08:00
chenbaiyu
c8df8ae551 collapse imports 2022-01-14 18:30:34 +08:00
chenbaiyu
d0ca9de946 add new service install tip in Chinese 2022-01-14 18:28:39 +08:00
open-trade
0a2bc1cf8a try out muliticast on multiple interface 2022-01-14 18:16:00 +08:00
chenbaiyu
d5286782cd fix server service not start after daemon installed at first time 2022-01-14 17:36:41 +08:00
RustDesk
07aa0898c5 Merge pull request #369 from Heasn/master
New launch daemon/agents and config sync service on macOS
2022-01-14 10:49:48 +08:00
chenbaiyu
4d37a9ee23 fix CI failed build on linux 2022-01-14 03:52:39 +08:00
chenbaiyu
1fda4c257d fix CI failed build on linux 2022-01-14 03:47:16 +08:00
chenbaiyu
fea4b068cd fix CI failed build on linux 2022-01-14 03:43:01 +08:00
chenbaiyu
e23eb3e79b Merge remote-tracking branch 'origin/master' 2022-01-14 03:38:41 +08:00
chenbaiyu
78450fda08 fix CI failed build on linux 2022-01-14 03:38:22 +08:00
Chen Baiyu
78f2d3f31f Merge branch 'rustdesk:master' into master 2022-01-14 03:18:41 +08:00
chenbaiyu
b4f61c735e fix plist files and enhance privilege escalation method 2022-01-14 03:17:36 +08:00
rustdesk
7944e0bc36 fix CI 2022-01-14 01:29:52 +08:00
rustdesk
780b57f597 load keyboard layout for mac 2022-01-14 01:15:03 +08:00
chenbaiyu
29bb10a40a modify daemon install check 2022-01-13 20:34:28 +08:00
chenbaiyu
8e6dd76c5b remove unused import and launch service when install 2022-01-13 19:42:25 +08:00
chenbaiyu
9be6b17a8b Add launch service 2022-01-13 19:23:41 +08:00
open-trade
7b1806b0f3 disable crc, because super slow on my Ubuntu in virtualbox 2022-01-13 19:00:00 +08:00
chenbaiyu
f45a2c7a94 Add user and root config sync action 2022-01-13 16:33:51 +08:00
Chen Baiyu
81e43c2970 Merge branch 'rustdesk:master' into master 2022-01-13 16:08:57 +08:00
chenbaiyu
e51e5ac4b1 Revert "temp commit"
This reverts commit 2e03ca19f6.
2022-01-13 16:07:18 +08:00
chenbaiyu
1995f9fa4e Revert "temp commit"
This reverts commit 88f0f67ee3.
2022-01-13 16:06:51 +08:00
chenbaiyu
88f0f67ee3 temp commit 2022-01-13 15:26:57 +08:00
rustdesk
d379f23490 my bad 2022-01-13 02:11:47 +08:00
rustdesk
75ef279e47 avoid select! all branches disabled panic 2022-01-13 01:16:23 +08:00
chenbaiyu
5b03e99404 Merge remote-tracking branch 'origin/master' 2022-01-12 21:40:19 +08:00
chenbaiyu
2e03ca19f6 temp commit 2022-01-12 21:40:02 +08:00
open-trade
3aebc43111 more control keys, and VkKeyScanW -> VkKeyScanExW with forground window
keyboard layout
2022-01-12 18:11:42 +08:00
rustdesk
8ea5d80f01 new lan discovery https://github.com/rustdesk/rustdesk/issues/261 2022-01-12 03:10:15 +08:00
open-trade
4071f803f7 fix compile error 2022-01-11 16:59:53 +08:00
open-trade
65eef2b579 raw lan discovery 2022-01-11 16:24:35 +08:00
open-trade
9c9855877d bind_multicast 2022-01-10 18:58:51 +08:00
open-trade
9a92b6ac4a revert back from lan discovery merge 2022-01-10 18:05:42 +08:00
RustDesk
b400e4305f Merge pull request #337 from fufesou/lan_discovery
Lan discovery
2022-01-10 17:35:54 +08:00
RustDesk
dfeb9a29c1 Merge branch 'master' into lan_discovery 2022-01-10 17:34:51 +08:00
rustdesk
e2a879692d ignore modifiers for name 2022-01-10 03:11:53 +08:00
rustdesk
3a6dc19616 to be compatible with 1.1.8 2022-01-10 01:29:50 +08:00
rustdesk
ae79a36f7b remove valid_for_capslock 2022-01-10 01:06:31 +08:00
rustdesk
3212290f6e fix on rdev 2022-01-10 00:33:31 +08:00
rustdesk
d07ae9f2c6 numpad 2022-01-09 23:59:30 +08:00
rustdesk
3f56c82c7b revert keysym back, enigo's Layout can do this 2022-01-09 21:05:00 +08:00
rustdesk
a0c704f36e string len is num of bytes 2022-01-09 20:56:56 +08:00
rustdesk
baccff8f99 Merge branch 'master' of github.com-rustdesk:rustdesk/rustdesk 2022-01-09 19:56:48 +08:00
rustdesk
0a294d9ff3 https://github.com/rustdesk/rustdesk/issues/292 2022-01-09 19:56:24 +08:00
RustDesk
03fb47b312 Merge pull request #361 from Heasn/master
fix pre-login window behavior on macOS Big Sur or above
2022-01-08 02:17:28 +08:00
chenbaiyu
29f15aabed fix security problem caused server hang and unexpected input behavior at pre-login window when macOS version on Big Sur or above 2022-01-08 01:39:54 +08:00
RustDesk
089acaa6e7 Merge pull request #359 from fufesou/master
Failed to decode audio frame
2022-01-07 21:34:53 +08:00
fufesou
709a2a30bc Merge branch 'rustdesk:master' into master 2022-01-07 21:30:51 +08:00
fufesou
54269b6f5d fix audio play with sample rate 48000
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-01-07 21:30:13 +08:00
open-trade
a7a4cd7eac CI 2022-01-07 18:05:33 +08:00
open-trade
26d161f827 working on keysym 2022-01-07 18:03:55 +08:00
open-trade
9df1fcb783 update tigervnc 2022-01-07 16:21:56 +08:00
open-trade
e82f040d6d kick start international keyboard 2022-01-07 13:59:21 +08:00
fufesou
35462eecfe comment out discovery button
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2021-12-21 01:17:29 +08:00
fufesou
d00352f4e4 lan discovery almost done
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2021-12-21 00:34:10 +08:00
fufesou
5682b088de lan discovery will be done soon
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2021-12-21 00:34:10 +08:00
fufesou
bcbe9ccbe5 trivial changes
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2021-12-21 00:34:09 +08:00
fufesou
87f50a6318 lan discovery in socket_cs
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2021-12-21 00:34:09 +08:00
131 changed files with 15384 additions and 2265 deletions

4
.cargo/config.toml Normal file
View File

@@ -0,0 +1,4 @@
[target.'cfg(target_os="macos")']
rustflags = [
"-C", "link-args=-sectcreate __CGPreLoginApp __cgpreloginapp /dev/null",
]

30
.github/workflows/snap-ci.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: Snap CI
on:
push:
branches:
- master
paths-ignore:
- README.md
tags:
- '*'
jobs:
build-snap-master-package:
runs-on: ubuntu-18.04
steps:
- name: Check out Git repository
uses: actions/checkout@v2
- name: Use Snapcraft
uses: snapcore/action-build@v1
id: build
- uses: actions/upload-artifact@v2
with:
name: rustdesk.snap
path: ${{ steps.build.outputs.snap }}
# - uses: snapcore/action-publish@v1
# with:
# store_login: ${{ secrets.SNAP_TOKEN }}
# snap: ${{ steps.build.outputs.snap }}
# release: edge

1
.gitignore vendored
View File

@@ -8,3 +8,4 @@ __pycache__
src/version.rs
*dmg
sciter.dll
**pdb

133
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,133 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[info@rustdesk.com](mailto:info@rustdesk.com).
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
at [https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View File

@@ -39,7 +39,7 @@ For specific git instructions, see [GitHub workflow 101](https://github.com/serv
## Conduct
We follow the [Rust Code of Conduct](https://www.rust-lang.org/policies/code-of-conduct).
https://github.com/rustdesk/rustdesk/blob/master/CODE_OF_CONDUCT.md
## Communication

1945
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
[package]
name = "rustdesk"
version = "1.1.8"
version = "1.1.9"
authors = ["rustdesk <info@rustdesk.com>"]
edition = "2018"
edition = "2021"
build= "build.rs"
description = "A remote control software."
@@ -21,7 +21,9 @@ whoami = "1.2"
scrap = { path = "libs/scrap" }
hbb_common = { path = "libs/hbb_common" }
enigo = { path = "libs/enigo" }
sys-locale = "0.1"
clipboard = { path = "libs/clipboard" }
virtual_display = { path = "libs/virtual_display" }
sys-locale = "0.2"
serde_derive = "1.0"
serde = "1.0"
serde_json = "1.0"
@@ -31,21 +33,22 @@ sha2 = "0.10"
repng = "0.2"
libc = "0.2"
parity-tokio-ipc = { git = "https://github.com/open-trade/parity-tokio-ipc" }
flexi_logger = "0.22"
flexi_logger = { version = "0.22", features = ["async", "use_chrono_for_offset"] }
runas = "0.2"
magnum-opus = { git = "https://github.com/open-trade/magnum-opus" }
dasp = { version = "0.11", features = ["signal", "interpolate-linear", "interpolate"], optional = true }
rubato = { version = "0.10", optional = true }
rubato = { version = "0.12", optional = true }
samplerate = { version = "0.2", optional = true }
async-trait = "0.1"
crc32fast = "1.3"
uuid = { version = "0.8", features = ["v4"] }
clap = "2.34"
rpassword = "5.0"
uuid = { version = "1.0.0", features = ["v4"] }
clap = "3.0"
rpassword = "6.0"
base64 = "0.13"
sysinfo = "0.23"
num_cpus = "1.13"
[target.'cfg(not(any(target_os = "android")))'.dependencies]
cpal = { git = "https://github.com/open-trade/cpal" }
[target.'cfg(not(any(target_os = "android", target_os = "linux")))'.dependencies]
cpal = "0.13.5"
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
machine-uid = "0.2"
@@ -54,6 +57,8 @@ sciter-rs = { git = "https://github.com/open-trade/rust-sciter", branch = "dyn"
ctrlc = "3.2"
arboard = "2.0"
clipboard-master = "3.1"
#rdev = { path = "../rdev" }
rdev = { git = "https://github.com/open-trade/rdev" }
[target.'cfg(target_os = "windows")'.dependencies]
systray = { git = "https://github.com/liyue201/systray-rs" }
@@ -67,20 +72,19 @@ cocoa = "0.24"
dispatch = "0.2"
core-foundation = "0.9"
core-graphics = "0.22"
include_dir = "0.7.2"
tray-item = "0.7" # looks better than trayicon
[target.'cfg(target_os = "linux")'.dependencies]
libpulse-simple-binding = "2.24"
libpulse-binding = "2.25"
psimple = { package = "libpulse-simple-binding", version = "2.25" }
pulse = { package = "libpulse-binding", version = "2.26" }
rust-pulsectl = { git = "https://github.com/open-trade/pulsectl" }
[target.'cfg(not(any(target_os = "windows", target_os = "android", target_os = "ios")))'.dependencies]
psutil = { version = "3.2", features = [ "process" ], git = "https://github.com/open-trade/rust-psutil" }
[target.'cfg(target_os = "android")'.dependencies]
android_logger = "0.10"
android_logger = "0.11"
[workspace]
members = ["libs/scrap", "libs/hbb_common", "libs/enigo"]
members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display"]
[package.metadata.winres]
LegalCopyright = "Copyright © 2020"
@@ -104,6 +108,7 @@ identifier = "com.carriez.rustdesk"
icon = ["32x32.png", "128x128.png", "128x128@2x.png"]
deb_depends = ["libgtk-3-0", "libxcb-randr0", "libxdo3", "libxfixes3", "libxcb-shape0", "libxcb-xfixes0", "libasound2", "libsystemd0", "pulseaudio"]
osx_minimum_system_version = "10.14"
resources = ["mac-tray.png"]
#https://github.com/johnthagen/min-sized-rust
#!!! rembember call "strip target/release/rustdesk"

19
DEBIAN/postinst Normal file
View File

@@ -0,0 +1,19 @@
#!/bin/bash
set -e
if [ "$1" = configure ]; then
INITSYS=$(ls -al /proc/1/exe | awk -F' ' '{print $NF}' | awk -F'/' '{print $NF}')
if [ "systemd" == "$INITSYS" ]; then
if [ -e /etc/systemd/system/rustdesk.service ]; then
rm /etc/systemd/system/rustdesk.service
fi
sudo -H pip3 install pynput
cp /usr/share/rustdesk/files/systemd/rustdesk.service /etc/systemd/system/rustdesk.service
systemctl daemon-reload
systemctl enable rustdesk
systemctl start rustdesk
fi
fi

11
DEBIAN/postrm Normal file
View File

@@ -0,0 +1,11 @@
#!/bin/bash
set -e
case $1 in
purge)
rm -rf /root/.config/rustdesk || true
;;
esac
exit 0

16
DEBIAN/preinst Normal file
View File

@@ -0,0 +1,16 @@
#!/bin/bash
set -e
case $1 in
install|upgrade)
INITSYS=$(ls -al /proc/1/exe | awk -F' ' '{print $NF}' | awk -F'/' '{print $NF}')
if [ "systemd" == "${INITSYS}" ]; then
service rustdesk stop || true
sleep 1
rm -rf /usr/bin/libsciter-gtk.so
fi
;;
esac
exit 0

16
DEBIAN/prerm Normal file
View File

@@ -0,0 +1,16 @@
#!/bin/bash
set -e
case $1 in
remove|upgrade)
INITSYS=$(ls -al /proc/1/exe | awk -F' ' '{print $NF}' | awk -F'/' '{print $NF}')
if [ "systemd" == "${INITSYS}" ]; then
systemctl stop rustdesk || true
systemctl disable rustdesk || true
rm /etc/systemd/system/rustdesk.service || true
fi
;;
esac
exit 0

View File

@@ -5,7 +5,7 @@
<a href="#auf-docker-kompilieren">Docker</a> •
<a href="#dateistruktur">Dateistruktur</a> •
<a href="#screenshots">Screenshots</a><br>
[<a href="README.md">English</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PT.md">Português</a>]<br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
<b>Wir brauchen deine Hilfe um diese README Datei zu verbessern und aktualisieren</b>
</p>
@@ -13,7 +13,7 @@ Rede mit uns: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.re
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
Das hier ist ein Programm was man nutzen kann, um einen Computer fernzusteuern, es wurde in Rust geschrieben. Es funktioniert ohne Konfiguration oder ähnliches, man kann es einfach direkt nutzen. Du hast volle Kontrolle über deine Daten und brauchst dir daher auch keine Sorgen um die Sicherheit dieser Daten zu machen. Du kannst unseren rendezvous/relay Server nutzen, [einen eigenen Server eröffnen](https://rustdesk.com/blog/id-relay-set/) oder [einen neuen eigenen Server programmieren](https://github.com/rustdesk/rustdesk-server-demo).
Das hier ist ein Programm was, man nutzen kann, um einen Computer fernzusteuern, es wurde in Rust geschrieben. Es funktioniert ohne Konfiguration oder ähnliches, man kann es einfach direkt nutzen. Du hast volle Kontrolle über deine Daten und brauchst dir daher auch keine Sorgen um die Sicherheit dieser Daten zu machen. Du kannst unseren Rendezvous/Relay Server nutzen, [einen eigenen Server eröffnen](https://rustdesk.com/server) oder [einen neuen eigenen Server programmieren](https://github.com/rustdesk/rustdesk-server-demo).
RustDesk heißt jegliche Mitarbeit willkommen. Schau dir [`CONTRIBUTING.md`](CONTRIBUTING.md) an, wenn du Hilfe brauchst für den Start.
@@ -21,7 +21,7 @@ RustDesk heißt jegliche Mitarbeit willkommen. Schau dir [`CONTRIBUTING.md`](CON
## Kostenlose öffentliche Server
Hier sind die Server die du kostenlos nutzen kannst, es kann sein das sich diese Liste immer mal wieder ändert. Falls du nicht in der Nähe einer dieser Server bist, kann es sein, dass deine Verbindung langsam sein wird.
Hier sind die Server, die du kostenlos nutzen kannst, es kann sein das sich diese Liste immer mal wieder ändert. Falls du nicht in der Nähe einer dieser Server bist, kann es sein, dass deine Verbindung langsam sein wird.
| Standort | Serverart | Spezifikationen | Kommentare |
| --------- | ------------- | ------------------ | ---------- |
@@ -31,7 +31,7 @@ Hier sind die Server die du kostenlos nutzen kannst, es kann sein das sich diese
## Abhängigkeiten
Die Desktop Versionen nutzen [Sciter](https://sciter.com/) für die Oberfläche, bitte lade die dynamische Sciter Bibliothek selbst herunter.
Die Desktop-Versionen nutzen [Sciter](https://sciter.com/) für die Oberfläche, bitte lade die dynamische Sciter Bibliothek selbst herunter.
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
@@ -126,7 +126,7 @@ Jedes Mal, wenn du das Programm Kompilieren musst, nutze diesen Befehl:
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
```
Bedenke, dass das erste Mal Kompilieren länger dauern kann, da die Abhängigkeiten erst kompiliert werden müssen bevor sie zwischengespeichert werden können. Darauf folgende Kompiliervorgänge werden schneller sein. Falls du zusätzliche oder andere Argumente für den Kompilierbefehl angeben musst, kannst du diese am Ende des Befehls an der `<OPTIONAL-ARGS>` Position machen. Wenn du zum Beispiel eine optimierte Releaseversion kompilieren willst, kannst du das tun indem du `--release` am Ende des Befehls anhängst. Das daraus entstehende Programm kannst du im “target” Ordner auf deinem System finden. Du kannst es mit folgenden Befehlen ausführen:
Bedenke, dass das erste Mal Kompilieren länger dauern kann, da die Abhängigkeiten erst kompiliert werden müssen bevor sie zwischengespeichert werden können. Darauf folgende Kompiliervorgänge werden schneller sein. Falls du zusätzliche oder andere Argumente für den Kompilierbefehl angeben musst, kannst du diese am Ende des Befehls an der `<OPTIONAL-ARGS>` Position machen. Wenn du zum Beispiel eine optimierte Releaseversion kompilieren willst, kannst du das tun, indem du `--release` am Ende des Befehls anhängst. Das daraus entstehende Programm kannst du im “target” Ordner auf deinem System finden. Du kannst es mit folgenden Befehlen ausführen:
```sh
target/debug/rustdesk
@@ -138,7 +138,7 @@ Oder, wenn du eine Releaseversion benutzt:
target/release/rustdesk
```
Bitte gehe sicher, dass du diese Befehle vom Stammverzeichnis vom RustDesk Repository nutzt, sonst kann es passieren, dass das Programm die Ressourcen nicht finden kann. Bitte bedenke auch, dass Unterbefehle von Cargo, wie z.B. `install` oder `run` aktuell noch nicht unterstützt werden, da sie das Programm innerhalb des Containers starten oder installieren würden, anstatt auf deinem eigentlichen System.
Bitte gehe sicher, dass du diese Befehle vom Stammverzeichnis vom RustDesk Repository nutzt, sonst kann es passieren, dass das Programm die Ressourcen nicht finden kann. Bitte bedenke auch, dass Unterbefehle von Cargo, wie z. B. `install` oder `run` aktuell noch nicht unterstützt werden, da sie das Programm innerhalb des Containers starten oder installieren würden, anstatt auf deinem eigentlichen System.
## Dateistruktur

161
README-EO.md Normal file
View File

@@ -0,0 +1,161 @@
<p align="center">
<img src="logo-header.svg" alt="RustDesk - Your remote desktop"><br>
<a href="#senpagaj-publikaj-serviloj">Serviloj</a> •
<a href="#paŝoj-por-kompili">Kompili</a> •
<a href="#kiel-kompili-kun-docker">Docker</a> •
<a href="#dosierstrukturo">Strukturo</a> •
<a href="#ekrankopio">Ekrankopio</a><br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
<b>Ni bezonas helpon traduki tiun README kaj <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">la interfacon</a> al via denaska lingvo</b>
</p>
Babili kun ni: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
Denove alia fora labortabla programo, skribita en Rust. Ĝi funkcias elskatole, ne bezonas konfiguraĵon. Vi havas la tutan kontrolon sur viaj datumoj, sen zorgo pri sekureco. Vi povas uzi nian servilon rendezvous/relajsan, [agordi vian propran](https://rustdesk.com/server), aŭ [skribi vian propran servilon rendezvous/relajsan](https://github.com/rustdesk/rustdesk-server-demo).
RustDesk bonvenigas kontribuon de ĉiuj. Vidu [`CONTRIBUTING.md`](CONTRIBUTING.md) por helpo komenci.
[**BINARA ELŜUTO**](https://github.com/rustdesk/rustdesk/releases)
## Senpagaj publikaj serviloj
Malsupre estas la serviloj, kiuj vi uzas senpage, ĝi povas ŝanĝi laŭlonge de la tempo. Se vi ne estas proksima de unu de tiuj, via reto povas esti malrapida.
| Situo | Vendanto | Detaloj |
| --------- | ------------- | ------------------ |
| Seulo | AWS lightsail | 1 VCPU / 0.5GB RAM |
| Singapuro | Vultr | 1 VCPU / 1GB RAM |
| Dalaso | Vultr | 1 VCPU / 1GB RAM | |
## Dependantaĵoj
La labortabla versio uzas [sciter](https://sciter.com/) por la interfaco, bonvolu elŝuti la bibliotekon dinamikan sciter.
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
## Paŝoj por kompili
- Preparu vian medion de programado Rust kaj vian medion de kompilado C++
- Instalu [vcpkg](https://github.com/microsoft/vcpkg), kaj agordu la medivariablon `VCPKG_ROOT` korekte
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
- Linux/MacOS: vcpkg install libvpx libyuv opus
- Plenumu `cargo run`
## Kiel kompili sur Linukso
### Ubuntu 18 (Debian 10)
```sh
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
```
### Fedora 28 (CentOS 8)
```sh
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
```
### Arch (Manjaro)
```sh
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
```
### Instali vcpkg
```sh
git clone https://github.com/microsoft/vcpkg
cd vcpkg
git checkout 2021.12.01
cd ..
vcpkg/bootstrap-vcpkg.sh
export VCPKG_ROOT=$HOME/vcpkg
vcpkg/vcpkg install libvpx libyuv opus
```
### Ripari libvpx (Por Fedora)
```sh
cd vcpkg/buildtrees/libvpx/src
cd *
./configure
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
make
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
cd
```
### Kompili
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
mkdir -p target/debug
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
mv libsciter-gtk.so target/debug
VCPKG_ROOT=$HOME/vcpkg cargo run
```
### Ŝanĝi Wayland por X11 (Xorg)
RustDesk ne subtenas Wayland. Kontrolu [tion](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) por agordi Xorg kiel defaŭlta sesio GNOME.
## Kiel kompili kun Docker
Komencu klonante la deponejon kaj kompilu la konteneron Docker:
```sh
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
docker build -t "rustdesk-builder" .
```
Tiam, ĉiuj fojoj, kiuj vi bezonas kompili la programon, plenumu tiun komandon:
```sh
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
```
Notu, ke la unua kompilado povas daŭri longe, antaŭ ke la dependantaĵoj estu kaŝitaj, sekvaj kompiladoj estos pli rapidaj. Aldone, se vi bezonas specifi diferentajn argumentojn por la kompilkomando, vi povas fari ĝin en la fine de la komando, en la posicio `<OPTIONAL-ARGS>`. Ekzemple, se vi volas kompili version de eldono optimigita, vi plenumus la komandon supre, kun `---release`. La plenumebla dosiero disponeblos en la cela dosierujo sur via sistemo, kaj povos esti plenumita kun:
```sh
target/debug/rustdesk
```
Aŭ, se vi plenumas eldonan plenumeblan dosieron:
```sh
target/release/rustdesk
```
Bonvolu certigi, ke vi plenumas tiujn komandojn el la radiko de la deponejo RustDesk, alie la programo povus esti nekapabla de trovi la devigajn resursojn. Ankaŭ notu, ke la aliaj subkomandoj de cargo kiel `install``run` momente ne estas subtenitaj per tiu metodo, ĉar instalus aŭ plenumus la programon en la kontenero anstataŭ de la gastiganto.
## Dosierstrukturo
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: videa kodeko, agordado, kovrilo tcp/udp, protobuf, funkcioj fs por dosiertransigo, kaj aliaj utilaĵaj funkcioj
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: ekrankaptado
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: operaciumspecifa kontrolo de klavaro/muso
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: interfaco
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: aŭdio/poŝo/enigo/videa servoj, kaj retkonektoj
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: starti konekto kun samtavolo
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: komuniki kun [rustdesk-server](https://github.com/rustdesk/rustdesk-server), atendi foran direktan (TCP hole punching) aŭ relajsatan konekton
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: operaciumspecifa kodo
## Ekrankopio
![image](https://user-images.githubusercontent.com/71636191/113112362-ae4deb80-923b-11eb-957d-ff88daad4f06.png)
![image](https://user-images.githubusercontent.com/71636191/113112619-f705a480-923b-11eb-911d-97e984ef52b6.png)
![image](https://user-images.githubusercontent.com/71636191/113112857-3fbd5d80-923c-11eb-9836-768325faf906.png)
![image](https://user-images.githubusercontent.com/71636191/135385039-38fdbd72-379a-422d-b97f-33df71fb1cec.png)

View File

@@ -5,7 +5,7 @@
<a href="#como-compilar-con-docker">Docker</a> •
<a href="#estructura-de-archivos">Estructura</a> •
<a href="#captura-de-pantalla">Captura de pantalla</a><br>
[<a href="README.md">English</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PT.md">Português</a>]<br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
<b>Necesitamos tu ayuda para traducir este README a tu idioma</b>
</p>
@@ -13,7 +13,7 @@ Chat with us: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.re
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
Otro software de escritorio remoto, escrito en Rust. Funciona de forma inmediata, sin necesidad de configuración. Tienes el control total de sus datos, sin preocupaciones sobre la seguridad. Puedes utilizar nuestro servidor de rendezvous/relay, [set up your own](https://rustdesk.com/blog/id-relay-set/), o [escribir tu propio servidor rendezvous/relay](https://github.com/rustdesk/rustdesk-server-demo).
Otro software de escritorio remoto, escrito en Rust. Funciona de forma inmediata, sin necesidad de configuración. Tienes el control total de sus datos, sin preocupaciones sobre la seguridad. Puedes utilizar nuestro servidor de rendezvous/relay, [set up your own](https://rustdesk.com/server), o [escribir tu propio servidor rendezvous/relay](https://github.com/rustdesk/rustdesk-server-demo).
RustDesk agradece la contribución de todo el mundo. Ve [`CONTRIBUTING.md`](CONTRIBUTING.md) para ayuda inicial.

View File

@@ -5,7 +5,7 @@
<a href="#how-to-build-with-docker">Docker</a> •
<a href="#file-structure">Rakenne</a> •
<a href="#snapshot">Tilannevedos</a><br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PT.md">Português</a>] | [<a href="README-FI.md">Suomi</a>]<br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
<b>Tarvitsemme apua tämän README-tiedoston kääntämiseksi äidinkielellesi</b>
</p>
@@ -13,7 +13,7 @@ Juttele meidän kanssa: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](http
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
Vielä yksi etätyöpöytäohjelmisto, ohjelmoitu Rust-kielellä. Toimii suoraan pakkauksesta, ei tarvitse asetuksia. Hallitset täysin tietojasi, ei tarvitse murehtia turvallisuutta. Voit käyttää meidän rendezvous/relay-palvelinta, [aseta omasi](https://rustdesk.com/blog/id-relay-set/), tai [kirjoita oma rendezvous/relay-palvelin](https://github.com/rustdesk/rustdesk-server-demo).
Vielä yksi etätyöpöytäohjelmisto, ohjelmoitu Rust-kielellä. Toimii suoraan pakkauksesta, ei tarvitse asetuksia. Hallitset täysin tietojasi, ei tarvitse murehtia turvallisuutta. Voit käyttää meidän rendezvous/relay-palvelinta, [aseta omasi](https://rustdesk.com/server), tai [kirjoita oma rendezvous/relay-palvelin](https://github.com/rustdesk/rustdesk-server-demo).
RustDesk toivottaa avustukset tervetulleiksi kaikilta. Katso lisätietoja [`CONTRIBUTING.md`](CONTRIBUTING.md) avun saamiseksi.
@@ -125,7 +125,7 @@ Sitten, joka kerta kun sinun on rakennettava sovellus, aja seuraava komento:
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
```
Huomaa, että ensimmäinen rakentaminen saattaa kestää pitempään ennen kuin riippuvuudet on siirretty välimuistiin, seuraavat rakentamiset ovat nopeampia. Lisäksi, jos sinun on määritettävä eri argumentteja rakentamiskomennolle, saatat tehdä sen niin, että komennon lopussa <OPTIONAL-ARGS>`-kohdassa. Esimerkiksi, jos haluat rakentaa optimoidun julkaisuversion, sinun on ajettava komento yllä siten, että sitä seuraa argumentti `---release`. Suoritettava tiedosto on saatavilla järjestelmäsi kohdehakemistossa, ja se voidaan suorittaa seuraavan kera:
Huomaa, että ensimmäinen rakentaminen saattaa kestää pitempään ennen kuin riippuvuudet on siirretty välimuistiin, seuraavat rakentamiset ovat nopeampia. Lisäksi, jos sinun on määritettävä eri argumentteja rakentamiskomennolle, saatat tehdä sen niin, että komennon lopussa <OPTIONAL-ARGS>`-kohdassa. Esimerkiksi, jos haluat rakentaa optimoidun julkaisuversion, sinun on ajettava komento yllä siten, että sitä seuraa argumentti`---release`. Suoritettava tiedosto on saatavilla järjestelmäsi kohdehakemistossa, ja se voidaan suorittaa seuraavan kera:
```sh
target/debug/rustdesk

View File

@@ -5,7 +5,7 @@
<a href="#comment-construire-avec-docker">Docker</a> -
<a href="#structure-du-projet">Structure</a> -
<a href="#images">Images</a><br>
[<a href="README.md">English</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-ES.md">Española</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PT.md">Português</a>]<br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
<b>Nous avons besoin de votre aide pour traduire ce README dans votre langue maternelle</b>.
</p>
@@ -13,7 +13,7 @@ Chattez avec nous : [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
Encore un autre logiciel de bureau à distance, écrit en Rust. Fonctionne directement, aucune configuration n'est nécessaire. Vous avez le contrôle total de vos données, sans aucun souci de sécurité. Vous pouvez utiliser notre serveur de rendez-vous/relais, [configurer le vôtre](https://rustdesk.com/blog/id-relay-set/), ou [écrire votre propre serveur de rendez-vous/relais](https://github.com/rustdesk/rustdesk-server-demo).
Encore un autre logiciel de bureau à distance, écrit en Rust. Fonctionne directement, aucune configuration n'est nécessaire. Vous avez le contrôle total de vos données, sans aucun souci de sécurité. Vous pouvez utiliser notre serveur de rendez-vous/relais, [configurer le vôtre](https://rustdesk.com/server), ou [écrire votre propre serveur de rendez-vous/relais](https://github.com/rustdesk/rustdesk-server-demo).
RustDesk accueille les contributions de tout le monde. Voir [`CONTRIBUTING.md`](CONTRIBUTING.md) pour plus d'informations.
@@ -118,13 +118,13 @@ cd rustdesk
docker build -t "rustdesk-builder" .
```
Ensuite, chaque fois que vous devez build le logiciel, exécutez la commande suivante :
Ensuite, chaque fois que vous devez compiler le logiciel, exécutez la commande suivante :
```sh
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
```
Notez que le premier build peut prendre plus de temps avant que les dépendances ne soient mises en cache, les constructions suivantes seront plus rapides. De plus, si vous devez spécifier différents arguments à la commande de compilation, vous pouvez le faire à la fin de la commande dans la position `<OPTIONAL-ARGS>`. Par exemple, si vous voulez construire une version optimisée de la version release, vous devez exécuter la commande ci-dessus suivie de `---release`. L'exécutable résultant sera disponible dans le dossier cible sur votre système, et peut être lancé avec :
Notez que la première compilation peut prendre plus de temps avant que les dépendances ne soient mises en cache, les compilations suivantes seront plus rapides. De plus, si vous devez spécifier différents arguments à la commande de compilation, vous pouvez le faire à la fin de la commande à la position `<OPTIONAL-ARGS>`. Par exemple, si vous voulez compiler une version de release optimisée, vous devez exécuter la commande ci-dessus suivie de `---release`. L'exécutable résultant sera disponible dans le dossier cible sur votre système, et peut être lancé avec :
```sh
target/debug/rustdesk
@@ -136,14 +136,14 @@ Ou, si vous exécutez un exécutable provenant d'une release :
target/release/rustdesk
```
Veuillez vous assurer que vous exécutez ces commandes à partir de la racine du référentiel RustDesk, sinon l'application ne pourra pas trouver les ressources requises. Notez également que les autres sous-commandes de cargo telles que `install` ou `run` ne sont pas actuellement supportées par cette méthode car elles installeraient ou exécuteraient le programme à l'intérieur du conteneur au lieu de l'hôte.
Veuillez vous assurer que vous exécutez ces commandes à partir de la racine du dépôt RustDesk, sinon l'application ne pourra pas trouver les ressources requises. Notez également que les autres sous-commandes de cargo telles que `install` ou `run` ne sont pas actuellement supportées par cette méthode car elles installeraient ou exécuteraient le programme à l'intérieur du conteneur au lieu de l'hôte.
## Structure du projet
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)** : codec vidéo, config, wrapper tcp/udp, protobuf, fonctions fs pour le transfert de fichiers, et quelques autres fonctions utilitaires.
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)** : capture d'écran
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)** : contrôle clavier/souris spécifique à la plate-forme
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)** : INTERFACE GRAPHIQUE
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)** : interface graphique
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)** : services audio/clipboard/input/vidéo, et connexions réseau
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)** : démarrer une connexion entre pairs
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)** : Communiquer avec [rustdesk-server](https://github.com/rustdesk/rustdesk-server), attendre une connexion distante directe (TCP hole punching) ou relayée.

161
README-IT.md Normal file
View File

@@ -0,0 +1,161 @@
<p align="center">
<img src="logo-header.svg" alt="RustDesk - Your remote desktop"><br>
<a href="#server-pubblici-gratuiti">Servers</a> •
<a href="#passaggi-per-la-compilazione">Compilazione</a> •
<a href="#come-compilare-con-docker">Docker</a> •
<a href="#struttura-dei-file">Struttura</a> •
<a href="#screenshots">Screenshots</a><br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
<b>Abbiamo bisogno del tuo aiuto per tradurre questo README e la <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> nella tua lingua nativa</b>
</p>
Chatta con noi: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
Ancora un altro software per il controllo remoto del desktop, scritto in Rust. Funziona immediatamente, nessuna configurazione richiesta. Hai il pieno controllo dei tuoi dati, senza preoccupazioni per la sicurezza. Puoi utilizzare il nostro server rendezvous/relay, [configurare il tuo](https://rustdesk.com/server) o [scrivere il tuo rendezvous/relay server](https://github.com/rustdesk/rustdesk-server-demo).
RustDesk accoglie il contributo di tutti. Per ulteriori informazioni su come inizare a contribuire, vedere [`CONTRIBUTING.md`](CONTRIBUTING.md).
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
## Server pubblici gratuiti
Qui sotto trovate i server che possono essere usati gratuitamente, la lista potrebbe cambiare nel tempo. Se non si è vicini a uno di questi server, la vostra connessione potrebbe essere lenta.
| Posizione | Vendor | Specifiche |
| --------- | ------------- | ------------------ |
| Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM |
| Singapore | Vultr | 1 VCPU / 1GB RAM |
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
## Dipendenze
La versione Desktop utilizza [sciter](https://sciter.com/) per la GUI, per favore scarica sciter dynamic library.
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
## Passaggi per la compilazione
- Prepara l'ambiente per lo sviluppo e compilazione in Rust e C++
- Installa [vcpkg](https://github.com/microsoft/vcpkg), e imposta correttamente la variabile d'ambiente `VCPKG_ROOT`
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
- Linux/MacOS: vcpkg install libvpx libyuv opus
- Esegui `cargo run`
## Come compilare su Linux
### Ubuntu 18 (Debian 10)
```sh
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
```
### Fedora 28 (CentOS 8)
```sh
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
```
### Arch (Manjaro)
```sh
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
```
### Installare vcpkg
```sh
git clone https://github.com/microsoft/vcpkg
cd vcpkg
git checkout 2021.12.01
cd ..
vcpkg/bootstrap-vcpkg.sh
export VCPKG_ROOT=$HOME/vcpkg
vcpkg/vcpkg install libvpx libyuv opus
```
### Fix libvpx (Per Fedora)
```sh
cd vcpkg/buildtrees/libvpx/src
cd *
./configure
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
make
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
cd
```
### Compilazione
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
mkdir -p target/debug
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
mv libsciter-gtk.so target/debug
VCPKG_ROOT=$HOME/vcpkg cargo run
```
### Cambiare Wayland a X11 (Xorg)
RustDesk non supporta Wayland. Controlla [questo](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) per configurare Xorg come sessione di default di GNOME.
## Come compilare con Docker
Cominciare clonando il repository e compilare i container docker:
```sh
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
docker build -t "rustdesk-builder" .
```
Quindi, ogni volta che devi compilare l'applicazione, esegui il comando seguente:
```sh
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
```
Tieni presente che la prima build potrebbe richiedere più tempo prima che le dipendenze vengano memorizzate nella cache, le build successive saranno più veloci. Inoltre, se hai bisogno di specificare argomenti diversi per il comando build, puoi farlo alla fine del comando nella posizione `<OPTIONAL-ARGS>`. Ad esempio, se si desidera creare una versione di rilascio ottimizzata, eseguire il comando sopra seguito da `---release`. L'eseguibile generato sarà creato nella cartella di destinazione del proprio sistema e può essere eseguito con:
```sh
target/debug/rustdesk
```
Oppure, se si sta eseguendo un eseguibile di rilascio:
```sh
target/release/rustdesk
```
Assicurati di eseguire questi comandi dalla radice del repository RustDesk, altrimenti l'applicazione potrebbe non essere in grado di trovare le risorse richieste. Notare inoltre che altri sottocomandi cargo come `install` o `run` non sono attualmente supportati tramite questo metodo poiché installerebbero o eseguirebbero il programma all'interno del container anziché nell'host.
## Struttura dei file
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, config, tcp/udp wrapper, protobuf, fs funzioni per il trasferimento file, e altre funzioni utili.
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: cattura dello schermo
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: controllo tastiera/mouse specifico della piattaforma
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: servizi audio/appunti/input/video e connessioni di rete
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: avviare una connessione peer
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Comunica con [rustdesk-server](https://github.com/rustdesk/rustdesk-server), attende la connessione remota diretta (TCP hole punching) oppure indiretta (relayed)
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: codice specifico della piattaforma
## Screenshots
![image](https://user-images.githubusercontent.com/71636191/113112362-ae4deb80-923b-11eb-957d-ff88daad4f06.png)
![image](https://user-images.githubusercontent.com/71636191/113112619-f705a480-923b-11eb-911d-97e984ef52b6.png)
![image](https://user-images.githubusercontent.com/71636191/113112857-3fbd5d80-923c-11eb-9836-768325faf906.png)
![image](https://user-images.githubusercontent.com/71636191/135385039-38fdbd72-379a-422d-b97f-33df71fb1cec.png)

View File

@@ -5,7 +5,7 @@
<a href="#how-to-build-with-docker">Docker</a> •
<a href="#file-structure">Structure</a> •
<a href="#snapshot">Snapshot</a><br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PT.md">Português</a>]<br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
<b>このREADMEをあなたの母国語に翻訳するために、あなたの助けが必要です。</b>
</p>
@@ -13,7 +13,7 @@ Chat with us: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.re
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
Rustで書かれた、設定不要ですぐに使えるリモートデスクトップソフトウェアです。自分のデータを完全にコントロールでき、セキュリティの心配もありません。私たちのランデブー/リレーサーバを使うことも、[自分で設定する](https://rustdesk.com/blog/id-relay-set/) ことも、 [自分でランデブー/リレーサーバを書くこともできます。](https://github.com/rustdesk/rustdesk-server-demo).
Rustで書かれた、設定不要ですぐに使えるリモートデスクトップソフトウェアです。自分のデータを完全にコントロールでき、セキュリティの心配もありません。私たちのランデブー/リレーサーバを使うことも、[自分で設定する](https://rustdesk.com/server) ことも、 [自分でランデブー/リレーサーバを書くこともできます。](https://github.com/rustdesk/rustdesk-server-demo).
RustDeskは誰からの貢献も歓迎します。 貢献するには [`CONTRIBUTING.md`](CONTRIBUTING.md) を参照してください。
@@ -114,7 +114,6 @@ RustDeskはWaylandをサポートしていません。
リポジトリのクローンを作成し、Dockerコンテナを構築することから始めます。
```sh
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
@@ -127,7 +126,7 @@ docker build -t "rustdesk-builder" .
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
```
なお、最初のビルドでは、依存関係がキャッシュされるまで時間がかかることがありますが、その後のビルドではより速くなります。さらに、ビルドコマンドに別の引数を指定する必要がある場合は、コマンドの最後にある `<OPTIONAL-ARGS>` の位置で指定することができます。例えば、最適化されたリリースバージョンをビルドしたい場合は、上記のコマンドの後に
なお、最初のビルドでは、依存関係がキャッシュされるまで時間がかかることがありますが、その後のビルドではより速くなります。さらに、ビルドコマンドに別の引数を指定する必要がある場合は、コマンドの最後にある `<OPTIONAL-ARGS>` の位置で指定することができます。例えば、最適化されたリリースバージョンをビルドしたい場合は、上記のコマンドの後に
`---release` を実行します。できあがった実行ファイルは、システムのターゲット・フォルダに格納され、次のコマンドで実行できます。
```sh

View File

@@ -5,7 +5,7 @@
<a href="#how-to-build-with-docker">Docker</a> •
<a href="#file-structure">Structure</a> •
<a href="#snapshot">Snapshot</a><br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PT.md">Português</a>]<br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
<b>ഈ README നിങ്ങളുടെ മാതൃഭാഷയിലേക്ക് വിവർത്തനം ചെയ്യാൻ ഞങ്ങൾക്ക് നിങ്ങളുടെ സഹായം ആവശ്യമാണ്</b>
</p>
@@ -13,7 +13,7 @@
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
റസ്റ്റിൽ എഴുതിയ മറ്റൊരു റിമോട്ട് ഡെസ്ക്ടോപ്പ് സോഫ്റ്റ്‌വെയർ. ബോക്‌സിന് പുറത്ത് പ്രവർത്തിക്കുന്നു, കോൺഫിഗറേഷൻ ആവശ്യമില്ല. സുരക്ഷയെക്കുറിച്ച് ആശങ്കകളൊന്നുമില്ലാതെ, നിങ്ങളുടെ ഡാറ്റയുടെ പൂർണ്ണ നിയന്ത്രണം നിങ്ങൾക്കുണ്ട്. നിങ്ങൾക്ക് ഞങ്ങളുടെ rendezvous/relay സെർവർ ഉപയോഗിക്കാം, [സ്വന്തമായി സജ്ജീകരിക്കുക](https://rustdesk.com/blog/id-relay-set/), അല്ലെങ്കിൽ [നിങ്ങളുടെ സ്വന്തം rendezvous/relay സെർവർ എഴുതുക](https://github.com/rustdesk/rustdesk-server-demo).
റസ്റ്റിൽ എഴുതിയ മറ്റൊരു റിമോട്ട് ഡെസ്ക്ടോപ്പ് സോഫ്റ്റ്‌വെയർ. ബോക്‌സിന് പുറത്ത് പ്രവർത്തിക്കുന്നു, കോൺഫിഗറേഷൻ ആവശ്യമില്ല. സുരക്ഷയെക്കുറിച്ച് ആശങ്കകളൊന്നുമില്ലാതെ, നിങ്ങളുടെ ഡാറ്റയുടെ പൂർണ്ണ നിയന്ത്രണം നിങ്ങൾക്കുണ്ട്. നിങ്ങൾക്ക് ഞങ്ങളുടെ rendezvous/relay സെർവർ ഉപയോഗിക്കാം, [സ്വന്തമായി സജ്ജീകരിക്കുക](https://rustdesk.com/server), അല്ലെങ്കിൽ [നിങ്ങളുടെ സ്വന്തം rendezvous/relay സെർവർ എഴുതുക](https://github.com/rustdesk/rustdesk-server-demo).
എല്ലാവരുടെയും സംഭാവനയെ RustDesk സ്വാഗതം ചെയ്യുന്നു. ആരംഭിക്കുന്നതിനുള്ള സഹായത്തിന് [`CONTRIBUTING.md`](CONTRIBUTING.md) കാണുക.
@@ -28,7 +28,7 @@
| Singapore | Vultr | 1 VCPU / 1GB RAM |
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
## ഡിപെൻഡൻസികൾ
## ഡിപെൻഡൻസികൾ
ഡെസ്‌ക്‌ടോപ്പ് പതിപ്പുകൾ GUI-യ്‌ക്കായി [sciter](https://sciter.com/) ഉപയോഗിക്കുന്നു, ദയവായി സ്‌സൈറ്റർ ഡൈനാമിക് ലൈബ്രറി സ്വയം ഡൗൺലോഡ് ചെയ്യുക.
@@ -92,7 +92,7 @@ cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
cd
```
### നിർമാണം
### നിർമാണം
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

View File

@@ -5,7 +5,7 @@
<a href="#how-to-build-with-docker">Docker</a> •
<a href="#file-structure">Structuur</a> •
<a href="#snapshot">Snapshot</a><br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PT.md">Português</a>]<br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
<b>We hebben je hulp nodig om deze README te vertalen naar jouw moedertaal</b>
</p>
@@ -28,7 +28,7 @@ Onderstaande servers zijn de servers die je gratis kunt gebruiken, ze kunnen op
| Singapore | Vultr | 1 VCPU / 1GB RAM |
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
## Afhankelijkheden
## Afhankelijkheden
Desktopversies gebruiken [sciter](https://sciter.com/) voor de grafische schil. Gelieve zelf de sciter-library te downloaden.
@@ -141,7 +141,7 @@ target/release/rustdesk
Zorg ervoor dat je deze commando's van de root van de RustDesk-repository uitvoert, anders kan het programma de nodige afhankelijkheden mogelijk niet vinden. Let ook op dat andere cargo-subcommando's zoals `install` en `run` zijn momenteel niet ondersteund, aangezien deze zouden worden uitgevoerd in een container in plaats van op de host.
## Bestandsstructuur
## Bestandsstructuur
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: videocodec, configuratie, TCP/UDP-wrapper, protobuf, bestandssysteemfuncties voor bestandsoverdracht en nog wat andere nuttige functies
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: schermopname

View File

@@ -5,7 +5,7 @@
<a href="#jak-kompilować-za-pomocą-dockera">Docker</a> •
<a href="#struktura-plików">Struktura</a> •
<a href="#migawkisnapshoty">Snapshot</a><br>
[<a href="README.md">English</a>] | [<a href="README-ZH.md">中文</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-ES.md">Española</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PT.md">Português</a>]<br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
<b>Potrzebujemy twojej pomocy w tłumaczeniu README na twój ojczysty język</b>
</p>
@@ -13,7 +13,7 @@ Porozmawiaj z nami na: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
Kolejny program do zdalnego pulpitu, napisany w Rust. Działa od samego początku, nie wymaga konfiguracji. Masz pełną kontrolę nad swoimi danymi, bez obaw o bezpieczeństwo. Możesz skorzystać z naszego darmowego serwera publicznego , [skonfigurować własny](https://rustdesk.com/blog/id-relay-set/), lub [napisać własny serwer rendezvous/relay server](https://github.com/rustdesk/rustdesk-server-demo).
Kolejny program do zdalnego pulpitu, napisany w Rust. Działa od samego początku, nie wymaga konfiguracji. Masz pełną kontrolę nad swoimi danymi, bez obaw o bezpieczeństwo. Możesz skorzystać z naszego darmowego serwera publicznego , [skonfigurować własny](https://rustdesk.com/server), lub [napisać własny serwer rendezvous/relay server](https://github.com/rustdesk/rustdesk-server-demo).
RustDesk zaprasza do współpracy każdego. Zobacz [`CONTRIBUTING.md`](CONTRIBUTING.md) pomoc w uruchomieniu programu.
@@ -36,7 +36,7 @@ Wersje desktopowe używają [sciter](https://sciter.com/) dla GUI, proszę pobra
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
## Podstawowe kroki do kompilacji.
## Podstawowe kroki do kompilacji
- Przygotuj środowisko programistyczne Rust i środowisko programowania C++

162
README-PTBR.md Normal file
View File

@@ -0,0 +1,162 @@
<p align="center">
<img src="logo-header.svg" alt="RustDesk - Seu desktop remoto"><br>
<a href="#servidores-públicos-grátis">Servidores</a> •
<a href="#compilação-crua">Compilar</a> •
<a href="#como-compilar-com-docker">Docker</a> •
<a href="#estrutura-de-arquivos">Estrutura</a> •
<a href="#screenshots">Screenshots</a><br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
<b>Precisamos de sua ajuda para traduzir este README e a <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">UI do RustDesk</a> para sua língua nativa</b>
</p>
Converse conosco: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
Mais um software de desktop remoto, escrito em Rust. Funciona por padrão, sem necessidade de configuração. Você tem completo controle de seus dados, sem se preocupar com segurança. Você pode usar nossos servidores de rendezvous/relay, [configurar seu próprio](https://rustdesk.com/server), ou [escrever seu próprio servidor de rendezvous/relay](https://github.com/rustdesk/rustdesk-server-demo).
RustDesk acolhe contribuições de todos. Leia [`CONTRIBUTING.md`](CONTRIBUTING.md) para ver como começar.
[**DOWNLOAD DE BINÁRIOS**](https://github.com/rustdesk/rustdesk/releases)
## Servidores Públicos Grátis
Abaixo estão os servidores que você está utilizando de graça, ele pode mudar com o tempo. Se você não está próximo de algum deles, sua conexão pode ser lenta.
| Localização | Fornecedor | Especificações |
| ----------- | ------------- | ------------------ |
| Seul | AWS lightsail | 1 VCPU / 0.5GB RAM |
| Singapura | Vultr | 1 VCPU / 1GB RAM |
| Dallas | Vultr | 1 VCPU / 1GB RAM |
## Dependências
Versões de desktop utilizam [sciter](https://sciter.com/) para a GUI, por favor baixe a biblioteca dinâmica sciter por conta própria.
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
## Compilação crua
- Prepare seu ambiente de desenvolvimento Rust e ambiente de compilação C++
- Instale [vcpkg](https://github.com/microsoft/vcpkg), e configure a variável de ambiente `VCPKG_ROOT` corretamente
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
- Linux/MacOS: vcpkg install libvpx libyuv opus
- Execute `cargo run`
## Como compilar no Linux
### Ubuntu 18 (Debian 10)
```sh
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
```
### Fedora 28 (CentOS 8)
```sh
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
```
### Arch (Manjaro)
```sh
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
```
### Instale vcpkg
```sh
git clone https://github.com/microsoft/vcpkg
cd vcpkg
git checkout 2021.12.01
cd ..
vcpkg/bootstrap-vcpkg.sh
export VCPKG_ROOT=$HOME/vcpkg
vcpkg/vcpkg install libvpx libyuv opus
```
### Conserte libvpx (Para o Fedora)
```sh
cd vcpkg/buildtrees/libvpx/src
cd *
./configure
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
make
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
cd
```
### Compile
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
mkdir -p target/debug
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
mv libsciter-gtk.so target/debug
VCPKG_ROOT=$HOME/vcpkg cargo run
```
### Mude Wayland para X11 (Xorg)
RustDesk não suporta Wayland. Veja [esse link](https://docs.fedoraproject.org/pt_BR/quick-docs/configuring-xorg-as-default-gnome-session/) para configurar o Xorg como a sessão padrão do GNOME.
## Como compilar com Docker
Comece clonando o repositório e montando o container docker:
```sh
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
docker build -t "rustdesk-builder" .
```
Então, sempre que precisar compilar a aplicação, execute este comando:
```sh
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
```
Note que a primeira compilação pode demorar mais antes que as dependências sejam armazenadas em cache, as compilações subsequentes serão mais rápidas. Adicionalmente, se você precisar especificar argumentos diferentes para o comando de compilação, você pode fazê-lo ao final do comando na posição do `<OPTIONAL-ARGS>`. Por exemplo, se você gostaria de compilar uma versão de release otimizada, você executaria o comando acima seguido de `--release`. O executável gerado estará disponível no diretório alvo no seu sistema, e pode ser executado com:
```sh
target/debug/rustdesk
```
Ou, se estiver rodando um executável de release:
```sh
target/release/rustdesk
```
Por favor verifique que está executando estes comandos da raiz do repositório do RustDesk, senão a aplicação pode não encontrar os recursos necessários. Note também que outros subcomandos do cargo como `install` ou `run` não são suportados atualmente via este método, já que eles iriam instalar ou rodar o programa dentro do container ao invés do host.
## Estrutura de arquivos
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: codec de vídeo, configurações, wrapper de tcp/udp, protobuf, funções de sistema de arquivos para transferência de arquivos, e outras funções utilitárias
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: captura de tela
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: controle de teclado/mouse específico a cada plataforma
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: serviços de áudio/área de transferência/entrada/vídeo, e conexões de rede
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: iniciar uma conexão "peer to peer"
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Comunicação com [rustdesk-server](https://github.com/rustdesk/rustdesk-server), aguardar pela conexão remota direta (TCP hole punching) ou conexão indireta (relayed)
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: código específico a cada plataforma
## Screenshots
![image](https://user-images.githubusercontent.com/71636191/113112362-ae4deb80-923b-11eb-957d-ff88daad4f06.png)
![image](https://user-images.githubusercontent.com/71636191/113112619-f705a480-923b-11eb-911d-97e984ef52b6.png)
![image](https://user-images.githubusercontent.com/71636191/113112857-3fbd5d80-923c-11eb-9836-768325faf906.png)
![image](https://user-images.githubusercontent.com/71636191/135385039-38fdbd72-379a-422d-b97f-33df71fb1cec.png)

161
README-RU.md Normal file
View File

@@ -0,0 +1,161 @@
<p align="center">
<img src="logo-header.svg" alt="RustDesk - Your remote desktop"><br>
<a href="#free-public-servers">Servers</a> •
<a href="#raw-steps-to-build">Build</a> •
<a href="#how-to-build-with-docker">Docker</a> •
<a href="#file-structure">Structure</a> •
<a href="#snapshot">Snapshot</a><br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
<b>Нам нужна ваша помощь для перевода этого README и <a href="https://github.com/rustdesk/rustdesk/tree/master/src/rustdesk/tree/master/src/lang">RustDesk UI</a> на ваш родной язык</B>
</p>
Общение с нами: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
Еще одно программное обеспечение для удаленного рабочего стола, написанное на Rust. Работает из коробки, не требует настройки. Вы полностью контролируете свои данные, не беспокоясь о безопасности. Вы можете использовать наш сервер ретрансляции, [настроить свой собственный](https://rustdesk.com/server), или [написать свой собственный сервер ретрансляции](https://github.com/rustdesk/rustdesk-server-demo).
RustDesk приветствует вклад каждого. Смотри [`CONTRIBUTING.md`](CONTRIBUTING.md) для помощи в начале работы.
[**СКАЧАТЬ ПРИЛОЖЕНИЕ**](https://github.com/rustdesk/rustdesk/releases)
## Бесплатные общедоступные серверы
Ниже приведены серверы, для бесплатного использования, они могут меняться со временем. Если вы не находитесь рядом с одним из них, ваша сеть может работать медленно.
| Местонахождение | Поставщик | Технические характеристики |
| --------- | ------------- | ------------------ |
| Сеул | AWS lightsail | 1 VCPU / 0.5GB RAM |
| Сингапур | Vultr | 1 VCPU / 1GB RAM |
| Даллас | Vultr | 1 VCPU / 1GB RAM | |
## Зависимости
Настольные версии используют [sciter](https://sciter.com/) для графического интерфейса, загрузите динамическую библиотеку sciter самостоятельно.
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[Linux](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so) |
[MacOS](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib)
## Необработанные шаги для сборки
- Подготовьте среду разработки Rust и среду сборки C++.
- Установите [vcpkg](https://github.com/microsoft/vcpkg), и правильно установите переменную `VCPKG_ROOT`
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
- Linux/MacOS: vcpkg install libvpx libyuv opus
- Запустите`cargo run`
## Как собрать в Linux
### Ubuntu 18 (Debian 10)
```sh
sudo apt install -y g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake
```
### Fedora 28 (CentOS 8)
```sh
sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel
```
### Arch (Manjaro)
```sh
sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-config clang gtk3 xdotool libxcb libxfixes alsa-lib pulseaudio
```
### Установка vcpkg
```sh
git clone https://github.com/microsoft/vcpkg
cd vcpkg
git checkout 2021.12.01
cd ..
vcpkg/bootstrap-vcpkg.sh
export VCPKG_ROOT=$HOME/vcpkg
vcpkg/vcpkg install libvpx libyuv opus
```
### Исправления libvpx (Для Fedora)
```sh
cd vcpkg/buildtrees/libvpx/src
cd *
./configure
sed -i 's/CFLAGS+=-I/CFLAGS+=-fPIC -I/g' Makefile
sed -i 's/CXXFLAGS+=-I/CXXFLAGS+=-fPIC -I/g' Makefile
make
cp libvpx.a $HOME/vcpkg/installed/x64-linux/lib/
cd
```
### Сборка
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
mkdir -p target/debug
wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
mv libsciter-gtk.so target/debug
VCPKG_ROOT=$HOME/vcpkg cargo run
```
### Смените Wayland на X11 (Xorg)
RustDesk не поддерживает Wayland. Смотрите [этот документ](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) для настройки Xorg в качестве сеанса GNOME по умолчанию.
## Как собрать используя Docker
Начните с клонирования репозитория и создания docker контейнера:
```sh
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
docker build -t "rustdesk-builder" .
```
Затем каждый раз, когда вам нужно собрать приложение, запустите следующую команду:
```sh
docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user/.cargo/git -v rustdesk-registry-cache:/home/user/.cargo/registry -e PUID="$(id -u)" -e PGID="$(id -g)" rustdesk-builder
```
Обратите внимание, что первая сборка может занять больше времени но последующие сборки будут выполняться быстрее. Кроме того, если вам нужно указать другие аргументы для команды сборки, вы можете сделать это в конце команды в переменной `<OPTIONAL-ARGS>`. Например, если вы хотите создать оптимизированную версию, вы должны запустить приведенную выше команду и в хвосте строки добавить `---release`. Полученный исполняемый файл будет доступен в целевой папке вашей системы и может быть запущен с помощью:
```sh
target/debug/rustdesk
```
Или, если вы используете исполняемый файл релиза:
```sh
target/release/rustdesk
```
Пожалуйста, убедитесь, что вы запускаете эти команды из корня репозитория RustDesk, иначе приложение не сможет найти необходимые ресурсы. Также обратите внимание, что другие cargo подкоманды, такие как `install` или `run`, в настоящее время не поддерживаются этим методом, поскольку они будут устанавливать или запускать программу внутри контейнера, а не на хосте.
## Структура файлов
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: видеокодек, конфиг, обертка tcp/udp, protobuf, функции fs для передачи файлов и некоторые другие служебные функции
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: захват экрана
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: специфичное для платформы управление клавиатурой/мышью
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: графический пользовательский интерфейс
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: сервисы аудио/буфера обмена/ввода/видео и сетевых подключений
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: одноранговое соединение
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: свяжитесь с [rustdesk-server](https://github.com/rustdesk/rustdesk-server), дождитесь удаленного прямого (обход TCP NAT) или ретранслируемого соединения
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: специфичный для платформы код
## Снимки
![image](https://user-images.githubusercontent.com/71636191/113112362-ae4deb80-923b-11eb-957d-ff88daad4f06.png)
![image](https://user-images.githubusercontent.com/71636191/113112619-f705a480-923b-11eb-911d-97e984ef52b6.png)
![image](https://user-images.githubusercontent.com/71636191/113112857-3fbd5d80-923c-11eb-9836-768325faf906.png)
![image](https://user-images.githubusercontent.com/71636191/135385039-38fdbd72-379a-422d-b97f-33df71fb1cec.png)

View File

@@ -5,7 +5,7 @@
<a href="#使用Docker编译">Docker</a> •
<a href="#文件结构">结构</a> •
<a href="#截图">截图</a><br>
[<a href="README.md">English</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PT.md">Português</a>]<br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
</p>
Chat with us: [知乎](https://www.zhihu.com/people/rustdesk) | [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk)
@@ -13,7 +13,7 @@ Chat with us: [知乎](https://www.zhihu.com/people/rustdesk) | [Discord](https:
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
远程桌面软件,开箱即用,无需任何配置。您完全掌控数据,不用担心安全问题。您可以使用我们的注册/中继服务器,
或者[自己设置](https://rustdesk.com/blog/id-relay-set/)
或者[自己设置](https://rustdesk.com/server)
亦或者[开发您的版本](https://github.com/rustdesk/rustdesk-server-demo)。
欢迎大家贡献代码, 请看 [`CONTRIBUTING.md`](CONTRIBUTING.md).
@@ -154,6 +154,7 @@ docker build -t "rustdesk-builder" .
```
4. docker build 命令后面加上 proxy 参数
```
docker build -t "rustdesk-builder" . --build-arg http_proxy=http://host:port --build-arg https_proxy=http://host:port
```

View File

@@ -5,7 +5,7 @@
<a href="#how-to-build-with-docker">Docker</a> •
<a href="#file-structure">Structure</a> •
<a href="#snapshot">Snapshot</a><br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PT.md">Português</a>]<br>
[<a href="README-ZH.md">中文</a>] | [<a href="README-ES.md">Español</a>] | [<a href="README-FR.md">Français</a>] | [<a href="README-DE.md">Deutsch</a>] | [<a href="README-PL.md">Polski</a>] | [<a href="README-FI.md">Suomi</a>] | [<a href="README-ML.md">മലയാളം</a>] | [<a href="README-JP.md">日本語</a>] | [<a href="README-NL.md">Nederlands</a>] | [<a href="README-IT.md">Italiano</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PTBR.md">Português (Brasil)</a>] | [<a href="README-EO.md">Esperanto</a>]<br>
<b>We need your help to translate this README and <a href="https://github.com/rustdesk/rustdesk/tree/master/src/lang">RustDesk UI</a> to your native language</b>
</p>
@@ -13,7 +13,7 @@ Chat with us: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.re
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
Yet another remote desktop software, written in Rust. Works out of the box, no configuration required. You have full control of your data, with no concerns about security. You can use our rendezvous/relay server, [set up your own](https://rustdesk.com/blog/id-relay-set/), or [write your own rendezvous/relay server](https://github.com/rustdesk/rustdesk-server-demo).
Yet another remote desktop software, written in Rust. Works out of the box, no configuration required. You have full control of your data, with no concerns about security. You can use our rendezvous/relay server, [set up your own](https://rustdesk.com/server), or [write your own rendezvous/relay server](https://github.com/rustdesk/rustdesk-server-demo).
RustDesk welcomes contribution from everyone. See [`CONTRIBUTING.md`](CONTRIBUTING.md) for help getting started.

112
build.py Normal file
View File

@@ -0,0 +1,112 @@
#!/usr/bin/env python3
import os
import platform
import zlib
from shutil import copy2
import hashlib
windows = platform.platform().startswith('Windows')
osx = platform.platform().startswith('Darwin') or platform.platform().startswith("macOS")
hbb_name = 'rustdesk' + ('.exe' if windows else '')
exe_path = 'target/release/' + hbb_name
def get_version():
with open("Cargo.toml") as fh:
for line in fh:
if line.startswith("version"):
return line.replace("version", "").replace("=", "").replace('"', '').strip()
return ''
def main():
os.system("cp Cargo.toml Cargo.toml.bk")
os.system("cp src/main.rs src/main.rs.bk")
if windows:
txt = open('src/main.rs', encoding='utf8').read()
with open('src/main.rs', 'wt', encoding='utf8') as fh:
fh.write(txt.replace(
'//#![windows_subsystem', '#![windows_subsystem'))
if os.path.exists(exe_path):
os.unlink(exe_path)
os.system('python3 inline-sciter.py')
if os.path.isfile('/usr/bin/pacman'):
os.system('git checkout src/ui/common.tis')
version = get_version()
if windows:
os.system('cargo build --release --features inline')
# os.system('upx.exe target/release/rustdesk.exe')
os.system('mv target/release/rustdesk.exe target/release/RustDesk.exe')
pa = os.environ.get('P')
if pa:
os.system('signtool sign /a /v /p %s /debug /f .\\cert.pfx /t http://timestamp.digicert.com target\\release\\rustdesk.exe'%pa)
else:
print('Not signed')
os.system('cp -rf target/release/RustDesk.exe rustdesk-%s-putes.exe'%version)
else:
os.system('cargo bundle --release --features inline')
if osx:
os.system(
'strip target/release/bundle/osx/RustDesk.app/Contents/MacOS/rustdesk')
os.system(
'cp libsciter.dylib target/release/bundle/osx/RustDesk.app/Contents/MacOS/')
# https://github.com/sindresorhus/create-dmg
os.system('/bin/rm -rf *.dmg')
plist = "target/release/bundle/osx/RustDesk.app/Contents/Info.plist"
txt = open(plist).read()
with open(plist, "wt") as fh:
fh.write(txt.replace("</dict>", """
<key>LSUIElement</key>
<string>1</string>
</dict>"""))
pa = os.environ.get('P')
if pa:
os.system('''
# buggy: rcodesign sign ... path/*, have to sign one by one
#rcodesign sign --p12-file ~/.p12/rustdesk-developer-id.p12 --p12-password-file ~/.p12/.cert-pass --code-signature-flags runtime ./target/release/bundle/osx/RustDesk.app/Contents/MacOS/rustdesk
#rcodesign sign --p12-file ~/.p12/rustdesk-developer-id.p12 --p12-password-file ~/.p12/.cert-pass --code-signature-flags runtime ./target/release/bundle/osx/RustDesk.app/Contents/MacOS/libsciter.dylib
#rcodesign sign --p12-file ~/.p12/rustdesk-developer-id.p12 --p12-password-file ~/.p12/.cert-pass --code-signature-flags runtime ./target/release/bundle/osx/RustDesk.app
# goto "Keychain Access" -> "My Certificates" for below id which starts with "Developer ID Application:"
codesign -s "Developer ID Application: {0}" --force --options runtime ./target/release/bundle/osx/RustDesk.app/Contents/MacOS/*
codesign -s "Developer ID Application: {0}" --force --options runtime ./target/release/bundle/osx/RustDesk.app
'''.format(pa))
os.system('create-dmg target/release/bundle/osx/RustDesk.app')
os.rename('RustDesk %s.dmg'%version, 'rustdesk-%s.dmg'%version)
if pa:
os.system('''
#rcodesign sign --p12-file ~/.p12/rustdesk-developer-id.p12 --p12-password-file ~/.p12/.cert-pass --code-signature-flags runtime ./rustdesk-{1}.dmg
codesign -s "Developer ID Application: {0}" --force --options runtime ./rustdesk-{1}.dmg
# https://pyoxidizer.readthedocs.io/en/latest/apple_codesign_rcodesign.html
rcodesign notarize --api-issuer 69a6de7d-2907-47e3-e053-5b8c7c11a4d1 --api-key 9JBRHG3JHT --staple ./rustdesk-{1}.dmg
# verify: spctl -a -t exec -v /Applications/RustDesk.app
'''.format(pa, version))
else:
print('Not signed')
else:
os.system('mv target/release/bundle/deb/rustdesk*.deb ./rustdesk.deb')
os.system('dpkg-deb -R rustdesk.deb tmpdeb')
os.system('mkdir -p tmpdeb/usr/share/rustdesk/files/systemd/')
os.system(
'cp rustdesk.service tmpdeb/usr/share/rustdesk/files/systemd/')
os.system('cp pynput_service.py tmpdeb/usr/share/rustdesk/files/')
os.system('cp DEBIAN/* tmpdeb/DEBIAN/')
os.system('strip tmpdeb/usr/bin/rustdesk')
os.system('mkdir -p tmpdeb/usr/lib/rustdesk')
os.system('cp libsciter-gtk.so tmpdeb/usr/lib/rustdesk/')
md5_file('usr/share/rustdesk/files/systemd/rustdesk.service')
md5_file('usr/share/rustdesk/files/pynput_service.py')
md5_file('usr/lib/rustdesk/libsciter-gtk.so')
os.system('dpkg-deb -b tmpdeb rustdesk.deb; /bin/rm -rf tmpdeb/')
os.rename('rustdesk.deb', 'rustdesk-%s.deb'%version)
os.system("mv Cargo.toml.bk Cargo.toml")
os.system("mv src/main.rs.bk src/main.rs")
def md5_file(fn):
md5 = hashlib.md5(open('tmpdeb/' + fn, 'rb').read()).hexdigest()
os.system('echo "%s %s" >> tmpdeb/DEBIAN/md5sums' % (md5, fn))
if __name__ == "__main__":
main()

81
inline-sciter.py Normal file
View File

@@ -0,0 +1,81 @@
#!/usr/bin/env python3
import re
def strip(s): return re.sub(r'\s+\n', '\n', re.sub(r'\n\s+', '\n', s))
common_css = open('src/ui/common.css').read()
common_tis = open('src/ui/common.tis', encoding='UTF8').read()
index = open('src/ui/index.html').read() \
.replace('@import url(index.css);', open('src/ui/index.css').read()) \
.replace('include "index.tis";', open('src/ui/index.tis').read()) \
.replace('include "msgbox.tis";', open('src/ui/msgbox.tis').read()) \
.replace('include "ab.tis";', open('src/ui/ab.tis').read())
remote = open('src/ui/remote.html').read() \
.replace('@import url(remote.css);', open('src/ui/remote.css').read()) \
.replace('@import url(header.css);', open('src/ui/header.css').read()) \
.replace('@import url(file_transfer.css);', open('src/ui/file_transfer.css').read()) \
.replace('include "remote.tis";', open('src/ui/remote.tis').read()) \
.replace('include "msgbox.tis";', open('src/ui/msgbox.tis').read()) \
.replace('include "grid.tis";', open('src/ui/grid.tis').read()) \
.replace('include "header.tis";', open('src/ui/header.tis').read()) \
.replace('include "file_transfer.tis";', open('src/ui/file_transfer.tis').read()) \
.replace('include "port_forward.tis";', open('src/ui/port_forward.tis').read())
chatbox = open('src/ui/chatbox.html').read()
install = open('src/ui/install.html').read().replace('include "install.tis";', open('src/ui/install.tis').read())
cm = open('src/ui/cm.html').read() \
.replace('@import url(cm.css);', open('src/ui/cm.css').read()) \
.replace('include "cm.tis";', open('src/ui/cm.tis').read())
def compress(s):
s = s.replace("\r\n", "\n")
x = bytes(s, encoding='utf-8')
return '&[u8; ' + str(len(x)) + '] = b"' + str(x)[2:-1].replace(r"\'", "'").replace(r'"',
r'\"') + '"'
with open('src/ui/inline.rs', 'wt') as fh:
fh.write('const _COMMON_CSS: ' + compress(strip(common_css)) + ';\n')
fh.write('const _COMMON_TIS: ' + compress(strip(common_tis)) + ';\n')
fh.write('const _INDEX: ' + compress(strip(index)) + ';\n')
fh.write('const _REMOTE: ' + compress(strip(remote)) + ';\n')
fh.write('const _CHATBOX: ' + compress(strip(chatbox)) + ';\n')
fh.write('const _INSTALL: ' + compress(strip(install)) + ';\n')
fh.write('const _CONNECTION_MANAGER: ' + compress(strip(cm)) + ';\n')
fh.write('''
fn get(data: &[u8]) -> String {
String::from_utf8_lossy(data).to_string()
}
fn replace(data: &[u8]) -> String {
let css = get(&_COMMON_CSS[..]);
let res = get(data).replace("@import url(common.css);", &css);
let tis = get(&_COMMON_TIS[..]);
res.replace("include \\\"common.tis\\\";", &tis)
}
#[inline]
pub fn get_index() -> String {
replace(&_INDEX[..])
}
#[inline]
pub fn get_remote() -> String {
replace(&_REMOTE[..])
}
#[inline]
pub fn get_install() -> String {
replace(&_INSTALL[..])
}
#[inline]
pub fn get_chatbox() -> String {
replace(&_CHATBOX[..])
}
#[inline]
pub fn get_cm() -> String {
replace(&_CONNECTION_MANAGER[..])
}
''')

17
libs/clipboard/Cargo.toml Normal file
View File

@@ -0,0 +1,17 @@
[package]
name = "clipboard"
version = "0.1.0"
edition = "2021"
build= "build.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
cc = "1.0"
[dependencies]
thiserror = "1.0.30"
lazy_static = "1.4"
serde = "1.0"
serde_derive = "1.0"
hbb_common = { path = "../hbb_common" }

16
libs/clipboard/README.md Normal file
View File

@@ -0,0 +1,16 @@
# clipboard
Copy files and text through network.
Main lowlevel logic from [FreeRDP](https://github.com/FreeRDP/FreeRDP).
TODO: Move this lib to a separate project.
## impl
### windows
![scene](./docs/assets/scene3.png)
![A1->B1](./docs/assets/win_A_B.png)
![B1->A1](./docs/assets/win_B_A.png)

43
libs/clipboard/build.rs Normal file
View File

@@ -0,0 +1,43 @@
use cc;
fn build_c_impl() {
let mut build = cc::Build::new();
#[cfg(target_os = "windows")]
build.file("src/windows/wf_cliprdr.c");
#[cfg(target_os = "linux")]
build.file("src/X11/xf_cliprdr.c");
#[cfg(target_os = "macos")]
build.file("src/OSX/Clipboard.m");
build.flag_if_supported("-Wno-c++0x-extensions");
build.flag_if_supported("-Wno-return-type-c-linkage");
build.flag_if_supported("-Wno-invalid-offsetof");
build.flag_if_supported("-Wno-unused-parameter");
if build.get_compiler().is_like_msvc() {
build.define("WIN32", "");
// build.define("_AMD64_", "");
build.flag("-Zi");
build.flag("-GR-");
// build.flag("-std:c++11");
} else {
build.flag("-fPIC");
// build.flag("-std=c++11");
// build.flag("-include");
// build.flag(&confdefs_path.to_string_lossy());
}
build.compile("mycliprdr");
#[cfg(target_os = "windows")]
println!("cargo:rerun-if-changed=src/windows/wf_cliprdr.c");
#[cfg(target_os = "linux")]
println!("cargo:rerun-if-changed=src/X11/xf_cliprdr.c");
#[cfg(target_os = "macos")]
println!("cargo:rerun-if-changed=src/OSX/Clipboard.m");
}
fn main() {
build_c_impl();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

@@ -0,0 +1,11 @@
#include "../cliprdr.h"
void mac_cliprdr_init(CliprdrClientContext *cliprdr)
{
(void)cliprdr;
}
void mac_cliprdr_uninit(CliprdrClientContext *cliprdr)
{
(void)cliprdr;
}

View File

@@ -0,0 +1,11 @@
#include "../cliprdr.h"
void xf_cliprdr_init(CliprdrClientContext* cliprdr)
{
(void)cliprdr;
}
void xf_cliprdr_uninit( CliprdrClientContext* cliprdr)
{
(void)cliprdr;
}

View File

@@ -0,0 +1,233 @@
#ifndef WF_CLIPRDR_H__
#define WF_CLIPRDR_H__
#ifdef __cplusplus
extern "C"
{
#endif
typedef signed char INT8, *PINT8;
typedef signed short INT16, *PINT16;
typedef signed int INT32, *PINT32;
typedef unsigned char UINT8, *PUINT8;
typedef unsigned short UINT16, *PUINT16;
typedef unsigned int UINT32, *PUINT32;
typedef unsigned int UINT;
typedef int BOOL;
typedef unsigned char BYTE;
/* Clipboard Messages */
#define DEFINE_CLIPRDR_HEADER_COMMON() \
UINT32 connID; \
UINT16 msgType; \
UINT16 msgFlags; \
UINT32 dataLen
struct _CLIPRDR_HEADER
{
DEFINE_CLIPRDR_HEADER_COMMON();
};
typedef struct _CLIPRDR_HEADER CLIPRDR_HEADER;
struct _CLIPRDR_CAPABILITY_SET
{
UINT16 capabilitySetType;
UINT16 capabilitySetLength;
};
typedef struct _CLIPRDR_CAPABILITY_SET CLIPRDR_CAPABILITY_SET;
struct _CLIPRDR_GENERAL_CAPABILITY_SET
{
UINT16 capabilitySetType;
UINT16 capabilitySetLength;
UINT32 version;
UINT32 generalFlags;
};
typedef struct _CLIPRDR_GENERAL_CAPABILITY_SET CLIPRDR_GENERAL_CAPABILITY_SET;
struct _CLIPRDR_CAPABILITIES
{
DEFINE_CLIPRDR_HEADER_COMMON();
UINT32 cCapabilitiesSets;
CLIPRDR_CAPABILITY_SET *capabilitySets;
};
typedef struct _CLIPRDR_CAPABILITIES CLIPRDR_CAPABILITIES;
struct _CLIPRDR_MONITOR_READY
{
DEFINE_CLIPRDR_HEADER_COMMON();
};
typedef struct _CLIPRDR_MONITOR_READY CLIPRDR_MONITOR_READY;
struct _CLIPRDR_TEMP_DIRECTORY
{
DEFINE_CLIPRDR_HEADER_COMMON();
char szTempDir[520];
};
typedef struct _CLIPRDR_TEMP_DIRECTORY CLIPRDR_TEMP_DIRECTORY;
struct _CLIPRDR_FORMAT
{
UINT32 formatId;
char *formatName;
};
typedef struct _CLIPRDR_FORMAT CLIPRDR_FORMAT;
struct _CLIPRDR_FORMAT_LIST
{
DEFINE_CLIPRDR_HEADER_COMMON();
UINT32 numFormats;
CLIPRDR_FORMAT *formats;
};
typedef struct _CLIPRDR_FORMAT_LIST CLIPRDR_FORMAT_LIST;
struct _CLIPRDR_FORMAT_LIST_RESPONSE
{
DEFINE_CLIPRDR_HEADER_COMMON();
};
typedef struct _CLIPRDR_FORMAT_LIST_RESPONSE CLIPRDR_FORMAT_LIST_RESPONSE;
struct _CLIPRDR_LOCK_CLIPBOARD_DATA
{
DEFINE_CLIPRDR_HEADER_COMMON();
UINT32 clipDataId;
};
typedef struct _CLIPRDR_LOCK_CLIPBOARD_DATA CLIPRDR_LOCK_CLIPBOARD_DATA;
struct _CLIPRDR_UNLOCK_CLIPBOARD_DATA
{
DEFINE_CLIPRDR_HEADER_COMMON();
UINT32 clipDataId;
};
typedef struct _CLIPRDR_UNLOCK_CLIPBOARD_DATA CLIPRDR_UNLOCK_CLIPBOARD_DATA;
struct _CLIPRDR_FORMAT_DATA_REQUEST
{
DEFINE_CLIPRDR_HEADER_COMMON();
UINT32 requestedFormatId;
};
typedef struct _CLIPRDR_FORMAT_DATA_REQUEST CLIPRDR_FORMAT_DATA_REQUEST;
struct _CLIPRDR_FORMAT_DATA_RESPONSE
{
DEFINE_CLIPRDR_HEADER_COMMON();
const BYTE *requestedFormatData;
};
typedef struct _CLIPRDR_FORMAT_DATA_RESPONSE CLIPRDR_FORMAT_DATA_RESPONSE;
struct _CLIPRDR_FILE_CONTENTS_REQUEST
{
DEFINE_CLIPRDR_HEADER_COMMON();
UINT32 streamId;
UINT32 listIndex;
UINT32 dwFlags;
UINT32 nPositionLow;
UINT32 nPositionHigh;
UINT32 cbRequested;
BOOL haveClipDataId;
UINT32 clipDataId;
};
typedef struct _CLIPRDR_FILE_CONTENTS_REQUEST CLIPRDR_FILE_CONTENTS_REQUEST;
struct _CLIPRDR_FILE_CONTENTS_RESPONSE
{
DEFINE_CLIPRDR_HEADER_COMMON();
UINT32 streamId;
UINT32 cbRequested;
const BYTE *requestedData;
};
typedef struct _CLIPRDR_FILE_CONTENTS_RESPONSE CLIPRDR_FILE_CONTENTS_RESPONSE;
typedef struct _cliprdr_client_context CliprdrClientContext;
typedef UINT (*pcCliprdrServerCapabilities)(CliprdrClientContext *context,
const CLIPRDR_CAPABILITIES *capabilities);
typedef UINT (*pcCliprdrClientCapabilities)(CliprdrClientContext *context,
const CLIPRDR_CAPABILITIES *capabilities);
typedef UINT (*pcCliprdrMonitorReady)(CliprdrClientContext *context,
const CLIPRDR_MONITOR_READY *monitorReady);
typedef UINT (*pcCliprdrTempDirectory)(CliprdrClientContext *context,
const CLIPRDR_TEMP_DIRECTORY *tempDirectory);
typedef UINT (*pcCliprdrClientFormatList)(CliprdrClientContext *context,
const CLIPRDR_FORMAT_LIST *formatList);
typedef UINT (*pcCliprdrServerFormatList)(CliprdrClientContext *context,
const CLIPRDR_FORMAT_LIST *formatList);
typedef UINT (*pcCliprdrClientFormatListResponse)(
CliprdrClientContext *context, const CLIPRDR_FORMAT_LIST_RESPONSE *formatListResponse);
typedef UINT (*pcCliprdrServerFormatListResponse)(
CliprdrClientContext *context, const CLIPRDR_FORMAT_LIST_RESPONSE *formatListResponse);
typedef UINT (*pcCliprdrClientLockClipboardData)(
CliprdrClientContext *context, const CLIPRDR_LOCK_CLIPBOARD_DATA *lockClipboardData);
typedef UINT (*pcCliprdrServerLockClipboardData)(
CliprdrClientContext *context, const CLIPRDR_LOCK_CLIPBOARD_DATA *lockClipboardData);
typedef UINT (*pcCliprdrClientUnlockClipboardData)(
CliprdrClientContext *context, const CLIPRDR_UNLOCK_CLIPBOARD_DATA *unlockClipboardData);
typedef UINT (*pcCliprdrServerUnlockClipboardData)(
CliprdrClientContext *context, const CLIPRDR_UNLOCK_CLIPBOARD_DATA *unlockClipboardData);
typedef UINT (*pcCliprdrClientFormatDataRequest)(
CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest);
typedef UINT (*pcCliprdrServerFormatDataRequest)(
CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest);
typedef UINT (*pcCliprdrClientFormatDataResponse)(
CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_RESPONSE *formatDataResponse);
typedef UINT (*pcCliprdrServerFormatDataResponse)(
CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_RESPONSE *formatDataResponse);
typedef UINT (*pcCliprdrClientFileContentsRequest)(
CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_REQUEST *fileContentsRequest);
typedef UINT (*pcCliprdrServerFileContentsRequest)(
CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_REQUEST *fileContentsRequest);
typedef UINT (*pcCliprdrClientFileContentsResponse)(
CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse);
typedef UINT (*pcCliprdrServerFileContentsResponse)(
CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse);
typedef BOOL (*pcCheckEnabled)(UINT32 connID);
// TODO: hide more members of clipboard context
struct _cliprdr_client_context
{
void *custom;
BOOL enableFiles;
BOOL enableOthers;
pcCheckEnabled CheckEnabled;
pcCliprdrServerCapabilities ServerCapabilities;
pcCliprdrClientCapabilities ClientCapabilities;
pcCliprdrMonitorReady MonitorReady;
pcCliprdrTempDirectory TempDirectory;
pcCliprdrClientFormatList ClientFormatList;
pcCliprdrServerFormatList ServerFormatList;
pcCliprdrClientFormatListResponse ClientFormatListResponse;
pcCliprdrServerFormatListResponse ServerFormatListResponse;
pcCliprdrClientLockClipboardData ClientLockClipboardData;
pcCliprdrServerLockClipboardData ServerLockClipboardData;
pcCliprdrClientUnlockClipboardData ClientUnlockClipboardData;
pcCliprdrServerUnlockClipboardData ServerUnlockClipboardData;
pcCliprdrClientFormatDataRequest ClientFormatDataRequest;
pcCliprdrServerFormatDataRequest ServerFormatDataRequest;
pcCliprdrClientFormatDataResponse ClientFormatDataResponse;
pcCliprdrServerFormatDataResponse ServerFormatDataResponse;
pcCliprdrClientFileContentsRequest ClientFileContentsRequest;
pcCliprdrServerFileContentsRequest ServerFileContentsRequest;
pcCliprdrClientFileContentsResponse ClientFileContentsResponse;
pcCliprdrServerFileContentsResponse ServerFileContentsResponse;
UINT32 lastRequestedFormatId;
};
#ifdef __cplusplus
}
#endif
#endif // WF_CLIPRDR_H__

View File

@@ -0,0 +1,564 @@
#![allow(dead_code)]
#![allow(non_camel_case_types)]
#![allow(unused_variables)]
#![allow(non_snake_case)]
#![allow(deref_nullptr)]
use std::{boxed::Box, result::Result};
use thiserror::Error;
pub type size_t = ::std::os::raw::c_ulonglong;
pub type __vcrt_bool = bool;
pub type wchar_t = ::std::os::raw::c_ushort;
pub type POINTER_64_INT = ::std::os::raw::c_ulonglong;
pub type INT8 = ::std::os::raw::c_schar;
pub type PINT8 = *mut ::std::os::raw::c_schar;
pub type INT16 = ::std::os::raw::c_short;
pub type PINT16 = *mut ::std::os::raw::c_short;
pub type INT32 = ::std::os::raw::c_int;
pub type PINT32 = *mut ::std::os::raw::c_int;
pub type INT64 = ::std::os::raw::c_longlong;
pub type PINT64 = *mut ::std::os::raw::c_longlong;
pub type UINT8 = ::std::os::raw::c_uchar;
pub type PUINT8 = *mut ::std::os::raw::c_uchar;
pub type UINT16 = ::std::os::raw::c_ushort;
pub type PUINT16 = *mut ::std::os::raw::c_ushort;
pub type UINT32 = ::std::os::raw::c_uint;
pub type PUINT32 = *mut ::std::os::raw::c_uint;
pub type UINT64 = ::std::os::raw::c_ulonglong;
pub type PUINT64 = *mut ::std::os::raw::c_ulonglong;
pub type LONG32 = ::std::os::raw::c_int;
pub type PLONG32 = *mut ::std::os::raw::c_int;
pub type ULONG32 = ::std::os::raw::c_uint;
pub type PULONG32 = *mut ::std::os::raw::c_uint;
pub type DWORD32 = ::std::os::raw::c_uint;
pub type PDWORD32 = *mut ::std::os::raw::c_uint;
pub type INT_PTR = ::std::os::raw::c_longlong;
pub type PINT_PTR = *mut ::std::os::raw::c_longlong;
pub type UINT_PTR = ::std::os::raw::c_ulonglong;
pub type PUINT_PTR = *mut ::std::os::raw::c_ulonglong;
pub type LONG_PTR = ::std::os::raw::c_longlong;
pub type PLONG_PTR = *mut ::std::os::raw::c_longlong;
pub type ULONG_PTR = ::std::os::raw::c_ulonglong;
pub type PULONG_PTR = *mut ::std::os::raw::c_ulonglong;
pub type SHANDLE_PTR = ::std::os::raw::c_longlong;
pub type HANDLE_PTR = ::std::os::raw::c_ulonglong;
pub type UHALF_PTR = ::std::os::raw::c_uint;
pub type PUHALF_PTR = *mut ::std::os::raw::c_uint;
pub type HALF_PTR = ::std::os::raw::c_int;
pub type PHALF_PTR = *mut ::std::os::raw::c_int;
pub type SIZE_T = ULONG_PTR;
pub type PSIZE_T = *mut ULONG_PTR;
pub type SSIZE_T = LONG_PTR;
pub type PSSIZE_T = *mut LONG_PTR;
pub type DWORD_PTR = ULONG_PTR;
pub type PDWORD_PTR = *mut ULONG_PTR;
pub type LONG64 = ::std::os::raw::c_longlong;
pub type PLONG64 = *mut ::std::os::raw::c_longlong;
pub type ULONG64 = ::std::os::raw::c_ulonglong;
pub type PULONG64 = *mut ::std::os::raw::c_ulonglong;
pub type DWORD64 = ::std::os::raw::c_ulonglong;
pub type PDWORD64 = *mut ::std::os::raw::c_ulonglong;
pub type KAFFINITY = ULONG_PTR;
pub type PKAFFINITY = *mut KAFFINITY;
pub type PVOID = *mut ::std::os::raw::c_void;
pub type CHAR = ::std::os::raw::c_char;
pub type SHORT = ::std::os::raw::c_short;
pub type LONG = ::std::os::raw::c_long;
pub type WCHAR = wchar_t;
pub type PWCHAR = *mut WCHAR;
pub type LPWCH = *mut WCHAR;
pub type PWCH = *mut WCHAR;
pub type LPCWCH = *const WCHAR;
pub type PCWCH = *const WCHAR;
pub type NWPSTR = *mut WCHAR;
pub type LPWSTR = *mut WCHAR;
pub type PWSTR = *mut WCHAR;
pub type PZPWSTR = *mut PWSTR;
pub type PCZPWSTR = *const PWSTR;
pub type LPUWSTR = *mut WCHAR;
pub type PUWSTR = *mut WCHAR;
pub type LPCWSTR = *const WCHAR;
pub type PCWSTR = *const WCHAR;
pub type PZPCWSTR = *mut PCWSTR;
pub type PCZPCWSTR = *const PCWSTR;
pub type LPCUWSTR = *const WCHAR;
pub type PCUWSTR = *const WCHAR;
pub type PZZWSTR = *mut WCHAR;
pub type PCZZWSTR = *const WCHAR;
pub type PUZZWSTR = *mut WCHAR;
pub type PCUZZWSTR = *const WCHAR;
pub type PNZWCH = *mut WCHAR;
pub type PCNZWCH = *const WCHAR;
pub type PUNZWCH = *mut WCHAR;
pub type PCUNZWCH = *const WCHAR;
pub type PCHAR = *mut CHAR;
pub type LPCH = *mut CHAR;
pub type PCH = *mut CHAR;
pub type LPCCH = *const CHAR;
pub type PCCH = *const CHAR;
pub type NPSTR = *mut CHAR;
pub type LPSTR = *mut CHAR;
pub type PSTR = *mut CHAR;
pub type PZPSTR = *mut PSTR;
pub type PCZPSTR = *const PSTR;
pub type LPCSTR = *const CHAR;
pub type PCSTR = *const CHAR;
pub type PZPCSTR = *mut PCSTR;
pub type PCZPCSTR = *const PCSTR;
pub type PZZSTR = *mut CHAR;
pub type PCZZSTR = *const CHAR;
pub type PNZCH = *mut CHAR;
pub type PCNZCH = *const CHAR;
pub type TCHAR = ::std::os::raw::c_char;
pub type PTCHAR = *mut ::std::os::raw::c_char;
pub type TBYTE = ::std::os::raw::c_uchar;
pub type PTBYTE = *mut ::std::os::raw::c_uchar;
pub type LPTCH = LPCH;
pub type PTCH = LPCH;
pub type LPCTCH = LPCCH;
pub type PCTCH = LPCCH;
pub type PTSTR = LPSTR;
pub type LPTSTR = LPSTR;
pub type PUTSTR = LPSTR;
pub type LPUTSTR = LPSTR;
pub type PCTSTR = LPCSTR;
pub type LPCTSTR = LPCSTR;
pub type PCUTSTR = LPCSTR;
pub type LPCUTSTR = LPCSTR;
pub type PZZTSTR = PZZSTR;
pub type PUZZTSTR = PZZSTR;
pub type PCZZTSTR = PCZZSTR;
pub type PCUZZTSTR = PCZZSTR;
pub type PZPTSTR = PZPSTR;
pub type PNZTCH = PNZCH;
pub type PUNZTCH = PNZCH;
pub type PCNZTCH = PCNZCH;
pub type PCUNZTCH = PCNZCH;
pub type PSHORT = *mut SHORT;
pub type PLONG = *mut LONG;
pub type ULONG = ::std::os::raw::c_ulong;
pub type PULONG = *mut ULONG;
pub type USHORT = ::std::os::raw::c_ushort;
pub type PUSHORT = *mut USHORT;
pub type UCHAR = ::std::os::raw::c_uchar;
pub type PUCHAR = *mut UCHAR;
pub type PSZ = *mut ::std::os::raw::c_char;
pub type DWORD = ::std::os::raw::c_ulong;
pub type BOOL = ::std::os::raw::c_int;
pub type BYTE = ::std::os::raw::c_uchar;
pub type WORD = ::std::os::raw::c_ushort;
pub type FLOAT = f32;
pub type PFLOAT = *mut FLOAT;
pub type PBOOL = *mut BOOL;
pub type LPBOOL = *mut BOOL;
pub type PBYTE = *mut BYTE;
pub type LPBYTE = *mut BYTE;
pub type PINT = *mut ::std::os::raw::c_int;
pub type LPINT = *mut ::std::os::raw::c_int;
pub type PWORD = *mut WORD;
pub type LPWORD = *mut WORD;
pub type LPLONG = *mut ::std::os::raw::c_long;
pub type PDWORD = *mut DWORD;
pub type LPDWORD = *mut DWORD;
pub type LPVOID = *mut ::std::os::raw::c_void;
pub type LPCVOID = *const ::std::os::raw::c_void;
pub type INT = ::std::os::raw::c_int;
pub type UINT = ::std::os::raw::c_uint;
pub type PUINT = *mut ::std::os::raw::c_uint;
pub type va_list = *mut ::std::os::raw::c_char;
pub const TRUE: ::std::os::raw::c_int = 1;
pub const FALSE: ::std::os::raw::c_int = 0;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_HEADER {
pub connID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
}
pub type CLIPRDR_HEADER = _CLIPRDR_HEADER;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_CAPABILITY_SET {
pub capabilitySetType: UINT16,
pub capabilitySetLength: UINT16,
}
pub type CLIPRDR_CAPABILITY_SET = _CLIPRDR_CAPABILITY_SET;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_GENERAL_CAPABILITY_SET {
pub capabilitySetType: UINT16,
pub capabilitySetLength: UINT16,
pub version: UINT32,
pub generalFlags: UINT32,
}
pub type CLIPRDR_GENERAL_CAPABILITY_SET = _CLIPRDR_GENERAL_CAPABILITY_SET;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_CAPABILITIES {
pub connID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub cCapabilitiesSets: UINT32,
pub capabilitySets: *mut CLIPRDR_CAPABILITY_SET,
}
pub type CLIPRDR_CAPABILITIES = _CLIPRDR_CAPABILITIES;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_MONITOR_READY {
pub connID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
}
pub type CLIPRDR_MONITOR_READY = _CLIPRDR_MONITOR_READY;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_TEMP_DIRECTORY {
pub connID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub szTempDir: [::std::os::raw::c_char; 520usize],
}
pub type CLIPRDR_TEMP_DIRECTORY = _CLIPRDR_TEMP_DIRECTORY;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_FORMAT {
pub formatId: UINT32,
pub formatName: *mut ::std::os::raw::c_char,
}
pub type CLIPRDR_FORMAT = _CLIPRDR_FORMAT;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_FORMAT_LIST {
pub connID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub numFormats: UINT32,
pub formats: *mut CLIPRDR_FORMAT,
}
pub type CLIPRDR_FORMAT_LIST = _CLIPRDR_FORMAT_LIST;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_FORMAT_LIST_RESPONSE {
pub connID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
}
pub type CLIPRDR_FORMAT_LIST_RESPONSE = _CLIPRDR_FORMAT_LIST_RESPONSE;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_LOCK_CLIPBOARD_DATA {
pub connID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub clipDataId: UINT32,
}
pub type CLIPRDR_LOCK_CLIPBOARD_DATA = _CLIPRDR_LOCK_CLIPBOARD_DATA;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_UNLOCK_CLIPBOARD_DATA {
pub connID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub clipDataId: UINT32,
}
pub type CLIPRDR_UNLOCK_CLIPBOARD_DATA = _CLIPRDR_UNLOCK_CLIPBOARD_DATA;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_FORMAT_DATA_REQUEST {
pub connID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub requestedFormatId: UINT32,
}
pub type CLIPRDR_FORMAT_DATA_REQUEST = _CLIPRDR_FORMAT_DATA_REQUEST;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_FORMAT_DATA_RESPONSE {
pub connID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub requestedFormatData: *const BYTE,
}
pub type CLIPRDR_FORMAT_DATA_RESPONSE = _CLIPRDR_FORMAT_DATA_RESPONSE;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_FILE_CONTENTS_REQUEST {
pub connID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub streamId: UINT32,
pub listIndex: UINT32,
pub dwFlags: UINT32,
pub nPositionLow: UINT32,
pub nPositionHigh: UINT32,
pub cbRequested: UINT32,
pub haveClipDataId: BOOL,
pub clipDataId: UINT32,
}
pub type CLIPRDR_FILE_CONTENTS_REQUEST = _CLIPRDR_FILE_CONTENTS_REQUEST;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_FILE_CONTENTS_RESPONSE {
pub connID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub streamId: UINT32,
pub cbRequested: UINT32,
pub requestedData: *const BYTE,
}
pub type CLIPRDR_FILE_CONTENTS_RESPONSE = _CLIPRDR_FILE_CONTENTS_RESPONSE;
pub type CliprdrClientContext = _cliprdr_client_context;
pub type pcCliprdrServerCapabilities = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
capabilities: *const CLIPRDR_CAPABILITIES,
) -> UINT,
>;
pub type pcCliprdrClientCapabilities = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
capabilities: *const CLIPRDR_CAPABILITIES,
) -> UINT,
>;
pub type pcCliprdrMonitorReady = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
monitorReady: *const CLIPRDR_MONITOR_READY,
) -> UINT,
>;
pub type pcCliprdrTempDirectory = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
tempDirectory: *const CLIPRDR_TEMP_DIRECTORY,
) -> UINT,
>;
pub type pcCliprdrClientFormatList = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
formatList: *const CLIPRDR_FORMAT_LIST,
) -> UINT,
>;
pub type pcCliprdrServerFormatList = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
formatList: *const CLIPRDR_FORMAT_LIST,
) -> UINT,
>;
pub type pcCliprdrClientFormatListResponse = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
formatListResponse: *const CLIPRDR_FORMAT_LIST_RESPONSE,
) -> UINT,
>;
pub type pcCliprdrServerFormatListResponse = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
formatListResponse: *const CLIPRDR_FORMAT_LIST_RESPONSE,
) -> UINT,
>;
pub type pcCliprdrClientLockClipboardData = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
lockClipboardData: *const CLIPRDR_LOCK_CLIPBOARD_DATA,
) -> UINT,
>;
pub type pcCliprdrServerLockClipboardData = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
lockClipboardData: *const CLIPRDR_LOCK_CLIPBOARD_DATA,
) -> UINT,
>;
pub type pcCliprdrClientUnlockClipboardData = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
unlockClipboardData: *const CLIPRDR_UNLOCK_CLIPBOARD_DATA,
) -> UINT,
>;
pub type pcCliprdrServerUnlockClipboardData = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
unlockClipboardData: *const CLIPRDR_UNLOCK_CLIPBOARD_DATA,
) -> UINT,
>;
pub type pcCliprdrClientFormatDataRequest = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
formatDataRequest: *const CLIPRDR_FORMAT_DATA_REQUEST,
) -> UINT,
>;
pub type pcCliprdrServerFormatDataRequest = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
formatDataRequest: *const CLIPRDR_FORMAT_DATA_REQUEST,
) -> UINT,
>;
pub type pcCliprdrClientFormatDataResponse = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
formatDataResponse: *const CLIPRDR_FORMAT_DATA_RESPONSE,
) -> UINT,
>;
pub type pcCliprdrServerFormatDataResponse = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
formatDataResponse: *const CLIPRDR_FORMAT_DATA_RESPONSE,
) -> UINT,
>;
pub type pcCliprdrClientFileContentsRequest = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
fileContentsRequest: *const CLIPRDR_FILE_CONTENTS_REQUEST,
) -> UINT,
>;
pub type pcCliprdrServerFileContentsRequest = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
fileContentsRequest: *const CLIPRDR_FILE_CONTENTS_REQUEST,
) -> UINT,
>;
pub type pcCliprdrClientFileContentsResponse = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
fileContentsResponse: *const CLIPRDR_FILE_CONTENTS_RESPONSE,
) -> UINT,
>;
pub type pcCliprdrServerFileContentsResponse = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
fileContentsResponse: *const CLIPRDR_FILE_CONTENTS_RESPONSE,
) -> UINT,
>;
pub type pcCheckEnabled = ::std::option::Option<
unsafe extern "C" fn(connID: UINT32) -> BOOL,
>;
// TODO: hide more members of clipboard context
#[repr(C)]
#[derive(Debug, Clone)]
pub struct _cliprdr_client_context {
pub custom: *mut ::std::os::raw::c_void,
pub enableFiles: BOOL,
pub enableOthers: BOOL,
pub CheckEnabled: pcCheckEnabled,
pub ServerCapabilities: pcCliprdrServerCapabilities,
pub ClientCapabilities: pcCliprdrClientCapabilities,
pub MonitorReady: pcCliprdrMonitorReady,
pub TempDirectory: pcCliprdrTempDirectory,
pub ClientFormatList: pcCliprdrClientFormatList,
pub ServerFormatList: pcCliprdrServerFormatList,
pub ClientFormatListResponse: pcCliprdrClientFormatListResponse,
pub ServerFormatListResponse: pcCliprdrServerFormatListResponse,
pub ClientLockClipboardData: pcCliprdrClientLockClipboardData,
pub ServerLockClipboardData: pcCliprdrServerLockClipboardData,
pub ClientUnlockClipboardData: pcCliprdrClientUnlockClipboardData,
pub ServerUnlockClipboardData: pcCliprdrServerUnlockClipboardData,
pub ClientFormatDataRequest: pcCliprdrClientFormatDataRequest,
pub ServerFormatDataRequest: pcCliprdrServerFormatDataRequest,
pub ClientFormatDataResponse: pcCliprdrClientFormatDataResponse,
pub ServerFormatDataResponse: pcCliprdrServerFormatDataResponse,
pub ClientFileContentsRequest: pcCliprdrClientFileContentsRequest,
pub ServerFileContentsRequest: pcCliprdrServerFileContentsRequest,
pub ClientFileContentsResponse: pcCliprdrClientFileContentsResponse,
pub ServerFileContentsResponse: pcCliprdrServerFileContentsResponse,
pub lastRequestedFormatId: UINT32,
}
// #[link(name = "user32")]
// #[link(name = "ole32")]
extern "C" {
pub(crate) fn init_cliprdr(context: *mut CliprdrClientContext) -> BOOL;
pub(crate) fn uninit_cliprdr(context: *mut CliprdrClientContext) -> BOOL;
pub(crate) fn empty_cliprdr(
context: *mut CliprdrClientContext,
connID: UINT32,
) -> BOOL;
}
#[derive(Error, Debug)]
pub enum CliprdrError {
#[error("invalid cliprdr name")]
CliprdrName,
#[error("failed to init cliprdr")]
CliprdrInit,
#[error("unknown cliprdr error")]
Unknown,
}
impl CliprdrClientContext {
pub fn create(
enable_files: bool,
enable_others: bool,
check_enabled: pcCheckEnabled,
client_format_list: pcCliprdrClientFormatList,
client_format_list_response: pcCliprdrClientFormatListResponse,
client_format_data_request: pcCliprdrClientFormatDataRequest,
client_format_data_response: pcCliprdrClientFormatDataResponse,
client_file_contents_request: pcCliprdrClientFileContentsRequest,
client_file_contents_response: pcCliprdrClientFileContentsResponse,
) -> Result<Box<Self>, CliprdrError> {
let context = CliprdrClientContext {
custom: 0 as *mut _,
enableFiles: if enable_files { TRUE } else { FALSE },
enableOthers: if enable_others { TRUE } else { FALSE },
CheckEnabled: check_enabled,
ServerCapabilities: None,
ClientCapabilities: None,
MonitorReady: None,
TempDirectory: None,
ClientFormatList: client_format_list,
ServerFormatList: None,
ClientFormatListResponse: client_format_list_response,
ServerFormatListResponse: None,
ClientLockClipboardData: None,
ServerLockClipboardData: None,
ClientUnlockClipboardData: None,
ServerUnlockClipboardData: None,
ClientFormatDataRequest: client_format_data_request,
ServerFormatDataRequest: None,
ClientFormatDataResponse: client_format_data_response,
ServerFormatDataResponse: None,
ClientFileContentsRequest: client_file_contents_request,
ServerFileContentsRequest: None,
ClientFileContentsResponse: client_file_contents_response,
ServerFileContentsResponse: None,
lastRequestedFormatId: 0,
};
let mut context = Box::new(context);
unsafe {
if FALSE == init_cliprdr(&mut (*context)) {
println!("Failed to init cliprdr");
Err(CliprdrError::CliprdrInit)
} else {
Ok(context)
}
}
}
}
impl Drop for CliprdrClientContext {
fn drop(&mut self) {
unsafe {
if FALSE == uninit_cliprdr(&mut *self) {
println!("Failed to uninit cliprdr");
} else {
println!("Succeeded to uninit cliprdr");
}
}
}
}

605
libs/clipboard/src/lib.rs Normal file
View File

@@ -0,0 +1,605 @@
use cliprdr::*;
use hbb_common::{
log,
tokio::sync::{
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
Mutex as TokioMutex,
},
ResultType,
};
use serde_derive::{Deserialize, Serialize};
use std::{
boxed::Box,
collections::HashMap,
ffi::{CStr, CString},
sync::Mutex,
};
pub mod cliprdr;
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(tag = "t", content = "c")]
pub enum ClipbaordFile {
ServerFormatList {
conn_id: i32,
format_list: Vec<(i32, String)>,
},
ServerFormatListResponse {
conn_id: i32,
msg_flags: i32,
},
ServerFormatDataRequest {
conn_id: i32,
requested_format_id: i32,
},
ServerFormatDataResponse {
conn_id: i32,
msg_flags: i32,
format_data: Vec<u8>,
},
FileContentsRequest {
conn_id: i32,
stream_id: i32,
list_index: i32,
dw_flags: i32,
n_position_low: i32,
n_position_high: i32,
cb_requested: i32,
have_clip_data_id: bool,
clip_data_id: i32,
},
FileContentsResponse {
conn_id: i32,
msg_flags: i32,
stream_id: i32,
requested_data: Vec<u8>,
},
}
#[derive(Default)]
struct ConnEnabled {
conn_enabled: HashMap<i32, bool>,
}
lazy_static::lazy_static! {
static ref MSG_CHANNEL_CLIENT: (UnboundedSender<(i32, ClipbaordFile)>, TokioMutex<UnboundedReceiver<(i32, ClipbaordFile)>>) = {
let (tx, rx) = unbounded_channel();
(tx, TokioMutex::new(rx))
};
static ref CLIP_CONN_ENABLED: Mutex<ConnEnabled> = Mutex::new(ConnEnabled::default());
}
#[inline(always)]
pub fn get_rx_clip_client<'a>() -> &'a TokioMutex<UnboundedReceiver<(i32, ClipbaordFile)>> {
&MSG_CHANNEL_CLIENT.1
}
pub fn set_conn_enabled(conn_id: i32, enabled: bool) {
let mut lock = CLIP_CONN_ENABLED.lock().unwrap();
if conn_id != 0 {
let _ = lock.conn_enabled.insert(conn_id, enabled);
}
}
pub fn empty_clipboard(context: &mut Box<CliprdrClientContext>, conn_id: i32) -> bool {
unsafe { TRUE == cliprdr::empty_cliprdr(&mut (**context), conn_id as u32) }
}
pub fn server_clip_file(
context: &mut Box<CliprdrClientContext>,
s_conn_id: i32,
msg: ClipbaordFile,
) -> u32 {
match msg {
ClipbaordFile::ServerFormatList {
mut conn_id,
format_list,
} => {
if s_conn_id != 0 {
conn_id = s_conn_id as i32;
}
log::debug!("server_format_list called");
let ret = server_format_list(context, conn_id, format_list);
log::debug!("server_format_list called, return {}", ret);
ret
}
ClipbaordFile::ServerFormatListResponse {
mut conn_id,
msg_flags,
} => {
if s_conn_id != 0 {
conn_id = s_conn_id as i32;
}
log::debug!("format_list_response called");
let ret = server_format_list_response(context, conn_id, msg_flags);
log::debug!("server_format_list_response called, return {}", ret);
ret
}
ClipbaordFile::ServerFormatDataRequest {
mut conn_id,
requested_format_id,
} => {
if s_conn_id != 0 {
conn_id = s_conn_id as i32;
}
log::debug!("format_data_request called");
let ret = server_format_data_request(context, conn_id, requested_format_id);
log::debug!("server_format_data_request called, return {}", ret);
ret
}
ClipbaordFile::ServerFormatDataResponse {
mut conn_id,
msg_flags,
format_data,
} => {
if s_conn_id != 0 {
conn_id = s_conn_id as i32;
}
log::debug!("format_data_response called");
let ret = server_format_data_response(context, conn_id, msg_flags, format_data);
log::debug!("server_format_data_response called, return {}", ret);
ret
}
ClipbaordFile::FileContentsRequest {
mut conn_id,
stream_id,
list_index,
dw_flags,
n_position_low,
n_position_high,
cb_requested,
have_clip_data_id,
clip_data_id,
} => {
if s_conn_id != 0 {
conn_id = s_conn_id as i32;
}
log::debug!("file_contents_request called");
let ret = server_file_contents_request(
context,
conn_id,
stream_id,
list_index,
dw_flags,
n_position_low,
n_position_high,
cb_requested,
have_clip_data_id,
clip_data_id,
);
log::debug!("server_file_contents_request called, return {}", ret);
ret
}
ClipbaordFile::FileContentsResponse {
mut conn_id,
msg_flags,
stream_id,
requested_data,
} => {
if s_conn_id != 0 {
conn_id = s_conn_id as i32;
}
log::debug!("file_contents_response called");
let ret = server_file_contents_response(
context,
conn_id,
msg_flags,
stream_id,
requested_data,
);
log::debug!("server_file_contents_response called, return {}", ret);
ret
}
}
}
pub fn server_format_list(
context: &mut Box<CliprdrClientContext>,
conn_id: i32,
format_list: Vec<(i32, String)>,
) -> u32 {
unsafe {
let num_formats = format_list.len() as UINT32;
let mut formats = format_list
.into_iter()
.map(|format| {
if format.1.is_empty() {
CLIPRDR_FORMAT {
formatId: format.0 as UINT32,
formatName: 0 as *mut _,
}
} else {
let n = match CString::new(format.1) {
Ok(n) => n,
Err(_) => CString::new("").unwrap(),
};
CLIPRDR_FORMAT {
formatId: format.0 as UINT32,
formatName: n.into_raw(),
}
}
})
.collect::<Vec<CLIPRDR_FORMAT>>();
let format_list = CLIPRDR_FORMAT_LIST {
connID: conn_id as UINT32,
msgType: 0 as UINT16,
msgFlags: 0 as UINT16,
dataLen: 0 as UINT32,
numFormats: num_formats,
formats: formats.as_mut_ptr(),
};
let ret = ((**context).ServerFormatList.unwrap())(&mut (**context), &format_list);
for f in formats {
if !f.formatName.is_null() {
// retake pointer to free memory
let _ = CString::from_raw(f.formatName);
}
}
ret as u32
}
}
pub fn server_format_list_response(
context: &mut Box<CliprdrClientContext>,
conn_id: i32,
msg_flags: i32,
) -> u32 {
unsafe {
let format_list_response = CLIPRDR_FORMAT_LIST_RESPONSE {
connID: conn_id as UINT32,
msgType: 0 as UINT16,
msgFlags: msg_flags as UINT16,
dataLen: 0 as UINT32,
};
let ret =
(**context).ServerFormatListResponse.unwrap()(&mut (**context), &format_list_response);
ret as u32
}
}
pub fn server_format_data_request(
context: &mut Box<CliprdrClientContext>,
conn_id: i32,
requested_format_id: i32,
) -> u32 {
unsafe {
let format_data_request = CLIPRDR_FORMAT_DATA_REQUEST {
connID: conn_id as UINT32,
msgType: 0 as UINT16,
msgFlags: 0 as UINT16,
dataLen: 0 as UINT32,
requestedFormatId: requested_format_id as UINT32,
};
let ret =
((**context).ServerFormatDataRequest.unwrap())(&mut (**context), &format_data_request);
ret as u32
}
}
pub fn server_format_data_response(
context: &mut Box<CliprdrClientContext>,
conn_id: i32,
msg_flags: i32,
mut format_data: Vec<u8>,
) -> u32 {
unsafe {
let format_data_response = CLIPRDR_FORMAT_DATA_RESPONSE {
connID: conn_id as UINT32,
msgType: 0 as UINT16,
msgFlags: msg_flags as UINT16,
dataLen: format_data.len() as UINT32,
requestedFormatData: format_data.as_mut_ptr(),
};
let ret = ((**context).ServerFormatDataResponse.unwrap())(
&mut (**context),
&format_data_response,
);
ret as u32
}
}
pub fn server_file_contents_request(
context: &mut Box<CliprdrClientContext>,
conn_id: i32,
stream_id: i32,
list_index: i32,
dw_flags: i32,
n_position_low: i32,
n_position_high: i32,
cb_requested: i32,
have_clip_data_id: bool,
clip_data_id: i32,
) -> u32 {
unsafe {
let file_contents_request = CLIPRDR_FILE_CONTENTS_REQUEST {
connID: conn_id as UINT32,
msgType: 0 as UINT16,
msgFlags: 0 as UINT16,
dataLen: 0 as UINT32,
streamId: stream_id as UINT32,
listIndex: list_index as UINT32,
dwFlags: dw_flags as UINT32,
nPositionLow: n_position_low as UINT32,
nPositionHigh: n_position_high as UINT32,
cbRequested: cb_requested as UINT32,
haveClipDataId: if have_clip_data_id { TRUE } else { FALSE },
clipDataId: clip_data_id as UINT32,
};
let ret = ((**context).ServerFileContentsRequest.unwrap())(
&mut (**context),
&file_contents_request,
);
ret as u32
}
}
pub fn server_file_contents_response(
context: &mut Box<CliprdrClientContext>,
conn_id: i32,
msg_flags: i32,
stream_id: i32,
mut requested_data: Vec<u8>,
) -> u32 {
unsafe {
let file_contents_response = CLIPRDR_FILE_CONTENTS_RESPONSE {
connID: conn_id as UINT32,
msgType: 0 as UINT16,
msgFlags: msg_flags as UINT16,
dataLen: 4 + requested_data.len() as UINT32,
streamId: stream_id as UINT32,
cbRequested: requested_data.len() as UINT32,
requestedData: requested_data.as_mut_ptr(),
};
let ret = ((**context).ServerFileContentsResponse.unwrap())(
&mut (**context),
&file_contents_response,
);
ret as u32
}
}
pub fn create_cliprdr_context(
enable_files: bool,
enable_others: bool,
) -> ResultType<Box<CliprdrClientContext>> {
Ok(CliprdrClientContext::create(
enable_files,
enable_others,
Some(check_enabled),
Some(client_format_list),
Some(client_format_list_response),
Some(client_format_data_request),
Some(client_format_data_response),
Some(client_file_contents_request),
Some(client_file_contents_response),
)?)
}
extern "C" fn check_enabled(conn_id: UINT32) -> BOOL {
let lock = CLIP_CONN_ENABLED.lock().unwrap();
let mut connd_enabled = false;
if conn_id != 0 {
if let Some(true) = lock.conn_enabled.get(&(conn_id as i32)) {
connd_enabled = true;
}
} else {
connd_enabled = true;
}
return if connd_enabled { TRUE } else { FALSE };
}
extern "C" fn client_format_list(
_context: *mut CliprdrClientContext,
clip_format_list: *const CLIPRDR_FORMAT_LIST,
) -> UINT {
log::debug!("client_format_list called");
let conn_id;
let mut format_list: Vec<(i32, String)> = Vec::new();
unsafe {
let mut i = 0u32;
while i < (*clip_format_list).numFormats {
let format_data = &(*(*clip_format_list).formats.offset(i as isize));
if format_data.formatName.is_null() {
format_list.push((format_data.formatId as i32, "".to_owned()));
} else {
let format_name = CStr::from_ptr(format_data.formatName).to_str();
let format_name = match format_name {
Ok(n) => n.to_owned(),
Err(_) => {
log::warn!("failed to get format name");
"".to_owned()
}
};
format_list.push((format_data.formatId as i32, format_name));
}
// log::debug!("format list item {}: format id: {}, format name: {}", i, format_data.formatId, &format_name);
i += 1;
}
conn_id = (*clip_format_list).connID as i32;
}
let data = ClipbaordFile::ServerFormatList {
conn_id,
format_list,
};
// no need to handle result here
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
0
}
extern "C" fn client_format_list_response(
_context: *mut CliprdrClientContext,
format_list_response: *const CLIPRDR_FORMAT_LIST_RESPONSE,
) -> UINT {
log::debug!("client_format_list_response called");
let conn_id;
let msg_flags;
unsafe {
conn_id = (*format_list_response).connID as i32;
msg_flags = (*format_list_response).msgFlags as i32;
}
let data = ClipbaordFile::ServerFormatListResponse { conn_id, msg_flags };
// no need to handle result here
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
0
}
extern "C" fn client_format_data_request(
_context: *mut CliprdrClientContext,
format_data_request: *const CLIPRDR_FORMAT_DATA_REQUEST,
) -> UINT {
log::debug!("client_format_data_request called");
let conn_id;
let requested_format_id;
unsafe {
conn_id = (*format_data_request).connID as i32;
requested_format_id = (*format_data_request).requestedFormatId as i32;
}
let data = ClipbaordFile::ServerFormatDataRequest {
conn_id,
requested_format_id,
};
// no need to handle result here
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
0
}
extern "C" fn client_format_data_response(
_context: *mut CliprdrClientContext,
format_data_response: *const CLIPRDR_FORMAT_DATA_RESPONSE,
) -> UINT {
log::debug!("cconn_idlient_format_data_response called");
let conn_id;
let msg_flags;
let format_data;
unsafe {
conn_id = (*format_data_response).connID as i32;
msg_flags = (*format_data_response).msgFlags as i32;
if (*format_data_response).requestedFormatData.is_null() {
format_data = Vec::new();
} else {
format_data = std::slice::from_raw_parts(
(*format_data_response).requestedFormatData,
(*format_data_response).dataLen as usize,
)
.to_vec();
}
}
let data = ClipbaordFile::ServerFormatDataResponse {
conn_id,
msg_flags,
format_data,
};
// no need to handle result here
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
0
}
extern "C" fn client_file_contents_request(
_context: *mut CliprdrClientContext,
file_contents_request: *const CLIPRDR_FILE_CONTENTS_REQUEST,
) -> UINT {
log::debug!("client_file_contents_request called");
// TODO: support huge file?
// if (!cliprdr->hasHugeFileSupport)
// {
// if (((UINT64)fileContentsRequest->cbRequested + fileContentsRequest->nPositionLow) >
// UINT32_MAX)
// return ERROR_INVALID_PARAMETER;
// if (fileContentsRequest->nPositionHigh != 0)
// return ERROR_INVALID_PARAMETER;
// }
let conn_id;
let stream_id;
let list_index;
let dw_flags;
let n_position_low;
let n_position_high;
let cb_requested;
let have_clip_data_id;
let clip_data_id;
unsafe {
conn_id = (*file_contents_request).connID as i32;
stream_id = (*file_contents_request).streamId as i32;
list_index = (*file_contents_request).listIndex as i32;
dw_flags = (*file_contents_request).dwFlags as i32;
n_position_low = (*file_contents_request).nPositionLow as i32;
n_position_high = (*file_contents_request).nPositionHigh as i32;
cb_requested = (*file_contents_request).cbRequested as i32;
have_clip_data_id = (*file_contents_request).haveClipDataId == TRUE;
clip_data_id = (*file_contents_request).clipDataId as i32;
}
let data = ClipbaordFile::FileContentsRequest {
conn_id,
stream_id,
list_index,
dw_flags,
n_position_low,
n_position_high,
cb_requested,
have_clip_data_id,
clip_data_id,
};
// no need to handle result here
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
0
}
extern "C" fn client_file_contents_response(
_context: *mut CliprdrClientContext,
file_contents_response: *const CLIPRDR_FILE_CONTENTS_RESPONSE,
) -> UINT {
log::debug!("client_file_contents_response called");
let conn_id;
let msg_flags;
let stream_id;
let requested_data;
unsafe {
conn_id = (*file_contents_response).connID as i32;
msg_flags = (*file_contents_response).msgFlags as i32;
stream_id = (*file_contents_response).streamId as i32;
if (*file_contents_response).requestedData.is_null() {
requested_data = Vec::new();
} else {
requested_data = std::slice::from_raw_parts(
(*file_contents_response).requestedData,
(*file_contents_response).cbRequested as usize,
)
.to_vec();
}
}
let data = ClipbaordFile::FileContentsResponse {
conn_id,
msg_flags,
stream_id,
requested_data,
};
// no need to handle result here
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
0
}
#[cfg(test)]
mod tests {
// #[test]
// fn test_cliprdr_run() {
// super::cliprdr_run();
// }
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@ use libc;
use crate::{Key, KeyboardControllable, MouseButton, MouseControllable};
use self::libc::{c_char, c_int, c_void, useconds_t};
use std::{borrow::Cow, ffi::CString, ptr};
use std::{borrow::Cow, ffi::CString, io::prelude::*, ptr, sync::mpsc};
const CURRENT_WINDOW: c_int = 0;
const DEFAULT_DELAY: u64 = 12000;
@@ -60,10 +60,16 @@ fn mousebutton(button: MouseButton) -> c_int {
}
}
enum PyMsg {
Char(char),
Str(&'static str),
}
/// The main struct for handling the event emitting
pub struct Enigo {
xdo: Xdo,
delay: u64,
tx: mpsc::Sender<(PyMsg, bool)>,
}
// This is safe, we have a unique pointer.
// TODO: use Unique<c_char> once stable.
@@ -72,9 +78,12 @@ unsafe impl Send for Enigo {}
impl Default for Enigo {
/// Create a new Enigo instance
fn default() -> Self {
let (tx, rx) = mpsc::channel();
start_pynput_service(rx);
Self {
xdo: unsafe { xdo_new(ptr::null()) },
delay: DEFAULT_DELAY,
tx,
}
}
}
@@ -90,6 +99,99 @@ impl Enigo {
pub fn set_delay(&mut self, delay: u64) {
self.delay = delay;
}
///
pub fn reset(&mut self) {
self.tx.send((PyMsg::Char('\0'), true)).ok();
}
#[inline]
fn send_pynput(&mut self, key: &Key, is_press: bool) -> bool {
if unsafe { PYNPUT_EXIT || !PYNPUT_REDAY } {
return false;
}
if let Key::Layout(c) = key {
return self.tx.send((PyMsg::Char(*c), is_press)).is_ok();
}
if let Key::Raw(_) = key {
return false;
}
#[allow(deprecated)]
let s = match key {
Key::Alt => "Alt_L",
Key::Backspace => "BackSpace",
Key::CapsLock => "Caps_Lock",
Key::Control => "Control_L",
Key::Delete => "Delete",
Key::DownArrow => "Down",
Key::End => "End",
Key::Escape => "Escape",
Key::F1 => "F1",
Key::F10 => "F10",
Key::F11 => "F11",
Key::F12 => "F12",
Key::F2 => "F2",
Key::F3 => "F3",
Key::F4 => "F4",
Key::F5 => "F5",
Key::F6 => "F6",
Key::F7 => "F7",
Key::F8 => "F8",
Key::F9 => "F9",
Key::Home => "Home",
Key::LeftArrow => "Left",
Key::Option => "Option",
Key::PageDown => "Page_Down",
Key::PageUp => "Page_Up",
Key::Return => "Return",
Key::RightArrow => "Right",
Key::Shift => "Shift_L",
Key::Space => "space",
Key::Tab => "Tab",
Key::UpArrow => "Up",
Key::Numpad0 => "0",
Key::Numpad1 => "1",
Key::Numpad2 => "2",
Key::Numpad3 => "3",
Key::Numpad4 => "4",
Key::Numpad5 => "5",
Key::Numpad6 => "6",
Key::Numpad7 => "7",
Key::Numpad8 => "8",
Key::Numpad9 => "9",
Key::Decimal => "KP_Decimal",
Key::Cancel => "Cancel",
Key::Clear => "Clear",
Key::Pause => "Pause",
Key::Kana => "Kana",
Key::Hangul => "Hangul",
Key::Hanja => "Hanja",
Key::Kanji => "Kanji",
Key::Select => "Select",
Key::Print => "Print",
Key::Execute => "Execute",
Key::Snapshot => "3270_PrintScreen",
Key::Insert => "Insert",
Key::Help => "Help",
Key::Separator => "KP_Separator",
Key::Scroll => "Scroll_Lock",
Key::NumLock => "Num_Lock",
Key::RWin => "Super_R",
Key::Apps => "Menu",
Key::Multiply => "KP_Multiply",
Key::Add => "KP_Add",
Key::Subtract => "KP_Subtract",
Key::Divide => "KP_Divide",
Key::Equals => "KP_Equal",
Key::NumpadEnter => "KP_Enter",
Key::RightShift => "Shift_R",
Key::RightControl => "Control_R",
Key::RightAlt => "Mode_switch",
Key::Command | Key::Super | Key::Windows | Key::Meta => "Super_L",
_ => {
return true;
}
};
return self.tx.send((PyMsg::Str(s), is_press)).is_ok();
}
}
impl Drop for Enigo {
fn drop(&mut self) {
@@ -281,6 +383,17 @@ impl KeyboardControllable for Enigo {
if self.xdo.is_null() {
return false;
}
/*
// modifier keys mask
pub const ShiftMask: c_uint = 0x01;
pub const LockMask: c_uint = 0x02;
pub const ControlMask: c_uint = 0x04;
pub const Mod1Mask: c_uint = 0x08;
pub const Mod2Mask: c_uint = 0x10;
pub const Mod3Mask: c_uint = 0x20;
pub const Mod4Mask: c_uint = 0x40;
pub const Mod5Mask: c_uint = 0x80;
*/
let mod_shift = 1 << 0;
let mod_lock = 1 << 1;
let mod_control = 1 << 2;
@@ -288,7 +401,6 @@ impl KeyboardControllable for Enigo {
let mod_numlock = 1 << 4;
let mod_meta = 1 << 6;
let mask = unsafe { xdo_get_input_state(self.xdo) };
// println!("{:b}", mask);
match key {
Key::Shift => mask & mod_shift != 0,
Key::CapsLock => mask & mod_lock != 0,
@@ -319,6 +431,9 @@ impl KeyboardControllable for Enigo {
if self.xdo.is_null() {
return Ok(());
}
if self.send_pynput(&key, true) {
return Ok(());
}
let string = CString::new(&*keysequence(key))?;
unsafe {
xdo_send_keysequence_window_down(
@@ -334,6 +449,9 @@ impl KeyboardControllable for Enigo {
if self.xdo.is_null() {
return;
}
if self.send_pynput(&key, false) {
return;
}
if let Ok(string) = CString::new(&*keysequence(key)) {
unsafe {
xdo_send_keysequence_window_up(
@@ -361,3 +479,119 @@ impl KeyboardControllable for Enigo {
}
}
}
static mut PYNPUT_EXIT: bool = false;
static mut PYNPUT_REDAY: bool = false;
static IPC_FILE: &'static str = "/tmp/RustDesk/pynput_service";
fn start_pynput_service(rx: mpsc::Receiver<(PyMsg, bool)>) {
let mut py = "./pynput_service.py".to_owned();
if !std::path::Path::new(&py).exists() {
py = "/usr/share/rustdesk/files/pynput_service.py".to_owned();
if !std::path::Path::new(&py).exists() {
log::error!("{} not exits", py);
}
}
log::info!("pynput service: {}", py);
std::thread::spawn(move || {
let username = std::env::var("PYNPUT_USERNAME").unwrap_or("".to_owned());
let userid = std::env::var("PYNPUT_USERID").unwrap_or("".to_owned());
let status = if username.is_empty() {
std::process::Command::new("python3")
.arg(&py)
.arg(IPC_FILE)
.status()
.map(|x| x.success())
} else {
let mut status = Ok(true);
for i in 0..100 {
if i % 10 == 0 {
log::info!("#{} try to start pynput server", i);
}
status = std::process::Command::new("sudo")
.args(vec![
&format!("XDG_RUNTIME_DIR=/run/user/{}", userid) as &str,
"-u",
&username,
"python3",
&py,
IPC_FILE,
])
.status()
.map(|x| x.success());
match status {
Ok(true) => break,
_ => {}
}
std::thread::sleep(std::time::Duration::from_millis(100));
}
status
};
log::info!(
"pynput server exit with username/id {}/{}: {:?}",
username,
userid,
status
);
unsafe {
PYNPUT_EXIT = true;
}
});
std::thread::spawn(move || {
for i in 0..300 {
std::thread::sleep(std::time::Duration::from_millis(100));
let mut conn = match std::os::unix::net::UnixStream::connect(IPC_FILE) {
Ok(conn) => conn,
Err(err) => {
if i % 15 == 0 {
log::warn!("Failed to connect to {}: {}", IPC_FILE, err);
}
continue;
}
};
if let Err(err) = conn.set_nonblocking(true) {
log::error!("Failed to set ipc nonblocking: {}", err);
return;
}
log::info!("Conntected to pynput server");
let d = std::time::Duration::from_millis(30);
unsafe {
PYNPUT_REDAY = true;
}
let mut buf = [0u8; 1024];
loop {
if unsafe { PYNPUT_EXIT } {
break;
}
match rx.recv_timeout(d) {
Ok((msg, is_press)) => {
let msg = match msg {
PyMsg::Char(chr) => {
format!("{}{}", if is_press { 'p' } else { 'r' }, chr)
}
PyMsg::Str(s) => format!("{}{}", if is_press { 'p' } else { 'r' }, s),
};
let n = msg.len();
buf[0] = n as _;
buf[1..(n + 1)].copy_from_slice(msg.as_bytes());
if let Err(err) = conn.write_all(&buf[..n + 1]) {
log::error!("Failed to write to ipc: {}", err);
break;
}
}
Err(err) => match err {
mpsc::RecvTimeoutError::Disconnected => {
log::error!("pynput sender disconnecte");
break;
}
_ => {}
},
}
}
unsafe {
PYNPUT_REDAY = false;
}
break;
}
});
}

View File

@@ -5,18 +5,73 @@ use core_graphics;
use self::core_graphics::display::*;
use self::core_graphics::event::*;
use self::core_graphics::event_source::*;
use std::collections::HashMap as Map;
use std::ffi::c_void;
use std::ffi::CStr;
use std::os::raw::*;
use std::ptr::null_mut;
use crate::macos::keycodes::*;
use crate::{Key, KeyboardControllable, MouseButton, MouseControllable};
use objc::runtime::Class;
struct MyCGEvent;
type TISInputSourceRef = *mut c_void;
type CFDataRef = *const c_void;
type OptionBits = u32;
type OSStatus = i32;
type UniChar = u16;
type UniCharCount = usize;
type Boolean = c_uchar;
type CFStringEncoding = u32;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct __CFString([u8; 0]);
type CFStringRef = *const __CFString;
#[allow(non_upper_case_globals)]
const kCFStringEncodingUTF8: u32 = 134_217_984;
#[allow(non_upper_case_globals)]
const kUCKeyActionDisplay: u16 = 3;
#[allow(non_upper_case_globals)]
const kUCKeyTranslateDeadKeysBit: OptionBits = 1 << 31;
const BUF_LEN: usize = 4;
#[allow(improper_ctypes)]
#[allow(non_snake_case)]
#[link(name = "ApplicationServices", kind = "framework")]
extern "C" {
fn CFDataGetBytePtr(theData: CFDataRef) -> *const u8;
fn TISCopyCurrentKeyboardInputSource() -> TISInputSourceRef;
fn TISCopyCurrentKeyboardLayoutInputSource() -> TISInputSourceRef;
fn TISCopyCurrentASCIICapableKeyboardLayoutInputSource() -> TISInputSourceRef;
static kTISPropertyUnicodeKeyLayoutData: *mut c_void;
static kTISPropertyInputSourceID: *mut c_void;
fn UCKeyTranslate(
keyLayoutPtr: *const u8, //*const UCKeyboardLayout,
virtualKeyCode: u16,
keyAction: u16,
modifierKeyState: u32,
keyboardType: u32,
keyTranslateOptions: OptionBits,
deadKeyState: *mut u32,
maxStringLength: UniCharCount,
actualStringLength: *mut UniCharCount,
unicodeString: *mut [UniChar; BUF_LEN],
) -> OSStatus;
fn LMGetKbdType() -> u8;
fn CFStringGetCString(
theString: CFStringRef,
buffer: *mut c_char,
bufferSize: CFIndex,
encoding: CFStringEncoding,
) -> Boolean;
fn CGEventPost(tapLocation: CGEventTapLocation, event: *mut MyCGEvent);
// Actually return CFDataRef which is const here, but for coding convienence, return *mut c_void
fn TISGetInputSourceProperty(source: TISInputSourceRef, property: *const c_void)
-> *mut c_void;
// not present in servo/core-graphics
fn CGEventCreateScrollWheelEvent(
source: &CGEventSourceRef,
@@ -51,6 +106,7 @@ pub struct Enigo {
last_click_time: Option<std::time::Instant>,
multiple_click: i64,
flags: CGEventFlags,
char_to_vkey_map: Map<String, Map<char, CGKeyCode>>,
}
impl Enigo {
@@ -102,6 +158,7 @@ impl Default for Enigo {
multiple_click: 1,
last_click_time: None,
flags: CGEventFlags::CGEventFlagNull,
char_to_vkey_map: Default::default(),
}
}
}
@@ -433,7 +490,32 @@ impl Enigo {
}
#[inline]
fn map_key_board(&self, ch: char) -> CGKeyCode {
fn map_key_board(&mut self, ch: char) -> CGKeyCode {
let mut code = 0;
unsafe {
let (keyboard, layout) = get_layout();
if !keyboard.is_null() && !layout.is_null() {
let name_ref = TISGetInputSourceProperty(keyboard, kTISPropertyInputSourceID);
if !name_ref.is_null() {
let name = get_string(name_ref as _);
if let Some(name) = name {
if let Some(m) = self.char_to_vkey_map.get(&name) {
code = *m.get(&ch).unwrap_or(&0);
} else {
let m = get_map(&name, layout);
code = *m.get(&ch).unwrap_or(&0);
self.char_to_vkey_map.insert(name.clone(), m);
}
}
}
}
if !keyboard.is_null() {
CFRelease(keyboard);
}
}
if code > 0 {
return code;
}
match ch {
'a' => kVK_ANSI_A,
'b' => kVK_ANSI_B,
@@ -487,4 +569,99 @@ impl Enigo {
}
}
#[inline]
unsafe fn get_string(cf_string: CFStringRef) -> Option<String> {
if !cf_string.is_null() {
let mut buf: [i8; 255] = [0; 255];
let success = CFStringGetCString(
cf_string,
buf.as_mut_ptr(),
buf.len() as _,
kCFStringEncodingUTF8,
);
if success != 0 {
let name: &CStr = CStr::from_ptr(buf.as_ptr());
if let Ok(name) = name.to_str() {
return Some(name.to_string());
}
}
}
None
}
#[inline]
unsafe fn get_layout() -> (TISInputSourceRef, *const u8) {
let mut keyboard = TISCopyCurrentKeyboardInputSource();
let mut layout = null_mut();
if !keyboard.is_null() {
layout = TISGetInputSourceProperty(keyboard, kTISPropertyUnicodeKeyLayoutData);
}
if layout.is_null() {
if !keyboard.is_null() {
CFRelease(keyboard);
}
// https://github.com/microsoft/vscode/issues/23833
keyboard = TISCopyCurrentKeyboardLayoutInputSource();
if !keyboard.is_null() {
layout = TISGetInputSourceProperty(keyboard, kTISPropertyUnicodeKeyLayoutData);
}
}
if layout.is_null() {
if !keyboard.is_null() {
CFRelease(keyboard);
}
keyboard = TISCopyCurrentASCIICapableKeyboardLayoutInputSource();
if !keyboard.is_null() {
layout = TISGetInputSourceProperty(keyboard, kTISPropertyUnicodeKeyLayoutData);
}
}
if layout.is_null() {
if !keyboard.is_null() {
CFRelease(keyboard);
}
return (null_mut(), null_mut());
}
let layout_ptr = CFDataGetBytePtr(layout as _);
if layout_ptr.is_null() {
if !keyboard.is_null() {
CFRelease(keyboard);
}
return (null_mut(), null_mut());
}
(keyboard, layout_ptr)
}
#[inline]
fn get_map(name: &str, layout: *const u8) -> Map<char, CGKeyCode> {
log::info!("Create keyboard map for {}", name);
let mut keys_down: u32 = 0;
let mut map = Map::new();
for keycode in 0..128 {
let mut buff = [0_u16; BUF_LEN];
let kb_type = unsafe { LMGetKbdType() };
let mut length: UniCharCount = 0;
let _retval = unsafe {
UCKeyTranslate(
layout,
keycode,
kUCKeyActionDisplay as _,
0,
kb_type as _,
kUCKeyTranslateDeadKeysBit as _,
&mut keys_down,
BUF_LEN,
&mut length,
&mut buff,
)
};
if length > 0 {
if let Ok(str) = String::from_utf16(&buff[..length]) {
if let Some(chr) = str.chars().next() {
map.insert(chr, keycode as _);
}
}
}
}
map
}
unsafe impl Send for Enigo {}

View File

@@ -16,6 +16,7 @@ extern "system" {
/// The main struct for handling the event emitting
#[derive(Default)]
pub struct Enigo;
static mut LAYOUT: HKL = std::ptr::null_mut();
fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) -> DWORD {
let mut input = INPUT {
@@ -35,6 +36,18 @@ fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) -> DWORD {
}
fn keybd_event(flags: u32, vk: u16, scan: u16) -> DWORD {
let mut scan = scan;
unsafe {
// https://github.com/rustdesk/rustdesk/issues/366
if scan == 0 {
if LAYOUT.is_null() {
let current_window_thread_id =
GetWindowThreadProcessId(GetForegroundWindow(), std::ptr::null_mut());
LAYOUT = GetKeyboardLayout(current_window_thread_id);
}
scan = MapVirtualKeyExW(vk as _, 0, LAYOUT) as _;
}
}
let mut input = INPUT {
type_: INPUT_KEYBOARD,
u: unsafe {
@@ -253,6 +266,9 @@ impl Enigo {
}
fn key_to_keycode(&self, key: Key) -> u16 {
unsafe {
LAYOUT = std::ptr::null_mut();
}
// do not use the codes from crate winapi they're
// wrongly typed with i32 instead of i16 use the
// ones provided by win/keycodes.rs that are prefixed
@@ -347,10 +363,13 @@ impl Enigo {
// get the first char from the string ignore the rest
// ensure its not a multybyte char
if let Some(chr) = string.chars().nth(0) {
// NOTE VkKeyScanW uses the current keyboard layout
// to specify a layout use VkKeyScanExW and GetKeyboardLayout
// NOTE VkKeyScanW uses the current keyboard LAYOUT
// to specify a LAYOUT use VkKeyScanExW and GetKeyboardLayout
// or load one with LoadKeyboardLayoutW
let keycode_and_shiftstate = unsafe { VkKeyScanW(chr as _) };
let current_window_thread_id =
unsafe { GetWindowThreadProcessId(GetForegroundWindow(), std::ptr::null_mut()) };
unsafe { LAYOUT = GetKeyboardLayout(current_window_thread_id) };
let keycode_and_shiftstate = unsafe { VkKeyScanExW(chr as _, LAYOUT) };
keycode_and_shiftstate as _
} else {
0

View File

@@ -29,7 +29,7 @@ dirs-next = "2.0"
filetime = "0.2"
sodiumoxide = "0.2"
regex = "1.4"
tokio-socks = { git = "https://github.com/fufesou/tokio-socks" }
tokio-socks = { git = "https://github.com/open-trade/tokio-socks" }
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
mac_address = "1.1"

View File

@@ -25,6 +25,11 @@ message VideoFrame {
}
}
message IdPk {
string id = 1;
bytes pk = 2;
}
message DisplayInfo {
sint32 x = 1;
sint32 y = 2;
@@ -54,6 +59,7 @@ message LoginRequest {
FileTransfer file_transfer = 7;
PortForward port_forward = 8;
}
bool video_ack_required = 9;
}
message ChatMessage { string text = 1; }
@@ -83,6 +89,7 @@ message MouseEvent {
}
enum ControlKey {
Unknown = 0;
Alt = 1;
Backspace = 2;
CapsLock = 3;
@@ -108,7 +115,7 @@ enum ControlKey {
/// meta key (also known as "windows"; "super"; and "command")
Meta = 23;
/// option key on macOS (alt key on Linux and Windows)
Option = 24;
Option = 24; // deprecated, use Alt instead
PageDown = 25;
PageUp = 26;
Return = 27;
@@ -157,7 +164,7 @@ enum ControlKey {
Divide = 70;
Equals = 71;
NumpadEnter = 72;
RShift= 73;
RShift = 73;
RControl = 74;
RAlt = 75;
CtrlAltDel = 100;
@@ -193,15 +200,15 @@ message CursorPosition {
message Hash {
string salt = 1;
string challenge = 2;
};
}
message Clipboard {
bool compress = 1;
bytes content = 2;
};
}
enum FileType {
Dir = 1;
Dir = 0;
DirLink = 2;
DirDrive = 3;
File = 4;
@@ -304,6 +311,69 @@ message FileDirCreate {
string path = 2;
}
// main logic from freeRDP
message CliprdrMonitorReady {
int32 conn_id = 1;
}
message CliprdrFormat {
int32 conn_id = 1;
int32 id = 2;
string format = 3;
}
message CliprdrServerFormatList {
int32 conn_id = 1;
repeated CliprdrFormat formats = 2;
}
message CliprdrServerFormatListResponse {
int32 conn_id = 1;
int32 msg_flags = 2;
}
message CliprdrServerFormatDataRequest {
int32 conn_id = 1;
int32 requested_format_id = 2;
}
message CliprdrServerFormatDataResponse {
int32 conn_id = 1;
int32 msg_flags = 2;
bytes format_data = 3;
}
message CliprdrFileContentsRequest {
int32 conn_id = 1;
int32 stream_id = 2;
int32 list_index = 3;
int32 dw_flags = 4;
int32 n_position_low = 5;
int32 n_position_high = 6;
int32 cb_requested = 7;
bool have_clip_data_id = 8;
int32 clip_data_id = 9;
}
message CliprdrFileContentsResponse {
int32 conn_id = 1;
int32 msg_flags = 3;
int32 stream_id = 4;
bytes requested_data = 5;
}
message Cliprdr {
oneof union {
CliprdrMonitorReady ready = 1;
CliprdrServerFormatList format_list = 2;
CliprdrServerFormatListResponse format_list_response = 3;
CliprdrServerFormatDataRequest format_data_request = 4;
CliprdrServerFormatDataResponse format_data_response = 5;
CliprdrFileContentsRequest file_contents_request = 6;
CliprdrFileContentsResponse file_contents_response = 7;
}
}
message SwitchDisplay {
int32 display = 1;
sint32 x = 2;
@@ -312,13 +382,14 @@ message SwitchDisplay {
int32 height = 5;
}
enum Permission {
Keyboard = 1;
Clipboard = 2;
Audio = 3;
}
message PermissionInfo {
enum Permission {
Keyboard = 0;
Clipboard = 2;
Audio = 3;
File = 4;
}
Permission permission = 1;
bool enabled = 2;
}
@@ -330,13 +401,12 @@ enum ImageQuality {
Best = 4;
}
enum BoolOption {
NotSet = 0;
No = 1;
Yes = 2;
}
message OptionMessage {
enum BoolOption {
NotSet = 0;
No = 1;
Yes = 2;
}
ImageQuality image_quality = 1;
BoolOption lock_after_session_end = 2;
BoolOption show_remote_cursor = 3;
@@ -345,6 +415,12 @@ message OptionMessage {
int32 custom_image_quality = 6;
BoolOption disable_audio = 7;
BoolOption disable_clipboard = 8;
BoolOption enable_file_transfer = 9;
}
message OptionResponse {
OptionMessage opt = 1;
string error = 2;
}
message TestDelay {
@@ -357,9 +433,7 @@ message PublicKey {
bytes symmetric_value = 2;
}
message SignedId {
bytes id = 1;
}
message SignedId { bytes id = 1; }
message AudioFormat {
uint32 sample_rate = 1;
@@ -377,6 +451,8 @@ message Misc {
AudioFormat audio_format = 8;
string close_reason = 9;
bool refresh_video = 10;
OptionResponse option_response = 11;
bool video_received = 12;
}
}
@@ -399,5 +475,6 @@ message Message {
FileAction file_action = 17;
FileResponse file_response = 18;
Misc misc = 19;
Cliprdr cliprdr = 20;
}
}

View File

@@ -59,7 +59,7 @@ message RegisterPk {
message RegisterPkResponse {
enum Result {
OK = 1;
OK = 0;
UUID_MISMATCH = 2;
ID_EXISTS = 3;
TOO_FREQUENT = 4;
@@ -74,7 +74,7 @@ message PunchHoleResponse {
bytes socket_addr = 1;
bytes pk = 2;
enum Failure {
ID_NOT_EXIST = 1;
ID_NOT_EXIST = 0;
OFFLINE = 2;
LICENSE_MISMATCH = 3;
LICENSE_OVERUSE = 4;
@@ -133,6 +133,16 @@ message LocalAddr {
string version = 5;
}
message PeerDiscovery {
string cmd = 1;
string mac = 2;
string id = 3;
string username = 4;
string hostname = 5;
string platform = 6;
string misc = 7;
}
message RendezvousMessage {
oneof union {
RegisterPeer register_peer = 6;
@@ -151,5 +161,6 @@ message RendezvousMessage {
RelayResponse relay_response = 19;
TestNatRequest test_nat_request = 20;
TestNatResponse test_nat_response = 21;
PeerDiscovery peer_discovery = 22;
}
}

View File

@@ -15,16 +15,14 @@ use std::{
pub const APP_NAME: &str = "RustDesk";
pub const RENDEZVOUS_TIMEOUT: u64 = 12_000;
pub const CONNECT_TIMEOUT: u64 = 18_000;
pub const REG_INTERVAL: i64 = 12_000;
pub const COMPRESS_LEVEL: i32 = 3;
const SERIAL: i32 = 1;
// 128x128
#[cfg(target_os = "macos")] // 128x128 on 160x160 canvas, then shrink to 128, mac looks better with padding
pub const ICON: &str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAyVBMVEUAAAAAcf8Acf8Acf8Acv8Acf8Acf8Acf8Acf8AcP8Acf8Ab/8AcP8Acf////8AaP/z+f/o8v/k7v/5/v/T5f8AYP/u9v/X6f+hx/+Kuv95pP8Aef/B1/+TwP9xoP8BdP/g6P+Irv9ZmP8Bgf/E3f98q/9sn/+01f+Es/9nm/9Jif8hhv8off/M4P+syP+avP86iP/c7f+xy/9yqf9Om/9hk/9Rjv+60P99tv9fpf88lv8yjf8Tgf8deP+kvP8BiP8NeP8hkP80gP8oj2VLAAAADXRSTlMA7o7qLvnaxZ1FOxYPjH9HWgAABHJJREFUeNrtm+tW4jAQgBfwuu7MtIUWsOUiCCioIIgLiqvr+z/UHq/LJKVkmwTcc/r9E2nzlU4mSTP9lpGRkZGR8VX5cZjfL+yCEXYL+/nDH//U/Pd8DgyTy39Xbv7oIAcWyB0cqbW/sweW2NtRaj8H1sgpGOwUIAH7Bkd7YJW9dXFwAJY5WNP/cmCZQnJvzIN18on5LwfWySXlxEPYAIcad8D6PdiHDbCfIFCADVBIENiFDbCbIACKPPXrZ+cP8E6/0znvP4EymgIEravIRcTxu8HxNSJ60a8W0AYECKrlAN+YwAthCd9wm1Ug6wKzIn5SgRduXfwkqDasCjx0XFzi9PV6zwNcIuhcWBOg+ikySq8C9UD4dEKWBCoOcspvAuLHTo9sCDQiFPHotRM48j8G5gVur1FdAN2uaYEuiz7xFsgEJ2RUoMUakXuBTHHoGxQYOBhHjeUBAefEnMAowFhaLBOKuOemBBbxLRQrH2PBCgMvNCPQGMeevTb9zLrPxz2Mo+QbEaijzPUcOOHMQZkKGRAIPem39+bypREMPTkQW/oCfk866zAkiIFG4yIKRE/aAnfiSd0WrORY6pFdXQEqi9mvAQm0RIOSnoCcZ8vJoz3diCnjRk+g8VP4/fuQDJ2Lxr6WwG0gXs9aTpDzW0vgDBlVUpixR8gYk44AD8FrUKHr8JQJGgIDnoDqoALxmWPQSi9AVVzm8gKUuEPGr/QCvptwJkbSYT/TC4S8C96DGjTj86aHtAI0x2WaBIq0eSYYpRa4EsdWVVwWu9O0Aj6f6dyBMnwEraeOgSYu0wZlauzA47QCbT7DgAQSE+hZWoEBF/BBmWOewNMK3BsSqKUW4MGcWqCSVmDkbvkXGKQOwg6PAUO9oL3xXhA20yaiCjuwYygRVQlUOTWTCf2SuNJTxeFjgaHByGuAIvd8ItdPLTDhS7IuqEE1YSKVOgbayLhSFQhMzYh8hwfBs1r7c505YVIQYEdNoKwxK06MJiyrpUFHiF0NAfCQUVHoiRclIXJIR6C2fqG37pBHvcWpgwzvAtYwkR5UGV2e42UISdBJETl3mg8ouo54Rcnti1/vaT+iuUQBt500Cgo4U10BeHSkk57FB0JjWkKRMWgLUA0lLodtImAQdaMiiri3+gIAPZQoutHNsgKF1aaDMhMyIdBf8Th+Bh8MTjGWCpl5Wv43tDmnF+IUVMrcZgRoiAxhtrloYizNkZaAnF5leglbNhj0wYCAbCDvGb0mP4nib7O7ZlcYQ2m1gPtIZgVgGNNMeaVAaWR+57TrqgtUnm3sHQ+kYeE6fufUubG1ez50FXbPnWgBlgSABmN3TTcsRl2yWkHRrwbiunvk/W2+Mg1hPZplPDeXRbZzStFH15s1QIVd3UImP5z/bHpeeQLvRJ7XLFUffQIlCvqlXETQbgN9/rlYABGosv+Vi9m2Xs639YLGrZd0br+odetlvdsvbN56abfd4vbCzv9Q3v/ygoOV21A4OPpfXvH4Ai+5ZGRkZGRkbJA/t/I0QMzoMiEAAAAASUVORK5CYII=
";
#[cfg(windows)] // windows, 32x32, bigger very ugly after shrink
pub const ICON: &str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAolBMVEUAAAAAcf8Acf8Acf8AcP8Acf8Acf8Acf8AcP8Acf/////9/v/7/f+gyv9wr/8Ld/8GdP/A3P+nzv+Qwf9mqv8lhv8UfP+Kvv88k/8zjv/x+P/Y6f/U5//J4f/F3/+x1P+pz/+izP+Cuv9Zov9Qnv9FmP8gg//f7f+42P96tv9fpv8ui//1+f/q8//o8v/Q5f+ax/+Zxv+VxP+Fu/9rrf8rif+x1o3FAAAACXRSTlMAv/RPTPKHioRsIqhAAAABNklEQVQ4y4WT6XaCQAyFB7S2GUD2RaxSKGDV7sv7v1on4djEluL9Ncn5biaZk1FKzSwbRmVbM2V0DRNaGD9Maq6sacBS9jRwpUTw1Ww7SEOvkwQDaeVofQeJ1nrXjgD3pTaqCDCg/xs4OBrlwUGTHvxzoHAx69Y9+Hk5oGdAsCNXSoHfEN1JYEme4KcfvO9WAmtMBNx6jIaCgSPGLbAyvKRhAEcrAxAKTSZiACu+gNSbyWwZeKdQKj91yRXWIOWZTMgATun6EtjgczNQaKMEWD0+xJ6B4AnvECVqdKwYoJ50hIPyw25AANkzpsLB00cYOIUEoHU0uVaQVcMxBwlgVZJ3Orz+3ahH6gP2tBgfYzsZmdo1fGIzRx5Irn2WxKaHeJnKtb/4cS5/PbWACd0oo/n/39/4vwGFYSxtSYV4OAAAAABJRU5ErkJggg==
";
#[cfg(target_os = "linux")] // 128x128 no padding
#[cfg(not(target_os = "macos"))] // 128x128 no padding
pub const ICON: &str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAA7VBMVEUAAAAAcf8Acf8Acf8Adf8Acf8Acf8AcP8Acv8AcP8Acf8Acf8Acf8Acv8Acf8Acf8Ab/8AcP8Acf8Acf8Acf/////7/f8Dc/8TfP/1+f/n8v9Hmf/u9v+Uw//Q5f9hp/8Yfv8Qev8Ld/+52P+z1f+s0f81j/8wjP8Hdf/3+/8mh/8fg//x9//h7//H4P9xsP9rrf9oq/8rif/r9P/D3v+92/+Duv9bpP/d7f/U5/9NnP8/lP8jhP/L4v/B3P+OwP9+t/95tf9Rn/8bgf/Z6v+Zx/90sv9lqf85kf+hy/9UoP+Wxf+kzP+dyP+Lvv/H4q8IAAAAFHRSTlMA+u6bB6x5XR4V0+S4i4k5N+a81W8MiAQAAAVcSURBVHjazdvpWtpAGIbhgEutdW3fL2GHsMsiq4KI+66t5384XahF/GbizJAy3j/1Ah5CJhNCxpm1vbryLRrBfxKJrq+sbjtSa5u7WIDdzTVH5PNSBAsSWfrsMJ+iWKDoJ2fW8hIWbGl55vW/YuE2XhUsb8CCr9OCJVix9G//gyWf/o6/KCyJfrbwAfAPYS0CayK/j4mbsGjrV8AXWLTrONuwasdZhVWrzgqsWnG+wap1Jwqrok4EVkUcmKhdVvBaOVnzYEY/oJpMD4mo6ONF/ZSIUsX2FZjQA7xRqUET+y/v2W/Sy59u62DCDMgdJmhqgIk7eqWQBBNWwPhmj147w8QTzTjKVsGEEBBLuzSrhIkivTF8DD/Aa6forQNMHBD/VyXkgHGfuBN5ALln1TADOnESyGCiT8L/1kILqD6Q0BEm9kkofhdSwNUJiV1jQvZ/SnthBNSaJJGZbgGJUnX+gEqCZPpsJ2T2Y/MGVBrE8eOAvCA/X8A4QXLnmEhTgIPqPAG5IQU4fhmkFOT7HAFenwIU8Jd/TUEODQIUtu1eOj/dUD9cknOTpgEDkup3YrOfVStDUomcWcBVisTiNxVw3TPpgCl4RgFFybZ/9iHmn8uS2yYBA8m7qUEu9oOEejH9gHxC+PazCHbcFM8K+gGHJNAs4z2xgnAkVHQDcnG1IzvnCSfvom7AM3EZ9voah4+KXoAvGFJHMSgqEfegF3BBTKoOVfkMMXFfJ8AT7MuXUDeOE9PWCUiKBpKOlmAP1gngH2LChw7vhJgr9YD8Hnt0BxrE27CtHnDJR4AHTX1+KFAP4Ef0LHTxN9HwlAMSbAjmoavKZ8ayakDXYAhwN3wzqgZk2UPvwRjshmeqATeCT09f3mWnEqoBGf4NxAB/moRqADuOtmDiid6KqQVcsQeOYOKW3uqqBRwL5nITj/yrlFpAVrDpTJT5llQLaLMHwshY7UDgvD+VujDC96WWWsBtSAE5FnChFnAeUkDMdAvw88EqTNT5SYXpTlgPaRQM1AIGorkolNnoUS1gJHigCX48SaoF3Asuspg4Mz0U8+FTgIkCG01V09kwBQP8xG5ofD5AXeirkPEJSUlwSVIfP5ykVQNaggvz+k7prTvVgDKF8BnUXP4kqgEe/257E8Ig7EE1gA8g2stBTz7FLxqrB3SIeYaeQ2IG6gE5l2+Cmt5MGOfP4KsGiH8DOYWOoujnDY2ALHF3810goZFOQDVBTFx9Uj7eI6bp6QTgnLjeGGq6KeJuoRUQixN3pDYWyz1Rva8XIL5UPFQZCsmG3gV7R+dieS+Jd3iHLglce7oBuCOhp3zwHLxPQpfQDvBOSKjZqUIml3ZJ6AD6AajFSZJwewWR8ZPsEY26SQDaJOMeZP23w6bTJ6kBjAJQILm9hzqm7otu4G+nhgGxIQUlPLKzL7GhbxqAboMCuN2XXd+lAL0ajAMwclV+FD6jAPEy5ghAlhfwX2FODX445gHKxyN++fs64PUHmDMAbbYN2DlKk2QaScwdgMs4SZxMv4OJJSoIIQBl2Qtk3gk4qiOUANRPJQHB+0A6j5AC4J27QQEZ4eZPAsYBXFk0N/YD7iUrxRBqALxOTzoMC3x8lCFlfkMjuz8iLfk6fzQCQgjg8q3ZEd8RzUVuKelBh96Nzcc3qelL1V+2zfRv1xc56Ino3tpdPT7cd//MspfTrD/7R6p4W4O2qLMObfnyIHvvYcrPtkZjDybW7d/eb32Bg/UlHnYXuXz5CMt8rC90sr7Uy/5iN+vL/ewveLS/5NNKwcbyR1r2a3/h8wdY+v3L2tZC5oUvW2uO1M7qyvp/Xv6/48z4CTxjJEfyjEaMAAAAAElFTkSuQmCC
";
#[cfg(target_os = "macos")]
@@ -35,6 +33,7 @@ type Size = (i32, i32, i32, i32);
lazy_static::lazy_static! {
static ref CONFIG: Arc<RwLock<Config>> = Arc::new(RwLock::new(Config::load()));
static ref CONFIG2: Arc<RwLock<Config2>> = Arc::new(RwLock::new(Config2::load()));
static ref LOCAL_CONFIG: Arc<RwLock<LocalConfig>> = Arc::new(RwLock::new(LocalConfig::load()));
pub static ref ONLINE: Arc<Mutex<HashMap<String, i64>>> = Default::default();
}
#[cfg(any(target_os = "android", target_os = "ios"))]
@@ -60,7 +59,7 @@ pub enum NetworkType {
ProxySocks,
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub struct Config {
#[serde(default)]
id: String,
@@ -87,12 +86,8 @@ pub struct Socks5Server {
}
// more variable configs
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub struct Config2 {
#[serde(default)]
remote_id: String, // latest used one
#[serde(default)]
size: Size,
#[serde(default)]
rendezvous_server: String,
#[serde(default)]
@@ -138,6 +133,8 @@ pub struct PeerConfig {
pub disable_audio: bool,
#[serde(default)]
pub disable_clipboard: bool,
#[serde(default)]
pub enable_file_transfer: bool,
// the other scalar value must before this
#[serde(default)]
@@ -190,9 +187,23 @@ impl Config2 {
Config::load_::<Config2>("2")
}
pub fn file() -> PathBuf {
Config::file_("2")
}
fn store(&self) {
Config::store_(self, "2");
}
pub fn get() -> Config2 {
return CONFIG2.read().unwrap().clone();
}
pub fn set(cfg: Config2) {
let mut lock = CONFIG2.write().unwrap();
*lock = cfg;
lock.store();
}
}
impl Config {
@@ -272,7 +283,7 @@ impl Config {
}
}
fn path<P: AsRef<Path>>(p: P) -> PathBuf {
pub fn path<P: AsRef<Path>>(p: P) -> PathBuf {
#[cfg(any(target_os = "android", target_os = "ios"))]
{
let mut path: PathBuf = APP_DIR.read().unwrap().clone().into();
@@ -554,9 +565,6 @@ impl Config {
pub fn set_option(k: String, v: String) {
let mut config = CONFIG2.write().unwrap();
if k == "custom-rendezvous-server" {
config.rendezvous_server = "".to_owned();
}
let v2 = if v.is_empty() { None } else { Some(&v) };
if v2 != config.options.get(&k) {
if v2.is_none() {
@@ -613,33 +621,6 @@ impl Config {
salt
}
pub fn get_size() -> Size {
CONFIG2.read().unwrap().size
}
pub fn set_size(x: i32, y: i32, w: i32, h: i32) {
let mut config = CONFIG2.write().unwrap();
let size = (x, y, w, h);
if size == config.size || size.2 < 300 || size.3 < 300 {
return;
}
config.size = size;
config.store();
}
pub fn set_remote_id(remote_id: &str) {
let mut config = CONFIG2.write().unwrap();
if remote_id == config.remote_id {
return;
}
config.remote_id = remote_id.into();
config.store();
}
pub fn get_remote_id() -> String {
CONFIG2.read().unwrap().remote_id.clone()
}
pub fn set_socks(socks: Option<Socks5Server>) {
let mut config = CONFIG2.write().unwrap();
if config.socks == socks {
@@ -659,6 +640,16 @@ impl Config {
Some(_) => NetworkType::ProxySocks,
}
}
pub fn get() -> Config {
return CONFIG.read().unwrap().clone();
}
pub fn set(cfg: Config) {
let mut lock = CONFIG.write().unwrap();
*lock = cfg;
lock.store();
}
}
const PEERS: &str = "peers";
@@ -704,9 +695,7 @@ impl PeerConfig {
&& p.extension().map(|p| p.to_str().unwrap_or("")) == Some("toml")
})
.map(|p| {
let t = fs::metadata(p)
.map(|m| m.modified().unwrap_or(SystemTime::UNIX_EPOCH))
.unwrap_or(SystemTime::UNIX_EPOCH);
let t = crate::get_modified_time(&p);
let id = p
.file_stem()
.map(|p| p.to_str().unwrap_or(""))
@@ -729,29 +718,120 @@ impl PeerConfig {
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct Fav {
pub struct LocalConfig {
#[serde(default)]
pub peers: Vec<String>,
remote_id: String, // latest used one
#[serde(default)]
size: Size,
#[serde(default)]
pub fav: Vec<String>,
#[serde(default)]
options: HashMap<String, String>,
}
impl Fav {
pub fn load() -> Fav {
impl LocalConfig {
fn load() -> LocalConfig {
Config::load_::<LocalConfig>("_local")
}
fn store(&self) {
Config::store_(self, "_local");
}
pub fn get_size() -> Size {
LOCAL_CONFIG.read().unwrap().size
}
pub fn set_size(x: i32, y: i32, w: i32, h: i32) {
let mut config = LOCAL_CONFIG.write().unwrap();
let size = (x, y, w, h);
if size == config.size || size.2 < 300 || size.3 < 300 {
return;
}
config.size = size;
config.store();
}
pub fn set_remote_id(remote_id: &str) {
let mut config = LOCAL_CONFIG.write().unwrap();
if remote_id == config.remote_id {
return;
}
config.remote_id = remote_id.into();
config.store();
}
pub fn get_remote_id() -> String {
LOCAL_CONFIG.read().unwrap().remote_id.clone()
}
pub fn set_fav(fav: Vec<String>) {
let mut lock = LOCAL_CONFIG.write().unwrap();
if lock.fav == fav {
return;
}
lock.fav = fav;
lock.store();
}
pub fn get_fav() -> Vec<String> {
LOCAL_CONFIG.read().unwrap().fav.clone()
}
pub fn get_option(k: &str) -> String {
if let Some(v) = LOCAL_CONFIG.read().unwrap().options.get(k) {
v.clone()
} else {
"".to_owned()
}
}
pub fn set_option(k: String, v: String) {
let mut config = LOCAL_CONFIG.write().unwrap();
let v2 = if v.is_empty() { None } else { Some(&v) };
if v2 != config.options.get(&k) {
if v2.is_none() {
config.options.remove(&k);
} else {
config.options.insert(k, v);
}
config.store();
}
}
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct LanPeers {
#[serde(default)]
pub peers: String,
}
impl LanPeers {
pub fn load() -> LanPeers {
let _ = CONFIG.read().unwrap(); // for lock
match confy::load_path(&Config::file_("_fav")) {
Ok(fav) => fav,
match confy::load_path(&Config::file_("_lan_peers")) {
Ok(peers) => peers,
Err(err) => {
log::error!("Failed to load fav: {}", err);
log::error!("Failed to load lan peers: {}", err);
Default::default()
}
}
}
pub fn store(peers: Vec<String>) {
let f = Fav { peers };
if let Err(err) = confy::store_path(Config::file_("_fav"), f) {
log::error!("Failed to store fav: {}", err);
pub fn store(peers: String) {
let f = LanPeers { peers };
if let Err(err) = confy::store_path(Config::file_("_lan_peers"), f) {
log::error!("Failed to store lan peers: {}", err);
}
}
pub fn modify_time() -> crate::ResultType<u64> {
let p = Config::file_("_lan_peers");
Ok(fs::metadata(p)?
.modified()?
.duration_since(SystemTime::UNIX_EPOCH)?
.as_millis() as _)
}
}
#[cfg(test)]

View File

@@ -302,7 +302,7 @@ impl TransferJob {
}
}
pub async fn write(&mut self, block: FileTransferBlock) -> ResultType<()> {
pub async fn write(&mut self, block: FileTransferBlock, raw: Option<&[u8]>) -> ResultType<()> {
if block.id != self.id {
bail!("Wrong id");
}
@@ -324,15 +324,20 @@ impl TransferJob {
let path = format!("{}.download", get_string(&path));
self.file = Some(File::create(&path).await?);
}
let data = if let Some(data) = raw {
data
} else {
&block.data
};
if block.compressed {
let tmp = decompress(&block.data);
let tmp = decompress(data);
self.file.as_mut().unwrap().write_all(&tmp).await?;
self.finished_size += tmp.len() as u64;
} else {
self.file.as_mut().unwrap().write_all(&block.data).await?;
self.finished_size += block.data.len() as u64;
self.file.as_mut().unwrap().write_all(data).await?;
self.finished_size += data.len() as u64;
}
self.transferred += block.data.len() as u64;
self.transferred += data.len() as u64;
Ok(())
}

View File

@@ -27,6 +27,9 @@ pub use anyhow::{self, bail};
pub use futures_util;
pub mod config;
pub mod fs;
pub use lazy_static;
pub use mac_address;
pub use rand;
pub use regex;
pub use sodiumoxide;
pub use tokio_socks;
@@ -184,6 +187,12 @@ pub fn get_version_number(v: &str) -> i64 {
n
}
pub fn get_modified_time(path: &std::path::Path) -> SystemTime {
std::fs::metadata(&path)
.map(|m| m.modified().unwrap_or(UNIX_EPOCH))
.unwrap_or(UNIX_EPOCH)
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -18,7 +18,7 @@ use tokio_socks::{tcp::Socks5Stream, IntoTargetAddr, ToProxyAddrs};
use tokio_util::codec::Framed;
pub trait TcpStreamTrait: AsyncRead + AsyncWrite + Unpin {}
pub struct DynTcpStream(Box<dyn TcpStreamTrait + Send>);
pub struct DynTcpStream(Box<dyn TcpStreamTrait + Send + Sync>);
pub struct FramedStream(
Framed<DynTcpStream, BytesCodec>,
@@ -42,7 +42,7 @@ impl DerefMut for FramedStream {
}
impl Deref for DynTcpStream {
type Target = Box<dyn TcpStreamTrait + Send>;
type Target = Box<dyn TcpStreamTrait + Send + Sync>;
fn deref(&self) -> &Self::Target {
&self.0
@@ -85,6 +85,7 @@ impl FramedStream {
new_socket(local_addr, true)?.connect(remote_addr),
)
.await??;
stream.set_nodelay(true).ok();
let addr = stream.local_addr()?;
return Ok(Self(
Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
@@ -114,6 +115,7 @@ impl FramedStream {
if let Some(proxy) = proxy.to_proxy_addrs().next().await {
let stream =
super::timeout(ms_timeout, new_socket(local, true)?.connect(proxy?)).await??;
stream.set_nodelay(true).ok();
let stream = if username.trim().is_empty() {
super::timeout(
ms_timeout,
@@ -149,7 +151,7 @@ impl FramedStream {
self.3 = ms;
}
pub fn from(stream: impl TcpStreamTrait + Send + 'static, addr: SocketAddr) -> Self {
pub fn from(stream: impl TcpStreamTrait + Send + Sync + 'static, addr: SocketAddr) -> Self {
Self(
Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
addr,

View File

@@ -84,7 +84,7 @@ impl FramedSocket {
let _ = match self {
Self::Direct(f) => match addr {
TargetAddr::Ip(addr) => f.send((send_data, addr)).await?,
_ => unreachable!(),
_ => {}
},
Self::ProxySocks(f) => f.send((send_data, addr)).await?,
};
@@ -103,7 +103,7 @@ impl FramedSocket {
let _ = match self {
Self::Direct(f) => match addr {
TargetAddr::Ip(addr) => f.send((Bytes::from(msg), addr)).await?,
_ => unreachable!(),
_ => {}
},
Self::ProxySocks(f) => f.send((Bytes::from(msg), addr)).await?,
};

View File

@@ -33,6 +33,7 @@ quest = "0.3"
[build-dependencies]
target_build_utils = "0.3"
bindgen = "0.59"
vcpkg = "0.2"
[target.'cfg(target_os = "linux")'.dependencies]
dbus = { version = "0.9", optional = true }

View File

@@ -4,40 +4,35 @@ use std::{
};
fn find_package(name: &str) -> Vec<PathBuf> {
let vcpkg_root = std::env::var("VCPKG_ROOT").unwrap();
let mut path: PathBuf = vcpkg_root.into();
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
let mut target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
if target_arch == "x86_64" {
target_arch = "x64".to_owned();
} else if target_arch == "aarch64" {
target_arch = "arm64".to_owned();
let library = vcpkg::find_package(name).expect("Failed to find package");
println!("cargo:info={}", library.vcpkg_triplet); //TODO
let lib_name = name.trim_start_matches("lib").to_string();
println!("{}", format!("cargo:rustc-link-lib=static={}", lib_name));
match (
library.link_paths.as_slice(),
library.include_paths.as_slice(),
) {
([link_search, ..], [include, ..]) => {
println!(
"{}",
format!("cargo:rustc-link-search={}", link_search.display())
);
println!("{}", format!("cargo:include={}", include.display()));
}
_ => {
panic!(
"{}",
if library.link_paths.is_empty() {
"link path not found"
} else {
"include path not found"
}
)
}
}
let mut target = if target_os == "macos" {
"x64-osx".to_owned()
} else if target_os == "windows" {
"x64-windows-static".to_owned()
} else {
format!("{}-{}", target_arch, target_os)
};
if target_arch == "x86" {
target = target.replace("x64", "x86");
}
println!("cargo:info={}", target);
path.push("installed");
path.push(target);
let lib = name.trim_start_matches("lib").to_string();
println!("{}", format!("cargo:rustc-link-lib=static={}", lib));
println!(
"{}",
format!(
"cargo:rustc-link-search={}",
path.join("lib").to_str().unwrap()
)
);
let include = path.join("include");
println!("{}", format!("cargo:include={}", include.to_str().unwrap()));
vec![include]
library.include_paths
}
fn generate_bindings(

View File

@@ -36,6 +36,19 @@ extern "C" {
height: c_int,
) -> c_int;
pub fn ABGRToI420(
src_rgba: *const u8,
src_stride_rgba: c_int,
dst_y: *mut u8,
dst_stride_y: c_int,
dst_u: *mut u8,
dst_stride_u: c_int,
dst_v: *mut u8,
dst_stride_v: c_int,
width: c_int,
height: c_int,
) -> c_int;
pub fn NV12ToI420(
src_y: *const u8,
src_stride_y: c_int,
@@ -134,8 +147,7 @@ pub fn i420_to_rgb(width: usize, height: usize, src: &[u8], dst: &mut Vec<u8>) {
pub fn bgra_to_i420(width: usize, height: usize, src: &[u8], dst: &mut Vec<u8>) {
let (_, h, dst_stride_y, dst_stride_uv, u, v) =
get_vpx_i420_stride(width, height, super::STRIDE_ALIGN);
let bps = 12;
dst.resize(h * dst_stride_y * bps / 8, 0);
dst.resize(h * dst_stride_y * 2, 0); // waste some memory to ensure memory safety
let dst_y = dst.as_mut_ptr();
let dst_u = dst[u..].as_mut_ptr();
let dst_v = dst[v..].as_mut_ptr();
@@ -155,6 +167,29 @@ pub fn bgra_to_i420(width: usize, height: usize, src: &[u8], dst: &mut Vec<u8>)
}
}
pub fn rgba_to_i420(width: usize, height: usize, src: &[u8], dst: &mut Vec<u8>) {
let (_, h, dst_stride_y, dst_stride_uv, u, v) =
get_vpx_i420_stride(width, height, super::STRIDE_ALIGN);
dst.resize(h * dst_stride_y * 2, 0); // waste some memory to ensure memory safety
let dst_y = dst.as_mut_ptr();
let dst_u = dst[u..].as_mut_ptr();
let dst_v = dst[v..].as_mut_ptr();
unsafe {
ABGRToI420(
src.as_ptr(),
(src.len() / height) as _,
dst_y,
dst_stride_y as _,
dst_u,
dst_stride_uv as _,
dst_v,
dst_stride_uv as _,
width as _,
height as _,
);
}
}
pub unsafe fn nv12_to_i420(
src_y: *const u8,
src_stride_y: c_int,
@@ -164,10 +199,9 @@ pub unsafe fn nv12_to_i420(
height: usize,
dst: &mut Vec<u8>,
) {
let (w, h, dst_stride_y, dst_stride_uv, u, v) =
let (_, h, dst_stride_y, dst_stride_uv, u, v) =
get_vpx_i420_stride(width, height, super::STRIDE_ALIGN);
let bps = 12;
dst.resize(h * w * bps / 8, 0);
dst.resize(h * dst_stride_y * 2, 0); // waste some memory to ensure memory safety
let dst_y = dst.as_mut_ptr();
let dst_u = dst[u..].as_mut_ptr();
let dst_v = dst[v..].as_mut_ptr();

View File

@@ -27,6 +27,19 @@ cfg_if! {
pub mod codec;
mod convert;
pub use self::convert::*;
pub const STRIDE_ALIGN: usize = 16; // commonly used in libvpx vpx_img_alloc caller
pub const STRIDE_ALIGN: usize = 64; // commonly used in libvpx vpx_img_alloc caller
mod vpx;
#[inline]
pub fn would_block_if_equal(old: &mut Vec<u128>, b: &[u8]) -> std::io::Result<()> {
let b = unsafe {
std::slice::from_raw_parts::<u128>(b.as_ptr() as _, b.len() / 16)
};
if b == &old[..] {
return Err(std::io::ErrorKind::WouldBlock.into());
}
old.resize(b.len(), 0);
old.copy_from_slice(b);
Ok(())
}

View File

@@ -8,6 +8,7 @@ pub struct Capturer {
frame: Arc<Mutex<Option<quartz::Frame>>>,
use_yuv: bool,
i420: Vec<u8>,
saved_raw_data: Vec<u128>, // for faster compare and copy
}
impl Capturer {
@@ -20,7 +21,7 @@ impl Capturer {
display.width(),
display.height(),
if use_yuv {
quartz::PixelFormat::YCbCr420Full
quartz::PixelFormat::YCbCr420Video
} else {
quartz::PixelFormat::Argb8888
},
@@ -38,6 +39,7 @@ impl Capturer {
frame,
use_yuv,
i420: Vec::new(),
saved_raw_data: Vec::new(),
})
}
@@ -57,6 +59,7 @@ impl Capturer {
match frame {
Some(mut frame) => {
crate::would_block_if_equal(&mut self.saved_raw_data, frame.inner())?;
if self.use_yuv {
frame.nv12_to_i420(self.width(), self.height(), &mut self.i420);
}

View File

@@ -17,7 +17,7 @@ impl Capturer {
}
pub fn frame<'a>(&'a mut self, _timeout_ms: u32) -> io::Result<Frame<'a>> {
Ok(Frame(self.0.frame()))
Ok(Frame(self.0.frame()?))
}
}

View File

@@ -49,6 +49,7 @@ pub struct Capturer {
rotated: Vec<u8>,
gdi_capturer: Option<CapturerGDI>,
gdi_buffer: Vec<u8>,
saved_raw_data: Vec<u128>, // for faster compare and copy
}
impl Capturer {
@@ -150,6 +151,7 @@ impl Capturer {
rotated: Vec::new(),
gdi_capturer,
gdi_buffer: Vec::new(),
saved_raw_data: Vec::new(),
})
}
@@ -233,7 +235,13 @@ impl Capturer {
let result = {
if let Some(gdi_capturer) = &self.gdi_capturer {
match gdi_capturer.frame(&mut self.gdi_buffer) {
Ok(_) => &self.gdi_buffer,
Ok(_) => {
crate::would_block_if_equal(
&mut self.saved_raw_data,
&self.gdi_buffer,
)?;
&self.gdi_buffer
}
Err(err) => {
return Err(io::Error::new(io::ErrorKind::Other, err.to_string()));
}

View File

@@ -29,10 +29,12 @@ impl Frame {
}
}
#[inline]
pub fn inner(&self) -> &[u8] {
self.inner
}
pub fn nv12_to_i420<'a>(&'a mut self, w: usize, h: usize, i420: &'a mut Vec<u8>) {
if self.inner.is_empty() {
return;
}
unsafe {
let plane0 = IOSurfaceGetBaseAddressOfPlane(self.surface, 0);
let stride0 = IOSurfaceGetBytesPerRowOfPlane(self.surface, 0);

View File

@@ -14,6 +14,7 @@ pub struct Capturer {
size: usize,
use_yuv: bool,
yuv: Vec<u8>,
saved_raw_data: Vec<u128>, // for faster compare and copy
}
impl Capturer {
@@ -68,6 +69,7 @@ impl Capturer {
size,
use_yuv,
yuv: Vec::new(),
saved_raw_data: Vec::new(),
};
Ok(c)
}
@@ -97,15 +99,16 @@ impl Capturer {
}
}
pub fn frame<'b>(&'b mut self) -> &'b [u8] {
pub fn frame<'b>(&'b mut self) -> std::io::Result<&'b [u8]> {
self.get_image();
let result = unsafe { slice::from_raw_parts(self.buffer, self.size) };
if self.use_yuv {
crate::would_block_if_equal(&mut self.saved_raw_data, result)?;
Ok(if self.use_yuv {
crate::common::bgra_to_i420(self.display.w(), self.display.h(), &result, &mut self.yuv);
&self.yuv[..]
} else {
result
}
})
}
}

View File

@@ -0,0 +1,16 @@
[package]
name = "virtual_display"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
cc = "1.0"
[dependencies]
thiserror = "1.0.30"
lazy_static = "1.4"
serde = "1.0"
serde_derive = "1.0"
hbb_common = { path = "../hbb_common" }

View File

@@ -0,0 +1,32 @@
# virtual display
Virtual display may be used on computers that do not have a monitor.
[Development reference](https://github.com/pavlobu/deskreen/discussions/86)
## windows
### win10
Win10 provides [Indirect Display Driver Model](https://msdn.microsoft.com/en-us/library/windows/hardware/mt761968(v=vs.85).aspx).
This lib uses [this project](https://github.com/fufesou/RustDeskIddDriver) as the driver.
**NOTE**: Versions before Win10 1607. Try follow [this method](https://github.com/fanxiushu/xdisp_virt/tree/master/indirect_display).
#### tested platforms
- [x] 19041
- [x] 19043
### win7
TODO
[WDDM](https://docs.microsoft.com/en-us/windows-hardware/drivers/display/windows-vista-display-driver-model-design-guide).
## X11
## OSX

View File

@@ -0,0 +1,35 @@
use cc;
fn build_c_impl() {
let mut build = cc::Build::new();
#[cfg(target_os = "windows")]
build.file("src/win10/IddController.c");
build.flag_if_supported("-Wno-c++0x-extensions");
build.flag_if_supported("-Wno-return-type-c-linkage");
build.flag_if_supported("-Wno-invalid-offsetof");
build.flag_if_supported("-Wno-unused-parameter");
if build.get_compiler().is_like_msvc() {
build.define("WIN32", "");
build.flag("-Zi");
build.flag("-GR-");
// build.flag("-std:c++11");
} else {
build.flag("-fPIC");
// build.flag("-std=c++11");
// build.flag("-include");
// build.flag(&confdefs_path.to_string_lossy());
}
#[cfg(target_os = "windows")]
build.compile("xxx");
#[cfg(target_os = "windows")]
println!("cargo:rerun-if-changed=src/win10/IddController.c");
}
fn main() {
build_c_impl();
}

View File

@@ -0,0 +1,138 @@
#[cfg(windows)]
use virtual_display::win10::{idd, DRIVER_INSTALL_PATH};
use std::{
ffi::{CStr, CString},
io::{self, Read},
path::Path,
};
fn prompt_input() -> u8 {
println!("Press key execute:");
println!(" 1. 'x' 1. exit");
println!(" 2. 'i' 2. install or update driver");
println!(" 3. 'u' 3. uninstall driver");
println!(" 4. 'c' 4. create device");
println!(" 5. 'd' 5. destroy device");
println!(" 6. '1','2','3' 6. plug in monitor 0,1,2");
println!(" 7. '4','5','6' 7. plug out monitor 0,1,2");
io::stdin()
.bytes()
.next()
.and_then(|result| result.ok())
.unwrap_or(0)
}
unsafe fn plug_in(index: idd::UINT, edid: idd::UINT) {
println!("Plug in monitor begin");
if idd::FALSE == idd::MonitorPlugIn(index, edid, 25) {
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
} else {
println!("Plug in monitor done");
let mut modes: Vec<idd::MonitorMode> = Vec::new();
modes.push(idd::MonitorMode {
width: 1920 as idd::DWORD,
height: 1080 as idd::DWORD,
sync: 60 as idd::DWORD,
});
modes.push(idd::MonitorMode {
width: 1024 as idd::DWORD,
height: 768 as idd::DWORD,
sync: 60 as idd::DWORD,
});
if idd::FALSE == idd::MonitorModesUpdate(index, modes.len() as u32, modes.as_mut_ptr()) {
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
}
}
}
unsafe fn plug_out(index: idd::UINT) {
println!("Plug out monitor begin");
if idd::FALSE == idd::MonitorPlugOut(index) {
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
} else {
println!("Plug out monitor done");
}
}
fn main() {
let abs_path = Path::new(DRIVER_INSTALL_PATH).canonicalize().unwrap();
let full_inf_path = abs_path.to_str().unwrap();
unsafe {
let invalid_device = 0 as idd::HSWDEVICE;
let mut h_sw_device = invalid_device;
let full_inf_path = CString::new(full_inf_path).unwrap().into_raw();
loop {
match prompt_input() as char {
'x' => break,
'i' => {
println!("Install or update driver begin");
let mut reboot_required = idd::FALSE;
if idd::InstallUpdate(full_inf_path, &mut reboot_required) == idd::FALSE {
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
} else {
println!(
"Install or update driver done, reboot is {} required",
if reboot_required == idd::FALSE {
"not"
} else {
""
}
);
}
}
'u' => {
println!("Uninstall driver begin");
let mut reboot_required = idd::FALSE;
if idd::Uninstall(full_inf_path, &mut reboot_required) == idd::FALSE {
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
} else {
println!(
"Uninstall driver done, reboot is {} required",
if reboot_required == idd::FALSE {
"not"
} else {
""
}
);
}
}
'c' => {
println!("Create device begin");
if h_sw_device != invalid_device {
println!("Device created before");
continue;
}
if idd::FALSE == idd::DeviceCreate(&mut h_sw_device) {
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
idd::DeviceClose(h_sw_device);
h_sw_device = invalid_device;
} else {
println!("Create device done");
}
}
'd' => {
println!("Close device begin");
idd::DeviceClose(h_sw_device);
h_sw_device = invalid_device;
println!("Close device done");
}
'1' => plug_in(0, 0),
'2' => plug_in(1, 0),
'3' => plug_in(2, 0),
'4' => plug_out(0),
'5' => plug_out(1),
'6' => plug_out(2),
_ => {}
}
}
if !full_inf_path.is_null() {
let _ = CString::from_raw(full_inf_path);
}
idd::DeviceClose(h_sw_device);
}
}

View File

@@ -0,0 +1,89 @@
use std::io::{self, Read};
use virtual_display;
fn prompt_input() -> u8 {
println!("Press key execute:");
println!(" 1. 'x' 1. exit");
println!(" 2. 'i' 2. install or update driver");
println!(" 3. 'u' 3. uninstall driver");
println!(" 4. 'c' 4. create device");
println!(" 5. 'd' 5. destroy device");
println!(" 6. '1' 6. plug in monitor 0,1,2");
println!(" 7. '4' 7. plug out monitor 0,1,2");
io::stdin()
.bytes()
.next()
.and_then(|result| result.ok())
.unwrap_or(0)
}
fn plug_in() {
println!("Plug in monitor begin");
if let Err(e) = virtual_display::plug_in_monitor() {
println!("{}", e);
} else {
println!("Plug in monitor done");
}
}
fn plug_out() {
println!("Plug out monitor begin");
if let Err(e) = virtual_display::plug_out_monitor() {
println!("{}", e);
} else {
println!("Plug out monitor done");
}
}
fn main() {
loop {
match prompt_input() as char {
'x' => break,
'i' => {
println!("Install or update driver begin");
let mut reboot_required = false;
if let Err(e) = virtual_display::install_update_driver(&mut reboot_required) {
println!("{}", e);
} else {
println!(
"Install or update driver done, reboot is {} required",
if reboot_required { "" } else { "not" }
);
}
}
'u' => {
println!("Uninstall driver begin");
let mut reboot_required = false;
if let Err(e) = virtual_display::uninstall_driver(&mut reboot_required) {
println!("{}", e);
} else {
println!(
"Uninstall driver done, reboot is {} required",
if reboot_required { "" } else { "not" }
);
}
}
'c' => {
println!("Create device begin");
if virtual_display::is_device_created() {
println!("Device created before");
continue;
}
if let Err(e) = virtual_display::create_device() {
println!("{}", e);
} else {
println!("Create device done");
}
}
'd' => {
println!("Close device begin");
virtual_display::close_device();
println!("Close device done");
}
'1' => plug_in(),
'4' => plug_out(),
_ => {}
}
}
}

View File

@@ -0,0 +1,182 @@
#[cfg(windows)]
pub mod win10;
use hbb_common::{bail, lazy_static, ResultType};
use std::{ffi::CString, path::Path, sync::Mutex};
lazy_static::lazy_static! {
// If device is uninstalled though "Device Manager" Window.
// Rustdesk is unable to handle device any more...
static ref H_SW_DEVICE: Mutex<u64> = Mutex::new(0);
static ref MONITOR_PLUGIN: Mutex<Vec<u32>> = Mutex::new(Vec::new());
}
pub fn download_driver() -> ResultType<()> {
#[cfg(windows)]
let _download_url = win10::DRIVER_DOWNLOAD_URL;
#[cfg(target_os = "linux")]
let _download_url = "";
// process download and report progress
Ok(())
}
pub fn install_update_driver(_reboot_required: &mut bool) -> ResultType<()> {
#[cfg(windows)]
let install_path = win10::DRIVER_INSTALL_PATH;
#[cfg(not(windows))]
let install_path = "";
let abs_path = Path::new(install_path).canonicalize()?;
if !abs_path.exists() {
bail!("{} not exists", install_path)
}
let _full_install_path = match abs_path.to_str() {
Some(p) => CString::new(p)?.into_raw(),
None => bail!("{} not exists", install_path),
};
#[cfg(windows)]
unsafe {
{
let mut reboot_required_tmp = win10::idd::FALSE;
if win10::idd::InstallUpdate(_full_install_path, &mut reboot_required_tmp)
== win10::idd::FALSE
{
bail!("{}", win10::get_last_msg()?);
}
*_reboot_required = reboot_required_tmp == win10::idd::TRUE;
}
}
Ok(())
}
pub fn uninstall_driver(_reboot_required: &mut bool) -> ResultType<()> {
#[cfg(windows)]
let install_path = win10::DRIVER_INSTALL_PATH;
#[cfg(not(windows))]
let install_path = "";
let abs_path = Path::new(install_path).canonicalize()?;
if !abs_path.exists() {
bail!("{} not exists", install_path)
}
let _full_install_path = match abs_path.to_str() {
Some(p) => CString::new(p)?.into_raw(),
None => bail!("{} not exists", install_path),
};
#[cfg(windows)]
unsafe {
{
let mut reboot_required_tmp = win10::idd::FALSE;
if win10::idd::Uninstall(_full_install_path, &mut reboot_required_tmp)
== win10::idd::FALSE
{
bail!("{}", win10::get_last_msg()?);
}
*_reboot_required = reboot_required_tmp == win10::idd::TRUE;
}
}
Ok(())
}
pub fn is_device_created() -> bool {
#[cfg(windows)]
return *H_SW_DEVICE.lock().unwrap() != 0;
#[cfg(not(windows))]
return false;
}
pub fn create_device() -> ResultType<()> {
if is_device_created() {
return Ok(());
}
#[cfg(windows)]
unsafe {
let mut lock_device = H_SW_DEVICE.lock().unwrap();
let mut h_sw_device = *lock_device as win10::idd::HSWDEVICE;
if win10::idd::DeviceCreate(&mut h_sw_device) == win10::idd::FALSE {
bail!("{}", win10::get_last_msg()?);
} else {
*lock_device = h_sw_device as u64;
}
}
Ok(())
}
pub fn close_device() {
#[cfg(windows)]
unsafe {
win10::idd::DeviceClose(*H_SW_DEVICE.lock().unwrap() as win10::idd::HSWDEVICE);
*H_SW_DEVICE.lock().unwrap() = 0;
MONITOR_PLUGIN.lock().unwrap().clear();
}
}
pub fn plug_in_monitor() -> ResultType<()> {
#[cfg(windows)]
unsafe {
let monitor_index = 0 as u32;
let mut plug_in_monitors = MONITOR_PLUGIN.lock().unwrap();
for i in 0..plug_in_monitors.len() {
if let Some(d) = plug_in_monitors.get(i) {
if *d == monitor_index {
return Ok(());
}
};
}
if win10::idd::MonitorPlugIn(monitor_index, 0, 30) == win10::idd::FALSE {
bail!("{}", win10::get_last_msg()?);
}
(*plug_in_monitors).push(monitor_index);
}
Ok(())
}
pub fn plug_out_monitor() -> ResultType<()> {
#[cfg(windows)]
unsafe {
let monitor_index = 0 as u32;
if win10::idd::MonitorPlugOut(monitor_index) == win10::idd::FALSE {
bail!("{}", win10::get_last_msg()?);
}
let mut plug_in_monitors = MONITOR_PLUGIN.lock().unwrap();
for i in 0..plug_in_monitors.len() {
if let Some(d) = plug_in_monitors.get(i) {
if *d == monitor_index {
plug_in_monitors.remove(i);
break;
}
};
}
}
Ok(())
}
pub fn update_monitor_modes() -> ResultType<()> {
#[cfg(windows)]
unsafe {
let monitor_index = 0 as u32;
let mut modes = vec![win10::idd::MonitorMode {
width: 1920,
height: 1080,
sync: 60,
}];
if win10::idd::FALSE
== win10::idd::MonitorModesUpdate(
monitor_index as win10::idd::UINT,
modes.len() as win10::idd::UINT,
modes.as_mut_ptr(),
)
{
bail!("{}", win10::get_last_msg()?);
}
}
Ok(())
}

View File

@@ -0,0 +1,784 @@
#include "./IddController.h"
#include <stdio.h>
#include <stdlib.h>
#include <newdev.h>
#include <swdevice.h>
#include <strsafe.h>
#include <cfgmgr32.h>
#include <combaseapi.h>
#include "./Public.h"
const GUID GUID_DEVINTERFACE_IDD_DRIVER_DEVICE = \
{ 0x781EF630, 0x72B2, 0x11d2, { 0xB8, 0x52, 0x00, 0xC0, 0x4E, 0xAF, 0x52, 0x72 } };
//{781EF630-72B2-11d2-B852-00C04EAF5272}
BOOL g_printMsg = TRUE;
char g_lastMsg[1024];
const char* g_msgHeader = "RustDeskIdd: ";
VOID WINAPI
CreationCallback(
_In_ HSWDEVICE hSwDevice,
_In_ HRESULT hrCreateResult,
_In_opt_ PVOID pContext,
_In_opt_ PCWSTR pszDeviceInstanceId
);
// https://github.com/microsoft/Windows-driver-samples/blob/9f03207ae1e8df83325f067de84494ae55ab5e97/general/DCHU/osrfx2_DCHU_base/osrfx2_DCHU_testapp/testapp.c#L88
// Not a good way for this device, I don't not why. I'm not familiar with dirver.
BOOLEAN GetDevicePath(
_In_ LPCGUID InterfaceGuid,
_Out_writes_(BufLen) PTCHAR DevicePath,
_In_ size_t BufLen
);
// https://github.com/microsoft/Windows-driver-samples/blob/9f03207ae1e8df83325f067de84494ae55ab5e97/usb/umdf_fx2/exe/testapp.c#L90
// Works good to check whether device is created before.
BOOLEAN GetDevicePath2(
_In_ LPCGUID InterfaceGuid,
_Out_writes_(BufLen) PTCHAR DevicePath,
_In_ size_t BufLen
);
HANDLE DeviceOpenHandle();
VOID DeviceCloseHandle(HANDLE handle);
void SetLastMsg(const char* format, ...)
{
memset(g_lastMsg, 0, sizeof(g_lastMsg));
memcpy_s(g_lastMsg, sizeof(g_lastMsg), g_msgHeader, strlen(g_msgHeader));
va_list args;
va_start(args, format);
vsnprintf_s(
g_lastMsg + strlen(g_msgHeader),
sizeof(g_lastMsg) - strlen(g_msgHeader),
_TRUNCATE,
format,
args);
va_end(args);
}
const char* GetLastMsg()
{
return g_lastMsg;
}
BOOL InstallUpdate(LPCTSTR fullInfPath, PBOOL rebootRequired)
{
SetLastMsg("Sucess");
// UpdateDriverForPlugAndPlayDevices may return FALSE while driver was successfully installed...
if (FALSE == UpdateDriverForPlugAndPlayDevices(
NULL,
_T("RustDeskIddDriver"), // match hardware id in the inf file
fullInfPath,
INSTALLFLAG_FORCE
// | INSTALLFLAG_NONINTERACTIVE // INSTALLFLAG_NONINTERACTIVE may cause error 0xe0000247
,
rebootRequired
))
{
DWORD error = GetLastError();
if (error != 0)
{
SetLastMsg("UpdateDriverForPlugAndPlayDevices failed, last error 0x%x\n", error);
if (g_printMsg)
{
printf(g_lastMsg);
}
return FALSE;
}
}
return TRUE;
}
BOOL Uninstall(LPCTSTR fullInfPath, PBOOL rebootRequired)
{
SetLastMsg("Sucess");
if (FALSE == DiUninstallDriver(
NULL,
fullInfPath,
0,
rebootRequired
))
{
DWORD error = GetLastError();
if (error != 0)
{
SetLastMsg("DiUninstallDriver failed, last error 0x%x\n", error);
if (g_printMsg)
{
printf(g_lastMsg);
}
return FALSE;
}
}
return TRUE;
}
BOOL IsDeviceCreated(PBOOL created)
{
SetLastMsg("Sucess");
HDEVINFO hardwareDeviceInfo = SetupDiGetClassDevs(
&GUID_DEVINTERFACE_IDD_DRIVER_DEVICE,
NULL, // Define no enumerator (global)
NULL, // Define no
(DIGCF_PRESENT | // Only Devices present
DIGCF_DEVICEINTERFACE)); // Function class devices.
if (INVALID_HANDLE_VALUE == hardwareDeviceInfo)
{
SetLastMsg("Idd device: SetupDiGetClassDevs failed, last error 0x%x\n", GetLastError());
if (g_printMsg)
{
printf(g_lastMsg);
}
return FALSE;
}
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
BOOL ret = FALSE;
do
{
if (TRUE == SetupDiEnumDeviceInterfaces(hardwareDeviceInfo,
0, // No care about specific PDOs
&GUID_DEVINTERFACE_IDD_DRIVER_DEVICE,
0, //
&deviceInterfaceData))
{
*created = TRUE;
ret = TRUE;
break;
}
DWORD error = GetLastError();
if (error == ERROR_NO_MORE_ITEMS)
{
*created = FALSE;
ret = TRUE;
break;
}
SetLastMsg("Idd device: SetupDiEnumDeviceInterfaces failed, last error 0x%x\n", error);
if (g_printMsg)
{
printf(g_lastMsg);
}
ret = FALSE;
break;
} while (0);
(VOID)SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
return ret;
}
BOOL DeviceCreate(PHSWDEVICE hSwDevice)
{
SetLastMsg("Sucess");
if (*hSwDevice != NULL)
{
SetLastMsg("Device handler is not NULL\n");
return FALSE;
}
BOOL created = TRUE;
if (FALSE == IsDeviceCreated(&created))
{
return FALSE;
}
if (created == TRUE)
{
SetLastMsg("Device is created before, please uninstall it first\n");
if (g_printMsg)
{
printf(g_lastMsg);
}
return FALSE;
}
// create device
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hEvent == INVALID_HANDLE_VALUE || hEvent == NULL)
{
DWORD error = GetLastError();
SetLastMsg("CreateEvent failed 0x%lx\n", error);
if (g_printMsg)
{
printf(g_lastMsg);
}
return FALSE;
}
SW_DEVICE_CREATE_INFO createInfo = { 0 };
PCWSTR description = L"RustDesk Idd Driver";
// These match the Pnp id's in the inf file so OS will load the driver when the device is created
PCWSTR instanceId = L"RustDeskIddDriver";
PCWSTR hardwareIds = L"RustDeskIddDriver\0\0";
PCWSTR compatibleIds = L"RustDeskIddDriver\0\0";
createInfo.cbSize = sizeof(createInfo);
createInfo.pszzCompatibleIds = compatibleIds;
createInfo.pszInstanceId = instanceId;
createInfo.pszzHardwareIds = hardwareIds;
createInfo.pszDeviceDescription = description;
createInfo.CapabilityFlags = SWDeviceCapabilitiesRemovable |
SWDeviceCapabilitiesSilentInstall |
SWDeviceCapabilitiesDriverRequired;
// Create the device
HRESULT hr = SwDeviceCreate(L"RustDeskIddDriver",
L"HTREE\\ROOT\\0",
&createInfo,
0,
NULL,
CreationCallback,
&hEvent,
hSwDevice);
if (FAILED(hr))
{
SetLastMsg("SwDeviceCreate failed with 0x%lx\n", hr);
if (g_printMsg)
{
printf(g_lastMsg);
}
return FALSE;
}
// Wait for callback to signal that the device has been created
printf("Waiting for device to be created....\n");
DWORD waitResult = WaitForSingleObject(hEvent, 10 * 1000);
if (waitResult != WAIT_OBJECT_0)
{
SetLastMsg("Wait for device creation failed 0x%d\n", waitResult);
if (g_printMsg)
{
printf(g_lastMsg);
}
return FALSE;
}
// printf("Device created\n\n");
return TRUE;
}
VOID DeviceClose(HSWDEVICE hSwDevice)
{
SetLastMsg("Sucess");
if (hSwDevice != INVALID_HANDLE_VALUE && hSwDevice != NULL)
{
SwDeviceClose(hSwDevice);
}
}
BOOL MonitorPlugIn(UINT index, UINT edid, INT retries)
{
SetLastMsg("Sucess");
if (retries < 0)
{
SetLastMsg("invalid tries %d\n", retries);
if (g_printMsg)
{
printf(g_lastMsg);
}
return FALSE;
}
HANDLE hDevice = INVALID_HANDLE_VALUE;
for (; retries >= 0; --retries)
{
hDevice = DeviceOpenHandle();
if (hDevice != INVALID_HANDLE_VALUE && hDevice != NULL)
{
break;
}
Sleep(1000);
}
if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
{
return FALSE;
}
BOOL ret = FALSE;
DWORD junk = 0;
CtlPlugIn plugIn;
plugIn.ConnectorIndex = index;
plugIn.MonitorEDID = edid;
HRESULT hr = CoCreateGuid(&plugIn.ContainerId);
if (!SUCCEEDED(hr))
{
SetLastMsg("CoCreateGuid failed %d\n", hr);
if (g_printMsg)
{
printf(g_lastMsg);
}
ret = FALSE;
}
else
{
ret = FALSE;
for (; retries >= 0; --retries)
{
if (TRUE == DeviceIoControl(
hDevice,
IOCTL_CHANGER_IDD_PLUG_IN,
&plugIn, // Ptr to InBuffer
sizeof(CtlPlugIn), // Length of InBuffer
NULL, // Ptr to OutBuffer
0, // Length of OutBuffer
&junk, // BytesReturned
0)) // Ptr to Overlapped structure
{
ret = TRUE;
break;
}
}
if (ret == FALSE)
{
DWORD error = GetLastError();
SetLastMsg("DeviceIoControl failed 0x%lx\n", error);
printf(g_lastMsg);
}
}
DeviceCloseHandle(hDevice);
return ret;
}
BOOL MonitorPlugOut(UINT index)
{
SetLastMsg("Sucess");
HANDLE hDevice = DeviceOpenHandle();
if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
{
return FALSE;
}
BOOL ret = FALSE;
DWORD junk = 0;
CtlPlugOut plugOut;
plugOut.ConnectorIndex = index;
if (!DeviceIoControl(
hDevice,
IOCTL_CHANGER_IDD_PLUG_OUT,
&plugOut, // Ptr to InBuffer
sizeof(CtlPlugOut), // Length of InBuffer
NULL, // Ptr to OutBuffer
0, // Length of OutBuffer
&junk, // BytesReturned
0)) // Ptr to Overlapped structure
{
DWORD error = GetLastError();
SetLastMsg("DeviceIoControl failed 0x%lx\n", error);
if (g_printMsg)
{
printf(g_lastMsg);
}
ret = FALSE;
}
else
{
ret = TRUE;
}
DeviceCloseHandle(hDevice);
return ret;
}
BOOL MonitorModesUpdate(UINT index, UINT modeCount, PMonitorMode modes)
{
SetLastMsg("Sucess");
HANDLE hDevice = DeviceOpenHandle();
if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
{
return FALSE;
}
BOOL ret = FALSE;
DWORD junk = 0;
size_t buflen = sizeof(UINT) * 2 + modeCount * sizeof(MonitorMode);
PCtlMonitorModes pMonitorModes = (PCtlMonitorModes)malloc(buflen);
if (pMonitorModes == NULL)
{
SetLastMsg("CtlMonitorModes malloc failed 0x%lx\n");
if (g_printMsg)
{
printf(g_lastMsg);
}
return FALSE;
}
pMonitorModes->ConnectorIndex = index;
pMonitorModes->ModeCount = modeCount;
for (UINT i = 0; i < modeCount; ++i)
{
pMonitorModes->Modes[i].Width = modes[i].width;
pMonitorModes->Modes[i].Height = modes[i].height;
pMonitorModes->Modes[i].Sync = modes[i].sync;
}
if (!DeviceIoControl(
hDevice,
IOCTL_CHANGER_IDD_UPDATE_MONITOR_MODE,
pMonitorModes, // Ptr to InBuffer
buflen, // Length of InBuffer
NULL, // Ptr to OutBuffer
0, // Length of OutBuffer
&junk, // BytesReturned
0)) // Ptr to Overlapped structure
{
DWORD error = GetLastError();
SetLastMsg("DeviceIoControl failed 0x%lx\n", error);
if (g_printMsg)
{
printf(g_lastMsg);
}
ret = FALSE;
}
else
{
ret = TRUE;
}
free(pMonitorModes);
DeviceCloseHandle(hDevice);
return ret;
}
VOID WINAPI
CreationCallback(
_In_ HSWDEVICE hSwDevice,
_In_ HRESULT hrCreateResult,
_In_opt_ PVOID pContext,
_In_opt_ PCWSTR pszDeviceInstanceId
)
{
HANDLE hEvent = *(HANDLE*)pContext;
SetEvent(hEvent);
UNREFERENCED_PARAMETER(hSwDevice);
UNREFERENCED_PARAMETER(hrCreateResult);
// printf("Idd device %ls created\n", pszDeviceInstanceId);
}
BOOLEAN
GetDevicePath(
_In_ LPCGUID InterfaceGuid,
_Out_writes_(BufLen) PTCHAR DevicePath,
_In_ size_t BufLen
)
{
CONFIGRET cr = CR_SUCCESS;
PTSTR deviceInterfaceList = NULL;
ULONG deviceInterfaceListLength = 0;
PTSTR nextInterface;
HRESULT hr = E_FAIL;
BOOLEAN bRet = TRUE;
cr = CM_Get_Device_Interface_List_Size(
&deviceInterfaceListLength,
(LPGUID)InterfaceGuid,
NULL,
CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES);
if (cr != CR_SUCCESS)
{
SetLastMsg("Error GetDevicePath 0x%x retrieving device interface list size.\n", cr);
if (g_printMsg)
{
printf(g_lastMsg);
}
goto clean0;
}
// CAUTION: BUG here. deviceInterfaceListLength is greater than 1, even device was not created...
if (deviceInterfaceListLength <= 1)
{
SetLastMsg("Error: GetDevicePath No active device interfaces found. Is the sample driver loaded?\n");
if (g_printMsg)
{
printf(g_lastMsg);
}
bRet = FALSE;
goto clean0;
}
deviceInterfaceList = (PTSTR)malloc(deviceInterfaceListLength * sizeof(TCHAR));
if (deviceInterfaceList == NULL)
{
SetLastMsg("Error GetDevicePath allocating memory for device interface list.\n");
if (g_printMsg)
{
printf(g_lastMsg);
}
bRet = FALSE;
goto clean0;
}
ZeroMemory(deviceInterfaceList, deviceInterfaceListLength * sizeof(TCHAR));
for (int i = 0; i < 3 && _tcslen(deviceInterfaceList) == 0; i++)
{
// CAUTION: BUG here. deviceInterfaceList is NULL, even device was not created...
cr = CM_Get_Device_Interface_List(
(LPGUID)InterfaceGuid,
NULL,
deviceInterfaceList,
deviceInterfaceListLength,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cr != CR_SUCCESS)
{
SetLastMsg("Error GetDevicePath 0x%x retrieving device interface list.\n", cr);
if (g_printMsg)
{
printf(g_lastMsg);
}
goto clean0;
}
_tprintf(_T("get deviceInterfaceList %s\n"), deviceInterfaceList);
Sleep(1000);
}
nextInterface = deviceInterfaceList + _tcslen(deviceInterfaceList) + 1;
#ifdef UNICODE
if (*nextInterface != UNICODE_NULL) {
#else
if (*nextInterface != ANSI_NULL) {
#endif
printf("Warning: More than one device interface instance found. \n"
"Selecting first matching device.\n\n");
}
printf("begin copy device path\n");
hr = StringCchCopy(DevicePath, BufLen, deviceInterfaceList);
if (FAILED(hr))
{
SetLastMsg("Error: GetDevicePath StringCchCopy failed with HRESULT 0x%x", hr);
if (g_printMsg)
{
printf(g_lastMsg);
}
bRet = FALSE;
goto clean0;
}
clean0:
if (deviceInterfaceList != NULL)
{
free(deviceInterfaceList);
}
if (CR_SUCCESS != cr)
{
bRet = FALSE;
}
return bRet;
}
BOOLEAN GetDevicePath2(
_In_ LPCGUID InterfaceGuid,
_Out_writes_(BufLen) PTCHAR DevicePath,
_In_ size_t BufLen
)
{
HANDLE hDevice = INVALID_HANDLE_VALUE;
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL;
ULONG predictedLength = 0;
ULONG requiredLength = 0;
ULONG bytes;
HDEVINFO hardwareDeviceInfo;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
BOOLEAN status = FALSE;
HRESULT hr;
hardwareDeviceInfo = SetupDiGetClassDevs(
InterfaceGuid,
NULL, // Define no enumerator (global)
NULL, // Define no
(DIGCF_PRESENT | // Only Devices present
DIGCF_DEVICEINTERFACE)); // Function class devices.
if (INVALID_HANDLE_VALUE == hardwareDeviceInfo)
{
SetLastMsg("Idd device: SetupDiGetClassDevs failed, last error 0x%x\n", GetLastError());
if (g_printMsg)
{
printf(g_lastMsg);
}
return FALSE;
}
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (!SetupDiEnumDeviceInterfaces(hardwareDeviceInfo,
0, // No care about specific PDOs
InterfaceGuid,
0, //
&deviceInterfaceData))
{
SetLastMsg("Idd device: SetupDiEnumDeviceInterfaces failed, last error 0x%x\n", GetLastError());
if (g_printMsg)
{
printf(g_lastMsg);
}
goto Clean0;
}
//
// Allocate a function class device data structure to receive the
// information about this particular device.
//
SetupDiGetDeviceInterfaceDetail(
hardwareDeviceInfo,
&deviceInterfaceData,
NULL, // probing so no output buffer yet
0, // probing so output buffer length of zero
&requiredLength,
NULL);//not interested in the specific dev-node
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
{
SetLastMsg("Idd device: SetupDiGetDeviceInterfaceDetail failed, last error 0x%x\n", GetLastError());
if (g_printMsg)
{
printf(g_lastMsg);
}
goto Clean0;
}
predictedLength = requiredLength;
deviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
predictedLength
);
if (deviceInterfaceDetailData)
{
deviceInterfaceDetailData->cbSize =
sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
}
else
{
SetLastMsg("Idd device: HeapAlloc failed, last error 0x%x\n", GetLastError());
if (g_printMsg)
{
printf(g_lastMsg);
}
goto Clean0;
}
if (!SetupDiGetDeviceInterfaceDetail(
hardwareDeviceInfo,
&deviceInterfaceData,
deviceInterfaceDetailData,
predictedLength,
&requiredLength,
NULL))
{
SetLastMsg("Idd device: SetupDiGetDeviceInterfaceDetail failed, last error 0x%x\n", GetLastError());
if (g_printMsg)
{
printf(g_lastMsg);
}
goto Clean1;
}
hr = StringCchCopy(DevicePath, BufLen, deviceInterfaceDetailData->DevicePath);
if (FAILED(hr))
{
SetLastMsg("Error: StringCchCopy failed with HRESULT 0x%x", hr);
if (g_printMsg)
{
printf(g_lastMsg);
}
status = FALSE;
goto Clean1;
}
else
{
status = TRUE;
}
Clean1:
(VOID)HeapFree(GetProcessHeap(), 0, deviceInterfaceDetailData);
Clean0:
(VOID)SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
return status;
}
// https://stackoverflow.com/questions/67164846/createfile-fails-unless-i-disable-enable-my-device
HANDLE DeviceOpenHandle()
{
SetLastMsg("Sucess");
// const int maxDevPathLen = 256;
TCHAR devicePath[256] = { 0 };
HANDLE hDevice = INVALID_HANDLE_VALUE;
do
{
if (FALSE == GetDevicePath2(
&GUID_DEVINTERFACE_IDD_DRIVER_DEVICE,
devicePath,
sizeof(devicePath) / sizeof(devicePath[0])))
{
break;
}
if (_tcslen(devicePath) == 0)
{
SetLastMsg("GetDevicePath got empty device path\n");
if (g_printMsg)
{
printf(g_lastMsg);
}
break;
}
_tprintf(_T("Idd device: try open %s\n"), devicePath);
hDevice = CreateFile(
devicePath,
GENERIC_READ | GENERIC_WRITE,
// FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
NULL, // no SECURITY_ATTRIBUTES structure
OPEN_EXISTING, // No special create flags
0, // No special attributes
NULL
);
if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
{
DWORD error = GetLastError();
SetLastMsg("CreateFile failed 0x%lx\n", error);
if (g_printMsg)
{
printf(g_lastMsg);
}
}
} while (0);
return hDevice;
}
VOID DeviceCloseHandle(HANDLE handle)
{
if (handle != INVALID_HANDLE_VALUE && handle != NULL)
{
CloseHandle(handle);
}
}
VOID SetPrintErrMsg(BOOL b)
{
g_printMsg = (b == TRUE);
}

View File

@@ -0,0 +1,144 @@
#pragma once
#include <Windows.h>
#include <tchar.h>
#include <swdevice.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Install or Update RustDeskIddDriver.
*
* @param fullInfPath [in] Full path of the driver inf file.
* @param rebootRequired [out] Indicates whether a restart is required.
*
* @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg()
*
* @see GetLastMsg#GetLastMsg
*/
BOOL InstallUpdate(LPCTSTR fullInfPath, PBOOL rebootRequired);
/**
* @brief Uninstall RustDeskIddDriver.
*
* @param fullInfPath [in] Full path of the driver inf file.
* @param rebootRequired [out] Indicates whether a restart is required.
*
* @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg()
*
* @see GetLastMsg#GetLastMsg
*/
BOOL Uninstall(LPCTSTR fullInfPath, PBOOL rebootRequired);
/**
* @brief Check if RustDeskIddDriver device is created before.
* The driver device(adapter) should be single instance.
*
* @param created [out] Indicates whether the device is created before.
*
* @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg()
*
* @see GetLastMsg#GetLastMsg
*
*/
BOOL IsDeviceCreated(PBOOL created);
/**
* @brief Create device.
* Only one device should be created.
* If device is installed ealier, this function returns FALSE.
*
* @param hSwDevice [out] Handler of software device, used by DeviceCreate(). Should be **NULL**.
*
* @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg()
*
* @see GetLastMsg#GetLastMsg
*
*/
BOOL DeviceCreate(PHSWDEVICE hSwDevice);
/**
* @brief Close device.
*
* @param hSwDevice Handler of software device, used by SwDeviceClose().
*
*/
VOID DeviceClose(HSWDEVICE hSwDevice);
/**
* @brief Plug in monitor.
*
* @param index [in] Monitor index, should be 0, 1, 2.
* @param edid [in] Monitor edid.
* 0 Modified EDID from Dell S2719DGF
* 1 Modified EDID from Lenovo Y27fA
* @param retries [in] Retry times. Retry 1 time / sec. 25~30 seconds may be good choices.
* -1 is invalid.
* 0 means doing once and no retries.
* 1 means doing once and retry one time...
*
* @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg()
*
* @see GetLastMsg#GetLastMsg
*
* @remark Plug in monitor may fail if device is created in a very short time.
* System need some time to prepare the device.
*
*/
BOOL MonitorPlugIn(UINT index, UINT edid, INT retries);
/**
* @brief Plug out monitor.
*
* @param index [in] Monitor index, should be 0, 1, 2.
*
* @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg()
*
* @see GetLastMsg#GetLastMsg
*
*/
BOOL MonitorPlugOut(UINT index);
typedef struct _MonitorMode {
DWORD width;
DWORD height;
// Sync affects frequency.
DWORD sync;
} MonitorMode, *PMonitorMode;
/**
* @brief Update monitor mode.
*
* @param index [in] Monitor index, should be 0, 1, 2.
* @param modeCount [in] Monitor mode count.
* @param MonitorMode [in] Monitor mode data.
*
* @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg()
*
* @see GetLastMsg#GetLastMsg
*
*/
BOOL MonitorModesUpdate(UINT index, UINT modeCount, PMonitorMode modes);
/**
* @brief Get last error message.
*
* @return Message string. The string is at most 1024 bytes.
*
*/
const char* GetLastMsg();
/**
* @brief Set if print error message when debug.
*
* @param b [in] TRUE to enable printing message.
*
* @remark For now, no need to read evironment variable to check if should print.
*
*/
VOID SetPrintErrMsg(BOOL b);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,54 @@
#pragma once
#include <minwindef.h>
#include <winioctl.h>
#include <guiddef.h>
#define IOCTL_CHANGER_IDD_PLUG_IN CTL_CODE(IOCTL_CHANGER_BASE, \
0x1001, \
METHOD_BUFFERED, \
FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_CHANGER_IDD_PLUG_OUT CTL_CODE(IOCTL_CHANGER_BASE, \
0x1002, \
METHOD_BUFFERED, \
FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_CHANGER_IDD_UPDATE_MONITOR_MODE CTL_CODE(IOCTL_CHANGER_BASE, \
0x1003, \
METHOD_BUFFERED, \
FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define STATUS_ERROR_ADAPTER_NOT_INIT (3 << 30) + 11
//#define STATUS_ERROR_IO_CTL_GET_INPUT (3 << 30) + 21
//#define STATUS_ERROR_IO_CTL_GET_OUTPUT (3 << 30) + 22
#define STATUS_ERROR_MONITOR_EXISTS (3 << 30) + 51
#define STATUS_ERROR_MONITOR_NOT_EXISTS (3 << 30) + 52
#define STATUS_ERROR_MONITOR_INVALID_PARAM (3 << 30) + 53
#define STATUS_ERROR_MONITOR_OOM (3 << 30) + 54
#define MONITOR_EDID_MOD_DELL_S2719DGF 0
#define MONITOR_EDID_MOD_LENOVO_Y27fA 1
typedef struct _CtlPlugIn {
UINT ConnectorIndex;
UINT MonitorEDID;
GUID ContainerId;
} CtlPlugIn, *PCtlPlugIn;
typedef struct _CtlPlugOut {
UINT ConnectorIndex;
} CtlPlugOut, *PCtlPlugOut;
typedef struct _CtlMonitorModes {
UINT ConnectorIndex;
UINT ModeCount;
struct {
DWORD Width;
DWORD Height;
DWORD Sync;
} Modes[1];
} CtlMonitorModes, *PCtlMonitorModes;
#define SYMBOLIC_LINK_NAME L"\\Device\\RustDeskIddDriver"

View File

@@ -0,0 +1,215 @@
#![allow(dead_code)]
#![allow(non_camel_case_types)]
#![allow(unused_variables)]
#![allow(non_snake_case)]
#![allow(deref_nullptr)]
pub type size_t = ::std::os::raw::c_ulonglong;
pub type __vcrt_bool = bool;
pub type wchar_t = ::std::os::raw::c_ushort;
pub type POINTER_64_INT = ::std::os::raw::c_ulonglong;
pub type INT8 = ::std::os::raw::c_schar;
pub type PINT8 = *mut ::std::os::raw::c_schar;
pub type INT16 = ::std::os::raw::c_short;
pub type PINT16 = *mut ::std::os::raw::c_short;
pub type INT32 = ::std::os::raw::c_int;
pub type PINT32 = *mut ::std::os::raw::c_int;
pub type INT64 = ::std::os::raw::c_longlong;
pub type PINT64 = *mut ::std::os::raw::c_longlong;
pub type UINT8 = ::std::os::raw::c_uchar;
pub type PUINT8 = *mut ::std::os::raw::c_uchar;
pub type UINT16 = ::std::os::raw::c_ushort;
pub type PUINT16 = *mut ::std::os::raw::c_ushort;
pub type UINT32 = ::std::os::raw::c_uint;
pub type PUINT32 = *mut ::std::os::raw::c_uint;
pub type UINT64 = ::std::os::raw::c_ulonglong;
pub type PUINT64 = *mut ::std::os::raw::c_ulonglong;
pub type LONG32 = ::std::os::raw::c_int;
pub type PLONG32 = *mut ::std::os::raw::c_int;
pub type ULONG32 = ::std::os::raw::c_uint;
pub type PULONG32 = *mut ::std::os::raw::c_uint;
pub type DWORD32 = ::std::os::raw::c_uint;
pub type PDWORD32 = *mut ::std::os::raw::c_uint;
pub type INT_PTR = ::std::os::raw::c_longlong;
pub type PINT_PTR = *mut ::std::os::raw::c_longlong;
pub type UINT_PTR = ::std::os::raw::c_ulonglong;
pub type PUINT_PTR = *mut ::std::os::raw::c_ulonglong;
pub type LONG_PTR = ::std::os::raw::c_longlong;
pub type PLONG_PTR = *mut ::std::os::raw::c_longlong;
pub type ULONG_PTR = ::std::os::raw::c_ulonglong;
pub type PULONG_PTR = *mut ::std::os::raw::c_ulonglong;
pub type SHANDLE_PTR = ::std::os::raw::c_longlong;
pub type HANDLE_PTR = ::std::os::raw::c_ulonglong;
pub type UHALF_PTR = ::std::os::raw::c_uint;
pub type PUHALF_PTR = *mut ::std::os::raw::c_uint;
pub type HALF_PTR = ::std::os::raw::c_int;
pub type PHALF_PTR = *mut ::std::os::raw::c_int;
pub type SIZE_T = ULONG_PTR;
pub type PSIZE_T = *mut ULONG_PTR;
pub type SSIZE_T = LONG_PTR;
pub type PSSIZE_T = *mut LONG_PTR;
pub type DWORD_PTR = ULONG_PTR;
pub type PDWORD_PTR = *mut ULONG_PTR;
pub type LONG64 = ::std::os::raw::c_longlong;
pub type PLONG64 = *mut ::std::os::raw::c_longlong;
pub type ULONG64 = ::std::os::raw::c_ulonglong;
pub type PULONG64 = *mut ::std::os::raw::c_ulonglong;
pub type DWORD64 = ::std::os::raw::c_ulonglong;
pub type PDWORD64 = *mut ::std::os::raw::c_ulonglong;
pub type KAFFINITY = ULONG_PTR;
pub type PKAFFINITY = *mut KAFFINITY;
pub type PVOID = *mut ::std::os::raw::c_void;
pub type CHAR = ::std::os::raw::c_char;
pub type SHORT = ::std::os::raw::c_short;
pub type LONG = ::std::os::raw::c_long;
pub type WCHAR = wchar_t;
pub type PWCHAR = *mut WCHAR;
pub type LPWCH = *mut WCHAR;
pub type PWCH = *mut WCHAR;
pub type LPCWCH = *const WCHAR;
pub type PCWCH = *const WCHAR;
pub type NWPSTR = *mut WCHAR;
pub type LPWSTR = *mut WCHAR;
pub type PWSTR = *mut WCHAR;
pub type PZPWSTR = *mut PWSTR;
pub type PCZPWSTR = *const PWSTR;
pub type LPUWSTR = *mut WCHAR;
pub type PUWSTR = *mut WCHAR;
pub type LPCWSTR = *const WCHAR;
pub type PCWSTR = *const WCHAR;
pub type PZPCWSTR = *mut PCWSTR;
pub type PCZPCWSTR = *const PCWSTR;
pub type LPCUWSTR = *const WCHAR;
pub type PCUWSTR = *const WCHAR;
pub type PZZWSTR = *mut WCHAR;
pub type PCZZWSTR = *const WCHAR;
pub type PUZZWSTR = *mut WCHAR;
pub type PCUZZWSTR = *const WCHAR;
pub type PNZWCH = *mut WCHAR;
pub type PCNZWCH = *const WCHAR;
pub type PUNZWCH = *mut WCHAR;
pub type PCUNZWCH = *const WCHAR;
pub type PCHAR = *mut CHAR;
pub type LPCH = *mut CHAR;
pub type PCH = *mut CHAR;
pub type LPCCH = *const CHAR;
pub type PCCH = *const CHAR;
pub type NPSTR = *mut CHAR;
pub type LPSTR = *mut CHAR;
pub type PSTR = *mut CHAR;
pub type PZPSTR = *mut PSTR;
pub type PCZPSTR = *const PSTR;
pub type LPCSTR = *const CHAR;
pub type PCSTR = *const CHAR;
pub type PZPCSTR = *mut PCSTR;
pub type PCZPCSTR = *const PCSTR;
pub type PZZSTR = *mut CHAR;
pub type PCZZSTR = *const CHAR;
pub type PNZCH = *mut CHAR;
pub type PCNZCH = *const CHAR;
pub type TCHAR = ::std::os::raw::c_char;
pub type PTCHAR = *mut ::std::os::raw::c_char;
pub type TBYTE = ::std::os::raw::c_uchar;
pub type PTBYTE = *mut ::std::os::raw::c_uchar;
pub type LPTCH = LPCH;
pub type PTCH = LPCH;
pub type LPCTCH = LPCCH;
pub type PCTCH = LPCCH;
pub type PTSTR = LPSTR;
pub type LPTSTR = LPSTR;
pub type PUTSTR = LPSTR;
pub type LPUTSTR = LPSTR;
pub type PCTSTR = LPCSTR;
pub type LPCTSTR = LPCSTR;
pub type PCUTSTR = LPCSTR;
pub type LPCUTSTR = LPCSTR;
pub type PZZTSTR = PZZSTR;
pub type PUZZTSTR = PZZSTR;
pub type PCZZTSTR = PCZZSTR;
pub type PCUZZTSTR = PCZZSTR;
pub type PZPTSTR = PZPSTR;
pub type PNZTCH = PNZCH;
pub type PUNZTCH = PNZCH;
pub type PCNZTCH = PCNZCH;
pub type PCUNZTCH = PCNZCH;
pub type PSHORT = *mut SHORT;
pub type PLONG = *mut LONG;
pub type ULONG = ::std::os::raw::c_ulong;
pub type PULONG = *mut ULONG;
pub type USHORT = ::std::os::raw::c_ushort;
pub type PUSHORT = *mut USHORT;
pub type UCHAR = ::std::os::raw::c_uchar;
pub type PUCHAR = *mut UCHAR;
pub type PSZ = *mut ::std::os::raw::c_char;
pub type DWORD = ::std::os::raw::c_ulong;
pub type BOOL = ::std::os::raw::c_int;
pub type BYTE = ::std::os::raw::c_uchar;
pub type WORD = ::std::os::raw::c_ushort;
pub type FLOAT = f32;
pub type PFLOAT = *mut FLOAT;
pub type PBOOL = *mut BOOL;
pub type LPBOOL = *mut BOOL;
pub type PBYTE = *mut BYTE;
pub type LPBYTE = *mut BYTE;
pub type PINT = *mut ::std::os::raw::c_int;
pub type LPINT = *mut ::std::os::raw::c_int;
pub type PWORD = *mut WORD;
pub type LPWORD = *mut WORD;
pub type LPLONG = *mut ::std::os::raw::c_long;
pub type PDWORD = *mut DWORD;
pub type LPDWORD = *mut DWORD;
pub type LPVOID = *mut ::std::os::raw::c_void;
pub type LPCVOID = *const ::std::os::raw::c_void;
pub type INT = ::std::os::raw::c_int;
pub type UINT = ::std::os::raw::c_uint;
pub type PUINT = *mut ::std::os::raw::c_uint;
pub type va_list = *mut ::std::os::raw::c_char;
pub const TRUE: ::std::os::raw::c_int = 1;
pub const FALSE: ::std::os::raw::c_int = 0;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _MonitorMode {
pub width: DWORD,
pub height: DWORD,
pub sync: DWORD,
}
pub type MonitorMode = _MonitorMode;
pub type PMonitorMode = *mut MonitorMode;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct HSWDEVICE__ {
pub unused: ::std::os::raw::c_int,
}
pub type HSWDEVICE = *mut HSWDEVICE__;
pub type PHSWDEVICE = *mut HSWDEVICE;
#[link(name = "Newdev")]
extern "C" {
pub fn InstallUpdate(fullInfPath: LPCTSTR, rebootRequired: PBOOL) -> BOOL;
}
#[link(name = "Setupapi")]
extern "C" {
pub fn IsDeviceCreated(created: PBOOL) -> BOOL;
}
#[link(name = "Swdevice")]
#[link(name = "OneCoreUAP")]
extern "C" {
pub fn DeviceCreate(hSwDevice: PHSWDEVICE) -> BOOL;
pub fn DeviceClose(hSwDevice: HSWDEVICE);
}
extern "C" {
pub fn Uninstall(fullInfPath: LPCTSTR, rebootRequired: PBOOL) -> BOOL;
pub fn MonitorPlugIn(index: UINT, edid: UINT, retries: INT) -> BOOL;
pub fn MonitorPlugOut(index: UINT) -> BOOL;
pub fn MonitorModesUpdate(index: UINT, modeCount: UINT, modes: PMonitorMode) -> BOOL;
pub fn GetLastMsg() -> PCHAR;
pub fn SetPrintErrMsg(b: BOOL);
}

View File

@@ -0,0 +1,9 @@
pub mod idd;
use std::ffi::CStr;
pub const DRIVER_INSTALL_PATH: &str = "RustDeskIddDriver/RustDeskIddDriver.inf";
pub const DRIVER_DOWNLOAD_URL: &str = "";
pub unsafe fn get_last_msg() -> Result<&'static str, std::str::Utf8Error> {
CStr::from_ptr(idd::GetLastMsg()).to_str()
}

BIN
mac-tray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

124
pynput_service.py Normal file
View File

@@ -0,0 +1,124 @@
from pynput.keyboard import Key, Controller
from pynput.keyboard._xorg import KeyCode
from pynput._util.xorg import display_manager
import Xlib
import os
import sys
import socket
KeyCode._from_symbol("\0") # test
class MyController(Controller):
def _handle(self, key, is_press):
"""Resolves a key identifier and sends a keyboard event.
:param event: The *X* keyboard event.
:param int keysym: The keysym to handle.
"""
event = Xlib.display.event.KeyPress if is_press \
else Xlib.display.event.KeyRelease
keysym = self._keysym(key)
# Make sure to verify that the key was resolved
if keysym is None:
raise self.InvalidKeyException(key)
# If the key has a virtual key code, use that immediately with
# fake_input; fake input,being an X server extension, has access to
# more internal state that we do
if key.vk is not None:
with display_manager(self._display) as dm:
Xlib.ext.xtest.fake_input(
dm,
Xlib.X.KeyPress if is_press else Xlib.X.KeyRelease,
dm.keysym_to_keycode(key.vk))
# Otherwise use XSendEvent; we need to use this in the general case to
# work around problems with keyboard layouts
else:
try:
keycode, shift_state = self.keyboard_mapping[keysym]
with self.modifiers as modifiers:
alt_gr = Key.alt_gr in modifiers
if alt_gr:
self._send_key(event, keycode, shift_state)
else:
with display_manager(self._display) as dm:
Xlib.ext.xtest.fake_input(
dm,
Xlib.X.KeyPress if is_press else Xlib.X.KeyRelease,
keycode)
except KeyError:
with self._borrow_lock:
keycode, index, count = self._borrows[keysym]
self._send_key(
event,
keycode,
index_to_shift(self._display, index))
count += 1 if is_press else -1
self._borrows[keysym] = (keycode, index, count)
# Notify any running listeners
self._emit('_on_fake_event', key, is_press)
keyboard = MyController()
server_address = sys.argv[1]
if not os.path.exists(os.path.dirname(server_address)):
os.makedirs(os.path.dirname(server_address))
try:
os.unlink(server_address)
except OSError:
if os.path.exists(server_address):
raise
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
server.bind(server_address)
server.listen(1)
clientsocket, address = server.accept()
os.system('chmod a+rw %s'%server_address)
print("Got pynput connection")
def loop():
global keyboard
buf = []
while True:
data = clientsocket.recv(1024)
if not data:
print("Connection broken")
break
buf.extend(data)
while buf:
n = buf[0]
n = n + 1
if len(buf) < n:
break
msg = bytearray(buf[1:n]).decode("utf-8")
buf = buf[n:]
if len(msg) < 2:
continue
if msg[1] == "\0":
keyboard = MyController()
print("Keyboard reset")
continue
if len(msg) == 2:
name = msg[1]
else:
name = KeyCode._from_symbol(msg[1:])
if str(name) == "<0>":
continue
try:
if msg[0] == "p":
keyboard.press(name)
else:
keyboard.release(name)
except Exception as e:
print(e)
loop()
clientsocket.close()
server.close()

16
rustdesk.service Normal file
View File

@@ -0,0 +1,16 @@
[Unit]
Description=RustDesk
Requires=network.target
After=systemd-user-sessions.service
[Service]
Type=simple
ExecStart=/usr/bin/rustdesk --service
PIDFile=/var/run/rustdesk.pid
KillMode=mixed
TimeoutStopSec=30
User=root
LimitNOFILE=100000
[Install]
WantedBy=multi-user.target

25
snap/README.md Normal file
View File

@@ -0,0 +1,25 @@
## How to build and run with Snap
Begin by cloning the repository and make sure snapcraft is installed in your Linux.
```sh
git clone https://github.com/rustdesk/rustdesk
# if snapcraft is installed, please skip this
sudo snap install snapcraft --classic
# build rustdesk snap package
snapcraft --use-lxd
# install rustdesk snap package, `--dangerous` flag must exists if u manually build and install rustdesk
sudo snap install rustdesk_xxx.snap --dangerous
```
Note: Some of interfaces needed by RustDesk cannot automatically connected by Snap. Please **manually** connect them by executing:
```sh
# record system audio
snap connect rustdesk:audio-record
snap connect rustdesk:pulseaudio
# observe loginctl session
snap connect rustdesk:login-session-observe
```
After steps above, RustDesk can be found in System App Menu.

20
snap/gui/rustdesk.desktop Normal file
View File

@@ -0,0 +1,20 @@
[Desktop Entry]
Version=1.0
Name=RustDesk
GenericName=Remote Desktop
Comment=Remote Desktop
Exec=rustdesk %u
Icon=${SNAP}/meta/gui/rustdesk.png
Terminal=false
Type=Application
MimeType=text/html;text/xml;application/xhtml+xml;application/vnd.mozilla.xul+xml;text/mml;x-scheme-handler/http;x-scheme-handler/https;
StartupNotify=true
Categories=Other;
Keywords=internet;
Actions=new-window;
X-Desktop-File-Install-Version=0.23
[Desktop Action new-window]
Name=Open a New Window

BIN
snap/gui/rustdesk.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

163
snap/snapcraft.yaml Normal file
View File

@@ -0,0 +1,163 @@
name: rustdesk
version: git
summary: rustdesk
description: |
rustdesk
base: core18
confinement: strict
grade: stable
plugs:
gsettings:
gtk-3-themes:
interface: content
target: $SNAP/data-dir/themes
default-provider: gtk-common-themes
icon-themes:
interface: content
target: $SNAP/data-dir/icons
default-provider: gtk-common-themes
sound-themes:
interface: content
target: $SNAP/data-dir/sounds
default-provider: gtk-common-themes
parts:
vcpkg-packages:
plugin: nil
build-packages:
- git
- curl
- unzip
- zip
- tar
build-environment:
- PATH: ${SNAPCRAFT_PART_SRC}/vcpkg:$PATH
override-pull: |
git clone https://github.com/Microsoft/vcpkg.git --depth=1
./vcpkg/bootstrap-vcpkg.sh
vcpkg install libyuv libvpx opus
sciter-deps:
plugin: nil
build-packages:
- curl
override-pull: |
curl "https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so" -o libsciter-gtk.so
override-build: |
mkdir -p ${SNAPCRAFT_PART_INSTALL}/usr/lib/rustdesk/
cp ${SNAPCRAFT_PART_SRC}/libsciter-gtk.so ${SNAPCRAFT_PART_INSTALL}/usr/lib/rustdesk/
rustdesk:
plugin: rust
source: .
build-environment:
- VCPKG_ROOT: ${SNAPCRAFT_PART_SRC}/../../vcpkg-packages/src/vcpkg
- PATH: ${SNAPCRAFT_PART_SRC}/../../vcpkg-packages/src/vcpkg:$PATH
override-pull: |
snapcraftctl pull
python3 inline-sciter.py
rust-features:
- inline
build-packages:
- g++
- gcc
- git
- curl
- wget
- nasm
- yasm
- libgtk-3-dev
- clang
- libxcb-randr0-dev
- libxdo-dev
- libxfixes-dev
- libxcb-shape0-dev
- libxcb-xfixes0-dev
- libasound2-dev
- libpulse-dev
- cmake
- python3
stage-packages:
- libssl1.1
- libasound2
- libpulse0
- libatk-bridge2.0-0
- libgtk-3-0
- libxcb-randr0
- libxdo3
- libxfixes3
- libxcb-shape0
- libxcb-xfixes0
- libxkbcommon0
- adwaita-icon-theme
- libcanberra-gtk-module
- libgdk-pixbuf2.0-0
- libglib2.0-bin
- xdg-user-dirs
- shared-mime-info
- light-themes
- dmz-cursor-theme
- gnome-themes-standard
- ttf-ubuntu-font-family
after:
- vcpkg-packages
rustdesk-files:
plugin: nil
override-pull: |
mkdir -p ${SNAPCRAFT_PART_INSTALL}/usr/share/rustdesk/files/systemd/
cp ${SNAPCRAFT_PART_SRC}/../../rustdesk/src/pynput_service.py ${SNAPCRAFT_PART_INSTALL}/usr/share/rustdesk/files/
cp ${SNAPCRAFT_PART_SRC}/../../rustdesk/src/rustdesk.service ${SNAPCRAFT_PART_INSTALL}/usr/share/rustdesk/files/systemd/
python3-deps:
plugin: python
python-packages:
- pynput == 1.7.6
layout:
/usr/share/rustdesk:
bind: $SNAP/usr/share/rustdesk
/usr/lib/rustdesk:
bind: $SNAP/usr/lib/rustdesk
apps:
rustdesk:
command: bin/rustdesk
plugs:
- network
- audio-playback
- home
- x11
- opengl
- wayland
- desktop
- desktop-legacy
- pulseaudio
- gsettings
- unity7
# must manually connect
- login-session-observe
# [option] manually connect
- audio-record
rustdesk-service:
command: bin/rustdesk --service
daemon: simple
plugs:
- network
- audio-playback
- home
- x11
- opengl
- wayland
- desktop
- desktop-legacy
- pulseaudio
- gsettings
- unity7
# must manually connect
- login-session-observe
# [option] manually connect
- audio-record

View File

@@ -1,5 +1,5 @@
pub use async_trait::async_trait;
#[cfg(not(any(target_os = "android")))]
#[cfg(not(any(target_os = "android", target_os = "linux")))]
use cpal::{
traits::{DeviceTrait, HostTrait, StreamTrait},
Device, Host, StreamConfig,
@@ -10,7 +10,7 @@ use hbb_common::{
bail,
config::{Config, PeerConfig, PeerInfoSerde, CONNECT_TIMEOUT, RELAY_PORT, RENDEZVOUS_TIMEOUT},
log,
message_proto::*,
message_proto::{option_message::BoolOption, *},
protobuf::Message as _,
rendezvous_proto::*,
socket_client,
@@ -26,7 +26,7 @@ use std::{
collections::HashMap,
net::SocketAddr,
ops::Deref,
sync::{Arc, Mutex, RwLock},
sync::{mpsc, Arc, RwLock},
};
use uuid::Uuid;
@@ -36,7 +36,7 @@ pub struct Client;
pub use super::lang::*;
#[cfg(not(any(target_os = "android")))]
#[cfg(not(any(target_os = "android", target_os = "linux")))]
lazy_static::lazy_static! {
static ref AUDIO_HOST: Host = cpal::default_host();
}
@@ -45,7 +45,6 @@ cfg_if::cfg_if! {
if #[cfg(target_os = "android")] {
use libc::{c_float, c_int, c_void};
use std::cell::RefCell;
type Oboe = *mut c_void;
extern "C" {
fn create_oboe_player(channels: c_int, sample_rate: c_int) -> Oboe;
@@ -134,10 +133,9 @@ impl Client {
log::info!("rendezvous server: {}", rendezvous_server);
let mut socket =
socket_client::connect_tcp(&*rendezvous_server, any_addr, RENDEZVOUS_TIMEOUT)
.await?;
socket_client::connect_tcp(&*rendezvous_server, any_addr, RENDEZVOUS_TIMEOUT).await?;
let my_addr = socket.local_addr();
let mut pk = Vec::new();
let mut signed_id_pk = Vec::new();
let mut relay_server = "".to_owned();
let start = std::time::Instant::now();
@@ -162,6 +160,9 @@ impl Client {
match msg_in.union {
Some(rendezvous_message::Union::punch_hole_response(ph)) => {
if ph.socket_addr.is_empty() {
if !ph.other_failure.is_empty() {
bail!(ph.other_failure);
}
match ph.failure.enum_value_or_default() {
punch_hole_response::Failure::ID_NOT_EXIST => {
bail!("ID does not exist");
@@ -172,16 +173,14 @@ impl Client {
punch_hole_response::Failure::LICENSE_MISMATCH => {
bail!("Key mismatch");
}
_ => {
if !ph.other_failure.is_empty() {
bail!(ph.other_failure);
}
punch_hole_response::Failure::LICENSE_OVERUSE => {
bail!("Key overuse");
}
}
} else {
peer_nat_type = ph.get_nat_type();
is_local = ph.get_is_local();
pk = ph.pk;
signed_id_pk = ph.pk;
relay_server = ph.relay_server;
peer_addr = AddrMangle::decode(&ph.socket_addr);
log::info!("Hole Punched {} = {}", peer, peer_addr);
@@ -194,11 +193,11 @@ impl Client {
start.elapsed(),
rr.relay_server
);
pk = rr.get_pk().into();
signed_id_pk = rr.get_pk().into();
let mut conn =
Self::create_relay(peer, rr.uuid, rr.relay_server, conn_type)
.await?;
Self::secure_connection(peer, pk, &mut conn).await?;
Self::secure_connection(peer, signed_id_pk, &mut conn).await?;
return Ok((conn, false));
}
_ => {
@@ -229,7 +228,7 @@ impl Client {
my_addr,
peer_addr,
peer,
pk,
signed_id_pk,
&relay_server,
&rendezvous_server,
time_used,
@@ -245,7 +244,7 @@ impl Client {
local_addr: SocketAddr,
peer: SocketAddr,
peer_id: &str,
pk: Vec<u8>,
signed_id_pk: Vec<u8>,
relay_server: &str,
rendezvous_server: &str,
punch_time_used: u64,
@@ -297,7 +296,7 @@ impl Client {
peer_id,
relay_server.to_owned(),
rendezvous_server,
pk.len() == sign::PUBLICKEYBYTES,
!signed_id_pk.is_empty(),
conn_type,
)
.await;
@@ -319,56 +318,39 @@ impl Client {
}
let mut conn = conn?;
log::info!("{:?} used to establish connection", start.elapsed());
Self::secure_connection(peer_id, pk, &mut conn).await?;
Self::secure_connection(peer_id, signed_id_pk, &mut conn).await?;
Ok((conn, direct))
}
async fn secure_connection(peer_id: &str, pk: Vec<u8>, conn: &mut Stream) -> ResultType<()> {
let mut pk = pk;
const RS_PK: &[u8; 32] = &[
177, 155, 15, 73, 116, 147, 172, 11, 55, 38, 92, 168, 30, 116, 213, 196, 12, 134, 130,
170, 181, 161, 192, 176, 132, 229, 139, 178, 17, 165, 150, 51,
];
if !pk.is_empty() {
let tmp = sign::PublicKey(*RS_PK);
if let Ok(data) = sign::verify(&pk, &tmp) {
pk = data;
} else {
async fn secure_connection(peer_id: &str, signed_id_pk: Vec<u8>, conn: &mut Stream) -> ResultType<()> {
let rs_pk = get_rs_pk("OeVuKk5nlHiXp+APNn0Y3pC1Iwpwn44JGqrQCsWqmBw=");
let mut sign_pk = None;
if !signed_id_pk.is_empty() && rs_pk.is_some() {
if let Ok((id, pk)) = decode_id_pk(&signed_id_pk, &rs_pk.unwrap()) {
if id == peer_id {
sign_pk = Some(sign::PublicKey(pk));
}
}
if sign_pk.is_none() {
log::error!("Handshake failed: invalid public key from rendezvous server");
pk.clear();
}
}
if pk.len() != sign::PUBLICKEYBYTES {
// send an empty message out in case server is setting up secure and waiting for first message
conn.send(&Message::new()).await?;
return Ok(());
}
let mut tmp = [0u8; sign::PUBLICKEYBYTES];
tmp[..].copy_from_slice(&pk);
let sign_pk = sign::PublicKey(tmp);
let sign_pk = match sign_pk {
Some(v) => v,
None => {
// send an empty message out in case server is setting up secure and waiting for first message
conn.send(&Message::new()).await?;
return Ok(());
}
};
match timeout(CONNECT_TIMEOUT, conn.next()).await? {
Some(res) => {
let bytes = res?;
if let Ok(msg_in) = Message::parse_from_bytes(&bytes) {
if let Some(message::Union::signed_id(si)) = msg_in.union {
if let Ok(data) = sign::verify(&si.id, &sign_pk) {
let s = String::from_utf8_lossy(&data);
let mut it = s.split("\0");
let id = it.next().unwrap_or_default();
let pk =
base64::decode(it.next().unwrap_or_default()).unwrap_or_default();
let their_pk_b = if pk.len() == box_::PUBLICKEYBYTES {
let mut pk_ = [0u8; box_::PUBLICKEYBYTES];
pk_[..].copy_from_slice(&pk);
box_::PublicKey(pk_)
} else {
log::error!(
"Handshake failed: invalid public box key length from peer"
);
conn.send(&Message::new()).await?;
return Ok(());
};
if let Ok((id, their_pk_b)) = decode_id_pk(&si.id, &sign_pk) {
if id == peer_id {
let their_pk_b = box_::PublicKey(their_pk_b);
let (our_pk_b, out_sk_b) = box_::gen_keypair();
let key = secretbox::gen_key();
let nonce = box_::Nonce([0u8; box_::NONCEBYTES]);
@@ -390,7 +372,7 @@ impl Client {
log::info!("pk mismatch, fall back to non-secure");
let mut msg_out = Message::new();
msg_out.set_public_key(PublicKey::new());
timeout(CONNECT_TIMEOUT, conn.send(&msg_out)).await??;
conn.send(&msg_out).await?;
}
} else {
log::error!("Handshake failed: invalid message type");
@@ -489,24 +471,60 @@ impl Client {
#[derive(Default)]
pub struct AudioHandler {
audio_decoder: Option<(AudioDecoder, Vec<f32>)>,
#[cfg(any(target_os = "android"))]
oboe: RefCell<OboePlayer>,
#[cfg(not(any(target_os = "android")))]
audio_buffer: Arc<Mutex<std::collections::vec_deque::VecDeque<f32>>>,
#[cfg(target_os = "android")]
oboe: Option<OboePlayer>,
#[cfg(target_os = "linux")]
simple: Option<psimple::Simple>,
#[cfg(not(any(target_os = "android", target_os = "linux")))]
audio_buffer: Arc<std::sync::Mutex<std::collections::vec_deque::VecDeque<f32>>>,
sample_rate: (u32, u32),
#[cfg(not(any(target_os = "android")))]
#[cfg(not(any(target_os = "android", target_os = "linux")))]
audio_stream: Option<Box<dyn StreamTrait>>,
channels: u16,
}
impl AudioHandler {
#[cfg(any(target_os = "android"))]
#[cfg(target_os = "linux")]
fn start_audio(&mut self, format0: AudioFormat) -> ResultType<()> {
use psimple::Simple;
use pulse::sample::{Format, Spec};
use pulse::stream::Direction;
let spec = Spec {
format: Format::F32le,
channels: format0.channels as _,
rate: format0.sample_rate as _,
};
if !spec.is_valid() {
bail!("Invalid audio format");
}
use hbb_common::config::APP_NAME;
self.simple = Some(Simple::new(
None, // Use the default server
APP_NAME, // Our applications name
Direction::Playback, // We want a playback stream
None, // Use the default device
"playback", // Description of our stream
&spec, // Our sample format
None, // Use default channel map
None, // Use default buffering attributes
)?);
self.sample_rate = (format0.sample_rate, format0.sample_rate);
Ok(())
}
#[cfg(not(any(target_os = "android")))]
#[cfg(target_os = "android")]
fn start_audio(&mut self, format0: AudioFormat) -> ResultType<()> {
self.oboe = Some(OboePlayer::new(
format0.channels as _,
format0.sample_rate as _,
));
self.sample_rate = (format0.sample_rate, format0.sample_rate);
Ok(())
}
#[cfg(not(any(target_os = "android", target_os = "linux")))]
fn start_audio(&mut self, format0: AudioFormat) -> ResultType<()> {
let device = AUDIO_HOST
.default_output_device()
@@ -544,39 +562,32 @@ impl AudioHandler {
}
}
pub fn handle_frame(&mut self, frame: AudioFrame, play: bool) {
if !play {
return;
}
#[cfg(not(any(target_os = "android")))]
pub fn handle_frame(&mut self, frame: AudioFrame) {
#[cfg(not(any(target_os = "android", target_os = "linux")))]
if self.audio_stream.is_none() {
return;
}
let sample_rate0 = self.sample_rate.0;
let sample_rate = self.sample_rate.1;
let channels = self.channels;
cfg_if::cfg_if! {
if #[cfg(not(target_os = "android"))] {
let audio_buffer = self.audio_buffer.clone();
// avoiding memory overflow if audio_buffer consumer side has problem
if audio_buffer.lock().unwrap().len() as u32 > sample_rate * 120 {
*audio_buffer.lock().unwrap() = Default::default();
}
} else {
if self.oboe.borrow().is_null() {
self.oboe = RefCell::new(OboePlayer::new(
channels as _,
sample_rate0 as _,
));
}
let mut oboe = self.oboe.borrow_mut();
#[cfg(target_os = "linux")]
if self.simple.is_none() {
return;
}
#[cfg(target_os = "android")]
if self.oboe.is_none() {
return;
}
self.audio_decoder.as_mut().map(|(d, buffer)| {
if let Ok(n) = d.decode_float(&frame.data, buffer, false) {
let channels = self.channels;
let n = n * (channels as usize);
#[cfg(not(any(target_os = "android")))]
#[cfg(not(any(target_os = "android", target_os = "linux")))]
{
let sample_rate0 = self.sample_rate.0;
let sample_rate = self.sample_rate.1;
let audio_buffer = self.audio_buffer.clone();
// avoiding memory overflow if audio_buffer consumer side has problem
if audio_buffer.lock().unwrap().len() as u32 > sample_rate * 120 {
*audio_buffer.lock().unwrap() = Default::default();
}
if sample_rate != sample_rate0 {
let buffer = crate::resample_channels(
&buffer[0..n],
@@ -586,18 +597,27 @@ impl AudioHandler {
);
audio_buffer.lock().unwrap().extend(buffer);
} else {
audio_buffer.lock().unwrap().extend(buffer.iter().cloned());
audio_buffer
.lock()
.unwrap()
.extend(buffer[0..n].iter().cloned());
}
}
#[cfg(any(target_os = "android"))]
#[cfg(target_os = "android")]
{
oboe.push(&buffer[0..n]);
self.oboe.as_mut().map(|x| x.push(&buffer[0..n]));
}
#[cfg(target_os = "linux")]
{
let data_u8 =
unsafe { std::slice::from_raw_parts::<u8>(buffer.as_ptr() as _, n * 4) };
self.simple.as_mut().map(|x| x.write(data_u8));
}
}
});
}
#[cfg(not(any(target_os = "android")))]
#[cfg(not(any(target_os = "android", target_os = "linux")))]
fn build_output_stream<T: cpal::Sample>(
&mut self,
config: &StreamConfig,
@@ -640,7 +660,7 @@ pub struct VideoHandler {
impl VideoHandler {
pub fn new() -> Self {
VideoHandler {
decoder: Decoder::new(VideoCodecId::VP9, 0).unwrap(),
decoder: Decoder::new(VideoCodecId::VP9, (num_cpus::get() / 2) as _).unwrap(),
rgb: Default::default(),
}
}
@@ -680,8 +700,7 @@ pub struct LoginConfigHandler {
pub remember: bool,
config: PeerConfig,
pub port_forward: (String, i32),
pub support_press: bool,
pub support_refresh: bool,
pub version: i64,
}
impl Deref for LoginConfigHandler {
@@ -771,6 +790,14 @@ impl LoginConfigHandler {
BoolOption::No
})
.into();
} else if name == "enable-file-transfer" {
config.enable_file_transfer = !config.enable_file_transfer;
option.enable_file_transfer = (if config.enable_file_transfer {
BoolOption::Yes
} else {
BoolOption::No
})
.into();
} else if name == "block-input" {
option.block_input = BoolOption::Yes.into();
} else if name == "unblock-input" {
@@ -785,7 +812,9 @@ impl LoginConfigHandler {
self.config.store(&self.id);
return None;
}
self.save_config(config);
if !name.contains("block-input") {
self.save_config(config);
}
let mut misc = Misc::new();
misc.set_option(option);
let mut msg_out = Message::new();
@@ -823,10 +852,22 @@ impl LoginConfigHandler {
msg.lock_after_session_end = BoolOption::Yes.into();
n += 1;
}
if self.get_toggle_option("privacy_mode") {
if self.get_toggle_option("privacy-mode") {
msg.privacy_mode = BoolOption::Yes.into();
n += 1;
}
if self.get_toggle_option("disable-audio") {
msg.disable_audio = BoolOption::Yes.into();
n += 1;
}
if self.get_toggle_option("enable-file-transfer") {
msg.enable_file_transfer = BoolOption::Yes.into();
n += 1;
}
if self.get_toggle_option("disable-clipboard") {
msg.disable_clipboard = BoolOption::Yes.into();
n += 1;
}
if n > 0 {
Some(msg)
} else {
@@ -857,6 +898,8 @@ impl LoginConfigHandler {
self.config.lock_after_session_end
} else if name == "privacy-mode" {
self.config.privacy_mode
} else if name == "enable-file-transfer" {
self.config.enable_file_transfer
} else if name == "disable-audio" {
self.config.disable_audio
} else if name == "disable-clipboard" {
@@ -936,8 +979,7 @@ impl LoginConfigHandler {
pub fn handle_peer_info(&mut self, username: String, pi: PeerInfo) {
if !pi.version.is_empty() {
self.support_press = true;
self.support_refresh = true;
self.version = hbb_common::get_version_number(&pi.version);
}
let serde = PeerInfoSerde {
username,
@@ -964,6 +1006,25 @@ impl LoginConfigHandler {
self.save_config(config);
}
fn get_remote_dir(&self) -> String {
serde_json::from_str::<HashMap<String, String>>(&self.get_option("remote_dir"))
.unwrap_or_default()
.remove(&self.info.username)
.unwrap_or_default()
}
pub fn get_all_remote_dir(&self, path: String) -> String {
let d = self.get_option("remote_dir");
let user = self.info.username.clone();
let mut x = serde_json::from_str::<HashMap<String, String>>(&d).unwrap_or_default();
if path.is_empty() {
x.remove(&user);
} else {
x.insert(user, path);
}
serde_json::to_string::<HashMap<String, String>>(&x).unwrap_or_default()
}
fn create_login_msg(&self, password: Vec<u8>) -> Message {
#[cfg(any(target_os = "android", target_os = "ios"))]
let my_id = crate::common::MOBILE_INFO1.lock().unwrap().clone();
@@ -979,7 +1040,7 @@ impl LoginConfigHandler {
};
if self.is_file_transfer {
lr.set_file_transfer(FileTransfer {
dir: self.get_option("remote_dir"),
dir: self.get_remote_dir(),
show_hidden: !self.get_option("remote_show_hidden").is_empty(),
..Default::default()
});
@@ -996,6 +1057,68 @@ impl LoginConfigHandler {
}
}
pub enum MediaData {
VideoFrame(VideoFrame),
AudioFrame(AudioFrame),
AudioFormat(AudioFormat),
Reset,
}
pub type MediaSender = mpsc::Sender<MediaData>;
pub fn start_video_audio_threads<F>(video_callback: F) -> (MediaSender, MediaSender)
where
F: 'static + FnMut(&[u8]) + Send,
{
let (video_sender, video_receiver) = mpsc::channel::<MediaData>();
let (audio_sender, audio_receiver) = mpsc::channel::<MediaData>();
let mut video_callback = video_callback;
std::thread::spawn(move || {
let mut video_handler = VideoHandler::new();
loop {
if let Ok(data) = video_receiver.recv() {
match data {
MediaData::VideoFrame(vf) => {
if let Some(video_frame::Union::vp9s(vp9s)) = &vf.union {
if let Ok(true) = video_handler.handle_vp9s(vp9s) {
video_callback(&video_handler.rgb);
}
}
}
MediaData::Reset => {
video_handler.reset();
}
_ => {}
}
} else {
break;
}
}
log::info!("Video decoder loop exits");
});
std::thread::spawn(move || {
let mut audio_handler = AudioHandler::default();
loop {
if let Ok(data) = audio_receiver.recv() {
match data {
MediaData::AudioFrame(af) => {
audio_handler.handle_frame(af);
}
MediaData::AudioFormat(f) => {
audio_handler.handle_format(f);
}
_ => {}
}
} else {
break;
}
}
log::info!("Audio decoder loop exits");
});
return (video_sender, audio_sender);
}
pub async fn handle_test_delay(t: TestDelay, peer: &mut Stream) {
if !t.from_client {
let mut msg_out = Message::new();
@@ -1075,6 +1198,7 @@ pub enum Data {
CancelJob(i32),
RemovePortForward(i32),
AddPortForward((i32, String, i32)),
ToggleClipboardFile,
NewRDP,
}
@@ -1219,4 +1343,36 @@ pub fn check_if_retry(msgtype: &str, title: &str, text: &str) -> bool {
&& !text.to_lowercase().contains("resolve")
&& !text.to_lowercase().contains("mismatch")
&& !text.to_lowercase().contains("manually")
&& !text.to_lowercase().contains("not allowed")
}
#[inline]
fn get_pk(pk: &[u8]) -> Option<[u8; 32]> {
if pk.len() == 32 {
let mut tmp = [0u8; 32];
tmp[..].copy_from_slice(&pk);
Some(tmp)
} else {
None
}
}
#[inline]
fn get_rs_pk(str_base64: &str) -> Option<sign::PublicKey> {
if let Ok(pk) = base64::decode(str_base64) {
get_pk(&pk).map(|x| sign::PublicKey(x))
} else {
None
}
}
fn decode_id_pk(signed: &[u8], key: &sign::PublicKey) -> ResultType<(String, [u8; 32])> {
let res = IdPk::parse_from_bytes(
&sign::verify(signed, key).map_err(|_| anyhow!("Signature mismatch"))?,
)?;
if let Some(pk) = get_pk(&res.pk) {
Ok((res.id, pk))
} else {
bail!("Wrong public length");
}
}

185
src/clipboard_file.rs Normal file
View File

@@ -0,0 +1,185 @@
use clipboard::ClipbaordFile;
use hbb_common::message_proto::*;
pub fn clip_2_msg(clip: ClipbaordFile) -> Message {
match clip {
ClipbaordFile::ServerFormatList {
conn_id,
format_list,
} => {
let mut formats: Vec<CliprdrFormat> = Vec::new();
for v in format_list.iter() {
formats.push(CliprdrFormat {
conn_id: 0,
id: v.0,
format: v.1.clone(),
..Default::default()
});
}
Message {
union: Some(message::Union::cliprdr(Cliprdr {
union: Some(cliprdr::Union::format_list(CliprdrServerFormatList {
conn_id,
formats,
..Default::default()
})),
..Default::default()
})),
..Default::default()
}
}
ClipbaordFile::ServerFormatListResponse { conn_id, msg_flags } => Message {
union: Some(message::Union::cliprdr(Cliprdr {
union: Some(cliprdr::Union::format_list_response(
CliprdrServerFormatListResponse {
conn_id,
msg_flags,
..Default::default()
},
)),
..Default::default()
})),
..Default::default()
},
ClipbaordFile::ServerFormatDataRequest {
conn_id,
requested_format_id,
} => Message {
union: Some(message::Union::cliprdr(Cliprdr {
union: Some(cliprdr::Union::format_data_request(
CliprdrServerFormatDataRequest {
conn_id,
requested_format_id,
..Default::default()
},
)),
..Default::default()
})),
..Default::default()
},
ClipbaordFile::ServerFormatDataResponse {
conn_id,
msg_flags,
format_data,
} => Message {
union: Some(message::Union::cliprdr(Cliprdr {
union: Some(cliprdr::Union::format_data_response(
CliprdrServerFormatDataResponse {
conn_id,
msg_flags,
format_data,
..Default::default()
},
)),
..Default::default()
})),
..Default::default()
},
ClipbaordFile::FileContentsRequest {
conn_id,
stream_id,
list_index,
dw_flags,
n_position_low,
n_position_high,
cb_requested,
have_clip_data_id,
clip_data_id,
} => Message {
union: Some(message::Union::cliprdr(Cliprdr {
union: Some(cliprdr::Union::file_contents_request(
CliprdrFileContentsRequest {
conn_id,
stream_id,
list_index,
dw_flags,
n_position_low,
n_position_high,
cb_requested,
have_clip_data_id,
clip_data_id,
..Default::default()
},
)),
..Default::default()
})),
..Default::default()
},
ClipbaordFile::FileContentsResponse {
conn_id,
msg_flags,
stream_id,
requested_data,
} => Message {
union: Some(message::Union::cliprdr(Cliprdr {
union: Some(cliprdr::Union::file_contents_response(
CliprdrFileContentsResponse {
conn_id,
msg_flags,
stream_id,
requested_data,
..Default::default()
},
)),
..Default::default()
})),
..Default::default()
},
}
}
pub fn msg_2_clip(msg: Cliprdr) -> Option<ClipbaordFile> {
match msg.union {
Some(cliprdr::Union::format_list(data)) => {
let mut format_list: Vec<(i32, String)> = Vec::new();
for v in data.formats.iter() {
format_list.push((v.id, v.format.clone()));
}
Some(ClipbaordFile::ServerFormatList {
conn_id: data.conn_id,
format_list,
})
}
Some(cliprdr::Union::format_list_response(data)) => {
Some(ClipbaordFile::ServerFormatListResponse {
conn_id: data.conn_id,
msg_flags: data.msg_flags,
})
}
Some(cliprdr::Union::format_data_request(data)) => {
Some(ClipbaordFile::ServerFormatDataRequest {
conn_id: data.conn_id,
requested_format_id: data.requested_format_id,
})
}
Some(cliprdr::Union::format_data_response(data)) => {
Some(ClipbaordFile::ServerFormatDataResponse {
conn_id: data.conn_id,
msg_flags: data.msg_flags,
format_data: data.format_data,
})
}
Some(cliprdr::Union::file_contents_request(data)) => {
Some(ClipbaordFile::FileContentsRequest {
conn_id: data.conn_id,
stream_id: data.stream_id,
list_index: data.list_index,
dw_flags: data.dw_flags,
n_position_low: data.n_position_low,
n_position_high: data.n_position_high,
cb_requested: data.cb_requested,
have_clip_data_id: data.have_clip_data_id,
clip_data_id: data.clip_data_id,
})
}
Some(cliprdr::Union::file_contents_response(data)) => {
Some(ClipbaordFile::FileContentsResponse {
conn_id: data.conn_id,
msg_flags: data.msg_flags,
stream_id: data.stream_id,
requested_data: data.requested_data,
})
}
_ => None,
}
}

View File

@@ -4,7 +4,7 @@ use hbb_common::{
anyhow::bail,
compress::{compress as compress_func, decompress},
config::{Config, COMPRESS_LEVEL, RENDEZVOUS_TIMEOUT},
log,
get_version_number, log,
message_proto::*,
protobuf::Message as _,
protobuf::ProtobufEnum,
@@ -40,15 +40,6 @@ pub fn valid_for_numlock(evt: &KeyEvent) -> bool {
}
}
#[inline]
pub fn valid_for_capslock(evt: &KeyEvent) -> bool {
if let Some(key_event::Union::chr(ch)) = evt.union {
ch >= 'a' as u32 && ch <= 'z' as u32
} else {
false
}
}
pub fn create_clipboard_msg(content: String) -> Message {
let bytes = content.into_bytes();
let compressed = compress_func(&bytes, COMPRESS_LEVEL);
@@ -220,6 +211,7 @@ pub fn resample_channels(
}
pub fn test_nat_type() {
let mut i = 0;
std::thread::spawn(move || loop {
match test_nat_type_() {
Ok(true) => break,
@@ -231,7 +223,11 @@ pub fn test_nat_type() {
if Config::get_nat_type() != 0 {
break;
}
std::thread::sleep(std::time::Duration::from_secs(12));
i = i * 2 + 1;
if i > 300 {
i = 300;
}
std::thread::sleep(std::time::Duration::from_secs(i));
});
}
@@ -239,6 +235,10 @@ pub fn test_nat_type() {
async fn test_nat_type_() -> ResultType<bool> {
log::info!("Testing nat ...");
let is_direct = crate::ipc::get_socks_async(1_000).await.is_none(); // sync socks BTW
if !is_direct {
Config::set_nat_type(NatType::SYMMETRIC as _);
return Ok(true);
}
let start = std::time::Instant::now();
let rendezvous_server = get_rendezvous_server(1_000).await;
let server1 = rendezvous_server;
@@ -273,12 +273,9 @@ async fn test_nat_type_() -> ResultType<bool> {
RENDEZVOUS_TIMEOUT,
)
.await?;
if is_direct {
// to-do: should set NatType::UNKNOWN for proxy
addr = socket.local_addr();
}
addr = socket.local_addr();
socket.send(&msg_out).await?;
if let Some(Ok(bytes)) = socket.next_timeout(3000).await {
if let Some(Ok(bytes)) = socket.next_timeout(RENDEZVOUS_TIMEOUT).await {
if let Ok(msg_in) = RendezvousMessage::parse_from_bytes(&bytes) {
if let Some(rendezvous_message::Union::test_nat_response(tnr)) = msg_in.union {
if i == 0 {
@@ -422,14 +419,6 @@ pub fn is_modifier(evt: &KeyEvent) -> bool {
}
}
pub fn get_version_number(v: &str) -> i64 {
let mut n = 0;
for x in v.split(".") {
n = n * 1000 + x.parse::<i64>().unwrap_or(0);
}
n
}
pub fn check_software_update() {
std::thread::spawn(move || allow_err!(_check_software_update()));
}
@@ -462,9 +451,22 @@ async fn _check_software_update() -> hbb_common::ResultType<()> {
Ok(())
}
#[cfg(target_os = "macos")]
pub fn get_full_name() -> String {
format!(
"{}.{}",
hbb_common::config::ORG,
hbb_common::config::APP_NAME,
)
}
pub fn is_ip(id: &str) -> bool {
hbb_common::regex::Regex::new(r"^\d+\.\d+\.\d+\.\d+$")
hbb_common::regex::Regex::new(r"^\d+\.\d+\.\d+\.\d+(:\d+)?$")
.unwrap()
.is_match(id)
}
#[inline]
pub fn get_app_name() -> &'static str {
hbb_common::config::APP_NAME
}

View File

@@ -1,7 +1,9 @@
use crate::rendezvous_mediator::RendezvousMediator;
pub use clipboard::ClipbaordFile;
use hbb_common::{
allow_err, bail, bytes,
bytes_codec::BytesCodec,
config::{self, Config},
config::{self, Config, Config2},
futures::StreamExt as _,
futures_util::sink::SinkExt,
log, timeout, tokio,
@@ -71,6 +73,8 @@ pub enum Data {
keyboard: bool,
clipboard: bool,
audio: bool,
file: bool,
file_transfer_enabled: bool,
},
ChatMessage {
text: String,
@@ -92,6 +96,10 @@ pub enum Data {
Socks(Option<config::Socks5Server>),
FS(FS),
Test,
SyncConfig(Option<(Config, Config2)>),
#[cfg(not(any(target_os = "android", target_os = "ios")))]
ClipbaordFile(ClipbaordFile),
ClipboardFileEnabled(bool),
}
#[tokio::main(flavor = "current_thread")]
@@ -158,6 +166,30 @@ pub async fn new_listener(postfix: &str) -> ResultType<Incoming> {
}
}
pub struct CheckIfRestart(String, Vec<String>, String);
impl CheckIfRestart {
pub fn new() -> CheckIfRestart {
CheckIfRestart(
Config::get_option("stop-service"),
Config::get_rendezvous_servers(),
Config::get_option("audio-input"),
)
}
}
impl Drop for CheckIfRestart {
fn drop(&mut self) {
if self.0 != Config::get_option("stop-service")
|| self.1 != Config::get_rendezvous_servers()
{
RendezvousMediator::restart();
}
if self.2 != Config::get_option("audio-input") {
crate::audio_service::restart();
}
}
}
async fn handle(data: Data, stream: &mut Connection) {
match data {
Data::SystemInfo(_) => {
@@ -203,7 +235,8 @@ async fn handle(data: Data, stream: &mut Connection) {
} else {
Config::set_socks(Some(data));
}
crate::rendezvous_mediator::RendezvousMediator::restart();
crate::common::test_nat_type();
RendezvousMediator::restart();
log::info!("socks updated");
}
},
@@ -245,13 +278,37 @@ async fn handle(data: Data, stream: &mut Connection) {
allow_err!(stream.send(&Data::Options(Some(v))).await);
}
Some(value) => {
let v0 = Config::get_option("stop-service");
let v1 = Config::get_rendezvous_servers();
let v2 = Config::get_option("audio-input");
Config::set_options(value);
if v0 != Config::get_option("stop-service")
|| v1 != Config::get_rendezvous_servers()
{
RendezvousMediator::restart();
}
if v2 != Config::get_option("audio-input") {
crate::audio_service::restart();
}
allow_err!(stream.send(&Data::Options(None)).await);
}
},
Data::NatType(_) => {
let t = Config::get_nat_type();
allow_err!(stream.send(&Data::NatType(Some(t))).await);
}
Data::SyncConfig(Some((config, config2))) => {
Config::set(config);
Config2::set(config2);
allow_err!(stream.send(&Data::SyncConfig(None)).await);
}
Data::SyncConfig(None) => {
allow_err!(
stream
.send(&Data::SyncConfig(Some((Config::get(), Config2::get()))))
.await
);
}
_ => {}
}
}
@@ -277,10 +334,12 @@ async fn check_pid(postfix: &str) {
file.read_to_string(&mut content).ok();
let pid = content.parse::<i32>().unwrap_or(0);
if pid > 0 {
if let Ok(p) = psutil::process::Process::new(pid as _) {
if let Ok(current) = psutil::process::Process::current() {
if current.name().unwrap_or("".to_owned()) == p.name().unwrap_or("".to_owned())
{
use sysinfo::{ProcessExt, System, SystemExt};
let mut sys = System::new();
sys.refresh_processes();
if let Some(p) = sys.process(pid.into()) {
if let Some(current) = sys.process((std::process::id() as i32).into()) {
if current.name() == p.name() {
// double check with connect
if connect(1000, postfix).await.is_ok() {
return;
@@ -360,6 +419,20 @@ where
}
}
}
pub async fn send_raw(&mut self, data: Vec<u8>) -> ResultType<()> {
self.inner.send(bytes::Bytes::from(data)).await?;
Ok(())
}
pub async fn next_raw(&mut self) -> ResultType<bytes::BytesMut> {
match self.inner.next().await {
Some(Ok(res)) => Ok(res),
_ => {
bail!("reset by the peer");
}
}
}
}
#[tokio::main(flavor = "current_thread")]
@@ -459,11 +532,12 @@ pub fn set_option(key: &str, value: &str) {
#[tokio::main(flavor = "current_thread")]
pub async fn set_options(value: HashMap<String, String>) -> ResultType<()> {
Config::set_options(value.clone());
connect(1000, "")
.await?
.send(&Data::Options(Some(value)))
.await?;
if let Ok(mut c) = connect(1000, "").await {
c.send(&Data::Options(Some(value.clone()))).await?;
// do not put below before connect, because we need to check should_exit
c.next_timeout(1000).await.ok();
}
Config::set_options(value);
Ok(())
}

View File

@@ -1,20 +1,25 @@
use hbb_common::{config::Config, log};
use hbb_common::{config::LocalConfig, log};
use std::ops::Deref;
mod cn;
mod en;
mod fr;
mod it;
mod tw;
mod de;
mod ru;
mod eo;
mod ptbr;
#[cfg(not(any(target_os = "android", target_os = "ios")))]
pub fn translate(name: String) -> String {
let locale = sys_locale::get_locale().unwrap_or_default().to_lowercase();
log::debug!("The current locale is {}", locale);
log::trace!("The current locale is {}", locale);
translate_locale(name, &locale)
}
pub fn translate_locale(name: String, locale: &str) -> String {
let mut lang = Config::get_option("lang");
let mut lang = LocalConfig::get_option("lang");
if lang.is_empty() {
lang = locale
.split("-")
@@ -23,15 +28,28 @@ pub fn translate_locale(name: String, locale: &str) -> String {
.unwrap_or_default()
.to_owned();
}
let m = match lang.to_lowercase().as_str() {
let lang = lang.to_lowercase();
let m = match lang.as_str() {
"fr" => fr::T.deref(),
"cn" => cn::T.deref(),
"it" => it::T.deref(),
"tw" => tw::T.deref(),
"de" => de::T.deref(),
"ru" => ru::T.deref(),
"eo" => eo::T.deref(),
"ptbr" => ptbr::T.deref(),
"br" => ptbr::T.deref(),
"pt" => ptbr::T.deref(),
_ => en::T.deref(),
};
if let Some(v) = m.get(&name as &str) {
v.to_string()
} else {
if lang != "en" {
if let Some(v) = en::T.get(&name as &str) {
return v.to_string();
}
}
name
}
}

View File

@@ -3,12 +3,14 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
[
("Status", "状态"),
("Your Desktop", "你的桌面"),
("desk_tip", "你的桌面可以通过下面的 ID和密码访问。"),
("desk_tip", "你的桌面可以通过下面的ID和密码访问。"),
("Password", "密码"),
("Ready", "就绪"),
("Established", "已建立"),
("connecting_status", "正在接入RustDesk网络..."),
("Enable Service", "允许服务"),
("Start Service", "启动服务"),
("Service is running", "服务正在运行"),
("Service is not running", "服务没有启动"),
("not_ready_status", "未就绪,请检查网络连接"),
("Control Remote Desktop", "控制远程桌面"),
@@ -62,23 +64,38 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Login Error", "登录错误"),
("Successful", "成功"),
("Connected, waiting for image...", "已连接,等待画面传输..."),
("Name", "文件"),
("Name", ""),
("Type", "类型"),
("Modified", "修改时间"),
("Size", "大小"),
("Show Hidden Files", "显示隐藏文件"),
("Receive", "接受"),
("Send", "发送"),
("Refresh File", "刷新文件"),
("Local", "本地"),
("Remote", "远程"),
("Remote Computer", "远程电脑"),
("Local Computer", "本地电脑"),
("Confirm Delete", "确认删除"),
("Delete", "删除"),
("Properties", "属性"),
("Multi Select", "多选"),
("Empty Directory", "空文件夹"),
("Not an empty directory", "这不是一个空文件夹"),
("Are you sure you want to delete this file?", "是否删除此文件?"),
("Are you sure you want to delete this empty directory?", "是否删除此空文件夹?"),
("Are you sure you want to delete the file of this directory?", "是否删除文件夹下的文件?"),
("Do this for all conflicts", "应用于其它冲突"),
("This is irreversible!", "此操作不可逆!"),
("Deleting", "正在删除"),
("files", "文件"),
("Waiting", "等待..."),
("Finished", "完成"),
("Speed", "速度"),
("Custom Image Quality", "设置画面质量"),
("Privacy mode", "隐私模式"),
("Block user input", "阻止用户输入"),
("Unblock user input", "取消阻止用户输入"),
("Adjust Window", "调节窗口"),
("Original", "原始比例"),
("Shrink", "收缩"),
@@ -107,7 +124,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("OS Password", "操作系统密码"),
("install_tip", "你正在运行未安装版本由于UAC限制作为被控端会在某些情况下无法控制鼠标键盘或者录制屏幕请点击下面的按钮将RustDesk安装到系统从而规避上述问题。"),
("Click to upgrade", "点击这里升级"),
("Configuration Permissions", "配置权限"),
("Click to download", "点击这里下载"),
("Click to update", "点击这里更新"),
("Configure", "配置"),
("config_acc", "为了能够远程控制你的桌面, 请给予RustDesk\"辅助功能\" 权限。"),
("config_screen", "为了能够远程访问你的桌面, 请给予RustDesk\"屏幕录制\" 权限。"),
@@ -139,6 +157,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Allow using keyboard and mouse", "允许使用键盘鼠标"),
("Allow using clipboard", "允许使用剪贴板"),
("Allow hearing sound", "允许听到声音"),
("Allow file transfer", "允许文件传输"),
("File transfer", "文件传输"),
("Connected", "已经连接"),
("Direct and encrypted connection", "加密直连"),
("Relayed and encrypted connection", "加密中继连接"),
@@ -194,5 +214,59 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Invalid folder name", "无效文件夹名称"),
("Socks5 Proxy", "Socks5 代理"),
("Hostname", "主机名"),
("Discovered", "已发现"),
("install_daemon_tip", "为了开机启动,请安装系统服务。"),
("Remote ID", "远程ID"),
("Paste", "粘贴"),
("Paste here?", "粘贴到这里?"),
("Are you sure to close the connection?", "是否确认关闭连接?"),
("Download new version", "下载新版本"),
("Touch mode", "触屏模式"),
("Mouse mode", "鼠标模式"),
("One-Finger Tap", "单指轻触"),
("Left Mouse", "鼠标左键"),
("One-Long Tap", "单指长按"),
("Two-Finger Tap", "双指轻触"),
("Right Mouse", "鼠标右键"),
("One-Finger Move", "单指移动"),
("Double Tap & Move", "双击并移动"),
("Mouse Drag", "鼠标选中拖动"),
("Two-Finger vertically", "双指垂直滑动"),
("Mouse Wheel", "鼠标滚轮"),
("Two-Finger Move", "双指移动"),
("Canvas Move", "移动画布"),
("Pinch to Zoom", "双指缩放"),
("Canvas Zoom", "缩放画布"),
("Reset canvas", "重置画布"),
("No permission of file transfer", "没有文件传输权限"),
("Note", "备注"),
("Connection", "连接"),
("Share Screen", "共享屏幕"),
("CLOSE", "关闭"),
("OPEN", "开启"),
("Chat", "聊天消息"),
("Total", "总计"),
("items", "个项目"),
("Selected", "已选择"),
("Screen Capture", "屏幕录制"),
("Input Control", "输入控制"),
("File Transfer", "文件传输"),
("Audio Capture", "音频录制"),
("File Connection", "文件连接"),
("Screen Connection", "屏幕连接"),
("Do you accept?", "是否接受?"),
("Open System Setting", "打开系统设置"),
("How to get Android input permission?", "如何获取安卓的输入权限?"),
("android_input_permission_tip1", "為了讓遠程設備通過鼠標或者觸屏控制您的安卓設備你需要允許RustDesk使用\"無障礙\"服務。"),
("android_input_permission_tip2", "请在接下来的系统设置页面里,找到并进入 [已安装的服务] 页面,将 [RustDesk Input] 服务开启。"),
("android_new_connection_tip", "收到新的连接控制请求,对方想要控制你当前的设备。"),
("android_service_will_start_tip", "开启录屏权限将自动开启服务,允许其他设备向此设备请求建立连接。"),
("android_stop_service_tip", "关闭服务将自动关闭所有已建立的连接。"),
("android_version_audio_tip", "当前安卓版本不支持音频录制请升级至安卓10或更高。"),
("android_start_service_tip", "点击 [启动服务] 或打开 [屏幕录制] 权限开启手机屏幕共享服务。"),
("Account", "账号"),
("Quit", "退出"),
("doc_mac_permission", "https://rustdesk.com/docs/zh-cn/manual/mac/#启用权限"),
("Help", "帮助"),
].iter().cloned().collect();
}
}

271
src/lang/de.rs Normal file
View File

@@ -0,0 +1,271 @@
lazy_static::lazy_static! {
pub static ref T: std::collections::HashMap<&'static str, &'static str> =
[
("Status", "Status"),
("Your Desktop", "Ihr Desktop"),
("desk_tip", "Mit dieser ID und diesem Passwort können Sie auf Ihren Desktop zugreifen."),
("Password", "Passwort"),
("Ready", "Bereit"),
("Established", "Etabliert"),
("connecting_status", "Verbinden mit dem RustDesk-Netzwerk..."),
("Enable Service", "Verbindungsserver einschalten"),
("Start Service", "Starte Verbindungsserver"),
("Service is running", "Dienst läuft"),
("Service is not running", "Der Verbindungsserver läuft nicht"),
("not_ready_status", "Nicht bereit. Bitte überprüfen Sie Ihre Verbindung"),
("Control Remote Desktop", "Entfernten Desktop steuern"),
("Transfer File", "Datei übertragen"),
("Connect", "Verbinden"),
("Recent Sessions", "Letzte Sitzungen"),
("Address Book", "Adressbuch"),
("Confirmation", "Bestätigung"),
("TCP Tunneling", "TCP Tunneln"),
("Remove", "Entfernen"),
("Refresh random password", "Zufälliges Passwort aktualisieren"),
("Set your own password", "Legen Sie Ihr eigenes Passwort fest"),
("Enable Keyboard/Mouse", "Tastatur/Maus einschalten"),
("Enable Clipboard", "Zwischenablage einschalten"),
("Enable File Transfer", "Dateiübertragung aktivieren"),
("Enable TCP Tunneling", "TCP-Tunneling einschalten"),
("IP Whitelisting", "IP Freigabeliste"),
("ID/Relay Server", "ID/Verbindungsserver"),
("Stop service", "Verbindungsserver ausschalten"),
("Change ID", "ID wechseln"),
("Website", "Webseite"),
("About", "Über"),
("Mute", "Stummschalten"),
("Audio Input", "Audio-Eingang"),
("ID Server", "ID Server"),
("Relay Server", "Verbindungsserver Server"),
("API Server", "API Server"),
("invalid_http", "Muss mit http:// oder https:// beginnen"),
("Invalid IP", "Ungültige IP-Adresse"),
("id_change_tip", "Nur die Zeichen a-z, A-Z, 0-9 und _ (Unterstrich) sind erlaubt. Der erste Buchstabe muss a-z, A-Z sein. Länge zwischen 6 und 16."),
("Invalid format", "Ungültiges Format"),
("This function is turned off by the server", "Diese Funktion wird vom Server nicht bereitgestellt"),
("Not available", "Nicht verfügbar"),
("Too frequent", "Zu häufig"),
("Cancel", "Abbrechen"),
("Skip", "Überspringen"),
("Close", "Schließen"),
("Retry", "Nochmal versuchen"),
("OK", "OK"),
("Password Required", "Passwort erforderlich"),
("Please enter your password", "Bitte geben Sie Ihr Passwort ein"),
("Remember password", "Passwort merken"),
("Wrong Password", "Falsches Passwort"),
("Do you want to enter again?", "Möchten Sie erneut teilnehmen?"),
("Connection Error", "Verbindungsfehler"),
("Error", "Fehler"),
("Reset by the peer", "Zurücksetzen durch die Gegenstelle"),
("Connecting...", "Verbinden..."),
("Connection in progress. Please wait.", "Die Verbindung wird hergestellt. Bitte warten Sie."),
("Please try 1 minute later", "Bitte versuchen Sie es 1 Minute später"),
("Login Error", "Anmeldefehler"),
("Successful", "Erfolgreich"),
("Connected, waiting for image...", "Verbunden, warten auf Bild..."),
("Name", "Name"),
("Type", "Typ"),
("Modified", "Geändert"),
("Size", "Größe"),
("Show Hidden Files", "Versteckte Dateien anzeigen"),
("Receive", "Empfangen"),
("Send", "Senden"),
("Refresh File", "Datei aktualisieren"),
("Local", "Lokaler"),
("Remote", "Entfernter"),
("Remote Computer", "Entfernter Computer"),
("Local Computer", "Lokaler Computer"),
("Confirm Delete", "Löschen bestätigen"),
("Delete", "Löschen"),
("Properties", "Eigenschaften"),
("Multi Select", "Mehrfachauswahl"),
("Empty Directory", "Leeres Verzeichnis"),
("Not an empty directory", "Kein leeres Verzeichnis"),
("Are you sure you want to delete this file?", "Sind Sie sicher, dass Sie diese Datei löschen wollen?"),
("Are you sure you want to delete this empty directory?", "Sind Sie sicher, dass Sie dieses leere Verzeichnis löschen möchten?"),
("Are you sure you want to delete the file of this directory?", "Sind Sie sicher, dass Sie die Datei dieses Verzeichnisses löschen möchten?"),
("Do this for all conflicts", "Dies gilt für alle Konflikte"),
("This is irreversible!", "Dies ist irreversibel!"),
("Deleting", "Löschen"),
("files", "Dateien"),
("Waiting", "Warten"),
("Finished", "Fertiggestellt"),
("Speed", "Geschwindigkeit"),
("Custom Image Quality", "Individuelle Bildqualität"),
("Privacy mode", "Datenschutz-Modus"),
("Block user input", "Benutzereingaben blockieren"),
("Unblock user input", "Benutzereingaben freigeben"),
("Adjust Window", "Fenster anpassen"),
("Original", "Original"),
("Shrink", "Geschrumpft"),
("Stretch", "Gestreckt"),
("Good image quality", "Gute Bildqualität"),
("Balanced", "Ausgeglichen"),
("Optimize reaction time", "Optimierte Reaktionszeit"),
("Custom", "Benutzerdefiniert"),
("Show remote cursor", "Ferngesteuerten Cursor anzeigen"),
("Disable clipboard", "Zwischenablage deaktivieren"),
("Lock after session end", "Sperren nach Sitzungsende"),
("Insert", "Einfügen"),
("Insert Lock", "Sperre einfügen"),
("Refresh", "Aktualisieren"),
("ID does not exist", "Die ID existiert nicht"),
("Failed to connect to rendezvous server", "Verbindung zum Verbindungsserver fehlgeschlagen"),
("Please try later", "Bitte versuchen Sie es später"),
("Remote desktop is offline", "Entfernter Desktop ist offline"),
("Key mismatch", "Schlüssel nicht übereinstimmend"),
("Timeout", "Zeitüberschreitung"),
("Failed to connect to relay server", "Verbindung zum Verbindungsserver fehlgeschlagen"),
("Failed to connect via rendezvous server", "Verbindung über rendezvous server fehlgeschlagen"),
("Failed to connect via relay server", "Verbindung über den Verbindungsserver ist fehlgeschlagen"),
("Failed to make direct connection to remote desktop", "Direkte Verbindung zum Entfernten-Desktop konnte nicht hergestellt werden"),
("Set Password", "Passwort festlegen"),
("OS Password", "Betriebssystem-Passwort"),
("install_tip", "Aufgrund der UAC kann RustDesk in manchen Fällen nicht ordnungsgemäß auf der Gegenseite funktionieren. Um UAC zu vermeiden, klicken Sie bitte auf die Schaltfläche unten, um RustDesk auf dem System zu installieren"),
("Click to upgrade", "Zum Upgrade anklicken"),
("Click to download", "Zum Herunterladen klicken"),
("Click to update", "Zum Aktualisieren klicken"),
("Configure", "Konfigurieren"),
("config_acc", "Um Ihren Desktop aus der Ferne zu steuern, müssen Sie RustDesk \"Zugangs\" Rechte erteilen."),
("config_screen", "Um aus der Ferne auf Ihren Desktop zugreifen zu können, müssen Sie RustDesk \"Bildschirm-Aufnahme\" Berechtigungen erteilen."),
("Installing ...", "Installiere ..."),
("Install", "Installieren"),
("Installation", "Einrichtung"),
("Installation Path", "Einrichtungs Pfad"),
("Create start menu shortcuts", "Startmenü Verknüpfungen erstellen"),
("Create desktop icon", "Desktop Symbol erstellen"),
("agreement_tip", "Wenn Sie die Einrichtung starten, akzeptieren Sie die Lizenzvereinbarung"),
("Accept and Install", "Akzeptieren und installieren"),
("End-user license agreement", "Lizenzvereinbarung für Endbenutzer"),
("Generating ...", "Generierung ..."),
("Your installation is lower version.", "Ihre Installation ist eine niedrigere Version."),
("not_close_tcp_tip", "Schließen Sie dieses Fenster nicht, während Sie den Tunnel benutzen."),
("Listening ...", "Hören ..."),
("Remote Host", "Entfernter Rechner"),
("Remote Port", "Entfernter Port"),
("Action", "Aktion"),
("Add", "Hinzufügen"),
("Local Port", "Lokaler Port"),
("setup_server_tip", "Für eine schnellere Verbindung, richten Sie bitte Ihren eigenen Verbindungsserver ein"),
("Too short, at least 6 characters.", "Zu kurz, mindestens 6 Zeichen."),
("The confirmation is not identical.", "Die Bestätigung ist nicht identisch."),
("Permissions", "Berechtigungen"),
("Accept", "Akzeptieren"),
("Dismiss", "Ablehnen"),
("Disconnect", "Verbindung trennen"),
("Allow using keyboard and mouse", "Erlaubt die Verwendung von Tastatur und Maus"),
("Allow using clipboard", "Verwendung der Zwischenablage zulassen"),
("Allow hearing sound", "Erlaubt das Hören von Sound"),
("Allow file transfer", "Dateiübertragung zulassen"),
("File transfer", "Datei Übertragung"),
("Connected", "Verbunden"),
("Direct and encrypted connection", "Direkte und verschlüsselte Verbindung"),
("Relayed and encrypted connection", "Vermittelte und verschlüsselte Verbindung"),
("Direct and unencrypted connection", "Direkte und unverschlüsselte Verbindung"),
("Relayed and unencrypted connection", "Vermittelte und unverschlüsselte Verbindung"),
("Enter Remote ID", "Remote-ID eingeben"),
("Enter your password", "Geben Sie Ihr Passwort ein"),
("Logging in...", "Anmeldung..."),
("Enable RDP session sharing", "RDP-Sitzungsfreigabe aktivieren"),
("Auto Login", "Automatisches Login (nur gültig, wenn Sie \"Sperren nach Sitzungsende\" eingestellt haben)"),
("Enable Direct IP Access", "Direkten IP-Zugang aktivieren"),
("Rename", "Umbenennen"),
("Space", "Platz"),
("Create Desktop Shortcut", "Desktop-Verknüpfung erstellen"),
("Change Path", "Pfad ändern"),
("Create Folder", "Ordner erstellen"),
("Please enter the folder name", "Bitte geben Sie den Ordnernamen ein"),
("Fix it", "Reparieren"),
("Warning", "Warnung"),
("Login screen using Wayland is not supported", "Anmeldebildschirm mit Wayland wird nicht unterstützt"),
("Reboot required", "Neustart erforderlich"),
("Unsupported display server ", "Nicht unterstützter Display-Server"),
("x11 expected", "X11 erwartet"),
("Port", "Port"),
("Settings", "Einstellungen"),
("Username", " Benutzername"),
("Invalid port", "Ungültiger Port"),
("Closed manually by the peer", "Vom Peer manuell geschlossen"),
("Enable remote configuration modification", "Änderung der Fernkonfiguration zulassen"),
("Run without install", "Ohne Installation ausführen"),
("Always connected via relay", "Immer über Verbindungsserver verbunden"),
("Always connect via relay", "Verbindung immer über Verbindungsserver"),
("whitelist_tip", "Nur IPs auf der Freigabeliste können auf mich zugreifen"),
("Login", "Anmeldung"),
("Logout", "Abmeldung"),
("Tags", "Stichworte"),
("Search ID", "Suche ID"),
("Current Wayland display server is not supported", "Der aktuelle Wayland-Anzeigeserver wird nicht unterstützt"),
("whitelist_sep", "Getrennt durch Komma, Semikolon, Leerzeichen oder Zeilenumbruch"),
("Add ID", "ID hinzufügen"),
("Add Tag", "Stichwort hinzufügen"),
("Unselect all tags", "Alle Stichworte abwählen"),
("Network error", "Netzwerkfehler"),
("Username missed", "Benutzername fehlt"),
("Password missed", "Passwort vergessen"),
("Wrong credentials", "Falsche Anmeldedaten"),
("Edit Tag", "Stichwort bearbeiten"),
("Unremember Password", "Passwort nicht merken"),
("Favorites", "Favoriten"),
("Add to Favorites", "Zu Favoriten hinzufügen"),
("Remove from Favorites", "Entferne von Favoriten"),
("Empty", "Leer"),
("Invalid folder name", "Ungültiger Ordnername"),
("Socks5 Proxy", "Socks5 Proxy"),
("Hostname", "Rechnername"),
("Discovered", "Gefunden"),
("install_daemon_tip", "Um beim Booten zu starten, müssen Sie den Systemdienst installieren"),
("Remote ID", "Entfernte ID"),
("Paste", "Einfügen"),
("Paste here?", "Hier einfügen?"),
("Are you sure to close the connection?", "Sind Sie sicher, dass Sie die Verbindung schließen wollen?"),
("Download new version", "Neue Version herunterladen"),
("Touch mode", "Touch-Modus"),
("Mouse mode", "Mouse-Modus"),
("One-Finger Tap", "Ein Fingertipp"),
("Left Mouse", "Linke Maus"),
("One-Long Tap", "Tippen Sie mit einem Finger lang"),
("Two-Finger Tap", "Zwei Finger tippen"),
("Right Mouse", "Rechte Maus"),
("One-Finger Move", "Eine Fingerbewegung"),
("Double Tap & Move", "Doppeltippen und verschieben"),
("Mouse Drag", "Maus ziehen"),
("Two-Finger vertically", "Zwei Finger vertikal"),
("Mouse Wheel", "Mausrad"),
("Two-Finger Move", "Zwei Finger Bewegung"),
("Canvas Move", "Leinwand bewegen"),
("Pinch to Zoom", "Zum Zoomen kneifen"),
("Canvas Zoom", "Leinwand Zoom"),
("Reset canvas", "Anzeige zurücksetzen"),
("No permission of file transfer", "Keine Erlaubnis zur Dateiübertragung"),
("Note", "Notiz"),
("Connection", "Verbindung"),
("Share Screen", "Bildschirm freigeben"),
("CLOSE", "NAH DRAN"),
("OPEN", "OFFEN"),
("Chat", "Plaudern"),
("Total", "Gesamt"),
("items", "Artikel"),
("Selected", "Ausgewählt"),
("Screen Capture", "Bildschirmaufnahme"),
("Input Control", "Eingabesteuerung"),
("File Transfer", "Datei Übertragung"),
("Audio Capture", "Audioaufnahme"),
("File Connection", "Dateiverbindung"),
("Screen Connection", "Bildschirmanschluss"),
("Do you accept?", "Akzeptieren Sie?"),
("Open System Setting", "Systemeinstellung öffnen"),
("How to get Android input permission?", "Wie erhalte ich eine Android-Eingabeberechtigung?"),
("android_input_permission_tip1", "Damit ein Remote-Gerät Ihr Android-Gerät per Maus oder Berührung steuern kann, müssen Sie RustDesk erlauben, den Dienst \"Barrierefreiheit\" zu verwenden."),
("android_input_permission_tip2", "Bitte gehen Sie zur nächsten Systemeinstellungsseite, suchen und geben Sie [Installierte Dienste] ein, schalten Sie den Dienst [RustDesk Input] ein."),
("android_new_connection_tip", "Es wurde eine neue Steuerungsanforderung empfangen, die Ihr aktuelles Gerät steuern möchte."),
("android_service_will_start_tip", "Durch das Einschalten der Bildschirmaufnahme wird der Dienst automatisch gestartet, sodass andere Geräte eine Verbindung von diesem Gerät anfordern können."),
("android_stop_service_tip", "Durch das Schließen des Dienstes werden automatisch alle hergestellten Verbindungen geschlossen."),
("android_version_audio_tip", "Die aktuelle Android-Version unterstützt keine Audioaufnahme, bitte aktualisieren Sie auf Android 10 oder höher."),
("android_start_service_tip", "Tippen Sie auf [Dienst starten] oder ÖFFNEN Sie die Berechtigung [Bildschirmaufnahme], um den Bildschirmfreigabedienst zu starten."),
("Account", "Konto"),
("Quit", "Ausgang"),
("Help", "Hilfe"),
].iter().cloned().collect();
}

View File

@@ -16,5 +16,14 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("whitelist_sep", "Seperated by comma, semicolon, spaces or new line"),
("Wrong credentials", "Wrong username or password"),
("invalid_http", "must start with http:// or https://"),
("install_daemon_tip", "For starting on boot, you need to install system service."),
("android_input_permission_tip1", "In order for a remote device to control your Android device via mouse or touch, you need to allow RustDesk to use the \"Accessibility\" service."),
("android_input_permission_tip2", "Please go to the next system settings page, find and enter [Installed Services], turn on [RustDesk Input] service."),
("android_new_connection_tip", "New control request has been received, which wants to control your current device."),
("android_service_will_start_tip", "Turning on \"Screen Capture\" will automatically start the service, allowing other devices to request a connection to your device."),
("android_stop_service_tip", "Closing the service will automatically close all established connections."),
("android_version_audio_tip", "The current Android version does not support audio capture, please upgrade to Android 10 or higher."),
("android_start_service_tip", "Tap [Start Service] or OPEN [Screen Capture] permission to start the screen sharing service."),
("doc_mac_permission", "https://rustdesk.com/docs/en/manual/mac/#enable-permissions"),
].iter().cloned().collect();
}

269
src/lang/eo.rs Normal file
View File

@@ -0,0 +1,269 @@
lazy_static::lazy_static! {
pub static ref T: std::collections::HashMap<&'static str, &'static str> =
[
("Status", "Stato"),
("Your Desktop", "Via aparato"),
("desk_tip", "Via aparato povas esti alirita kun tiu identigilo kaj pasvorto"),
("Password", "Pasvorto"),
("Ready", "Preta"),
("Established", ""),
("connecting_status", "Konektante al la reto RustDesk..."),
("Enable Service", "Ebligi servon"),
("Start Service", "Starti servon"),
("Service is running", ""),
("Service is not running", "La servo ne funkcias"),
("not_ready_status", "Ne preta, bonvolu kontroli la retkonekto"),
("Control Remote Desktop", "Kontroli foran aparaton"),
("Transfer File", "Transigi dosieron"),
("Connect", "Konekti al"),
("Recent Sessions", "Lastaj sesioj"),
("Address Book", "Adresaro"),
("Confirmation", "Konfirmacio"),
("TCP Tunneling", "Tunelado TCP"),
("Remove", "Forigi"),
("Refresh random password", "Regeneri hazardan pasvorton"),
("Set your own password", "Agordi vian propran pasvorton"),
("Enable Keyboard/Mouse", "Ebligi klavaro/muso"),
("Enable Clipboard", "Sinkronigi poŝon"),
("Enable File Transfer", "Ebligi dosiertransigado"),
("Enable TCP Tunneling", "Ebligi tunelado TCP"),
("IP Whitelisting", "Listo de IP akceptataj"),
("ID/Relay Server", "Identigila/Relajsa servilo"),
("Stop service", "Haltu servon"),
("Change ID", "Ŝanĝi identigilon"),
("Website", "Retejo"),
("About", "Pri"),
("Mute", "Muta"),
("Audio Input", "Aŭdia enigo"),
("ID Server", "Servilo de identigiloj"),
("Relay Server", "Relajsa servilo"),
("API Server", "Servilo de API"),
("invalid_http", "Devas komenci kun http:// aŭ https://"),
("Invalid IP", "IP nevalida"),
("id_change_tip", "Nur la signoj a-z, A-Z, 0-9, _ (substreko) povas esti uzataj. La unua litero povas esti inter a-z, A-Z. La longeco devas esti inter 6 kaj 16."),
("Invalid format", "Formato nevalida"),
("This function is turned off by the server", "Tiu funkcio estas malebligata de la servilo"),
("Not available", "Nedisponebla"),
("Too frequent", "Tro ofte ŝanĝita, bonvolu reprovi poste"),
("Cancel", "Nuligi"),
("Skip", "Ignori"),
("Close", "Fermi"),
("Retry", "Reprovi"),
("OK", "Konfermi"),
("Password Required", "Pasvorto deviga"),
("Please enter your password", "Bonvolu tajpi vian pasvorton"),
("Remember password", "Memori pasvorton"),
("Wrong Password", "Erara pasvorto"),
("Do you want to enter again?", "Ĉu vi aliri denove?"),
("Connection Error", "Eraro de konektado"),
("Error", "Eraro"),
("Reset by the peer", "La konekto estas fermita de la samtavolano"),
("Connecting...", "Konektante..."),
("Connection in progress. Please wait.", "Konektado farata. Bonvolu atendi."),
("Please try 1 minute later", "Reprovi post 1 minuto"),
("Login Error", "Eraro de konektado"),
("Successful", "Sukceso"),
("Connected, waiting for image...", "Konektita, atendante bildon..."),
("Name", "Nomo"),
("Type", ""),
("Modified", "Modifita"),
("Size", "Grandeco"),
("Show Hidden Files", "Montri kaŝitajn dosierojn"),
("Receive", "Akcepti"),
("Send", "Sendi"),
("Refresh File", ""),
("Local", ""),
("Remote", ""),
("Remote Computer", "Fora komputilo"),
("Local Computer", "Loka komputilo"),
("Confirm Delete", "Konfermi la forigo"),
("Delete", ""),
("Properties", ""),
("Multi Select", ""),
("Empty Directory", ""),
("Not an empty directory", ""),
("Are you sure you want to delete this file?", "Ĉu vi vere volas forigi tiun dosieron?"),
("Are you sure you want to delete this empty directory?", ""),
("Are you sure you want to delete the file of this directory?", ""),
("Do this for all conflicts", "Same por ĉiuj konfliktoj"),
("This is irreversible!", ""),
("Deleting", "Forigado"),
("files", "dosiero"),
("Waiting", "Atendante..."),
("Finished", "Finita"),
("Speed", ""),
("Custom Image Quality", "Agordi bildan kvaliton"),
("Privacy mode", "Modo privata"),
("Block user input", "Bloki uzanta enigo"),
("Unblock user input", "Malbloki uzanta enigo"),
("Adjust Window", "Adapti fenestro"),
("Original", "Originala rilatumo"),
("Shrink", "Ŝrumpi"),
("Stretch", "Streĉi"),
("Good image quality", "Bona bilda kvalito"),
("Balanced", "Normala bilda kvalito"),
("Optimize reaction time", "Optimigi reakcia tempo"),
("Custom", "Personigi bilda kvalito"),
("Show remote cursor", "Montri foran kursoron"),
("Disable clipboard", "Malebligi poŝon"),
("Lock after session end", "Ŝlosi foran komputilon post malkonektado"),
("Insert", "Enmeti"),
("Insert Lock", "Ŝlosi foran komputilon"),
("Refresh", "Refreŝigi ekranon"),
("ID does not exist", "La identigilo ne ekzistas"),
("Failed to connect to rendezvous server", "Malsukcesis konekti al la servilo rendezvous"),
("Please try later", "Bonvolu provi poste"),
("Remote desktop is offline", "La fora aparato estas senkonektita"),
("Key mismatch", "Miskongruo de klavoj"),
("Timeout", "Konekta posttempo"),
("Failed to connect to relay server", "Malsukcesis konekti al la relajsa servilo"),
("Failed to connect via rendezvous server", "Malsukcesis konekti per servilo rendezvous"),
("Failed to connect via relay server", "Malsukcesis konekti per relajsa servilo"),
("Failed to make direct connection to remote desktop", "Malsukcesis konekti direkte"),
("Set Password", "Agordi pasvorton"),
("OS Password", "Pasvorto de la operaciumo"),
("install_tip", "Vi ne uzas instalita versio. Pro limigoj pro UAC, kiel aparato kontrolata, en kelkaj kazoj, ne estos ebla kontroli la muson kaj klavaron aŭ registri la ekranon. Bonvolu alkliku la butonon malsupre por instali RustDesk sur la operaciumo por eviti la demando supre."),
("Click to upgrade", "Alklaki por plibonigi"),
("Click to download", "Alklaki por elŝuti"),
("Click to update", "Alklaki por ĝisdatigi"),
("Configure", "Konfiguri"),
("config_acc", "Por uzi vian foran aparaton, bonvolu doni la permeson \"alirebleco\" al RustDesk."),
("config_screen", "Por uzi vian foran aparaton, bonvolu doni la permeson \"ekranregistrado\" al RustDesk."),
("Installing ...", "Instalante..."),
("Install", "Instali"),
("Installation", "Instalado"),
("Installation Path", "Vojo de instalo"),
("Create start menu shortcuts", "Aldoni ligilojn sur la startmenuo"),
("Create desktop icon", "Aldoni ligilojn sur la labortablo"),
("agreement_tip", "Starti la instaladon signifas akcepti la permesilon."),
("Accept and Install", "Akcepti kaj instali"),
("End-user license agreement", "Uzanta permesilon"),
("Generating ...", "Generante..."),
("Your installation is lower version.", "Via versio de instalaĵo estas pli malalta ol la lasta."),
("not_close_tcp_tip", "Bonvolu ne fermu tiun fenestron dum la uzo de la tunelo"),
("Listening ...", "Atendante konekton al la tunelo..."),
("Remote Host", "Fora gastiganto"),
("Remote Port", "Fora pordo"),
("Action", "Ago"),
("Add", "Aldoni"),
("Local Port", "Loka pordo"),
("setup_server_tip", "Se vi bezonas pli rapida konekcio, vi povas krei vian propran servilon"),
("Too short, at least 6 characters.", "Tro mallonga, almenaŭ 6 signoj."),
("The confirmation is not identical.", "Ambaŭ enigoj ne kongruas"),
("Permissions", "Permesoj"),
("Accept", "Akcepti"),
("Dismiss", "Malakcepti"),
("Disconnect", "Malkonekti"),
("Allow using keyboard and mouse", "Permesi la uzon de la klavaro kaj muso"),
("Allow using clipboard", "Permesi la uzon de la poŝo"),
("Allow hearing sound", "Permesi la uzon de la sono"),
("Allow file transfer", "Permesi la dosiertransigadon"),
("File transfer", "Dosiertransigado"),
("Connected", "Konektata"),
("Direct and encrypted connection", "Konekcio direkta ĉifrata"),
("Relayed and encrypted connection", "Konekcio relajsa ĉifrata"),
("Direct and unencrypted connection", "Konekcio direkta neĉifrata"),
("Relayed and unencrypted connection", "Konekcio relajsa neĉifrata"),
("Enter Remote ID", "Tajpu foran identigilon"),
("Enter your password", "Tajpu vian pasvorton"),
("Logging in...", "Konektante..."),
("Enable RDP session sharing", "Ebligi la kundivido de sesio RDP"),
("Auto Login", "Aŭtomata konektado (la ŝloso nur estos ebligita post la malebligado de la unua parametro)"),
("Enable Direct IP Access", "Permesi direkta eniro per IP"),
("Rename", "Renomi"),
("Space", "Spaco"),
("Create Desktop Shortcut", "Krei ligilon sur la labortablon"),
("Change Path", "Ŝanĝi vojon"),
("Create Folder", "Krei dosierujon"),
("Please enter the folder name", "Bonvolu enigi la dosiernomon"),
("Fix it", "Riparu ĝin"),
("Warning", "Averto"),
("Login screen using Wayland is not supported", "Konektajn ekranojn uzantajn Wayland ne estas subtenitaj"),
("Reboot required", "Restarto deviga"),
("Unsupported display server ", "La aktuala bilda servilo ne estas subtenita"),
("x11 expected", "Bonvolu uzi x11"),
("Port", "Pordo"),
("Settings", "Agordoj"),
("Username", " Uzanta nomo"),
("Invalid port", "Pordo nevalida"),
("Closed manually by the peer", "Manuale fermita de la samtavolano"),
("Enable remote configuration modification", "Permesi foran redaktadon de la konfiguracio"),
("Run without install", "Plenumi sen instali"),
("Always connected via relay", "Ĉiam konektata per relajso"),
("Always connect via relay", "Ĉiam konekti per relajso"),
("whitelist_tip", "Nur la IP en la blanka listo povas kontroli mian komputilon"),
("Login", "Konekti"),
("Logout", "Malkonekti"),
("Tags", "Etikedi"),
("Search ID", "Serĉi ID"),
("Current Wayland display server is not supported", "La aktuala bilda servilo Wayland ne estas subtenita"),
("whitelist_sep", "Vi povas uzi komon, punktokomon, spacon aŭ linsalton kiel apartigilo"),
("Add ID", "Aldoni identigilo"),
("Add Tag", "Aldoni etikedo"),
("Unselect all tags", "Malselekti ĉiujn etikedojn"),
("Network error", "Reta eraro"),
("Username missed", "Uzantnomo forgesita"),
("Password missed", "Pasvorto forgesita"),
("Wrong credentials", "Identigilo aŭ pasvorto erara"),
("Edit Tag", "Redakti etikedo"),
("Unremember Password", "Forgesi pasvorton"),
("Favorites", "Favorataj"),
("Add to Favorites", "Aldoni al la favorataj"),
("Remove from Favorites", "Forigi el la favorataj"),
("Empty", "Malplena"),
("Invalid folder name", "Dosiernomo nevalida"),
("Socks5 Proxy", "Socks5 prokura servilo"),
("Hostname", "Nomo de gastiga"),
("Discovered", "Malkovritaj"),
("install_daemon_tip", ""),
("Remote ID", "Fora identigilo"),
("Paste", "Alglui"),
("Paste here?", ""),
("Are you sure to close the connection?", "Ĉu vi vere volas fermi la konekton?"),
("Download new version", "Elŝuti la novan version"),
("Touch mode", "Tuŝa modo"),
("Mouse mode", ""),
("One-Finger Tap", ""),
("Left Mouse", ""),
("One-Long Tap", ""),
("Two-Finger Tap", ""),
("Right Mouse", ""),
("One-Finger Move", ""),
("Double Tap & Move", ""),
("Mouse Drag", ""),
("Two-Finger vertically", ""),
("Mouse Wheel", ""),
("Two-Finger Move", ""),
("Canvas Move", ""),
("Pinch to Zoom", ""),
("Canvas Zoom", ""),
("Reset canvas", "Restarigi kanvaso"),
("No permission of file transfer", "Neniu permeso de dosiertransigo"),
("Note", "Notu"),
("Connection", ""),
("Share Screen", ""),
("CLOSE", ""),
("OPEN", ""),
("Chat", ""),
("Total", ""),
("items", ""),
("Selected", ""),
("Screen Capture", ""),
("Input Control", ""),
("File Transfer", ""),
("Audio Capture", ""),
("File Connection", ""),
("Screen Connection", ""),
("Do you accept?", ""),
("Open System Setting", ""),
("How to get Android input permission?", ""),
("android_input_permission_tip1", ""),
("android_input_permission_tip2", ""),
("android_new_connection_tip", ""),
("android_service_will_start_tip", ""),
("android_stop_service_tip", ""),
("android_version_audio_tip", ""),
("android_start_service_tip", ""),
("Account", ""),
].iter().cloned().collect();
}

View File

@@ -6,9 +6,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("desk_tip", "Votre bureau est accessible via l'identifiant et le mot de passe ci-dessous."),
("Password", "Mot de passe"),
("Ready", "Prêt"),
("Established", "Établi"),
("connecting_status", "Connexion au réseau RustDesk..."),
("Enable Service", "Autoriser le service"),
("Start Service", "Démarrer le service"),
("Service is running", "Le service est en cours d'exécution"),
("Service is not running", "Le service ne fonctionne pas"),
("not_ready_status", "Pas prêt, veuillez vérifier la connexion réseau"),
("Control Remote Desktop", "Contrôler le bureau à distance"),
@@ -22,27 +24,27 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Refresh random password", "Actualiser le mot de passe aléatoire"),
("Set your own password", "Définir votre propre mot de passe"),
("Enable Keyboard/Mouse", "Activer le contrôle clavier/souris"),
("Enable Clipboard", "Activer la synchronisation du presse-papiers"),
("Enable Clipboard", "Activer la synchronisation du presse-papier"),
("Enable File Transfer", "Activer le transfert de fichiers"),
("Enable TCP Tunneling", "Activer le tunneling TCP"),
("IP Whitelisting", "Liste blanche IP"),
("ID/Relay Server", "ID/Serveur Relais"),
("Stop service", "Arrêter service"),
("Stop service", "Arrêter le service"),
("Change ID", "Changer d'ID"),
("Website", "Site Web"),
("About", "Sur"),
("About", "À propos de"),
("Mute", "Muet"),
("Audio Input", "Entrée audio"),
("ID Server", "Serveur ID"),
("Relay Server", "Serveur Relais"),
("Relay Server", "Serveur relais"),
("API Server", "Serveur API"),
("invalid_http", "Doit commencer par http:// ou https://"),
("Invalid IP", "IP invalide"),
("id_change_tip", "Seules les lettres a-z, A-Z, 0-9, _ (trait de soulignement) peuvent être utilisées. La première lettre doit être a-z, A-Z. La longueur est comprise entre 6 et 16."),
("id_change_tip", "Seules les lettres a-z, A-Z, 0-9, _ (trait de soulignement) peuvent être utilisées. La première lettre doit être a-z, A-Z. La longueur doit être comprise entre 6 et 16."),
("Invalid format", "Format invalide"),
("This function is turned off by the server", "Cette fonction est désactivée par le serveur"),
("Not available", "Indisponible"),
("Too frequent", "Modifier trop fréquemment, veuillez réessayer plus tard"),
("Too frequent", "Modifié trop fréquemment, veuillez réessayer plus tard"),
("Cancel", "Annuler"),
("Skip", "Ignorer"),
("Close", "Fermer"),
@@ -52,7 +54,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Please enter your password", "Veuillez saisir votre mot de passe"),
("Remember password", "Mémoriser le mot de passe"),
("Wrong Password", "Mauvais mot de passe"),
("Do you want to enter again?", "Voulez-vous participer à nouveau ?"),
("Do you want to enter again?", "Voulez-vous participer à nouveau ?"),
("Connection Error", "Erreur de connexion"),
("Error", "Erreur"),
("Reset by the peer", "La connexion a été fermée par le pair"),
@@ -62,56 +64,72 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Login Error", "Erreur de connexion"),
("Successful", "Succès"),
("Connected, waiting for image...", "Connecté, en attente de transmission d'image..."),
("Name", "Nom du fichier"),
("Name", "Nom"),
("Type", "Taper"),
("Modified", "Modifié"),
("Size", "Taille"),
("Show Hidden Files", "Afficher les fichiers cachés"),
("Receive", "Accepter"),
("Send", "Envoyer"),
("Refresh File", "Actualiser le fichier"),
("Local", "Local"),
("Remote", "Distant"),
("Remote Computer", "Ordinateur distant"),
("Local Computer", "Ordinateur local"),
("Confirm Delete", "Confirmer la suppression"),
("Are you sure you want to delete this file?", "Voulez-vous vraiment supprimer ce fichier ?"),
("Delete", "Supprimer"),
("Properties", "Propriétés"),
("Multi Select", "Choix multiple"),
("Empty Directory", "Répertoire vide"),
("Not an empty directory", "Pas un répertoire vide"),
("Are you sure you want to delete this file?", "Voulez-vous vraiment supprimer ce fichier?"),
("Are you sure you want to delete this empty directory?", "Voulez-vous vraiment supprimer ce répertoire vide ?"),
("Are you sure you want to delete the file of this directory?", "Voulez-vous vraiment supprimer le fichier de ce répertoire ?"),
("Do this for all conflicts", "Appliquer à d'autres conflits"),
("This is irreversible!", "C'est irréversible !"),
("Deleting", "Suppression"),
("files", "fichier"),
("Waiting", "En attente en attente..."),
("Waiting", "En attente..."),
("Finished", "Terminé"),
("Speed", "Vitesse"),
("Custom Image Quality", "Définir la qualité d'image"),
("Privacy mode", "Mode privé"),
("Block user input", "Bloquer la saisie de l'utilisateur"),
("Unblock user input", "Débloquer l'entrée de l'utilisateur"),
("Adjust Window", "Ajuster la fenêtre"),
("Original", "Ratio d'origine"),
("Shrink", "Rétréci"),
("Shrink", "Rétrécir"),
("Stretch", "Étirer"),
("Good image quality", "Bonne qualité d'image"),
("Balanced", "Qualité d'image normale"),
("Optimize reaction time", "Optimiser le temps de réaction"),
("Custom", "Qualité d'image personnalisée"),
("Show remote cursor", "Afficher le curseur distant"),
("Disable clipboard", "Désactiver le presse-papiers"),
("Disable clipboard", "Désactiver le presse-papier"),
("Lock after session end", "Verrouiller l'ordinateur distant après la déconnexion"),
("Insert", "Insérer"),
("Insert Lock", "Verrouiller l'ordinateur distant"),
("Refresh", "Rafraîchir l'écran"),
("ID does not exist", "L'ID n'existe pas"),
("Failed to connect to rendezvous server", "Échec de la connexion au serveur de rendez-vous"),
("Failed to connect to rendezvous server", "Échec de la connexion au serveur rendezvous"),
("Please try later", "Veuillez essayer plus tard"),
("Remote desktop is offline", "Le bureau à distance est hors ligne"),
("Key mismatch", "Discordance de clé"),
("Key mismatch", "Discordance de clés"),
("Timeout", "Connexion expirée"),
("Failed to connect to relay server", "Échec de la connexion au serveur relais"),
("Failed to connect via rendezvous server", "Échec de l'établissement d'une connexion via le serveur de rendez-vous"),
("Failed to connect via rendezvous server", "Échec de l'établissement d'une connexion via le serveur rendezvous"),
("Failed to connect via relay server", "Impossible d'établir une connexion via le serveur relais"),
("Failed to make direct connection to remote desktop", "Impossible d'établir une connexion directe"),
("Set Password", "Définir le mot de passe"),
("OS Password", "Mot de passe du système d'exploitation"),
("install_tip", "Vous utilisez une version désinstallée. En raison des restrictions UAC, en tant que terminal contrôlé, dans certains cas, il ne sera pas en mesure de contrôler la souris et le clavier ou d'enregistrer l'écran. Veuillez cliquer sur le bouton ci-dessous pour installer RustDesk au système pour éviter la question ci-dessus."),
("install_tip", "Vous utilisez une version non installée. En raison des restrictions UAC, en tant que terminal contrôlé, dans certains cas, il ne sera pas en mesure de contrôler la souris et le clavier ou d'enregistrer l'écran. Veuillez cliquer sur le bouton ci-dessous pour installer RustDesk au système pour éviter la question ci-dessus."),
("Click to upgrade", "Cliquez pour mettre à niveau"),
("Configuration Permissions", "Autorisations de configuration"),
("Click to download", "Cliquez pour télécharger"),
("Click to update", "Cliquez pour mettre à jour"),
("Configure", "Configurer"),
("config_acc", "Afin de pouvoir contrôler votre bureau à distance, veuillez donner l'autorisation\"accessibilité\" à RustDesk."),
("config_screen", "Afin de pouvoir accéder à votre bureau à distance, veuillez donner l'autorisation à RustDesk\"enregistrement d'écran\"."),
("Installing ...", "Installation ..."),
("config_acc", "Afin de pouvoir contrôler votre bureau à distance, veuillez donner l'autorisation \"accessibilité\" à RustDesk."),
("config_screen", "Afin de pouvoir accéder à votre bureau à distance, veuillez donner à RustDesk l'autorisation \"enregistrement d'écran\"."),
("Installing ...", "Installation..."),
("Install", "Installer"),
("Installation", "Installation"),
("Installation Path", "Chemin d'installation"),
@@ -120,7 +138,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("agreement_tip", "Démarrer l'installation signifie accepter le contrat de licence."),
("Accept and Install", "Accepter et installer"),
("End-user license agreement", "Contrat d'utilisateur"),
("Generating ...", "Génération ..."),
("Generating ...", "Génération..."),
("Your installation is lower version.", "La version que vous avez installée est inférieure à la version en cours d'exécution."),
("not_close_tcp_tip", "Veuillez ne pas fermer cette fenêtre lors de l'utilisation du tunnel"),
("Listening ...", "En attente de connexion tunnel..."),
@@ -137,19 +155,21 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Dismiss", "Rejeter"),
("Disconnect", "Déconnecter"),
("Allow using keyboard and mouse", "Autoriser l'utilisation du clavier et de la souris"),
("Allow using clipboard", "Autoriser l'utilisation du presse-papiers"),
("Allow using clipboard", "Autoriser l'utilisation du presse-papier"),
("Allow hearing sound", "Autoriser l'audition du son"),
("Allow file transfer", "Autoriser le transfert de fichiers"),
("File transfer", "Transfert de fichiers"),
("Connected", "Connecté"),
("Direct and encrypted connection", "Connexion directe cryptée"),
("Relayed and encrypted connection", "Connexion relais cryptée"),
("Direct and unencrypted connection", "Connexion directe non cryptée"),
("Relayed and unencrypted connection", "Connexion relais non cryptée"),
("Enter Remote ID", "Entrez l'ID à distance"),
("Direct and encrypted connection", "Connexion directe chiffrée"),
("Relayed and encrypted connection", "Connexion relais chiffrée"),
("Direct and unencrypted connection", "Connexion directe non chiffrée"),
("Relayed and unencrypted connection", "Connexion relais non chiffrée"),
("Enter Remote ID", "Entrez l'ID de l'appareil à distance"),
("Enter your password", "Entrez votre mot de passe"),
("Logging in...", "Se connecter..."),
("Enable RDP session sharing", "Activer le partage de session RDP"),
("Auto Login", "Connexion automatique (le verrouillage ne sera effectif qu'après la déconnexion du paramètre)"),
("Enable Direct IP Access", "Autoriser l'accès direct IP"),
("Auto Login", "Connexion automatique (le verrouillage ne sera effectif qu'après la désactivation du premier paramètre)"),
("Enable Direct IP Access", "Autoriser l'accès direct par IP"),
("Rename", "Renommer"),
("Space", "Espace"),
("Create Desktop Shortcut", "Créer un raccourci sur le bureau"),
@@ -171,14 +191,14 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Run without install", "Exécuter sans installer"),
("Always connected via relay", "Forcer la connexion relais"),
("Always connect via relay", "Forcer la connexion relais"),
("whitelist_tip", "Seul l'ip dans la liste blanche peut m'accéder"),
("whitelist_tip", "Seul l'IP dans la liste blanche peut accéder à mon appareil"),
("Login", "Connexion"),
("Logout", "Déconnexion"),
("Tags", "Étiqueter"),
("Search ID", "Identifiant de recherche"),
("Search ID", "Rechercher un ID"),
("Current Wayland display server is not supported", "Le serveur d'affichage Wayland n'est pas pris en charge"),
("whitelist_sep", "Vous pouvez utiliser une virgule, un point-virgule, un espace ou une nouvelle ligne comme séparateur"),
("Add ID", "Ajouter ID"),
("Add ID", "Ajouter un ID"),
("Add Tag", "Ajouter une balise"),
("Unselect all tags", "Désélectionner toutes les balises"),
("Network error", "Erreur réseau"),
@@ -186,7 +206,66 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Password missed", "Mot de passe manqué"),
("Wrong credentials", "Identifiant ou mot de passe erroné"),
("Edit Tag", "Modifier la balise"),
("Unremember Password", "Mot de passe oublié"),
("Favorites", "Favoris"),
("Add to Favorites", "Ajouter aux Favoris"),
("Remove from Favorites", "Retirer des favoris"),
("Empty", "Vide"),
("Invalid folder name", "Nom de dossier invalide"),
("Hostname", "nom d'hôte"),
("Socks5 Proxy", "Socks5 Agents"),
("Hostname", "Nom d'hôte"),
("Discovered", "Découvert"),
("install_daemon_tip", "Pour démarrer au démarrage, vous devez installer le service système."),
("Remote ID", "ID de l'appareil à distance"),
("Paste", "Coller"),
("Paste here?", "Coller ici ?"),
("Are you sure to close the connection?", "Êtes-vous sûr de fermer la connexion?"),
("Download new version", "Télécharger la nouvelle version"),
("Touch mode", "Mode tactile"),
("Mouse mode", "Mode souris"),
("One-Finger Tap", "Tapez d'un doigt"),
("Left Mouse", "Souris gauche"),
("One-Long Tap", "Un long robinet"),
("Two-Finger Tap", "Tapez à deux doigts"),
("Right Mouse", "Bouton droit de la souris"),
("One-Finger Move", "Mouvement à un doigt"),
("Double Tap & Move", "Appuyez deux fois et déplacez"),
("Mouse Drag", "Glissement de la souris"),
("Two-Finger vertically", "Deux doigts verticalement"),
("Mouse Wheel", "Roulette de la souris"),
("Two-Finger Move", "Mouvement à deux doigts"),
("Canvas Move", "Déplacement de la toile"),
("Pinch to Zoom", "Pincer pour zoomer"),
("Canvas Zoom", "Zoom sur la toile"),
("Reset canvas", "Réinitialiser le canevas"),
("No permission of file transfer", "Aucune autorisation de transfert de fichiers"),
("Note", "Noter"),
("Connection", "Connexion"),
("Share Screen", "Partager l'écran"),
("CLOSE", "FERMER"),
("OPEN", "OUVRIR"),
("Chat", "Discuter"),
("Total", "Total"),
("items", "éléments"),
("Selected", "Choisi"),
("Screen Capture", "Capture d'écran"),
("Input Control", "Contrôle de saisie"),
("File Transfer", "Transfert de fichier"),
("Audio Capture", "Capture audio"),
("File Connection", "Connexion de fichier"),
("Screen Connection", "Connexion de l'écran"),
("Do you accept?", "Accepter vous ?"),
("Open System Setting", "Ouvrir les paramètres système"),
("How to get Android input permission?", "Comment obtenir l'autorisation d'entrée Android ?"),
("android_input_permission_tip1", "Pour qu'un appareil distant puisse contrôler votre appareil Android via la souris ou le toucher, vous devez autoriser RustDesk à utiliser le service \"Accessibilité\"."),
("android_input_permission_tip2", "Veuillez accéder à la page suivante des paramètres système, recherchez et entrez [Services installés], activez le service [RustDesk Input]."),
("android_new_connection_tip", "Une nouvelle demande de contrôle a été reçue, elle souhaite contrôler votre appareil actuel."),
("android_service_will_start_tip", "L'activation de la capture d'écran démarrera automatiquement le service, permettant à d'autres appareils de demander une connexion à partir de cet appareil."),
("android_stop_service_tip", "La fermeture du service fermera automatiquement toutes les connexions établies."),
("android_version_audio_tip", "La version actuelle d'Android ne prend pas en charge la capture audio, veuillez passer à Android 10 ou supérieur."),
("android_start_service_tip", "Appuyez sur [Démarrer le service] ou sur l'autorisation OUVRIR [Capture d'écran] pour démarrer le service de partage d'écran."),
("Account", "Compte"),
("Quit", "Quitter"),
("Help", "Aider"),
].iter().cloned().collect();
}
}

View File

@@ -1,193 +1,271 @@
lazy_static::lazy_static! {
pub static ref T: std::collections::HashMap<&'static str, &'static str> =
[
("Status", "Stato"),
("Your Desktop", "Il tuo desktop"),
("desk_tip", "Puoi accedere al tuo desktop usando l'ID e la password riportati qui."),
("Password", "Password"),
("Ready", "Pronto"),
("connecting_status", "Connessione alla rete RustDesk in corso..."),
("Enable Service", "Abilita servizio"),
("Start Service", "Avvia servizio"),
("Service is not running", "Il servizio non è in esecuzione"),
("not_ready_status", "Non pronto. Verifica la tua connessione"),
("Control Remote Desktop", "Controlla una scrivania remota"),
("Transfer File", "Trasferisci file"),
("Connect", "Connetti"),
("Recent Sessions", "Sessioni recenti"),
("Address Book", "Rubrica"),
("Confirmation", "Conferma"),
("TCP Tunneling", "Tunnel TCP"),
("Remove", "Rimuovi"),
("Refresh random password", "Nuova password casuale"),
("Set your own password", "Imposta la tua password"),
("Enable Keyboard/Mouse", "Abilita tastiera/mouse"),
("Enable Clipboard", "Abilita appunti"),
("Enable File Transfer", "Abilita trasferimento file"),
("Enable TCP Tunneling", "Abilita tunnel TCP"),
("IP Whitelisting", "IP autorizzati"),
("ID/Relay Server", "Server ID/Relay"),
("Stop service", "Arresta servizio"),
("Change ID", "Cambia ID"),
("Website", "Sito web"),
("About", "Informazioni"),
("Mute", "Silenzia"),
("Audio Input", "Input audio"),
("ID Server", "ID server"),
("Relay Server", "Server relay"),
("API Server", "Server API"),
("invalid_http", "deve iniziare con http:// o https://"),
("Invalid IP", "Indirizzo IP non valido"),
("id_change_tip", "Puoi usare solo i caratteri a-z, A-Z, 0-9 e _ (underscore). Il primo carattere deve essere a-z o A-Z. La lunghezza deve essere fra 6 e 16 caratteri."),
("Invalid format", "Formato non valido"),
("This function is turned off by the server", "Questa funzione è disabilitata sul server"),
("Not available", "Non disponibile"),
("Too frequent", "Troppo frequente"),
("Cancel", "Annulla"),
("Skip", "Ignora"),
("Close", "Chiudi"),
("Retry", "Riprova"),
("OK", "OK"),
("Password Required", "Password richiesta"),
("Please enter your password", "Inserisci la tua password"),
("Remember password", "Ricorda password"),
("Wrong Password", "Password errata"),
("Do you want to enter again?", "Vuoi riprovare?"),
("Connection Error", "Errore di connessione"),
("Error", "Errore"),
("Reset by the peer", "Reimpostata dal peer"),
("Connecting...", "Connessione..."),
("Connection in progress. Please wait.", "Connessione in corso. Attendi."),
("Please try 1 minute later", "Per favore riprova fra 1 minuto"),
("Login Error", "Errore di login"),
("Successful", "Successo"),
("Connected, waiting for image...", "Connesso, in attesa dell'immagine..."),
("Name", "Nome"),
("Modified", "Modificato"),
("Size", "Dimensione"),
("Show Hidden Files", "Mostra file nascosti"),
("Receive", "Ricevi"),
("Send", "Invia"),
("Remote Computer", "Computer remoto"),
("Local Computer", "Computer locale"),
("Confirm Delete", "Conferma cancellazione"),
("Are you sure you want to delete this file?", "Vuoi davvero eliminare questo file?"),
("Do this for all conflicts", "Ricorca questa scelta per tutti i conflitti"),
("Deleting", "Cancellazione di"),
("files", "file"),
("Waiting", "In attesa"),
("Finished", "Terminato"),
("Custom Image Quality", "Qualità immagine personalizzata"),
("Privacy mode", "Modalità privacy"),
("Adjust Window", "Adatta la finestra"),
("Original", "Originale"),
("Shrink", "Restringi"),
("Stretch", "Allarga"),
("Good image quality", "Buona qualità immagine"),
("Balanced", "Bilanciato"),
("Optimize reaction time", "Ottimizza il tempo di reazione"),
("Custom", "Personalizzato"),
("Show remote cursor", "Mostra il cursore remoto"),
("Disable clipboard", "Disabilita appunti"),
("Lock after session end", "Blocca al termine della sessione"),
("Insert", "Inserisci"),
("Insert Lock", "Blocco inserimento"),
("Refresh", "Aggiorna"),
("ID does not exist", "L'ID non esiste"),
("Failed to connect to rendezvous server", "Errore di connessione al server rendezvous"),
("Please try later", "Riprova più tardi"),
("Remote desktop is offline", "Il desktop remoto è offline"),
("Key mismatch", "La chiave non corrisponde"),
("Timeout", "Timeout"),
("Failed to connect to relay server", "Errore di connessione al server relay"),
("Failed to connect via rendezvous server", "Errore di connessione tramite il server rendezvous"),
("Failed to connect via relay server", "Errore di connessione tramite il server relay"),
("Failed to make direct connection to remote desktop", "Impossibile connettersi direttamente al desktop remoto"),
("Set Password", "Imposta password"),
("OS Password", "Password del sistema operativo"),
("install_tip", "A causa del Controllo Account Utente, RustDesk potrebbe non funzionare correttamente come desktop remoto. Per evitare questo problema, fai click sul tasto qui sotto per installare RustDesk a livello di sistema."),
("Click to upgrade", "Fai click per aggiornare"),
("Configuration Permissions", "Permessi di configurazione"),
("Configure", "Configura"),
("config_acc", "Per controllare il tuo desktop dall'esterno, devi fornire a RustDesk il permesso \"Accessibilità\"."),
("config_screen", "Per controllare il tuo desktop dall'esterno, devi fornire a RustDesk il permesso \"Registrazione schermo\"."),
("Installing ...", "Installazione ..."),
("Install", "Installa"),
("Installation", "Installazione"),
("Installation Path", "Percorso di installazione"),
("Create start menu shortcuts", "Crea i collegamenti nel menu di avvio"),
("Create desktop icon", "Crea un'icona sul desktop"),
("agreement_tip", "Avviando l'installazione, accetti i termini del contratto di licenza."),
("Accept and Install", "Accetta e installa"),
("End-user license agreement", "Contratto di licenza con l'utente finale"),
("Generating ...", "Generazione ..."),
("Your installation is lower version.", "La tua installazione non è aggiornata."),
("not_close_tcp_tip", "Non chiudere questa finestra mentre stai usando il tunnel"),
("Listening ...", "In ascolto ..."),
("Remote Host", "Host remoto"),
("Remote Port", "Porta remota"),
("Action", "Azione"),
("Add", "Aggiungi"),
("Local Port", "Porta locale"),
("setup_server_tip", "Per una connessione più veloce, configura un tuo server"),
("Too short, at least 6 characters.", "Troppo breve, almeno 6 caratteri"),
("The confirmation is not identical.", "La conferma non corrisponde"),
("Permissions", "Permessi"),
("Accept", "Accetta"),
("Dismiss", "Rifiuta"),
("Disconnect", "Disconnetti"),
("Allow using keyboard and mouse", "Consenti l'uso di tastiera e mouse"),
("Allow using clipboard", "Consenti l'uso degli appunti"),
("Allow hearing sound", "Consenti la riproduzione dell'audio"),
("Connected", "Connesso"),
("Direct and encrypted connection", "Connessione diretta e cifrata"),
("Relayed and encrypted connection", "Connessione tramite relay e cifrata"),
("Direct and unencrypted connection", "Connessione diretta e non cifrata"),
("Relayed and unencrypted connection", "Connessione tramite relay e non cifrata"),
("Enter Remote ID", "Inserisci l'ID remoto"),
("Enter your password", "Inserisci la tua password"),
("Logging in...", "Autenticazione..."),
("Enable RDP session sharing", "Abilita la condivisione della sessione RDP"),
("Auto Login", "Login automatico"),
("Enable Direct IP Access", "Abilita l'accesso diretto tramite IP"),
("Rename", "Rinomina"),
("Space", "Spazio"),
("Create Desktop Shortcut", "Crea collegamento sul desktop"),
("Change Path", "Cambia percorso"),
("Create Folder", "Crea cartella"),
("Please enter the folder name", "Inserisci il nome della cartella"),
("Fix it", "Risolvi"),
("Warning", "Avviso"),
("Login screen using Wayland is not supported", "La schermata di login non è supportata utilizzando Wayland"),
("Reboot required", "Riavvio necessario"),
("Unsupported display server ", "Display server non supportato"),
("x11 expected", "x11 necessario"),
("Port", "Porta"),
("Settings", "Impostazioni"),
("Username", " Nome utente"),
("Invalid port", "Porta non valida"),
("Closed manually by the peer", "Chiuso manualmente dal peer"),
("Enable remote configuration modification", "Abilita la modifica remota della configurazione"),
("Run without install", "Avvia senza installare"),
("Always connected via relay", "Connesso sempre tramite relay"),
("Always connect via relay", "Connetti sempre tramite relay"),
("whitelist_tip", "Solo gli indirizzi IP autorizzati possono connettersi a questo desktop"),
("Login", "Accedi"),
("Logout", "Esci"),
("Tags", "Tag"),
("Search ID", "Cerca ID"),
("Current Wayland display server is not supported", "Questo display server Wayland non è supportato"),
("whitelist_sep", "Separati da virgola, punto e virgola, spazio o a capo"),
("Add ID", "Aggiungi ID"),
("Add Tag", "Aggiungi tag"),
("Unselect all tags", "Deseleziona tutti i tag"),
("Network error", "Errore di rete"),
("Username missed", "Nome utente dimenticato"),
("Password missed", "Password dimenticata"),
("Wrong credentials", "Credenziali errate"),
("Edit Tag", "Modifica tag"),
("Invalid folder name", "Nome della cartella non valido"),
("Hostname", "Nome host"),
].iter().cloned().collect();
}
pub static ref T: std::collections::HashMap<&'static str, &'static str> =
[
("Status", "Stato"),
("Your Desktop", "Il tuo desktop"),
("desk_tip", "Puoi accedere al tuo desktop usando l'ID e la password riportati qui."),
("Password", "Password"),
("Ready", "Pronto"),
("Established", "Stabilito"),
("connecting_status", "Connessione alla rete RustDesk in corso..."),
("Enable Service", "Abilita servizio"),
("Start Service", "Avvia servizio"),
("Service is running", "Il servizio è in esecuzione"),
("Service is not running", "Il servizio non è in esecuzione"),
("not_ready_status", "Non pronto. Verifica la tua connessione"),
("Control Remote Desktop", "Controlla una scrivania remota"),
("Transfer File", "Trasferisci file"),
("Connect", "Connetti"),
("Recent Sessions", "Sessioni recenti"),
("Address Book", "Rubrica"),
("Confirmation", "Conferma"),
("TCP Tunneling", "Tunnel TCP"),
("Remove", "Rimuovi"),
("Refresh random password", "Nuova password casuale"),
("Set your own password", "Imposta la tua password"),
("Enable Keyboard/Mouse", "Abilita tastiera/mouse"),
("Enable Clipboard", "Abilita appunti"),
("Enable File Transfer", "Abilita trasferimento file"),
("Enable TCP Tunneling", "Abilita tunnel TCP"),
("IP Whitelisting", "IP autorizzati"),
("ID/Relay Server", "Server ID/Relay"),
("Stop service", "Arresta servizio"),
("Change ID", "Cambia ID"),
("Website", "Sito web"),
("About", "Informazioni"),
("Mute", "Silenzia"),
("Audio Input", "Input audio"),
("ID Server", "ID server"),
("Relay Server", "Server relay"),
("API Server", "Server API"),
("invalid_http", "deve iniziare con http:// o https://"),
("Invalid IP", "Indirizzo IP non valido"),
("id_change_tip", "Puoi usare solo i caratteri a-z, A-Z, 0-9 e _ (underscore). Il primo carattere deve essere a-z o A-Z. La lunghezza deve essere fra 6 e 16 caratteri."),
("Invalid format", "Formato non valido"),
("This function is turned off by the server", "Questa funzione è disabilitata sul server"),
("Not available", "Non disponibile"),
("Too frequent", "Troppo frequente"),
("Cancel", "Annulla"),
("Skip", "Ignora"),
("Close", "Chiudi"),
("Retry", "Riprova"),
("OK", "OK"),
("Password Required", "Password richiesta"),
("Please enter your password", "Inserisci la tua password"),
("Remember password", "Ricorda password"),
("Wrong Password", "Password errata"),
("Do you want to enter again?", "Vuoi riprovare?"),
("Connection Error", "Errore di connessione"),
("Error", "Errore"),
("Reset by the peer", "Reimpostata dal peer"),
("Connecting...", "Connessione..."),
("Connection in progress. Please wait.", "Connessione in corso. Attendi."),
("Please try 1 minute later", "Per favore riprova fra 1 minuto"),
("Login Error", "Errore di login"),
("Successful", "Successo"),
("Connected, waiting for image...", "Connesso, in attesa dell'immagine..."),
("Name", "Nome"),
("Type", "Tipo"),
("Modified", "Modificato"),
("Size", "Dimensione"),
("Show Hidden Files", "Mostra file nascosti"),
("Receive", "Ricevi"),
("Send", "Invia"),
("Refresh File", "Aggiorna file"),
("Local", "Locale"),
("Remote", "Remote"),
("Remote Computer", "Computer remoto"),
("Local Computer", "Computer locale"),
("Confirm Delete", "Conferma cancellazione"),
("Delete", "Eliminare"),
("Properties", "Proprietà"),
("Multi Select", "Selezione multipla"),
("Empty Directory", "Directory vuota"),
("Not an empty directory", "Non una directory vuota"),
("Are you sure you want to delete this file?", "Vuoi davvero eliminare questo file?"),
("Are you sure you want to delete this empty directory?", "Sei sicuro di voler eliminare questa directory vuota?"),
("Are you sure you want to delete the file of this directory?", "Sei sicuro di voler eliminare il file di questa directory?"),
("Do this for all conflicts", "Ricorca questa scelta per tutti i conflitti"),
("This is irreversible!", "Questo è irreversibile!"),
("Deleting", "Cancellazione di"),
("files", "file"),
("Waiting", "In attesa"),
("Finished", "Terminato"),
("Speed", "Velocità"),
("Custom Image Quality", "Qualità immagine personalizzata"),
("Privacy mode", "Modalità privacy"),
("Block user input", "Blocca l'input dell'utente"),
("Unblock user input", "Sbloccare l'input dell'utente"),
("Adjust Window", "Adatta la finestra"),
("Original", "Originale"),
("Shrink", "Restringi"),
("Stretch", "Allarga"),
("Good image quality", "Buona qualità immagine"),
("Balanced", "Bilanciato"),
("Optimize reaction time", "Ottimizza il tempo di reazione"),
("Custom", "Personalizzato"),
("Show remote cursor", "Mostra il cursore remoto"),
("Disable clipboard", "Disabilita appunti"),
("Lock after session end", "Blocca al termine della sessione"),
("Insert", "Inserisci"),
("Insert Lock", "Blocco inserimento"),
("Refresh", "Aggiorna"),
("ID does not exist", "L'ID non esiste"),
("Failed to connect to rendezvous server", "Errore di connessione al server rendezvous"),
("Please try later", "Riprova più tardi"),
("Remote desktop is offline", "Il desktop remoto è offline"),
("Key mismatch", "La chiave non corrisponde"),
("Timeout", "Timeout"),
("Failed to connect to relay server", "Errore di connessione al server relay"),
("Failed to connect via rendezvous server", "Errore di connessione tramite il server rendezvous"),
("Failed to connect via relay server", "Errore di connessione tramite il server relay"),
("Failed to make direct connection to remote desktop", "Impossibile connettersi direttamente al desktop remoto"),
("Set Password", "Imposta password"),
("OS Password", "Password del sistema operativo"),
("install_tip", "A causa del Controllo Account Utente, RustDesk potrebbe non funzionare correttamente come desktop remoto. Per evitare questo problema, fai click sul tasto qui sotto per installare RustDesk a livello di sistema."),
("Click to upgrade", "Fai click per aggiornare"),
("Click to download", "Cliquez per scaricare"),
("Click to update", "Fare clic per aggiornare"),
("Configure", "Configura"),
("config_acc", "Per controllare il tuo desktop dall'esterno, devi fornire a RustDesk il permesso \"Accessibilità\"."),
("config_screen", "Per controllare il tuo desktop dall'esterno, devi fornire a RustDesk il permesso \"Registrazione schermo\"."),
("Installing ...", "Installazione ..."),
("Install", "Installa"),
("Installation", "Installazione"),
("Installation Path", "Percorso di installazione"),
("Create start menu shortcuts", "Crea i collegamenti nel menu di avvio"),
("Create desktop icon", "Crea un'icona sul desktop"),
("agreement_tip", "Avviando l'installazione, accetti i termini del contratto di licenza."),
("Accept and Install", "Accetta e installa"),
("End-user license agreement", "Contratto di licenza con l'utente finale"),
("Generating ...", "Generazione ..."),
("Your installation is lower version.", "La tua installazione non è aggiornata."),
("not_close_tcp_tip", "Non chiudere questa finestra mentre stai usando il tunnel"),
("Listening ...", "In ascolto ..."),
("Remote Host", "Host remoto"),
("Remote Port", "Porta remota"),
("Action", "Azione"),
("Add", "Aggiungi"),
("Local Port", "Porta locale"),
("setup_server_tip", "Per una connessione più veloce, configura un tuo server"),
("Too short, at least 6 characters.", "Troppo breve, almeno 6 caratteri"),
("The confirmation is not identical.", "La conferma non corrisponde"),
("Permissions", "Permessi"),
("Accept", "Accetta"),
("Dismiss", "Rifiuta"),
("Disconnect", "Disconnetti"),
("Allow using keyboard and mouse", "Consenti l'uso di tastiera e mouse"),
("Allow using clipboard", "Consenti l'uso degli appunti"),
("Allow hearing sound", "Consenti la riproduzione dell'audio"),
("Allow file transfer", "Consenti trasferimento file"),
("File transfer", "Trasferimento di file"),
("Connected", "Connesso"),
("Direct and encrypted connection", "Connessione diretta e cifrata"),
("Relayed and encrypted connection", "Connessione tramite relay e cifrata"),
("Direct and unencrypted connection", "Connessione diretta e non cifrata"),
("Relayed and unencrypted connection", "Connessione tramite relay e non cifrata"),
("Enter Remote ID", "Inserisci l'ID remoto"),
("Enter your password", "Inserisci la tua password"),
("Logging in...", "Autenticazione..."),
("Enable RDP session sharing", "Abilita la condivisione della sessione RDP"),
("Auto Login", "Login automatico"),
("Enable Direct IP Access", "Abilita l'accesso diretto tramite IP"),
("Rename", "Rinomina"),
("Space", "Spazio"),
("Create Desktop Shortcut", "Crea collegamento sul desktop"),
("Change Path", "Cambia percorso"),
("Create Folder", "Crea cartella"),
("Please enter the folder name", "Inserisci il nome della cartella"),
("Fix it", "Risolvi"),
("Warning", "Avviso"),
("Login screen using Wayland is not supported", "La schermata di login non è supportata utilizzando Wayland"),
("Reboot required", "Riavvio necessario"),
("Unsupported display server ", "Display server non supportato"),
("x11 expected", "x11 necessario"),
("Port", "Porta"),
("Settings", "Impostazioni"),
("Username", " Nome utente"),
("Invalid port", "Porta non valida"),
("Closed manually by the peer", "Chiuso manualmente dal peer"),
("Enable remote configuration modification", "Abilita la modifica remota della configurazione"),
("Run without install", "Avvia senza installare"),
("Always connected via relay", "Connesso sempre tramite relay"),
("Always connect via relay", "Connetti sempre tramite relay"),
("whitelist_tip", "Solo gli indirizzi IP autorizzati possono connettersi a questo desktop"),
("Login", "Accedi"),
("Logout", "Esci"),
("Tags", "Tag"),
("Search ID", "Cerca ID"),
("Current Wayland display server is not supported", "Questo display server Wayland non è supportato"),
("whitelist_sep", "Separati da virgola, punto e virgola, spazio o a capo"),
("Add ID", "Aggiungi ID"),
("Add Tag", "Aggiungi tag"),
("Unselect all tags", "Deseleziona tutti i tag"),
("Network error", "Errore di rete"),
("Username missed", "Nome utente dimenticato"),
("Password missed", "Password dimenticata"),
("Wrong credentials", "Credenziali errate"),
("Edit Tag", "Modifica tag"),
("Unremember Password", "Non ricordare la password"),
("Favorites", "Preferiti"),
("Add to Favorites", "Aggiungi ai preferiti"),
("Remove from Favorites", "Rimuovi dai preferiti"),
("Empty", "Vuoto"),
("Invalid folder name", "Nome della cartella non valido"),
("Socks5 Proxy", "Socks5 Proxy"),
("Hostname", "Nome host"),
("Discovered", "Scoperto"),
("install_daemon_tip", "Per iniziare all'avvio, è necessario installare il servizio di sistema."),
("Remote ID", "ID remoto"),
("Paste", "Impasto"),
("Paste here?", "Incolla qui?"),
("Are you sure to close the connection?", "Sei sicuro di chiudere la connessione?"),
("Download new version", "Scarica nuova versione"),
("Touch mode", "Modalità tocco"),
("Mouse mode", "Modalità mouse"),
("One-Finger Tap", "Tocca con un dito"),
("Left Mouse", "Mouse sinistro"),
("One-Long Tap", "Tocco lungo con un dito"),
("Two-Finger Tap", "Tocca con due dita"),
("Right Mouse", "Mouse destro"),
("One-Finger Move", "Movimento con un dito"),
("Double Tap & Move", "Tocca due volte e sposta"),
("Mouse Drag", "Trascina il mouse"),
("Two-Finger vertically", "Due dita in verticale"),
("Mouse Wheel", "Rotellina del mouse"),
("Two-Finger Move", "Movimento con due dita"),
("Canvas Move", "Sposta tela"),
("Pinch to Zoom", "Pizzica per zoomare"),
("Canvas Zoom", "Zoom tela"),
("Reset canvas", "Ripristina tela"),
("No permission of file transfer", "Nessun permesso di trasferimento di file"),
("Note", "Nota"),
("Connection", "Connessione"),
("Share Screen", "Condividi schermo"),
("CLOSE", "CHIUDERE"),
("OPEN", "APRIRE"),
("Chat", "Chiacchierata"),
("Total", "Totale"),
("items", "Oggetti"),
("Selected", "Selezionato"),
("Screen Capture", "Cattura schermo"),
("Input Control", "Controllo di input"),
("File Transfer", "Trasferimento di file"),
("Audio Capture", "Acquisizione audio"),
("File Connection", "Connessione file"),
("Screen Connection", "Connessione schermo"),
("Do you accept?", "Accetti?"),
("Open System Setting", "Apri Impostazioni di sistema"),
("How to get Android input permission?", "Come ottenere l'autorizzazione di input Android?"),
("android_input_permission_tip1", "Affinché un dispositivo remoto possa controllare il tuo dispositivo Android tramite mouse o tocco, devi consentire a RustDesk di utilizzare il servizio \"Accessibilità\"."),
("android_input_permission_tip2", "Vai alla pagina delle impostazioni di sistema successiva, trova e accedi a [Servizi installati], attiva il servizio [RustDesk Input]."),
("android_new_connection_tip", "È stata ricevuta una nuova richiesta di controllo, desidera controllare il dispositivo corrente."),
("android_service_will_start_tip", "L'attivazione di Cattura schermo avvierà automaticamente il servizio, consentendo ad altri dispositivi di richiedere una connessione da questo dispositivo."),
("android_stop_service_tip", "La chiusura del servizio chiuderà automaticamente tutte le connessioni stabilite."),
("android_version_audio_tip", "L'attuale versione di Android non supporta l'acquisizione audio, esegui l'upgrade ad Android 10 o versioni successive."),
("android_start_service_tip", "Toccare [Avvia servizio] o APRI l'autorizzazione [Cattura schermo] per avviare il servizio di condivisione dello schermo."),
("Account", "Account"),
("Quit", "Esci"),
("Help", "Aiuto"),
].iter().cloned().collect();
}

271
src/lang/ptbr.rs Normal file
View File

@@ -0,0 +1,271 @@
lazy_static::lazy_static! {
pub static ref T: std::collections::HashMap<&'static str, &'static str> =
[
("Status", "Status"),
("Your Desktop", "Seu Desktop"),
("desk_tip", "Seu desktop pode ser acessado com este ID e senha."),
("Password", "Senha"),
("Ready", "Pronto"),
("Established", "Estabelecido"),
("connecting_status", "Conectando à rede do RustDesk..."),
("Enable Service", "Habilitar Serviço"),
("Start Service", "Iniciar Serviço"),
("Service is running", "Serviço está em execução"),
("Service is not running", "Serviço não está em execução"),
("not_ready_status", "Não está pronto. Por favor verifique sua conexão"),
("Control Remote Desktop", "Controle o Desktop à distância"),
("Transfer File", "Transferir Arquivo"),
("Connect", "Conectar"),
("Recent Sessions", "Sessões recentes"),
("Address Book", "Lista de Endereços"),
("Confirmation", "Confirmação"),
("TCP Tunneling", "Tunelamento TCP"),
("Remove", "Remover"),
("Refresh random password", "Atualizar senha aleatória"),
("Set your own password", "Configure sua própria senha"),
("Enable Keyboard/Mouse", "Habilitar Teclado/Mouse"),
("Enable Clipboard", "Habilitar Área de Transferência"),
("Enable File Transfer", "Habilitar Transferência de Arquivos"),
("Enable TCP Tunneling", "Habilitar Tunelamento TCP"),
("IP Whitelisting", "Whitelisting de IP"),
("ID/Relay Server", "Servidor ID/Relay"),
("Stop service", "Parar serviço"),
("Change ID", "Alterar ID"),
("Website", "Website"),
("About", "Sobre"),
("Mute", "Emudecer"),
("Audio Input", "Endtrada de Áudio"),
("ID Server", "Servidor de ID"),
("Relay Server", "Servidor de Relay"),
("API Server", "Servidor da API"),
("invalid_http", "deve iniciar com http:// ou https://"),
("Invalid IP", "IP inválido"),
("id_change_tip", "Somente os caracteres a-z, A-Z, 0-9 e _ (sublinhado) são permitidos. A primeira letra deve ser a-z, A-Z. Comprimento entre 6 e 16."),
("Invalid format", "Formato inválido"),
("This function is turned off by the server", "Esta funcionalidade foi desligada pelo servidor"),
("Not available", "Indisponível"),
("Too frequent", "Muito frequente"),
("Cancel", "Cancelar"),
("Skip", "Pular"),
("Close", "Fechar"),
("Retry", "Tentar novamente"),
("OK", "OK"),
("Password Required", "Senha Necessária"),
("Please enter your password", "Por favor informe sua senha"),
("Remember password", "Lembrar senha"),
("Wrong Password", "Senha Incorreta"),
("Do you want to enter again?", "Você quer entrar novamente?"),
("Connection Error", "Erro de Conexão"),
("Error", "Erro"),
("Reset by the peer", "Reiniciado pelo par"),
("Connecting...", "Conectando..."),
("Connection in progress. Please wait.", "Conexão em progresso. Aguarde por favor."),
("Please try 1 minute later", "Por favor tente após 1 minuto"),
("Login Error", "Erro de Login"),
("Successful", "Sucesso"),
("Connected, waiting for image...", "Conectado. Aguardando pela imagem..."),
("Name", "Nome"),
("Type", "Tipo"),
("Modified", "Modificado"),
("Size", "Tamanho"),
("Show Hidden Files", "Mostrar Arquivos Ocultos"),
("Receive", "Receber"),
("Send", "Enviar"),
("Refresh File", "Atualizar Arquivo"),
("Local", "Local"),
("Remote", "Remoto"),
("Remote Computer", "Computador Remoto"),
("Local Computer", "Computador Local"),
("Confirm Delete", "Comfirmar Apagar"),
("Delete", "Apagar"),
("Properties", "Propriedades"),
("Multi Select", "Seleção Múltipla"),
("Empty Directory", "Diretório Vazio"),
("Not an empty directory", "Diretório não está vazio"),
("Are you sure you want to delete this file?", "Tem certeza que deseja apagar este arquivo?"),
("Are you sure you want to delete this empty directory?", "Tem certeza que deseja apagar este diretório vazio?"),
("Are you sure you want to delete the file of this directory?", "Tem certeza que deseja apagar este arquivo deste diretório?"),
("Do this for all conflicts", "Fazer isto para todos os conflitos"),
("This is irreversible!", "Isso é irreversível!"),
("Deleting", "Apagando"),
("files", "arquivos"),
("Waiting", "Aguardando"),
("Finished", "Completo"),
("Speed", "Velocidade"),
("Custom Image Quality", "Qualidade Visual Personalizada"),
("Privacy mode", "Modo privado"),
("Block user input", "Bloquear entrada de usuário"),
("Unblock user input", "Desbloquear entrada de usuário"),
("Adjust Window", "Ajustar Janela"),
("Original", "Original"),
("Shrink", "Reduzir"),
("Stretch", "Aumentar"),
("Good image quality", "Qualidade visual boa"),
("Balanced", "Balanceada"),
("Optimize reaction time", "Otimizar tempo de reação"),
("Custom", "Personalizado"),
("Show remote cursor", "Mostrar cursor remoto"),
("Disable clipboard", "Desabilitar área de transferência"),
("Lock after session end", "Bloquear após o fim da sessão"),
("Insert", "Inserir"),
("Insert Lock", "Inserir Trava"),
("Refresh", "Atualizar"),
("ID does not exist", "ID não existe"),
("Failed to connect to rendezvous server", "Falha ao conectar ao servidor de rendezvous"),
("Please try later", "Por favor tente mais tarde"),
("Remote desktop is offline", "Desktop remoto está offline"),
("Key mismatch", "Chaves incompatíveis"),
("Timeout", "Tempo esgotado"),
("Failed to connect to relay server", "Falha ao conectar ao servidor de relay"),
("Failed to connect via rendezvous server", "Falha ao conectar ao servidor de rendezvous"),
("Failed to connect via relay server", "Falha ao conectar através do servidor de relay"),
("Failed to make direct connection to remote desktop", "Falha ao fazer conexão direta ao desktop remoto"),
("Set Password", "Definir Senha"),
("OS Password", "Senha do SO"),
("install_tip", "Devido ao UAC, o RustDesk não funciona corretamente como o lado remoto em alguns casos. Para evitar o UAC, por favor clique no botão abaixo para instalar o RustDesk no sistema."),
("Click to upgrade", "Clique para fazer o upgrade"),
("Click to download", "Clique para baixar"),
("Click to update", "Clique para fazer o update"),
("Configure", "Configurar"),
("config_acc", "Para controlar seu Desktop remotamente, você precisa conceder ao RustDesk permissões de \"Acessibilidade\"."),
("config_screen", "Para acessar seu Desktop remotamente, você precisa conceder ao RustDesk permissões de \"Gravar a Tela\"/"),
("Installing ...", "Instalando ..."),
("Install", "Instalar"),
("Installation", "Instalação"),
("Installation Path", "Caminho da Instalação"),
("Create start menu shortcuts", "Criar atalhos no menu iniciar"),
("Create desktop icon", "Criar ícone na área de trabalho"),
("agreement_tip", "Ao iniciar a instalação, você concorda com o acordo de licença."),
("Accept and Install", "Aceitar e Instalar"),
("End-user license agreement", "Acordo de licença do usuário final"),
("Generating ...", "Gerando ..."),
("Your installation is lower version.", "Sua instalação é de uma versão menor."),
("not_close_tcp_tip", "Não feche esta janela enquanto estiver utilizando o túnel"),
("Listening ...", "Escutando ..."),
("Remote Host", "Host Remoto"),
("Remote Port", "Porta Remota"),
("Action", "Ação"),
("Add", "Adicionar"),
("Local Port", "Porta Local"),
("setup_server_tip", "Para uma conexão mais rápida, por favor configure seu próprio servidor"),
("Too short, at least 6 characters.", "Muito curto, pelo menos 6 caracteres."),
("The confirmation is not identical.", "A confirmação não é idêntica."),
("Permissions", "Permissões"),
("Accept", "Aceitar"),
("Dismiss", "Dispensar"),
("Disconnect", "Desconectar"),
("Allow using keyboard and mouse", "Permitir o uso de teclado e mouse"),
("Allow using clipboard", "Permitir o uso da área de transferência"),
("Allow hearing sound", "Permitir escutar som"),
("Allow file transfer", "Permitir transferência de arquivo"),
("File transfer", "Transferência de arquivo"),
("Connected", "Conectado"),
("Direct and encrypted connection", "Conexão direta e criptografada"),
("Relayed and encrypted connection", "Conexão via relay e criptografada"),
("Direct and unencrypted connection", "Conexão direta e não criptografada"),
("Relayed and unencrypted connection", "Conexão via relay e não criptografada"),
("Enter Remote ID", "Informe o ID Remoto"),
("Enter your password", "Informe sua senha"),
("Logging in...", "Fazendo Login..."),
("Enable RDP session sharing", "Habilitar compartilhamento de sessão RDP"),
("Auto Login", "Login Automático (Somente válido se você habilitou \"Bloquear após o fim da sessão\")"),
("Enable Direct IP Access", "Habilitar Acesso IP Direto"),
("Rename", "Renomear"),
("Space", "Espaõ"),
("Create Desktop Shortcut", "Criar Atalho na Área de Trabalho"),
("Change Path", "Alterar Caminho"),
("Create Folder", "Criar Diretório"),
("Please enter the folder name", "Por favor informe o nome do diretório"),
("Fix it", "Conserte"),
("Warning", "Aguardando"),
("Login screen using Wayland is not supported", "Tela de Login utilizando Wayland não é suportada"),
("Reboot required", "Reinicialização necessária"),
("Unsupported display server ", "Servidor de display não suportado"),
("x11 expected", "x11 esperado"),
("Port", "Porta"),
("Settings", "Configurações"),
("Username", "Nome de usuário"),
("Invalid port", "Porta inválida"),
("Closed manually by the peer", "Fechada manualmente pelo par"),
("Enable remote configuration modification", "Habilitar modificações de configuração remotas"),
("Run without install", "Executar sem instalar"),
("Always connected via relay", "Sempre conectado via relay"),
("Always connect via relay", "Sempre conectar via relay"),
("whitelist_tip", "Somente IPs na whitelist podem me acessar"),
("Login", "Login"),
("Logout", "Sair"),
("Tags", "Tags"),
("Search ID", "Buscar ID"),
("Current Wayland display server is not supported", "Servidor de display Wayland atual não é suportado"),
("whitelist_sep", "Separado por vírcula, ponto-e-vírgula, espaços ou nova linha"),
("Add ID", "Adicionar ID"),
("Add Tag", "Adicionar Tag"),
("Unselect all tags", "Desselecionar todas as tags"),
("Network error", "Erro de rede"),
("Username missed", "Nome de usuário faltante"),
("Password missed", "Senha faltante"),
("Wrong credentials", "Nome de usuário ou senha incorretos"),
("Edit Tag", "Editar Tag"),
("Unremember Password", "Esquecer Senha"),
("Favorites", "Favoritos"),
("Add to Favorites", "Adicionar aos Favoritos"),
("Remove from Favorites", "Remover dos Favoritos"),
("Empty", "Vazio"),
("Invalid folder name", "Nome de diretório inválido"),
("Socks5 Proxy", "Proxy Socks5"),
("Hostname", "Nome de anfitrião"),
("Discovered", "Descoberto"),
("install_daemon_tip", "Para inicialização junto ao sistema, você deve instalar o serviço de sistema."),
("Remote ID", "ID Remoto"),
("Paste", "Colar"),
("Paste here?", "Colar aqui?"),
("Are you sure to close the connection?", "Tem certeza que deseja fechar a conexão?"),
("Download new version", "Baixar nova versão"),
("Touch mode", "Modo toque"),
("Mouse mode", "Modo mouse"),
("One-Finger Tap", "Toque com um dedo"),
("Left Mouse", "Botão esquerdo do mouse"),
("One-Long Tap", "Um toque longo"),
("Two-Finger Tap", "Toque com dois dedos"),
("Right Mouse", "Botão direito do mouse"),
("One-Finger Move", "Mover com um dedo"),
("Double Tap & Move", "Toque duplo & mover"),
("Mouse Drag", "Arrastar com o mouse"),
("Two-Finger vertically", "Dois dedos verticalmente"),
("Mouse Wheel", "Roda do Mouse"),
("Two-Finger Move", "Mover com dois dedos"),
("Canvas Move", "Mover Tela"),
("Pinch to Zoom", "Beliscar para Zoom"),
("Canvas Zoom", "Zoom na Tela"),
("Reset canvas", "Reiniciar tela"),
("No permission of file transfer", "Sem permissões de transferência de arquivo"),
("Note", "Nota"),
("Connection", "Conexão"),
("Share Screen", "Compartilhar Tela"),
("CLOSE", "FECHAR"),
("OPEN", "ABRIR"),
("Chat", "Chat"),
("Total", "Total"),
("items", "itens"),
("Selected", "Selecionado"),
("Screen Capture", "Captura de Tela"),
("Input Control", "Controlo de Entrada"),
("File Transfer", "Transferência de Arquivo"),
("Audio Capture", "Captura de Áudio"),
("File Connection", "Conexão de Arquivo"),
("Screen Connection", "Conexão de Tela"),
("Do you accept?", "Você aceita?"),
("Open System Setting", "Abrir Configurações do Sistema"),
("How to get Android input permission?", "Como habilitar a permissão de entrada do Android?"),
("android_input_permission_tip1", "Para que um dispositivo remoto controle seu dispositivo Android via mouse ou toque, você precisa permitir que o RustDesk use o serviço \"Acessibilidade\"."),
("android_input_permission_tip2", "Por favor vá para a próxima página de configuração do sistema, encontre e entre [Serviços Instalados], HABILITE o serviço [RustDesk Input]."),
("android_new_connection_tip", "Nova requisição de controle recebida, solicita o controle de seu dispositivo atual."),
("android_service_will_start_tip", "Habilitar a Captura de Tela irá automaticamente inicalizar o serviço, permitindo que outros dispositivos solicitem uma conexão deste dispositivo."),
("android_stop_service_tip", "Fechar o serviço irá automaticamente fechar todas as conexões estabelecidas."),
("android_version_audio_tip", "A versão atual do Android não suporta captura de áudio, por favor atualize para o Android 10 ou maior."),
("android_start_service_tip", "Toque [Iniciar Serviço] ou ABRA a permissão [Captura de Tela] para iniciar o serviço de compartilhamento de tela."),
("Account", "Conta"),
("Quit", "Saída"),
("Help", "Ajuda"),
].iter().cloned().collect();
}

271
src/lang/ru.rs Normal file
View File

@@ -0,0 +1,271 @@
lazy_static::lazy_static! {
pub static ref T: std::collections::HashMap<&'static str, &'static str> =
[
("Status", "атус"),
("Your Desktop", "Ваш рабочий стол"),
("desk_tip", "Ваш рабочий стол доступен с этим идентификатором и паролем"),
("Password", "Пароль"),
("Ready", "Готово"),
("Established", "Установлено"),
("connecting_status", "Подключение к сети RustDesk.."),
("Enable Service", "Включить службу"),
("Start Service", "Запустить службу"),
("Service is running", "Служба работает"),
("Service is not running", "Служба не запущена"),
("not_ready_status", "Не готово. Пожалуйста, проверьте подключение"),
("Control Remote Desktop", "Управление удаленным рабочим столом"),
("Transfer File", "Передать файл"),
("Connect", "Подключиться"),
("Recent Sessions", "Последние сеансы"),
("Address Book", "Адресная книга"),
("Confirmation", "Подтверждение"),
("TCP Tunneling", "TCP-туннелирование"),
("Remove", "Удалить"),
("Refresh random password", "Обновить случайный пароль"),
("Set your own password", "Установить свой пароль"),
("Enable Keyboard/Mouse", "Включить клавиатуру/мышь"),
("Enable Clipboard", "Включить буфер обмена"),
("Enable File Transfer", "Включить передачу файлов"),
("Enable TCP Tunneling", "Включить туннелирование TCP"),
("IP Whitelisting", "Список разрешенных IP-адресов"),
("ID/Relay Server", "ID/Сервер ретрансляции"),
("Stop service", "Остановить службу"),
("Change ID", "Изменить ID"),
("Website", "Веб-сайт"),
("About", "О RustDesk"),
("Mute", "Отключить звук"),
("Audio Input", "Аудиовход"),
("ID Server", "ID сервер"),
("Relay Server", "Сервер ретрансляции"),
("API Server", "API сервер"),
("invalid_http", "Должен начинаться с http:// или https://"),
("Invalid IP", "Неверный IP-адрес"),
("id_change_tip", "Допускаются только символы a-z, A-Z, 0-9 и _ (подчеркивание). Первая буква должна быть a-z, A-Z. Длина от 6 до 16"),
("Invalid format", "Неверный формат"),
("This function is turned off by the server", "Эта функция не предоставляется сервером"),
("Not available", "Недоступно"),
("Too frequent", "Слишком часто"),
("Cancel", "Отменить"),
("Skip", "Пропустить"),
("Close", "Закрыть"),
("Retry", "Попробовать еще раз"),
("OK", "ОК"),
("Password Required", "Требуется пароль"),
("Please enter your password", "Пожалуйста, введите ваш пароль"),
("Remember password", "Запомнить пароль"),
("Wrong Password", "Неверный пароль"),
("Do you want to enter again?", "Вы хотите снова войти?"),
("Connection Error", "Ошибка подключения"),
("Error", "Ошибка"),
("Reset by the peer", "Сброшено узлом"),
("Connecting...", "Подключение.."),
("Connection in progress. Please wait.", "Подключение. Подождите"),
("Please try 1 minute later", "Попробуйте через 1 минуту"),
("Login Error", "Ошибка входа"),
("Successful", "Операция успешна"),
("Connected, waiting for image...", "Подключено, ожидание изображения.."),
("Name", "Имя"),
("Type", "Тип"),
("Modified", "Изменено"),
("Size", "Размер"),
("Show Hidden Files", "Показать скрытые файлы"),
("Receive", "Получить"),
("Send", "Отправить"),
("Refresh File", "Обновить файл"),
("Local", "Местный"),
("Remote", "Удаленный"),
("Remote Computer", "Удаленный компьютер"),
("Local Computer", "Локальный компьютер"),
("Confirm Delete", "Подтвердить удаление"),
("Delete", "Удалить"),
("Properties", "Свойства"),
("Multi Select", "Многоэлементный выбор"),
("Empty Directory", "Пустая папка"),
("Not an empty directory", "Папка не пуста"),
("Are you sure you want to delete this file?", "Вы уверены, что хотите удалить этот файл?"),
("Are you sure you want to delete this empty directory?", "Вы уверены, что хотите удалить пустую папку?"),
("Are you sure you want to delete the file of this directory?", "Вы уверены, что хотите удалить файл из этой папки?"),
("Do this for all conflicts", "Это относится ко всем конфликтам"),
("This is irreversible!", "Это необратимо!"),
("Deleting", "Удаление"),
("files", "файлы"),
("Waiting", "Ожидание"),
("Finished", "Завершено"),
("Speed", "Скорость"),
("Custom Image Quality", "Пользовательские настройки изображения"),
("Privacy mode", "Режим конфиденциальности"),
("Block user input", "Блокировать пользовательский ввод"),
("Unblock user input", "Разблокировать пользовательский ввод"),
("Adjust Window", "Настроить окно"),
("Original", "Оригинал"),
("Shrink", "Уменьшить"),
("Stretch", "Растянуть"),
("Good image quality", "Хорошее качество изображения"),
("Balanced", "Сбалансированный"),
("Optimize reaction time", "Оптимизировать время реакции"),
("Custom", "Пользовательский"),
("Show remote cursor", "Показать удаленный курсор"),
("Disable clipboard", "Отключить буфер обмена"),
("Lock after session end", "Выход из учётной записи после завершения сеанса"),
("Insert", "Вставить"),
("Insert Lock", "Установить замок"),
("Refresh", "Обновить"),
("ID does not exist", "ID не существует"),
("Failed to connect to rendezvous server", "Не удалось подключиться к промежуточному серверу"),
("Please try later", "Пожалуйста, попробуйте позже"),
("Remote desktop is offline", "Удаленный рабочий стол не онлайн"),
("Key mismatch", "Несоответствие ключей"),
("Timeout", "Тайм-аут"),
("Failed to connect to relay server", "Не удалось подключиться к серверу ретрансляции"),
("Failed to connect via rendezvous server", "Не удалось подключиться через промежуточный сервер"),
("Failed to connect via relay server", "Не удалось подключиться через сервер ретрансляции"),
("Failed to make direct connection to remote desktop", "Не удалось установить прямое подключение к удаленному рабочему столу"),
("Set Password", "Установить пароль"),
("OS Password", "Пароль операционной системы"),
("install_tip", "В некоторых случаях из-за UAC RustDesk может работать некорректно на удаленном узле. Чтобы избежать UAC, нажмите кнопку ниже, чтобы установить RustDesk в системе"),
("Click to upgrade", "Нажмите, чтобы проверить на наличие обновлений"),
("Click to download", "Нажмите, чтобы скачать"),
("Click to update", "Нажмите, чтобы обновить"),
("Configure", "Настроить"),
("config_acc", "Чтобы удаленно управлять своим рабочим столом, вы должны предоставить RustDesk права \"доступа\""),
("config_screen", "Для удаленного доступа к рабочему столу вы должны предоставить RustDesk права \"снимок экрана\""),
("Installing ...", "Устанавливаеться..."),
("Install", "Установить"),
("Installation", "Установка"),
("Installation Path", "Папка установки"),
("Create start menu shortcuts", "Создать ярлыки меню \"Пуск\""),
("Create desktop icon", "Создать значок на рабочем столе"),
("agreement_tip", "Если вы начнете установку, примите лицензионное соглашение"),
("Accept and Install", "Принять и установить"),
("End-user license agreement", "Лицензионное соглашение с конечным пользователем"),
("Generating ...", "Генерация..."),
("Your installation is lower version.", "Ваша инсталяция является более ранней версией"),
("not_close_tcp_tip", "Не закрывать это окно при использовании туннеля"),
("Listening ...", "Ожидаем ..."),
("Remote Host", "Удаленная машина"),
("Remote Port", "Удаленный порт"),
("Action", "Действие"),
("Add", "Добавить"),
("Local Port", "Локальный порт"),
("setup_server_tip", "Для более быстрого подключения настройте свой собственный сервер подключения"),
("Too short, at least 6 characters.", "Слишком коротко, не менее 6 символов"),
("The confirmation is not identical.", "Подтверждение не идентично"),
("Permissions", "Разрешения"),
("Accept", "Принять"),
("Dismiss", "Отклонить"),
("Disconnect", "Отключить"),
("Allow using keyboard and mouse", "Разрешить использование клавиатуры и мыши"),
("Allow using clipboard", "Разрешить использование буфера обмена"),
("Allow hearing sound", "Разрешить передачу звука"),
("Allow file transfer", "Разрешить передачу файлов"),
("File transfer", "Передача файлов"),
("Connected", "Подключено"),
("Direct and encrypted connection", "Прямое и шифрованное соединение"),
("Relayed and encrypted connection", "Коммутируемое и зашифрованное соединение"),
("Direct and unencrypted connection", "Прямое и незашифрованное соединение"),
("Relayed and unencrypted connection", "Коммутируемое и незашифрованное соединение"),
("Enter Remote ID", "Введите удаленный идентификатор"),
("Enter your password", "Введите пароль"),
("Logging in...", "Входим..."),
("Enable RDP session sharing", "Включить общий доступ к сеансу RDP"),
("Auto Login", "Автоматический вход (действителен, только если вы установили \"Завершения пользовательского сеанса после завершения удалённого подключения\""),
("Enable Direct IP Access", "Включить прямой IP-доступ"),
("Rename", "Переименовать"),
("Space", "Место"),
("Create Desktop Shortcut", "Создать ярлык на рабочем столе"),
("Change Path", "Изменить путь"),
("Create Folder", "Создать папку"),
("Please enter the folder name", "Пожалуйста, введите имя папки"),
("Fix it", "Отремонтировать"),
("Warning", "Предупреждение"),
("Login screen using Wayland is not supported", "Вход в систему с использованием Wayland не поддерживается"),
("Reboot required", "Требуется перезагрузка"),
("Unsupported display server ", "Неподдерживаемый сервер дисплея"),
("x11 expected", "Ожидается X11"),
("Port", "Порт"),
("Settings", "Настройки"),
("Username", "Имя пользователя"),
("Invalid port", "Неверный порт"),
("Closed manually by the peer", "Закрыто узлом вручную"),
("Enable remote configuration modification", "Разрешить удаленное изменение конфигурации"),
("Run without install", "Запустить без установки"),
("Always connected via relay", "Всегда подключен через ретрансляционный сервер"),
("Always connect via relay", "Всегда подключаться через ретрансляционный сервер"),
("whitelist_tip", "Только IP-адреса из белого списка могут получить доступ ко мне"),
("Login", "Войти"),
("Logout", "Выйти"),
("Tags", "Ключевые слова"),
("Search ID", "Поиск по ID"),
("Current Wayland display server is not supported", "Текущий сервер отображения Wayland не поддерживается"),
("whitelist_sep", "Раздельно запятой, точкой с запятой, пробелом или новой строкой"),
("Add ID", "Добавить ID"),
("Add Tag", "Добавить ключевое слово"),
("Unselect all tags", "Отменить выбор всех тегов"),
("Network error", "Ошибка сети"),
("Username missed", "Имя пользователя отсутствует"),
("Password missed", "Забыли пароль"),
("Wrong credentials", "Неверные учетные данные"),
("Edit Tag", "Редактировать тег"),
("Unremember Password", "Не сохранять пароль"),
("Favorites", "Избранное"),
("Add to Favorites", "Добавить в избранное"),
("Remove from Favorites", "Удалить из избранного"),
("Empty", "Пусто"),
("Invalid folder name", "Недопустимое имя папки"),
("Socks5 Proxy", "Прокси-сервер Socks5"),
("Hostname", "Имя ПК"),
("Discovered", "Найдено"),
("install_daemon_tip", "Для запуска при загрузке необходимо установить системную службу"),
("Remote ID", "Удаленный идентификатор"),
("Paste", "Вставить"),
("Paste here?", "Вставить сюда?"),
("Are you sure to close the connection?", "Вы уверены, что хотите закрыть соединение?"),
("Download new version", "Загрузить новую версию"),
("Touch mode", "Сенсорный режим"),
("Mouse mode", "Режим мыши"),
("One-Finger Tap", "Касание одним пальцем"),
("Left Mouse", "Левая кнопка мыши"),
("One-Long Tap", "Одно долгое касание пальцем"),
("Two-Finger Tap", "Касание двумя пальцами"),
("Right Mouse", "Правая мышь"),
("One-Finger Move", "Движение одним пальцем"),
("Double Tap & Move", "Двойное нажатие и перемещение"),
("Mouse Drag", "Перетаскивание мышью"),
("Two-Finger vertically", "Двумя пальцами по вертикали"),
("Mouse Wheel", "Колесико мыши"),
("Two-Finger Move", "Движение двумя пальцами"),
("Canvas Move", "Перемещение холста"),
("Pinch to Zoom", "Щепотка, чтобы увеличить"),
("Canvas Zoom", "Масштаб холста"),
("Reset canvas", "Сбросить холст"),
("No permission of file transfer", "Нет разрешения на передачу файлов"),
("Note", "Примечание"),
("Connection", "Соединение"),
("Share Screen", "Поделиться экраном"),
("CLOSE", "ЗАКРЫТЬ"),
("OPEN", "ОТКРЫТЬ"),
("Chat", "Чат"),
("Total", "Всего"),
("items", "обьекты"),
("Selected", "Выбрано"),
("Screen Capture", "Скриншот"),
("Input Control", "Входной контроль"),
("File Transfer", "Передача файлов"),
("Audio Capture", "Захват аудио"),
("File Connection", "Файловое соединение"),
("Screen Connection", "Подключение экрана"),
("Do you accept?", "Вы согласны?"),
("Open System Setting", "Открыть настройки системы"),
("How to get Android input permission?", "Как получить разрешение на ввод Android?"),
("android_input_permission_tip1", "Чтобы удаленное устройство могло управлять вашим Android-устройством с помощью мыши или касания, вам необходимо разрешить RustDesk использовать службу «Специальные возможности»."),
("android_input_permission_tip2", "Перейдите на следующую страницу системных настроек, найдите и войдите в [Установленные службы], включите службу [RustDesk Input]."),
("android_new_connection_tip", "Получен новый запрос на управление вашим текущим устройством."),
("android_service_will_start_tip", "Включение захвата экрана автоматически запускает службу, позволяя другим устройствам запрашивать соединение с этого устройства."),
("android_stop_service_tip", "Закрытие службы автоматически закроет все установленные соединения."),
("android_version_audio_tip", "Текущая версия Android не поддерживает захват звука, обновите ее до Android 10 или выше."),
("android_start_service_tip", "Коснитесь [Запуск промежуточного сервера] или ОТКРЫТЬ разрешение [Скриншот], чтобы запустить службу демонстрации экрана."),
("Account", "Аккаунт"),
("Quit", "Выйти"),
("Help", "Помощь"),
].iter().cloned().collect();
}

269
src/lang/template.rs Normal file
View File

@@ -0,0 +1,269 @@
lazy_static::lazy_static! {
pub static ref T: std::collections::HashMap<&'static str, &'static str> =
[
("Status", ""),
("Your Desktop", ""),
("desk_tip", ""),
("Password", ""),
("Ready", ""),
("Established", ""),
("connecting_status", ""),
("Enable Service", ""),
("Start Service", ""),
("Service is running", ""),
("Service is not running", ""),
("not_ready_status", ""),
("Control Remote Desktop", ""),
("Transfer File", ""),
("Connect", ""),
("Recent Sessions", ""),
("Address Book", ""),
("Confirmation", ""),
("TCP Tunneling", ""),
("Remove", ""),
("Refresh random password", ""),
("Set your own password", ""),
("Enable Keyboard/Mouse", ""),
("Enable Clipboard", ""),
("Enable File Transfer", ""),
("Enable TCP Tunneling", ""),
("IP Whitelisting", ""),
("ID/Relay Server", ""),
("Stop service", ""),
("Change ID", ""),
("Website", ""),
("About", ""),
("Mute", ""),
("Audio Input", ""),
("ID Server", ""),
("Relay Server", ""),
("API Server", ""),
("invalid_http", ""),
("Invalid IP", ""),
("id_change_tip", ""),
("Invalid format", ""),
("This function is turned off by the server", ""),
("Not available", ""),
("Too frequent", ""),
("Cancel", ""),
("Skip", ""),
("Close", ""),
("Retry", ""),
("OK", ""),
("Password Required", ""),
("Please enter your password", ""),
("Remember password", ""),
("Wrong Password", ""),
("Do you want to enter again?", ""),
("Connection Error", ""),
("Error", ""),
("Reset by the peer", ""),
("Connecting...", ""),
("Connection in progress. Please wait.", ""),
("Please try 1 minute later", ""),
("Login Error", ""),
("Successful", ""),
("Connected, waiting for image...", ""),
("Name", ""),
("Type", ""),
("Modified", ""),
("Size", ""),
("Show Hidden Files", ""),
("Receive", ""),
("Send", ""),
("Refresh File", ""),
("Local", ""),
("Remote", ""),
("Remote Computer", ""),
("Local Computer", ""),
("Confirm Delete", ""),
("Delete", ""),
("Properties", ""),
("Multi Select", ""),
("Empty Directory", ""),
("Not an empty directory", ""),
("Are you sure you want to delete this file?", ""),
("Are you sure you want to delete this empty directory?", ""),
("Are you sure you want to delete the file of this directory?", ""),
("Do this for all conflicts", ""),
("This is irreversible!", ""),
("Deleting", ""),
("files", ""),
("Waiting", ""),
("Finished", ""),
("Speed", ""),
("Custom Image Quality", ""),
("Privacy mode", ""),
("Block user input", ""),
("Unblock user input", ""),
("Adjust Window", ""),
("Original", ""),
("Shrink", ""),
("Stretch", ""),
("Good image quality", ""),
("Balanced", ""),
("Optimize reaction time", ""),
("Custom", ""),
("Show remote cursor", ""),
("Disable clipboard", ""),
("Lock after session end", ""),
("Insert", ""),
("Insert Lock", ""),
("Refresh", ""),
("ID does not exist", ""),
("Failed to connect to rendezvous server", ""),
("Please try later", ""),
("Remote desktop is offline", ""),
("Key mismatch", ""),
("Timeout", ""),
("Failed to connect to relay server", ""),
("Failed to connect via rendezvous server", ""),
("Failed to connect via relay server", ""),
("Failed to make direct connection to remote desktop", ""),
("Set Password", ""),
("OS Password", ""),
("install_tip", ""),
("Click to upgrade", ""),
("Click to download", ""),
("Click to update", ""),
("Configure", ""),
("config_acc", ""),
("config_screen", ""),
("Installing ...", ""),
("Install", ""),
("Installation", ""),
("Installation Path", ""),
("Create start menu shortcuts", ""),
("Create desktop icon", ""),
("agreement_tip", ""),
("Accept and Install", ""),
("End-user license agreement", ""),
("Generating ...", ""),
("Your installation is lower version.", ""),
("not_close_tcp_tip", ""),
("Listening ...", ""),
("Remote Host", ""),
("Remote Port", ""),
("Action", ""),
("Add", ""),
("Local Port", ""),
("setup_server_tip", ""),
("Too short, at least 6 characters.", ""),
("The confirmation is not identical.", ""),
("Permissions", ""),
("Accept", ""),
("Dismiss", ""),
("Disconnect", ""),
("Allow using keyboard and mouse", ""),
("Allow using clipboard", ""),
("Allow hearing sound", ""),
("Allow file transfer", ""),
("File transfer", ""),
("Connected", ""),
("Direct and encrypted connection", ""),
("Relayed and encrypted connection", ""),
("Direct and unencrypted connection", ""),
("Relayed and unencrypted connection", ""),
("Enter Remote ID", ""),
("Enter your password", ""),
("Logging in...", ""),
("Enable RDP session sharing", ""),
("Auto Login", ""),
("Enable Direct IP Access", ""),
("Rename", ""),
("Space", ""),
("Create Desktop Shortcut", ""),
("Change Path", ""),
("Create Folder", ""),
("Please enter the folder name", ""),
("Fix it", ""),
("Warning", ""),
("Login screen using Wayland is not supported", ""),
("Reboot required", ""),
("Unsupported display server ", ""),
("x11 expected", ""),
("Port", ""),
("Settings", ""),
("Username", ""),
("Invalid port", ""),
("Closed manually by the peer", ""),
("Enable remote configuration modification", ""),
("Run without install", ""),
("Always connected via relay", ""),
("Always connect via relay", ""),
("whitelist_tip", ""),
("Login", ""),
("Logout", ""),
("Tags", ""),
("Search ID", ""),
("Current Wayland display server is not supported", ""),
("whitelist_sep", ""),
("Add ID", ""),
("Add Tag", ""),
("Unselect all tags", ""),
("Network error", ""),
("Username missed", ""),
("Password missed", ""),
("Wrong credentials", ""),
("Edit Tag", ""),
("Unremember Password", ""),
("Favorites", ""),
("Add to Favorites", ""),
("Remove from Favorites", ""),
("Empty", ""),
("Invalid folder name", ""),
("Socks5 Proxy", ""),
("Hostname", ""),
("Discovered", ""),
("install_daemon_tip", ""),
("Remote ID", ""),
("Paste", ""),
("Paste here?", ""),
("Are you sure to close the connection?", ""),
("Download new version", ""),
("Touch mode", ""),
("Mouse mode", ""),
("One-Finger Tap", ""),
("Left Mouse", ""),
("One-Long Tap", ""),
("Two-Finger Tap", ""),
("Right Mouse", ""),
("One-Finger Move", ""),
("Double Tap & Move", ""),
("Mouse Drag", ""),
("Two-Finger vertically", ""),
("Mouse Wheel", ""),
("Two-Finger Move", ""),
("Canvas Move", ""),
("Pinch to Zoom", ""),
("Canvas Zoom", ""),
("Reset canvas", ""),
("No permission of file transfer", ""),
("Note", ""),
("Connection", ""),
("Share Screen", ""),
("CLOSE", ""),
("OPEN", ""),
("Chat", ""),
("Total", ""),
("items", ""),
("Selected", ""),
("Screen Capture", ""),
("Input Control", ""),
("File Transfer", ""),
("Audio Capture", ""),
("File Connection", ""),
("Screen Connection", ""),
("Do you accept?", ""),
("Open System Setting", ""),
("How to get Android input permission?", ""),
("android_input_permission_tip1", ""),
("android_input_permission_tip2", ""),
("android_new_connection_tip", ""),
("android_service_will_start_tip", ""),
("android_stop_service_tip", ""),
("android_version_audio_tip", ""),
("android_start_service_tip", ""),
("Account", ""),
].iter().cloned().collect();
}

272
src/lang/tw.rs Normal file
View File

@@ -0,0 +1,272 @@
lazy_static::lazy_static! {
pub static ref T: std::collections::HashMap<&'static str, &'static str> =
[
("Status", "狀態"),
("Your Desktop", "您的桌面"),
("desk_tip", "您可以透過此 ID 及密碼存取您的桌面"),
("Password", "密碼"),
("Ready", "就緒"),
("Established", "已建立"),
("connecting_status", "正在連接至 RustDesk 網路..."),
("Enable Service", "啟用服務"),
("Start Service", "啟動服務"),
("Service is running", "服務正在運行"),
("Service is not running", "服務尚未執行"),
("not_ready_status", "尚未就緒。請檢查您的網路連線"),
("Control Remote Desktop", "控制遠端桌面"),
("Transfer File", "傳輸檔案"),
("Connect", "連接"),
("Recent Sessions", "近期的工作階段"),
("Address Book", "通訊錄"),
("Confirmation", "確認"),
("TCP Tunneling", "TCP 通道"),
("Remove", "移除"),
("Refresh random password", "重新產生隨機密碼"),
("Set your own password", "自行設置密碼"),
("Enable Keyboard/Mouse", "啟用鍵盤/滑鼠"),
("Enable Clipboard", "啟用剪貼簿"),
("Enable File Transfer", "啟用檔案傳輸"),
("Enable TCP Tunneling", "啟用 TCP 通道"),
("IP Whitelisting", "IP 白名單"),
("ID/Relay Server", "ID/轉送伺服器"),
("Stop service", "停止服務"),
("Change ID", "更改 ID"),
("Website", "網站"),
("About", "關於"),
("Mute", "靜音"),
("Audio Input", "音訊輸入"),
("ID Server", "ID 伺服器"),
("Relay Server", "轉送伺服器"),
("API Server", "API 伺服器"),
("invalid_http", "開頭必須為 http:// 或 https://"),
("Invalid IP", "IP 無效"),
("id_change_tip", "僅能使用以下字元a-z、A-Z、0-9、_ (底線)。首字元必須為 a-z 或 A-Z。長度介於 6 到 16 之間。"),
("Invalid format", "格式無效"),
("This function is turned off by the server", "此功能已被伺服器停用"),
("Not available", "無法使用"),
("Too frequent", "修改過於頻繁,請稍後再試。"),
("Cancel", "取消"),
("Skip", "跳過"),
("Close", "關閉"),
("Retry", "重試"),
("OK", "確定"),
("Password Required", "需要密碼"),
("Please enter your password", "請輸入您的密碼"),
("Remember password", "記住密碼"),
("Wrong Password", "密碼錯誤"),
("Do you want to enter again?", "您要重新輸入嗎?"),
("Connection Error", "連線錯誤"),
("Error", "錯誤"),
("Reset by the peer", "對方重置了連線"),
("Connecting...", "正在連接..."),
("Connection in progress. Please wait.", "正在連接,請稍候。"),
("Please try 1 minute later", "請於 1 分鐘後再試"),
("Login Error", "登入錯誤"),
("Successful", "成功"),
("Connected, waiting for image...", "已連線,等待畫面傳輸..."),
("Name", "名稱"),
("Type", "類型"),
("Modified", "修改時間"),
("Size", "大小"),
("Show Hidden Files", "顯示隱藏檔案"),
("Receive", "接收"),
("Send", "傳送"),
("Refresh File", "刷新文件"),
("Local", "本地"),
("Remote", "遠端"),
("Remote Computer", "遠端電腦"),
("Local Computer", "本地電腦"),
("Confirm Delete", "確認刪除"),
("Delete", "刪除"),
("Properties", "屬性"),
("Multi Select", "多選"),
("Empty Directory", "空文件夾"),
("Not an empty directory", "不是一個空文件夾"),
("Are you sure you want to delete this file?", "您確定要刪除此檔案嗎?"),
("Are you sure you want to delete this empty directory?", "您確定要刪除此空文件夾?"),
("Are you sure you want to delete the file of this directory?", "您確定要刪除文件夾下的文件?"),
("Do this for all conflicts", "套用到其他衝突"),
("This is irreversible!", "此操作不可逆!"),
("Deleting", "正在刪除"),
("files", "檔案"),
("Waiting", "正在等候..."),
("Finished", "已完成"),
("Speed", "速度"),
("Custom Image Quality", "自訂圖片品質"),
("Privacy mode", "隱私模式"),
("Block user input", "封鎖使用者輸入"),
("Unblock user input", "取消封鎖使用者輸入"),
("Adjust Window", "調整視窗"),
("Original", "原始"),
("Shrink", "縮減"),
("Stretch", "延展"),
("Good image quality", "畫面品質良好"),
("Balanced", "平衡"),
("Optimize reaction time", "回應速度最佳化"),
("Custom", "自訂"),
("Show remote cursor", "顯示遠端游標"),
("Disable clipboard", "停用剪貼簿"),
("Lock after session end", "工作階段結束後鎖定電腦"),
("Insert", "插入"),
("Insert Lock", "鎖定遠端電腦"),
("Refresh", "重新載入"),
("ID does not exist", "ID 不存在"),
("Failed to connect to rendezvous server", "無法連接至 rendezvous 伺服器"),
("Please try later", "請稍候再試"),
("Remote desktop is offline", "遠端電腦離線"),
("Key mismatch", "金鑰不符"),
("Timeout", "逾時"),
("Failed to connect to relay server", "無法連接至轉送伺服器"),
("Failed to connect via rendezvous server", "無法透過 rendezvous 伺服器連接"),
("Failed to connect via relay server", "無法透過轉送伺服器連接"),
("Failed to make direct connection to remote desktop", "無法直接連線至遠端電腦"),
("Set Password", "設置密碼"),
("OS Password", "作業系統密碼"),
("install_tip", "UAC 會導致 RustDesk 在某些情況下無法正常以遠端電腦運作。若要避開 UAC請點擊下方按鈕將 RustDesk 安裝到系統中。"),
("Click to upgrade", "點擊以升級"),
("Click to download", "點擊以下載"),
("Click to update", "點擊以更新"),
("Configure", "設定"),
("config_acc", "您需要授予 RustDesk 「協助工具」 權限才能遠端存取電腦。"),
("config_screen", "您需要授予 RustDesk 「畫面錄製」 權限才能遠端存取電腦。"),
("Installing ...", "正在安裝..."),
("Install", "安裝"),
("Installation", "安裝"),
("Installation Path", "安裝路徑"),
("Create start menu shortcuts", "建立開始選單捷徑"),
("Create desktop icon", "建立桌面圖示"),
("agreement_tip", "開始安裝即表示接受許可協議"),
("Accept and Install", "接受並安裝"),
("End-user license agreement", "使用者授權合約"),
("Generating ...", "正在產生 ..."),
("Your installation is lower version.", "您的安裝版本過舊。"),
("not_close_tcp_tip", "使用通道時請不要關閉此視窗"),
("Listening ...", "正在等待通道連接..."),
("Remote Host", "遠端主機"),
("Remote Port", "遠端連接埠"),
("Action", "操作"),
("Add", "新增"),
("Local Port", "本機連接埠"),
("setup_server_tip", "若您需要更快的連接速度,可以選擇自行建立伺服器"),
("Too short, at least 6 characters.", "過短,至少需 6 個字元。"),
("The confirmation is not identical.", "兩次輸入不相符"),
("Permissions", "權限"),
("Accept", "接受"),
("Dismiss", "關閉"),
("Disconnect", "斷開連線"),
("Allow using keyboard and mouse", "允許使用鍵盤和滑鼠"),
("Allow using clipboard", "允許使用剪貼簿"),
("Allow hearing sound", "允許分享音訊"),
("Allow file transfer", "允許文件傳輸"),
("File transfer", "文件傳輸"),
("Connected", "已連接"),
("Direct and encrypted connection", "加密直接連線"),
("Relayed and encrypted connection", "加密轉送連線"),
("Direct and unencrypted connection", "未加密直接連線"),
("Relayed and unencrypted connection", "未加密轉送連線"),
("Enter Remote ID", "輸入遠端 ID"),
("Enter your password", "輸入您的密碼"),
("Logging in...", "正在登入..."),
("Enable RDP session sharing", "啟用 RDP 工作階段共享"),
("Auto Login", "自動登入 (鎖定將在設定關閉後套用)"),
("Enable Direct IP Access", "允許 IP 直接存取"),
("Rename", "重新命名"),
("Space", "空白"),
("Create Desktop Shortcut", "建立桌面捷徑"),
("Change Path", "更改路徑"),
("Create Folder", "建立資料夾"),
("Please enter the folder name", "請輸入資料夾名稱"),
("Fix it", "修復"),
("Warning", "警告"),
("Login screen using Wayland is not supported", "不支援使用 Wayland 的登入畫面"),
("Reboot required", "需要重新啟動"),
("Unsupported display server ", "不支援顯示伺服器"),
("x11 expected", "預期 x11"),
("Port", "連接埠"),
("Settings", "設定"),
("Username", " 使用者名稱"),
("Invalid port", "連接埠無效"),
("Closed manually by the peer", "由對方手動關閉"),
("Enable remote configuration modification", "啟用遠端更改設定"),
("Run without install", "跳過安裝直接執行"),
("Always connected via relay", "一律透過轉送連線"),
("Always connect via relay", "一律透過轉送連線"),
("whitelist_tip", "只有白名單中的 IP 可以存取"),
("Login", "登入"),
("Logout", "登出"),
("Tags", "標籤"),
("Search ID", "搜尋 ID"),
("Current Wayland display server is not supported", "目前不支援 Wayland 顯示伺服器"),
("whitelist_sep", "使用逗號、分號、空白,或是換行來分隔"),
("Add ID", "新增 ID"),
("Add Tag", "新增標籤"),
("Unselect all tags", "取消選取所有標籤"),
("Network error", "網路錯誤"),
("Username missed", "缺少使用者名稱"),
("Password missed", "缺少密碼"),
("Wrong credentials", "提供的登入資訊有誤"),
("Edit Tag", "編輯標籤"),
("Unremember Password", "忘掉密碼"),
("Favorites", "收藏"),
("Add to Favorites", "加入到收藏"),
("Remove from Favorites", "從收藏中刪除"),
("Empty", "空空如也"),
("Invalid folder name", "資料夾名稱無效"),
("Socks5 Proxy", "Socks5 代理"),
("Hostname", "主機名稱"),
("Discovered", "已發現"),
("install_daemon_tip", "為了開機啟動,請安裝系統服務。"),
("Remote ID", "遠端 ID"),
("Paste", "貼上"),
("Paste here?", "貼上到這裡?"),
("Are you sure to close the connection?", "您確定要關閉連線嗎?"),
("Download new version", "下載新版本"),
("Touch mode", "觸控模式"),
("Mouse mode", "鼠標模式"),
("One-Finger Tap", "單指輕觸"),
("Left Mouse", "鼠標左鍵"),
("One-Long Tap", "單指長按"),
("Two-Finger Tap", "雙指輕觸"),
("Right Mouse", "鼠標右鍵"),
("One-Finger Move", "單指移動"),
("Double Tap & Move", "雙擊並移動"),
("Mouse Drag", "鼠標選中拖動"),
("Two-Finger vertically", "雙指垂直滑動"),
("Mouse Wheel", "鼠標滾輪"),
("Two-Finger Move", "雙指移動"),
("Canvas Move", "移動畫布"),
("Pinch to Zoom", "雙指縮放"),
("Canvas Zoom", "縮放畫布"),
("Reset canvas", "重置畫布"),
("No permission of file transfer", "無文件傳輸權限"),
("Note", "備註"),
("Connection", "連接"),
("Share Screen", "屏幕錄製"),
("CLOSE", "關閉"),
("OPEN", "開啟"),
("Chat", "聊天消息"),
("Total", "總計"),
("items", "個項目"),
("Selected", "已選擇"),
("Screen Capture", "屏幕錄製"),
("Input Control", "輸入控制"),
("File Transfer", "文件傳輸"),
("Audio Capture", "音頻錄製"),
("File Connection", "文件連接"),
("Screen Connection", "屏幕連接"),
("Do you accept?", "是否接受?"),
("Open System Setting", "打開系統設置"),
("How to get Android input permission?", "如何獲取安卓的輸入權限?"),
("android_input_permission_tip1", "獲取輸入權限後可以讓遠程設備通過鼠標控制這台安卓設備"),
("android_input_permission_tip2", "請在接下來的系統設置頁面裡,找到並進入 [已安裝的服務] 頁面,將 [RustDesk Input] 服務開啟"),
("android_new_connection_tip", "收到新的連接控制請求,對方想要控制你當前的設備"),
("android_service_will_start_tip", "開啟錄屏權限將自動開啟服務,允許其他設備向此設備請求建立連接。"),
("android_stop_service_tip", "關閉服務將自動關閉所有已建立的連接。"),
("android_version_audio_tip", "當前安卓版本不支持音頻錄製請升級至安卓10或更高。"),
("android_start_service_tip", "點擊 [啟動服務] 或打開 [屏幕錄製] 權限開啟手機屏幕共享服務。"),
("Account", "帳戶"),
("Quit", "退出"),
("doc_mac_permission", "https://rustdesk.com/docs/zh-tw/manual/mac/#啟用權限"),
("Help", "幫助"),
].iter().cloned().collect();
}

View File

@@ -28,3 +28,6 @@ pub mod cli;
#[cfg(not(any(target_os = "android", target_os = "ios")))]
mod port_forward;
mod lang;
#[cfg(windows)]
pub mod clipboard_file;

View File

@@ -16,14 +16,9 @@ fn main() {
#[cfg(not(any(target_os = "android", target_os = "ios", feature = "cli")))]
fn main() {
let mut args = Vec::new();
let mut i = 0;
for arg in std::env::args() {
if i > 0 {
args.push(arg);
}
i += 1;
}
// https://docs.rs/flexi_logger/latest/flexi_logger/error_info/index.html#write
let mut _async_logger_holder: Option<flexi_logger::LoggerHandle> = None;
let mut args: Vec<String> = std::env::args().skip(1).collect();
if args.len() > 0 && args[0] == "--version" {
println!("{}", crate::VERSION);
return;
@@ -43,19 +38,19 @@ fn main() {
}
}
use flexi_logger::*;
Logger::try_with_env_or_str("debug")
.map(|x| {
x.log_to_file(FileSpec::default().directory(path))
.format(opt_format)
.rotate(
Criterion::Age(Age::Day),
Naming::Timestamps,
Cleanup::KeepLogFiles(6),
)
.start()
.ok();
})
.ok();
if let Ok(x) = Logger::try_with_env_or_str("debug") {
_async_logger_holder = x
.log_to_file(FileSpec::default().directory(path))
.write_mode(WriteMode::Async)
.format(opt_format)
.rotate(
Criterion::Age(Age::Day),
Naming::Timestamps,
Cleanup::KeepLogFiles(6),
)
.start()
.ok();
}
}
if args.is_empty() {
std::thread::spawn(move || start_server(false, false));
@@ -89,8 +84,15 @@ fn main() {
return;
} else if args[0] == "--server" {
log::info!("start --server");
start_server(true, true);
return;
#[cfg(not(target_os = "macos"))]
{
start_server(true, true);
return;
}
#[cfg(target_os = "macos")]
{
std::thread::spawn(move || start_server(true, true));
}
} else if args[0] == "--import-config" {
if args.len() == 2 {
hbb_common::config::Config::import(&args[1]);

View File

@@ -240,10 +240,10 @@ pub fn start_os_service() {
if let Some(ps) = server.take().as_mut() {
allow_err!(ps.kill());
}
println!("Exit");
log::info!("Exit");
}
fn get_active_userid() -> String {
pub fn get_active_userid() -> String {
get_value_of_seat0(1)
}
@@ -585,27 +585,15 @@ pub fn get_pa_sources() -> Vec<(String, String)> {
}
pub fn lock_screen() {
std::thread::spawn(move || {
use crate::server::input_service::handle_key;
use hbb_common::message_proto::*;
let mut evt = KeyEvent {
down: true,
modifiers: vec![ControlKey::Meta.into()],
..Default::default()
};
evt.set_chr('l' as _);
handle_key(&evt);
evt.down = false;
handle_key(&evt);
});
std::process::Command::new("xdg-screensaver").arg("lock").spawn().ok();
}
pub fn toggle_privacy_mode(_v: bool) {
pub fn toggle_blank_screen(_v: bool) {
// https://unix.stackexchange.com/questions/17170/disable-keyboard-mouse-input-on-unix-under-x
}
pub fn block_input(_v: bool) {
//
pub fn block_input(_v: bool) -> bool {
true
}
pub fn is_installed() -> bool {

View File

@@ -16,10 +16,13 @@ use core_graphics::{
display::{kCGNullWindowID, kCGWindowListOptionOnScreenOnly, CGWindowListCopyWindowInfo},
window::{kCGWindowName, kCGWindowOwnerPID},
};
use hbb_common::{allow_err, bail, log};
use hbb_common::{bail, log};
use include_dir::{include_dir, Dir};
use objc::{class, msg_send, sel, sel_impl};
use scrap::{libc::c_void, quartz::ffi::*};
static PRIVILEGES_SCRIPTS_DIR: Dir =
include_dir!("$CARGO_MANIFEST_DIR/src/platform/privileges_scripts");
static mut LATEST_SEED: i32 = 0;
extern "C" {
@@ -98,6 +101,117 @@ pub fn is_can_screen_recording(prompt: bool) -> bool {
can_record_screen
}
pub fn is_installed_daemon(prompt: bool) -> bool {
let daemon = format!("{}_service.plist", crate::get_full_name());
let agent = format!("{}_server.plist", crate::get_full_name());
let agent_plist_file = format!("/Library/LaunchAgents/{}", agent);
if !prompt {
if !std::path::Path::new(&format!("/Library/LaunchDaemons/{}", daemon)).exists() {
return false;
}
if !std::path::Path::new(&agent_plist_file).exists() {
return false;
}
return true;
}
let install_script = PRIVILEGES_SCRIPTS_DIR.get_file("install.scpt").unwrap();
let install_script_body = install_script.contents_utf8().unwrap();
let daemon_plist = PRIVILEGES_SCRIPTS_DIR.get_file(&daemon).unwrap();
let daemon_plist_body = daemon_plist.contents_utf8().unwrap();
let agent_plist = PRIVILEGES_SCRIPTS_DIR.get_file(&agent).unwrap();
let agent_plist_body = agent_plist.contents_utf8().unwrap();
std::thread::spawn(move || {
match std::process::Command::new("osascript")
.arg("-e")
.arg(install_script_body)
.arg(daemon_plist_body)
.arg(agent_plist_body)
.arg(&get_active_username())
.status()
{
Err(e) => {
log::error!("run osascript failed: {}", e);
}
_ => {
let installed = std::path::Path::new(&agent_plist_file).exists();
log::info!("Agent file {} installed: {}", agent_plist_file, installed);
if installed {
log::info!("launch server");
std::process::Command::new("launchctl")
.args(&["load", "-w", &agent_plist_file])
.status()
.ok();
std::process::Command::new("sh")
.arg("-c")
.arg(&format!(
"sleep 0.5; open -n /Applications/{}.app",
crate::get_app_name(),
))
.spawn()
.ok();
quit_gui();
}
}
}
});
false
}
pub fn uninstall() -> bool {
// to-do: do together with win/linux about refactory start/stop service
if !is_installed_daemon(false) {
return false;
}
let script_file = PRIVILEGES_SCRIPTS_DIR.get_file("uninstall.scpt").unwrap();
let script_body = script_file.contents_utf8().unwrap();
std::thread::spawn(move || {
match std::process::Command::new("osascript")
.arg("-e")
.arg(script_body)
.status()
{
Err(e) => {
log::error!("run osascript failed: {}", e);
}
_ => {
let agent = format!("{}_server.plist", crate::get_full_name());
let agent_plist_file = format!("/Library/LaunchAgents/{}", agent);
let uninstalled = !std::path::Path::new(&agent_plist_file).exists();
log::info!(
"Agent file {} uninstalled: {}",
agent_plist_file,
uninstalled
);
if uninstalled {
crate::ipc::set_option("stop-service", "Y");
// leave ipc a little time
std::thread::sleep(std::time::Duration::from_millis(300));
std::process::Command::new("launchctl")
.args(&["remove", &format!("{}_server", crate::get_full_name())])
.status()
.ok();
std::process::Command::new("sh")
.arg("-c")
.arg(&format!(
"sleep 0.5; open /Applications/{}.app",
crate::get_app_name(),
))
.spawn()
.ok();
quit_gui();
}
}
}
});
true
}
pub fn get_cursor_pos() -> Option<(i32, i32)> {
unsafe {
let e = CGEventCreate(0 as _);
@@ -287,49 +401,127 @@ pub fn lock_screen() {
}
pub fn start_os_service() {
let mut server: Option<std::process::Child> = None;
let mut uid = "".to_owned();
loop {
let tmp = get_active_userid();
let mut start_new = false;
if tmp != uid && !tmp.is_empty() {
uid = tmp;
log::info!("active uid: {}", uid);
if let Some(ps) = server.as_mut() {
allow_err!(ps.kill());
let exe = std::env::current_exe().unwrap_or_default();
let tm0 = hbb_common::get_modified_time(&exe);
log::info!("{}", crate::username());
std::thread::spawn(move || loop {
loop {
std::thread::sleep(std::time::Duration::from_millis(300));
let now = hbb_common::get_modified_time(&exe);
if now != tm0 && now != std::time::UNIX_EPOCH {
// sleep a while to wait for resources file ready
std::thread::sleep(std::time::Duration::from_millis(300));
println!("{:?} updated, will restart", exe);
// this won't kill myself
std::process::Command::new("pkill")
.args(&["-f", &crate::get_app_name()])
.status()
.ok();
println!("The others killed");
// launchctl load/unload/start agent not work in daemon, show not priviledged.
// sudo launchctl asuser 501 open -n also not allowed.
std::process::Command::new("launchctl")
.args(&[
"asuser",
&get_active_userid(),
"open",
"-a",
&exe.to_str().unwrap_or(""),
"--args",
"--server",
])
.status()
.ok();
std::process::exit(0);
}
}
if let Some(ps) = server.as_mut() {
match ps.try_wait() {
Ok(Some(_)) => {
server = None;
start_new = true;
}
_ => {}
}
} else {
start_new = true;
}
if start_new {
match crate::run_me(vec!["--server"]) {
Ok(ps) => server = Some(ps),
Err(err) => {
log::error!("Failed to start server: {}", err);
}
}
}
std::thread::sleep(std::time::Duration::from_millis(super::SERVICE_INTERVAL));
});
if let Err(err) = crate::ipc::start("_service") {
log::error!("Failed to start ipc_service: {}", err);
}
/* // mouse/keyboard works in prelogin now with launchctl asuser.
// below can avoid multi-users logged in problem, but having its own below problem.
// Not find a good way to start --cm without root privilege (affect file transfer).
// one way is to start with `launchctl asuser <uid> open -n -a /Applications/RustDesk.app/ --args --cm`,
// this way --cm is started with the user privilege, but we will have problem to start another RustDesk.app
// with open in explorer.
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
let running = Arc::new(AtomicBool::new(true));
let r = running.clone();
let mut uid = "".to_owned();
let mut server: Option<std::process::Child> = None;
if let Err(err) = ctrlc::set_handler(move || {
r.store(false, Ordering::SeqCst);
}) {
println!("Failed to set Ctrl-C handler: {}", err);
}
while running.load(Ordering::SeqCst) {
let tmp = get_active_userid();
let mut start_new = false;
if tmp != uid && !tmp.is_empty() {
uid = tmp;
log::info!("active uid: {}", uid);
if let Some(ps) = server.as_mut() {
hbb_common::allow_err!(ps.kill());
}
}
if let Some(ps) = server.as_mut() {
match ps.try_wait() {
Ok(Some(_)) => {
server = None;
start_new = true;
}
_ => {}
}
} else {
start_new = true;
}
if start_new {
match run_as_user("--server") {
Ok(Some(ps)) => server = Some(ps),
Err(err) => {
log::error!("Failed to start server: {}", err);
}
_ => { /*no hapen*/ }
}
}
std::thread::sleep(std::time::Duration::from_millis(super::SERVICE_INTERVAL));
}
if let Some(ps) = server.take().as_mut() {
hbb_common::allow_err!(ps.kill());
}
log::info!("Exit");
*/
}
pub fn toggle_privacy_mode(_v: bool) {
pub fn toggle_blank_screen(_v: bool) {
// https://unix.stackexchange.com/questions/17115/disable-keyboard-mouse-temporarily
}
pub fn block_input(_v: bool) {
//
pub fn block_input(_v: bool) -> bool {
true
}
pub fn is_installed() -> bool {
true
if let Ok(p) = std::env::current_exe() {
return p
.to_str()
.unwrap_or_default()
.starts_with(&format!("/Applications/{}.app", crate::get_app_name()));
}
false
}
fn quit_gui() {
use cocoa::appkit::NSApp;
unsafe {
let () = msg_send!(NSApp(), terminate: nil);
};
}

View File

@@ -15,6 +15,7 @@ pub mod macos;
pub mod linux;
use hbb_common::{message_proto::CursorData, ResultType};
#[cfg(not(target_os = "macos"))]
const SERVICE_INTERVAL: u64 = 300;
pub fn is_xfce() -> bool {

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.carriez.RustDesk_server</string>
<key>LimitLoadToSessionType</key>
<array>
<string>LoginWindow</string>
<string>Aqua</string>
</array>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false />
<key>AfterInitialDemand</key>
<false />
</dict>
<key>RunAtLoad</key>
<true />
<key>ProgramArguments</key>
<array>
<string>/Applications/RustDesk.app/Contents/MacOS/rustdesk</string>
<string>--server</string>
</array>
<key>WorkingDirectory</key>
<string>/Applications/RustDesk.app/Contents/MacOS/</string>
</dict>
</plist>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.carriez.RustDesk_service</string>
<key>KeepAlive</key>
<true/>
<key>ProgramArguments</key>
<array>
<string>/Applications/RustDesk.app/Contents/MacOS/rustdesk</string>
<string>--service</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>WorkingDirectory</key>
<string>/Applications/RustDesk.app/Contents/MacOS/</string>
<key>StandardErrorPath</key>
<string>/tmp/rustdesk_service.err</string>
<key>StandardOutPath</key>
<string>/tmp/rustdesk_service.out</string>
</dict>
</plist>

View File

@@ -0,0 +1,16 @@
on run {daemon_file, agent_file, user}
set sh1 to "echo " & quoted form of daemon_file & " > /Library/LaunchDaemons/com.carriez.RustDesk_service.plist && chown root:wheel /Library/LaunchDaemons/com.carriez.RustDesk_service.plist;"
set sh2 to "echo " & quoted form of agent_file & " > /Library/LaunchAgents/com.carriez.RustDesk_server.plist && chown root:wheel /Library/LaunchAgents/com.carriez.RustDesk_server.plist;"
set sh3 to "cp -rf /Users/" & user & "/Library/Preferences/com.carriez.RustDesk/RustDesk.toml /var/root/Library/Preferences/com.carriez.RustDesk/;"
set sh4 to "cp -rf /Users/" & user & "/Library/Preferences/com.carriez.RustDesk/RustDesk2.toml /var/root/Library/Preferences/com.carriez.RustDesk/;"
set sh5 to "launchctl load -w /Library/LaunchDaemons/com.carriez.RustDesk_service.plist;"
set sh to sh1 & sh2 & sh3 & sh4 & sh5
do shell script sh with prompt "RustDesk want to install daemon and agent" with administrator privileges
end run

Some files were not shown because too many files have changed in this diff Show More