From 0959c24e0f40e4b2e86d5cba76fe6670b3d0da93 Mon Sep 17 00:00:00 2001 From: NiiightmareXD Date: Sun, 26 Nov 2023 08:02:45 -0800 Subject: [PATCH] =?UTF-8?q?Update=20Monitor=20Struct=20=E2=AD=90=20=09modi?= =?UTF-8?q?fied:=20=20=20Cargo.toml=20=09new=20file:=20=20=20obs.c=20=09mo?= =?UTF-8?q?dified:=20=20=20src/monitor.rs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 1 + obs.c | 70 ++++++++++++++++++++++ src/monitor.rs | 157 ++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 225 insertions(+), 3 deletions(-) create mode 100644 obs.c diff --git a/Cargo.toml b/Cargo.toml index 7c2ee20..2f26712 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ windows = { version = "0.52.0", features = [ "System", "Graphics_DirectX_Direct3D11", "Foundation_Metadata", + "Win32_Devices_Display", ] } [package.metadata.docs.rs] diff --git a/obs.c b/obs.c new file mode 100644 index 0000000..ad8248f --- /dev/null +++ b/obs.c @@ -0,0 +1,70 @@ +static bool GetMonitorTarget(LPCWSTR device, + DISPLAYCONFIG_TARGET_DEVICE_NAME *target) +{ + bool found = false; + + UINT32 numPath, numMode; + if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPath, + &numMode) == ERROR_SUCCESS) { + DISPLAYCONFIG_PATH_INFO *paths = + bmalloc(numPath * sizeof(DISPLAYCONFIG_PATH_INFO)); + DISPLAYCONFIG_MODE_INFO *modes = + bmalloc(numMode * sizeof(DISPLAYCONFIG_MODE_INFO)); + if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &numPath, paths, + &numMode, modes, + NULL) == ERROR_SUCCESS) { + for (size_t i = 0; i < numPath; ++i) { + const DISPLAYCONFIG_PATH_INFO *const path = + &paths[i]; + + DISPLAYCONFIG_SOURCE_DEVICE_NAME + source; + source.header.type = + DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + source.header.size = sizeof(source); + source.header.adapterId = + path->sourceInfo.adapterId; + source.header.id = path->sourceInfo.id; + if (DisplayConfigGetDeviceInfo( + &source.header) == ERROR_SUCCESS && + wcscmp(device, source.viewGdiDeviceName) == + 0) { + target->header.type = + DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; + target->header.size = sizeof(*target); + target->header.adapterId = + path->sourceInfo.adapterId; + target->header.id = path->targetInfo.id; + found = DisplayConfigGetDeviceInfo( + &target->header) == + ERROR_SUCCESS; + break; + } + } + } + + bfree(modes); + bfree(paths); + } + + return found; +} + +static void GetMonitorName(HMONITOR handle, char *name, size_t count) +{ + MONITORINFOEXW mi; + DISPLAYCONFIG_TARGET_DEVICE_NAME target; + + mi.cbSize = sizeof(mi); + if (GetMonitorInfoW(handle, (LPMONITORINFO)&mi) && + GetMonitorTarget(mi.szDevice, &target)) { + char *friendly_name; + os_wcs_to_utf8_ptr(target.monitorFriendlyDeviceName, 0, + &friendly_name); + + strcpy_s(name, count, friendly_name); + bfree(friendly_name); + } else { + strcpy_s(name, count, "[OBS: Unknown]"); + } +} \ No newline at end of file diff --git a/src/monitor.rs b/src/monitor.rs index 430edf6..7f3c0bc 100644 --- a/src/monitor.rs +++ b/src/monitor.rs @@ -4,6 +4,14 @@ use windows::{ core::PCWSTR, Graphics::Capture::GraphicsCaptureItem, Win32::{ + Devices::Display::{ + DisplayConfigGetDeviceInfo, GetDisplayConfigBufferSizes, QueryDisplayConfig, + DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME, DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME, + DISPLAYCONFIG_DEVICE_INFO_HEADER, DISPLAYCONFIG_MODE_INFO, DISPLAYCONFIG_PATH_INFO, + DISPLAYCONFIG_SOURCE_DEVICE_NAME, DISPLAYCONFIG_TARGET_DEVICE_NAME, + DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS, DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY, + QDC_ONLY_ACTIVE_PATHS, + }, Foundation::{BOOL, LPARAM, POINT, RECT, TRUE}, Graphics::Gdi::{ EnumDisplayDevicesW, EnumDisplayMonitors, GetMonitorInfoW, MonitorFromPoint, @@ -18,6 +26,10 @@ use windows::{ pub enum MonitorErrors { #[error("Failed To Find Monitor")] NotFound, + #[error("Failed To Find Monitor Name")] + NameNotFound, + #[error("Monitor Index Is Lower Than One")] + IndexIsLowerThanOne, #[error("Failed To Get Monitor Info")] FailedToGetMonitorInfo, #[error("Failed To Get Monitor Name")] @@ -43,10 +55,14 @@ impl Monitor { Ok(Self { monitor }) } - /// Get The Monitor From Enumerate Index + /// Get The Monitor From It's Index pub fn from_index(index: usize) -> Result> { + if index < 1 { + return Err(Box::new(MonitorErrors::IndexIsLowerThanOne)); + } + let monitor = Self::enumerate()?; - let monitor = match monitor.get(index) { + let monitor = match monitor.get(index - 1) { Some(monitor) => *monitor, None => return Err(Box::new(MonitorErrors::NotFound)), }; @@ -54,6 +70,11 @@ impl Monitor { Ok(monitor) } + pub fn index(&self) -> Result> { + let device_name = self.device_name()?; + Ok(device_name.replace("\\\\.\\DISPLAY1", "to").parse()?) + } + /// Get Monitor Name pub fn name(&self) -> Result> { let mut monitor_info = MONITORINFOEXW { @@ -75,6 +96,111 @@ impl Monitor { return Err(Box::new(MonitorErrors::FailedToGetMonitorInfo)); } + let mut number_of_paths = 0; + let mut number_of_modes = 0; + unsafe { + GetDisplayConfigBufferSizes( + QDC_ONLY_ACTIVE_PATHS, + &mut number_of_paths, + &mut number_of_modes, + )?; + }; + + let mut paths = vec![DISPLAYCONFIG_PATH_INFO::default(); number_of_paths as usize]; + let mut modes = vec![DISPLAYCONFIG_MODE_INFO::default(); number_of_modes as usize]; + unsafe { + QueryDisplayConfig( + QDC_ONLY_ACTIVE_PATHS, + &mut number_of_paths, + paths.as_mut_ptr(), + &mut number_of_modes, + modes.as_mut_ptr(), + None, + ) + }?; + + for path in paths { + let mut source = DISPLAYCONFIG_SOURCE_DEVICE_NAME { + header: DISPLAYCONFIG_DEVICE_INFO_HEADER { + r#type: DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME, + size: mem::size_of::() as u32, + adapterId: path.sourceInfo.adapterId, + id: path.sourceInfo.id, + }, + viewGdiDeviceName: [0; 32], + }; + + let device_name = self.device_name()?; + let view_gdi_device_name = String::from_utf16( + &monitor_info + .szDevice + .as_slice() + .iter() + .take_while(|ch| **ch != 0x0000) + .copied() + .collect::>(), + )?; + + if unsafe { DisplayConfigGetDeviceInfo(&mut source.header) } == 0 + && device_name == view_gdi_device_name + { + let mut target = DISPLAYCONFIG_TARGET_DEVICE_NAME { + header: DISPLAYCONFIG_DEVICE_INFO_HEADER { + r#type: DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME, + size: mem::size_of::() as u32, + adapterId: path.sourceInfo.adapterId, + id: path.targetInfo.id, + }, + flags: DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS::default(), + outputTechnology: DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY::default(), + edidManufactureId: 0, + edidProductCodeId: 0, + connectorInstance: 0, + monitorFriendlyDeviceName: [0; 64], + monitorDevicePath: [0; 128], + }; + + if unsafe { DisplayConfigGetDeviceInfo(&mut target.header) } == 0 { + let name = String::from_utf16( + &target + .monitorFriendlyDeviceName + .as_slice() + .iter() + .take_while(|ch| **ch != 0x0000) + .copied() + .collect::>(), + )?; + return Ok(name); + } else { + return Err(Box::new(MonitorErrors::FailedToGetMonitorInfo)); + } + } + } + + Err(Box::new(MonitorErrors::NameNotFound)) + } + + /// Get Monitor Device Name + pub fn device_name(&self) -> Result> { + let mut monitor_info = MONITORINFOEXW { + monitorInfo: MONITORINFO { + cbSize: mem::size_of::() as u32, + rcMonitor: RECT::default(), + rcWork: RECT::default(), + dwFlags: 0, + }, + szDevice: [0; 32], + }; + if unsafe { + !GetMonitorInfoW( + self.as_raw_hmonitor(), + std::ptr::addr_of_mut!(monitor_info).cast(), + ) + .as_bool() + } { + return Err(Box::new(MonitorErrors::FailedToGetMonitorInfo)); + } + let device_name = String::from_utf16( &monitor_info .szDevice @@ -85,6 +211,30 @@ impl Monitor { .collect::>(), )?; + Ok(device_name) + } + + /// Get Monitor Device String + pub fn device_string(&self) -> Result> { + let mut monitor_info = MONITORINFOEXW { + monitorInfo: MONITORINFO { + cbSize: mem::size_of::() as u32, + rcMonitor: RECT::default(), + rcWork: RECT::default(), + dwFlags: 0, + }, + szDevice: [0; 32], + }; + if unsafe { + !GetMonitorInfoW( + self.as_raw_hmonitor(), + std::ptr::addr_of_mut!(monitor_info).cast(), + ) + .as_bool() + } { + return Err(Box::new(MonitorErrors::FailedToGetMonitorInfo)); + } + let mut display_device = DISPLAY_DEVICEW { cb: mem::size_of::() as u32, DeviceName: [0; 32], @@ -105,6 +255,7 @@ impl Monitor { } { return Err(Box::new(MonitorErrors::FailedToGetMonitorName)); } + let device_string = String::from_utf16( &display_device .DeviceString @@ -115,7 +266,7 @@ impl Monitor { .collect::>(), )?; - Ok(format!("{device_string} ({device_name})")) + Ok(device_string) } /// Get A List Of All Monitors