Compare commits

...

470 Commits
1.1.8 ... 1.1.9

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
rustdesk
1931cb8c7c https://github.com/rustdesk/rustdesk/issues/356 2022-01-05 23:50:13 +08:00
rustdesk
32c5437c5d more equal check in config 2022-01-05 21:12:07 +08:00
open-trade
1b61b77fbe more trans 2022-01-05 18:38:40 +08:00
open-trade
c0b6367137 sock5 gui part 2022-01-05 18:34:30 +08:00
open-trade
12ab22e048 bug fix 2022-01-05 17:10:12 +08:00
open-trade
7bde8a3713 remove some unnessary handler.msgbox 2022-01-05 16:53:37 +08:00
open-trade
9c55e1efc8 fix on msgbox 2022-01-05 16:48:09 +08:00
open-trade
b24e16d6c1 bug fix for msgbox, todo: test more for msgbox in file_transfer.tis 2022-01-05 16:32:45 +08:00
open-trade
6767dda246 refactor 2022-01-05 15:59:01 +08:00
open-trade
5f61c2442a bug fix 2022-01-05 15:47:04 +08:00
open-trade
5631ffac4c fix 2022-01-05 15:09:36 +08:00
open-trade
78097f4006 refactort 2022-01-05 14:38:38 +08:00
rustdesk
1d8cdb5e93 refactor target address 2022-01-05 13:21:14 +08:00
open-trade
3e590b8212 refactor to_socket_addr and dns_check 2022-01-04 19:49:44 +08:00
open-trade
533efd04d7 rename 2022-01-04 17:45:52 +08:00
open-trade
fb392b81cb rendezvous_mediator: ensure once one exits, the others also exit. 2022-01-04 17:44:06 +08:00
rustdesk
cbcad03bc6 fix style 2022-01-04 11:22:09 +08:00
RustDesk
2ec5f8fe7e Merge pull request #353 from fufesou/socks5
Socks5
2022-01-04 01:11:04 +08:00
fufesou
875570e040 refactor udp framed
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-01-04 00:44:50 +08:00
fufesou
6d506cbb64 socks5 support
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2022-01-03 22:50:43 +08:00
open-trade
b17bda9a55 resize tab 2022-01-03 16:31:13 +08:00
rustdesk
d6b56a2f35 refactor 2022-01-03 11:16:07 +08:00
rustdesk
64f181e4a1 fav 2022-01-03 00:24:36 +08:00
rustdesk
1552402907 working on fav 2022-01-02 21:56:04 +08:00
rustdesk
f0a6c706fa https://github.com/rustdesk/rustdesk/issues/275 2022-01-02 15:09:44 +08:00
rustdesk
042114ae37 refactor 2022-01-02 14:23:32 +08:00
rustdesk
241623c406 reload session list if alias change 2022-01-02 13:56:47 +08:00
rustdesk
40730cbbae ID search 2022-01-02 11:40:30 +08:00
rustdesk
cedc384ba1 working on search bar 2022-01-01 19:44:02 +08:00
rustdesk
15f3c36c5f header button hover bg 2022-01-01 17:18:10 +08:00
rustdesk
ee088a8ddf workaround for stupid sciter 2021-12-31 18:38:46 +08:00
open-trade
cb1818ab37 same width of session card 2021-12-30 16:31:33 +08:00
rustdesk
66af938858 https://sciter.com/forums/topic/menu-not-be-hidden-when-open-dialog-on-linux/ 2021-12-29 23:40:24 +08:00
open-trade
e26a838882 fix on log after upgrade 2021-12-29 19:01:36 +08:00
open-trade
e0bb25cbe5 upgrade vcpkg 2021-12-29 19:00:29 +08:00
open-trade
3491c79cbc get_local_option for ui style, todo: set_local_option 2021-12-29 17:53:36 +08:00
rustdesk
365fc90d8b refactor msgbox 2021-12-29 11:42:43 +08:00
rustdesk
8be7331cb6 add it 2021-12-29 00:48:58 +08:00
RustDesk
ea46d2493e Merge pull request #347 from ale-rinaldi/feature/italian-translation
Italian translation
2021-12-29 00:46:57 +08:00
Alessandro Rinaldi
1141be01f5 Italian translation 2021-12-28 17:42:50 +01:00
rustdesk
6c713f3135 reset AUDIO_ZERO_COUNT 2021-12-29 00:20:51 +08:00
RustDesk
3059ca061e Merge pull request #346 from Heap-Hop/master
optimize audio
2021-12-29 00:11:41 +08:00
rustdesk
2631c68b88 fix cm minimized not working sometimes 2021-12-29 00:05:52 +08:00
csf
f69f6bc8d4 optimize audio 2021-12-29 00:00:23 +08:00
open-trade
66e39b62a2 https://github.com/rustdesk/rustdesk/issues/223 2021-12-28 18:33:36 +08:00
RustDesk
993a419793 Merge pull request #344 from liyue201/dev
fix dependence
2021-12-28 14:27:22 +08:00
liyue
f1444049bf fix dependence 2021-12-28 14:18:37 +08:00
rustdesk
da629ec42c remove unused 2021-12-27 02:38:22 +08:00
rustdesk
7225c1fcf0 session list style and refactor 2021-12-27 02:28:25 +08:00
rustdesk
dbdff120bc move get_version_number to hbb_common 2021-12-27 00:24:57 +08:00
rustdesk
51f4f736bc update package 2021-12-26 15:34:10 +08:00
rustdesk
d4d90da196 https://github.com/rustdesk/rustdesk/issues/301 2021-12-25 22:31:42 +08:00
RustDesk
9903e9df9e Update README.md 2021-12-25 16:55:01 +08:00
rustdesk
af218dbc83 internationalization 2021-12-25 16:45:22 +08:00
rustdesk
b3e3f6151d get last env instead of the first one avoid problem when just switch from wayland to xorg 2021-12-25 01:07:41 +08:00
rustdesk
3d39d9c27c https://github.com/rustdesk/rustdesk/issues/328 2021-12-25 00:18:54 +08:00
rustdesk
589177fc94 Merge branch 'master' of github.com-rustdesk:rustdesk/rustdesk 2021-12-24 19:13:38 +08:00
rustdesk
4703a7d332 https://github.com/rustdesk/rustdesk/issues/327 2021-12-24 19:13:11 +08:00
rustdesk
8d90c5a93b change codec cpu usage to 0 2021-12-24 12:40:47 +08:00
rustdesk
885d8a4586 https://github.com/rustdesk/rustdesk/issues/332 2021-12-24 00:27:27 +08:00
rustdesk
0e8fc4a815 65515 -> Meta(win) on Linux 2021-12-23 23:03:43 +08:00
rustdesk
96afb88518 change line-through style from grey to red 2021-12-23 21:41:53 +08:00
open-trade
a30aaebc72 fix clipboard crash and https://github.com/rustdesk/rustdesk/issues/302 2021-12-23 17:44:44 +08:00
rustdesk
252d3cb797 refactor 2021-12-23 11:11:48 +08:00
open-trade
26a4b1f3eb comment on bias 2021-12-22 16:51:33 +08:00
open-trade
dc724a30e7 https://github.com/rustdesk/rustdesk/issues/298 2021-12-22 14:56:10 +08:00
open-trade
334c94ceb3 https://github.com/rustdesk/rustdesk/issues/210 2021-12-22 14:28:08 +08:00
RustDesk
b6feaa695f Merge pull request #338 from Heap-Hop/master
adjust #[warn(unreachable_code)] position
2021-12-21 17:45:54 +08:00
csf
5f190297a9 adjust #[warn(unreachable_code)] position 2021-12-21 16:35:18 +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
rustdesk
362b5594a2 nothing big 2021-12-21 00:11:12 +08:00
RustDesk
b9d8de1ec1 Merge pull request #335 from fufesou/fix_video_image_tearing
Fix video image tearing
2021-12-20 23:15:07 +08:00
fufesou
8a6b33b841 image tearing fixed
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2021-12-20 22:21:15 +08:00
fufesou
3ffd8ac146 add video channel
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2021-12-20 17:19:56 +08:00
RustDesk
07ea52d620 Merge pull request #331 from fufesou/master
add error log for graphics failure
2021-12-20 13:26:56 +08:00
fufesou
4cb967251b add error log for graphics failure
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2021-12-10 22:36:34 +08:00
rustdesk
29905608b5 fix on NL 2021-12-10 00:46:23 +08:00
RustDesk
36db9f65cd Merge pull request #326 from jeroenhd/master
Add Dutch translation for README
2021-12-10 00:12:16 +08:00
jeroenhd
91445da094 Add hyperlinks to Dutch translation
Signed-off-by: jeroenhd <git@jeroenhd.nl>
2021-12-08 02:34:13 +01:00
jeroenhd
083d6c591a Add Dutch translation of the README
Signed-off-by: jeroenhd <git@jeroenhd.nl>
2021-12-08 02:29:55 +01:00
RustDesk
e352ea67f4 Merge pull request #320 from ioridev/master
README translated to Japanese (README-JP.md)
2021-12-01 18:16:56 +08:00
iori
4103ab70a7 Update README-JP 2021-12-01 17:11:06 +09:00
iori
fd9d6db2ed Create README-JP.md 2021-12-01 17:08:10 +09:00
RustDesk
d0b15fbd2a Merge pull request #316 from josephjosedev/master
Update README-ML.md
2021-11-27 13:19:48 +08:00
Joseph Jose
7c42c04b23 Update README-ML.md
updated
2021-11-27 10:42:38 +05:30
Joseph Jose
81e4998a37 Update README-ML.md 2021-11-26 22:50:40 +05:30
RustDesk
1ab5bb0a2e Update README.md 2021-11-27 01:05:29 +08:00
RustDesk
0f39626782 Merge pull request #315 from varghesejose2020/master
README translated to MALAYALAM (README-ML.md)
2021-11-27 01:00:58 +08:00
Varghese Jose
dc2edcec5d Update README-ML.md 2021-11-26 13:55:56 +05:30
Varghese Jose
3198236a8c Update README-ML.md
updated
2021-11-26 13:54:53 +05:30
Varghese Jose
e044212eb6 Update README-ML.md
updated
2021-11-26 13:50:20 +05:30
Varghese Jose
33e8f2aa85 Update README-ML.md
upd
2021-11-26 13:45:44 +05:30
Varghese Jose
031ca4e50c Update README-ML.md 2021-11-26 13:40:30 +05:30
Varghese Jose
73d0da726d Update README-ML.md 2021-11-26 13:38:28 +05:30
Varghese Jose
5c97f5dce5 Create README-ML.md
MALAYALAM added to README
2021-11-26 13:22:44 +05:30
RustDesk
8d5aa731a1 Merge pull request #306 from mingxingren/master
Delete a line of typos
2021-11-23 20:28:49 +08:00
mamingkun
e8c5a63986 1. Delete a line of duplicate code 2021-11-23 20:07:25 +08:00
mingxingren
46fe37015f Merge pull request #1 from rustdesk/master
Update from master
2021-11-23 20:06:07 +08:00
rustdesk
b79f086df5 suomi -> Suomi 2021-11-22 01:42:53 +08:00
rustdesk
6afb6aaff2 Fix on FI 2021-11-22 01:40:45 +08:00
rustdesk
5a1ab37171 FI 2021-11-22 01:38:58 +08:00
RustDesk
5e0bf8f5a9 Merge pull request #304 from fufesou/master
resolution changed, no need to reconnect
2021-11-21 23:10:00 +08:00
cxl
7964afeb84 resolution changed, no need to reconnect
Signed-off-by: cxl <xiaolong.chen@nazhiai.com>
2021-11-21 22:45:12 +08:00
RustDesk
3759347d47 Merge pull request #294 from hatamiarash7/master
Spell & Format
2021-11-15 00:12:59 +08:00
Arash Hatami
2758f6b7d5 Fix misspelled words 2021-11-14 19:01:34 +03:30
Arash Hatami
70a4ee4318 Merge branch 'rustdesk:master' into master 2021-11-14 18:52:51 +03:30
Arash Hatami
7f13edd14a Fix misspelled words 2021-11-14 18:52:05 +03:30
Arash Hatami
96208e9fef git ignore .vscode 2021-11-14 18:36:03 +03:30
rustdesk
e6bd5b0698 pb in version 2021-11-07 10:18:10 +08:00
rustdesk
231231e51f refactor 2021-10-30 14:03:33 +08:00
RustDesk
247ea5fed3 Merge pull request #279 from cc-morning/master
Clipboard service optimization and bug fixes
2021-10-30 12:50:39 +08:00
cc-morning
0cf2db9239 Clipboard listener lifecycle follows service 2021-10-27 20:02:17 +08:00
cc-morning
318e3cbd7d Code Format 2021-10-26 16:59:31 +08:00
cc-morning
5164f76919 Fix lost clipboard content again 2021-10-25 16:25:23 +08:00
cc-morning
972ec8d79d Fix missing clipboard content 2021-10-24 23:47:02 +08:00
RustDesk
516904551c Merge pull request #268 from cc-morning/master
Optimize clipboard change listener
2021-10-24 00:45:52 +08:00
cc-morning
1bf80e3dd6 Optimize clipboard change listener 2021-10-22 16:02:01 +08:00
RustDesk
8f22273759 Update ci.yml 2021-10-21 10:00:53 +08:00
rustdesk
1ddd5203e5 fix overflow 2021-10-20 17:03:48 +08:00
RustDesk
62d2c0fb6d Merge pull request #265 from dannkunt/master
Fix buiding trough docker
2021-10-20 14:24:44 +08:00
dannkunt
0db250f02a Delete this code
This code is unnessesary and bug casing with previous fix
2021-10-20 08:38:36 +03:00
dannkunt
8be912a8cf Add user privelege
To fix this
2021-10-20 08:35:52 +03:00
RustDesk
03f913e49d Merge pull request #256 from starccy/multiple-selection
Transfer multiple files
2021-10-19 23:36:15 +08:00
Starccy
fb126164ef use multiple jobs to delete 2021-10-19 21:52:59 +08:00
Starccy
eea85b9b5a send & receive multiple files 2021-10-17 21:27:10 +08:00
RustDesk
b16b2bc1b4 Merge pull request #253 from palfrey/ci
CI setup
2021-10-12 23:47:09 +08:00
Tom Parker-Shemilt
55d21ab151 Just build the tests 2021-10-11 22:35:31 +01:00
Tom Parker-Shemilt
d25e17317d Skip tests for the moment 2021-10-11 22:09:13 +01:00
Tom Parker-Shemilt
7a7cca7e45 Add rust cache 2021-10-11 21:48:56 +01:00
Tom Parker-Shemilt
0ef4246360 Set vcpkg commit id 2021-10-11 21:40:06 +01:00
Tom Parker-Shemilt
686e495171 Initial CI setup 2021-10-11 21:36:45 +01:00
rustdesk
c0db2e6da4 refactor and fix 2021-10-08 00:16:10 +08:00
rustdesk
c0459b8f94 move change wayland to linux section 2021-10-02 08:51:56 +08:00
rustdesk
678a3d2d28 README format bug 2021-10-02 08:48:41 +08:00
Arash Hatami
2894a5ab7b Format rust files 2021-10-01 22:48:04 +03:30
RustDesk
2efd0e61b4 Merge pull request #243 from hatamiarash7/master
Update Readme & Other Markdown files
2021-10-01 17:05:17 +08:00
Arash Hatami
18b1646cd4 Fix Markdown syntax in all MD files 2021-10-01 12:28:08 +03:30
Arash Hatami
66cdbbacd0 Update README.md
- Remove extra space after `git clone` command
- Add `VCPKG_ROOT` env before `cargo run` command
2021-10-01 12:10:53 +03:30
rustdesk
aaba4c144c fix README 2021-09-30 12:07:18 +08:00
RustDesk
2d5758e880 Update README.md 2021-09-30 12:01:45 +08:00
RustDesk
b20ec86fac Merge pull request #237 from kerlw/master
Add some optimization options for Chinese developer in README-ZH.md.
2021-09-26 10:10:57 +08:00
kerl.d.w
1df5234eea Add some optimization options for Chinese developer in README-ZH.md. 2021-09-26 09:51:40 +08:00
RustDesk
1b8dbbeac9 https://github.com/rustdesk/rustdesk/issues/226 2021-09-12 17:53:45 +08:00
RustDesk
c5f1222476 Merge pull request #224 from desertstsung/addfun/relogin_xorg
add function
2021-09-09 18:24:58 +08:00
desertstsung
1009eabdfe add function
relogin required if current is wayland
2021-09-09 15:07:09 +08:00
open-trade
8138a661a6 new fall back to gdi 2021-09-07 19:03:59 +08:00
RustDesk
d369955790 Merge pull request #221 from desertstsung/ui/labelchange
ui label change
2021-09-06 20:59:12 +08:00
desertstsung
0afca9d1ea ui label change:
src/ui/index.tis#L547:Fix it -> Disable it
2021-09-06 20:41:37 +08:00
rustdesk
0325500ebf refactor 2021-08-29 19:26:33 +08:00
RustDesk
b0dfd777fb Update Cargo.toml 2021-08-24 22:18:39 +08:00
148 changed files with 19945 additions and 3428 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",
]

181
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,181 @@
name: CI
# env:
# MIN_SUPPORTED_RUST_VERSION: "1.46.0"
# CICD_INTERMEDIATES_DIR: "_cicd-intermediates"
on:
workflow_dispatch:
pull_request:
push:
branches:
- master
tags:
- '*'
jobs:
# ensure_cargo_fmt:
# name: Ensure 'cargo fmt' has been run
# runs-on: ubuntu-20.04
# steps:
# - uses: actions-rs/toolchain@v1
# with:
# toolchain: stable
# default: true
# profile: minimal
# components: rustfmt
# - uses: actions/checkout@v2
# - run: cargo fmt -- --check
# min_version:
# name: Minimum supported rust version
# runs-on: ubuntu-20.04
# steps:
# - name: Checkout source code
# uses: actions/checkout@v2
# - name: Install rust toolchain (v${{ env.MIN_SUPPORTED_RUST_VERSION }})
# uses: actions-rs/toolchain@v1
# with:
# toolchain: ${{ env.MIN_SUPPORTED_RUST_VERSION }}
# default: true
# profile: minimal # minimal component installation (ie, no documentation)
# components: clippy
# - name: Run clippy (on minimum supported rust version to prevent warnings we can't fix)
# uses: actions-rs/cargo@v1
# with:
# command: clippy
# args: --locked --all-targets --all-features -- --allow clippy::unknown_clippy_lints
# - name: Run tests
# uses: actions-rs/cargo@v1
# with:
# command: test
# args: --locked
build:
name: ${{ matrix.job.target }} (${{ matrix.job.os }})
runs-on: ${{ matrix.job.os }}
strategy:
fail-fast: false
matrix:
job:
# - { target: aarch64-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
# - { target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true }
# - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true }
# - { target: i686-pc-windows-msvc , os: windows-2019 }
# - { target: i686-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
# - { target: i686-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
# - { target: x86_64-apple-darwin , os: macos-10.15 }
# - { target: x86_64-pc-windows-gnu , os: windows-2019 }
# - { target: x86_64-pc-windows-msvc , os: windows-2019 }
- { target: x86_64-unknown-linux-gnu , os: ubuntu-20.04 }
# - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
steps:
- name: Checkout source code
uses: actions/checkout@v2
- name: Install prerequisites
shell: bash
run: |
case ${{ matrix.job.target }} in
x86_64-unknown-linux-gnu) sudo apt-get -y update ; 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 ;;
# arm-unknown-linux-*) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;;
# aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;;
esac
- name: Restore from cache and install vcpkg
uses: lukka/run-vcpkg@v7
with:
setupOnly: true
vcpkgGitCommitId: '1d4128f08e30cec31b94500840c7eca8ebc579cb'
- name: Install vcpkg dependencies
run: |
$VCPKG_ROOT/vcpkg install libvpx libyuv opus
shell: bash
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: ${{ matrix.job.target }}
override: true
profile: minimal # minimal component installation (ie, no documentation)
- name: Show version information (Rust, cargo, GCC)
shell: bash
run: |
gcc --version || true
rustup -V
rustup toolchain list
rustup default
cargo -V
rustc -V
- uses: Swatinem/rust-cache@v1
- name: Build
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.job.use-cross }}
command: build
args: --locked --release --target=${{ matrix.job.target }}
# - name: Strip debug information from executable
# id: strip
# shell: bash
# run: |
# # Figure out suffix of binary
# EXE_suffix=""
# case ${{ matrix.job.target }} in
# *-pc-windows-*) EXE_suffix=".exe" ;;
# esac;
# # Figure out what strip tool to use if any
# STRIP="strip"
# case ${{ matrix.job.target }} in
# arm-unknown-linux-*) STRIP="arm-linux-gnueabihf-strip" ;;
# aarch64-unknown-linux-gnu) STRIP="aarch64-linux-gnu-strip" ;;
# *-pc-windows-msvc) STRIP="" ;;
# esac;
# # Setup paths
# BIN_DIR="${{ env.CICD_INTERMEDIATES_DIR }}/stripped-release-bin/"
# mkdir -p "${BIN_DIR}"
# BIN_NAME="${{ env.PROJECT_NAME }}${EXE_suffix}"
# BIN_PATH="${BIN_DIR}/${BIN_NAME}"
# # Copy the release build binary to the result location
# cp "target/${{ matrix.job.target }}/release/${BIN_NAME}" "${BIN_DIR}"
# # Also strip if possible
# if [ -n "${STRIP}" ]; then
# "${STRIP}" "${BIN_PATH}"
# fi
# # Let subsequent steps know where to find the (stripped) bin
# echo ::set-output name=BIN_PATH::${BIN_PATH}
# echo ::set-output name=BIN_NAME::${BIN_NAME}
- name: Set testing options
id: test-options
shell: bash
run: |
# test only library unit tests and binary for arm-type targets
unset CARGO_TEST_OPTIONS
unset CARGO_TEST_OPTIONS ; case ${{ matrix.job.target }} in arm-* | aarch64-*) CARGO_TEST_OPTIONS="--lib --bin ${PROJECT_NAME}" ;; esac;
echo ::set-output name=CARGO_TEST_OPTIONS::${CARGO_TEST_OPTIONS}
- name: Build tests
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.job.use-cross }}
command: build
args: --locked --tests --target=${{ matrix.job.target }}
# - name: Run tests
# uses: actions-rs/cargo@v1
# with:
# use-cross: ${{ matrix.job.use-cross }}
# command: test
# args: --locked --target=${{ matrix.job.target }} ${{ steps.test-options.outputs.CARGO_TEST_OPTIONS}}

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

3
.gitignore vendored
View File

@@ -1,4 +1,5 @@
/target
.vscode
.idea
.DS_Store
src/ui/inline.rs
@@ -6,3 +7,5 @@ extractor
__pycache__
src/version.rs
*dmg
sciter.dll
**pdb

BIN
128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

BIN
128x128@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

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

@@ -3,7 +3,6 @@
RustDesk welcomes contribution from everyone. Here are the guidelines if you are
thinking of helping us:
## Contributions
Contributions to RustDesk or its dependencies should be made in the form of GitHub
@@ -23,7 +22,7 @@ efforts from contributors on the same issue.
master you may be asked to rebase your changes.
- Commits should be as small as possible, while ensuring that each commit is
correct independently (i.e., each commit should compile and pass tests).
correct independently (i.e., each commit should compile and pass tests).
- Commits should be accompanied by a Developer Certificate of Origin
(http://developercertificate.org) sign-off, which indicates that you (and
@@ -40,10 +39,8 @@ 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
RustDesk contributors frequent the [Discord](https://discord.gg/nDceKgxnkV).

2711
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.6"
version = "1.1.9"
authors = ["rustdesk <info@rustdesk.com>"]
edition = "2018"
edition = "2021"
build= "build.rs"
description = "A remote control software."
@@ -17,33 +17,38 @@ default = ["use_dasp"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
whoami = "1.1"
whoami = "1.2"
scrap = { path = "libs/scrap" }
hbb_common = { path = "libs/hbb_common" }
enigo = { path = "libs/enigo" }
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"
cfg-if = "1.0"
lazy_static = "1.4"
sha2 = "0.9"
sha2 = "0.10"
repng = "0.2"
libc = "0.2"
parity-tokio-ipc = { git = "https://github.com/open-trade/parity-tokio-ipc" }
flexi_logger = "0.17"
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.8", optional = true }
rubato = { version = "0.12", optional = true }
samplerate = { version = "0.2", optional = true }
async-trait = "0.1"
crc32fast = "1.2"
uuid = { version = "0.8", features = ["v4"] }
clap = "2.33"
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"
@@ -51,12 +56,15 @@ mac_address = "1.1"
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/open-trade/systray-rs" }
systray = { git = "https://github.com/liyue201/systray-rs" }
winapi = { version = "0.3", features = ["winuser"] }
winreg = "0.7"
windows-service = { git = 'https://github.com/mullvad/windows-service-rs.git' }
winreg = "0.10"
windows-service = "0.4"
[target.'cfg(target_os = "macos")'.dependencies]
objc = "0.2"
@@ -64,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.16"
libpulse-binding = "2.16"
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 = "3.2"
[target.'cfg(target_os = "android")'.dependencies]
android_logger = "0.9"
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"
@@ -101,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

@@ -7,7 +7,7 @@ RUN git clone https://github.com/microsoft/vcpkg && cd vcpkg && git checkout 134
RUN /vcpkg/bootstrap-vcpkg.sh -disableMetrics
RUN /vcpkg/vcpkg --disable-metrics install libvpx libyuv opus
RUN groupadd -r user && useradd -r -g user user --home /home/user && mkdir -p /home/user && chown user /home/user
RUN groupadd -r user && useradd -r -g user user --home /home/user && mkdir -p /home/user && chown user /home/user && echo "user ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/user
WORKDIR /home/user
RUN wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
USER user

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-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,61 +13,67 @@ 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. Es ist eine gute Alternative zu Programmen wie TeamViewer und AnyDesk! 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.
[**PROGRAMM DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
## 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.
| Standort | Serverart | Spezifikationen | Kommentare |
| --------- | ------------- | ------------------ | ---------------------------------------- |
| Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | |
| Singapore | Vultr | 1 VCPU / 1GB RAM | |
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
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 |
| --------- | ------------- | ------------------ | ---------- |
| Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM | |
| Singapore | Vultr | 1 VCPU / 1GB RAM | |
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
## 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) |
[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)
## Die groben Schritte zum Kompilieren
* Bereite deine Rust Entwicklungsumgebung und C++ Entwicklungsumgebung vor
* Installiere [vcpkg](https://github.com/microsoft/vcpkg) und füge die `VCPKG_ROOT` Systemumgebungsvariable hinzu
- Bereite deine Rust Entwicklungsumgebung und C++ Entwicklungsumgebung vor
- Windows: `vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static`
- Linux/MacOS: `vcpkg install libvpx libyuv opus`
- Installiere [vcpkg](https://github.com/microsoft/vcpkg) und füge die `VCPKG_ROOT` Systemumgebungsvariable hinzu
* Nutze `cargo run`
- Windows: `vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static`
- Linux/MacOS: `vcpkg install libvpx libyuv opus`
- Nutze `cargo run`
## Kompilieren auf 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 installieren
```sh
git clone https://github.com/microsoft/vcpkg
git clone https://github.com/microsoft/vcpkg
cd vcpkg
git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82
git checkout 2021.12.01
cd ..
vcpkg/bootstrap-vcpkg.sh
export VCPKG_ROOT=$HOME/vcpkg
@@ -75,6 +81,7 @@ vcpkg/vcpkg install libvpx libyuv opus
```
### libvpx reparieren (Für Fedora)
```sh
cd vcpkg/buildtrees/libvpx/src
cd *
@@ -87,6 +94,7 @@ cd
```
### Kompilieren
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
@@ -98,6 +106,10 @@ mv libsciter-gtk.so target/debug
cargo run
```
### Ändere Wayland zu X11 (Xorg)
RustDesk unterstützt "Wayland" nicht. Siehe [hier](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) um Xorg als Standard GNOME Session zu nutzen.
## Auf Docker Kompilieren
Beginne damit das Repository zu klonen und den Docker Container zu bauen:
@@ -109,11 +121,12 @@ docker build -t "rustdesk-builder" .
```
Jedes Mal, wenn du das Programm Kompilieren musst, nutze diesen Befehl:
```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
```
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
@@ -125,10 +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.
### Ändere Wayland zu X11 (Xorg)
RustDesk unterstützt "Wayland" nicht. Siehe [hier](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) um Xorg als Standard GNOME Session zu nutzen.
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
@@ -142,10 +152,11 @@ RustDesk unterstützt "Wayland" nicht. Siehe [hier](https://docs.fedoraproject.o
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: Plattformspezifischer Code
## 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/113112990-65e2fd80-923c-11eb-840e-349b4d6e340d.png)
![image](https://user-images.githubusercontent.com/71636191/135385039-38fdbd72-379a-422d-b97f-33df71fb1cec.png)

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-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,77 +13,86 @@ 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. Gran alternativa a TeamViewer o AnyDesk. 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.
RustDesk agradece la contribución de todo el mundo. Ve [`CONTRIBUTING.md`](CONTRIBUTING.md) para ayuda inicial.
[**DESCARGA DE BINARIOS**](https://github.com/rustdesk/rustdesk/releases)
## Servidores gratis de uso público
A continuación se muestran los servidores que está utilizando de forma gratuita, puede cambiar en algún momento. Si no estás cerca de uno de ellos, tu red puede ser lenta.
- Seoul, AWS lightsail, 1 VCPU/0.5G RAM
- Singapore, Vultr, 1 VCPU/1G RAM
- Dallas, Vultr, 1 VCPU/1G RAM
## Dependencies
La versión Desktop usa [sciter](https://sciter.com/) para GUI, por favor bajate la librería sciter tu mismo..
La versión Desktop usa [sciter](https://sciter.com/) para GUI, por favor bajate la librería sciter tu mismo..
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[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)
## Pasos para compilar desde el inicio
* Prepara el entono de desarrollode Rust y el entorno de compilación de C++ y Rust.
* Instala [vcpkg](https://github.com/microsoft/vcpkg), y configura la variable de entono `VCPKG_ROOT` correctamente.
- Prepara el entono de desarrollode Rust y el entorno de compilación de C++ y Rust.
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
- Linux/Osx: vcpkg install libvpx libyuv opus
* run `cargo run`
- Instala [vcpkg](https://github.com/microsoft/vcpkg), y configura la variable de entono `VCPKG_ROOT` correctamente.
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
- Linux/Osx: vcpkg install libvpx libyuv opus
- run `cargo run`
## Como compilar en 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
```
### Install vcpkg
```sh
git clone https://github.com/microsoft/vcpkg
cd vcpkg
git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82
cd ..
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
```
### Soluciona libvpx (For 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
```
### Soluciona libvpx (For 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
```
### Compila
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
@@ -95,6 +104,10 @@ mv libsciter-gtk.so target/debug
cargo run
```
### Cambia Wayland a X11 (Xorg)
RustDesk no soporta Wayland. Comprueba [aquí](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) para configurar Xorg en la sesión por defecto de GNOME.
## Como compilar con Docker
Empieza clonando el repositorio y compilando el contenedor de docker:
@@ -104,6 +117,7 @@ git clone https://github.com/rustdesk/rustdesk
cd rustdesk
docker build -t "rustdesk-builder" .
```
Entonces, cada vez que necesites compilar una modificación, ejecuta el siguiente comando:
```sh
@@ -124,9 +138,6 @@ target/release/rustdesk
Por favor, asegurate de que estás ejecutando estos comandos desde la raíz del repositorio de RustDesk, de lo contrario la aplicación puede ser incapaz de encontrar los recursos necesarios. También hay que tener en cuenta que otros subcomandos de carga como `install` o `run` no estan actualmente soportados via este metodo y podrían requerir ser instalados dentro del contenedor y no en el host.
### Cambia Wayland a X11 (Xorg)
RustDesk no soporta Wayland. Comprueba [aquí](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) para configurar Xorg en la sesión por defecto de GNOME.
## Estructura de archivos
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, configuración, tcp/udp wrapper, protobuf, fs funciones para transferencia de ficheros, y alguna función de utilidad.
@@ -139,10 +150,11 @@ RustDesk no soporta Wayland. Comprueba [aquí](https://docs.fedoraproject.org/en
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: código específico de cada plataforma
## Captura de pantalla
![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/113112990-65e2fd80-923c-11eb-840e-349b4d6e340d.png)
![image](https://user-images.githubusercontent.com/71636191/135385039-38fdbd72-379a-422d-b97f-33df71fb1cec.png)

161
README-FI.md Normal file
View File

@@ -0,0 +1,161 @@
<p align="center">
<img src="logo-header.svg" alt="RustDesk - Etätyöpöytäsi"><br>
<a href="#free-public-servers">Palvelimet</a> •
<a href="#raw-steps-to-build">Rakenna</a> •
<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-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>
Juttele meidän kanssa: [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)
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.
[**BINAARILATAUS**](https://github.com/rustdesk/rustdesk/releases)
## Vapaita julkisia palvelimia
Alla on palvelimia, joita voit käyttää ilmaiseksi, ne saattavat muuttua ajan mittaan. Jos et ole lähellä yhtä näistä, verkkosi voi olla hidas.
| Sijainti | Myyjä | Määrittely |
| --------- | ------------- | ------------------ |
| Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM |
| Singapore | Vultr | 1 VCPU / 1GB RAM |
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
## Riippuvuudet
Desktop-versiot käyttävät [sciter](https://sciter.com/) graafisena käyttöliittymänä, lataa sciter-dynaaminen kirjasto itsellesi.
[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)
## Rakentamisaskeleet harppoen
- Valmistele Rust-kehitysympäristö ja C++-rakentamisympäristö
- Asenna [vcpkg](https://github.com/microsoft/vcpkg), ja aseta `VCPKG_ROOT`-ympäristömuuttuja oikein
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
- Linux/MacOS: vcpkg install libvpx libyuv opus
- aja `cargo run`
## Kuinka rakentaa Linuxissa
### 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
```
### Asenna 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
```
### Korjaa libvpx (Fedora-linux-versiota varten)
```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
```
### Rakenna
```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
```
### Vaihda Wayland-ympäristö X11 (Xorg)-ympäristöön
RustDesk ei tue Waylandia. Tarkista [tämä](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) asettamaan Xorg oletus GNOME-istuntona.
## Kuinka rakennetaan Dockerin kanssa
Aloita kloonaamalla tietovarasto ja rakentamalla docker-säiliö:
```sh
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
docker build -t "rustdesk-builder" .
```
Sitten, joka kerta kun sinun on rakennettava sovellus, aja seuraava komento:
```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
```
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
```
Tai, jos olet suorittamassa jakeluversion suoritettavaa tiedostoa:
```sh
target/release/rustdesk
```
Varmista, että suoritat näitä komentoja RustDesktop-tietovaraston juurihakemistossa, muutoin sovellus ei ehkä löydä vaadittuja resursseja. Huomaa myös, että muita cargo-alikomentoja kuten `install` tai `run` ei nykyisin tueta tässä menetelmässä, koska ne asentavat tai suorittavat ohjelman säiliön sisällä eikä isäntäohjelman sisällä.
## Tiedostorakenne
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, config, tcp/udp wrapper, protobuf, fs-funktiot tiedostosiirtoon, ja jotkut muut apuohjelmafunktiot
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: näyttökaappaukset
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: platform specific keyboard/mouse control
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: Graafinen käyttöliittymä
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: audio/clipboard/input/video services, and network connections
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: start a peer connection
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Communicate with [rustdesk-server](https://github.com/rustdesk/rustdesk-server), wait for remote direct (TCP hole punching) or relayed connection
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platform specific code
## Tilannekuvat
![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="#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-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,14 +13,16 @@ 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. Une excellente alternative à TeamViewer et AnyDesk ! 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.
RustDesk accueille les contributions de tout le monde. Voir [`CONTRIBUTING.md`](CONTRIBUTING.md) pour plus d'informations.
[**TÉLÉCHARGEMENT BINAIRE**](https://github.com/rustdesk/rustdesk/releases)
## Serveurs publics libres
Ci-dessous se trouvent les serveurs que vous utilisez gratuitement, cela peut changer au fil du temps. Si vous n'êtes pas proche de l'un d'entre eux, votre réseau peut être lent.
- Séoul, AWS lightsail, 1 VCPU/0.5G RAM
- Singapour, Vultr, 1 VCPU/1G RAM
- Dallas, Vultr, 1 VCPU/1G RAM
@@ -29,42 +31,47 @@ Ci-dessous se trouvent les serveurs que vous utilisez gratuitement, cela peut ch
Les versions de bureau utilisent [sciter](https://sciter.com/) pour l'interface graphique, veuillez télécharger la bibliothèque dynamique sciter vous-même.
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[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)
## Étapes brutes de la compilation/build
* Préparez votre environnement de développement Rust et votre environnement de compilation C++.
* Installez [vcpkg](https://github.com/microsoft/vcpkg), et définissez correctement la variable d'environnement `VCPKG_ROOT`.
- Préparez votre environnement de développement Rust et votre environnement de compilation C++.
- Windows : vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
- Linux/Osx : vcpkg install libvpx libyuv opus
* Exécuter `cargo run`
- Installez [vcpkg](https://github.com/microsoft/vcpkg), et définissez correctement la variable d'environnement `VCPKG_ROOT`.
- Windows : vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
- Linux/Osx : vcpkg install libvpx libyuv opus
- Exécuter `cargo run`
## Comment compiler/build sous 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
```
### Installer vcpkg
```sh
git clone https://github.com/microsoft/vcpkg
git clone https://github.com/microsoft/vcpkg
cd vcpkg
git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82
git checkout 2021.12.01
cd ..
vcpkg/bootstrap-vcpkg.sh
export VCPKG_ROOT=$HOME/vcpkg
@@ -72,6 +79,7 @@ vcpkg/vcpkg install libvpx libyuv opus
```
### Corriger libvpx (Pour Fedora)
```sh
cd vcpkg/buildtrees/libvpx/src
cd *
@@ -84,6 +92,7 @@ cd
```
### Construire
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
@@ -95,6 +104,10 @@ mv libsciter-gtk.so target/debug
Exécution du cargo
```
### Changer Wayland en X11 (Xorg)
RustDesk ne supporte pas Wayland. Lisez [cela](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) pour configurer Xorg comme la session GNOME par défaut.
## Comment construire avec Docker
Commencez par cloner le dépôt et construire le conteneur Docker :
@@ -105,44 +118,43 @@ 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
```
Ou, si vous exécutez un exécutable provenant d'une release :
```sh
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.
### Changer Wayland en X11 (Xorg)
RustDesk ne supporte pas Wayland. Lisez [cela](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) pour configurer Xorg comme la session GNOME par défaut.
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.
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)** : code spécifique à la plateforme
## Images
![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/113112990-65e2fd80-923c-11eb-840e-349b4d6e340d.png)
![image](https://user-images.githubusercontent.com/71636191/135385039-38fdbd72-379a-422d-b97f-33df71fb1cec.png)

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)

163
README-JP.md Normal file
View File

@@ -0,0 +1,163 @@
<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をあなたの母国語に翻訳するために、あなたの助けが必要です。</b>
</p>
Chat with us: [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) を参照してください。
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
## 無料のパブリックサーバー
下記のサーバーは、無料で使用できますが、後々変更されることがあります。これらのサーバーから遠い場合、接続が遅い可能性があります。
| Location | Vendor | Specification |
| --------- | ------------- | ------------------ |
| Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM |
| Singapore | Vultr | 1 VCPU / 1GB RAM |
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
## 依存関係
デスクトップ版ではGUIに [sciter](https://sciter.com/) が使われています。 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)
## ビルド手順
- 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
- run `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
```
### Install 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 (For 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
```
### Build
```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 の場合、X11Xorgに変更します
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リポジトリのルートから実行していることを確認してください。そうしないと、アプリケーションが必要なリソースを見つけられない可能性があります。また、 `install``run` などの他の cargo サブコマンドは、ホストではなくコンテナ内にプログラムをインストールまたは実行するため、現在この方法ではサポートされていないことに注意してください。
## File Structure
- **[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)**: GUI
- **[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 hole punching) または中継接続を待つ。
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: プラットフォーム固有のコード
## Snapshot
![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-ML.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 നിങ്ങളുടെ മാതൃഭാഷയിലേക്ക് വിവർത്തനം ചെയ്യാൻ ഞങ്ങൾക്ക് നിങ്ങളുടെ സഹായം ആവശ്യമാണ്</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)
റസ്റ്റിൽ എഴുതിയ മറ്റൊരു റിമോട്ട് ഡെസ്ക്ടോപ്പ് സോഫ്റ്റ്‌വെയർ. ബോക്‌സിന് പുറത്ത് പ്രവർത്തിക്കുന്നു, കോൺഫിഗറേഷൻ ആവശ്യമില്ല. സുരക്ഷയെക്കുറിച്ച് ആശങ്കകളൊന്നുമില്ലാതെ, നിങ്ങളുടെ ഡാറ്റയുടെ പൂർണ്ണ നിയന്ത്രണം നിങ്ങൾക്കുണ്ട്. നിങ്ങൾക്ക് ഞങ്ങളുടെ rendezvous/relay സെർവർ ഉപയോഗിക്കാം, [സ്വന്തമായി സജ്ജീകരിക്കുക](https://rustdesk.com/server), അല്ലെങ്കിൽ [നിങ്ങളുടെ സ്വന്തം rendezvous/relay സെർവർ എഴുതുക](https://github.com/rustdesk/rustdesk-server-demo).
എല്ലാവരുടെയും സംഭാവനയെ RustDesk സ്വാഗതം ചെയ്യുന്നു. ആരംഭിക്കുന്നതിനുള്ള സഹായത്തിന് [`CONTRIBUTING.md`](CONTRIBUTING.md) കാണുക.
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
## സൗജന്യ പൊതു സെർവറുകൾ
നിങ്ങൾ സൗജന്യമായി ഉപയോഗിക്കുന്ന സെർവറുകൾ ചുവടെയുണ്ട്, അത് സമയത്തിനനുസരിച്ച് മാറിയേക്കാം. നിങ്ങൾ ഇവയിലൊന്നിനോട് അടുത്തല്ലെങ്കിൽ, നിങ്ങളുടെ നെറ്റ്‌വർക്ക് സ്ലോ ആയേക്കാം.
| സ്ഥാനം | കച്ചവടക്കാരൻ | വിവരണം |
| --------- | ------------- | ------------------ |
| Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM |
| Singapore | Vultr | 1 VCPU / 1GB RAM |
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
## ഡിപെൻഡൻസികൾ
ഡെസ്‌ക്‌ടോപ്പ് പതിപ്പുകൾ GUI-യ്‌ക്കായി [sciter](https://sciter.com/) ഉപയോഗിക്കുന്നു, ദയവായി സ്‌സൈറ്റർ ഡൈനാമിക് ലൈബ്രറി സ്വയം ഡൗൺലോഡ് ചെയ്യുക.
[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 development envയു and C++ build envയു തയ്യാറാക്കുക
- [vcpkg](https://github.com/microsoft/vcpkg) ഇൻസ്റ്റാൾ ചെയ്ത് `VCPKG_ROOT` env വേരിയബിൾ ശരിയായി സജ്ജമാക്കുക
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
- Linux/MacOS: vcpkg install libvpx libyuv opus
- run `cargo run`
## ലിനക്സിൽ എങ്ങനെ നിർമ്മിക്കാം
### ഉബുണ്ടു 18 (ഡെബിയൻ 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
```
### ഫെഡോറ 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
```
### ആർച് (മഞ്ചാരോ)
```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 പരിഹരിക്കുക (ഫെഡോറയ്ക്ക്)
```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
```
### വേലാൻഡ് X11 (Xorg) ആയി മാറ്റുക
RustDesk Wayland-നെ പിന്തുണയ്ക്കുന്നില്ല. സ്ഥിരസ്ഥിതി ഗ്നോം സെഷനായി Xorg കോൺഫിഗർ ചെയ്യുന്നതിന് [ഇത്](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) പരിശോധിക്കുക.
## ഡോക്കർ ഉപയോഗിച്ച് എങ്ങനെ നിർമ്മിക്കാം
റെപ്പോസിറ്റോറി ക്ലോണുചെയ്‌ത് ഡോക്കർ കണ്ടെയ്‌നർ നിർമ്മിക്കുന്നതിലൂടെ ആരംഭിക്കുക:
```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 റിപ്പോസിറ്ററിയുടെ റൂട്ടിൽ നിന്നാണ് നിങ്ങൾ ഈ കമാൻഡുകൾ പ്രവർത്തിപ്പിക്കുന്നതെന്ന് ദയവായി ഉറപ്പാക്കുക, അല്ലാത്തപക്ഷം ആപ്ലിക്കേഷന് ആവശ്യമായ ഉറവിടങ്ങൾ കണ്ടെത്താൻ കഴിഞ്ഞേക്കില്ല. ഹോസ്റ്റിന് പകരം കണ്ടെയ്‌നറിനുള്ളിൽ പ്രോഗ്രാം ഇൻസ്റ്റാൾ ചെയ്യുകയോ പ്രവർത്തിപ്പിക്കുകയോ ചെയ്യുന്നതിനാൽ, `install` അല്ലെങ്കിൽ `run` പോലുള്ള മറ്റ് കാർഗോ സബ്‌കമാൻഡുകൾ നിലവിൽ ഈ രീതിയെ പിന്തുണയ്ക്കുന്നില്ല എന്നതും ശ്രദ്ധിക്കുക.
## ഫയൽ ഘടന
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, config, tcp/udp wrapper, protobuf, fs functions for file transfer, and some other utility functions
- **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: screen capture
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: platform specific keyboard/mouse control
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: audio/clipboard/input/video services, and network connections
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: start a peer connection
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Communicate with [rustdesk-server](https://github.com/rustdesk/rustdesk-server), wait for remote direct (TCP hole punching) or relayed connection
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platform specific code
## സ്നാപ്പ്ഷോട്ടുകൾ
![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)

163
README-NL.md Normal file
View File

@@ -0,0 +1,163 @@
<p align="center">
<img src="logo-header.svg" alt="RustDesk - Jouw verbinding op afstand"><br>
<a href="#free-public-servers">Servers</a> •
<a href="#raw-steps-to-build">Bouwen</a> •
<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-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>
Praat met ons: [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)
Nog weer een applicatie voor toegang op afstand, geschreven in Rust. Werkt meteen, geen configuratie nodig. Je hebt volledig beheer over je data, zonder na te hoeven denken over veiligheid. Je kunt onze rendez-vous/relay-server gebruiken, [je eigen server opzetten](https://rustdesk.com/blog/id-relay-set), of [je eigen rendez-vous/relay-server schrijven](https://github.com/rustdesk/rustdesk-server-demo).
RustDesk verwelkomt bijdragen van iedereen. Zie [`CONTRIBUTING.md`](CONTRIBUTING.md) om te lezen hoe je van start kunt gaan.
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
## Gratis openbare servers
Onderstaande servers zijn de servers die je gratis kunt gebruiken, ze kunnen op termijn veranderen. Als je niet fysiek dichtbij een van deze servers bent, kan je verbinding traag werken.
| Locatie | Aanbieder | Specificaties |
| --------- | ------------- | ------------------ |
| Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM |
| Singapore | Vultr | 1 VCPU / 1GB RAM |
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
## Afhankelijkheden
Desktopversies gebruiken [sciter](https://sciter.com/) voor de grafische schil. Gelieve zelf de sciter-library te downloaden.
[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)
## Handmatige bouwinstructies
- Bereid je Rust-ontwikkelomgeving en C++-bouwomgeving voor.
- Installeer [vcpkg](https://github.com/microsoft/vcpkg) en configureer de `VCPKG_ROOT` omgevingsvariabele op de juiste manier:
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
- Linux/MacOS: vcpkg install libvpx libyuv opus
- Voer uit: `cargo run`
## Bouwen op 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
```
### Installatie van 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 voor libvpx (voor 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
```
### Bouwen
```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
```
### Wissel van Wayland naar X11 (Xorg)
RustDesk ondersteunt Wayland niet. Lees [hier](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) hoe je Xorg als standaardsessie kunt instellen voor GNOME.
## Bouwen met Docker
Kloon eerst deze repository en bouw de Docker-container:
```sh
git clone https://github.com/rustdesk/rustdesk
cd rustdesk
docker build -t "rustdesk-builder" .
```
Voer vervolgens de volgende commando's uit iedere keer dat je de applicatie opnieuw moet bouwen:
```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
```
Let op dat de eerste build langer kan duren omdat de dependencies nog niet zijn gecached; latere builds zullen sneller zijn. Als je extra command line arguments wilt toevoegen aan het build-commando, dan kun je dat doen aan het einde van de opdrachtregel in plaats van `<OPTIONAL-ARGS>`. Bijvoorbeeld: als je een geoptimaliseerde releaseversie wilt bouwen, draai dan het bovenstaande commando gevolgd door `---release`.
Het uitvoerbare bestand, in debug-modus, zal verschijnen in de target-map, en kan als volgt worden uitgevoerd:
```sh
target/debug/rustdesk
```
Als je een release-versie hebt gebouwd, is het commando als volgt:
```sh
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
- **[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
- **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: platformspecifieke muis- en toetsenbordbeheer
- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: geluids-, klembord-, invoer- en video-services, netwerkverbindingen
- **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: voor het opzetten van peer-verbindingen
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Communicatie met [rustdesk-server](https://github.com/rustdesk/rustdesk-server), afwachten van redirect op afstand (TCP hole punching) of een relayed verbinding
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platformspecifieke code
## Snapshot
![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="#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-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,60 +13,66 @@ 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. Świetna alternatywa dla TeamViewera i AnyDesk! 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.
RustDesk zaprasza do współpracy każdego. Zobacz [`CONTRIBUTING.md`](CONTRIBUTING.md) pomoc w uruchomieniu programu.
[**POBIERZ KOMPILACJE**](https://github.com/rustdesk/rustdesk/releases)
## Darmowe Serwery Publiczne
Poniżej znajdują się serwery, z których można korzystać za darmo, może się to zmienić z upływem czasu. Jeśli nie znajdujesz się w pobliżu jednego z nich, Twoja prędkość połączenia może być niska.
| Lokalizacja | Dostawca | Specyfikacja |
| Lokalizacja | Dostawca | Specyfikacja |
| --------- | ------------- | ------------------ |
| Seul | AWS lightsail | 1 VCPU / 0.5GB RAM |
| Singapur | Vultr | 1 VCPU / 1GB RAM |
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
| Seul | AWS lightsail | 1 VCPU / 0.5GB RAM |
| Singapur | Vultr | 1 VCPU / 1GB RAM |
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
## Zależności
Wersje desktopowe używają [sciter](https://sciter.com/) dla GUI, proszę pobrać bibliotekę dynamiczną sciter samodzielnie.
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[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)
## Podstawowe kroki do kompilacji.
* Przygotuj środowisko programistyczne Rust i środowisko programowania C++
## Podstawowe kroki do kompilacji
* Zainstaluj [vcpkg](https://github.com/microsoft/vcpkg), i ustaw `VCPKG_ROOT` env zmienną prawidłowo
- Przygotuj środowisko programistyczne Rust i środowisko programowania C++
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
- Linux/MacOS: vcpkg install libvpx libyuv opus
* uruchom `cargo run`
- Zainstaluj [vcpkg](https://github.com/microsoft/vcpkg), i ustaw `VCPKG_ROOT` env zmienną prawidłowo
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
- Linux/MacOS: vcpkg install libvpx libyuv opus
- uruchom `cargo run`
## Jak Kompilować na Linuxie
### 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
```
### Zainstaluj vcpkg
```sh
git clone https://github.com/microsoft/vcpkg
git clone https://github.com/microsoft/vcpkg
cd vcpkg
git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82
git checkout 2021.12.01
cd ..
vcpkg/bootstrap-vcpkg.sh
export VCPKG_ROOT=$HOME/vcpkg
@@ -74,6 +80,7 @@ vcpkg/vcpkg install libvpx libyuv opus
```
### Fix libvpx (For Fedora)
```sh
cd vcpkg/buildtrees/libvpx/src
cd *
@@ -86,6 +93,7 @@ cd
```
### Kompilacja
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
@@ -97,6 +105,10 @@ mv libsciter-gtk.so target/debug
cargo run
```
### Zmień Wayland na X11 (Xorg)
RustDesk nie obsługuje Waylanda. Sprawdź [this](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) by skonfigurować Xorg jako domyślną sesję GNOME.
## Jak kompilować za pomocą Dockera
Rozpocznij od sklonowania repozytorium i stworzenia kontenera docker:
@@ -115,7 +127,6 @@ docker run --rm -it -v $PWD:/home/user/rustdesk -v rustdesk-git-cache:/home/user
Zauważ, że pierwsza kompilacja może potrwać dłużej zanim zależności zostaną zbuforowane, kolejne będą szybsze. Dodatkowo, jeśli potrzebujesz określić inne argumenty dla polecenia budowania, możesz to zrobić na końcu komendy w miejscu `<OPTIONAL-ARGS>`. Na przykład, jeśli chciałbyś zbudować zoptymalizowaną wersję wydania, uruchomiłbyś powyższą komendę a następnie `---release`. Powstały plik wykonywalny będzie dostępny w folderze docelowym w twoim systemie, i może być uruchomiony z:
```sh
target/debug/rustdesk
```
@@ -128,9 +139,6 @@ target/release/rustdesk
Upewnij się, że uruchamiasz te polecenia z katalogu głównego repozytorium RustDesk, w przeciwnym razie aplikacja może nie być w stanie znaleźć wymaganych zasobów. Należy również pamiętać, że inne podpolecenia ładowania, takie jak `install` lub `run` nie są obecnie obsługiwane za pomocą tej metody, ponieważ instalowałyby lub uruchamiały program wewnątrz kontenera zamiast na hoście.
### Zmień Wayland na X11 (Xorg)
RustDesk nie obsługuje Waylanda. Sprawdź [this](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) by skonfigurować Xorg jako domyślną sesję GNOME.
## Struktura plików
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: kodek wideo, config, wrapper tcp/udp, protobuf, funkcje fs do transferu plików i kilka innych funkcji użytkowych
@@ -143,10 +151,11 @@ RustDesk nie obsługuje Waylanda. Sprawdź [this](https://docs.fedoraproject.org
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: specyficzny dla danej platformy kod
## Migawki(Snapshoty)
![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/113112990-65e2fd80-923c-11eb-840e-349b4d6e340d.png)
![image](https://user-images.githubusercontent.com/71636191/135385039-38fdbd72-379a-422d-b97f-33df71fb1cec.png)

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,23 +5,25 @@
<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-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)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I04VU09)
远程桌面软件,开箱即用,无需任何配置替代TeamViewer和AnyDesk。您完全掌控数据,不用担心安全问题。您可以使用我们的注册/中继服务器,
或者[自己设置](https://rustdesk.com/blog/id-relay-set/)
远程桌面软件,开箱即用,无需任何配置。您完全掌控数据,不用担心安全问题。您可以使用我们的注册/中继服务器,
或者[自己设置](https://rustdesk.com/server)
亦或者[开发您的版本](https://github.com/rustdesk/rustdesk-server-demo)。
欢迎大家贡献代码, 请看 [`CONTRIBUTING.md`](CONTRIBUTING.md).
欢迎大家贡献代码, 请看 [`CONTRIBUTING.md`](CONTRIBUTING.md).
[**可执行程序下载**](https://github.com/rustdesk/rustdesk/releases)
## 免费公共服务器
以下是您免费使用的服务器,它可能会随着时间的推移而变化。如果您不靠近其中之一,您的网络可能会很慢。
- 首尔, AWS lightsail, 1 VCPU/0.5G RAM
- 新加坡, Vultr, 1 VCPU/1G RAM
- 达拉斯, Vultr, 1 VCPU/1G RAM
@@ -30,49 +32,55 @@ Chat with us: [知乎](https://www.zhihu.com/people/rustdesk) | [Discord](https:
桌面版本界面使用[sciter](https://sciter.com/), 请自行下载。
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[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`环境变量
- 请准备好 Rust 开发环境和 C++编译环境
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
- Linux/Osx: vcpkg install libvpx libyuv opus
* 运行 `cargo run`
- 安装[vcpkg](https://github.com/microsoft/vcpkg), 正确设置`VCPKG_ROOT`环境变量
## 在Linux上编译
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
- Linux/Osx: 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
### 安装 vcpkg
```sh
git clone https://github.com/microsoft/vcpkg
git clone https://github.com/microsoft/vcpkg
cd vcpkg
git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82
git checkout 2021.12.01
cd ..
vcpkg/bootstrap-vcpkg.sh
export VCPKG_ROOT=$HOME/vcpkg
vcpkg/vcpkg install libvpx libyuv opus
```
### 修复libvpx (仅仅针对Fedora)
### 修复 libvpx (仅仅针对 Fedora)
```sh
cd vcpkg/buildtrees/libvpx/src
cd *
@@ -85,6 +93,7 @@ cd
```
### 构建
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
@@ -96,7 +105,12 @@ mv libsciter-gtk.so target/debug
cargo run
```
## 使用Docker编译
### 把 Wayland 修改成 X11 (Xorg)
RustDesk 暂时不支持 Wayland不过正在积极开发中.
请查看[this](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/)配置 X11.
## 使用 Docker 编译
首先克隆存储库并构建 docker 容器:
@@ -106,16 +120,65 @@ cd rustdesk
docker build -t "rustdesk-builder" .
```
针对国内网络访问问题,可以做以下几点优化:
1. Dockerfile 中修改系统的源到国内镜像
```
在Dockerfile的RUN apt update之前插入两行
RUN sed -i "s/deb.debian.org/mirrors.163.com/g" /etc/apt/sources.list
RUN sed -i "s/security.debian.org/mirrors.163.com/g" /etc/apt/sources.list
```
2. 修改容器系统中的 cargo 源,在`RUN ./rustup.sh -y`后插入下面代码:
```
RUN echo '[source.crates-io]' > ~/.cargo/config \
&& echo 'registry = "https://github.com/rust-lang/crates.io-index"' >> ~/.cargo/config \
&& echo '# 替换成你偏好的镜像源' >> ~/.cargo/config \
&& echo "replace-with = 'sjtu'" >> ~/.cargo/config \
&& echo '# 上海交通大学' >> ~/.cargo/config \
&& echo '[source.sjtu]' >> ~/.cargo/config \
&& echo 'registry = "https://mirrors.sjtug.sjtu.edu.cn/git/crates.io-index"' >> ~/.cargo/config \
&& echo '' >> ~/.cargo/config
```
3. Dockerfile 中加入代理的 env
```
在User root后插入两行
ENV http_proxy=http://host:port
ENV https_proxy=http://host:port
```
4. docker build 命令后面加上 proxy 参数
```
docker build -t "rustdesk-builder" . --build-arg http_proxy=http://host:port --build-arg https_proxy=http://host:port
```
然后,每次需要构建应用程序时,运行以下命令:
```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
```
运行若遇到无权限问题,出现以下提示:
请注意,第一次构建可能需要比较长的时间,因为需要缓存依赖项,后续构建会更快。此外,如果您需要为构建命令指定不同的参数,
```
usermod: user user is currently used by process 1
groupmod: Permission denied.
groupmod: cannot lock /etc/group; try again later.
```
可以尝试把`-e PUID="$(id -u)" -e PGID="$(id -g)"`参数去掉。(出现这一问题的原因是容器中的 entrypoint 脚本中判定 uid 和 gid 与给定的环境变量不一致时会修改 user 的 uid 和 gid 重新运行,但是重新运行时取不到环境变量中的 uid 和 gid 了,会再次进入 uid 与 gid 与给定值不一致的逻辑分支)
请注意,第一次构建可能需要比较长的时间,因为需要缓存依赖项(国内网络经常出现拉取失败,可多尝试几次),后续构建会更快。此外,如果您需要为构建命令指定不同的参数,
您可以在命令末尾的 `<OPTIONAL-ARGS>` 位置执行此操作。例如,如果你想构建一个优化的发布版本,你可以在命令后跟 `---release`。
将在target下产生可执行程序请通过以下方式运行调试版本
将在 target 下产生可执行程序,请通过以下方式运行调试版本:
```sh
target/debug/rustdesk
```
@@ -129,26 +192,23 @@ target/release/rustdesk
请确保您从 RustDesk 存储库的根目录运行这些命令,否则应用程序可能无法找到所需的资源。另请注意,此方法当前不支持其他`Cargo`子命令,
例如 `install` 或 `run`,因为运行在容器里,而不是宿主机上。
### 把Wayland修改成X11 (Xorg)
RustDesk暂时不支持Wayland不过正在积极开发中.
请查看[this](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/)配置X11.
## 文件结构
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: 视频编解码, 配置, tcp/udp封装, protobuf, 文件传输相关文件系统操作函数, 以及一些其他实用函数
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: 视频编解码, 配置, tcp/udp 封装, protobuf, 文件传输相关文件系统操作函数, 以及一些其他实用函数
- **[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)**: GUI
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: 被控端服务audio/clipboard/input/video服务, 已经连接实现
- **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: 被控端服务audio/clipboard/input/video 服务, 已经连接实现
- **[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)保持UDP通讯, 等待远程连接(通过打洞直连或者中继)
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: 与[rustdesk-server](https://github.com/rustdesk/rustdesk-server)保持 UDP 通讯, 等待远程连接(通过打洞直连或者中继)
- **[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/113112990-65e2fd80-923c-11eb-840e-349b4d6e340d.png)
![image](https://user-images.githubusercontent.com/71636191/135385039-38fdbd72-379a-422d-b97f-33df71fb1cec.png)

View File

@@ -5,68 +5,74 @@
<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-JP.md">日本語</a>] | [<a href="README-RU.md">Русский</a>] | [<a href="README-PT.md">Português</a>]<br>
<b>We need your help to translate this README to your native language</b>
[<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>
Chat with us: [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)
Yet another remote desktop software, written in Rust. Works out of the box, no configuration required. Great alternative to TeamViewer and AnyDesk! 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.
RustDesk welcomes contribution from everyone. See [`CONTRIBUTING.md`](CONTRIBUTING.md) for help getting started.
[**BINARY DOWNLOAD**](https://github.com/rustdesk/rustdesk/releases)
## Free Public Servers
Below are the servers you are using for free, it may change along the time. If you are not close to one of these, your network may be slow.
| Location | Vendor | Specification |
| Location | Vendor | Specification |
| --------- | ------------- | ------------------ |
| Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM |
| Singapore | Vultr | 1 VCPU / 1GB RAM |
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
| Seoul | AWS lightsail | 1 VCPU / 0.5GB RAM |
| Singapore | Vultr | 1 VCPU / 1GB RAM |
| Dallas | Vultr | 1 VCPU / 1GB RAM | |
## Dependencies
Desktop versions use [sciter](https://sciter.com/) for GUI, please download sciter dynamic library yourself.
[Windows](https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll) |
[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)
## Raw steps to build
* Prepare your Rust development env and C++ build env
* Install [vcpkg](https://github.com/microsoft/vcpkg), and set `VCPKG_ROOT` env variable correctly
- Prepare your Rust development env and C++ build env
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
- Linux/MacOS: vcpkg install libvpx libyuv opus
* run `cargo run`
- Install [vcpkg](https://github.com/microsoft/vcpkg), and set `VCPKG_ROOT` env variable correctly
- Windows: vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
- Linux/MacOS: vcpkg install libvpx libyuv opus
- run `cargo run`
## How to build on 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
```
### Install vcpkg
```sh
git clone https://github.com/microsoft/vcpkg
git clone https://github.com/microsoft/vcpkg
cd vcpkg
git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82
git checkout 2021.12.01
cd ..
vcpkg/bootstrap-vcpkg.sh
export VCPKG_ROOT=$HOME/vcpkg
@@ -74,6 +80,7 @@ vcpkg/vcpkg install libvpx libyuv opus
```
### Fix libvpx (For Fedora)
```sh
cd vcpkg/buildtrees/libvpx/src
cd *
@@ -86,6 +93,7 @@ cd
```
### Build
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
@@ -94,9 +102,13 @@ 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
cargo run
VCPKG_ROOT=$HOME/vcpkg cargo run
```
### Change Wayland to X11 (Xorg)
RustDesk does not support Wayland. Check [this](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) to configuring Xorg as the default GNOME session.
## How to build with Docker
Begin by cloning the repository and building the docker container:
@@ -127,9 +139,6 @@ target/release/rustdesk
Please ensure that you are running these commands from the root of the RustDesk repository, otherwise the application may be unable to find the required resources. Also note that other cargo subcommands such as `install` or `run` are not currently supported via this method as they would install or run the program inside the container instead of the host.
### Change Wayland to X11 (Xorg)
RustDesk does not support Wayland. Check [this](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) to configuring Xorg as the default GNOME session.
## File Structure
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, config, tcp/udp wrapper, protobuf, fs functions for file transfer, and some other utility functions
@@ -142,10 +151,11 @@ RustDesk does not support Wayland. Check [this](https://docs.fedoraproject.org/e
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platform specific code
## Snapshot
![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/113112990-65e2fd80-923c-11eb-840e-349b4d6e340d.png)
![image](https://user-images.githubusercontent.com/71636191/135385039-38fdbd72-379a-422d-b97f-33df71fb1cec.png)

View File

@@ -2,11 +2,11 @@
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 1.1.x | :white_check_mark: |
| 1.x | :white_check_mark: |
| Below 1.0 | :x: |
| Version | Supported |
| --------- | ------------------ |
| 1.1.x | :white_check_mark: |
| 1.x | :white_check_mark: |
| Below 1.0 | :x: |
## Reporting a Vulnerability

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()

View File

@@ -1,13 +1,5 @@
#!/bin/sh
if [ "$(id -u)" != "${PUID:-1000}" ] || [ "$(id -g)" != "${PGID:-1000}" ]; then
usermod -o -u "${PUID:-1000}" user
groupmod -o -g "${PGID:-1000}" user
chown -R user /home/user
sudo -u user /entrypoint $@
exit 0
fi
cd $HOME/rustdesk
. $HOME/.cargo/env

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

@@ -6,7 +6,7 @@ fn main() {
thread::sleep(Duration::from_secs(2));
let mut enigo = Enigo::new();
enigo.key_down(Key::Layout('a'));
enigo.key_down(Key::Layout('a')).ok();
thread::sleep(Duration::from_secs(1));
enigo.key_up(Key::Layout('a'));
}

View File

@@ -10,7 +10,7 @@ fn main() {
enigo.key_sequence("Hello World! here is a lot of text ❤️");
// select all
enigo.key_down(Key::Control);
enigo.key_down(Key::Control).ok();
enigo.key_click(Key::Layout('a'));
enigo.key_up(Key::Control);
}

View File

@@ -11,7 +11,7 @@ fn main() {
enigo.mouse_move_to(500, 200);
thread::sleep(wait_time);
enigo.mouse_down(MouseButton::Left);
enigo.mouse_down(MouseButton::Left).ok();
thread::sleep(wait_time);
enigo.mouse_move_relative(100, 100);

View File

@@ -16,7 +16,7 @@ fn main() {
println!("{:?}", time);
// select all
enigo.key_down(Key::Control);
enigo.key_down(Key::Control).ok();
enigo.key_click(Key::Layout('a'));
enigo.key_up(Key::Control);
}

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

@@ -7,16 +7,16 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
protobuf = { version = "3.0.0-pre", git = "https://github.com/stepancheg/rust-protobuf" }
tokio = { version = "1.10", features = ["full"] }
protobuf = "3.0.0-alpha.2"
tokio = { version = "1.15", features = ["full"] }
tokio-util = { version = "0.6", features = ["full"] }
futures = "0.3"
bytes = "1.0"
bytes = "1.1"
log = "0.4"
env_logger = "0.9"
socket2 = { version = "0.3", features = ["reuseport"] }
zstd = "0.9"
quinn = {version = "0.6", optional = true }
quinn = {version = "0.8", optional = true }
anyhow = "1.0"
futures-util = "0.3"
directories-next = "2.0"
@@ -28,6 +28,8 @@ confy = { git = "https://github.com/open-trade/confy" }
dirs-next = "2.0"
filetime = "0.2"
sodiumoxide = "0.2"
regex = "1.4"
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"
@@ -36,7 +38,7 @@ mac_address = "1.1"
quic = ["quinn"]
[build-dependencies]
protobuf-codegen-pure = { version = "3.0.0-pre", git = "https://github.com/stepancheg/rust-protobuf" }
protobuf-codegen-pure = "3.0.0-alpha.2"
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = ["winuser"] }

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,10 +433,7 @@ message PublicKey {
bytes symmetric_value = 2;
}
message SignedId {
bytes id = 1;
bytes pk = 2;
}
message SignedId { bytes id = 1; }
message AudioFormat {
uint32 sample_rate = 1;
@@ -378,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;
}
}
@@ -400,5 +475,6 @@ message Message {
FileAction file_action = 17;
FileResponse file_response = 18;
Misc misc = 19;
Cliprdr cliprdr = 20;
}
}

View File

@@ -48,6 +48,7 @@ message PunchHoleSent {
string id = 2;
string relay_server = 3;
NatType nat_type = 4;
string version = 5;
}
message RegisterPk {
@@ -58,7 +59,7 @@ message RegisterPk {
message RegisterPkResponse {
enum Result {
OK = 1;
OK = 0;
UUID_MISMATCH = 2;
ID_EXISTS = 3;
TOO_FREQUENT = 4;
@@ -73,10 +74,10 @@ message PunchHoleResponse {
bytes socket_addr = 1;
bytes pk = 2;
enum Failure {
ID_NOT_EXIST = 1;
ID_NOT_EXIST = 0;
OFFLINE = 2;
LICENCE_MISMATCH = 3;
LICENCE_OVERUSE = 4;
LICENSE_MISMATCH = 3;
LICENSE_OVERUSE = 4;
}
Failure failure = 3;
string relay_server = 4;
@@ -110,6 +111,7 @@ message RelayResponse {
bytes pk = 5;
}
string refuse_reason = 6;
string version = 7;
}
message SoftwareUpdate { string url = 1; }
@@ -128,6 +130,17 @@ message LocalAddr {
bytes local_addr = 2;
string relay_server = 3;
string id = 4;
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 {
@@ -148,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

@@ -6,26 +6,23 @@ use sodiumoxide::crypto::sign;
use std::{
collections::HashMap,
fs,
net::SocketAddr,
net::{IpAddr, Ipv4Addr, SocketAddr},
path::{Path, PathBuf},
sync::{Arc, Mutex, RwLock},
time::SystemTime,
};
pub const APP_NAME: &str = "RustDesk";
pub const BIND_INTERFACE: &str = "0.0.0.0";
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")]
@@ -36,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"))]
@@ -55,7 +53,13 @@ pub const RENDEZVOUS_SERVERS: &'static [&'static str] = &[
pub const RENDEZVOUS_PORT: i32 = 21116;
pub const RELAY_PORT: i32 = 21117;
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum NetworkType {
Direct,
ProxySocks,
}
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub struct Config {
#[serde(default)]
id: String,
@@ -71,13 +75,19 @@ pub struct Config {
keys_confirmed: HashMap<String, bool>,
}
#[derive(Debug, Default, PartialEq, Serialize, Deserialize, Clone)]
pub struct Socks5Server {
#[serde(default)]
pub proxy: String,
#[serde(default)]
pub username: String,
#[serde(default)]
pub password: String,
}
// 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)]
@@ -85,6 +95,9 @@ pub struct Config2 {
#[serde(default)]
serial: i32,
#[serde(default)]
socks: Option<Socks5Server>,
// the other scalar value must before this
#[serde(default)]
pub options: HashMap<String, String>,
@@ -120,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)]
@@ -153,7 +168,10 @@ fn patch(path: PathBuf) -> PathBuf {
{
if _tmp == "/root" {
if let Ok(output) = std::process::Command::new("whoami").output() {
let user = String::from_utf8_lossy(&output.stdout).to_string().trim().to_owned();
let user = String::from_utf8_lossy(&output.stdout)
.to_string()
.trim()
.to_owned();
if user != "root" {
return format!("/home/{}", user).into();
}
@@ -169,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 {
@@ -251,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();
@@ -271,8 +303,8 @@ impl Config {
return "".into();
}
#[allow(unreachable_code)]
pub fn log_path() -> PathBuf {
#[allow(unreachable_code)]
#[cfg(target_os = "macos")]
{
if let Some(path) = dirs_next::home_dir().as_mut() {
@@ -324,10 +356,10 @@ impl Config {
#[inline]
pub fn get_any_listen_addr() -> SocketAddr {
format!("{}:0", BIND_INTERFACE).parse().unwrap()
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0)
}
pub fn get_rendezvous_server() -> SocketAddr {
pub fn get_rendezvous_server() -> String {
let mut rendezvous_server = Self::get_option("custom-rendezvous-server");
if rendezvous_server.is_empty() {
rendezvous_server = CONFIG2.write().unwrap().rendezvous_server.clone();
@@ -341,11 +373,7 @@ impl Config {
if !rendezvous_server.contains(":") {
rendezvous_server = format!("{}:{}", rendezvous_server, RENDEZVOUS_PORT);
}
if let Ok(addr) = crate::to_socket_addr(&rendezvous_server) {
addr
} else {
Self::get_any_listen_addr()
}
rendezvous_server
}
pub fn get_rendezvous_servers() -> Vec<String> {
@@ -485,6 +513,9 @@ impl Config {
pub fn set_key_pair(pair: (Vec<u8>, Vec<u8>)) {
let mut config = CONFIG.write().unwrap();
if config.key_pair == pair {
return;
}
config.key_pair = pair;
config.store();
}
@@ -517,6 +548,9 @@ impl Config {
pub fn set_options(v: HashMap<String, String>) {
let mut config = CONFIG2.write().unwrap();
if config.options == v {
return;
}
config.options = v;
config.store();
}
@@ -531,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() {
@@ -590,31 +621,34 @@ impl Config {
salt
}
pub fn get_size() -> Size {
CONFIG2.read().unwrap().size
}
pub fn set_size(x: i32, y: i32, w: i32, h: i32) {
pub fn set_socks(socks: Option<Socks5Server>) {
let mut config = CONFIG2.write().unwrap();
let size = (x, y, w, h);
if size == config.size || size.2 < 300 || size.3 < 300 {
if config.socks == socks {
return;
}
config.size = size;
config.socks = socks;
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_socks() -> Option<Socks5Server> {
CONFIG2.read().unwrap().socks.clone()
}
pub fn get_remote_id() -> String {
CONFIG2.read().unwrap().remote_id.clone()
pub fn get_network_type() -> NetworkType {
match &CONFIG2.read().unwrap().socks {
None => NetworkType::Direct,
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();
}
}
@@ -661,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(""))
@@ -685,6 +717,123 @@ impl PeerConfig {
}
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct LocalConfig {
#[serde(default)]
remote_id: String, // latest used one
#[serde(default)]
size: Size,
#[serde(default)]
pub fav: Vec<String>,
#[serde(default)]
options: HashMap<String, String>,
}
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_("_lan_peers")) {
Ok(peers) => peers,
Err(err) => {
log::error!("Failed to load lan peers: {}", err);
Default::default()
}
}
}
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)]
mod tests {
use super::*;

View File

@@ -193,7 +193,7 @@ pub struct TransferJob {
file: Option<File>,
total_size: u64,
finished_size: u64,
transfered: u64,
transferred: u64,
}
#[inline]
@@ -268,8 +268,8 @@ impl TransferJob {
}
#[inline]
pub fn transfered(&self) -> u64 {
self.transfered
pub fn transferred(&self) -> u64 {
self.transferred
}
#[inline]
@@ -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.transfered += block.data.len() as u64;
self.transferred += data.len() as u64;
Ok(())
}
@@ -398,7 +403,7 @@ impl TransferJob {
compressed = true;
}
}
self.transfered += buf.len() as u64;
self.transferred += buf.len() as u64;
}
Ok(Some(FileTransferBlock {
id: self.id,

View File

@@ -9,12 +9,13 @@ pub use protobuf;
use std::{
fs::File,
io::{self, BufRead},
net::{Ipv4Addr, SocketAddr, SocketAddrV4, ToSocketAddrs},
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
path::Path,
time::{self, SystemTime, UNIX_EPOCH},
};
pub use tokio;
pub use tokio_util;
pub mod socket_client;
pub mod tcp;
pub mod udp;
pub use env_logger;
@@ -26,7 +27,14 @@ 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;
pub use tokio_socks::IntoTargetAddr;
pub use tokio_socks::TargetAddr;
#[cfg(feature = "quic")]
pub type Stream = quic::Connection;
@@ -147,14 +155,6 @@ pub fn get_version_from_url(url: &str) -> String {
"".to_owned()
}
pub fn to_socket_addr(host: &str) -> ResultType<SocketAddr> {
let addrs: Vec<SocketAddr> = host.to_socket_addrs()?.collect();
if addrs.is_empty() {
bail!("Failed to solve {}", host);
}
Ok(addrs[0])
}
pub fn gen_version() {
let mut file = File::create("./src/version.rs").unwrap();
for line in read_lines("Cargo.toml").unwrap() {
@@ -179,6 +179,20 @@ where
Ok(io::BufReader::new(file).lines())
}
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 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

@@ -0,0 +1,91 @@
use crate::{
config::{Config, NetworkType},
tcp::FramedStream,
udp::FramedSocket,
ResultType,
};
use anyhow::Context;
use std::net::SocketAddr;
use tokio::net::ToSocketAddrs;
use tokio_socks::{IntoTargetAddr, TargetAddr};
fn to_socket_addr(host: &str) -> ResultType<SocketAddr> {
use std::net::ToSocketAddrs;
host.to_socket_addrs()?.next().context("Failed to solve")
}
pub fn get_target_addr(host: &str) -> ResultType<TargetAddr<'static>> {
let addr = match Config::get_network_type() {
NetworkType::Direct => to_socket_addr(&host)?.into_target_addr()?,
NetworkType::ProxySocks => host.into_target_addr()?,
}
.to_owned();
Ok(addr)
}
pub fn test_if_valid_server(host: &str) -> String {
let mut host = host.to_owned();
if !host.contains(":") {
host = format!("{}:{}", host, 0);
}
match Config::get_network_type() {
NetworkType::Direct => match to_socket_addr(&host) {
Err(err) => err.to_string(),
Ok(_) => "".to_owned(),
},
NetworkType::ProxySocks => match &host.into_target_addr() {
Err(err) => err.to_string(),
Ok(_) => "".to_owned(),
},
}
}
pub async fn connect_tcp<'t, T: IntoTargetAddr<'t>>(
target: T,
local: SocketAddr,
ms_timeout: u64,
) -> ResultType<FramedStream> {
let target_addr = target.into_target_addr()?;
if let Some(conf) = Config::get_socks() {
FramedStream::connect(
conf.proxy.as_str(),
target_addr,
local,
conf.username.as_str(),
conf.password.as_str(),
ms_timeout,
)
.await
} else {
let addr = std::net::ToSocketAddrs::to_socket_addrs(&target_addr)?
.next()
.context("Invalid target addr")?;
Ok(FramedStream::new(addr, local, ms_timeout).await?)
}
}
pub async fn new_udp<T: ToSocketAddrs>(local: T, ms_timeout: u64) -> ResultType<FramedSocket> {
match Config::get_socks() {
None => Ok(FramedSocket::new(local).await?),
Some(conf) => {
let socket = FramedSocket::new_proxy(
conf.proxy.as_str(),
local,
conf.username.as_str(),
conf.password.as_str(),
ms_timeout,
)
.await?;
Ok(socket)
}
}
}
pub async fn rebind_udp<T: ToSocketAddrs>(local: T) -> ResultType<Option<FramedSocket>> {
match Config::get_network_type() {
NetworkType::Direct => Ok(Some(FramedSocket::new(local).await?)),
_ => Ok(None),
}
}

View File

@@ -4,16 +4,31 @@ use futures::{SinkExt, StreamExt};
use protobuf::Message;
use sodiumoxide::crypto::secretbox::{self, Key, Nonce};
use std::{
io::{Error, ErrorKind},
io::{self, Error, ErrorKind},
net::SocketAddr,
ops::{Deref, DerefMut},
pin::Pin,
task::{Context, Poll},
};
use tokio::net::{lookup_host, TcpListener, TcpSocket, TcpStream, ToSocketAddrs};
use tokio::{
io::{AsyncRead, AsyncWrite, ReadBuf},
net::{lookup_host, TcpListener, TcpSocket, ToSocketAddrs},
};
use tokio_socks::{tcp::Socks5Stream, IntoTargetAddr, ToProxyAddrs};
use tokio_util::codec::Framed;
pub struct FramedStream(Framed<TcpStream, BytesCodec>, Option<(Key, u64, u64)>);
pub trait TcpStreamTrait: AsyncRead + AsyncWrite + Unpin {}
pub struct DynTcpStream(Box<dyn TcpStreamTrait + Send + Sync>);
pub struct FramedStream(
Framed<DynTcpStream, BytesCodec>,
SocketAddr,
Option<(Key, u64, u64)>,
u64,
);
impl Deref for FramedStream {
type Target = Framed<TcpStream, BytesCodec>;
type Target = Framed<DynTcpStream, BytesCodec>;
fn deref(&self) -> &Self::Target {
&self.0
@@ -26,6 +41,20 @@ impl DerefMut for FramedStream {
}
}
impl Deref for DynTcpStream {
type Target = Box<dyn TcpStreamTrait + Send + Sync>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for DynTcpStream {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
fn new_socket(addr: std::net::SocketAddr, reuse: bool) -> Result<TcpSocket, std::io::Error> {
let socket = match addr {
std::net::SocketAddr::V4(..) => TcpSocket::new_v4()?,
@@ -34,7 +63,7 @@ fn new_socket(addr: std::net::SocketAddr, reuse: bool) -> Result<TcpSocket, std:
if reuse {
// windows has no reuse_port, but it's reuse_address
// almost equals to unix's reuse_port + reuse_address,
// though may introduce nondeterministic bahavior
// though may introduce nondeterministic behavior
#[cfg(unix)]
socket.set_reuseport(true)?;
socket.set_reuseaddr(true)?;
@@ -44,8 +73,8 @@ fn new_socket(addr: std::net::SocketAddr, reuse: bool) -> Result<TcpSocket, std:
}
impl FramedStream {
pub async fn new<T: ToSocketAddrs, T2: ToSocketAddrs>(
remote_addr: T,
pub async fn new<T1: ToSocketAddrs, T2: ToSocketAddrs>(
remote_addr: T1,
local_addr: T2,
ms_timeout: u64,
) -> ResultType<Self> {
@@ -56,23 +85,88 @@ impl FramedStream {
new_socket(local_addr, true)?.connect(remote_addr),
)
.await??;
return Ok(Self(Framed::new(stream, BytesCodec::new()), None));
stream.set_nodelay(true).ok();
let addr = stream.local_addr()?;
return Ok(Self(
Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
addr,
None,
0,
));
}
}
bail!("could not resolve to any address");
}
pub fn from(stream: TcpStream) -> Self {
Self(Framed::new(stream, BytesCodec::new()), None)
pub async fn connect<'a, 't, P, T1, T2>(
proxy: P,
target: T1,
local: T2,
username: &'a str,
password: &'a str,
ms_timeout: u64,
) -> ResultType<Self>
where
P: ToProxyAddrs,
T1: IntoTargetAddr<'t>,
T2: ToSocketAddrs,
{
if let Some(local) = lookup_host(&local).await?.next() {
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,
Socks5Stream::connect_with_socket(stream, target),
)
.await??
} else {
super::timeout(
ms_timeout,
Socks5Stream::connect_with_password_and_socket(
stream, target, username, password,
),
)
.await??
};
let addr = stream.local_addr()?;
return Ok(Self(
Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
addr,
None,
0,
));
};
};
bail!("could not resolve to any address");
}
pub fn local_addr(&self) -> SocketAddr {
self.1
}
pub fn set_send_timeout(&mut self, ms: u64) {
self.3 = ms;
}
pub fn from(stream: impl TcpStreamTrait + Send + Sync + 'static, addr: SocketAddr) -> Self {
Self(
Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
addr,
None,
0,
)
}
pub fn set_raw(&mut self) {
self.0.codec_mut().set_raw();
self.1 = None;
self.2 = None;
}
pub fn is_secured(&self) -> bool {
self.1.is_some()
self.2.is_some()
}
#[inline]
@@ -83,24 +177,29 @@ impl FramedStream {
#[inline]
pub async fn send_raw(&mut self, msg: Vec<u8>) -> ResultType<()> {
let mut msg = msg;
if let Some(key) = self.1.as_mut() {
if let Some(key) = self.2.as_mut() {
key.1 += 1;
let nonce = Self::get_nonce(key.1);
msg = secretbox::seal(&msg, &nonce, &key.0);
}
self.0.send(bytes::Bytes::from(msg)).await?;
self.send_bytes(bytes::Bytes::from(msg)).await?;
Ok(())
}
#[inline]
pub async fn send_bytes(&mut self, bytes: Bytes) -> ResultType<()> {
self.0.send(bytes).await?;
if self.3 > 0 {
super::timeout(self.3, self.0.send(bytes)).await??;
} else {
self.0.send(bytes).await?;
}
Ok(())
}
#[inline]
pub async fn next(&mut self) -> Option<Result<BytesMut, Error>> {
let mut res = self.0.next().await;
if let Some(key) = self.1.as_mut() {
if let Some(key) = self.2.as_mut() {
if let Some(Ok(bytes)) = res.as_mut() {
key.2 += 1;
let nonce = Self::get_nonce(key.2);
@@ -128,7 +227,7 @@ impl FramedStream {
}
pub fn set_key(&mut self, key: Key) {
self.1 = Some((key, 0, 0));
self.2 = Some((key, 0, 0));
}
fn get_nonce(seqnum: u64) -> Nonce {
@@ -152,3 +251,35 @@ pub async fn new_listener<T: ToSocketAddrs>(addr: T, reuse: bool) -> ResultType<
bail!("could not resolve to any address");
}
}
impl Unpin for DynTcpStream {}
impl AsyncRead for DynTcpStream {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<io::Result<()>> {
AsyncRead::poll_read(Pin::new(&mut self.0), cx, buf)
}
}
impl AsyncWrite for DynTcpStream {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
AsyncWrite::poll_write(Pin::new(&mut self.0), cx, buf)
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
AsyncWrite::poll_flush(Pin::new(&mut self.0), cx)
}
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
AsyncWrite::poll_shutdown(Pin::new(&mut self.0), cx)
}
}
impl<R: AsyncRead + AsyncWrite + Unpin> TcpStreamTrait for R {}

View File

@@ -1,24 +1,17 @@
use crate::{bail, ResultType};
use bytes::BytesMut;
use anyhow::anyhow;
use bytes::{Bytes, BytesMut};
use futures::{SinkExt, StreamExt};
use protobuf::Message;
use socket2::{Domain, Socket, Type};
use std::{
io::Error,
net::SocketAddr,
ops::{Deref, DerefMut},
};
use tokio::{net::ToSocketAddrs, net::UdpSocket};
use std::net::SocketAddr;
use tokio::net::{ToSocketAddrs, UdpSocket};
use tokio_socks::{udp::Socks5UdpFramed, IntoTargetAddr, TargetAddr, ToProxyAddrs};
use tokio_util::{codec::BytesCodec, udp::UdpFramed};
pub struct FramedSocket(UdpFramed<BytesCodec>);
impl Deref for FramedSocket {
type Target = UdpFramed<BytesCodec>;
fn deref(&self) -> &Self::Target {
&self.0
}
pub enum FramedSocket {
Direct(UdpFramed<BytesCodec>),
ProxySocks(Socks5UdpFramed),
}
fn new_socket(addr: SocketAddr, reuse: bool) -> Result<Socket, std::io::Error> {
@@ -29,7 +22,7 @@ fn new_socket(addr: SocketAddr, reuse: bool) -> Result<Socket, std::io::Error> {
if reuse {
// windows has no reuse_port, but it's reuse_address
// almost equals to unix's reuse_port + reuse_address,
// though may introduce nondeterministic bahavior
// though may introduce nondeterministic behavior
#[cfg(unix)]
socket.set_reuse_port(true)?;
socket.set_reuse_address(true)?;
@@ -38,52 +31,110 @@ fn new_socket(addr: SocketAddr, reuse: bool) -> Result<Socket, std::io::Error> {
Ok(socket)
}
impl DerefMut for FramedSocket {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl FramedSocket {
pub async fn new<T: ToSocketAddrs>(addr: T) -> ResultType<Self> {
let socket = UdpSocket::bind(addr).await?;
Ok(Self(UdpFramed::new(socket, BytesCodec::new())))
Ok(Self::Direct(UdpFramed::new(socket, BytesCodec::new())))
}
#[allow(clippy::never_loop)]
pub async fn new_reuse<T: std::net::ToSocketAddrs>(addr: T) -> ResultType<Self> {
for addr in addr.to_socket_addrs()? {
return Ok(Self(UdpFramed::new(
UdpSocket::from_std(new_socket(addr, true)?.into_udp_socket())?,
let socket = new_socket(addr, true)?.into_udp_socket();
return Ok(Self::Direct(UdpFramed::new(
UdpSocket::from_std(socket)?,
BytesCodec::new(),
)));
}
bail!("could not resolve to any address");
}
pub async fn new_proxy<'a, 't, P: ToProxyAddrs, T: ToSocketAddrs>(
proxy: P,
local: T,
username: &'a str,
password: &'a str,
ms_timeout: u64,
) -> ResultType<Self> {
let framed = if username.trim().is_empty() {
super::timeout(ms_timeout, Socks5UdpFramed::connect(proxy, Some(local))).await??
} else {
super::timeout(
ms_timeout,
Socks5UdpFramed::connect_with_password(proxy, Some(local), username, password),
)
.await??
};
log::trace!(
"Socks5 udp connected, local addr: {:?}, target addr: {}",
framed.local_addr(),
framed.socks_addr()
);
Ok(Self::ProxySocks(framed))
}
#[inline]
pub async fn send(&mut self, msg: &impl Message, addr: SocketAddr) -> ResultType<()> {
self.0
.send((bytes::Bytes::from(msg.write_to_bytes().unwrap()), addr))
.await?;
pub async fn send(
&mut self,
msg: &impl Message,
addr: impl IntoTargetAddr<'_>,
) -> ResultType<()> {
let addr = addr.into_target_addr()?.to_owned();
let send_data = Bytes::from(msg.write_to_bytes()?);
let _ = match self {
Self::Direct(f) => match addr {
TargetAddr::Ip(addr) => f.send((send_data, addr)).await?,
_ => {}
},
Self::ProxySocks(f) => f.send((send_data, addr)).await?,
};
Ok(())
}
// https://stackoverflow.com/a/68733302/1926020
#[inline]
pub async fn send_raw(
&mut self,
msg: &'static [u8],
addr: impl IntoTargetAddr<'static>,
) -> ResultType<()> {
let addr = addr.into_target_addr()?.to_owned();
let _ = match self {
Self::Direct(f) => match addr {
TargetAddr::Ip(addr) => f.send((Bytes::from(msg), addr)).await?,
_ => {}
},
Self::ProxySocks(f) => f.send((Bytes::from(msg), addr)).await?,
};
Ok(())
}
#[inline]
pub async fn send_raw(&mut self, msg: &'static [u8], addr: SocketAddr) -> ResultType<()> {
self.0.send((bytes::Bytes::from(msg), addr)).await?;
Ok(())
pub async fn next(&mut self) -> Option<ResultType<(BytesMut, TargetAddr<'static>)>> {
match self {
Self::Direct(f) => match f.next().await {
Some(Ok((data, addr))) => {
Some(Ok((data, addr.into_target_addr().ok()?.to_owned())))
}
Some(Err(e)) => Some(Err(anyhow!(e))),
None => None,
},
Self::ProxySocks(f) => match f.next().await {
Some(Ok((data, _))) => Some(Ok((data.data, data.dst_addr))),
Some(Err(e)) => Some(Err(anyhow!(e))),
None => None,
},
}
}
#[inline]
pub async fn next(&mut self) -> Option<Result<(BytesMut, SocketAddr), Error>> {
self.0.next().await
}
#[inline]
pub async fn next_timeout(&mut self, ms: u64) -> Option<Result<(BytesMut, SocketAddr), Error>> {
pub async fn next_timeout(
&mut self,
ms: u64,
) -> Option<ResultType<(BytesMut, TargetAddr<'static>)>> {
if let Ok(res) =
tokio::time::timeout(std::time::Duration::from_millis(ms), self.0.next()).await
tokio::time::timeout(std::time::Duration::from_millis(ms), self.next()).await
{
res
} else {

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

@@ -43,7 +43,6 @@ struct Args {
flag_time: Option<u64>,
flag_fps: u64,
flag_bv: u32,
flag_ba: u32,
}
#[derive(Debug, serde::Deserialize)]

View File

@@ -9,8 +9,8 @@ extern "C" {
src_stride_argb: c_int,
dst_argb: *mut u8,
dst_stride_argb: c_int,
width: c_int,
height: c_int,
src_width: c_int,
src_height: c_int,
mode: c_int,
) -> c_int;
@@ -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

@@ -3,32 +3,20 @@ pub mod gdi;
pub use gdi::CapturerGDI;
use winapi::{
shared::dxgi::{
CreateDXGIFactory1, IDXGIAdapter1, IDXGIFactory1, IDXGIResource, IDXGISurface,
IID_IDXGIFactory1, IID_IDXGISurface, DXGI_MAP_READ, DXGI_OUTPUT_DESC,
DXGI_RESOURCE_PRIORITY_MAXIMUM,
shared::{
dxgi::*,
dxgi1_2::*,
dxgitype::*,
minwindef::{DWORD, FALSE, TRUE, UINT},
ntdef::LONG,
windef::HMONITOR,
winerror::*,
// dxgiformat::{DXGI_FORMAT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_420_OPAQUE},
},
shared::dxgi1_2::IDXGIOutputDuplication,
// shared::dxgiformat::{DXGI_FORMAT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_420_OPAQUE},
shared::dxgi1_2::{IDXGIOutput1, IID_IDXGIOutput1},
shared::dxgitype::DXGI_MODE_ROTATION,
shared::minwindef::{DWORD, FALSE, TRUE, UINT},
shared::ntdef::LONG,
shared::windef::HMONITOR,
shared::winerror::{
DXGI_ERROR_ACCESS_LOST, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_NOT_CURRENTLY_AVAILABLE,
DXGI_ERROR_SESSION_DISCONNECTED, DXGI_ERROR_UNSUPPORTED, DXGI_ERROR_WAIT_TIMEOUT,
E_ACCESSDENIED, E_INVALIDARG, S_OK,
um::{
d3d11::*, d3dcommon::D3D_DRIVER_TYPE_UNKNOWN, unknwnbase::IUnknown, wingdi::*,
winnt::HRESULT, winuser::*,
},
um::d3d11::{
D3D11CreateDevice, ID3D11Device, ID3D11DeviceContext, ID3D11Texture2D, IID_ID3D11Texture2D,
D3D11_CPU_ACCESS_READ, D3D11_SDK_VERSION, D3D11_USAGE_STAGING,
},
um::d3dcommon::D3D_DRIVER_TYPE_UNKNOWN,
um::unknwnbase::IUnknown,
um::wingdi::*,
um::winnt::HRESULT,
um::winuser::*,
};
pub struct ComPtr<T>(*mut T);
@@ -54,14 +42,14 @@ pub struct Capturer {
duplication: ComPtr<IDXGIOutputDuplication>,
fastlane: bool,
surface: ComPtr<IDXGISurface>,
data: *const u8,
len: usize,
width: usize,
height: usize,
use_yuv: bool,
yuv: Vec<u8>,
rotated: Vec<u8>,
gdi_capturer: Option<CapturerGDI>,
gdi_buffer: Vec<u8>,
saved_raw_data: Vec<u128>, // for faster compare and copy
}
impl Capturer {
@@ -158,12 +146,12 @@ impl Capturer {
width: display.width() as usize,
height: display.height() as usize,
display,
data: ptr::null(),
len: 0,
use_yuv,
yuv: Vec::new(),
rotated: Vec::new(),
gdi_capturer,
gdi_buffer: Vec::new(),
saved_raw_data: Vec::new(),
})
}
@@ -181,10 +169,9 @@ impl Capturer {
self.gdi_capturer.take();
}
unsafe fn load_frame(&mut self, timeout: UINT) -> io::Result<()> {
unsafe fn load_frame(&mut self, timeout: UINT) -> io::Result<(*const u8, i32)> {
let mut frame = ptr::null_mut();
let mut info = mem::MaybeUninit::uninit().assume_init();
self.data = ptr::null();
wrap_hresult((*self.duplication.0).AcquireNextFrame(timeout, &mut info, &mut frame))?;
let frame = ComPtr(frame);
@@ -200,9 +187,7 @@ impl Capturer {
self.surface = ComPtr(self.ohgodwhat(frame.0)?);
wrap_hresult((*self.surface.0).Map(&mut rect, DXGI_MAP_READ))?;
}
self.data = rect.pBits;
self.len = self.height * rect.Pitch as usize;
Ok(())
Ok((rect.pBits, rect.Pitch))
}
// copy from GPU memory to system memory
@@ -250,15 +235,55 @@ 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()));
}
}
} else {
self.unmap();
self.load_frame(timeout)?;
slice::from_raw_parts(self.data, self.len)
let r = self.load_frame(timeout)?;
let rotate = match self.display.rotation() {
DXGI_MODE_ROTATION_IDENTITY | DXGI_MODE_ROTATION_UNSPECIFIED => 0,
DXGI_MODE_ROTATION_ROTATE90 => 90,
DXGI_MODE_ROTATION_ROTATE180 => 180,
DXGI_MODE_ROTATION_ROTATE270 => 270,
_ => {
return Err(io::Error::new(
io::ErrorKind::Other,
"Unknown roration".to_string(),
));
}
};
if rotate == 0 {
slice::from_raw_parts(r.0, r.1 as usize * self.height)
} else {
self.rotated.resize(self.width * self.height * 4, 0);
crate::common::ARGBRotate(
r.0,
r.1,
self.rotated.as_mut_ptr(),
4 * self.width as i32,
if rotate == 180 {
self.width
} else {
self.height
} as _,
if rotate != 180 {
self.width
} else {
self.height
} as _,
rotate,
);
&self.rotated[..]
}
}
};
Ok({
@@ -478,7 +503,10 @@ pub struct Display {
gdi: bool,
}
// https://github.com/dchapyshev/aspia/blob/59233c5d01a4d03ed6de19b03ce77d61a6facf79/source/base/desktop/win/screen_capture_utils.cc
// optimized for updated region
// https://github.com/dchapyshev/aspia/blob/master/source/base/desktop/win/dxgi_output_duplicator.cc
// rotation
// https://github.com/bryal/dxgcap-rs/blob/master/src/lib.rs
impl Display {
pub fn width(&self) -> LONG {

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,11 +10,11 @@ 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,
sodiumoxide::crypto::{box_, secretbox, sign},
tcp::FramedStream,
timeout,
tokio::time::Duration,
AddrMangle, ResultType, Stream,
@@ -26,7 +26,7 @@ use std::{
collections::HashMap,
net::SocketAddr,
ops::Deref,
sync::{Arc, Mutex, RwLock},
sync::{mpsc, Arc, RwLock},
};
use uuid::Uuid;
@@ -34,7 +34,9 @@ pub const SEC30: Duration = Duration::from_secs(30);
pub struct Client;
#[cfg(not(any(target_os = "android")))]
pub use super::lang::*;
#[cfg(not(any(target_os = "android", target_os = "linux")))]
lazy_static::lazy_static! {
static ref AUDIO_HOST: Host = cpal::default_host();
}
@@ -43,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;
@@ -101,15 +102,40 @@ impl Drop for OboePlayer {
impl Client {
pub async fn start(peer: &str, conn_type: ConnType) -> ResultType<(Stream, bool)> {
match Self::_start(peer, conn_type).await {
Err(err) => {
let err_str = err.to_string();
if err_str.starts_with("Failed") {
bail!(err_str + ": Please try later");
} else {
return Err(err);
}
}
Ok(x) => Ok(x),
}
}
async fn _start(peer: &str, conn_type: ConnType) -> ResultType<(Stream, bool)> {
// to-do: remember the port for each peer, so that we can retry easier
let any_addr = Config::get_any_listen_addr();
if crate::is_ip(peer) {
return Ok((
socket_client::connect_tcp(
crate::check_port(peer, RELAY_PORT + 1),
any_addr,
RENDEZVOUS_TIMEOUT,
)
.await?,
true,
));
}
let rendezvous_server = crate::get_rendezvous_server(1_000).await;
log::info!("rendezvous server: {}", rendezvous_server);
let mut socket = FramedStream::new(rendezvous_server, any_addr, RENDEZVOUS_TIMEOUT)
.await
.with_context(|| "Failed to connect to rendezvous server")?;
let my_addr = socket.get_ref().local_addr()?;
let mut pk = Vec::new();
let mut socket =
socket_client::connect_tcp(&*rendezvous_server, any_addr, RENDEZVOUS_TIMEOUT).await?;
let my_addr = socket.local_addr();
let mut signed_id_pk = Vec::new();
let mut relay_server = "".to_owned();
let start = std::time::Instant::now();
@@ -134,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");
@@ -141,19 +170,17 @@ impl Client {
punch_hole_response::Failure::OFFLINE => {
bail!("Remote desktop is offline");
}
punch_hole_response::Failure::LICENCE_MISMATCH => {
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);
@@ -166,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));
}
_ => {
@@ -201,9 +228,9 @@ impl Client {
my_addr,
peer_addr,
peer,
pk,
signed_id_pk,
&relay_server,
rendezvous_server,
&rendezvous_server,
time_used,
peer_nat_type,
my_nat_type,
@@ -217,9 +244,9 @@ impl Client {
local_addr: SocketAddr,
peer: SocketAddr,
peer_id: &str,
pk: Vec<u8>,
signed_id_pk: Vec<u8>,
relay_server: &str,
rendezvous_server: SocketAddr,
rendezvous_server: &str,
punch_time_used: u64,
peer_nat_type: NatType,
my_nat_type: i32,
@@ -260,7 +287,8 @@ impl Client {
}
log::info!("peer address: {}, timeout: {}", peer, connect_timeout);
let start = std::time::Instant::now();
let mut conn = FramedStream::new(peer, local_addr, connect_timeout).await;
// NOTICE: Socks5 is be used event in intranet. Which may be not a good way.
let mut conn = socket_client::connect_tcp(peer, local_addr, connect_timeout).await;
let direct = !conn.is_err();
if conn.is_err() {
if !relay_server.is_empty() {
@@ -268,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;
@@ -290,33 +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<()> {
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(());
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");
}
}
let mut pk_ = [0u8; sign::PUBLICKEYBYTES];
pk_[..].copy_from_slice(&pk);
let pk = sign::PublicKey(pk_);
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 {
let their_pk_b = if si.pk.len() == box_::PUBLICKEYBYTES {
let mut pk_ = [0u8; box_::PUBLICKEYBYTES];
pk_[..].copy_from_slice(&si.pk);
box_::PublicKey(pk_)
} else {
bail!("Handshake failed: invalid public box key length from peer");
};
if let Ok(id) = sign::verify(&si.id, &pk) {
if id == peer_id.as_bytes() {
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]);
@@ -330,20 +364,23 @@ impl Client {
timeout(CONNECT_TIMEOUT, conn.send(&msg_out)).await??;
conn.set_key(key);
} else {
bail!("Handshake failed: sign failure");
log::error!("Handshake failed: sign failure");
conn.send(&Message::new()).await?;
}
} else {
// fall back to non-secure connection in case pk mismatch
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 {
bail!("Handshake failed: invalid message type");
log::error!("Handshake failed: invalid message type");
conn.send(&Message::new()).await?;
}
} else {
bail!("Handshake failed: invalid message format");
log::error!("Handshake failed: invalid message format");
conn.send(&Message::new()).await?;
}
}
None => {
@@ -356,7 +393,7 @@ impl Client {
async fn request_relay(
peer: &str,
relay_server: String,
rendezvous_server: SocketAddr,
rendezvous_server: &str,
secure: bool,
conn_type: ConnType,
) -> ResultType<Stream> {
@@ -365,9 +402,11 @@ impl Client {
let mut uuid = "".to_owned();
for i in 1..=3 {
// use different socket due to current hbbs implement requiring different nat address for each attempt
let mut socket = FramedStream::new(rendezvous_server, any_addr, RENDEZVOUS_TIMEOUT)
.await
.with_context(|| "Failed to connect to rendezvous server")?;
let mut socket =
socket_client::connect_tcp(rendezvous_server, any_addr, RENDEZVOUS_TIMEOUT)
.await
.with_context(|| "Failed to connect to rendezvous server")?;
let mut msg_out = RendezvousMessage::new();
uuid = Uuid::new_v4().to_string();
log::info!(
@@ -410,7 +449,7 @@ impl Client {
relay_server: String,
conn_type: ConnType,
) -> ResultType<Stream> {
let mut conn = FramedStream::new(
let mut conn = socket_client::connect_tcp(
crate::check_port(relay_server, RELAY_PORT),
Config::get_any_listen_addr(),
CONNECT_TIMEOUT,
@@ -432,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()
@@ -487,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],
@@ -529,25 +597,35 @@ 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,
device: &Device,
) -> ResultType<()> {
let err_fn = move |err| {
log::error!("an error occurred on stream: {}", err);
// too many errors, will improve later
log::trace!("an error occurred on stream: {}", err);
};
let audio_buffer = self.audio_buffer.clone();
let stream = device.build_output_stream(
@@ -582,7 +660,7 @@ pub struct VideoHandler {
impl VideoHandler {
pub fn new() -> Self {
VideoHandler {
decoder: Decoder::new(VideoCodecId::VP9, 1).unwrap(),
decoder: Decoder::new(VideoCodecId::VP9, (num_cpus::get() / 2) as _).unwrap(),
rgb: Default::default(),
}
}
@@ -622,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 {
@@ -658,6 +735,12 @@ impl LoginConfigHandler {
self.config = config;
}
pub fn set_option(&mut self, k: String, v: String) {
let mut config = self.load_config();
config.options.insert(k, v);
self.save_config(config);
}
pub fn save_view_style(&mut self, value: String) {
let mut config = self.load_config();
config.view_style = value;
@@ -707,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" {
@@ -721,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();
@@ -759,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 {
@@ -793,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" {
@@ -872,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,
@@ -900,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();
@@ -915,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()
});
@@ -932,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();
@@ -1011,6 +1198,7 @@ pub enum Data {
CancelJob(i32),
RemovePortForward(i32),
AddPortForward((i32, String, i32)),
ToggleClipboardFile,
NewRDP,
}
@@ -1086,7 +1274,6 @@ lazy_static::lazy_static! {
("VK_F10", Key::ControlKey(ControlKey::F10)),
("VK_F11", Key::ControlKey(ControlKey::F11)),
("VK_F12", Key::ControlKey(ControlKey::F12)),
("VK_F12", Key::ControlKey(ControlKey::F12)),
("VK_ENTER", Key::ControlKey(ControlKey::Return)),
("VK_CANCEL", Key::ControlKey(ControlKey::Cancel)),
("VK_BACK", Key::ControlKey(ControlKey::Backspace)),
@@ -1156,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

@@ -1,16 +1,15 @@
pub use arboard::Clipboard as ClipboardContext;
use hbb_common::{
allow_err,
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,
rendezvous_proto::*,
sleep,
tcp::FramedStream,
tokio, ResultType,
sleep, socket_client, tokio, ResultType,
};
#[cfg(any(target_os = "android", target_os = "ios", feature = "cli"))]
use hbb_common::{config::RENDEZVOUS_PORT, futures::future::join_all};
@@ -41,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);
@@ -95,7 +85,10 @@ pub fn update_clipboard(clipboard: Clipboard, old: Option<&Arc<Mutex<String>>>)
let side = if old.is_none() { "host" } else { "client" };
let old = if let Some(old) = old { old } else { &CONTENT };
*old.lock().unwrap() = content.clone();
allow_err!(ctx.set_text(content));
if !content.is_empty() {
// empty content make ctx.set_text crash
allow_err!(ctx.set_text(content));
}
log::debug!("{} updated on {}", CLIPBOARD_NAME, side);
}
Err(err) => {
@@ -218,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,
@@ -229,18 +223,34 @@ 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));
});
}
#[tokio::main(flavor = "current_thread")]
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(100).await;
let rendezvous_server = get_rendezvous_server(1_000).await;
let server1 = rendezvous_server;
let mut server2 = server1;
server2.set_port(server1.port() - 1);
let tmp: Vec<&str> = server1.split(":").collect();
if tmp.len() != 2 {
bail!("Invalid server address: {}", server1);
}
let port: u16 = tmp[1].parse()?;
if port == 0 {
bail!("Invalid server address: {}", server1);
}
let server2 = format!("{}:{}", tmp[0], port - 1);
let mut msg_out = RendezvousMessage::new();
let serial = Config::get_serial();
msg_out.set_test_nat_request(TestNatRequest {
@@ -249,17 +259,23 @@ async fn test_nat_type_() -> ResultType<bool> {
});
let mut port1 = 0;
let mut port2 = 0;
let server1 = socket_client::get_target_addr(&server1)?;
let server2 = socket_client::get_target_addr(&server2)?;
let mut addr = Config::get_any_listen_addr();
for i in 0..2 {
let mut socket = FramedStream::new(
if i == 0 { &server1 } else { &server2 },
let mut socket = socket_client::connect_tcp(
if i == 0 {
server1.clone()
} else {
server2.clone()
},
addr,
RENDEZVOUS_TIMEOUT,
)
.await?;
addr = socket.get_ref().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 {
@@ -294,12 +310,12 @@ async fn test_nat_type_() -> ResultType<bool> {
}
#[cfg(any(target_os = "android", target_os = "ios"))]
pub async fn get_rendezvous_server(_ms_timeout: u64) -> std::net::SocketAddr {
pub async fn get_rendezvous_server(_ms_timeout: u64) -> String {
Config::get_rendezvous_server()
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
pub async fn get_rendezvous_server(ms_timeout: u64) -> std::net::SocketAddr {
pub async fn get_rendezvous_server(ms_timeout: u64) -> String {
crate::ipc::get_rendezvous_server(ms_timeout).await
}
@@ -322,8 +338,8 @@ async fn test_rendezvous_server_() {
for host in servers {
futs.push(tokio::spawn(async move {
let tm = std::time::Instant::now();
if FramedStream::new(
&crate::check_port(&host, RENDEZVOUS_PORT),
if socket_client::connect_tcp(
crate::check_port(&host, RENDEZVOUS_PORT),
Config::get_any_listen_addr(),
RENDEZVOUS_TIMEOUT,
)
@@ -403,25 +419,6 @@ pub fn is_modifier(evt: &KeyEvent) -> bool {
}
}
pub fn test_if_valid_server(host: String) -> String {
let mut host = host;
if !host.contains(":") {
host = format!("{}:{}", host, 0);
}
match hbb_common::to_socket_addr(&host) {
Err(err) => err.to_string(),
Ok(_) => "".to_owned(),
}
}
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()));
}
@@ -429,8 +426,11 @@ pub fn check_software_update() {
#[tokio::main(flavor = "current_thread")]
async fn _check_software_update() -> hbb_common::ResultType<()> {
sleep(3.).await;
let rendezvous_server = get_rendezvous_server(1_000).await;
let mut socket = hbb_common::udp::FramedSocket::new(Config::get_any_listen_addr()).await?;
let rendezvous_server = socket_client::get_target_addr(&get_rendezvous_server(1_000).await)?;
let mut socket =
socket_client::new_udp(Config::get_any_listen_addr(), RENDEZVOUS_TIMEOUT).await?;
let mut msg_out = RendezvousMessage::new();
msg_out.set_software_update(SoftwareUpdate {
url: crate::VERSION.to_owned(),
@@ -450,3 +450,23 @@ 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+(:\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,
@@ -13,7 +15,7 @@ use parity_tokio_ipc::{
Connection as Conn, ConnectionClient as ConnClient, Endpoint, Incoming, SecurityAttributes,
};
use serde_derive::{Deserialize, Serialize};
use std::{collections::HashMap, net::SocketAddr};
use std::collections::HashMap;
#[cfg(not(windows))]
use std::{fs::File, io::prelude::*};
@@ -71,6 +73,8 @@ pub enum Data {
keyboard: bool,
clipboard: bool,
audio: bool,
file: bool,
file_transfer_enabled: bool,
},
ChatMessage {
text: String,
@@ -89,8 +93,13 @@ pub enum Data {
NatType(Option<i32>),
ConfirmedKey(Option<(Vec<u8>, Vec<u8>)>),
RawMessage(Vec<u8>),
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")]
@@ -147,7 +156,7 @@ pub async fn new_listener(postfix: &str) -> ResultType<Incoming> {
}
Err(err) => {
log::error!(
"Faild to start ipc{} server at path {}: {}",
"Failed to start ipc{} server at path {}: {}",
postfix,
path,
err
@@ -157,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(_) => {
@@ -192,6 +225,21 @@ async fn handle(data: Data, stream: &mut Connection) {
};
allow_err!(stream.send(&Data::ConfirmedKey(out)).await);
}
Data::Socks(s) => match s {
None => {
allow_err!(stream.send(&Data::Socks(Config::get_socks())).await);
}
Some(data) => {
if data.proxy.is_empty() {
Config::set_socks(None);
} else {
Config::set_socks(Some(data));
}
crate::common::test_nat_type();
RendezvousMediator::restart();
log::info!("socks updated");
}
},
Data::Config((name, value)) => match value {
None => {
let value;
@@ -202,7 +250,9 @@ async fn handle(data: Data, stream: &mut Connection) {
} else if name == "salt" {
value = Some(Config::get_salt());
} else if name == "rendezvous_server" {
value = Some(Config::get_rendezvous_server().to_string());
value = Some(Config::get_rendezvous_server());
} else if name == "rendezvous_servers" {
value = Some(Config::get_rendezvous_servers().join(","));
} else {
value = None;
}
@@ -210,6 +260,7 @@ async fn handle(data: Data, stream: &mut Connection) {
}
Some(value) => {
if name == "id" {
Config::set_key_confirmed(false);
Config::set_id(&value);
} else if name == "password" {
Config::set_password(&value);
@@ -227,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
);
}
_ => {}
}
}
@@ -259,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;
@@ -342,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")]
@@ -374,7 +465,7 @@ pub fn set_password(v: String) -> ResultType<()> {
pub fn get_id() -> String {
if let Ok(Some(v)) = get_config("id") {
// update salt also, so that nexttime reinstallation not causing first-time auto-login failure
// update salt also, so that next time reinstallation not causing first-time auto-login failure
if let Ok(Some(v2)) = get_config("salt") {
Config::set_salt(&v2);
}
@@ -397,13 +488,12 @@ pub fn get_password() -> String {
}
}
pub async fn get_rendezvous_server(ms_timeout: u64) -> SocketAddr {
pub async fn get_rendezvous_server(ms_timeout: u64) -> String {
if let Ok(Some(v)) = get_config_async("rendezvous_server", ms_timeout).await {
if let Ok(v) = v.parse() {
return v;
}
v
} else {
Config::get_rendezvous_server()
}
return Config::get_rendezvous_server();
}
async fn get_options_(ms_timeout: u64) -> ResultType<HashMap<String, String>> {
@@ -442,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(())
}
@@ -468,6 +559,41 @@ pub async fn get_nat_type(ms_timeout: u64) -> i32 {
.unwrap_or(Config::get_nat_type())
}
#[inline]
async fn get_socks_(ms_timeout: u64) -> ResultType<Option<config::Socks5Server>> {
let mut c = connect(ms_timeout, "").await?;
c.send(&Data::Socks(None)).await?;
if let Some(Data::Socks(value)) = c.next_timeout(ms_timeout).await? {
Config::set_socks(value.clone());
Ok(value)
} else {
Ok(Config::get_socks())
}
}
pub async fn get_socks_async(ms_timeout: u64) -> Option<config::Socks5Server> {
get_socks_(ms_timeout).await.unwrap_or(Config::get_socks())
}
#[tokio::main(flavor = "current_thread")]
pub async fn get_socks() -> Option<config::Socks5Server> {
get_socks_async(1_000).await
}
#[tokio::main(flavor = "current_thread")]
pub async fn set_socks(value: config::Socks5Server) -> ResultType<()> {
Config::set_socks(if value.proxy.is_empty() {
None
} else {
Some(value.clone())
});
connect(1_000, "")
.await?
.send(&Data::Socks(Some(value)))
.await?;
Ok(())
}
/*
static mut SHARED_MEMORY: *mut i64 = std::ptr::null_mut();

55
src/lang.rs Normal file
View File

@@ -0,0 +1,55 @@
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::trace!("The current locale is {}", locale);
translate_locale(name, &locale)
}
pub fn translate_locale(name: String, locale: &str) -> String {
let mut lang = LocalConfig::get_option("lang");
if lang.is_empty() {
lang = locale
.split("-")
.last()
.map(|x| x.split("_").last().unwrap_or_default())
.unwrap_or_default()
.to_owned();
}
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
}
}

272
src/lang/cn.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", "一分钟后再试"),
("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", "Key不匹配"),
("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安装到系统从而规避上述问题。"),
("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", "為了讓遠程設備通過鼠標或者觸屏控制您的安卓設備你需要允許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();
}

29
src/lang/en.rs Normal file
View File

@@ -0,0 +1,29 @@
lazy_static::lazy_static! {
pub static ref T: std::collections::HashMap<&'static str, &'static str> =
[
("desk_tip", "Your desktop can be accessed with this ID and password."),
("connecting_status", "Connecting to the RustDesk network..."),
("not_ready_status", "Not ready. Please check your connection"),
("id_change_tip", "Only a-z, A-Z, 0-9 and _ (underscore) characters allowed. The first letter must be a-z, A-Z. Length between 6 and 16."),
("install_tip", "Due to UAC, RustDesk can not work properly as the remote side in some cases. To avoid UAC, please click the button below to install RustDesk to the system."),
("config_acc", "In order to control your Desktop remotely, you need to grant RustDesk \"Accessibility\" permissions."),
("config_screen", "In order to access your Desktop remotely, you need to grant RustDesk \"Screen Recording\" permissions."),
("agreement_tip", "By starting the installation, you accept the license agreement."),
("not_close_tcp_tip", "Don't close this window while you are using the tunnel"),
("setup_server_tip", "For faster connection, please set up your own server"),
("Auto Login", "Auto Login (Only valid if you set \"Lock after session end\")"),
("whitelist_tip", "Only whitelisted IP can access me"),
("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();
}

271
src/lang/fr.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", "Statut"),
("Your Desktop", "Votre bureau"),
("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"),
("Transfer File", "Transférer le fichier"),
("Connect", "Connecter"),
("Recent Sessions", "Sessions récentes"),
("Address Book", "Carnet d'adresses"),
("Confirmation", "Confirmation"),
("TCP Tunneling", "Tunneling TCP"),
("Remove", "Supprimer"),
("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-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 le service"),
("Change ID", "Changer d'ID"),
("Website", "Site Web"),
("About", "À propos de"),
("Mute", "Muet"),
("Audio Input", "Entrée audio"),
("ID Server", "Serveur ID"),
("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 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", "Modifié trop fréquemment, veuillez réessayer plus tard"),
("Cancel", "Annuler"),
("Skip", "Ignorer"),
("Close", "Fermer"),
("Retry", "Réessayer"),
("OK", "Confirmer"),
("Password Required", "Mot de passe requis"),
("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 ?"),
("Connection Error", "Erreur de connexion"),
("Error", "Erreur"),
("Reset by the peer", "La connexion a été fermée par le pair"),
("Connecting...", "Connexion..."),
("Connection in progress. Please wait.", "Connexion en cours. Veuillez patienter."),
("Please try 1 minute later", "Réessayez dans une minute"),
("Login Error", "Erreur de connexion"),
("Successful", "Succès"),
("Connected, waiting for image...", "Connecté, en attente de transmission d'image..."),
("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"),
("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..."),
("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é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-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 rendezvous"),
("Please try later", "Veuillez essayer plus tard"),
("Remote desktop is offline", "Le bureau à distance est hors ligne"),
("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 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 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"),
("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 à RustDesk l'autorisation \"enregistrement d'écran\"."),
("Installing ...", "Installation..."),
("Install", "Installer"),
("Installation", "Installation"),
("Installation Path", "Chemin d'installation"),
("Create start menu shortcuts", "Créer des raccourcis dans le menu démarrer"),
("Create desktop icon", "Créer une icône sur le bureau"),
("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..."),
("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..."),
("Remote Host", "Hôte distant"),
("Remote Port", "Port distant"),
("Action", "Action"),
("Add", "Ajouter"),
("Local Port", "Port local"),
("setup_server_tip", "Si vous avez besoin d'une vitesse de connexion plus rapide, vous pouvez choisir de créer votre propre serveur"),
("Too short, at least 6 characters.", "Trop court, au moins 6 caractères."),
("The confirmation is not identical.", "Les deux entrées ne correspondent pas"),
("Permissions", "Autorisations"),
("Accept", "Accepter"),
("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-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 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é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"),
("Change Path", "Changer de chemin"),
("Create Folder", "Créer un dossier"),
("Please enter the folder name", "Veuillez saisir le nom du dossier"),
("Fix it", "Réparez-le"),
("Warning", "Avertissement"),
("Login screen using Wayland is not supported", "L'écran de connexion utilisant Wayland n'est pas pris en charge"),
("Reboot required", "Redémarrage pour prendre effet"),
("Unsupported display server ", "Le serveur d'affichage actuel n'est pas pris en charge"),
("x11 expected", "Veuillez passer à x11"),
("Port", "Port"),
("Settings", "Paramètres"),
("Username", " Nom d'utilisateur"),
("Invalid port", "Port invalide"),
("Closed manually by the peer", "Fermé manuellement par le pair"),
("Enable remote configuration modification", "Autoriser la modification de la configuration à distance"),
("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 accéder à mon appareil"),
("Login", "Connexion"),
("Logout", "Déconnexion"),
("Tags", "Étiqueter"),
("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 un ID"),
("Add Tag", "Ajouter une balise"),
("Unselect all tags", "Désélectionner toutes les balises"),
("Network error", "Erreur réseau"),
("Username missed", "Nom d'utilisateur manqué"),
("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"),
("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();
}

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