1use serde::{Deserialize, Serialize};
4
5use crate::{MaaError, MaaResult, common, sys};
6use std::ffi::{CStr, CString};
7use std::path::{Path, PathBuf};
8use std::sync::Once;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct AdbDevice {
13 pub name: String,
15 pub adb_path: PathBuf,
17 pub address: String,
19 pub screencap_methods: u64,
21 pub input_methods: u64,
23 pub config: serde_json::Value,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct DesktopWindow {
30 pub hwnd: usize,
32 pub class_name: String,
34 pub window_name: String,
36}
37
38#[repr(i32)]
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
41pub enum MacOSPermission {
42 ScreenCapture = sys::MaaMacOSPermissionEnum_MaaMacOSPermissionScreenCapture as i32,
44 Accessibility = sys::MaaMacOSPermissionEnum_MaaMacOSPermissionAccessibility as i32,
46}
47
48pub struct Toolkit;
50
51static AGENT_SERVER_INIT_OPTION_WARNING: Once = Once::new();
52
53impl Toolkit {
54 #[inline]
55 fn unsupported(api: &str) -> MaaError {
56 MaaError::UnsupportedInAgentServer(api.to_string())
57 }
58
59 fn maybe_warn_init_option_in_agent_server() {
60 if std::env::var_os("MAA_RUST_WARN_AGENTSERVER_TOOLKIT_INIT").is_none() {
61 return;
62 }
63
64 AGENT_SERVER_INIT_OPTION_WARNING.call_once(|| {
65 eprintln!(
66 "Warning: Toolkit::init_option is deprecated in AgentServer; only log_dir is applied."
67 );
68 });
69 }
70
71 pub fn init_option(user_path: &str, default_config: &str) -> MaaResult<()> {
77 if crate::is_agent_server_context() {
78 let _ = default_config;
79 Self::maybe_warn_init_option_in_agent_server();
80 let log_dir = Path::new(user_path).join("debug");
81 return crate::configure_logging(log_dir.to_string_lossy().as_ref());
82 }
83
84 let c_path = CString::new(user_path)?;
85 let c_config = CString::new(default_config)?;
86 let ret = unsafe { sys::MaaToolkitConfigInitOption(c_path.as_ptr(), c_config.as_ptr()) };
87 common::check_bool(ret)
88 }
89
90 pub fn find_adb_devices() -> MaaResult<Vec<AdbDevice>> {
97 if crate::is_agent_server_context() {
98 return Err(Self::unsupported("Toolkit::find_adb_devices"));
99 }
100 Self::find_adb_devices_impl(None)
101 }
102
103 pub fn find_adb_devices_with_adb(adb_path: &str) -> MaaResult<Vec<AdbDevice>> {
111 if crate::is_agent_server_context() {
112 return Err(Self::unsupported("Toolkit::find_adb_devices_with_adb"));
113 }
114 Self::find_adb_devices_impl(Some(adb_path))
115 }
116
117 fn find_adb_devices_impl(specified_adb: Option<&str>) -> MaaResult<Vec<AdbDevice>> {
118 let list = unsafe { sys::MaaToolkitAdbDeviceListCreate() };
119 if list.is_null() {
120 return Err(MaaError::NullPointer);
121 }
122
123 let _guard = AdbDeviceListGuard(list);
124
125 unsafe {
126 let ret = if let Some(adb_path) = specified_adb {
127 let c_path = CString::new(adb_path)?;
128 sys::MaaToolkitAdbDeviceFindSpecified(c_path.as_ptr(), list)
129 } else {
130 sys::MaaToolkitAdbDeviceFind(list)
131 };
132 common::check_bool(ret)?;
133
134 let count = sys::MaaToolkitAdbDeviceListSize(list);
135 let mut devices = Vec::with_capacity(count as usize);
136
137 for i in 0..count {
138 let device_ptr = sys::MaaToolkitAdbDeviceListAt(list, i);
139 if device_ptr.is_null() {
140 continue;
141 }
142
143 let name = CStr::from_ptr(sys::MaaToolkitAdbDeviceGetName(device_ptr))
144 .to_string_lossy()
145 .into_owned();
146
147 let adb_path_str = CStr::from_ptr(sys::MaaToolkitAdbDeviceGetAdbPath(device_ptr))
148 .to_string_lossy()
149 .into_owned();
150
151 let address = CStr::from_ptr(sys::MaaToolkitAdbDeviceGetAddress(device_ptr))
152 .to_string_lossy()
153 .into_owned();
154
155 let screencap_methods =
156 sys::MaaToolkitAdbDeviceGetScreencapMethods(device_ptr) as u64;
157 let input_methods = sys::MaaToolkitAdbDeviceGetInputMethods(device_ptr) as u64;
158
159 let config_str =
160 CStr::from_ptr(sys::MaaToolkitAdbDeviceGetConfig(device_ptr)).to_string_lossy();
161 let config = serde_json::from_str(&config_str).unwrap_or(serde_json::Value::Null);
162
163 devices.push(AdbDevice {
164 name,
165 adb_path: PathBuf::from(adb_path_str),
166 address,
167 screencap_methods,
168 input_methods,
169 config,
170 });
171 }
172 Ok(devices)
173 }
174 }
175
176 pub fn find_desktop_windows() -> MaaResult<Vec<DesktopWindow>> {
181 if crate::is_agent_server_context() {
182 return Err(Self::unsupported("Toolkit::find_desktop_windows"));
183 }
184
185 let list = unsafe { sys::MaaToolkitDesktopWindowListCreate() };
186 if list.is_null() {
187 return Err(MaaError::NullPointer);
188 }
189
190 let _guard = DesktopWindowListGuard(list);
191
192 unsafe {
193 let ret = sys::MaaToolkitDesktopWindowFindAll(list);
194 common::check_bool(ret)?;
195
196 let count = sys::MaaToolkitDesktopWindowListSize(list);
197 let mut windows = Vec::with_capacity(count as usize);
198
199 for i in 0..count {
200 let win_ptr = sys::MaaToolkitDesktopWindowListAt(list, i);
201 if win_ptr.is_null() {
202 continue;
203 }
204
205 let hwnd = sys::MaaToolkitDesktopWindowGetHandle(win_ptr) as usize;
206
207 let class_name = CStr::from_ptr(sys::MaaToolkitDesktopWindowGetClassName(win_ptr))
208 .to_string_lossy()
209 .into_owned();
210
211 let window_name =
212 CStr::from_ptr(sys::MaaToolkitDesktopWindowGetWindowName(win_ptr))
213 .to_string_lossy()
214 .into_owned();
215
216 windows.push(DesktopWindow {
217 hwnd,
218 class_name,
219 window_name,
220 });
221 }
222 Ok(windows)
223 }
224 }
225
226 pub fn macos_check_permission(permission: MacOSPermission) -> MaaResult<bool> {
228 if crate::is_agent_server_context() {
229 return Err(Self::unsupported("Toolkit::macos_check_permission"));
230 }
231
232 let ret =
233 unsafe { sys::MaaToolkitMacOSCheckPermission(permission as sys::MaaMacOSPermission) };
234 Ok(ret != 0)
235 }
236
237 pub fn macos_request_permission(permission: MacOSPermission) -> MaaResult<bool> {
242 if crate::is_agent_server_context() {
243 return Err(Self::unsupported("Toolkit::macos_request_permission"));
244 }
245
246 let ret =
247 unsafe { sys::MaaToolkitMacOSRequestPermission(permission as sys::MaaMacOSPermission) };
248 Ok(ret != 0)
249 }
250
251 pub fn macos_reveal_permission_settings(permission: MacOSPermission) -> MaaResult<bool> {
253 if crate::is_agent_server_context() {
254 return Err(Self::unsupported(
255 "Toolkit::macos_reveal_permission_settings",
256 ));
257 }
258
259 let ret = unsafe {
260 sys::MaaToolkitMacOSRevealPermissionSettings(permission as sys::MaaMacOSPermission)
261 };
262 Ok(ret != 0)
263 }
264}
265
266struct AdbDeviceListGuard(*mut sys::MaaToolkitAdbDeviceList);
267impl Drop for AdbDeviceListGuard {
268 fn drop(&mut self) {
269 unsafe { sys::MaaToolkitAdbDeviceListDestroy(self.0) }
270 }
271}
272
273struct DesktopWindowListGuard(*mut sys::MaaToolkitDesktopWindowList);
274impl Drop for DesktopWindowListGuard {
275 fn drop(&mut self) {
276 unsafe { sys::MaaToolkitDesktopWindowListDestroy(self.0) }
277 }
278}