parsec-vdd/src/main.rs

114 lines
3.9 KiB
Rust

#[allow(non_snake_case)]
use parsec_vdd::{
query_device_status, open_device_handle, vdd_version, vdd_update,
vdd_add_display, vdd_remove_display, DeviceStatus, VddHandle,
VDD_CLASS_GUID, VDD_HARDWARE_ID, VDD_ADAPTER_GUID, VDD_MAX_DISPLAYS
};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
// FFI import for _getch() to read a single character without waiting for Enter.
#[link(name = "msvcrt")]
extern "C" {
fn _getch() -> i32;
}
// Main application logic, translated from main.c
fn main() {
// 1. Check driver status.
let status = query_device_status(&VDD_CLASS_GUID, VDD_HARDWARE_ID);
if status != DeviceStatus::Ok {
println!("Parsec VDD device is not OK, status: {:?}", status);
return;
}
println!("Parsec VDD device is OK.");
// 2. Obtain device handle.
// The handle is wrapped in an Option and our RAII VddHandle struct.
let vdd = match open_device_handle(&VDD_ADAPTER_GUID) {
Some(handle) => Arc::new(handle), // Use Arc for sharing between threads
None => {
println!("Failed to obtain the device handle.");
return;
}
};
println!("Successfully obtained device handle.");
if let Some(version) = vdd_version(&vdd) {
println!("Driver version: {}", version);
}
// 3. Set up the updater thread.
let running = Arc::new(AtomicBool::new(true));
let running_clone = Arc::clone(&running);
let vdd_clone = Arc::clone(&vdd);
let updater_thread = thread::spawn(move || {
while running_clone.load(Ordering::SeqCst) {
vdd_update(&vdd_clone);
thread::sleep(Duration::from_millis(100));
}
});
// 4. Main interaction loop.
let mut displays: Vec<i32> = Vec::new();
println!("\nPress 'a' to add a virtual display.");
println!("Press 'r' to remove the last added display.");
println!("Press 'q' to quit (this will unplug all displays).");
while running.load(Ordering::SeqCst) {
// Use the imported _getch function.
let key = unsafe { _getch() as u8 as char };
match key {
'q' | 'Q' => {
println!("\nQuitting...");
running.store(false, Ordering::SeqCst);
}
'a' | 'A' => {
if displays.len() < VDD_MAX_DISPLAYS {
if let Some(index) = vdd_add_display(&vdd) {
if index != -1 {
displays.push(index);
println!("Added a new virtual display, index: {}", index);
} else {
println!("Failed to add virtual display (driver returned -1).");
}
} else {
println!("IOCTL call to add display failed.");
}
} else {
println!(
"Limit exceeded ({}), could not add more virtual displays.",
VDD_MAX_DISPLAYS
);
}
}
'r' | 'R' => {
if let Some(index) = displays.pop() {
vdd_remove_display(&vdd, index);
println!("Removed the last virtual display, index: {}", index);
} else {
println!("No added virtual displays to remove.");
}
}
_ => {} // Ignore other keys
}
}
// 5. Cleanup.
println!("Removing all displays before exiting...");
for index in displays {
vdd_remove_display(&vdd, index);
}
// Wait for the updater thread to finish.
updater_thread.join().expect("Updater thread panicked");
println!("Cleanup complete. Exiting.");
// The VddHandle (wrapped in Arc) will be dropped automatically here,
// which calls CloseHandle, cleaning up the resource.
}