Skip to main content

maa_framework/
toolkit.rs

1//! Device discovery and configuration utilities.
2
3use serde::{Deserialize, Serialize};
4
5use crate::{common, sys, MaaError, MaaResult};
6use std::ffi::{CStr, CString};
7use std::path::PathBuf;
8
9/// Information about a connected ADB device.
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct AdbDevice {
12    /// Device display name.
13    pub name: String,
14    /// Path to the ADB executable.
15    pub adb_path: PathBuf,
16    /// Device address (e.g., "127.0.0.1:5555").
17    pub address: String,
18    /// Supported screencap methods (bitflags).
19    pub screencap_methods: u64,
20    /// Supported input methods (bitflags).
21    pub input_methods: u64,
22    /// Device configuration as JSON.
23    pub config: serde_json::Value,
24}
25
26/// Information about a desktop window (Win32).
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct DesktopWindow {
29    /// Window handle (HWND).
30    pub hwnd: usize,
31    /// Window class name.
32    pub class_name: String,
33    /// Window title.
34    pub window_name: String,
35}
36
37/// Toolkit utilities for device discovery and configuration.
38pub struct Toolkit;
39
40impl Toolkit {
41    /// Initialize MAA framework options.
42    ///
43    /// # Arguments
44    /// * `user_path` - Path to user data directory
45    /// * `default_config` - Default configuration JSON string
46    pub fn init_option(user_path: &str, default_config: &str) -> MaaResult<()> {
47        let c_path = CString::new(user_path)?;
48        let c_config = CString::new(default_config)?;
49        let ret = unsafe { sys::MaaToolkitConfigInitOption(c_path.as_ptr(), c_config.as_ptr()) };
50        common::check_bool(ret)
51    }
52
53    /// Find connected ADB devices.
54    ///
55    /// Scans for all known Android emulators and connected ADB devices.
56    ///
57    /// # Returns
58    /// List of discovered ADB devices with their configurations.
59    pub fn find_adb_devices() -> MaaResult<Vec<AdbDevice>> {
60        Self::find_adb_devices_impl(None)
61    }
62
63    /// Find connected ADB devices using a specific ADB binary.
64    ///
65    /// # Arguments
66    /// * `adb_path` - Path to the ADB binary to use for discovery
67    ///
68    /// # Returns
69    /// List of discovered ADB devices with their configurations.
70    pub fn find_adb_devices_with_adb(adb_path: &str) -> MaaResult<Vec<AdbDevice>> {
71        Self::find_adb_devices_impl(Some(adb_path))
72    }
73
74    fn find_adb_devices_impl(specified_adb: Option<&str>) -> MaaResult<Vec<AdbDevice>> {
75        let list = unsafe { sys::MaaToolkitAdbDeviceListCreate() };
76        if list.is_null() {
77            return Err(MaaError::NullPointer);
78        }
79
80        let _guard = AdbDeviceListGuard(list);
81
82        unsafe {
83            let ret = if let Some(adb_path) = specified_adb {
84                let c_path = CString::new(adb_path)?;
85                sys::MaaToolkitAdbDeviceFindSpecified(c_path.as_ptr(), list)
86            } else {
87                sys::MaaToolkitAdbDeviceFind(list)
88            };
89            common::check_bool(ret)?;
90
91            let count = sys::MaaToolkitAdbDeviceListSize(list);
92            let mut devices = Vec::with_capacity(count as usize);
93
94            for i in 0..count {
95                let device_ptr = sys::MaaToolkitAdbDeviceListAt(list, i);
96                if device_ptr.is_null() {
97                    continue;
98                }
99
100                let name = CStr::from_ptr(sys::MaaToolkitAdbDeviceGetName(device_ptr))
101                    .to_string_lossy()
102                    .into_owned();
103
104                let adb_path_str = CStr::from_ptr(sys::MaaToolkitAdbDeviceGetAdbPath(device_ptr))
105                    .to_string_lossy()
106                    .into_owned();
107
108                let address = CStr::from_ptr(sys::MaaToolkitAdbDeviceGetAddress(device_ptr))
109                    .to_string_lossy()
110                    .into_owned();
111
112                let screencap_methods =
113                    sys::MaaToolkitAdbDeviceGetScreencapMethods(device_ptr) as u64;
114                let input_methods = sys::MaaToolkitAdbDeviceGetInputMethods(device_ptr) as u64;
115
116                let config_str =
117                    CStr::from_ptr(sys::MaaToolkitAdbDeviceGetConfig(device_ptr)).to_string_lossy();
118                let config = serde_json::from_str(&config_str).unwrap_or(serde_json::Value::Null);
119
120                devices.push(AdbDevice {
121                    name,
122                    adb_path: PathBuf::from(adb_path_str),
123                    address,
124                    screencap_methods,
125                    input_methods,
126                    config,
127                });
128            }
129            Ok(devices)
130        }
131    }
132
133    /// Find all desktop windows (Win32 only).
134    ///
135    /// # Returns
136    /// List of visible desktop windows.
137    pub fn find_desktop_windows() -> MaaResult<Vec<DesktopWindow>> {
138        let list = unsafe { sys::MaaToolkitDesktopWindowListCreate() };
139        if list.is_null() {
140            return Err(MaaError::NullPointer);
141        }
142
143        let _guard = DesktopWindowListGuard(list);
144
145        unsafe {
146            let ret = sys::MaaToolkitDesktopWindowFindAll(list);
147            common::check_bool(ret)?;
148
149            let count = sys::MaaToolkitDesktopWindowListSize(list);
150            let mut windows = Vec::with_capacity(count as usize);
151
152            for i in 0..count {
153                let win_ptr = sys::MaaToolkitDesktopWindowListAt(list, i);
154                if win_ptr.is_null() {
155                    continue;
156                }
157
158                let hwnd = sys::MaaToolkitDesktopWindowGetHandle(win_ptr) as usize;
159
160                let class_name = CStr::from_ptr(sys::MaaToolkitDesktopWindowGetClassName(win_ptr))
161                    .to_string_lossy()
162                    .into_owned();
163
164                let window_name =
165                    CStr::from_ptr(sys::MaaToolkitDesktopWindowGetWindowName(win_ptr))
166                        .to_string_lossy()
167                        .into_owned();
168
169                windows.push(DesktopWindow {
170                    hwnd,
171                    class_name,
172                    window_name,
173                });
174            }
175            Ok(windows)
176        }
177    }
178}
179
180struct AdbDeviceListGuard(*mut sys::MaaToolkitAdbDeviceList);
181impl Drop for AdbDeviceListGuard {
182    fn drop(&mut self) {
183        unsafe { sys::MaaToolkitAdbDeviceListDestroy(self.0) }
184    }
185}
186
187struct DesktopWindowListGuard(*mut sys::MaaToolkitDesktopWindowList);
188impl Drop for DesktopWindowListGuard {
189    fn drop(&mut self) {
190        unsafe { sys::MaaToolkitDesktopWindowListDestroy(self.0) }
191    }
192}