Skip to content

Commit

Permalink
Update Monitor Struct ⭐
Browse files Browse the repository at this point in the history
	modified:   Cargo.toml
	new file:   obs.c
	modified:   src/monitor.rs
  • Loading branch information
NiiightmareXD committed Nov 26, 2023
1 parent ef49c63 commit 0959c24
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 3 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ windows = { version = "0.52.0", features = [
"System",
"Graphics_DirectX_Direct3D11",
"Foundation_Metadata",
"Win32_Devices_Display",
] }

[package.metadata.docs.rs]
Expand Down
70 changes: 70 additions & 0 deletions obs.c
Original file line number Diff line number Diff line change
@@ -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]");
}
}
157 changes: 154 additions & 3 deletions src/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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")]
Expand All @@ -43,17 +55,26 @@ 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<Self, Box<dyn Error + Send + Sync>> {
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)),
};

Ok(monitor)
}

pub fn index(&self) -> Result<usize, Box<dyn Error + Send + Sync>> {
let device_name = self.device_name()?;
Ok(device_name.replace("\\\\.\\DISPLAY1", "to").parse()?)
}

/// Get Monitor Name
pub fn name(&self) -> Result<String, Box<dyn Error + Send + Sync>> {
let mut monitor_info = MONITORINFOEXW {
Expand All @@ -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::<DISPLAYCONFIG_SOURCE_DEVICE_NAME>() 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::<Vec<_>>(),
)?;

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::<DISPLAYCONFIG_TARGET_DEVICE_NAME>() 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::<Vec<_>>(),
)?;
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<String, Box<dyn Error + Send + Sync>> {
let mut monitor_info = MONITORINFOEXW {
monitorInfo: MONITORINFO {
cbSize: mem::size_of::<MONITORINFOEXW>() 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
Expand All @@ -85,6 +211,30 @@ impl Monitor {
.collect::<Vec<_>>(),
)?;

Ok(device_name)
}

/// Get Monitor Device String
pub fn device_string(&self) -> Result<String, Box<dyn Error + Send + Sync>> {
let mut monitor_info = MONITORINFOEXW {
monitorInfo: MONITORINFO {
cbSize: mem::size_of::<MONITORINFOEXW>() 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::<DISPLAY_DEVICEW>() as u32,
DeviceName: [0; 32],
Expand All @@ -105,6 +255,7 @@ impl Monitor {
} {
return Err(Box::new(MonitorErrors::FailedToGetMonitorName));
}

let device_string = String::from_utf16(
&display_device
.DeviceString
Expand All @@ -115,7 +266,7 @@ impl Monitor {
.collect::<Vec<_>>(),
)?;

Ok(format!("{device_string} ({device_name})"))
Ok(device_string)
}

/// Get A List Of All Monitors
Expand Down

0 comments on commit 0959c24

Please sign in to comment.