mirror of
https://github.com/MolotovCherry/virtual-display-rs.git
synced 2025-09-04 15:17:53 +00:00
Implement hardware cursor #81
This commit is contained in:
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"rust-analyzer.check.command": "clippy"
|
||||
"rust-analyzer.check.command": "clippy",
|
||||
}
|
||||
|
@@ -81,6 +81,8 @@ Please see the [wiki](https://github.com/MolotovCherry/virtual-display-rs/wiki/V
|
||||
3. Install [`cargo-make`](https://github.com/sagiegurari/cargo-make) if you don't have it
|
||||
4. Install [`cargo-target-dir`](https://github.com/MolotovCherry/cargo-target-dir)
|
||||
|
||||
Make sure you generate your own windows code signing cert and install it according to "Installing the certificate" section.
|
||||
|
||||
You can build it with `cargo make build` (debug) or `cargo make -p prod build` (release), and check the `target/output` directory for all the files
|
||||
|
||||
To build the installer, do a `cargo make build-installer` (dev) or `cargo make -p prod build-installer` (release). In order to build the installer, you need [wix toolset](https://github.com/wixtoolset/wix3/releases) installed and on `Path`
|
||||
|
@@ -1,24 +1,29 @@
|
||||
use std::{
|
||||
ffi::c_void,
|
||||
mem::{self, size_of},
|
||||
num::{ParseIntError, TryFromIntError},
|
||||
ptr::{addr_of_mut, NonNull},
|
||||
};
|
||||
|
||||
use anyhow::anyhow;
|
||||
use log::error;
|
||||
use log::{error, warn};
|
||||
use wdf_umdf::{
|
||||
IddCxAdapterInitAsync, IddCxError, IddCxMonitorArrival, IddCxMonitorCreate, WdfError,
|
||||
WdfObjectDelete, WDF_DECLARE_CONTEXT_TYPE,
|
||||
IddCxAdapterInitAsync, IddCxError, IddCxMonitorArrival, IddCxMonitorCreate,
|
||||
IddCxMonitorSetupHardwareCursor, WdfError, WdfObjectDelete, WDF_DECLARE_CONTEXT_TYPE,
|
||||
};
|
||||
use wdf_umdf_sys::{
|
||||
DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY, HANDLE, IDARG_IN_ADAPTER_INIT, IDARG_IN_MONITORCREATE,
|
||||
IDARG_OUT_ADAPTER_INIT, IDARG_OUT_MONITORARRIVAL, IDARG_OUT_MONITORCREATE, IDDCX_ADAPTER,
|
||||
IDDCX_ADAPTER_CAPS, IDDCX_ENDPOINT_DIAGNOSTIC_INFO, IDDCX_ENDPOINT_VERSION,
|
||||
IDDCX_FEATURE_IMPLEMENTATION, IDDCX_MONITOR, IDDCX_MONITOR_DESCRIPTION,
|
||||
IDDCX_MONITOR_DESCRIPTION_TYPE, IDDCX_MONITOR_INFO, IDDCX_SWAPCHAIN, IDDCX_TRANSMISSION_TYPE,
|
||||
LUID, NTSTATUS, WDFDEVICE, WDFOBJECT, WDF_OBJECT_ATTRIBUTES,
|
||||
IDARG_IN_SETUP_HWCURSOR, IDARG_OUT_ADAPTER_INIT, IDARG_OUT_MONITORARRIVAL,
|
||||
IDARG_OUT_MONITORCREATE, IDDCX_ADAPTER, IDDCX_ADAPTER_CAPS, IDDCX_CURSOR_CAPS,
|
||||
IDDCX_ENDPOINT_DIAGNOSTIC_INFO, IDDCX_ENDPOINT_VERSION, IDDCX_FEATURE_IMPLEMENTATION,
|
||||
IDDCX_MONITOR, IDDCX_MONITOR_DESCRIPTION, IDDCX_MONITOR_DESCRIPTION_TYPE, IDDCX_MONITOR_INFO,
|
||||
IDDCX_SWAPCHAIN, IDDCX_TRANSMISSION_TYPE, IDDCX_XOR_CURSOR_SUPPORT, LUID, NTSTATUS, WDFDEVICE,
|
||||
WDFOBJECT, WDF_OBJECT_ATTRIBUTES,
|
||||
};
|
||||
use windows::{
|
||||
core::{s, w, GUID},
|
||||
Win32::{Foundation::TRUE, System::Threading::CreateEventA},
|
||||
};
|
||||
use windows::core::{w, GUID};
|
||||
|
||||
use crate::{
|
||||
direct_3d_device::Direct3DDevice,
|
||||
@@ -250,6 +255,8 @@ impl MonitorContext {
|
||||
processor.run(swap_chain, device, new_frame_event);
|
||||
|
||||
self.swap_chain_processor = Some(processor);
|
||||
|
||||
self.setup_hw_cursor();
|
||||
} else {
|
||||
// It's important to delete the swap-chain if D3D initialization fails, so that the OS knows to generate a new
|
||||
// swap-chain and try again.
|
||||
@@ -263,4 +270,40 @@ impl MonitorContext {
|
||||
pub fn unassign_swap_chain(&mut self) {
|
||||
self.swap_chain_processor.take();
|
||||
}
|
||||
|
||||
pub fn setup_hw_cursor(&mut self) {
|
||||
let mouse_event = unsafe { CreateEventA(None, false, false, s!("vdd_mouse_event")) };
|
||||
let Ok(mouse_event) = mouse_event else {
|
||||
error!("CreateEventA failed: {mouse_event:?}");
|
||||
return;
|
||||
};
|
||||
|
||||
// setup hardware cursor
|
||||
let cursor_info = IDDCX_CURSOR_CAPS {
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
Size: std::mem::size_of::<IDDCX_CURSOR_CAPS>() as u32,
|
||||
AlphaCursorSupport: TRUE.0,
|
||||
MaxX: 512,
|
||||
MaxY: 512,
|
||||
ColorXorCursorSupport: IDDCX_XOR_CURSOR_SUPPORT::IDDCX_XOR_CURSOR_SUPPORT_NONE,
|
||||
};
|
||||
|
||||
let hw_cursor = IDARG_IN_SETUP_HWCURSOR {
|
||||
CursorInfo: cursor_info,
|
||||
hNewCursorDataAvailable: mouse_event.0 as *mut c_void,
|
||||
};
|
||||
|
||||
let res = unsafe { IddCxMonitorSetupHardwareCursor(self.device, &hw_cursor) };
|
||||
let Ok(res) = res else {
|
||||
error!("IddCxMonitorSetupHardwareCursor() failed: {res:?}");
|
||||
return;
|
||||
};
|
||||
|
||||
if res.is_warning() {
|
||||
warn!("IddCxMonitorSetupHardwareCursor() warn: {res:?}");
|
||||
}
|
||||
if res.is_error() {
|
||||
error!("IddCxMonitorSetupHardwareCursor() failed: {res:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,8 +2,9 @@
|
||||
#![allow(clippy::missing_errors_doc)]
|
||||
|
||||
use wdf_umdf_sys::{
|
||||
IDARG_IN_ADAPTER_INIT, IDARG_IN_MONITORCREATE, IDARG_IN_SWAPCHAINSETDEVICE,
|
||||
IDARG_OUT_ADAPTER_INIT, IDARG_OUT_MONITORARRIVAL, IDARG_OUT_MONITORCREATE,
|
||||
IDARG_IN_ADAPTER_INIT, IDARG_IN_MONITORCREATE, IDARG_IN_QUERY_HWCURSOR,
|
||||
IDARG_IN_SETUP_HWCURSOR, IDARG_IN_SWAPCHAINSETDEVICE, IDARG_OUT_ADAPTER_INIT,
|
||||
IDARG_OUT_MONITORARRIVAL, IDARG_OUT_MONITORCREATE, IDARG_OUT_QUERY_HWCURSOR,
|
||||
IDARG_OUT_RELEASEANDACQUIREBUFFER, IDDCX_ADAPTER, IDDCX_MONITOR, IDDCX_SWAPCHAIN,
|
||||
IDD_CX_CLIENT_CONFIG, NTSTATUS, WDFDEVICE, WDFDEVICE_INIT,
|
||||
};
|
||||
@@ -135,9 +136,9 @@ pub unsafe fn IddCxDeviceInitialize(
|
||||
/// None. User is responsible for safety.
|
||||
pub unsafe fn IddCxAdapterInitAsync(
|
||||
// in
|
||||
pInArgs: *const IDARG_IN_ADAPTER_INIT,
|
||||
pInArgs: &IDARG_IN_ADAPTER_INIT,
|
||||
// out
|
||||
pOutArgs: *mut IDARG_OUT_ADAPTER_INIT,
|
||||
pOutArgs: &mut IDARG_OUT_ADAPTER_INIT,
|
||||
) -> Result<NTSTATUS, IddCxError> {
|
||||
IddCxCall! {
|
||||
IddCxAdapterInitAsync(
|
||||
@@ -155,9 +156,9 @@ pub unsafe fn IddCxMonitorCreate(
|
||||
// in
|
||||
AdapterObject: IDDCX_ADAPTER,
|
||||
// in
|
||||
pInArgs: *const IDARG_IN_MONITORCREATE,
|
||||
pInArgs: &IDARG_IN_MONITORCREATE,
|
||||
// out
|
||||
pOutArgs: *mut IDARG_OUT_MONITORCREATE,
|
||||
pOutArgs: &mut IDARG_OUT_MONITORCREATE,
|
||||
) -> Result<NTSTATUS, IddCxError> {
|
||||
IddCxCall!(
|
||||
IddCxMonitorCreate(
|
||||
@@ -176,7 +177,7 @@ pub unsafe fn IddCxMonitorArrival(
|
||||
// in
|
||||
MonitorObject: IDDCX_MONITOR,
|
||||
// out
|
||||
pOutArgs: *mut IDARG_OUT_MONITORARRIVAL,
|
||||
pOutArgs: &mut IDARG_OUT_MONITORARRIVAL,
|
||||
) -> Result<NTSTATUS, IddCxError> {
|
||||
IddCxCall!(
|
||||
IddCxMonitorArrival(
|
||||
@@ -254,3 +255,42 @@ pub unsafe fn IddCxMonitorDeparture(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// None. User is responsible for safety.
|
||||
#[rustfmt::skip]
|
||||
pub unsafe fn IddCxMonitorSetupHardwareCursor(
|
||||
// in
|
||||
MonitorObject: IDDCX_MONITOR,
|
||||
// in
|
||||
pInArgs: &IDARG_IN_SETUP_HWCURSOR
|
||||
) -> Result<NTSTATUS, IddCxError> {
|
||||
IddCxCall!(
|
||||
IddCxMonitorSetupHardwareCursor(
|
||||
MonitorObject,
|
||||
pInArgs
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// None. User is responsible for safety.
|
||||
#[rustfmt::skip]
|
||||
pub unsafe fn IddCxMonitorQueryHardwareCursor(
|
||||
// in
|
||||
MonitorObject: IDDCX_MONITOR,
|
||||
// in
|
||||
pInArgs: &IDARG_IN_QUERY_HWCURSOR,
|
||||
// out
|
||||
pOutArgs: &mut IDARG_OUT_QUERY_HWCURSOR
|
||||
) -> Result<NTSTATUS, IddCxError> {
|
||||
IddCxCall!(
|
||||
IddCxMonitorQueryHardwareCursor(
|
||||
MonitorObject,
|
||||
pInArgs,
|
||||
pOutArgs
|
||||
)
|
||||
)
|
||||
}
|
||||
|
Reference in New Issue
Block a user