Skip to main content

maa_framework/
toolkit.rs

1//! Device discovery and configuration utilities.
2
3use crate::{common, sys, MaaError, MaaResult};
4use std::ffi::{CStr, CString};
5use std::path::PathBuf;
6
7/// Information about a connected ADB device.
8#[derive(Debug, Clone)]
9pub struct AdbDevice {
10    /// Device display name.
11    pub name: String,
12    /// Path to the ADB executable.
13    pub adb_path: PathBuf,
14    /// Device address (e.g., "127.0.0.1:5555").
15    pub address: String,
16    /// Supported screencap methods (bitflags).
17    pub screencap_methods: u64,
18    /// Supported input methods (bitflags).
19    pub input_methods: u64,
20    /// Device configuration as JSON.
21    pub config: serde_json::Value,
22}
23
24/// Information about a desktop window (Win32).
25#[derive(Debug, Clone)]
26pub struct DesktopWindow {
27    /// Window handle (HWND).
28    pub hwnd: usize,
29    /// Window class name.
30    pub class_name: String,
31    /// Window title.
32    pub window_name: String,
33}
34
35/// Toolkit utilities for device discovery and configuration.
36pub struct Toolkit;
37
38impl Toolkit {
39    /// Initialize MAA framework options.
40    ///
41    /// # Arguments
42    /// * `user_path` - Path to user data directory
43    /// * `default_config` - Default configuration JSON string
44    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    /// Find connected ADB devices.
52    ///
53    /// Scans for all known Android emulators and connected ADB devices.
54    ///
55    /// # Returns
56    /// List of discovered ADB devices with their configurations.
57    pub fn find_adb_devices() -> MaaResult<Vec<AdbDevice>> {
58        Self::find_adb_devices_impl(None)
59    }
60
61    /// Find connected ADB devices using a specific ADB binary.
62    ///
63    /// # Arguments
64    /// * `adb_path` - Path to the ADB binary to use for discovery
65    ///
66    /// # Returns
67    /// List of discovered ADB devices with their configurations.
68    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    /// Find all desktop windows (Win32 only).
132    ///
133    /// # Returns
134    /// List of visible desktop windows.
135    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}