if (is_osx) view.windowBlurbehind = #light; stdout.println("current platform:", OS); // html min-width, min-height not working on mac, below works for all view.windowMinSize = (500, 300); var app; var tmp = handler.get_connect_status(); var connect_status = tmp[0]; var service_stopped = false; var software_update_url = ""; var key_confirmed = tmp[1]; var system_error = ""; var svg_menu = ; class ConnectStatus: Reactor.Component { function render() { return
{this.getConnectStatusStr()} {service_stopped ? Start Service : ""}
; } function getConnectStatusStr() { if (service_stopped) { return "Service is not running"; } else if (connect_status == -1) { return "Not ready. Please check your connection"; } else if (connect_status == 0) { return "Connecting to the RustDesk network..."; } return "Ready"; } event click $(.connect-status .link) () { var options = handler.get_options(); options["stop-service"] = ""; handler.set_options(options); } } class RecentSessions: Reactor.Component { function render() { var sessions = handler.get_recent_sessions(); if (sessions.length == 0) return ; sessions = sessions.map(this.getSession); return
RECENT SESSIONS
{sessions}
; } function getSession(s) { var id = s[0]; var username = s[1]; var hostname = s[2]; var platform = s[3]; var alias = s[4]; return
{platformSvg(platform, "white")}
{username}@{hostname}
{alias ? alias : formatId(id)}
{svg_menu}
; } event dblclick $(div.remote-session) (evt, me) { createNewConnect(me.id, "connect"); } event click $(#menu) (_, me) { var id = me.parent.parent.id; var platform = me.parent.parent.attributes["platform"]; $(#rdp).style.set{ display: (platform == "Windows" && is_win) ? "block" : "none", }; // https://sciter.com/forums/topic/replacecustomize-context-menu/ var menu = $(menu#remote-context); menu.attributes["remote-id"] = id; me.popup(menu); } } event click $(menu#remote-context li) (evt, me) { var action = me.id; var id = me.parent.attributes["remote-id"]; if (action == "connect") { createNewConnect(id, "connect"); } else if (action == "transfer") { createNewConnect(id, "file-transfer"); } else if (action == "remove") { handler.remove_peer(id); app.recent_sessions.update(); } else if (action == "shortcut") { handler.create_shortcut(id); } else if (action == "rdp") { createNewConnect(id, "rdp"); } else if (action == "tunnel") { createNewConnect(id, "port-forward"); } else if (action == "rename") { var old_name = handler.get_peer_option(id, "alias"); handler.msgbox("custom-rename", "Rename", "
\
\
\ ", function(res=null) { if (!res) return; var name = (res.name || "").trim(); if (name != old_name) handler.set_peer_option(id, "alias", name); self.select('#' + id).select('#alias').text = name || id; }); } } function createNewConnect(id, type) { id = id.replace(/\s/g, ""); app.remote_id.value = formatId(id); if (!id) return; if (id == handler.get_id()) { handler.msgbox("custom-error", "Error", "You cannot connect to your own computer"); return; } handler.set_remote_id(id); handler.new_remote(id, type); } var myIdMenu; var audioInputMenu; var configOptions = {}; class AudioInputs: Reactor.Component { function this() { audioInputMenu = this; } function render() { if (!this.show) return
  • ; var inputs = handler.get_sound_inputs(); if (is_win) inputs = ["System Sound"].concat(inputs); if (!inputs.length) return
  • ; inputs = ["Mute"].concat(inputs); var me = this; self.timer(1ms, function() { me.toggleMenuState() }); return
  • Audio Input {inputs.map(function(name) { return
  • {svg_checkmark}{name}
  • ; })}
  • ; } function get_default() { if (is_win) return "System Sound"; return ""; } function get_value() { return configOptions["audio-input"] || this.get_default(); } function toggleMenuState() { var v = this.get_value(); for (var el in $$(menu#audio-input>li)) { var selected = el.id == v; el.attributes.toggleClass("selected", selected); } } event click $(menu#audio-input>li) (_, me) { var v = me.id; if (v == this.get_value()) return; if (v == this.get_default()) v = ""; configOptions["audio-input"] = v; handler.set_options(configOptions); this.toggleMenuState(); } } class MyIdMenu: Reactor.Component { function this() { myIdMenu = this; } function render() { var me = this; return
    {this.renderPop()} ID{svg_menu}
    ; } function renderPop() { return
  • {svg_checkmark}Enable Keyboard/Mouse
  • {svg_checkmark}Enable Clipboard
  • {svg_checkmark}Enable File Transfer
  • {svg_checkmark}Enable TCP Tunneling
  • IP Whitelisting
  • ID/Relay Server
  • {service_stopped ? "Start service" : "Stop service"}
  • Forum
  • About {handler.get_app_name()}
  • ; } event click $(svg#menu) (_, me) { audioInputMenu.update({ show: true }); configOptions = handler.get_options(); this.toggleMenuState(); var menu = $(menu#config-options); me.popup(menu); } function toggleMenuState() { for (var el in $$(menu#config-options>li)) { if (el.id && el.id.indexOf("enable-") == 0) { var enabled = configOptions[el.id] != "N"; el.attributes.toggleClass("selected", enabled); } } } event click $(menu#config-options>li) (_, me) { if (me.id && me.id.indexOf("enable-") == 0) { configOptions[me.id] = configOptions[me.id] == "N" ? "" : "N"; handler.set_options(configOptions); this.toggleMenuState(); } if (me.id == "whitelist") { var old_value = (configOptions["whitelist"] || "").split(",").join("\n"); handler.msgbox("custom-whitelist", "IP Whitelisting", "
    \ \
    \ ", function(res=null) { if (!res) return; var value = (res.text || "").trim(); if (value) { var values = value.split(/[\s,;]+/g); for (var ip in values) { if (!ip.match(/^\d+\.\d+\.\d+\.\d+$/)) { return "Invalid ip: " + ip; } } value = values.join("\n"); } if (value == old_value) return; configOptions["whitelist"] = value.replace("\n", ","); stdout.println("whitelist updated"); handler.set_options(configOptions); }, 300); } else if (me.id == "custom-server") { var old_relay = configOptions["relay-server"] || ""; var old_id = configOptions["custom-rendezvous-server"] || ""; handler.msgbox("custom-server", "ID/Relay Server", "
    \
    ID Server:
    \
    Relay Server:
    \
    \ ", function(res=null) { if (!res) return; var id = (res.id || "").trim(); var relay = (res.relay || "").trim(); if (id == old_id && relay == old_relay) return; if (id) { var err = handler.test_if_valid_server(id); if (err) return "ID Server: " + err; } if (relay) { var err = handler.test_if_valid_server(relay); if (err) return "Relay Server: " + err; } configOptions["custom-rendezvous-server"] = id; configOptions["relay-server"] = relay; handler.set_options(configOptions); }); } else if (me.id == "forum") { handler.open_url("https:://forum.rustdesk.com"); } else if (me.id == "stop-service") { configOptions["stop-service"] = service_stopped ? "" : "Y"; handler.set_options(configOptions); } else if (me.id == "about") { var name = handler.get_app_name(); handler.msgbox("custom-nocancel-nook-hasclose", "About " + name, "
    \
    Version: " + handler.get_version() + " \
    Privacy Statement
    \
    Forum
    \
    Copyright © 2020 CarrieZ Studio \
    Author: Carrie \

    Made with heart in this chaotic world!

    \
    \
    ", function(el) { if (el && el.attributes) { handler.open_url(el.attributes['url']); }; }, 400); } } } class App: Reactor.Component { function this() { app = this; } function render() { var is_can_screen_recording = handler.is_can_screen_recording(false); return
  • Connect
  • Transfer File
  • TCP Tunneling
  • RDP
  • Rename
  • Remove
  • {is_win &&
  • Create Desktop Shortcut
  • }
  • Refresh random password
  • Set your own password
  • Your Desktop
    Your desktop can be accessed with this ID and password.
    {key_confirmed ? : "Generating ..."}
    Password
    {handler.is_installed() ? "": } {handler.is_installed() && software_update_url ? : ""} {handler.is_installed() && !software_update_url && handler.is_installed_lower_version() ? : ""} {is_can_screen_recording ? "": } {is_can_screen_recording && !handler.is_process_trusted(false) ? : ""} {system_error ? : ""} {!system_error && handler.is_login_wayland() ? : ""}
    Control Remote Desktop
    ; } event click $(button#connect) { this.newRemote("connect"); } event click $(button#file-transfer) { this.newRemote("file-transfer"); } function newRemote(type) { createNewConnect(this.remote_id.value, type); } } class InstalllMe: Reactor.Component { function render() { return
    Install RustDesk
    Install RustDesk on this computer ...
    ; } event click $(#install-me) { handler.goto_install(); } } const http = function() { function makeRequest(httpverb) { return function( params ) { params.type = httpverb; view.request(params); }; } function download(from, to, args..) { var rqp = { type:#get, url: from, toFile: to }; var fn = 0; var on = 0; for( var p in args ) if( p instanceof Function ) { switch(++fn) { case 1: rqp.success = p; break; case 2: rqp.error = p; break; case 3: rqp.progress = p; break; } } else if( p instanceof Object ) { switch(++on) { case 1: rqp.params = p; break; case 2: rqp.headers = p; break; } } view.request(rqp); } return { get: makeRequest(#get), post: makeRequest(#post), put: makeRequest(#put), del: makeRequest(#delete), download: download }; }(); class UpgradeMe: Reactor.Component { function render() { var update_or_download = is_osx ? "download" : "update"; return
    {handler.get_app_name()} Status
    An update is available for RustDesk.
    Click to upgrade
    ; } event click $(#install-me) { handler.update_me(""); } } class UpdateMe: Reactor.Component { function render() { var update_or_download = is_osx ? "download" : "update"; return
    {handler.get_app_name()} Status
    There is a newer version of {handler.get_app_name()} ({handler.get_new_version()}) available.
    Click to {update_or_download}
    ; } event click $(#install-me) { if (is_osx) { handler.open_url("https://rustdesk.com"); return; } var url = software_update_url + '.' + handler.get_software_ext(); var path = handler.get_software_store_path(); var onsuccess = function(md5) { $(#download-percent).content("Installing ..."); handler.update_me(path); }; var onerror = function(err) { handler.msgbox("custom-error", "Download Error", "Failed to download"); }; var onprogress = function(loaded, total) { if (!total) total = 5 * 1024 * 1024; var el = $(#download-percent); el.style.set{display: "block"}; el.content("Downloading %" + (loaded * 100 / total)); }; stdout.println("Downloading " + url + " to " + path); http.download( url, self.url(path), onsuccess, onerror, onprogress); } } class SystemError: Reactor.Component { function render() { return
    {system_error}
    ; } } class TrustMe: Reactor.Component { function render() { return
    Configuration Permissions
    In order to control your Desktop remotely, you need to grant RustDesk "Accessibility" permissions
    Configure
    ; } event click $(#trust-me) { handler.is_process_trusted(true); watch_trust(); } } class CanScreenRecording: Reactor.Component { function render() { return
    Configuration Permissions
    In order to access your Desktop remotely, you need to grant RustDesk "Screen Recording" permissions
    Configure
    ; } event click $(#screen-recording) { handler.is_can_screen_recording(true); watch_trust(); } } class FixWayland: Reactor.Component { function render() { return
    Warning
    Login screen using Wayland is not supported
    Fix it
    ; } event click $(#fix-wayland) { handler.fix_login_wayland(); app.update(); } } function watch_trust() { // not use TrustMe::update, because it is buggy var trusted = handler.is_process_trusted(false); var el = $(div.trust-me); if (el) { el.style.set { display: trusted ? "none" : "block", }; } // if (trusted) return; self.timer(1s, watch_trust); } class PasswordEyeArea : Reactor.Component { render() { return
    {svg_eye}
    ; } event mouseenter { var me = this; me.leaved = false; me.timer(300ms, function() { if (me.leaved) return; me.input.value = handler.get_password(); }); } event mouseleave { this.leaved = true; this.input.value = "******"; } } class Password: Reactor.Component { function render() { return
    {svg_edit}
    ; } event click $(svg#edit) (_, me) { var menu = $(menu#edit-password-context); me.popup(menu); } event click $(li#refresh-password) { handler.update_password(""); this.update(); } event click $(li#set-password) { var me = this; handler.msgbox("custom-password", "Set Password", "
    \
    Password:
    \
    Confirmation:
    \
    \ ", function(res=null) { if (!res) return; var p0 = (res.password || "").trim(); var p1 = (res.confirmation || "").trim(); if (p0.length < 6) { return "Too short, at least 6 characters."; } if (p0 != p1) { return "The confirmation is not identical."; } handler.update_password(p0); me.update(); }); } } class ID: Reactor.Component { function render() { return ; } // https://github.com/c-smile/sciter-sdk/blob/master/doc/content/sciter/Event.htm event change { var fid = formatId(this.value); var d = this.value.length - (this.old_value || "").length; this.old_value = this.value; var start = this.xcall(#selectionStart) || 0; var end = this.xcall(#selectionEnd); if (fid == this.value || d <= 0 || start != end) { return; } // fix Caret position this.value = fid; var text_after_caret = this.old_value.substr(start); var n = fid.length - formatId(text_after_caret).length; this.xcall(#setSelection, n, n); } } var reg = /^\d+$/; function formatId(id) { id = id.replace(/\s/g, ""); if (reg.test(id) && id.length > 3) { var n = id.length; var a = n % 3 || 3; var new_id = id.substr(0, a); for (var i = a; i < n; i += 3) { new_id += " " + id.substr(i, 3); } return new_id; } return id; } event keydown (evt) { if (!evt.shortcutKey) { if (evt.keyCode == Event.VK_ENTER || (is_osx && evt.keyCode == 0x4C) || (is_linux && evt.keyCode == 65421)) { var el = $(button#connect); view.focus = el; el.sendEvent("click"); // simulate button click effect, windows does not have this issue el.attributes.toggleClass("active", true); self.timer(0.3s, function() { el.attributes.toggleClass("active", false); }); } } } $(body).content(); function self.closing() { // return false; // can prevent window close var (x, y, w, h) = view.box(#rectw, #border, #screen); handler.save_size(x, y, w, h); } function self.ready() { var r = handler.get_size(); if (r[2] == 0) { centerize(800, 600); } else { view.move(r[0], r[1], r[2], r[3]); } if (!handler.get_remote_id()) { view.focus = $(#remote_id); } } function checkConnectStatus() { self.timer(1s, function() { var tmp = !!handler.get_option("stop-service"); if (tmp != service_stopped) { service_stopped = tmp; app.connect_status.update(); myIdMenu.update(); } tmp = handler.get_connect_status(); if (tmp[0] != connect_status) { connect_status = tmp[0]; app.connect_status.update(); } if (tmp[1] != key_confirmed) { key_confirmed = tmp[1]; app.update(); } tmp = handler.get_error(); if (system_error != tmp) { system_error = tmp; app.update(); } tmp = handler.get_software_update_url(); if (tmp != software_update_url) { software_update_url = tmp; app.update(); } if (handler.recent_sessions_updated()) { stdout.println("recent sessions updated"); app.recent_sessions.update(); } checkConnectStatus(); }); } checkConnectStatus();