mirror of
https://github.com/rustdesk/rustdesk.git
synced 2025-01-20 00:53:01 +08:00
fix: win, virtual display (#9023)
1. Default resolution 1920x1080. 2. Restore on conn & disconn. Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
parent
ce56be6507
commit
6625aca994
@ -937,6 +937,24 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_toggle_virtual_display_msg(&self, peer: &mut Stream) {
|
||||
let lc = self.handler.lc.read().unwrap();
|
||||
let displays = lc.get_option("virtual-display");
|
||||
for d in displays.split(',') {
|
||||
if let Ok(index) = d.parse::<i32>() {
|
||||
let mut misc = Misc::new();
|
||||
misc.set_toggle_virtual_display(ToggleVirtualDisplay {
|
||||
display: index,
|
||||
on: true,
|
||||
..Default::default()
|
||||
});
|
||||
let mut msg_out = Message::new();
|
||||
msg_out.set_misc(misc);
|
||||
allow_err!(peer.send(&msg_out).await);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_toggle_privacy_mode_msg(&self, peer: &mut Stream) {
|
||||
let lc = self.handler.lc.read().unwrap();
|
||||
if lc.version >= hbb_common::get_version_number("1.2.4")
|
||||
@ -1073,6 +1091,7 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
self.handler.close_success();
|
||||
self.handler.adapt_size();
|
||||
self.send_opts_after_login(peer).await;
|
||||
self.send_toggle_virtual_display_msg(peer).await;
|
||||
self.send_toggle_privacy_mode_msg(peer).await;
|
||||
}
|
||||
let incoming_format = CodecFormat::from(&vf);
|
||||
|
@ -1780,6 +1780,54 @@ pub fn try_sync_peer_option(
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn session_update_virtual_display(session: &FlutterSession, index: i32, on: bool) {
|
||||
let virtual_display_key = "virtual-display";
|
||||
let displays = session.get_option(virtual_display_key.to_owned());
|
||||
if !on {
|
||||
if index == -1 {
|
||||
if !displays.is_empty() {
|
||||
session.set_option(virtual_display_key.to_owned(), "".to_owned());
|
||||
}
|
||||
} else {
|
||||
let mut vdisplays = displays.split(',').collect::<Vec<_>>();
|
||||
let len = vdisplays.len();
|
||||
if index == 0 {
|
||||
// 0 means we cann't toggle the virtual display by index.
|
||||
vdisplays.remove(vdisplays.len() - 1);
|
||||
} else {
|
||||
if let Some(i) = vdisplays.iter().position(|&x| x == index.to_string()) {
|
||||
vdisplays.remove(i);
|
||||
}
|
||||
}
|
||||
if vdisplays.len() != len {
|
||||
session.set_option(
|
||||
virtual_display_key.to_owned(),
|
||||
vdisplays.join(",").to_owned(),
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let mut vdisplays = displays
|
||||
.split(',')
|
||||
.map(|x| x.to_string())
|
||||
.collect::<Vec<_>>();
|
||||
let len = vdisplays.len();
|
||||
if index == 0 {
|
||||
vdisplays.push(index.to_string());
|
||||
} else {
|
||||
if !vdisplays.iter().any(|x| *x == index.to_string()) {
|
||||
vdisplays.push(index.to_string());
|
||||
}
|
||||
}
|
||||
if vdisplays.len() != len {
|
||||
session.set_option(
|
||||
virtual_display_key.to_owned(),
|
||||
vdisplays.join(",").to_owned(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sessions mod is used to avoid the big lock of sessions' map.
|
||||
pub mod sessions {
|
||||
use std::collections::HashSet;
|
||||
|
@ -1568,6 +1568,7 @@ pub fn session_on_waiting_for_image_dialog_show(session_id: SessionID) {
|
||||
pub fn session_toggle_virtual_display(session_id: SessionID, index: i32, on: bool) {
|
||||
if let Some(session) = sessions::get_session_by_session_id(&session_id) {
|
||||
session.toggle_virtual_display(index, on);
|
||||
flutter::session_update_virtual_display(&session, index, on);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2595,3 +2595,107 @@ pub fn try_set_window_foreground(window: HWND) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod reg_display_settings {
|
||||
use hbb_common::ResultType;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use winreg::{enums::*, RegValue};
|
||||
const REG_GRAPHICS_DRIVERS_PATH: &str = "SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers";
|
||||
const REG_CONNECTIVITY_PATH: &str = "Connectivity";
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct RegRecovery {
|
||||
path: String,
|
||||
key: String,
|
||||
old: (Vec<u8>, isize),
|
||||
new: (Vec<u8>, isize),
|
||||
}
|
||||
|
||||
pub fn read_reg_connectivity() -> ResultType<HashMap<String, HashMap<String, RegValue>>>
|
||||
{
|
||||
let hklm = winreg::RegKey::predef(HKEY_LOCAL_MACHINE);
|
||||
let reg_connectivity = hklm.open_subkey_with_flags(
|
||||
format!("{}\\{}", REG_GRAPHICS_DRIVERS_PATH, REG_CONNECTIVITY_PATH),
|
||||
KEY_READ,
|
||||
)?;
|
||||
|
||||
let mut map_connectivity = HashMap::new();
|
||||
for key in reg_connectivity.enum_keys() {
|
||||
let key = key?;
|
||||
let mut map_item = HashMap::new();
|
||||
let reg_item = reg_connectivity.open_subkey_with_flags(&key, KEY_READ)?;
|
||||
for value in reg_item.enum_values() {
|
||||
let (name, value) = value?;
|
||||
map_item.insert(name, value);
|
||||
}
|
||||
map_connectivity.insert(key, map_item);
|
||||
}
|
||||
Ok(map_connectivity)
|
||||
}
|
||||
|
||||
pub fn diff_recent_connectivity(
|
||||
map1: HashMap<String, HashMap<String, RegValue>>,
|
||||
map2: HashMap<String, HashMap<String, RegValue>>,
|
||||
) -> Option<RegRecovery> {
|
||||
for (subkey, map_item2) in map2 {
|
||||
if let Some(map_item1) = map1.get(&subkey) {
|
||||
let key = "Recent";
|
||||
if let Some(value1) = map_item1.get(key) {
|
||||
if let Some(value2) = map_item2.get(key) {
|
||||
if value1 != value2 {
|
||||
return Some(RegRecovery {
|
||||
path: format!(
|
||||
"{}\\{}\\{}",
|
||||
REG_GRAPHICS_DRIVERS_PATH, REG_CONNECTIVITY_PATH, subkey
|
||||
),
|
||||
key: key.to_owned(),
|
||||
old: (value1.bytes.clone(), value1.vtype.clone() as isize),
|
||||
new: (value2.bytes.clone(), value2.vtype.clone() as isize),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn restore_reg_connectivity(reg_recovery: RegRecovery) -> ResultType<()> {
|
||||
let hklm = winreg::RegKey::predef(HKEY_LOCAL_MACHINE);
|
||||
let reg_item = hklm.open_subkey_with_flags(®_recovery.path, KEY_READ | KEY_WRITE)?;
|
||||
let cur_reg_value = reg_item.get_raw_value(®_recovery.key)?;
|
||||
let new_reg_value = RegValue {
|
||||
bytes: reg_recovery.new.0,
|
||||
vtype: isize_to_reg_type(reg_recovery.new.1),
|
||||
};
|
||||
if cur_reg_value != new_reg_value {
|
||||
return Ok(());
|
||||
}
|
||||
let reg_value = RegValue {
|
||||
bytes: reg_recovery.old.0,
|
||||
vtype: isize_to_reg_type(reg_recovery.old.1),
|
||||
};
|
||||
reg_item.set_raw_value(®_recovery.key, ®_value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn isize_to_reg_type(i: isize) -> RegType {
|
||||
match i {
|
||||
0 => RegType::REG_NONE,
|
||||
1 => RegType::REG_SZ,
|
||||
2 => RegType::REG_EXPAND_SZ,
|
||||
3 => RegType::REG_BINARY,
|
||||
4 => RegType::REG_DWORD,
|
||||
5 => RegType::REG_DWORD_BIG_ENDIAN,
|
||||
6 => RegType::REG_LINK,
|
||||
7 => RegType::REG_MULTI_SZ,
|
||||
8 => RegType::REG_RESOURCE_LIST,
|
||||
9 => RegType::REG_FULL_RESOURCE_DESCRIPTOR,
|
||||
10 => RegType::REG_RESOURCE_REQUIREMENTS_LIST,
|
||||
11 => RegType::REG_QWORD,
|
||||
_ => RegType::REG_NONE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::{PrivacyMode, PrivacyModeState, INVALID_PRIVACY_MODE_CONN_ID, NO_PHYSICAL_DISPLAYS};
|
||||
use crate::virtual_display_manager;
|
||||
use crate::{platform::windows::reg_display_settings, virtual_display_manager};
|
||||
use hbb_common::{allow_err, bail, config::Config, log, ResultType};
|
||||
use std::{
|
||||
io::Error,
|
||||
@ -150,7 +150,8 @@ impl PrivacyModeImpl {
|
||||
}
|
||||
|
||||
fn restore_plug_out_monitor(&mut self) {
|
||||
let _ = virtual_display_manager::plug_out_monitor_indices(&self.virtual_displays_added);
|
||||
let _ =
|
||||
virtual_display_manager::plug_out_monitor_indices(&self.virtual_displays_added, true);
|
||||
self.virtual_displays_added.clear();
|
||||
}
|
||||
|
||||
@ -296,7 +297,7 @@ impl PrivacyModeImpl {
|
||||
|
||||
// No physical displays, no need to use the privacy mode.
|
||||
if self.displays.is_empty() {
|
||||
virtual_display_manager::plug_out_monitor_indices(&displays)?;
|
||||
virtual_display_manager::plug_out_monitor_indices(&displays, false)?;
|
||||
bail!(NO_PHYSICAL_DISPLAYS);
|
||||
}
|
||||
|
||||
@ -414,8 +415,14 @@ impl PrivacyMode for PrivacyModeImpl {
|
||||
) -> ResultType<()> {
|
||||
self.check_off_conn_id(conn_id)?;
|
||||
super::win_input::unhook()?;
|
||||
self.restore_plug_out_monitor();
|
||||
let virtual_display_added = self.virtual_displays_added.len() > 0;
|
||||
if virtual_display_added {
|
||||
self.restore_plug_out_monitor();
|
||||
}
|
||||
restore_reg_connectivity(false);
|
||||
if !virtual_display_added {
|
||||
Self::commit_change_display(CDS_RESET)?;
|
||||
}
|
||||
|
||||
if self.conn_id != INVALID_PRIVACY_MODE_CONN_ID {
|
||||
if let Some(state) = state {
|
||||
@ -462,7 +469,7 @@ pub fn restore_reg_connectivity(plug_out_monitors: bool) {
|
||||
return;
|
||||
}
|
||||
if plug_out_monitors {
|
||||
let _ = virtual_display_manager::plug_out_monitor(-1);
|
||||
let _ = virtual_display_manager::plug_out_monitor(-1, true);
|
||||
}
|
||||
if let Ok(reg_recovery) =
|
||||
serde_json::from_str::<reg_display_settings::RegRecovery>(&config_recovery_value)
|
||||
@ -473,107 +480,3 @@ pub fn restore_reg_connectivity(plug_out_monitors: bool) {
|
||||
}
|
||||
reset_config_reg_connectivity();
|
||||
}
|
||||
|
||||
mod reg_display_settings {
|
||||
use hbb_common::ResultType;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use winreg::{enums::*, RegValue};
|
||||
const REG_GRAPHICS_DRIVERS_PATH: &str = "SYSTEM\\CurrentControlSet\\Control\\GraphicsDrivers";
|
||||
const REG_CONNECTIVITY_PATH: &str = "Connectivity";
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub(super) struct RegRecovery {
|
||||
path: String,
|
||||
key: String,
|
||||
old: (Vec<u8>, isize),
|
||||
new: (Vec<u8>, isize),
|
||||
}
|
||||
|
||||
pub(super) fn read_reg_connectivity() -> ResultType<HashMap<String, HashMap<String, RegValue>>>
|
||||
{
|
||||
let hklm = winreg::RegKey::predef(HKEY_LOCAL_MACHINE);
|
||||
let reg_connectivity = hklm.open_subkey_with_flags(
|
||||
format!("{}\\{}", REG_GRAPHICS_DRIVERS_PATH, REG_CONNECTIVITY_PATH),
|
||||
KEY_READ,
|
||||
)?;
|
||||
|
||||
let mut map_connectivity = HashMap::new();
|
||||
for key in reg_connectivity.enum_keys() {
|
||||
let key = key?;
|
||||
let mut map_item = HashMap::new();
|
||||
let reg_item = reg_connectivity.open_subkey_with_flags(&key, KEY_READ)?;
|
||||
for value in reg_item.enum_values() {
|
||||
let (name, value) = value?;
|
||||
map_item.insert(name, value);
|
||||
}
|
||||
map_connectivity.insert(key, map_item);
|
||||
}
|
||||
Ok(map_connectivity)
|
||||
}
|
||||
|
||||
pub(super) fn diff_recent_connectivity(
|
||||
map1: HashMap<String, HashMap<String, RegValue>>,
|
||||
map2: HashMap<String, HashMap<String, RegValue>>,
|
||||
) -> Option<RegRecovery> {
|
||||
for (subkey, map_item2) in map2 {
|
||||
if let Some(map_item1) = map1.get(&subkey) {
|
||||
let key = "Recent";
|
||||
if let Some(value1) = map_item1.get(key) {
|
||||
if let Some(value2) = map_item2.get(key) {
|
||||
if value1 != value2 {
|
||||
return Some(RegRecovery {
|
||||
path: format!(
|
||||
"{}\\{}\\{}",
|
||||
REG_GRAPHICS_DRIVERS_PATH, REG_CONNECTIVITY_PATH, subkey
|
||||
),
|
||||
key: key.to_owned(),
|
||||
old: (value1.bytes.clone(), value1.vtype.clone() as isize),
|
||||
new: (value2.bytes.clone(), value2.vtype.clone() as isize),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub(super) fn restore_reg_connectivity(reg_recovery: RegRecovery) -> ResultType<()> {
|
||||
let hklm = winreg::RegKey::predef(HKEY_LOCAL_MACHINE);
|
||||
let reg_item = hklm.open_subkey_with_flags(®_recovery.path, KEY_READ | KEY_WRITE)?;
|
||||
let cur_reg_value = reg_item.get_raw_value(®_recovery.key)?;
|
||||
let new_reg_value = RegValue {
|
||||
bytes: reg_recovery.new.0,
|
||||
vtype: isize_to_reg_type(reg_recovery.new.1),
|
||||
};
|
||||
if cur_reg_value != new_reg_value {
|
||||
return Ok(());
|
||||
}
|
||||
let reg_value = RegValue {
|
||||
bytes: reg_recovery.old.0,
|
||||
vtype: isize_to_reg_type(reg_recovery.old.1),
|
||||
};
|
||||
reg_item.set_raw_value(®_recovery.key, ®_value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn isize_to_reg_type(i: isize) -> RegType {
|
||||
match i {
|
||||
0 => RegType::REG_NONE,
|
||||
1 => RegType::REG_SZ,
|
||||
2 => RegType::REG_EXPAND_SZ,
|
||||
3 => RegType::REG_BINARY,
|
||||
4 => RegType::REG_DWORD,
|
||||
5 => RegType::REG_DWORD_BIG_ENDIAN,
|
||||
6 => RegType::REG_LINK,
|
||||
7 => RegType::REG_MULTI_SZ,
|
||||
8 => RegType::REG_RESOURCE_LIST,
|
||||
9 => RegType::REG_FULL_RESOURCE_DESCRIPTOR,
|
||||
10 => RegType::REG_RESOURCE_REQUIREMENTS_LIST,
|
||||
11 => RegType::REG_QWORD,
|
||||
_ => RegType::REG_NONE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2670,7 +2670,7 @@ impl Connection {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Err(e) = virtual_display_manager::plug_out_monitor(t.display) {
|
||||
if let Err(e) = virtual_display_manager::plug_out_monitor(t.display, false) {
|
||||
log::error!("Failed to plug out virtual display {}: {}", t.display, e);
|
||||
self.send(make_msg(format!(
|
||||
"Failed to plug out virtual displays: {}",
|
||||
|
@ -433,7 +433,6 @@ pub fn try_get_displays_(add_amyuni_headless: bool) -> ResultType<Vec<Display>>
|
||||
// }
|
||||
|
||||
let no_displays_v = no_displays(&displays);
|
||||
virtual_display_manager::set_can_plug_out_all(!no_displays_v);
|
||||
if no_displays_v {
|
||||
log::debug!("no displays, create virtual display");
|
||||
if let Err(e) = virtual_display_manager::plug_in_headless() {
|
||||
|
@ -1,5 +1,4 @@
|
||||
use hbb_common::{bail, platform::windows::is_windows_version_or_greater, ResultType};
|
||||
use std::sync::atomic;
|
||||
|
||||
// This string is defined here.
|
||||
// https://github.com/rustdesk-org/RustDeskIddDriver/blob/b370aad3f50028b039aad211df60c8051c4a64d6/RustDeskIddDriver/RustDeskIddDriver.inf#LL73C1-L73C40
|
||||
@ -10,29 +9,6 @@ const IDD_IMPL: &str = IDD_IMPL_AMYUNI;
|
||||
const IDD_IMPL_RUSTDESK: &str = "rustdesk_idd";
|
||||
const IDD_IMPL_AMYUNI: &str = "amyuni_idd";
|
||||
|
||||
const IS_CAN_PLUG_OUT_ALL_NOT_SET: i8 = 0;
|
||||
const IS_CAN_PLUG_OUT_ALL_YES: i8 = 1;
|
||||
const IS_CAN_PLUG_OUT_ALL_NO: i8 = 2;
|
||||
static IS_CAN_PLUG_OUT_ALL: atomic::AtomicI8 = atomic::AtomicI8::new(IS_CAN_PLUG_OUT_ALL_NOT_SET);
|
||||
|
||||
pub fn is_can_plug_out_all() -> bool {
|
||||
IS_CAN_PLUG_OUT_ALL.load(atomic::Ordering::Relaxed) != IS_CAN_PLUG_OUT_ALL_NO
|
||||
}
|
||||
|
||||
// No need to consider concurrency here.
|
||||
pub fn set_can_plug_out_all(v: bool) {
|
||||
if IS_CAN_PLUG_OUT_ALL.load(atomic::Ordering::Relaxed) == IS_CAN_PLUG_OUT_ALL_NOT_SET {
|
||||
IS_CAN_PLUG_OUT_ALL.store(
|
||||
if v {
|
||||
IS_CAN_PLUG_OUT_ALL_YES
|
||||
} else {
|
||||
IS_CAN_PLUG_OUT_ALL_NO
|
||||
},
|
||||
atomic::Ordering::Relaxed,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_amyuni_idd() -> bool {
|
||||
IDD_IMPL == IDD_IMPL_AMYUNI
|
||||
}
|
||||
@ -100,7 +76,7 @@ pub fn plug_in_monitor(idx: u32, modes: Vec<virtual_display::MonitorMode>) -> Re
|
||||
}
|
||||
}
|
||||
|
||||
pub fn plug_out_monitor(index: i32) -> ResultType<()> {
|
||||
pub fn plug_out_monitor(index: i32, force_all: bool) -> ResultType<()> {
|
||||
match IDD_IMPL {
|
||||
IDD_IMPL_RUSTDESK => {
|
||||
let indices = if index == -1 {
|
||||
@ -110,7 +86,7 @@ pub fn plug_out_monitor(index: i32) -> ResultType<()> {
|
||||
};
|
||||
rustdesk_idd::plug_out_peer_request(&indices)
|
||||
}
|
||||
IDD_IMPL_AMYUNI => amyuni_idd::plug_out_monitor(index),
|
||||
IDD_IMPL_AMYUNI => amyuni_idd::plug_out_monitor(index, force_all),
|
||||
_ => bail!("Unsupported virtual display implementation."),
|
||||
}
|
||||
}
|
||||
@ -126,12 +102,12 @@ pub fn plug_in_peer_request(modes: Vec<Vec<virtual_display::MonitorMode>>) -> Re
|
||||
}
|
||||
}
|
||||
|
||||
pub fn plug_out_monitor_indices(indices: &[u32]) -> ResultType<()> {
|
||||
pub fn plug_out_monitor_indices(indices: &[u32], force_all: bool) -> ResultType<()> {
|
||||
match IDD_IMPL {
|
||||
IDD_IMPL_RUSTDESK => rustdesk_idd::plug_out_peer_request(indices),
|
||||
IDD_IMPL_AMYUNI => {
|
||||
for _idx in indices.iter() {
|
||||
amyuni_idd::plug_out_monitor(0)?;
|
||||
amyuni_idd::plug_out_monitor(0, force_all)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -142,7 +118,7 @@ pub fn plug_out_monitor_indices(indices: &[u32]) -> ResultType<()> {
|
||||
pub fn reset_all() -> ResultType<()> {
|
||||
match IDD_IMPL {
|
||||
IDD_IMPL_RUSTDESK => rustdesk_idd::reset_all(),
|
||||
IDD_IMPL_AMYUNI => crate::privacy_mode::turn_off_privacy(0, None).unwrap_or(Ok(())),
|
||||
IDD_IMPL_AMYUNI => amyuni_idd::reset_all(),
|
||||
_ => bail!("Unsupported virtual display implementation."),
|
||||
}
|
||||
}
|
||||
@ -402,7 +378,7 @@ pub mod rustdesk_idd {
|
||||
|
||||
pub mod amyuni_idd {
|
||||
use super::windows;
|
||||
use crate::platform::win_device;
|
||||
use crate::platform::{reg_display_settings, win_device};
|
||||
use hbb_common::{bail, lazy_static, log, tokio::time::Instant, ResultType};
|
||||
use std::{
|
||||
ptr::null_mut,
|
||||
@ -532,6 +508,13 @@ pub mod amyuni_idd {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn reset_all() -> ResultType<()> {
|
||||
let _ = crate::privacy_mode::turn_off_privacy(0, None);
|
||||
let _ = plug_out_monitor(-1, true);
|
||||
*LAST_PLUG_IN_HEADLESS_TIME.lock().unwrap() = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn plug_monitor_(add: bool) -> Result<(), win_device::DeviceError> {
|
||||
let cmd = if add { 0x10 } else { 0x00 };
|
||||
@ -547,6 +530,7 @@ pub mod amyuni_idd {
|
||||
fn plug_in_monitor_(add: bool, is_driver_async_installed: bool) -> ResultType<()> {
|
||||
let timeout = Duration::from_secs(3);
|
||||
let now = Instant::now();
|
||||
let reg_connectivity_old = reg_display_settings::read_reg_connectivity();
|
||||
loop {
|
||||
match plug_monitor_(add) {
|
||||
Ok(_) => {
|
||||
@ -567,9 +551,36 @@ pub mod amyuni_idd {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Workaround for the issue that we can't set the default the resolution.
|
||||
if let Ok(old_connectivity_old) = reg_connectivity_old {
|
||||
std::thread::spawn(move || {
|
||||
try_reset_resolution_on_first_plug_in(old_connectivity_old.len(), 1920, 1080);
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn try_reset_resolution_on_first_plug_in(
|
||||
old_connectivity_len: usize,
|
||||
width: usize,
|
||||
height: usize,
|
||||
) {
|
||||
for _ in 0..10 {
|
||||
std::thread::sleep(Duration::from_millis(300));
|
||||
if let Ok(reg_connectivity_new) = reg_display_settings::read_reg_connectivity() {
|
||||
if reg_connectivity_new.len() != old_connectivity_len {
|
||||
for name in
|
||||
windows::get_device_names(Some(super::AMYUNI_IDD_DEVICE_STRING)).iter()
|
||||
{
|
||||
crate::platform::change_resolution(&name, width, height).ok();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn plug_in_headless() -> ResultType<()> {
|
||||
let mut tm = LAST_PLUG_IN_HEADLESS_TIME.lock().unwrap();
|
||||
if let Some(tm) = &mut *tm {
|
||||
@ -603,7 +614,7 @@ pub mod amyuni_idd {
|
||||
plug_in_monitor_(true, is_async)
|
||||
}
|
||||
|
||||
pub fn plug_out_monitor(index: i32) -> ResultType<()> {
|
||||
pub fn plug_out_monitor(index: i32, force_all: bool) -> ResultType<()> {
|
||||
let all_count = windows::get_device_names(None).len();
|
||||
let amyuni_count = get_monitor_count();
|
||||
let mut to_plug_out_count = match all_count {
|
||||
@ -612,7 +623,7 @@ pub mod amyuni_idd {
|
||||
if amyuni_count == 0 {
|
||||
bail!("No virtual displays to plug out.")
|
||||
} else {
|
||||
if super::is_can_plug_out_all() {
|
||||
if force_all {
|
||||
1
|
||||
} else {
|
||||
bail!("This only virtual display cannot be pulled out.")
|
||||
@ -621,7 +632,7 @@ pub mod amyuni_idd {
|
||||
}
|
||||
_ => {
|
||||
if all_count == amyuni_count {
|
||||
if super::is_can_plug_out_all() {
|
||||
if force_all {
|
||||
all_count
|
||||
} else {
|
||||
all_count - 1
|
||||
|
Loading…
Reference in New Issue
Block a user