add virtual display

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2022-03-12 19:51:55 +08:00
parent e6bf858ae1
commit b734e8aee9
13 changed files with 153 additions and 13 deletions

1
Cargo.lock generated
View File

@ -4186,6 +4186,7 @@ name = "virtual_display"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cc", "cc",
"hbb_common",
"lazy_static", "lazy_static",
"serde 1.0.136", "serde 1.0.136",
"serde_derive", "serde_derive",

View File

@ -27,13 +27,14 @@ pub use anyhow::{self, bail};
pub use futures_util; pub use futures_util;
pub mod config; pub mod config;
pub mod fs; pub mod fs;
pub use lazy_static;
pub use mac_address;
pub use rand; pub use rand;
pub use regex; pub use regex;
pub use sodiumoxide; pub use sodiumoxide;
pub use tokio_socks; pub use tokio_socks;
pub use tokio_socks::IntoTargetAddr; pub use tokio_socks::IntoTargetAddr;
pub use tokio_socks::TargetAddr; pub use tokio_socks::TargetAddr;
pub use mac_address;
#[cfg(feature = "quic")] #[cfg(feature = "quic")]
pub type Stream = quic::Connection; pub type Stream = quic::Connection;

View File

@ -13,3 +13,4 @@ thiserror = "1.0.30"
lazy_static = "1.4" lazy_static = "1.4"
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
hbb_common = { path = "../hbb_common" }

View File

@ -1,5 +1,5 @@
#[cfg(windows)] #[cfg(windows)]
use virtual_display::win10::idd; use virtual_display::win10::{idd, DRIVER_INSTALL_PATH};
use std::{ use std::{
ffi::{CStr, CString}, ffi::{CStr, CString},
@ -24,9 +24,9 @@ fn prompt_input() -> u8 {
.unwrap_or(0) .unwrap_or(0)
} }
unsafe fn plug_in(index: idd::UINT) { unsafe fn plug_in(index: idd::UINT, edid: idd::UINT) {
println!("Plug in monitor begin"); println!("Plug in monitor begin");
if idd::FALSE == idd::MonitorPlugIn(index, 25) { if idd::FALSE == idd::MonitorPlugIn(index, edid, 25) {
println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap()); println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap());
} else { } else {
println!("Plug in monitor done"); println!("Plug in monitor done");
@ -58,8 +58,7 @@ unsafe fn plug_out(index: idd::UINT) {
} }
fn main() { fn main() {
let relative_path = "RustDeskIddDriver/RustDeskIddDriver.inf"; let abs_path = Path::new(DRIVER_INSTALL_PATH).canonicalize().unwrap();
let abs_path = Path::new(relative_path).canonicalize().unwrap();
let full_inf_path = abs_path.to_str().unwrap(); let full_inf_path = abs_path.to_str().unwrap();
unsafe { unsafe {
@ -121,9 +120,9 @@ fn main() {
h_sw_device = invalid_device; h_sw_device = invalid_device;
println!("Close device done"); println!("Close device done");
} }
'1' => plug_in(0), '1' => plug_in(0, 0),
'2' => plug_in(1), '2' => plug_in(1, 0),
'3' => plug_in(2), '3' => plug_in(2, 0),
'4' => plug_out(0), '4' => plug_out(0),
'5' => plug_out(1), '5' => plug_out(1),
'6' => plug_out(2), '6' => plug_out(2),
@ -133,5 +132,7 @@ fn main() {
if !full_inf_path.is_null() { if !full_inf_path.is_null() {
let _ = CString::from_raw(full_inf_path); let _ = CString::from_raw(full_inf_path);
} }
idd::DeviceClose(h_sw_device);
} }
} }

View File

@ -1,2 +1,103 @@
#[cfg(windows)] #[cfg(windows)]
pub mod win10; pub mod win10;
use hbb_common::{bail, lazy_static, ResultType};
use std::{
ffi::{CStr, CString},
path::Path,
sync::Mutex,
};
lazy_static::lazy_static! {
#[cfg(windows)]
static ref H_SW_DEVICE: Mutex<u64> = Mutex::new(0);
}
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() -> 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),
};
unsafe {
#[cfg(windows)]
{
let mut reboot_required = win10::idd::FALSE;
if win10::idd::InstallUpdate(full_install_path, &mut reboot_required)
== win10::idd::FALSE
{
bail!("{}", CStr::from_ptr(win10::idd::GetLastMsg()).to_str()?);
}
}
}
Ok(())
}
pub fn is_device_created() -> bool {
#[cfg(windows)]
return *H_SW_DEVICE.lock().unwrap() != 0;
#[cfg(not(windows))]
return false;
}
#[cfg(windows)]
pub fn create_device() -> ResultType<()> {
unsafe {
let mut h_sw_device = *H_SW_DEVICE.lock().unwrap() as win10::idd::HSWDEVICE;
if win10::idd::DeviceCreate(&mut h_sw_device) == win10::idd::FALSE {
bail!("{}", CStr::from_ptr(win10::idd::GetLastMsg()).to_str()?);
} else {
*H_SW_DEVICE.lock().unwrap() = h_sw_device as u64;
Ok(())
}
}
}
#[cfg(windows)]
pub fn close_device() {
unsafe {
win10::idd::DeviceClose(*H_SW_DEVICE.lock().unwrap() as win10::idd::HSWDEVICE);
}
}
#[cfg(windows)]
pub fn plug_in_monitor() -> ResultType<()> {
unsafe {
if win10::idd::MonitorPlugIn(0, 0, 30) == win10::idd::FALSE {
bail!("{}", CStr::from_ptr(win10::idd::GetLastMsg()).to_str()?);
}
Ok(())
}
}
#[cfg(windows)]
pub fn plug_out_monitor() -> ResultType<()> {
unsafe {
if win10::idd::MonitorPlugOut(0) == win10::idd::FALSE {
bail!("{}", CStr::from_ptr(win10::idd::GetLastMsg()).to_str()?);
}
Ok(())
}
}

View File

@ -282,7 +282,7 @@ VOID DeviceClose(HSWDEVICE hSwDevice)
} }
} }
BOOL MonitorPlugIn(UINT index, INT retries) BOOL MonitorPlugIn(UINT index, UINT edid, INT retries)
{ {
SetLastMsg("Sucess"); SetLastMsg("Sucess");
@ -315,6 +315,7 @@ BOOL MonitorPlugIn(UINT index, INT retries)
DWORD junk = 0; DWORD junk = 0;
CtlPlugIn plugIn; CtlPlugIn plugIn;
plugIn.ConnectorIndex = index; plugIn.ConnectorIndex = index;
plugIn.MonitorEDID = edid;
HRESULT hr = CoCreateGuid(&plugIn.ContainerId); HRESULT hr = CoCreateGuid(&plugIn.ContainerId);
if (!SUCCEEDED(hr)) if (!SUCCEEDED(hr))
{ {

View File

@ -70,6 +70,9 @@ VOID DeviceClose(HSWDEVICE hSwDevice);
* @brief Plug in monitor. * @brief Plug in monitor.
* *
* @param index [in] Monitor index, should be 0, 1, 2. * @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. * @param retries [in] Retry times. Retry 1 time / sec. 25~30 seconds may be good choices.
* -1 is invalid. * -1 is invalid.
* 0 means doing once and no retries. * 0 means doing once and no retries.
@ -83,7 +86,7 @@ VOID DeviceClose(HSWDEVICE hSwDevice);
* System need some time to prepare the device. * System need some time to prepare the device.
* *
*/ */
BOOL MonitorPlugIn(UINT index, INT retries); BOOL MonitorPlugIn(UINT index, UINT edid, INT retries);
/** /**
* @brief Plug out monitor. * @brief Plug out monitor.

View File

@ -26,8 +26,12 @@
#define STATUS_ERROR_MONITOR_INVALID_PARAM (3 << 30) + 53 #define STATUS_ERROR_MONITOR_INVALID_PARAM (3 << 30) + 53
#define STATUS_ERROR_MONITOR_OOM (3 << 30) + 54 #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 { typedef struct _CtlPlugIn {
UINT ConnectorIndex; UINT ConnectorIndex;
UINT MonitorEDID;
GUID ContainerId; GUID ContainerId;
} CtlPlugIn, *PCtlPlugIn; } CtlPlugIn, *PCtlPlugIn;

View File

@ -206,7 +206,7 @@ extern "C" {
extern "C" { extern "C" {
pub fn Uninstall(fullInfPath: LPCTSTR, rebootRequired: PBOOL) -> BOOL; pub fn Uninstall(fullInfPath: LPCTSTR, rebootRequired: PBOOL) -> BOOL;
pub fn MonitorPlugIn(index: UINT, retries: INT) -> BOOL; pub fn MonitorPlugIn(index: UINT, edid: UINT, retries: INT) -> BOOL;
pub fn MonitorPlugOut(index: UINT) -> BOOL; pub fn MonitorPlugOut(index: UINT) -> BOOL;
pub fn MonitorModesUpdate(index: UINT, modeCount: UINT, modes: PMonitorMode) -> BOOL; pub fn MonitorModesUpdate(index: UINT, modeCount: UINT, modes: PMonitorMode) -> BOOL;

View File

@ -1 +1,4 @@
pub mod idd; pub mod idd;
pub const DRIVER_INSTALL_PATH: &str = "RustDeskIddDriver/RustDeskIddDriver.inf";
pub const DRIVER_DOWNLOAD_URL: &str = "";

View File

@ -32,6 +32,7 @@ use std::{
io::ErrorKind::WouldBlock, io::ErrorKind::WouldBlock,
time::{self, Duration, Instant}, time::{self, Duration, Instant},
}; };
use virtual_display;
const WAIT_BASE: i32 = 17; const WAIT_BASE: i32 = 17;
pub const NAME: &'static str = "video"; pub const NAME: &'static str = "video";
@ -446,6 +447,12 @@ fn get_current_display() -> ResultType<(usize, usize, Display)> {
let mut current = *CURRENT_DISPLAY.lock().unwrap() as usize; let mut current = *CURRENT_DISPLAY.lock().unwrap() as usize;
let mut displays = Display::all()?; let mut displays = Display::all()?;
if displays.len() == 0 { if displays.len() == 0 {
// try plugin monitor
if virtual_display::is_device_created() {
if let Err(e) = virtual_display::plug_in_monitor() {
log::error!("plug in monitor failed {}", e)
}
}
bail!("No displays"); bail!("No displays");
} }
let n = displays.len(); let n = displays.len();

View File

@ -19,6 +19,7 @@ use std::{
process::Child, process::Child,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
use virtual_display;
pub type Childs = Arc<Mutex<(bool, HashMap<(String, String), Child>)>>; pub type Childs = Arc<Mutex<(bool, HashMap<(String, String), Child>)>>;
@ -364,6 +365,18 @@ impl UI {
} }
} }
// TODO: ui prompt
fn install_virtual_display(&self) {
match virtual_display::install_update_driver() {
Ok(_) => {
log::info!("Virtual Display: install virtual display done");
}
Err(e) => {
log::error!("Virtual Display: install virtual display failed {}", e);
}
}
}
fn install_path(&mut self) -> String { fn install_path(&mut self) -> String {
#[cfg(windows)] #[cfg(windows)]
return crate::platform::windows::get_install_info().1; return crate::platform::windows::get_install_info().1;
@ -690,6 +703,7 @@ impl sciter::EventHandler for UI {
fn get_sound_inputs(); fn get_sound_inputs();
fn set_options(Value); fn set_options(Value);
fn set_option(String, String); fn set_option(String, String);
fn install_virtual_display();
fn get_software_update_url(); fn get_software_update_url();
fn get_new_version(); fn get_new_version();
fn get_version(); fn get_version();

View File

@ -168,6 +168,7 @@ class MyIdMenu: Reactor.Component {
<li #custom-server>{translate('ID/Relay Server')}</li> <li #custom-server>{translate('ID/Relay Server')}</li>
<li #whitelist title={translate('whitelist_tip')}>{translate('IP Whitelisting')}</li> <li #whitelist title={translate('whitelist_tip')}>{translate('IP Whitelisting')}</li>
<li #socks5-server>{translate('Socks5 Proxy')}</li> <li #socks5-server>{translate('Socks5 Proxy')}</li>
{is_win ? <li #install-virtual-display>Install virtual display</li> : ""}
<div .separator /> <div .separator />
<li #stop-service class={service_stopped ? "line-through" : "selected"}><span>{svg_checkmark}</span>{translate("Enable Service")}</li> <li #stop-service class={service_stopped ? "line-through" : "selected"}><span>{svg_checkmark}</span>{translate("Enable Service")}</li>
<DirectServer /> <DirectServer />
@ -268,6 +269,8 @@ class MyIdMenu: Reactor.Component {
} }
handler.set_socks(proxy, username, password); handler.set_socks(proxy, username, password);
}, 240); }, 240);
} else if (me.id == "install-virtual-display") {
handler.install_virtual_display();
} else if (me.id == "stop-service") { } else if (me.id == "stop-service") {
handler.set_option("stop-service", service_stopped ? "" : "Y"); handler.set_option("stop-service", service_stopped ? "" : "Y");
} else if (me.id == "about") { } else if (me.id == "about") {