2022-05-08 21:01:03 +08:00
|
|
|
|
use std::{
|
|
|
|
|
collections::HashMap,
|
2022-08-31 16:31:31 +08:00
|
|
|
|
ops::{Deref, DerefMut},
|
2023-02-16 20:01:06 +08:00
|
|
|
|
sync::{Arc, Mutex, RwLock},
|
2021-03-29 15:59:14 +08:00
|
|
|
|
};
|
2022-05-08 21:01:03 +08:00
|
|
|
|
|
|
|
|
|
use sciter::{
|
|
|
|
|
dom::{
|
2023-02-13 16:40:24 +08:00
|
|
|
|
event::{EventReason, BEHAVIOR_EVENTS, EVENT_GROUPS, PHASE_MASK},
|
|
|
|
|
Element, HELEMENT,
|
2022-05-08 21:01:03 +08:00
|
|
|
|
},
|
|
|
|
|
make_args,
|
2023-02-13 16:40:24 +08:00
|
|
|
|
video::{video_destination, AssetPtr, COLOR_SPACE},
|
2022-05-08 21:01:03 +08:00
|
|
|
|
Value,
|
|
|
|
|
};
|
|
|
|
|
|
2022-09-05 10:27:33 +08:00
|
|
|
|
use hbb_common::{
|
|
|
|
|
allow_err, fs::TransferJobMeta, log, message_proto::*, rendezvous_proto::ConnType,
|
|
|
|
|
};
|
2022-05-08 21:01:03 +08:00
|
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
|
client::*,
|
2022-09-07 03:52:31 -04:00
|
|
|
|
ui_session_interface::{InvokeUiSession, Session},
|
2021-03-29 15:59:14 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
type Video = AssetPtr<video_destination>;
|
|
|
|
|
|
|
|
|
|
lazy_static::lazy_static! {
|
|
|
|
|
static ref VIDEO: Arc<Mutex<Option<Video>>> = Default::default();
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-31 16:31:31 +08:00
|
|
|
|
/// SciterHandler
|
|
|
|
|
/// * element
|
|
|
|
|
/// * close_state for file path when close
|
|
|
|
|
#[derive(Clone, Default)]
|
|
|
|
|
pub struct SciterHandler {
|
|
|
|
|
element: Arc<Mutex<Option<Element>>>,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
close_state: HashMap<String, String>,
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-31 16:31:31 +08:00
|
|
|
|
impl SciterHandler {
|
|
|
|
|
#[inline]
|
|
|
|
|
fn call(&self, func: &str, args: &[Value]) {
|
|
|
|
|
if let Some(ref e) = self.element.lock().unwrap().as_ref() {
|
|
|
|
|
allow_err!(e.call_method(func, args));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn call2(&self, func: &str, args: &[Value]) {
|
|
|
|
|
if let Some(ref e) = self.element.lock().unwrap().as_ref() {
|
|
|
|
|
allow_err!(e.call_method(func, &super::value_crash_workaround(args)[..]));
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-02-17 13:32:17 +08:00
|
|
|
|
|
|
|
|
|
fn make_displays_array(displays: &Vec<DisplayInfo>) -> Value {
|
|
|
|
|
let mut displays_value = Value::array(0);
|
|
|
|
|
for d in displays.iter() {
|
|
|
|
|
let mut display = Value::map();
|
|
|
|
|
display.set_item("x", d.x);
|
|
|
|
|
display.set_item("y", d.y);
|
|
|
|
|
display.set_item("width", d.width);
|
|
|
|
|
display.set_item("height", d.height);
|
|
|
|
|
display.set_item("cursor_embedded", d.cursor_embedded);
|
|
|
|
|
displays_value.push(display);
|
|
|
|
|
}
|
|
|
|
|
displays_value
|
|
|
|
|
}
|
2022-08-31 16:31:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-09-05 19:41:09 +08:00
|
|
|
|
impl InvokeUiSession for SciterHandler {
|
2022-08-31 16:31:31 +08:00
|
|
|
|
fn set_cursor_data(&self, cd: CursorData) {
|
|
|
|
|
let mut colors = hbb_common::compress::decompress(&cd.colors);
|
|
|
|
|
if colors.iter().filter(|x| **x != 0).next().is_none() {
|
|
|
|
|
log::info!("Fix transparent");
|
|
|
|
|
// somehow all 0 images shows black rect, here is a workaround
|
|
|
|
|
colors[3] = 1;
|
|
|
|
|
}
|
|
|
|
|
let mut png = Vec::new();
|
|
|
|
|
if let Ok(()) = repng::encode(&mut png, cd.width as _, cd.height as _, &colors) {
|
|
|
|
|
self.call(
|
|
|
|
|
"setCursorData",
|
|
|
|
|
&make_args!(
|
|
|
|
|
cd.id.to_string(),
|
|
|
|
|
cd.hotx,
|
|
|
|
|
cd.hoty,
|
|
|
|
|
cd.width,
|
|
|
|
|
cd.height,
|
|
|
|
|
&png[..]
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-31 21:41:16 +08:00
|
|
|
|
fn set_display(&self, x: i32, y: i32, w: i32, h: i32, cursor_embedded: bool) {
|
|
|
|
|
self.call("setDisplay", &make_args!(x, y, w, h, cursor_embedded));
|
2022-09-01 16:21:41 +08:00
|
|
|
|
// https://sciter.com/forums/topic/color_spaceiyuv-crash
|
|
|
|
|
// Nothing spectacular in decoder – done on CPU side.
|
|
|
|
|
// So if you can do BGRA translation on your side – the better.
|
|
|
|
|
// BGRA is used as internal image format so it will not require additional transformations.
|
2022-08-31 20:46:30 +08:00
|
|
|
|
VIDEO.lock().unwrap().as_mut().map(|v| {
|
|
|
|
|
v.stop_streaming().ok();
|
|
|
|
|
let ok = v.start_streaming((w, h), COLOR_SPACE::Rgb32, None);
|
|
|
|
|
log::info!("[video] reinitialized: {:?}", ok);
|
|
|
|
|
});
|
2022-08-31 16:31:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn update_privacy_mode(&self) {
|
|
|
|
|
self.call("updatePrivacyMode", &[]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_permission(&self, name: &str, value: bool) {
|
|
|
|
|
self.call2("setPermission", &make_args!(name, value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn close_success(&self) {
|
|
|
|
|
self.call2("closeSuccess", &make_args!());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn update_quality_status(&self, status: QualityStatus) {
|
|
|
|
|
self.call2(
|
|
|
|
|
"updateQualityStatus",
|
|
|
|
|
&make_args!(
|
|
|
|
|
status.speed.map_or(Value::null(), |it| it.into()),
|
2023-10-08 21:44:54 +08:00
|
|
|
|
status
|
|
|
|
|
.fps
|
|
|
|
|
.iter()
|
|
|
|
|
.next()
|
|
|
|
|
.map_or(Value::null(), |(_, v)| (*v).into()),
|
2022-08-31 16:31:31 +08:00
|
|
|
|
status.delay.map_or(Value::null(), |it| it.into()),
|
|
|
|
|
status.target_bitrate.map_or(Value::null(), |it| it.into()),
|
|
|
|
|
status
|
|
|
|
|
.codec_format
|
2023-10-27 15:44:07 +08:00
|
|
|
|
.map_or(Value::null(), |it| it.to_string().into()),
|
|
|
|
|
status.chroma.map_or(Value::null(), |it| it.into())
|
2022-08-31 16:31:31 +08:00
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_cursor_id(&self, id: String) {
|
|
|
|
|
self.call("setCursorId", &make_args!(id));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_cursor_position(&self, cp: CursorPosition) {
|
|
|
|
|
self.call("setCursorPosition", &make_args!(cp.x, cp.y));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_connection_type(&self, is_secured: bool, direct: bool) {
|
|
|
|
|
self.call("setConnectionType", &make_args!(is_secured, direct));
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-19 14:39:22 +08:00
|
|
|
|
fn set_fingerprint(&self, _fingerprint: String) {}
|
|
|
|
|
|
2022-08-31 16:31:31 +08:00
|
|
|
|
fn job_error(&self, id: i32, err: String, file_num: i32) {
|
2022-09-01 09:48:53 +08:00
|
|
|
|
self.call("jobError", &make_args!(id, err, file_num));
|
2022-08-31 16:31:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn job_done(&self, id: i32, file_num: i32) {
|
2022-09-01 09:48:53 +08:00
|
|
|
|
self.call("jobDone", &make_args!(id, file_num));
|
2022-08-31 16:31:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn clear_all_jobs(&self) {
|
2022-09-01 09:48:53 +08:00
|
|
|
|
self.call("clearAllJobs", &make_args!());
|
2022-08-31 16:31:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-09-05 10:27:33 +08:00
|
|
|
|
fn load_last_job(&self, cnt: i32, job_json: &str) {
|
|
|
|
|
let job: Result<TransferJobMeta, serde_json::Error> = serde_json::from_str(job_json);
|
|
|
|
|
if let Ok(job) = job {
|
|
|
|
|
let path;
|
|
|
|
|
let to;
|
|
|
|
|
if job.is_remote {
|
|
|
|
|
path = job.remote.clone();
|
|
|
|
|
to = job.to.clone();
|
|
|
|
|
} else {
|
|
|
|
|
path = job.to.clone();
|
|
|
|
|
to = job.remote.clone();
|
|
|
|
|
}
|
|
|
|
|
self.call(
|
|
|
|
|
"addJob",
|
|
|
|
|
&make_args!(cnt, path, to, job.file_num, job.show_hidden, job.is_remote),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn update_folder_files(
|
2022-08-31 16:31:31 +08:00
|
|
|
|
&self,
|
|
|
|
|
id: i32,
|
2022-09-05 10:27:33 +08:00
|
|
|
|
entries: &Vec<FileEntry>,
|
2022-08-31 16:31:31 +08:00
|
|
|
|
path: String,
|
2022-09-05 10:27:33 +08:00
|
|
|
|
_is_local: bool,
|
|
|
|
|
only_count: bool,
|
2022-08-31 16:31:31 +08:00
|
|
|
|
) {
|
2022-09-05 10:27:33 +08:00
|
|
|
|
let mut m = make_fd(id, entries, only_count);
|
|
|
|
|
m.set_item("path", path);
|
|
|
|
|
self.call("updateFolderFiles", &make_args!(m));
|
2022-08-31 16:31:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn update_transfer_list(&self) {
|
2022-09-01 09:48:53 +08:00
|
|
|
|
self.call("updateTransferList", &make_args!());
|
2022-08-31 16:31:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn confirm_delete_files(&self, id: i32, i: i32, name: String) {
|
2022-09-01 09:48:53 +08:00
|
|
|
|
self.call("confirmDeleteFiles", &make_args!(id, i, name));
|
2022-08-31 16:31:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-03-31 16:10:52 +08:00
|
|
|
|
fn override_file_confirm(
|
|
|
|
|
&self,
|
|
|
|
|
id: i32,
|
|
|
|
|
file_num: i32,
|
|
|
|
|
to: String,
|
|
|
|
|
is_upload: bool,
|
|
|
|
|
is_identical: bool,
|
|
|
|
|
) {
|
2022-09-01 09:48:53 +08:00
|
|
|
|
self.call(
|
|
|
|
|
"overrideFileConfirm",
|
2023-03-15 17:18:59 +08:00
|
|
|
|
&make_args!(id, file_num, to, is_upload, is_identical),
|
2022-09-01 09:48:53 +08:00
|
|
|
|
);
|
2022-08-31 16:31:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn job_progress(&self, id: i32, file_num: i32, speed: f64, finished_size: f64) {
|
2022-09-01 09:48:53 +08:00
|
|
|
|
self.call(
|
|
|
|
|
"jobProgress",
|
|
|
|
|
&make_args!(id, file_num, speed, finished_size),
|
|
|
|
|
);
|
2022-08-31 16:31:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn adapt_size(&self) {
|
|
|
|
|
self.call("adaptSize", &make_args!());
|
|
|
|
|
}
|
2022-08-31 20:46:30 +08:00
|
|
|
|
|
2023-10-08 21:44:54 +08:00
|
|
|
|
fn on_rgba(&self, _display: usize, rgba: &mut scrap::ImageRgb) {
|
2022-08-31 20:46:30 +08:00
|
|
|
|
VIDEO
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.as_mut()
|
2023-04-28 12:03:44 +08:00
|
|
|
|
.map(|v| v.render_frame(&rgba.raw).ok());
|
2022-08-31 20:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-09-01 16:21:41 +08:00
|
|
|
|
fn set_peer_info(&self, pi: &PeerInfo) {
|
|
|
|
|
let mut pi_sciter = Value::map();
|
|
|
|
|
pi_sciter.set_item("username", pi.username.clone());
|
|
|
|
|
pi_sciter.set_item("hostname", pi.hostname.clone());
|
|
|
|
|
pi_sciter.set_item("platform", pi.platform.clone());
|
|
|
|
|
pi_sciter.set_item("sas_enabled", pi.sas_enabled);
|
2023-02-17 13:32:17 +08:00
|
|
|
|
pi_sciter.set_item("displays", Self::make_displays_array(&pi.displays));
|
2022-09-01 16:21:41 +08:00
|
|
|
|
pi_sciter.set_item("current_display", pi.current_display);
|
2023-10-18 22:39:28 +08:00
|
|
|
|
pi_sciter.set_item("version", pi.version.clone());
|
2022-09-01 16:21:41 +08:00
|
|
|
|
self.call("updatePi", &make_args!(pi_sciter));
|
2022-08-31 20:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-02-17 13:32:17 +08:00
|
|
|
|
fn set_displays(&self, displays: &Vec<DisplayInfo>) {
|
|
|
|
|
self.call(
|
|
|
|
|
"updateDisplays",
|
|
|
|
|
&make_args!(Self::make_displays_array(displays)),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-27 16:19:42 +08:00
|
|
|
|
fn set_platform_additions(&self, _data: &str) {
|
|
|
|
|
// Ignore for sciter version.
|
|
|
|
|
}
|
|
|
|
|
|
refactor windows specific session (#7170)
1. Modify the process to have the control side lead the session switching: After the control side sends a `LoginRequest`, the controlled side will add all session information and the current session ID in the `LoginResponse`. Upon receiving the `LoginResponse`, the control side will check if the current session ID matches the ID in the `LoginConfigHandler`. If they match, the control side will send the current session ID. If they don't match, a session selection dialog will pop up, the selected session id will be sent. Upon receiving this message, the controlled side will restart if different or sub service if same .
2. Always show physical console session on the top
3. Show running session and distinguish sessions with the same name
4. Not sub service until correct session id is ensured
5. Fix switch sides not work for multisession session
6. Remove all session string join/split except get_available_sessions in
windows.rs
7. Fix prelogin, when share rdp is enabled and there is a rdp session,
the console is in login screen, get_active_username will be the rdp's
username and prelogin will be false, cm can't be created an that
causes disconnection in a loop
8. Rename all user session to windows session
Known issue:
1. Use current process session id for `run_as_user`, sahil says it can
be wrong but I didn't reproduce.
2. Have not change tray process to current session
3. File transfer doesn't update home directory when session changed
4. When it's in login screen, remote file directory is empty, because cm
have not start up
Signed-off-by: 21pages <pages21@163.com>
2024-02-18 22:08:25 +08:00
|
|
|
|
fn set_multiple_windows_session(&self, sessions: Vec<WindowsSession>) {
|
|
|
|
|
let mut v = Value::array(0);
|
|
|
|
|
let mut sessions = sessions;
|
|
|
|
|
for s in sessions.drain(..) {
|
|
|
|
|
let mut obj = Value::map();
|
|
|
|
|
obj.set_item("sid", s.sid.to_string());
|
|
|
|
|
obj.set_item("name", s.name);
|
|
|
|
|
v.push(obj);
|
|
|
|
|
}
|
|
|
|
|
self.call("setMultipleWindowsSession", &make_args!(v));
|
|
|
|
|
}
|
2024-02-14 21:29:17 +05:30
|
|
|
|
|
2022-12-09 21:16:09 +08:00
|
|
|
|
fn on_connected(&self, conn_type: ConnType) {
|
|
|
|
|
match conn_type {
|
2022-12-18 16:17:10 +08:00
|
|
|
|
ConnType::RDP => {}
|
|
|
|
|
ConnType::PORT_FORWARD => {}
|
|
|
|
|
ConnType::FILE_TRANSFER => {}
|
2022-12-09 21:16:09 +08:00
|
|
|
|
ConnType::DEFAULT_CONN => {
|
|
|
|
|
crate::keyboard::client::start_grab_loop();
|
2022-12-18 16:17:10 +08:00
|
|
|
|
}
|
2022-12-09 21:16:09 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-14 11:19:49 +08:00
|
|
|
|
fn msgbox(&self, msgtype: &str, title: &str, text: &str, link: &str, retry: bool) {
|
2022-11-15 16:49:55 +08:00
|
|
|
|
self.call2(
|
|
|
|
|
"msgbox_retry",
|
|
|
|
|
&make_args!(msgtype, title, text, link, retry),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn cancel_msgbox(&self, tag: &str) {
|
|
|
|
|
self.call("cancel_msgbox", &make_args!(tag));
|
2022-09-01 09:48:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn new_message(&self, msg: String) {
|
|
|
|
|
self.call("newMessage", &make_args!(msg));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn switch_display(&self, display: &SwitchDisplay) {
|
|
|
|
|
self.call("switchDisplay", &make_args!(display.display));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn update_block_input_state(&self, on: bool) {
|
|
|
|
|
self.call("updateBlockInputState", &make_args!(on));
|
2022-08-31 20:46:30 +08:00
|
|
|
|
}
|
2023-01-17 13:28:33 +08:00
|
|
|
|
|
|
|
|
|
fn switch_back(&self, _id: &str) {}
|
2023-02-06 11:42:25 +08:00
|
|
|
|
|
2023-02-24 15:51:13 +08:00
|
|
|
|
fn portable_service_running(&self, _running: bool) {}
|
|
|
|
|
|
2023-02-06 15:36:36 +08:00
|
|
|
|
fn on_voice_call_started(&self) {
|
2023-02-06 11:42:25 +08:00
|
|
|
|
self.call("onVoiceCallStart", &make_args!());
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-06 12:14:20 +08:00
|
|
|
|
fn on_voice_call_closed(&self, reason: &str) {
|
|
|
|
|
self.call("onVoiceCallClosed", &make_args!(reason));
|
2023-02-06 11:42:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn on_voice_call_waiting(&self) {
|
|
|
|
|
self.call("onVoiceCallWaiting", &make_args!());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn on_voice_call_incoming(&self) {
|
|
|
|
|
self.call("onVoiceCallIncoming", &make_args!());
|
|
|
|
|
}
|
2023-02-11 09:57:27 +08:00
|
|
|
|
|
|
|
|
|
/// RGBA is directly rendered by [on_rgba]. No need to store the rgba for the sciter ui.
|
2023-10-08 21:44:54 +08:00
|
|
|
|
fn get_rgba(&self, _display: usize) -> *const u8 {
|
2023-02-13 16:40:24 +08:00
|
|
|
|
std::ptr::null()
|
|
|
|
|
}
|
2023-02-12 10:28:04 +08:00
|
|
|
|
|
2023-10-08 21:44:54 +08:00
|
|
|
|
fn next_rgba(&self, _display: usize) {}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-08-31 16:31:31 +08:00
|
|
|
|
pub struct SciterSession(Session<SciterHandler>);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
|
2022-08-31 16:31:31 +08:00
|
|
|
|
impl Deref for SciterSession {
|
|
|
|
|
type Target = Session<SciterHandler>;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn deref(&self) -> &Self::Target {
|
2022-08-31 16:31:31 +08:00
|
|
|
|
&self.0
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-31 16:31:31 +08:00
|
|
|
|
impl DerefMut for SciterSession {
|
|
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
|
|
&mut self.0
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-05-12 17:35:25 +08:00
|
|
|
|
|
2022-08-31 16:31:31 +08:00
|
|
|
|
impl sciter::EventHandler for SciterSession {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn get_subscription(&mut self) -> Option<EVENT_GROUPS> {
|
|
|
|
|
Some(EVENT_GROUPS::HANDLE_BEHAVIOR_EVENT)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn attached(&mut self, root: HELEMENT) {
|
2022-08-31 16:31:31 +08:00
|
|
|
|
*self.element.lock().unwrap() = Some(Element::from(root));
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn detached(&mut self, _root: HELEMENT) {
|
2022-08-31 16:31:31 +08:00
|
|
|
|
*self.element.lock().unwrap() = None;
|
|
|
|
|
self.sender.write().unwrap().take().map(|sender| {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
sender.send(Data::Close).ok();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// https://github.com/sciter-sdk/rust-sciter/blob/master/examples/video.rs
|
|
|
|
|
fn on_event(
|
|
|
|
|
&mut self,
|
|
|
|
|
_root: HELEMENT,
|
|
|
|
|
source: HELEMENT,
|
|
|
|
|
_target: HELEMENT,
|
|
|
|
|
code: BEHAVIOR_EVENTS,
|
|
|
|
|
phase: PHASE_MASK,
|
|
|
|
|
reason: EventReason,
|
|
|
|
|
) -> bool {
|
|
|
|
|
if phase != PHASE_MASK::BUBBLING {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
match code {
|
|
|
|
|
BEHAVIOR_EVENTS::VIDEO_BIND_RQ => {
|
|
|
|
|
let source = Element::from(source);
|
|
|
|
|
log::debug!("[video] {:?} {} ({:?})", code, source, reason);
|
|
|
|
|
if let EventReason::VideoBind(ptr) = reason {
|
|
|
|
|
if ptr.is_null() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
let site = AssetPtr::adopt(ptr as *mut video_destination);
|
|
|
|
|
log::debug!("[video] start video");
|
|
|
|
|
*VIDEO.lock().unwrap() = Some(site);
|
refactor windows specific session (#7170)
1. Modify the process to have the control side lead the session switching: After the control side sends a `LoginRequest`, the controlled side will add all session information and the current session ID in the `LoginResponse`. Upon receiving the `LoginResponse`, the control side will check if the current session ID matches the ID in the `LoginConfigHandler`. If they match, the control side will send the current session ID. If they don't match, a session selection dialog will pop up, the selected session id will be sent. Upon receiving this message, the controlled side will restart if different or sub service if same .
2. Always show physical console session on the top
3. Show running session and distinguish sessions with the same name
4. Not sub service until correct session id is ensured
5. Fix switch sides not work for multisession session
6. Remove all session string join/split except get_available_sessions in
windows.rs
7. Fix prelogin, when share rdp is enabled and there is a rdp session,
the console is in login screen, get_active_username will be the rdp's
username and prelogin will be false, cm can't be created an that
causes disconnection in a loop
8. Rename all user session to windows session
Known issue:
1. Use current process session id for `run_as_user`, sahil says it can
be wrong but I didn't reproduce.
2. Have not change tray process to current session
3. File transfer doesn't update home directory when session changed
4. When it's in login screen, remote file directory is empty, because cm
have not start up
Signed-off-by: 21pages <pages21@163.com>
2024-02-18 22:08:25 +08:00
|
|
|
|
self.reconnect(false);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BEHAVIOR_EVENTS::VIDEO_INITIALIZED => {
|
|
|
|
|
log::debug!("[video] {:?}", code);
|
|
|
|
|
}
|
|
|
|
|
BEHAVIOR_EVENTS::VIDEO_STARTED => {
|
|
|
|
|
log::debug!("[video] {:?}", code);
|
|
|
|
|
let source = Element::from(source);
|
|
|
|
|
use sciter::dom::ELEMENT_AREAS;
|
|
|
|
|
let flags = ELEMENT_AREAS::CONTENT_BOX as u32 | ELEMENT_AREAS::SELF_RELATIVE as u32;
|
2023-07-22 14:16:41 +08:00
|
|
|
|
let rc = source.get_location(flags).unwrap_or_default();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
log::debug!(
|
|
|
|
|
"[video] start video thread on <{}> which is about {:?} pixels",
|
|
|
|
|
source,
|
|
|
|
|
rc.size()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
BEHAVIOR_EVENTS::VIDEO_STOPPED => {
|
|
|
|
|
log::debug!("[video] {:?}", code);
|
|
|
|
|
}
|
|
|
|
|
_ => return false,
|
|
|
|
|
};
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sciter::dispatch_script_call! {
|
2022-12-18 16:17:10 +08:00
|
|
|
|
fn get_audit_server(String);
|
2022-05-12 17:35:25 +08:00
|
|
|
|
fn send_note(String);
|
2021-05-02 21:19:48 +08:00
|
|
|
|
fn is_xfce();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn get_id();
|
|
|
|
|
fn get_default_pi();
|
|
|
|
|
fn get_option(String);
|
2021-12-25 16:45:22 +08:00
|
|
|
|
fn t(String);
|
|
|
|
|
fn set_option(String, String);
|
2022-05-12 17:35:25 +08:00
|
|
|
|
fn input_os_password(String, bool);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn save_close_state(String, String);
|
|
|
|
|
fn is_file_transfer();
|
|
|
|
|
fn is_port_forward();
|
|
|
|
|
fn is_rdp();
|
2023-03-22 17:01:11 +08:00
|
|
|
|
fn login(String, String, String, bool);
|
2024-01-19 19:29:04 +08:00
|
|
|
|
fn send2fa(String);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn new_rdp();
|
|
|
|
|
fn send_mouse(i32, i32, i32, bool, bool, bool, bool);
|
2023-09-17 13:41:00 +08:00
|
|
|
|
fn enter(String);
|
|
|
|
|
fn leave(String);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn ctrl_alt_del();
|
|
|
|
|
fn transfer_file();
|
|
|
|
|
fn tunnel();
|
|
|
|
|
fn lock_screen();
|
refactor windows specific session (#7170)
1. Modify the process to have the control side lead the session switching: After the control side sends a `LoginRequest`, the controlled side will add all session information and the current session ID in the `LoginResponse`. Upon receiving the `LoginResponse`, the control side will check if the current session ID matches the ID in the `LoginConfigHandler`. If they match, the control side will send the current session ID. If they don't match, a session selection dialog will pop up, the selected session id will be sent. Upon receiving this message, the controlled side will restart if different or sub service if same .
2. Always show physical console session on the top
3. Show running session and distinguish sessions with the same name
4. Not sub service until correct session id is ensured
5. Fix switch sides not work for multisession session
6. Remove all session string join/split except get_available_sessions in
windows.rs
7. Fix prelogin, when share rdp is enabled and there is a rdp session,
the console is in login screen, get_active_username will be the rdp's
username and prelogin will be false, cm can't be created an that
causes disconnection in a loop
8. Rename all user session to windows session
Known issue:
1. Use current process session id for `run_as_user`, sahil says it can
be wrong but I didn't reproduce.
2. Have not change tray process to current session
3. File transfer doesn't update home directory when session changed
4. When it's in login screen, remote file directory is empty, because cm
have not start up
Signed-off-by: 21pages <pages21@163.com>
2024-02-18 22:08:25 +08:00
|
|
|
|
fn reconnect(bool);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn get_chatbox();
|
|
|
|
|
fn get_icon();
|
|
|
|
|
fn get_home_dir();
|
|
|
|
|
fn read_dir(String, bool);
|
|
|
|
|
fn remove_dir(i32, String, bool);
|
|
|
|
|
fn create_dir(i32, String, bool);
|
|
|
|
|
fn remove_file(i32, String, i32, bool);
|
|
|
|
|
fn read_remote_dir(String, bool);
|
|
|
|
|
fn send_chat(String);
|
|
|
|
|
fn switch_display(i32);
|
2022-07-01 11:26:32 +08:00
|
|
|
|
fn remove_dir_all(i32, String, bool, bool);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn confirm_delete_files(i32, i32);
|
|
|
|
|
fn set_no_confirm(i32);
|
|
|
|
|
fn cancel_job(i32);
|
2022-05-13 11:23:30 +08:00
|
|
|
|
fn send_files(i32, String, String, i32, bool, bool);
|
2022-05-14 11:58:47 +08:00
|
|
|
|
fn add_job(i32, String, String, i32, bool, bool);
|
|
|
|
|
fn resume_job(i32, bool);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn get_platform(bool);
|
|
|
|
|
fn get_path_sep(bool);
|
|
|
|
|
fn get_icon_path(i32, String);
|
|
|
|
|
fn get_char(String, i32);
|
|
|
|
|
fn get_size();
|
|
|
|
|
fn get_port_forwards();
|
|
|
|
|
fn remove_port_forward(i32);
|
|
|
|
|
fn get_args();
|
|
|
|
|
fn add_port_forward(i32, String, i32);
|
|
|
|
|
fn save_size(i32, i32, i32, i32);
|
|
|
|
|
fn get_view_style();
|
|
|
|
|
fn get_image_quality();
|
|
|
|
|
fn get_custom_image_quality();
|
|
|
|
|
fn save_view_style(String);
|
|
|
|
|
fn save_image_quality(String);
|
2022-06-23 17:42:30 +08:00
|
|
|
|
fn save_custom_image_quality(i32);
|
2023-10-08 23:32:11 +08:00
|
|
|
|
fn refresh_video(i32);
|
2023-10-08 21:44:54 +08:00
|
|
|
|
fn record_screen(bool, i32, i32, i32);
|
2023-08-07 21:32:36 +08:00
|
|
|
|
fn record_status(bool);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn get_toggle_option(String);
|
2022-04-25 12:28:28 +08:00
|
|
|
|
fn is_privacy_mode_supported();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn toggle_option(String);
|
|
|
|
|
fn get_remember();
|
2022-04-17 23:35:53 +08:00
|
|
|
|
fn peer_platform();
|
2022-04-28 18:09:06 +08:00
|
|
|
|
fn set_write_override(i32, i32, bool, bool, bool);
|
2022-07-23 20:51:01 +08:00
|
|
|
|
fn get_keyboard_mode();
|
|
|
|
|
fn save_keyboard_mode(String);
|
2023-03-31 16:10:52 +08:00
|
|
|
|
fn alternative_codecs();
|
2022-07-09 20:17:10 +08:00
|
|
|
|
fn change_prefer_codec();
|
2022-07-25 19:35:15 +08:00
|
|
|
|
fn restart_remote_device();
|
2023-02-05 23:47:06 +08:00
|
|
|
|
fn request_voice_call();
|
|
|
|
|
fn close_voice_call();
|
2023-10-18 22:39:28 +08:00
|
|
|
|
fn version_cmp(String, String);
|
refactor windows specific session (#7170)
1. Modify the process to have the control side lead the session switching: After the control side sends a `LoginRequest`, the controlled side will add all session information and the current session ID in the `LoginResponse`. Upon receiving the `LoginResponse`, the control side will check if the current session ID matches the ID in the `LoginConfigHandler`. If they match, the control side will send the current session ID. If they don't match, a session selection dialog will pop up, the selected session id will be sent. Upon receiving this message, the controlled side will restart if different or sub service if same .
2. Always show physical console session on the top
3. Show running session and distinguish sessions with the same name
4. Not sub service until correct session id is ensured
5. Fix switch sides not work for multisession session
6. Remove all session string join/split except get_available_sessions in
windows.rs
7. Fix prelogin, when share rdp is enabled and there is a rdp session,
the console is in login screen, get_active_username will be the rdp's
username and prelogin will be false, cm can't be created an that
causes disconnection in a loop
8. Rename all user session to windows session
Known issue:
1. Use current process session id for `run_as_user`, sahil says it can
be wrong but I didn't reproduce.
2. Have not change tray process to current session
3. File transfer doesn't update home directory when session changed
4. When it's in login screen, remote file directory is empty, because cm
have not start up
Signed-off-by: 21pages <pages21@163.com>
2024-02-18 22:08:25 +08:00
|
|
|
|
fn set_selected_windows_session_id(String);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-31 16:31:31 +08:00
|
|
|
|
impl SciterSession {
|
2022-07-27 00:31:20 +08:00
|
|
|
|
pub fn new(cmd: String, id: String, password: String, args: Vec<String>) -> Self {
|
2023-02-26 11:23:43 +08:00
|
|
|
|
let force_relay = args.contains(&"--relay".to_string());
|
2023-11-06 20:12:01 +08:00
|
|
|
|
let mut session: Session<SciterHandler> = Session {
|
2022-07-27 00:31:20 +08:00
|
|
|
|
password: password.clone(),
|
2021-03-29 15:59:14 +08:00
|
|
|
|
args,
|
2023-02-16 20:01:06 +08:00
|
|
|
|
server_keyboard_enabled: Arc::new(RwLock::new(true)),
|
|
|
|
|
server_file_transfer_enabled: Arc::new(RwLock::new(true)),
|
|
|
|
|
server_clipboard_enabled: Arc::new(RwLock::new(true)),
|
2021-03-29 15:59:14 +08:00
|
|
|
|
..Default::default()
|
|
|
|
|
};
|
|
|
|
|
|
2022-09-01 17:36:37 +08:00
|
|
|
|
let conn_type = if cmd.eq("--file-transfer") {
|
|
|
|
|
ConnType::FILE_TRANSFER
|
|
|
|
|
} else if cmd.eq("--port-forward") {
|
|
|
|
|
ConnType::PORT_FORWARD
|
|
|
|
|
} else if cmd.eq("--rdp") {
|
|
|
|
|
ConnType::RDP
|
|
|
|
|
} else {
|
|
|
|
|
ConnType::DEFAULT_CONN
|
|
|
|
|
};
|
2021-03-29 15:59:14 +08:00
|
|
|
|
|
2023-02-13 16:40:24 +08:00
|
|
|
|
session
|
|
|
|
|
.lc
|
|
|
|
|
.write()
|
|
|
|
|
.unwrap()
|
2024-01-02 16:58:10 +08:00
|
|
|
|
.initialize(id, conn_type, None, force_relay, None);
|
2022-07-23 20:51:01 +08:00
|
|
|
|
|
2022-09-01 17:36:37 +08:00
|
|
|
|
Self(session)
|
2022-07-23 20:51:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-12-09 21:16:09 +08:00
|
|
|
|
pub fn inner(&self) -> Session<SciterHandler> {
|
|
|
|
|
self.0.clone()
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn get_custom_image_quality(&mut self) -> Value {
|
|
|
|
|
let mut v = Value::array(0);
|
|
|
|
|
for x in self.lc.read().unwrap().custom_image_quality.iter() {
|
|
|
|
|
v.push(x);
|
|
|
|
|
}
|
|
|
|
|
v
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-05 19:41:09 +08:00
|
|
|
|
pub fn t(&self, name: String) -> String {
|
|
|
|
|
crate::client::translate(name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_icon(&self) -> String {
|
2023-02-11 00:21:19 +08:00
|
|
|
|
super::get_icon()
|
2022-09-05 19:41:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-03-31 16:10:52 +08:00
|
|
|
|
fn alternative_codecs(&self) -> Value {
|
2023-05-08 20:35:24 +08:00
|
|
|
|
let (vp8, av1, h264, h265) = self.0.alternative_codecs();
|
2022-09-16 19:43:28 +08:00
|
|
|
|
let mut v = Value::array(0);
|
2023-03-31 16:10:52 +08:00
|
|
|
|
v.push(vp8);
|
2023-05-08 20:35:24 +08:00
|
|
|
|
v.push(av1);
|
2022-09-16 19:43:28 +08:00
|
|
|
|
v.push(h264);
|
|
|
|
|
v.push(h265);
|
|
|
|
|
v
|
2022-07-09 20:17:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn save_size(&mut self, x: i32, y: i32, w: i32, h: i32) {
|
|
|
|
|
let size = (x, y, w, h);
|
|
|
|
|
let mut config = self.load_config();
|
|
|
|
|
if self.is_file_transfer() {
|
2022-08-31 16:31:31 +08:00
|
|
|
|
let close_state = self.close_state.clone();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let mut has_change = false;
|
2022-04-07 22:13:30 +08:00
|
|
|
|
for (k, mut v) in close_state {
|
|
|
|
|
if k == "remote_dir" {
|
|
|
|
|
v = self.lc.read().unwrap().get_all_remote_dir(v);
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let v2 = if v.is_empty() { None } else { Some(&v) };
|
|
|
|
|
if v2 != config.options.get(&k) {
|
|
|
|
|
has_change = true;
|
|
|
|
|
if v2.is_none() {
|
|
|
|
|
config.options.remove(&k);
|
|
|
|
|
} else {
|
|
|
|
|
config.options.insert(k, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if size == config.size_ft && !has_change {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
config.size_ft = size;
|
|
|
|
|
} else if self.is_port_forward() {
|
|
|
|
|
if size == config.size_pf {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
config.size_pf = size;
|
|
|
|
|
} else {
|
|
|
|
|
if size == config.size {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
config.size = size;
|
|
|
|
|
}
|
|
|
|
|
self.save_config(config);
|
|
|
|
|
log::info!("size saved");
|
|
|
|
|
}
|
|
|
|
|
|
refactor windows specific session (#7170)
1. Modify the process to have the control side lead the session switching: After the control side sends a `LoginRequest`, the controlled side will add all session information and the current session ID in the `LoginResponse`. Upon receiving the `LoginResponse`, the control side will check if the current session ID matches the ID in the `LoginConfigHandler`. If they match, the control side will send the current session ID. If they don't match, a session selection dialog will pop up, the selected session id will be sent. Upon receiving this message, the controlled side will restart if different or sub service if same .
2. Always show physical console session on the top
3. Show running session and distinguish sessions with the same name
4. Not sub service until correct session id is ensured
5. Fix switch sides not work for multisession session
6. Remove all session string join/split except get_available_sessions in
windows.rs
7. Fix prelogin, when share rdp is enabled and there is a rdp session,
the console is in login screen, get_active_username will be the rdp's
username and prelogin will be false, cm can't be created an that
causes disconnection in a loop
8. Rename all user session to windows session
Known issue:
1. Use current process session id for `run_as_user`, sahil says it can
be wrong but I didn't reproduce.
2. Have not change tray process to current session
3. File transfer doesn't update home directory when session changed
4. When it's in login screen, remote file directory is empty, because cm
have not start up
Signed-off-by: 21pages <pages21@163.com>
2024-02-18 22:08:25 +08:00
|
|
|
|
fn set_selected_windows_session_id(&mut self, u_sid: String) {
|
|
|
|
|
self.send_selected_session_id(u_sid);
|
2024-02-14 21:29:17 +05:30
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn get_port_forwards(&mut self) -> Value {
|
|
|
|
|
let port_forwards = self.lc.read().unwrap().port_forwards.clone();
|
|
|
|
|
let mut v = Value::array(0);
|
|
|
|
|
for (port, remote_host, remote_port) in port_forwards {
|
|
|
|
|
let mut v2 = Value::array(0);
|
|
|
|
|
v2.push(port);
|
|
|
|
|
v2.push(remote_host);
|
|
|
|
|
v2.push(remote_port);
|
|
|
|
|
v.push(v2);
|
|
|
|
|
}
|
|
|
|
|
v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_args(&mut self) -> Value {
|
|
|
|
|
let mut v = Value::array(0);
|
|
|
|
|
for x in self.args.iter() {
|
|
|
|
|
v.push(x);
|
|
|
|
|
}
|
|
|
|
|
v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_size(&mut self) -> Value {
|
|
|
|
|
let s = if self.is_file_transfer() {
|
|
|
|
|
self.lc.read().unwrap().size_ft
|
|
|
|
|
} else if self.is_port_forward() {
|
|
|
|
|
self.lc.read().unwrap().size_pf
|
|
|
|
|
} else {
|
|
|
|
|
self.lc.read().unwrap().size
|
|
|
|
|
};
|
|
|
|
|
let mut v = Value::array(0);
|
|
|
|
|
v.push(s.0);
|
|
|
|
|
v.push(s.1);
|
|
|
|
|
v.push(s.2);
|
|
|
|
|
v.push(s.3);
|
|
|
|
|
v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_default_pi(&mut self) -> Value {
|
|
|
|
|
let mut pi = Value::map();
|
|
|
|
|
let info = self.lc.read().unwrap().info.clone();
|
|
|
|
|
pi.set_item("username", info.username.clone());
|
|
|
|
|
pi.set_item("hostname", info.hostname.clone());
|
|
|
|
|
pi.set_item("platform", info.platform.clone());
|
|
|
|
|
pi
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-31 16:31:31 +08:00
|
|
|
|
fn save_close_state(&mut self, k: String, v: String) {
|
|
|
|
|
self.close_state.insert(k, v);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_key_event(&self, down_or_up: i32, name: &str, code: i32) -> Option<KeyEvent> {
|
|
|
|
|
let mut key_event = KeyEvent::new();
|
|
|
|
|
if down_or_up == 2 {
|
|
|
|
|
/* windows send both keyup/keydown and keychar, so here we avoid keychar
|
2021-11-14 18:52:05 +03:30
|
|
|
|
for <= 0xFF, best practice should only avoid those not on keyboard, but
|
|
|
|
|
for now, we have no way to test, so avoid <= 0xFF totally
|
2021-03-29 15:59:14 +08:00
|
|
|
|
*/
|
|
|
|
|
if code <= 0xFF {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
key_event.set_unicode(code.clone() as _);
|
|
|
|
|
} else if let Some(key) = KEY_MAP.get(name) {
|
|
|
|
|
match key {
|
|
|
|
|
Key::Chr(chr) => {
|
|
|
|
|
key_event.set_chr(chr.clone());
|
|
|
|
|
}
|
|
|
|
|
Key::ControlKey(key) => {
|
|
|
|
|
key_event.set_control_key(key.clone());
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if cfg!(target_os = "macos") {
|
|
|
|
|
match code {
|
|
|
|
|
0x4C => key_event.set_control_key(ControlKey::NumpadEnter), // numpad enter
|
|
|
|
|
0x69 => key_event.set_control_key(ControlKey::Snapshot),
|
|
|
|
|
0x72 => key_event.set_control_key(ControlKey::Help),
|
2021-05-26 12:42:21 +08:00
|
|
|
|
0x6E => key_event.set_control_key(ControlKey::Apps),
|
2021-03-29 15:59:14 +08:00
|
|
|
|
0x47 => {
|
|
|
|
|
key_event.set_control_key(if self.peer_platform() == "Mac OS" {
|
|
|
|
|
ControlKey::Clear
|
|
|
|
|
} else {
|
|
|
|
|
ControlKey::NumLock
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
0x51 => key_event.set_control_key(ControlKey::Equals),
|
|
|
|
|
0x2F => key_event.set_chr('.' as _),
|
|
|
|
|
0x32 => key_event.set_chr('`' as _),
|
|
|
|
|
_ => {
|
|
|
|
|
log::error!("Unknown key code {}", code);
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if cfg!(windows) {
|
|
|
|
|
match code {
|
|
|
|
|
0x2C => key_event.set_control_key(ControlKey::Snapshot),
|
|
|
|
|
0x91 => key_event.set_control_key(ControlKey::Scroll),
|
|
|
|
|
0x90 => key_event.set_control_key(ControlKey::NumLock),
|
|
|
|
|
0x5C => key_event.set_control_key(ControlKey::RWin),
|
2021-05-26 12:42:21 +08:00
|
|
|
|
0x5B => key_event.set_control_key(ControlKey::Meta),
|
2021-03-29 15:59:14 +08:00
|
|
|
|
0x5D => key_event.set_control_key(ControlKey::Apps),
|
|
|
|
|
0xBE => key_event.set_chr('.' as _),
|
|
|
|
|
0xC0 => key_event.set_chr('`' as _),
|
|
|
|
|
_ => {
|
|
|
|
|
log::error!("Unknown key code {}", code);
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-05-26 12:42:21 +08:00
|
|
|
|
} else if cfg!(target_os = "linux") {
|
|
|
|
|
match code {
|
|
|
|
|
65300 => key_event.set_control_key(ControlKey::Scroll),
|
|
|
|
|
65421 => key_event.set_control_key(ControlKey::NumpadEnter), // numpad enter
|
|
|
|
|
65407 => key_event.set_control_key(ControlKey::NumLock),
|
2021-12-23 23:03:43 +08:00
|
|
|
|
65515 => key_event.set_control_key(ControlKey::Meta),
|
2021-05-26 12:42:21 +08:00
|
|
|
|
65516 => key_event.set_control_key(ControlKey::RWin),
|
|
|
|
|
65513 => key_event.set_control_key(ControlKey::Alt),
|
|
|
|
|
65514 => key_event.set_control_key(ControlKey::RAlt),
|
|
|
|
|
65508 => key_event.set_control_key(ControlKey::RControl),
|
|
|
|
|
65506 => key_event.set_control_key(ControlKey::RShift),
|
|
|
|
|
96 => key_event.set_chr('`' as _),
|
|
|
|
|
46 => key_event.set_chr('.' as _),
|
|
|
|
|
126 => key_event.set_chr('`' as _),
|
|
|
|
|
33 => key_event.set_chr('1' as _),
|
|
|
|
|
64 => key_event.set_chr('2' as _),
|
|
|
|
|
35 => key_event.set_chr('3' as _),
|
|
|
|
|
36 => key_event.set_chr('4' as _),
|
|
|
|
|
37 => key_event.set_chr('5' as _),
|
|
|
|
|
94 => key_event.set_chr('6' as _),
|
|
|
|
|
38 => key_event.set_chr('7' as _),
|
|
|
|
|
42 => key_event.set_chr('8' as _),
|
|
|
|
|
40 => key_event.set_chr('9' as _),
|
|
|
|
|
41 => key_event.set_chr('0' as _),
|
|
|
|
|
95 => key_event.set_chr('-' as _),
|
|
|
|
|
43 => key_event.set_chr('=' as _),
|
|
|
|
|
123 => key_event.set_chr('[' as _),
|
|
|
|
|
125 => key_event.set_chr(']' as _),
|
|
|
|
|
124 => key_event.set_chr('\\' as _),
|
|
|
|
|
58 => key_event.set_chr(';' as _),
|
|
|
|
|
34 => key_event.set_chr('\'' as _),
|
|
|
|
|
60 => key_event.set_chr(',' as _),
|
|
|
|
|
62 => key_event.set_chr('.' as _),
|
|
|
|
|
63 => key_event.set_chr('/' as _),
|
|
|
|
|
_ => {
|
|
|
|
|
log::error!("Unknown key code {}", code);
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
} else {
|
|
|
|
|
log::error!("Unknown key code {}", code);
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Some(key_event)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_char(&mut self, name: String, code: i32) -> String {
|
|
|
|
|
if let Some(key_event) = self.get_key_event(1, &name, code) {
|
|
|
|
|
match key_event.union {
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(key_event::Union::Chr(chr)) => {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if let Some(chr) = std::char::from_u32(chr as _) {
|
|
|
|
|
return chr.to_string();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
"".to_owned()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn transfer_file(&mut self) {
|
|
|
|
|
let id = self.get_id();
|
2022-07-27 00:31:20 +08:00
|
|
|
|
let args = vec!["--file-transfer", &id, &self.password];
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if let Err(err) = crate::run_me(args) {
|
|
|
|
|
log::error!("Failed to spawn file transfer: {}", err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn tunnel(&mut self) {
|
|
|
|
|
let id = self.get_id();
|
2022-07-27 00:31:20 +08:00
|
|
|
|
let args = vec!["--port-forward", &id, &self.password];
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if let Err(err) = crate::run_me(args) {
|
|
|
|
|
log::error!("Failed to spawn IP tunneling: {}", err);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-10-18 22:39:28 +08:00
|
|
|
|
|
|
|
|
|
fn version_cmp(&self, v1: String, v2: String) -> i32 {
|
|
|
|
|
(hbb_common::get_version_number(&v1) - hbb_common::get_version_number(&v2)) as i32
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-12 17:35:25 +08:00
|
|
|
|
pub fn make_fd(id: i32, entries: &Vec<FileEntry>, only_count: bool) -> Value {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let mut m = Value::map();
|
|
|
|
|
m.set_item("id", id);
|
|
|
|
|
let mut a = Value::array(0);
|
|
|
|
|
let mut n: u64 = 0;
|
|
|
|
|
for entry in entries {
|
|
|
|
|
n += entry.size;
|
|
|
|
|
if only_count {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
let mut e = Value::map();
|
|
|
|
|
e.set_item("name", entry.name.to_owned());
|
2022-01-21 12:52:08 +08:00
|
|
|
|
let tmp = entry.entry_type.value();
|
|
|
|
|
e.set_item("type", if tmp == 0 { 1 } else { tmp });
|
2021-03-29 15:59:14 +08:00
|
|
|
|
e.set_item("time", entry.modified_time as f64);
|
|
|
|
|
e.set_item("size", entry.size as f64);
|
|
|
|
|
a.push(e);
|
|
|
|
|
}
|
2022-09-05 10:27:33 +08:00
|
|
|
|
if !only_count {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
m.set_item("entries", a);
|
|
|
|
|
}
|
2022-09-05 10:27:33 +08:00
|
|
|
|
m.set_item("num_entries", entries.len() as i32);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
m.set_item("total_size", n as f64);
|
|
|
|
|
m
|
2022-09-16 19:43:28 +08:00
|
|
|
|
}
|