use tracing::warn;
use zerolaunch_plugin_api::services::parameter::provider::{
ProviderError, SystemParameterProvider,
};
thread_local! {
static UI_AUTOMATION: once_cell::unsync::OnceCell<uiautomation::UIAutomation> =
const { once_cell::unsync::OnceCell::new() };
}
pub struct WindowsClipboardProvider;
#[async_trait::async_trait]
impl SystemParameterProvider for WindowsClipboardProvider {
async fn get_value(&self) -> Result<String, ProviderError> {
match arboard::Clipboard::new() {
Ok(mut clipboard) => match clipboard.get_text() {
Ok(text) => Ok(text),
Err(e) => {
warn!("无法获取剪贴板文本: {:?}, 使用空字符串", e);
Ok(String::new())
}
},
Err(e) => {
warn!("无法初始化剪贴板: {:?}, 使用空字符串", e);
Ok(String::new())
}
}
}
}
pub struct WindowsWindowHandleProvider;
#[async_trait::async_trait]
impl SystemParameterProvider for WindowsWindowHandleProvider {
async fn get_value(&self) -> Result<String, ProviderError> {
unsafe {
use windows::Win32::UI::WindowsAndMessaging::GetForegroundWindow;
let hwnd = GetForegroundWindow();
if hwnd.0.is_null() {
warn!("无法获取前台窗口句柄,返回 0");
return Ok("0".to_string());
}
Ok((hwnd.0 as isize).to_string())
}
}
}
pub struct WindowsSelectionProvider;
impl WindowsSelectionProvider {
fn is_com_changed_mode(err: &uiautomation::Error) -> bool {
const RPC_E_CHANGED_MODE: i32 = -2147417850;
err.code() == RPC_E_CHANGED_MODE
}
fn create_ui_automation() -> Result<uiautomation::UIAutomation, uiautomation::Error> {
match uiautomation::UIAutomation::new() {
Ok(automation) => Ok(automation),
Err(e) if Self::is_com_changed_mode(&e) => {
uiautomation::UIAutomation::new_direct()
}
Err(e) => Err(e),
}
}
fn get_ui_automation() -> Result<uiautomation::UIAutomation, uiautomation::Error> {
UI_AUTOMATION.with(|cell| {
if let Some(automation) = cell.get() {
return Ok(automation.clone());
}
let automation = Self::create_ui_automation()?;
let _ = cell.set(automation.clone());
Ok(automation)
})
}
}
#[async_trait::async_trait]
impl SystemParameterProvider for WindowsSelectionProvider {
async fn get_value(&self) -> Result<String, ProviderError> {
use uiautomation::patterns::UITextPattern;
let automation = match Self::get_ui_automation() {
Ok(a) => a,
Err(e) => {
tracing::debug!("创建 UIAutomation 失败: {}, 返回空字符串", e);
return Ok(String::new());
}
};
let focused_element = match automation.get_focused_element() {
Ok(element) => element,
Err(e) => {
tracing::debug!("无法获取焦点元素: {}, 返回空字符串", e);
return Ok(String::new());
}
};
let text_pattern: UITextPattern = match focused_element.get_pattern() {
Ok(pattern) => pattern,
Err(e) => {
tracing::debug!("焦点元素不支持 TextPattern: {}, 返回空字符串", e);
return Ok(String::new());
}
};
let selections = match text_pattern.get_selection() {
Ok(selections) => selections,
Err(e) => {
tracing::debug!("无法获取选中范围: {}, 返回空字符串", e);
return Ok(String::new());
}
};
if let Some(first_selection) = selections.first() {
match first_selection.get_text(-1) {
Ok(text) => {
tracing::debug!("成功获取选中文本: {} 字符", text.len());
return Ok(text);
}
Err(e) => {
tracing::debug!("无法获取选中文本内容: {}", e);
}
}
}
Ok(String::new())
}
}