update
parent
886e6b3770
commit
8cac59d8bb
|
@ -18,3 +18,9 @@ features = [
|
||||||
"Win32_Graphics_Gdi",
|
"Win32_Graphics_Gdi",
|
||||||
"Win32_Security",
|
"Win32_Security",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
codegen-units = 1
|
||||||
|
# panic = 'abort'
|
||||||
|
# strip = true
|
20
src/app.rs
20
src/app.rs
|
@ -1,6 +1,7 @@
|
||||||
use log::{debug, error, info, trace};
|
use log::{debug, error, info, trace};
|
||||||
use parsec_vdd::{
|
use parsec_vdd::{
|
||||||
open_device_handle, query_device_status, vdd_add_display, vdd_remove_display, vdd_update, vdd_version, DeviceStatus, VddHandle, VDD_ADAPTER_GUID, VDD_CLASS_GUID, VDD_HARDWARE_ID
|
DeviceStatus, VDD_ADAPTER_GUID, VDD_CLASS_GUID, VDD_HARDWARE_ID, VddHandle, open_device_handle,
|
||||||
|
query_device_status, vdd_add_display, vdd_remove_display, vdd_update, vdd_version,
|
||||||
};
|
};
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
Arc,
|
Arc,
|
||||||
|
@ -32,7 +33,7 @@ impl App {
|
||||||
panic!("Failed to open device handle");
|
panic!("Failed to open device handle");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut app = App {
|
let app = App {
|
||||||
handle: handle.clone(),
|
handle: handle.clone(),
|
||||||
version: 0,
|
version: 0,
|
||||||
running: Arc::new(AtomicBool::new(true)),
|
running: Arc::new(AtomicBool::new(true)),
|
||||||
|
@ -123,12 +124,11 @@ impl App {
|
||||||
|
|
||||||
pub fn start(&mut self) {
|
pub fn start(&mut self) {
|
||||||
self.running.store(true, Ordering::SeqCst);
|
self.running.store(true, Ordering::SeqCst);
|
||||||
while self.running.load(Ordering::SeqCst) {
|
|
||||||
if self.index != -1 {
|
std::thread::spawn(move || {
|
||||||
vdd_update(&self.handle);
|
self.watch_monitors();
|
||||||
}
|
});
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
self.keep_alive();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keep_alive(&mut self) {
|
pub fn keep_alive(&mut self) {
|
||||||
|
@ -137,6 +137,7 @@ impl App {
|
||||||
std::thread::sleep(std::time::Duration::from_millis(1000));
|
std::thread::sleep(std::time::Duration::from_millis(1000));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
vdd_update(&self.handle);
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,10 +147,9 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Drop for App {
|
impl Drop for App {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.stop();
|
self.stop();
|
||||||
self.stop_virtual_display();
|
self.stop_virtual_display();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
45
src/lib.rs
45
src/lib.rs
|
@ -1,6 +1,6 @@
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
use std::mem::{size_of, zeroed};
|
use std::mem::{size_of, zeroed};
|
||||||
|
use log::{trace,debug,info};
|
||||||
use windows::{
|
use windows::{
|
||||||
Win32::{
|
Win32::{
|
||||||
Devices::DeviceAndDriverInstallation::{
|
Devices::DeviceAndDriverInstallation::{
|
||||||
|
@ -17,6 +17,9 @@ use windows::{
|
||||||
CloseHandle, ERROR_IO_PENDING, GENERIC_READ, GENERIC_WRITE, GetLastError, HANDLE,
|
CloseHandle, ERROR_IO_PENDING, GENERIC_READ, GENERIC_WRITE, GetLastError, HANDLE,
|
||||||
INVALID_HANDLE_VALUE,
|
INVALID_HANDLE_VALUE,
|
||||||
},
|
},
|
||||||
|
Graphics::Gdi::{
|
||||||
|
DISPLAY_DEVICE_ACTIVE, DISPLAY_DEVICE_STATE_FLAGS, DISPLAY_DEVICEW, EnumDisplayDevicesW,
|
||||||
|
},
|
||||||
Storage::FileSystem::{
|
Storage::FileSystem::{
|
||||||
CreateFileA, FILE_ATTRIBUTE_NORMAL, FILE_FLAG_NO_BUFFERING, FILE_FLAG_OVERLAPPED,
|
CreateFileA, FILE_ATTRIBUTE_NORMAL, FILE_FLAG_NO_BUFFERING, FILE_FLAG_OVERLAPPED,
|
||||||
FILE_FLAG_WRITE_THROUGH, FILE_SHARE_READ, FILE_SHARE_WRITE, OPEN_EXISTING,
|
FILE_FLAG_WRITE_THROUGH, FILE_SHARE_READ, FILE_SHARE_WRITE, OPEN_EXISTING,
|
||||||
|
@ -27,7 +30,7 @@ use windows::{
|
||||||
Threading::CreateEventA,
|
Threading::CreateEventA,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
core::{GUID, PCSTR},
|
core::{GUID, PCSTR, PWSTR},
|
||||||
};
|
};
|
||||||
|
|
||||||
// RAII wrapper for HDEVINFO to ensure SetupDiDestroyDeviceInfoList is always called.
|
// RAII wrapper for HDEVINFO to ensure SetupDiDestroyDeviceInfoList is always called.
|
||||||
|
@ -57,6 +60,9 @@ impl Drop for DevInfo {
|
||||||
// We expose this as the public handle type.
|
// We expose this as the public handle type.
|
||||||
pub struct VddHandle(HANDLE);
|
pub struct VddHandle(HANDLE);
|
||||||
|
|
||||||
|
unsafe impl Send for VddHandle {}
|
||||||
|
unsafe impl Sync for VddHandle {}
|
||||||
|
|
||||||
impl Drop for VddHandle {
|
impl Drop for VddHandle {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
close_device_handle(self.0);
|
close_device_handle(self.0);
|
||||||
|
@ -417,3 +423,38 @@ pub fn vdd_remove_display(vdd: &VddHandle, index: i32) -> bool {
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_physical_monitor_connected() -> bool {
|
||||||
|
// fetch windows monitor lists.
|
||||||
|
let mut physical_monitors = Vec::new();
|
||||||
|
let mut info = DISPLAY_DEVICEW {
|
||||||
|
cb: std::mem::size_of::<DISPLAY_DEVICEW>() as u32,
|
||||||
|
DeviceName: [0; 32],
|
||||||
|
DeviceString: [0; 128],
|
||||||
|
StateFlags: DISPLAY_DEVICE_STATE_FLAGS(0),
|
||||||
|
DeviceID: [0; 128],
|
||||||
|
DeviceKey: [0; 128],
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut i = 0;
|
||||||
|
while unsafe { EnumDisplayDevicesW(PWSTR::null(), i, &mut info, 0).as_bool() } {
|
||||||
|
if (info.StateFlags & DISPLAY_DEVICE_ACTIVE).0 != 0 {
|
||||||
|
let device_name = String::from_utf16_lossy(&info.DeviceName)
|
||||||
|
.trim_end_matches('\0')
|
||||||
|
.to_string();
|
||||||
|
debug!("Found monitor: {}", device_name);
|
||||||
|
// 排除 parsec 虚拟显示器,只统计物理显示器
|
||||||
|
if !device_name.to_lowercase().contains("parsec") {
|
||||||
|
physical_monitors.push(device_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
trace!("Found {} physical monitors", physical_monitors.len());
|
||||||
|
for (i, monitor) in physical_monitors.iter().enumerate() {
|
||||||
|
trace!("Physical Monitor {}: {}", i, monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
!physical_monitors.is_empty()
|
||||||
|
}
|
||||||
|
|
49
src/main.rs
49
src/main.rs
|
@ -1,8 +1,47 @@
|
||||||
mod app;
|
use std::sync::{
|
||||||
use app::App;
|
Arc,
|
||||||
|
atomic::{AtomicI32, Ordering},
|
||||||
|
};
|
||||||
|
|
||||||
|
use parsec_vdd::{
|
||||||
|
DeviceStatus, VDD_ADAPTER_GUID, VDD_CLASS_GUID, VDD_HARDWARE_ID, is_physical_monitor_connected,
|
||||||
|
open_device_handle, query_device_status, vdd_add_display, vdd_remove_display, vdd_update,
|
||||||
|
};
|
||||||
|
|
||||||
|
static INDEX: AtomicI32 = AtomicI32::new(-1);
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut app = App::new();
|
let status: DeviceStatus = query_device_status(&VDD_CLASS_GUID, VDD_HARDWARE_ID);
|
||||||
app.watch_monitors();
|
if status != DeviceStatus::Ok {
|
||||||
}
|
panic!("Failed to query device status");
|
||||||
|
}
|
||||||
|
let handle = match open_device_handle(&VDD_ADAPTER_GUID) {
|
||||||
|
Some(handle) => Arc::new(handle),
|
||||||
|
None => panic!("Failed to open device handle"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let handle_clone = Arc::clone(&handle);
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
loop {
|
||||||
|
vdd_update(&handle_clone);
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let vdd_is_running = INDEX.load(Ordering::SeqCst) != -1;
|
||||||
|
let has_physicial_monitor = is_physical_monitor_connected();
|
||||||
|
if !has_physicial_monitor && !vdd_is_running {
|
||||||
|
INDEX.store(
|
||||||
|
match vdd_add_display(&handle) {
|
||||||
|
Some(i) => i,
|
||||||
|
None => -1,
|
||||||
|
},
|
||||||
|
Ordering::SeqCst,
|
||||||
|
);
|
||||||
|
} else if has_physicial_monitor && vdd_is_running {
|
||||||
|
vdd_remove_display(&handle, INDEX.load(Ordering::SeqCst));
|
||||||
|
INDEX.store(-1, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(1000));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue