mirror of
https://github.com/fanchenio/DawnLauncher.git
synced 2025-07-13 12:52:10 +08:00
674 lines
21 KiB
Rust
674 lines
21 KiB
Rust
use base64::{engine::general_purpose, Engine as _};
|
||
use clipboard_win::{formats, get_clipboard};
|
||
use image::{imageops::flip_vertical, ImageBuffer, ImageFormat, Rgba};
|
||
use napi::{
|
||
threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode},
|
||
JsFunction,
|
||
};
|
||
use serde::{Deserialize, Serialize};
|
||
use std::{
|
||
collections::HashMap,
|
||
io::Cursor,
|
||
path::Path,
|
||
process::Command,
|
||
sync::atomic::{AtomicBool, Ordering},
|
||
};
|
||
use windows::{
|
||
core::{ComInterface, HSTRING, PCSTR, PCWSTR},
|
||
w,
|
||
Win32::{
|
||
Foundation::{HWND, LPARAM, LRESULT, MAX_PATH, POINT, RECT, SIZE, WPARAM},
|
||
Graphics::Gdi::{
|
||
GetMonitorInfoW, GetObjectW, MonitorFromWindow, BITMAP, MONITORINFO,
|
||
MONITOR_DEFAULTTONEAREST,
|
||
},
|
||
Storage::FileSystem::SearchPathW,
|
||
System::{
|
||
Com::{
|
||
CoCreateInstance, CoInitializeEx, CoUninitialize, IPersistFile,
|
||
CLSCTX_INPROC_SERVER, COINIT_APARTMENTTHREADED, STGM_READ,
|
||
},
|
||
Environment::GetEnvironmentVariableW,
|
||
SystemInformation::GetSystemDirectoryW,
|
||
},
|
||
UI::{
|
||
Input::Ime::{
|
||
ImmGetContext, ImmReleaseContext, ImmSetConversionStatus, IME_CMODE_ALPHANUMERIC,
|
||
IME_SMODE_AUTOMATIC,
|
||
},
|
||
Shell::{
|
||
BHID_SFUIObject, IContextMenu, IShellItem, IShellItemImageFactory, IShellLinkW,
|
||
SHCreateItemFromParsingName, SHEmptyRecycleBinW, SHQueryUserNotificationState,
|
||
ShellExecuteW, ShellLink, CMF_NORMAL, CMINVOKECOMMANDINFO,
|
||
QUNS_ACCEPTS_NOTIFICATIONS, QUNS_APP, QUNS_BUSY, QUNS_NOT_PRESENT,
|
||
QUNS_PRESENTATION_MODE, QUNS_QUIET_TIME, QUNS_RUNNING_D3D_FULL_SCREEN,
|
||
SHERB_NOSOUND, SIIGBF_ICONONLY, SLGP_UNCPRIORITY,
|
||
},
|
||
WindowsAndMessaging::{
|
||
CallNextHookEx, CreatePopupMenu, DestroyMenu, FindWindowW, GetClassNameW,
|
||
GetCursorPos, GetForegroundWindow, GetSystemMetrics, GetWindowRect, SendMessageW,
|
||
SetForegroundWindow, SetWindowsHookExW, TrackPopupMenu, WindowFromPoint, HHOOK,
|
||
MSLLHOOKSTRUCT, SC_MONITORPOWER, SM_CXSCREEN, SM_CYSCREEN, SW_NORMAL,
|
||
SW_SHOWDEFAULT, TPM_NONOTIFY, TPM_RETURNCMD, WH_MOUSE_LL, WM_LBUTTONDOWN,
|
||
WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEHWHEEL, WM_MOUSEMOVE,
|
||
WM_MOUSEWHEEL, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SYSCOMMAND,
|
||
},
|
||
},
|
||
},
|
||
};
|
||
|
||
// 获取图标并转为BASE64
|
||
pub fn get_file_icon(path: &str) -> Option<String> {
|
||
// 返回信息
|
||
let mut base64 = None;
|
||
// HSTRING
|
||
let path = HSTRING::from(path);
|
||
// PCWSTR
|
||
let path: PCWSTR = PCWSTR(path.as_ptr());
|
||
// unsafe
|
||
unsafe {
|
||
// Init
|
||
let _ = CoInitializeEx(None, COINIT_APARTMENTTHREADED);
|
||
}
|
||
// IShellItemImageFactory
|
||
let result = unsafe {
|
||
SHCreateItemFromParsingName::<PCWSTR, Option<_>, IShellItemImageFactory>(path, None)
|
||
};
|
||
if let Ok(shell_item_image_factory) = result {
|
||
if let Some(mut image_buffer) = get_file_icon_image_buffer(&shell_item_image_factory, 256) {
|
||
// 判断像素点,是否是小图标
|
||
let mut transparency: f64 = 0_f64;
|
||
let mut non_transparency: f64 = 0_f64;
|
||
for y in 0..image_buffer.height() {
|
||
for x in 0..image_buffer.width() {
|
||
let pixel = image_buffer.get_pixel(x, y);
|
||
let alpha = pixel[3]; // 获取像素的 Alpha 通道值
|
||
if alpha == 0 {
|
||
// 透明
|
||
transparency += 1_f64;
|
||
} else {
|
||
// 不透明
|
||
non_transparency += 1_f64;
|
||
}
|
||
}
|
||
}
|
||
// 计算如果透明区域大于百分之70就代表是小图标
|
||
let proportion =
|
||
(transparency / (transparency + non_transparency) * 100_f64).round() as u32;
|
||
if proportion >= 70 {
|
||
// 获取小图标
|
||
if let Some(image_buffer_small) =
|
||
get_file_icon_image_buffer(&shell_item_image_factory, 48)
|
||
{
|
||
image_buffer = image_buffer_small;
|
||
}
|
||
}
|
||
// 翻转图片
|
||
image_buffer = flip_vertical(&image_buffer);
|
||
// 转码
|
||
base64 = Some(image_buffer_to_base64(image_buffer));
|
||
}
|
||
}
|
||
unsafe {
|
||
// UnInit
|
||
CoUninitialize();
|
||
}
|
||
base64
|
||
}
|
||
|
||
// 获取图标并转为ImageBuffer
|
||
fn get_file_icon_image_buffer(
|
||
shell_item_image_factory: &IShellItemImageFactory,
|
||
size: i32,
|
||
) -> Option<ImageBuffer<Rgba<u8>, Vec<u8>>> {
|
||
// 获取图片
|
||
let result =
|
||
unsafe { shell_item_image_factory.GetImage(SIZE { cx: size, cy: size }, SIIGBF_ICONONLY) };
|
||
if let Ok(h_bitmap) = result {
|
||
// 转为BITMAP
|
||
let mut bitmap: BITMAP = BITMAP::default();
|
||
unsafe {
|
||
GetObjectW(
|
||
h_bitmap,
|
||
std::mem::size_of::<BITMAP>() as i32,
|
||
Some(&mut bitmap as *mut _ as _),
|
||
);
|
||
}
|
||
// 转换ImageBuffer
|
||
let width: u32 = bitmap.bmWidth as u32;
|
||
let height = bitmap.bmHeight as u32;
|
||
let pixel_data: &[u8] = unsafe {
|
||
std::slice::from_raw_parts(bitmap.bmBits as *const u8, (width * height * 4) as usize)
|
||
};
|
||
let result = ImageBuffer::<Rgba<u8>, _>::from_raw(width, height, pixel_data.to_vec());
|
||
if let Some(mut image_buffer) = result {
|
||
// 将ImageBuffer的颜色通道顺序从BGRA转为RGB
|
||
for pixel in image_buffer.pixels_mut() {
|
||
let b = pixel[0];
|
||
let r = pixel[2];
|
||
pixel[0] = r;
|
||
pixel[2] = b;
|
||
}
|
||
return Some(image_buffer);
|
||
}
|
||
}
|
||
None
|
||
}
|
||
|
||
/**
|
||
* imageBuffer转BASE64
|
||
*/
|
||
fn image_buffer_to_base64(image_buffer: ImageBuffer<Rgba<u8>, Vec<u8>>) -> String {
|
||
// imageBufferData
|
||
let mut image_buffer_data = Cursor::new(Vec::new());
|
||
// write
|
||
image_buffer
|
||
.write_to(&mut image_buffer_data, ImageFormat::Png)
|
||
.unwrap();
|
||
// 转码
|
||
format!(
|
||
"data:image/png;base64,{}",
|
||
general_purpose::STANDARD.encode(image_buffer_data.into_inner())
|
||
)
|
||
}
|
||
|
||
/**
|
||
* 运行
|
||
*/
|
||
pub fn shell_execute(
|
||
operation: String,
|
||
file: String,
|
||
params: String,
|
||
start_location: Option<String>,
|
||
) {
|
||
// dir
|
||
let dir = start_location.unwrap_or_else(|| {
|
||
// 判断是否是文件夹
|
||
let path = Path::new(&file);
|
||
if path.is_dir() {
|
||
// 文件夹
|
||
file.clone()
|
||
} else {
|
||
// 文件 获取上一级目录
|
||
path.parent().unwrap().display().to_string()
|
||
}
|
||
});
|
||
// HSTRING
|
||
let operation = HSTRING::from(operation.as_str());
|
||
let file = HSTRING::from(file.as_str());
|
||
let params = HSTRING::from(params.as_str());
|
||
let dir = HSTRING::from(dir.as_str());
|
||
// PCWSTR
|
||
let operation = PCWSTR(operation.as_ptr());
|
||
let file = PCWSTR(file.as_ptr());
|
||
let params = PCWSTR(params.as_ptr());
|
||
let dir = PCWSTR(dir.as_ptr());
|
||
unsafe {
|
||
// execute
|
||
ShellExecuteW(None, operation, file, params, dir, SW_SHOWDEFAULT);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取快捷方式信息
|
||
*/
|
||
pub fn get_shortcut_file_info(path: &str) -> Option<HashMap<String, String>> {
|
||
// HSTRING
|
||
let path = HSTRING::from(path);
|
||
unsafe {
|
||
// Init
|
||
let _ = CoInitializeEx(None, COINIT_APARTMENTTHREADED);
|
||
}
|
||
// IShellLinkW
|
||
let shell_link_result: Result<IShellLinkW, windows::core::Error> =
|
||
unsafe { CoCreateInstance(&ShellLink, None, CLSCTX_INPROC_SERVER) };
|
||
if let Ok(shell_link) = shell_link_result {
|
||
// IPersistFile
|
||
let persist_file_result: Result<IPersistFile, windows::core::Error> = shell_link.cast();
|
||
if let Ok(persist_file) = persist_file_result {
|
||
let load_result = unsafe {
|
||
// 加载路径
|
||
persist_file.Load(PCWSTR(path.as_ptr()), STGM_READ)
|
||
};
|
||
if let Ok(()) = load_result {
|
||
// 获取目标
|
||
let mut target_buffer = [0u16; MAX_PATH as usize];
|
||
let _ = unsafe {
|
||
shell_link.GetPath(
|
||
&mut target_buffer,
|
||
std::ptr::null_mut(),
|
||
SLGP_UNCPRIORITY.0 as u32,
|
||
)
|
||
};
|
||
// 获取参数
|
||
let mut arguments_buffer = [0u16; MAX_PATH as usize];
|
||
let _ = unsafe { shell_link.GetArguments(&mut arguments_buffer) };
|
||
// map
|
||
let mut map = HashMap::with_capacity(2);
|
||
map.insert(String::from("target"), u16_to_string(&target_buffer));
|
||
map.insert(String::from("arguments"), u16_to_string(&arguments_buffer));
|
||
return Some(map);
|
||
}
|
||
}
|
||
}
|
||
unsafe {
|
||
// UnInit
|
||
CoUninitialize();
|
||
}
|
||
None
|
||
}
|
||
|
||
/**
|
||
* 运行命令
|
||
*/
|
||
pub fn system_item_execute(target: &str, params: Option<&str>) {
|
||
if target == "static:TurnOffMonitor" {
|
||
// 关闭显示器
|
||
turn_off_monitor()
|
||
} else {
|
||
let mut file = target.to_string();
|
||
if !target.starts_with("shell:") {
|
||
// 如果不是shell开头,就查询路径
|
||
file = search_path(target).unwrap_or(target.to_string());
|
||
}
|
||
let file = HSTRING::from(file);
|
||
let params = match params {
|
||
Some(p) => HSTRING::from(p),
|
||
_ => HSTRING::new(),
|
||
};
|
||
// 获取系统盘路径当作工作目录
|
||
let mut buffer = [0u16; MAX_PATH as usize];
|
||
unsafe {
|
||
GetSystemDirectoryW(Some(&mut buffer));
|
||
}
|
||
let dir = u16_to_string(&buffer);
|
||
let dir = HSTRING::from(dir);
|
||
// execute
|
||
unsafe {
|
||
ShellExecuteW(
|
||
None,
|
||
w!("open"),
|
||
PCWSTR(file.as_ptr()),
|
||
PCWSTR(params.as_ptr()),
|
||
PCWSTR(dir.as_ptr()),
|
||
SW_SHOWDEFAULT,
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 关闭显示器
|
||
*/
|
||
pub fn turn_off_monitor() {
|
||
unsafe {
|
||
let _ = SendMessageW(
|
||
FindWindowW(PCWSTR::null(), PCWSTR::null()),
|
||
WM_SYSCOMMAND,
|
||
WPARAM(SC_MONITORPOWER as usize),
|
||
LPARAM(2),
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 打开文件所在位置
|
||
*/
|
||
pub fn open_file_location(path: &str) {
|
||
let _ = Command::new("explorer").arg("/select,").arg(path).spawn();
|
||
}
|
||
|
||
/**
|
||
* 资源管理器菜单
|
||
*/
|
||
pub fn explorer_context_menu(window: i32, path: &str, x: i32, y: i32) {
|
||
// IShellItem
|
||
let path = HSTRING::from(path);
|
||
if let Ok(shell_item) =
|
||
unsafe { SHCreateItemFromParsingName::<_, _, IShellItem>(PCWSTR(path.as_ptr()), None) }
|
||
{
|
||
// IContextMenu
|
||
if let Ok(context_menu) =
|
||
unsafe { shell_item.BindToHandler::<_, IContextMenu>(None, &BHID_SFUIObject) }
|
||
{
|
||
// Menu
|
||
if let Ok(menu) = unsafe { CreatePopupMenu() } {
|
||
// 写入菜单
|
||
if let Ok(()) =
|
||
unsafe { context_menu.QueryContextMenu(menu, 0, 1, 0x7FFF, CMF_NORMAL) }
|
||
{
|
||
// HWND
|
||
let hwnd = HWND(window as isize);
|
||
// 弹出菜单
|
||
let res = unsafe {
|
||
SetForegroundWindow(hwnd);
|
||
TrackPopupMenu(menu, TPM_RETURNCMD | TPM_NONOTIFY, x, y, 0, hwnd, None)
|
||
};
|
||
unsafe {
|
||
DestroyMenu(menu);
|
||
}
|
||
if res.as_bool() {
|
||
let mut info = CMINVOKECOMMANDINFO::default();
|
||
info.cbSize = std::mem::size_of::<CMINVOKECOMMANDINFO>() as u32;
|
||
info.hwnd = hwnd;
|
||
info.lpVerb = PCSTR((res.0 - 1) as *mut u8);
|
||
info.nShow = SW_NORMAL.0 as i32;
|
||
let _ = unsafe { context_menu.InvokeCommand(&info) };
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 搜索路径
|
||
*/
|
||
pub fn search_path(name: &str) -> Option<String> {
|
||
let name = HSTRING::from(name);
|
||
let mut buffer = [0u16; MAX_PATH as usize];
|
||
let result = unsafe {
|
||
SearchPathW(
|
||
PCWSTR::null(),
|
||
PCWSTR(name.as_ptr()),
|
||
PCWSTR::null(),
|
||
Some(&mut buffer),
|
||
None,
|
||
)
|
||
};
|
||
if result > 0 {
|
||
Some(u16_to_string(&buffer))
|
||
} else {
|
||
None
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 数组转String
|
||
*/
|
||
fn u16_to_string(slice: &[u16]) -> String {
|
||
let mut vec = vec![];
|
||
for s in slice {
|
||
if *s > 0 {
|
||
vec.push(*s);
|
||
}
|
||
}
|
||
String::from_utf16_lossy(&vec)
|
||
}
|
||
|
||
/**
|
||
* 获取环境变量
|
||
*/
|
||
pub fn get_env_by_name(name: &str) -> Option<String> {
|
||
let name = HSTRING::from(name);
|
||
let mut buffer = [0u16; MAX_PATH as usize];
|
||
let result = unsafe { GetEnvironmentVariableW(PCWSTR(name.as_ptr()), Some(&mut buffer)) };
|
||
if result > 0 {
|
||
Some(u16_to_string(&buffer))
|
||
} else {
|
||
None
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 是否有全屏窗口
|
||
*/
|
||
fn is_fullscreen_window() -> bool {
|
||
// 获取当前活动窗口的句柄
|
||
let foreground_window = unsafe { GetForegroundWindow() };
|
||
// 获取活动窗口的位置信息
|
||
let mut window_rect = RECT::default();
|
||
unsafe { GetWindowRect(foreground_window, &mut window_rect) };
|
||
// 获取包含活动窗口的显示器句柄
|
||
let monitor = unsafe { MonitorFromWindow(foreground_window, MONITOR_DEFAULTTONEAREST) };
|
||
// 获取显示器信息
|
||
let mut monitor_info = MONITORINFO::default();
|
||
monitor_info.cbSize = std::mem::size_of::<MONITORINFO>() as u32;
|
||
unsafe { GetMonitorInfoW(monitor, &mut monitor_info) };
|
||
// 获取屏幕的尺寸
|
||
let screen_width = unsafe { GetSystemMetrics(SM_CXSCREEN) };
|
||
let screen_height = unsafe { GetSystemMetrics(SM_CYSCREEN) };
|
||
// 比较窗口位置和显示器尺寸来判断是否处于全屏模式
|
||
if window_rect.left <= 0
|
||
&& window_rect.top <= 0
|
||
&& window_rect.right >= screen_width
|
||
&& window_rect.bottom >= screen_height
|
||
&& monitor_info.rcMonitor.left == 0
|
||
&& monitor_info.rcMonitor.top == 0
|
||
&& monitor_info.rcMonitor.right == screen_width
|
||
&& monitor_info.rcMonitor.bottom == screen_height
|
||
{
|
||
// 获取窗口类名
|
||
let mut buffer = [0u16; MAX_PATH as usize];
|
||
unsafe { GetClassNameW(foreground_window, &mut buffer) };
|
||
// 转为String
|
||
let name = u16_to_string(&buffer);
|
||
if name != "WorkerW" {
|
||
return true;
|
||
}
|
||
}
|
||
false
|
||
}
|
||
|
||
/**
|
||
* 是否是全屏模式
|
||
*/
|
||
pub fn is_fullscreen() -> bool {
|
||
if let Ok(state) = unsafe { SHQueryUserNotificationState() } {
|
||
if state == QUNS_NOT_PRESENT {
|
||
// 非全屏(机器锁定/屏幕保护程序/用户切换)
|
||
return false;
|
||
} else if state == QUNS_BUSY {
|
||
// 全屏(F11 全屏,我试过的所有视频游戏都使用它)
|
||
return is_fullscreen_window();
|
||
} else if state == QUNS_RUNNING_D3D_FULL_SCREEN {
|
||
// 全屏(Direct3D 应用程序以独占模式运行,即全屏)
|
||
return true;
|
||
} else if state == QUNS_PRESENTATION_MODE {
|
||
// 全屏(一种用于显示全屏演示文稿的特殊模式)
|
||
return true;
|
||
} else if state == QUNS_ACCEPTS_NOTIFICATIONS {
|
||
// 不是全屏
|
||
return false;
|
||
} else if state == QUNS_QUIET_TIME {
|
||
// 不是全屏
|
||
return false;
|
||
} else if state == QUNS_APP {
|
||
// 不是全屏
|
||
return false;
|
||
}
|
||
}
|
||
false
|
||
}
|
||
|
||
/**
|
||
* 切换英文输入法
|
||
*/
|
||
pub fn switch_english(window: i32) {
|
||
// 窗口句柄
|
||
let hwnd = HWND(window as isize);
|
||
// 获取输入法上下文
|
||
let imc = unsafe { ImmGetContext(hwnd) };
|
||
// 设置输入法的首选转换模式为英文
|
||
unsafe { ImmSetConversionStatus(imc, IME_CMODE_ALPHANUMERIC, IME_SMODE_AUTOMATIC) };
|
||
// 释放输入法上下文
|
||
unsafe { ImmReleaseContext(hwnd, imc) };
|
||
}
|
||
|
||
// 是否回调
|
||
static mut MOUSE_HOOK_CALL: AtomicBool = AtomicBool::new(false);
|
||
// ThreadsafeFunction
|
||
static mut TSFN: Option<ThreadsafeFunction<String>> = None;
|
||
// 全局鼠标HOOK
|
||
static mut MOUSE_HOOK: Option<HHOOK> = None;
|
||
|
||
// 鼠标事件
|
||
#[derive(Debug, Serialize, Deserialize)]
|
||
struct MouseEvent {
|
||
event: String,
|
||
x: i32,
|
||
y: i32,
|
||
button: i32,
|
||
mouse_data: u32,
|
||
}
|
||
|
||
/**
|
||
* HOOK回调方法
|
||
*/
|
||
unsafe extern "system" fn mouse_proc(code: i32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
|
||
if code >= 0 && MOUSE_HOOK_CALL.load(Ordering::Relaxed) {
|
||
// 鼠标坐标
|
||
let msll_struct = lparam.0 as *const MSLLHOOKSTRUCT;
|
||
let x = (*msll_struct).pt.x;
|
||
let y = (*msll_struct).pt.y;
|
||
let mouse_data = (*msll_struct).mouseData;
|
||
// 参数
|
||
let param = wparam.0 as u32;
|
||
// 事件
|
||
let mut event = String::from("");
|
||
// 按键类型
|
||
let mut button = -1;
|
||
// 判断事件
|
||
if param == WM_MOUSEMOVE {
|
||
// 鼠标移动
|
||
event.push_str("mousemove");
|
||
} else {
|
||
// 鼠标操作
|
||
if param == WM_LBUTTONUP || param == WM_RBUTTONUP || param == WM_MBUTTONUP {
|
||
event.push_str("mouseup");
|
||
} else if param == WM_LBUTTONDOWN || param == WM_RBUTTONDOWN || param == WM_MBUTTONDOWN
|
||
{
|
||
event.push_str("mousedown");
|
||
} else if param == WM_MOUSEWHEEL || param == WM_MOUSEHWHEEL {
|
||
event.push_str("mousewheel");
|
||
}
|
||
// 按键类型
|
||
if param == WM_LBUTTONUP || param == WM_LBUTTONDOWN {
|
||
button = 1;
|
||
} else if param == WM_RBUTTONUP || param == WM_RBUTTONDOWN {
|
||
button = 2;
|
||
} else if param == WM_MBUTTONUP || param == WM_MBUTTONDOWN {
|
||
button = 3;
|
||
} else if param == WM_MOUSEWHEEL {
|
||
button = 0;
|
||
} else if param == WM_MOUSEHWHEEL {
|
||
button = 1;
|
||
}
|
||
}
|
||
if event != "" {
|
||
if let Some(func) = TSFN.as_ref() {
|
||
let mouse_event = MouseEvent {
|
||
event,
|
||
x,
|
||
y,
|
||
mouse_data,
|
||
button,
|
||
};
|
||
func.call(
|
||
Ok(serde_json::to_string(&mouse_event).unwrap()),
|
||
ThreadsafeFunctionCallMode::NonBlocking,
|
||
);
|
||
}
|
||
}
|
||
}
|
||
return CallNextHookEx(MOUSE_HOOK.unwrap(), code, wparam, lparam);
|
||
}
|
||
|
||
/**
|
||
* 创建鼠标hook
|
||
*/
|
||
pub fn create_mouse_hook(callback: JsFunction) {
|
||
// 创建回调
|
||
if let Ok(threadsafe_function) =
|
||
callback.create_threadsafe_function(0, |ctx| Ok(vec![ctx.value]))
|
||
{
|
||
unsafe { TSFN = Some(threadsafe_function) };
|
||
// 创建鼠标HOOK
|
||
if let Ok(hook) = unsafe { SetWindowsHookExW(WH_MOUSE_LL, Some(mouse_proc), None, 0) } {
|
||
unsafe {
|
||
MOUSE_HOOK = Some(hook);
|
||
MOUSE_HOOK_CALL.store(true, Ordering::Relaxed);
|
||
};
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 启用鼠标HOOK
|
||
*/
|
||
pub fn enable_mouse_hook() {
|
||
unsafe { MOUSE_HOOK_CALL.store(true, Ordering::Relaxed) }
|
||
}
|
||
|
||
/**
|
||
* 禁用鼠标HOOK
|
||
*/
|
||
pub fn disable_mouse_hook() {
|
||
unsafe { MOUSE_HOOK_CALL.store(false, Ordering::Relaxed) }
|
||
}
|
||
|
||
/**
|
||
* 获取鼠标点击的窗口ClassName
|
||
*/
|
||
pub fn get_cursor_pos_window_class_name() -> String {
|
||
// 获取鼠标位置
|
||
let mut point: POINT = POINT::default();
|
||
unsafe {
|
||
GetCursorPos(&mut point);
|
||
}
|
||
// 获取鼠标所在的窗口句柄
|
||
let hwnd = unsafe { WindowFromPoint(point) };
|
||
// 获取窗口的ClassName
|
||
let mut buffer = [0u16; MAX_PATH as usize];
|
||
unsafe {
|
||
GetClassNameW(hwnd, &mut buffer);
|
||
};
|
||
// 返回
|
||
u16_to_string(&buffer)
|
||
}
|
||
|
||
/**
|
||
* 获取剪切板文件列表
|
||
*/
|
||
pub fn get_clipboard_file_list() -> Vec<String> {
|
||
match get_clipboard(formats::FileList) {
|
||
Ok(vec) => vec,
|
||
Err(_) => vec![],
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 剪切板是否存在BITMAP
|
||
*/
|
||
pub fn clipboard_has_bitmap() -> bool {
|
||
match get_clipboard(formats::Bitmap) {
|
||
Ok(_) => true,
|
||
Err(_) => false,
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取剪切板BITMAP的BASE64
|
||
*/
|
||
pub fn get_clipboard_bitmap_base64() -> Option<String> {
|
||
match get_clipboard(formats::Bitmap) {
|
||
Ok(data) => Some(format!(
|
||
"data:image/bmp;base64,{}",
|
||
general_purpose::STANDARD.encode(data)
|
||
)),
|
||
Err(_) => None,
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 清空回收站
|
||
*/
|
||
pub fn empty_recycle_bin(window: i32) {
|
||
// HWND
|
||
let hwnd = HWND(window as isize);
|
||
// 清空回收站
|
||
unsafe {
|
||
let _ = SHEmptyRecycleBinW(hwnd, None, SHERB_NOSOUND);
|
||
};
|
||
}
|