Merge remote-tracking branch 'rustdesk/master' into flutter_desktop

# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	build.rs
#	flutter/.gitignore
#	flutter/lib/common.dart
#	flutter/lib/mobile/pages/remote_page.dart
#	flutter/lib/models/model.dart
#	flutter/lib/models/native_model.dart
#	flutter/lib/models/server_model.dart
#	flutter/pubspec.lock
#	flutter/pubspec.yaml
#	src/client.rs
#	src/client/file_trait.rs
#	src/flutter.rs
#	src/mobile_ffi.rs
#	src/ui.rs
This commit is contained in:
Kingtous
2022-06-27 11:18:53 +08:00
138 changed files with 5534 additions and 798 deletions

View File

@@ -17,17 +17,19 @@ block = "0.1"
cfg-if = "1.0"
libc = "0.2"
num_cpus = "1.13"
lazy_static = "1.4"
[dependencies.winapi]
version = "0.3"
default-features = true
features = ["dxgi", "dxgi1_2", "dxgi1_5", "d3d11", "winuser"]
features = ["dxgi", "dxgi1_2", "dxgi1_5", "d3d11", "winuser", "winerror", "errhandlingapi", "libloaderapi"]
[target.'cfg(target_os = "android")'.dependencies]
android_logger = "0.10"
jni = "0.19"
lazy_static = "1.4"
log = "0.4"
serde_json = "1.0"
[target.'cfg(not(target_os = "android"))'.dev-dependencies]
repng = "0.2"

View File

@@ -0,0 +1,105 @@
extern crate repng;
extern crate scrap;
use std::fs::File;
#[cfg(windows)]
use scrap::CapturerMag;
use scrap::{i420_to_rgb, Display};
fn main() {
let n = Display::all().unwrap().len();
for i in 0..n {
#[cfg(windows)]
record(i);
}
}
fn get_display(i: usize) -> Display {
Display::all().unwrap().remove(i)
}
#[cfg(windows)]
fn record(i: usize) {
for d in Display::all().unwrap() {
println!("{:?} {} {}", d.origin(), d.width(), d.height());
}
let display = get_display(i);
let (w, h) = (display.width(), display.height());
{
let mut capture_mag =
CapturerMag::new(display.origin(), display.width(), display.height(), false)
.expect("Couldn't begin capture.");
let wnd_cls = "";
let wnd_name = "RustDeskPrivacyWindow";
if false == capture_mag.exclude(wnd_cls, wnd_name).unwrap() {
println!("No window found for cls {} name {}", wnd_cls, wnd_name);
} else {
println!("Filter window for cls {} name {}", wnd_cls, wnd_name);
}
let frame = capture_mag.frame(0).unwrap();
println!("Capture data len: {}, Saving...", frame.len());
let mut bitflipped = Vec::with_capacity(w * h * 4);
let stride = frame.len() / h;
for y in 0..h {
for x in 0..w {
let i = stride * y + 4 * x;
bitflipped.extend_from_slice(&[frame[i + 2], frame[i + 1], frame[i], 255]);
}
}
// Save the image.
let name = format!("capture_mag_{}_1.png", i);
repng::encode(
File::create(name.clone()).unwrap(),
w as u32,
h as u32,
&bitflipped,
)
.unwrap();
println!("Image saved to `{}`.", name);
}
{
let mut capture_mag =
CapturerMag::new(display.origin(), display.width(), display.height(), true)
.expect("Couldn't begin capture.");
let wnd_cls = "";
let wnd_title = "RustDeskPrivacyWindow";
if false == capture_mag.exclude(wnd_cls, wnd_title).unwrap() {
println!("No window found for cls {} title {}", wnd_cls, wnd_title);
} else {
println!("Filter window for cls {} title {}", wnd_cls, wnd_title);
}
let buffer = capture_mag.frame(0).unwrap();
println!("Capture data len: {}, Saving...", buffer.len());
let mut frame = Default::default();
i420_to_rgb(w, h, &buffer, &mut frame);
let mut bitflipped = Vec::with_capacity(w * h * 4);
let stride = frame.len() / h;
for y in 0..h {
for x in 0..w {
let i = stride * y + 3 * x;
bitflipped.extend_from_slice(&[frame[i], frame[i + 1], frame[i + 2], 255]);
}
}
let name = format!("capture_mag_{}_2.png", i);
repng::encode(
File::create(name.clone()).unwrap(),
w as u32,
h as u32,
&bitflipped,
)
.unwrap();
println!("Image saved to `{}`.", name);
}
}

View File

@@ -46,8 +46,7 @@ fn record(i: usize) {
}
}
};
println!("Captured! Saving...");
println!("Captured data len: {}, Saving...", buffer.len());
// Flip the BGRA image into a RGBA image.
@@ -96,8 +95,7 @@ fn record(i: usize) {
}
}
};
println!("Captured! Saving...");
println!("Captured data len: {}, Saving...", buffer.len());
let mut frame = Default::default();
i420_to_rgb(w, h, &buffer, &mut frame);

View File

@@ -17,7 +17,6 @@ use std::time::{Duration, Instant};
lazy_static! {
static ref JVM: RwLock<Option<JavaVM>> = RwLock::new(None);
static ref MAIN_SERVICE_CTX: RwLock<Option<GlobalRef>> = RwLock::new(None); // MainService -> video service / audio service / info
static ref INPUT_CTX: RwLock<Option<GlobalRef>> = RwLock::new(None);
static ref VIDEO_RAW: Mutex<FrameRaw> = Mutex::new(FrameRaw::new("video", MAX_VIDEO_FRAME_TIMEOUT));
static ref AUDIO_RAW: Mutex<FrameRaw> = Mutex::new(FrameRaw::new("audio", MAX_AUDIO_FRAME_TIMEOUT));
}
@@ -148,25 +147,10 @@ pub extern "system" fn Java_com_carriez_flutter_1hbb_MainService_init(
*MAIN_SERVICE_CTX.write().unwrap() = Some(context);
}
#[no_mangle]
pub extern "system" fn Java_com_carriez_flutter_1hbb_InputService_init(
env: JNIEnv,
_class: JClass,
ctx: JObject,
) {
log::debug!("InputService init from java");
let jvm = env.get_java_vm().unwrap();
*JVM.write().unwrap() = Some(jvm);
let context = env.new_global_ref(ctx).unwrap();
*INPUT_CTX.write().unwrap() = Some(context);
}
pub fn call_input_service_mouse_input(mask: i32, x: i32, y: i32) -> JniResult<()> {
pub fn call_main_service_mouse_input(mask: i32, x: i32, y: i32) -> JniResult<()> {
if let (Some(jvm), Some(ctx)) = (
JVM.read().unwrap().as_ref(),
INPUT_CTX.read().unwrap().as_ref(),
MAIN_SERVICE_CTX.read().unwrap().as_ref(),
) {
let env = jvm.attach_current_thread_as_daemon()?;
env.call_method(

View File

@@ -1,11 +1,13 @@
use crate::android::ffi::*;
use crate::rgba_to_i420;
use lazy_static::lazy_static;
use serde_json::Value;
use std::collections::HashMap;
use std::io;
use std::sync::Mutex;
lazy_static! {
static ref SCREEN_SIZE: Mutex<(u16, u16)> = Mutex::new((0, 0));
static ref SCREEN_SIZE: Mutex<(u16, u16, u16)> = Mutex::new((0, 0, 0)); // (width, height, scale)
}
pub struct Capturer {
@@ -65,9 +67,7 @@ impl Display {
pub fn primary() -> io::Result<Display> {
let mut size = SCREEN_SIZE.lock().unwrap();
if size.0 == 0 || size.1 == 0 {
let (w, h) = get_size().unwrap_or((0, 0));
size.0 = w;
size.1 = h;
*size = get_size().unwrap_or_default();
}
Ok(Display {
default: true,
@@ -111,19 +111,33 @@ impl Display {
pub fn refresh_size() {
let mut size = SCREEN_SIZE.lock().unwrap();
let (w, h) = get_size().unwrap_or((0, 0));
size.0 = w;
size.1 = h;
*size = get_size().unwrap_or_default();
}
// Big android screen size will be shrinked, to improve performance when screen-capturing and encoding
// e.g 2280x1080 size will be set to 1140x540, and `scale` is 2
// need to multiply by `4` (2*2) when compute the bitrate
pub fn fix_quality() -> u16 {
let scale = SCREEN_SIZE.lock().unwrap().2;
if scale <= 0 {
1
} else {
scale * scale
}
}
}
fn get_size() -> Option<(u16, u16)> {
fn get_size() -> Option<(u16, u16, u16)> {
let res = call_main_service_get_by_name("screen_size").ok()?;
if res.len() > 0 {
let mut sp = res.split(":");
let w = sp.next()?.parse::<u16>().ok()?;
let h = sp.next()?.parse::<u16>().ok()?;
return Some((w, h));
if let Ok(json) = serde_json::from_str::<HashMap<String, Value>>(&res) {
if let (Some(Value::Number(w)), Some(Value::Number(h)), Some(Value::Number(scale))) =
(json.get("width"), json.get("height"), json.get("scale"))
{
let w = w.as_i64()? as _;
let h = h.as_i64()? as _;
let scale = scale.as_i64()? as _;
return Some((w, h, scale));
}
}
None
}

View File

@@ -111,3 +111,32 @@ impl Display {
self.origin() == (0, 0)
}
}
pub struct CapturerMag {
inner: dxgi::mag::CapturerMag,
data: Vec<u8>,
}
impl CapturerMag {
pub fn is_supported() -> bool {
dxgi::mag::CapturerMag::is_supported()
}
pub fn new(origin: (i32, i32), width: usize, height: usize, use_yuv: bool) -> io::Result<Self> {
Ok(CapturerMag {
inner: dxgi::mag::CapturerMag::new(origin, width, height, use_yuv)?,
data: Vec::new(),
})
}
pub fn exclude(&mut self, cls: &str, name: &str) -> io::Result<bool> {
self.inner.exclude(cls, name)
}
// ((x, y), w, h)
pub fn get_rect(&self) -> ((i32, i32), usize, usize) {
self.inner.get_rect()
}
pub fn frame<'a>(&'a mut self, _timeout_ms: u32) -> io::Result<Frame<'a>> {
self.inner.frame(&mut self.data)?;
Ok(Frame(&self.data))
}
}

View File

@@ -19,7 +19,7 @@ cfg_if! {
} else if #[cfg(dxgi)] {
mod dxgi;
pub use self::dxgi::*;
} else if #[cfg(android)] {
} else if #[cfg(target_os = "android")] {
mod android;
pub use self::android::*;
}else {
@@ -36,13 +36,11 @@ mod vpx;
#[inline]
pub fn would_block_if_equal(old: &mut Vec<u128>, b: &[u8]) -> std::io::Result<()> {
let b = unsafe {
std::slice::from_raw_parts::<u128>(b.as_ptr() as _, b.len() / 16)
};
let b = unsafe { std::slice::from_raw_parts::<u128>(b.as_ptr() as _, b.len() / 16) };
if b == &old[..] {
return Err(std::io::ErrorKind::WouldBlock.into());
}
old.resize(b.len(), 0);
old.copy_from_slice(b);
Ok(())
}
}

662
libs/scrap/src/dxgi/mag.rs Normal file
View File

@@ -0,0 +1,662 @@
// logic from webrtc -- https://github.com/shiguredo/libwebrtc/blob/main/modules/desktop_capture/win/screen_capturer_win_magnifier.cc
use lazy_static;
use std::{
ffi::CString,
io::{Error, ErrorKind, Result},
mem::size_of,
sync::Mutex,
};
use winapi::{
shared::{
basetsd::SIZE_T,
guiddef::{IsEqualGUID, GUID},
minwindef::{BOOL, DWORD, FALSE, FARPROC, HINSTANCE, HMODULE, HRGN, TRUE, UINT},
ntdef::{LONG, NULL},
windef::{HWND, RECT},
winerror::ERROR_CLASS_ALREADY_EXISTS,
},
um::{
errhandlingapi::GetLastError,
libloaderapi::{FreeLibrary, GetModuleHandleExA, GetProcAddress, LoadLibraryExA},
winuser::*,
},
};
pub const MW_FILTERMODE_EXCLUDE: u32 = 0;
pub const MW_FILTERMODE_INCLUDE: u32 = 1;
pub const GET_MODULE_HANDLE_EX_FLAG_PIN: u32 = 1;
pub const GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT: u32 = 2;
pub const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS: u32 = 4;
pub const LOAD_LIBRARY_AS_DATAFILE: u32 = 2;
pub const LOAD_WITH_ALTERED_SEARCH_PATH: u32 = 8;
pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: u32 = 16;
pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: u32 = 32;
pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: u32 = 64;
pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: u32 = 128;
pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: u32 = 256;
pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: u32 = 512;
pub const LOAD_LIBRARY_SEARCH_USER_DIRS: u32 = 1024;
pub const LOAD_LIBRARY_SEARCH_SYSTEM32: u32 = 2048;
pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: u32 = 4096;
pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: u32 = 8192;
pub const LOAD_LIBRARY_SEARCH_SYSTEM32_NO_FORWARDER: u32 = 16384;
pub const LOAD_LIBRARY_OS_INTEGRITY_CONTINUITY: u32 = 32768;
extern "C" {
pub static GUID_WICPixelFormat32bppRGBA: GUID;
}
lazy_static::lazy_static! {
static ref MAG_BUFFER: Mutex<(bool, Vec<u8>)> = Default::default();
}
pub type REFWICPixelFormatGUID = *const GUID;
pub type WICPixelFormatGUID = GUID;
#[allow(non_snake_case)]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct tagMAGIMAGEHEADER {
pub width: UINT,
pub height: UINT,
pub format: WICPixelFormatGUID,
pub stride: UINT,
pub offset: UINT,
pub cbSize: SIZE_T,
}
pub type MAGIMAGEHEADER = tagMAGIMAGEHEADER;
pub type PMAGIMAGEHEADER = *mut tagMAGIMAGEHEADER;
// Function types
pub type MagImageScalingCallback = ::std::option::Option<
unsafe extern "C" fn(
hwnd: HWND,
srcdata: *mut ::std::os::raw::c_void,
srcheader: MAGIMAGEHEADER,
destdata: *mut ::std::os::raw::c_void,
destheader: MAGIMAGEHEADER,
unclipped: RECT,
clipped: RECT,
dirty: HRGN,
) -> BOOL,
>;
extern "C" {
pub fn MagShowSystemCursor(fShowCursor: BOOL) -> BOOL;
}
pub type MagInitializeFunc = ::std::option::Option<unsafe extern "C" fn() -> BOOL>;
pub type MagUninitializeFunc = ::std::option::Option<unsafe extern "C" fn() -> BOOL>;
pub type MagSetWindowSourceFunc =
::std::option::Option<unsafe extern "C" fn(hwnd: HWND, rect: RECT) -> BOOL>;
pub type MagSetWindowFilterListFunc = ::std::option::Option<
unsafe extern "C" fn(
hwnd: HWND,
dwFilterMode: DWORD,
count: ::std::os::raw::c_int,
pHWND: *mut HWND,
) -> BOOL,
>;
pub type MagSetImageScalingCallbackFunc = ::std::option::Option<
unsafe extern "C" fn(hwnd: HWND, callback: MagImageScalingCallback) -> BOOL,
>;
#[repr(C)]
#[derive(Debug, Clone)]
struct MagInterface {
init_succeeded: bool,
lib_handle: HINSTANCE,
pub mag_initialize_func: MagInitializeFunc,
pub mag_uninitialize_func: MagUninitializeFunc,
pub set_window_source_func: MagSetWindowSourceFunc,
pub set_window_filter_list_func: MagSetWindowFilterListFunc,
pub set_image_scaling_callback_func: MagSetImageScalingCallbackFunc,
}
// NOTE: MagInitialize and MagUninitialize should not be called in global init and uninit.
// If so, strange errors occur.
impl MagInterface {
fn new() -> Result<Self> {
let mut s = MagInterface {
init_succeeded: false,
lib_handle: NULL as _,
mag_initialize_func: None,
mag_uninitialize_func: None,
set_window_source_func: None,
set_window_filter_list_func: None,
set_image_scaling_callback_func: None,
};
s.init_succeeded = false;
unsafe {
if GetSystemMetrics(SM_CMONITORS) != 1 {
// Do not try to use the magnifier in multi-screen setup (where the API
// crashes sometimes).
return Err(Error::new(
ErrorKind::Other,
"Magnifier capturer cannot work on multi-screen system.",
));
}
// load lib
let lib_file_name = "Magnification.dll";
let lib_file_name_c = CString::new(lib_file_name).unwrap();
s.lib_handle = LoadLibraryExA(
lib_file_name_c.as_ptr() as _,
NULL,
LOAD_WITH_ALTERED_SEARCH_PATH,
);
if s.lib_handle.is_null() {
return Err(Error::new(
ErrorKind::Other,
format!(
"Failed to LoadLibraryExA {}, error: {}",
lib_file_name,
GetLastError()
),
));
};
// load functions
s.mag_initialize_func = Some(std::mem::transmute(Self::load_func(
s.lib_handle,
"MagInitialize",
)?));
s.mag_uninitialize_func = Some(std::mem::transmute(Self::load_func(
s.lib_handle,
"MagUninitialize",
)?));
s.set_window_source_func = Some(std::mem::transmute(Self::load_func(
s.lib_handle,
"MagSetWindowSource",
)?));
s.set_window_filter_list_func = Some(std::mem::transmute(Self::load_func(
s.lib_handle,
"MagSetWindowFilterList",
)?));
s.set_image_scaling_callback_func = Some(std::mem::transmute(Self::load_func(
s.lib_handle,
"MagSetImageScalingCallback",
)?));
// MagInitialize
if let Some(init_func) = s.mag_initialize_func {
if FALSE == init_func() {
return Err(Error::new(
ErrorKind::Other,
format!("Failed to MagInitialize, error: {}", GetLastError()),
));
} else {
s.init_succeeded = true;
}
} else {
return Err(Error::new(
ErrorKind::Other,
"Unreachable, mag_initialize_func should not be none",
));
}
}
Ok(s)
}
unsafe fn load_func(lib_module: HMODULE, func_name: &str) -> Result<FARPROC> {
let func_name_c = CString::new(func_name).unwrap();
let func = GetProcAddress(lib_module, func_name_c.as_ptr() as _);
if func.is_null() {
return Err(Error::new(
ErrorKind::Other,
format!(
"Failed to GetProcAddress {}, error: {}",
func_name,
GetLastError()
),
));
}
Ok(func)
}
pub(super) fn uninit(&mut self) {
if self.init_succeeded {
if let Some(uninit_func) = self.mag_uninitialize_func {
unsafe {
if FALSE == uninit_func() {
println!("Failed MagUninitialize {}", GetLastError())
}
}
}
if !self.lib_handle.is_null() {
unsafe {
if FALSE == FreeLibrary(self.lib_handle) {
println!("Failed FreeLibrary {}", GetLastError())
}
}
self.lib_handle = NULL as _;
}
}
self.init_succeeded = false;
}
}
impl Drop for MagInterface {
fn drop(&mut self) {
self.uninit();
}
}
pub struct CapturerMag {
mag_interface: MagInterface,
host_window: HWND,
magnifier_window: HWND,
magnifier_host_class: CString,
host_window_name: CString,
magnifier_window_class: CString,
magnifier_window_name: CString,
rect: RECT,
width: usize,
height: usize,
use_yuv: bool,
data: Vec<u8>,
}
impl Drop for CapturerMag {
fn drop(&mut self) {
self.destroy_windows();
self.mag_interface.uninit();
}
}
impl CapturerMag {
pub(crate) fn is_supported() -> bool {
MagInterface::new().is_ok()
}
pub(crate) fn new(
origin: (i32, i32),
width: usize,
height: usize,
use_yuv: bool,
) -> Result<Self> {
unsafe {
let x = GetSystemMetrics(SM_XVIRTUALSCREEN);
let y = GetSystemMetrics(SM_YVIRTUALSCREEN);
let w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
let h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
if !(origin.0 == x as _ && origin.1 == y as _ && width == w as _ && height == h as _) {
return Err(Error::new(
ErrorKind::Other,
format!(
"Failed Check screen rect ({}, {}, {} , {}) to ({}, {}, {}, {})",
origin.0,
origin.1,
origin.0 + width as i32,
origin.1 + height as i32,
x,
y,
x + w,
y + h
),
));
}
}
let mut s = Self {
mag_interface: MagInterface::new()?,
host_window: 0 as _,
magnifier_window: 0 as _,
magnifier_host_class: CString::new("ScreenCapturerWinMagnifierHost")?,
host_window_name: CString::new("MagnifierHost")?,
magnifier_window_class: CString::new("Magnifier")?,
magnifier_window_name: CString::new("MagnifierWindow")?,
rect: RECT {
left: origin.0 as _,
top: origin.1 as _,
right: origin.0 + width as LONG,
bottom: origin.1 + height as LONG,
},
width,
height,
use_yuv,
data: Vec::new(),
};
unsafe {
let mut instance = 0 as HMODULE;
if 0 == GetModuleHandleExA(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
DefWindowProcA as _,
&mut instance as _,
) {
return Err(Error::new(
ErrorKind::Other,
format!("Failed to GetModuleHandleExA, error: {}", GetLastError()),
));
}
// Register the host window class. See the MSDN documentation of the
// Magnification API for more infomation.
let wcex = WNDCLASSEXA {
cbSize: size_of::<WNDCLASSEXA>() as _,
style: 0,
lpfnWndProc: Some(DefWindowProcA),
cbClsExtra: 0,
cbWndExtra: 0,
hInstance: instance,
hIcon: 0 as _,
hCursor: LoadCursorA(NULL as _, IDC_ARROW as _),
hbrBackground: 0 as _,
lpszClassName: s.magnifier_host_class.as_ptr() as _,
lpszMenuName: 0 as _,
hIconSm: 0 as _,
};
// Ignore the error which may happen when the class is already registered.
if 0 == RegisterClassExA(&wcex) {
let code = GetLastError();
if code != ERROR_CLASS_ALREADY_EXISTS {
return Err(Error::new(
ErrorKind::Other,
format!("Failed to RegisterClassExA, error: {}", code),
));
}
}
// Create the host window.
s.host_window = CreateWindowExA(
WS_EX_LAYERED,
s.magnifier_host_class.as_ptr(),
s.host_window_name.as_ptr(),
WS_POPUP,
0,
0,
0,
0,
NULL as _,
NULL as _,
instance,
NULL,
);
if s.host_window.is_null() {
return Err(Error::new(
ErrorKind::Other,
format!(
"Failed to CreateWindowExA host_window, error: {}",
GetLastError()
),
));
}
// Create the magnifier control.
s.magnifier_window = CreateWindowExA(
0,
s.magnifier_window_class.as_ptr(),
s.magnifier_window_name.as_ptr(),
WS_CHILD | WS_VISIBLE,
0,
0,
0,
0,
s.host_window,
NULL as _,
instance,
NULL,
);
if s.magnifier_window.is_null() {
return Err(Error::new(
ErrorKind::Other,
format!(
"Failed CreateWindowA magnifier_window, error: {}",
GetLastError()
),
));
}
// Hide the host window.
let _ = ShowWindow(s.host_window, SW_HIDE);
// Set the scaling callback to receive captured image.
if let Some(set_callback_func) = s.mag_interface.set_image_scaling_callback_func {
if FALSE
== set_callback_func(
s.magnifier_window,
Some(Self::on_gag_image_scaling_callback),
)
{
return Err(Error::new(
ErrorKind::Other,
format!(
"Failed to MagSetImageScalingCallback, error: {}",
GetLastError()
),
));
}
} else {
return Err(Error::new(
ErrorKind::Other,
"Unreachable, set_image_scaling_callback_func should not be none",
));
}
}
Ok(s)
}
pub(crate) fn exclude(&mut self, cls: &str, name: &str) -> Result<bool> {
let name_c = CString::new(name).unwrap();
unsafe {
let mut hwnd = if cls.len() == 0 {
FindWindowExA(NULL as _, NULL as _, NULL as _, name_c.as_ptr())
} else {
let cls_c = CString::new(cls).unwrap();
FindWindowExA(NULL as _, NULL as _, cls_c.as_ptr(), name_c.as_ptr())
};
if hwnd.is_null() {
return Ok(false);
}
if let Some(set_window_filter_list_func) =
self.mag_interface.set_window_filter_list_func
{
if FALSE
== set_window_filter_list_func(
self.magnifier_window,
MW_FILTERMODE_EXCLUDE,
1,
&mut hwnd,
)
{
return Err(Error::new(
ErrorKind::Other,
format!(
"Failed MagSetWindowFilterList for cls {} name {}, err: {}",
cls,
name,
GetLastError()
),
));
}
} else {
return Err(Error::new(
ErrorKind::Other,
"Unreachable, MagSetWindowFilterList should not be none",
));
}
}
Ok(true)
}
pub(crate) fn get_rect(&self) -> ((i32, i32), usize, usize) {
(
(self.rect.left as _, self.rect.top as _),
self.width as _,
self.height as _,
)
}
fn clear_data() {
let mut lock = MAG_BUFFER.lock().unwrap();
lock.0 = false;
lock.1.clear();
}
pub(crate) fn frame(&mut self, data: &mut Vec<u8>) -> Result<()> {
Self::clear_data();
unsafe {
let x = GetSystemMetrics(SM_XVIRTUALSCREEN);
let y = GetSystemMetrics(SM_YVIRTUALSCREEN);
let w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
let h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
if !(self.rect.left == x as _
&& self.rect.top == y as _
&& self.rect.right == (x + w) as _
&& self.rect.bottom == (y + h) as _)
{
return Err(Error::new(
ErrorKind::Other,
format!(
"Failed Check screen rect ({}, {}, {} , {}) to ({}, {}, {}, {})",
self.rect.left,
self.rect.top,
self.rect.right,
self.rect.bottom,
x,
y,
x + w,
y + h
),
));
}
if FALSE
== SetWindowPos(
self.magnifier_window,
HWND_TOP,
self.rect.left,
self.rect.top,
self.rect.right,
self.rect.bottom,
0,
)
{
return Err(Error::new(
ErrorKind::Other,
format!(
"Failed SetWindowPos (x, y, w , h) - ({}, {}, {}, {}), error {}",
self.rect.left,
self.rect.top,
self.rect.right,
self.rect.bottom,
GetLastError()
),
));
}
// on_gag_image_scaling_callback will be called and fill in the
// frame before set_window_source_func_ returns.
if let Some(set_window_source_func) = self.mag_interface.set_window_source_func {
if FALSE == set_window_source_func(self.magnifier_window, self.rect) {
return Err(Error::new(
ErrorKind::Other,
format!("Failed to MagSetWindowSource, error: {}", GetLastError()),
));
}
} else {
return Err(Error::new(
ErrorKind::Other,
"Unreachable, set_window_source_func should not be none",
));
}
}
let mut lock = MAG_BUFFER.lock().unwrap();
if !lock.0 {
return Err(Error::new(
ErrorKind::Other,
"No data captured by magnifier",
));
}
if self.use_yuv {
self.data.resize(lock.1.len(), 0);
unsafe {
std::ptr::copy_nonoverlapping(&mut lock.1[0], &mut self.data[0], self.data.len());
}
crate::common::bgra_to_i420(
self.width as usize,
self.height as usize,
&self.data,
data,
);
} else {
data.resize(lock.1.len(), 0);
unsafe {
std::ptr::copy_nonoverlapping(&mut lock.1[0], &mut data[0], data.len());
}
}
Ok(())
}
fn destroy_windows(&mut self) {
if !self.magnifier_window.is_null() {
unsafe {
if FALSE == DestroyWindow(self.magnifier_window) {
//
println!("Failed DestroyWindow magnifier window {}", GetLastError())
}
}
}
self.magnifier_window = NULL as _;
if !self.host_window.is_null() {
unsafe {
if FALSE == DestroyWindow(self.host_window) {
//
println!("Failed DestroyWindow host window {}", GetLastError())
}
}
}
self.host_window = NULL as _;
}
unsafe extern "C" fn on_gag_image_scaling_callback(
_hwnd: HWND,
srcdata: *mut ::std::os::raw::c_void,
srcheader: MAGIMAGEHEADER,
_destdata: *mut ::std::os::raw::c_void,
_destheader: MAGIMAGEHEADER,
_unclipped: RECT,
_clipped: RECT,
_dirty: HRGN,
) -> BOOL {
Self::clear_data();
if !IsEqualGUID(&srcheader.format, &GUID_WICPixelFormat32bppRGBA) {
// log warning?
return FALSE;
}
let mut lock = MAG_BUFFER.lock().unwrap();
lock.1.resize(srcheader.cbSize, 0);
std::ptr::copy_nonoverlapping(srcdata as _, &mut lock.1[0], srcheader.cbSize);
lock.0 = true;
TRUE
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test() {
let mut capture_mag = CapturerMag::new((0, 0), 1920, 1080, false).unwrap();
capture_mag.exclude("", "RustDeskPrivacyWindow").unwrap();
std::thread::sleep(std::time::Duration::from_millis(1000 * 10));
let mut data = Vec::new();
capture_mag.frame(&mut data).unwrap();
println!("capture data len: {}", data.len());
}
}

View File

@@ -1,6 +1,7 @@
use std::{io, mem, ptr, slice};
pub mod gdi;
pub use gdi::CapturerGDI;
pub mod mag;
use winapi::{
shared::{

View File

@@ -14,13 +14,13 @@ pub mod quartz;
#[cfg(x11)]
pub mod x11;
#[cfg(all(x11, feature="wayland"))]
#[cfg(all(x11, feature = "wayland"))]
pub mod wayland;
#[cfg(dxgi)]
pub mod dxgi;
#[cfg(android)]
#[cfg(target_os = "android")]
pub mod android;
mod common;