use crate::{ common::{get_supported_keyboard_modes, is_keyboard_mode_supported}, input::{MOUSE_BUTTON_LEFT, MOUSE_TYPE_DOWN, MOUSE_TYPE_UP, MOUSE_TYPE_WHEEL}, ui_interface::use_texture_render, }; use async_trait::async_trait; use bytes::Bytes; use rdev::{Event, EventType::*, KeyCode}; use std::{ collections::HashMap, ffi::c_void, ops::{Deref, DerefMut}, str::FromStr, sync::{Arc, Mutex, RwLock}, time::SystemTime, }; use uuid::Uuid; #[cfg(not(feature = "flutter"))] use hbb_common::fs; use hbb_common::{ allow_err, config::{Config, LocalConfig, PeerConfig}, get_version_number, log, message_proto::*, rendezvous_proto::ConnType, tokio::{ self, sync::mpsc, time::{Duration as TokioDuration, Instant}, }, Stream, }; use crate::client::io_loop::Remote; use crate::client::{ check_if_retry, handle_hash, handle_login_error, handle_login_from_ui, handle_test_delay, input_os_password, send_mouse, send_pointer_device_event, start_video_audio_threads, FileManager, Key, LoginConfigHandler, QualityStatus, KEY_MAP, }; #[cfg(not(any(target_os = "android", target_os = "ios")))] use crate::common::GrabState; use crate::keyboard; use crate::{client::Data, client::Interface}; const CHANGE_RESOLUTION_VALID_TIMEOUT_SECS: u64 = 15; #[derive(Clone, Default)] pub struct Session<T: InvokeUiSession> { pub password: String, pub args: Vec<String>, pub lc: Arc<RwLock<LoginConfigHandler>>, pub sender: Arc<RwLock<Option<mpsc::UnboundedSender<Data>>>>, pub thread: Arc<Mutex<Option<std::thread::JoinHandle<()>>>>, pub ui_handler: T, pub server_keyboard_enabled: Arc<RwLock<bool>>, pub server_file_transfer_enabled: Arc<RwLock<bool>>, pub server_clipboard_enabled: Arc<RwLock<bool>>, pub last_change_display: Arc<Mutex<ChangeDisplayRecord>>, pub connection_round_state: Arc<Mutex<ConnectionRoundState>>, } #[derive(Clone)] pub struct SessionPermissionConfig { pub lc: Arc<RwLock<LoginConfigHandler>>, pub server_keyboard_enabled: Arc<RwLock<bool>>, pub server_file_transfer_enabled: Arc<RwLock<bool>>, pub server_clipboard_enabled: Arc<RwLock<bool>>, } pub struct ChangeDisplayRecord { time: Instant, display: i32, width: i32, height: i32, } enum ConnectionState { Connecting, Connected, Disconnected, } /// ConnectionRoundState is used to control the reconnecting logic. pub struct ConnectionRoundState { round: u32, state: ConnectionState, } impl ConnectionRoundState { pub fn new_round(&mut self) -> u32 { self.round += 1; self.state = ConnectionState::Connecting; self.round } pub fn set_connected(&mut self) { self.state = ConnectionState::Connected; } pub fn is_round_gt(&self, round: u32) -> bool { if round == u32::MAX && self.round == 0 { true } else { round < self.round } } pub fn set_


