diff --git a/libs/scrap/src/common/dxgi.rs b/libs/scrap/src/common/dxgi.rs index 476027a72..4683ad5f2 100644 --- a/libs/scrap/src/common/dxgi.rs +++ b/libs/scrap/src/common/dxgi.rs @@ -62,13 +62,23 @@ pub struct Display(dxgi::Display); impl Display { pub fn primary() -> io::Result { - match dxgi::Displays::new()?.next() { - Some(inner) => Ok(Display(inner)), - None => Err(NotFound.into()), - } + // not implemented yet + Err(NotFound.into()) } pub fn all() -> io::Result> { + let tmp = Self::all_().unwrap_or(Default::default()); + if tmp.is_empty() { + println!("Display got from gdi"); + return Ok(dxgi::Displays::get_from_gdi() + .drain(..) + .map(Display) + .collect::>()); + } + Ok(tmp) + } + + fn all_() -> io::Result> { Ok(dxgi::Displays::new()?.map(Display).collect::>()) } @@ -92,13 +102,12 @@ impl Display { self.0.is_online() } - pub fn origin(&self) -> (usize, usize) { - let o = self.0.origin(); - (o.0 as usize, o.1 as usize) + pub fn origin(&self) -> (i32, i32) { + self.0.origin() } - // to-do: not found primary display api for dxgi pub fn is_primary(&self) -> bool { - self.name() == Self::primary().unwrap().name() + // https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-devmodea + self.origin() == (0, 0) } } diff --git a/libs/scrap/src/common/quartz.rs b/libs/scrap/src/common/quartz.rs index 9b1d8907d..f0095a8ef 100644 --- a/libs/scrap/src/common/quartz.rs +++ b/libs/scrap/src/common/quartz.rs @@ -114,9 +114,9 @@ impl Display { self.0.is_online() } - pub fn origin(&self) -> (usize, usize) { + pub fn origin(&self) -> (i32, i32) { let o = self.0.bounds().origin; - (o.x as usize, o.y as usize) + (o.x as _, o.y as _) } pub fn is_primary(&self) -> bool { diff --git a/libs/scrap/src/common/x11.rs b/libs/scrap/src/common/x11.rs index 99063f1bb..3eab43c1c 100644 --- a/libs/scrap/src/common/x11.rs +++ b/libs/scrap/src/common/x11.rs @@ -68,7 +68,7 @@ impl Display { self.0.rect().h as usize } - pub fn origin(&self) -> (usize, usize) { + pub fn origin(&self) -> (i32, i32) { let r = self.0.rect(); (r.x as _, r.y as _) } diff --git a/libs/scrap/src/dxgi/gdi.rs b/libs/scrap/src/dxgi/gdi.rs index 015a42ecc..9fb0611e2 100644 --- a/libs/scrap/src/dxgi/gdi.rs +++ b/libs/scrap/src/dxgi/gdi.rs @@ -13,6 +13,7 @@ use winapi::{ BITMAPINFO, BITMAPINFOHEADER, BI_RGB, + CAPTUREBLT, DIB_RGB_COLORS, //CAPTUREBLT, HGDI_ERROR, RGBQUAD, @@ -97,7 +98,7 @@ impl CapturerGDI { self.screen_dc, 0, 0, - SRCCOPY, // | CAPTUREBLT, // CAPTUREBLT enable layered window but also make cursor blinking + SRCCOPY | CAPTUREBLT, // CAPTUREBLT enable layered window but also make cursor blinking ); if res == 0 { return Err("Failed to copy screen to Windows buffer".into()); diff --git a/libs/scrap/src/dxgi/mod.rs b/libs/scrap/src/dxgi/mod.rs index 08f4a2764..a24b357a3 100644 --- a/libs/scrap/src/dxgi/mod.rs +++ b/libs/scrap/src/dxgi/mod.rs @@ -12,7 +12,7 @@ use winapi::{ // shared::dxgiformat::{DXGI_FORMAT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_420_OPAQUE}, shared::dxgi1_2::{IDXGIOutput1, IID_IDXGIOutput1}, shared::dxgitype::DXGI_MODE_ROTATION, - shared::minwindef::{TRUE, UINT}, + shared::minwindef::{DWORD, FALSE, TRUE, UINT}, shared::ntdef::LONG, shared::windef::HMONITOR, shared::winerror::{ @@ -25,7 +25,9 @@ use winapi::{ D3D11_CPU_ACCESS_READ, D3D11_SDK_VERSION, D3D11_USAGE_STAGING, }, um::d3dcommon::D3D_DRIVER_TYPE_UNKNOWN, + um::wingdi::*, um::winnt::HRESULT, + um::winuser::*, }; //TODO: Split up into files. @@ -55,20 +57,24 @@ impl Capturer { let mut desc = unsafe { mem::MaybeUninit::uninit().assume_init() }; let mut gdi_capturer = None; - let mut res = wrap_hresult(unsafe { - D3D11CreateDevice( - display.adapter as *mut _, - D3D_DRIVER_TYPE_UNKNOWN, - ptr::null_mut(), // No software rasterizer. - 0, // No device flags. - ptr::null_mut(), // Feature levels. - 0, // Feature levels' length. - D3D11_SDK_VERSION, - &mut device, - ptr::null_mut(), - &mut context, - ) - }); + let mut res = if display.gdi { + wrap_hresult(1) + } else { + wrap_hresult(unsafe { + D3D11CreateDevice( + display.adapter as *mut _, + D3D_DRIVER_TYPE_UNKNOWN, + ptr::null_mut(), // No software rasterizer. + 0, // No device flags. + ptr::null_mut(), // Feature levels. + 0, // Feature levels' length. + D3D11_SDK_VERSION, + &mut device, + ptr::null_mut(), + &mut context, + ) + }) + }; if res.is_err() { gdi_capturer = display.create_gdi(); @@ -346,6 +352,56 @@ impl Displays { }) } + pub fn get_from_gdi() -> Vec { + let mut all = Vec::new(); + let mut i: DWORD = 0; + loop { + let mut d: DISPLAY_DEVICEW = unsafe { std::mem::MaybeUninit::uninit().assume_init() }; + d.cb = std::mem::size_of::() as _; + let ok = unsafe { EnumDisplayDevicesW(std::ptr::null(), i, &mut d as _, 0) }; + if ok == FALSE { + break; + } + i += 1; + if 0 == (d.StateFlags & DISPLAY_DEVICE_ACTIVE) + || (d.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) > 0 + { + continue; + } + // let is_primary = (d.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) > 0; + let mut disp = Display { + inner: std::ptr::null_mut(), + adapter: std::ptr::null_mut(), + desc: unsafe { std::mem::zeroed() }, + gdi: true, + }; + disp.desc.DeviceName = d.DeviceName; + let mut m: DEVMODEW = unsafe { std::mem::MaybeUninit::uninit().assume_init() }; + m.dmSize = std::mem::size_of::() as _; + m.dmDriverExtra = 0; + let ok = unsafe { + EnumDisplaySettingsExW( + disp.desc.DeviceName.as_ptr(), + ENUM_CURRENT_SETTINGS, + &mut m as _, + 0, + ) + }; + if ok == FALSE { + continue; + } + disp.desc.DesktopCoordinates.left = unsafe { m.u1.s2().dmPosition.x }; + disp.desc.DesktopCoordinates.top = unsafe { m.u1.s2().dmPosition.y }; + disp.desc.DesktopCoordinates.right = + disp.desc.DesktopCoordinates.left + m.dmPelsWidth as i32; + disp.desc.DesktopCoordinates.bottom = + disp.desc.DesktopCoordinates.top + m.dmPelsHeight as i32; + disp.desc.AttachedToDesktop = 1; + all.push(disp); + } + all + } + // No Adapter => Some(None) // Non-Empty Adapter => Some(Some(OUTPUT)) // End of Adapter => None @@ -414,6 +470,7 @@ impl Displays { inner, adapter: self.adapter, desc, + gdi: false, })) } } @@ -460,8 +517,11 @@ pub struct Display { inner: *mut IDXGIOutput1, adapter: *mut IDXGIAdapter1, desc: DXGI_OUTPUT_DESC, + gdi: bool, } +// https://github.com/dchapyshev/aspia/blob/59233c5d01a4d03ed6de19b03ce77d61a6facf79/source/base/desktop/win/screen_capture_utils.cc + impl Display { pub fn width(&self) -> LONG { self.desc.DesktopCoordinates.right - self.desc.DesktopCoordinates.left @@ -511,6 +571,9 @@ impl Display { impl Drop for Display { fn drop(&mut self) { + if self.inner.is_null() { + return; + } unsafe { (*self.inner).Release(); (*self.adapter).Release();