1use crate::{common, sys, MaaError, MaaResult};
4use std::ffi::{CStr, CString};
5use std::path::PathBuf;
6
7#[derive(Debug, Clone)]
9pub struct AdbDevice {
10 pub name: String,
12 pub adb_path: PathBuf,
14 pub address: String,
16 pub screencap_methods: u64,
18 pub input_methods: u64,
20 pub config: serde_json::Value,
22}
23
24#[derive(Debug, Clone)]
26pub struct DesktopWindow {
27 pub hwnd: usize,
29 pub class_name: String,
31 pub window_name: String,
33}
34
35pub struct Toolkit;
37
38impl Toolkit {
39 pub fn init_option(user_path: &str, default_config: &str) -> MaaResult<()> {
45 let c_path = CString::new(user_path)?;
46 let c_config = CString::new(default_config)?;
47 let ret = unsafe { sys::MaaToolkitConfigInitOption(c_path.as_ptr(), c_config.as_ptr()) };
48 common::check_bool(ret)
49 }
50
51 pub fn find_adb_devices() -> MaaResult<Vec<AdbDevice>> {
58 Self::find_adb_devices_impl(None)
59 }
60
61 pub fn find_adb_devices_with_adb(adb_path: &str) -> MaaResult<Vec<AdbDevice>> {
69 Self::find_adb_devices_impl(Some(adb_path))
70 }
71
72 fn find_adb_devices_impl(specified_adb: Option<&str>) -> MaaResult<Vec<AdbDevice>> {
73 let list = unsafe { sys::MaaToolkitAdbDeviceListCreate() };
74 if list.is_null() {
75 return Err(MaaError::NullPointer);
76 }
77
78 let _guard = AdbDeviceListGuard(list);
79
80 unsafe {
81 let ret = if let Some(adb_path) = specified_adb {
82 let c_path = CString::new(adb_path)?;
83 sys::MaaToolkitAdbDeviceFindSpecified(c_path.as_ptr(), list)
84 } else {
85 sys::MaaToolkitAdbDeviceFind(list)
86 };
87 common::check_bool(ret)?;
88
89 let count = sys::MaaToolkitAdbDeviceListSize(list);
90 let mut devices = Vec::with_capacity(count as usize);
91
92 for i in 0..count {
93 let device_ptr = sys::MaaToolkitAdbDeviceListAt(list, i);
94 if device_ptr.is_null() {
95 continue;
96 }
97
98 let name = CStr::from_ptr(sys::MaaToolkitAdbDeviceGetName(device_ptr))
99 .to_string_lossy()
100 .into_owned();
101
102 let adb_path_str = CStr::from_ptr(sys::MaaToolkitAdbDeviceGetAdbPath(device_ptr))
103 .to_string_lossy()
104 .into_owned();
105
106 let address = CStr::from_ptr(sys::MaaToolkitAdbDeviceGetAddress(device_ptr))
107 .to_string_lossy()
108 .into_owned();
109
110 let screencap_methods =
111 sys::MaaToolkitAdbDeviceGetScreencapMethods(device_ptr) as u64;
112 let input_methods = sys::MaaToolkitAdbDeviceGetInputMethods(device_ptr) as u64;
113
114 let config_str =
115 CStr::from_ptr(sys::MaaToolkitAdbDeviceGetConfig(device_ptr)).to_string_lossy();
116 let config = serde_json::from_str(&config_str).unwrap_or(serde_json::Value::Null);
117
118 devices.push(AdbDevice {
119 name,
120 adb_path: PathBuf::from(adb_path_str),
121 address,
122 screencap_methods,
123 input_methods,
124 config,
125 });
126 }
127 Ok(devices)
128 }
129 }
130
131 pub fn find_desktop_windows() -> MaaResult<Vec<DesktopWindow>> {
136 let list = unsafe { sys::MaaToolkitDesktopWindowListCreate() };
137 if list.is_null() {
138 return Err(MaaError::NullPointer);
139 }
140
141 let _guard = DesktopWindowListGuard(list);
142
143 unsafe {
144 let ret = sys::MaaToolkitDesktopWindowFindAll(list);
145 common::check_bool(ret)?;
146
147 let count = sys::MaaToolkitDesktopWindowListSize(list);
148 let mut windows = Vec::with_capacity(count as usize);
149
150 for i in 0..count {
151 let win_ptr = sys::MaaToolkitDesktopWindowListAt(list, i);
152 if win_ptr.is_null() {
153 continue;
154 }
155
156 let hwnd = sys::MaaToolkitDesktopWindowGetHandle(win_ptr) as usize;
157
158 let class_name = CStr::from_ptr(sys::MaaToolkitDesktopWindowGetClassName(win_ptr))
159 .to_string_lossy()
160 .into_owned();
161
162 let window_name =
163 CStr::from_ptr(sys::MaaToolkitDesktopWindowGetWindowName(win_ptr))
164 .to_string_lossy()
165 .into_owned();
166
167 windows.push(DesktopWindow {
168 hwnd,
169 class_name,
170 window_name,
171 });
172 }
173 Ok(windows)
174 }
175 }
176}
177
178struct AdbDeviceListGuard(*mut sys::MaaToolkitAdbDeviceList);
179impl Drop for AdbDeviceListGuard {
180 fn drop(&mut self) {
181 unsafe { sys::MaaToolkitAdbDeviceListDestroy(self.0) }
182 }
183}
184
185struct DesktopWindowListGuard(*mut sys::MaaToolkitDesktopWindowList);
186impl Drop for DesktopWindowListGuard {
187 fn drop(&mut self) {
188 unsafe { sys::MaaToolkitDesktopWindowListDestroy(self.0) }
189 }
190}