MaaFw 4.5.1__py3-none-manylinux2014_x86_64.whl → 5.4.0b1__py3-none-manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- maa/agent/agent_server.py +221 -3
- maa/agent_client.py +170 -2
- maa/bin/libMaaAdbControlUnit.so +0 -0
- maa/bin/libMaaAgentClient.so +0 -0
- maa/bin/libMaaAgentServer.so +0 -0
- maa/bin/libMaaCustomControlUnit.so +0 -0
- maa/bin/libMaaFramework.so +0 -0
- maa/bin/libMaaToolkit.so +0 -0
- maa/bin/libMaaUtils.so +0 -0
- maa/bin/libc++.so.1 +0 -0
- maa/bin/libc++abi.so.1 +0 -0
- maa/bin/libfastdeploy_ppocr.so +0 -0
- maa/bin/libonnxruntime.so.1 +0 -0
- maa/bin/libopencv_world4.so.411 +0 -0
- maa/bin/libunwind.so.1 +0 -0
- maa/bin/plugins/libMaaPluginDemo.so +0 -0
- maa/buffer.py +168 -0
- maa/context.py +402 -10
- maa/controller.py +611 -36
- maa/custom_action.py +40 -0
- maa/custom_recognition.py +57 -5
- maa/define.py +432 -16
- maa/event_sink.py +103 -0
- maa/job.py +77 -1
- maa/library.py +118 -50
- maa/pipeline.py +509 -0
- maa/resource.py +430 -21
- maa/tasker.py +630 -75
- maa/toolkit.py +52 -91
- {maafw-4.5.1.dist-info → maafw-5.4.0b1.dist-info}/METADATA +87 -44
- maafw-5.4.0b1.dist-info/RECORD +35 -0
- {maafw-4.5.1.dist-info → maafw-5.4.0b1.dist-info}/WHEEL +1 -1
- maa/bin/libMaaDbgControlUnit.so +0 -0
- maa/notification_handler.py +0 -199
- maafw-4.5.1.dist-info/RECORD +0 -34
- {maafw-4.5.1.dist-info → maafw-5.4.0b1.dist-info}/licenses/LICENSE.md +0 -0
maa/controller.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import os
|
|
3
|
+
import numpy
|
|
2
4
|
from abc import abstractmethod
|
|
3
5
|
from ctypes import c_int32
|
|
4
|
-
import os
|
|
5
6
|
from pathlib import Path
|
|
6
|
-
from typing import Any, Dict, Optional, Union
|
|
7
|
+
from typing import Any, Dict, Optional, Tuple, Union
|
|
7
8
|
|
|
8
9
|
from .buffer import ImageBuffer, StringBuffer
|
|
9
|
-
from .
|
|
10
|
+
from .event_sink import EventSink, NotificationType
|
|
10
11
|
from .define import *
|
|
11
12
|
from .job import Job, JobWithResult
|
|
12
13
|
from .library import Library
|
|
@@ -14,13 +15,14 @@ from .library import Library
|
|
|
14
15
|
__all__ = [
|
|
15
16
|
"AdbController",
|
|
16
17
|
"DbgController",
|
|
18
|
+
"PlayCoverController",
|
|
17
19
|
"Win32Controller",
|
|
20
|
+
"GamepadController",
|
|
18
21
|
"CustomController",
|
|
19
22
|
]
|
|
20
23
|
|
|
21
24
|
|
|
22
25
|
class Controller:
|
|
23
|
-
_notification_handler: Optional[NotificationHandler]
|
|
24
26
|
_handle: MaaControllerHandle
|
|
25
27
|
_own: bool
|
|
26
28
|
|
|
@@ -42,16 +44,63 @@ class Controller:
|
|
|
42
44
|
Library.framework().MaaControllerDestroy(self._handle)
|
|
43
45
|
|
|
44
46
|
def post_connection(self) -> Job:
|
|
47
|
+
"""异步连接设备 / Asynchronously connect device
|
|
48
|
+
|
|
49
|
+
这是一个异步操作,会立即返回一个 Job 对象
|
|
50
|
+
This is an asynchronous operation that immediately returns a Job object
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Job: 作业对象,可通过 status/wait 查询状态 / Job object, can query status via status/wait
|
|
54
|
+
"""
|
|
45
55
|
ctrl_id = Library.framework().MaaControllerPostConnection(self._handle)
|
|
46
56
|
return self._gen_ctrl_job(ctrl_id)
|
|
47
57
|
|
|
48
|
-
def post_click(self, x: int, y: int) -> Job:
|
|
49
|
-
|
|
58
|
+
def post_click(self, x: int, y: int, contact: int = 0, pressure: int = 1) -> Job:
|
|
59
|
+
"""异步点击 / Asynchronously click
|
|
60
|
+
|
|
61
|
+
这是一个异步操作,会立即返回一个 Job 对象
|
|
62
|
+
This is an asynchronous operation that immediately returns a Job object
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
x: x 坐标 / x coordinate
|
|
66
|
+
y: y 坐标 / y coordinate
|
|
67
|
+
contact: 触点编号 (Adb 控制器: 手指编号; Win32 控制器: 鼠标按键 0:左键, 1:右键, 2:中键) / Contact number (Adb controller: finger number; Win32 controller: mouse button 0:left, 1:right, 2:middle)
|
|
68
|
+
pressure: 触点力度 / Contact pressure
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
Job: 作业对象,可通过 status/wait 查询状态 / Job object, can query status via status/wait
|
|
72
|
+
"""
|
|
73
|
+
ctrl_id = Library.framework().MaaControllerPostClickV2(
|
|
74
|
+
self._handle, x, y, contact, pressure
|
|
75
|
+
)
|
|
50
76
|
return self._gen_ctrl_job(ctrl_id)
|
|
51
77
|
|
|
52
|
-
def post_swipe(
|
|
53
|
-
|
|
54
|
-
|
|
78
|
+
def post_swipe(
|
|
79
|
+
self,
|
|
80
|
+
x1: int,
|
|
81
|
+
y1: int,
|
|
82
|
+
x2: int,
|
|
83
|
+
y2: int,
|
|
84
|
+
duration: int,
|
|
85
|
+
contact: int = 0,
|
|
86
|
+
pressure: int = 1,
|
|
87
|
+
) -> Job:
|
|
88
|
+
"""滑动 / Swipe
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
x1: 起点 x 坐标 / Start x coordinate
|
|
92
|
+
y1: 起点 y 坐标 / Start y coordinate
|
|
93
|
+
x2: 终点 x 坐标 / End x coordinate
|
|
94
|
+
y2: 终点 y 坐标 / End y coordinate
|
|
95
|
+
duration: 滑动时长(毫秒) / Swipe duration in milliseconds
|
|
96
|
+
contact: 触点编号 (Adb 控制器: 手指编号; Win32 控制器: 鼠标按键 0:左键, 1:右键, 2:中键) / Contact number (Adb controller: finger number; Win32 controller: mouse button 0:left, 1:right, 2:middle)
|
|
97
|
+
pressure: 触点力度 / Contact pressure
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Job: 作业对象 / Job object
|
|
101
|
+
"""
|
|
102
|
+
ctrl_id = Library.framework().MaaControllerPostSwipeV2(
|
|
103
|
+
self._handle, x1, y1, x2, y2, duration, contact, pressure
|
|
55
104
|
)
|
|
56
105
|
return self._gen_ctrl_job(ctrl_id)
|
|
57
106
|
|
|
@@ -62,30 +111,78 @@ class Controller:
|
|
|
62
111
|
return self.post_click_key(key)
|
|
63
112
|
|
|
64
113
|
def post_click_key(self, key: int) -> Job:
|
|
114
|
+
"""单击按键 / Click key
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
key: 虚拟键码 / Virtual key code
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Job: 作业对象 / Job object
|
|
121
|
+
"""
|
|
65
122
|
ctrl_id = Library.framework().MaaControllerPostClickKey(self._handle, key)
|
|
66
123
|
return self._gen_ctrl_job(ctrl_id)
|
|
67
124
|
|
|
68
125
|
def post_key_down(self, key: int) -> Job:
|
|
126
|
+
"""按下键 / Key down
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
key: 虚拟键码 / Virtual key code
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
Job: 作业对象 / Job object
|
|
133
|
+
"""
|
|
69
134
|
ctrl_id = Library.framework().MaaControllerPostKeyDown(self._handle, key)
|
|
70
135
|
return self._gen_ctrl_job(ctrl_id)
|
|
71
136
|
|
|
72
137
|
def post_key_up(self, key: int) -> Job:
|
|
138
|
+
"""抬起键 / Key up
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
key: 虚拟键码 / Virtual key code
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
Job: 作业对象 / Job object
|
|
145
|
+
"""
|
|
73
146
|
ctrl_id = Library.framework().MaaControllerPostKeyUp(self._handle, key)
|
|
74
147
|
return self._gen_ctrl_job(ctrl_id)
|
|
75
148
|
|
|
76
149
|
def post_input_text(self, text: str) -> Job:
|
|
150
|
+
"""输入文本 / Input text
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
text: 要输入的文本 / Text to input
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
Job: 作业对象 / Job object
|
|
157
|
+
"""
|
|
77
158
|
ctrl_id = Library.framework().MaaControllerPostInputText(
|
|
78
159
|
self._handle, text.encode()
|
|
79
160
|
)
|
|
80
161
|
return self._gen_ctrl_job(ctrl_id)
|
|
81
162
|
|
|
82
163
|
def post_start_app(self, intent: str) -> Job:
|
|
164
|
+
"""启动应用 / Start app
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
intent: 目标应用 (Adb 控制器: package name 或 activity) / Target app (Adb controller: package name or activity)
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
Job: 作业对象 / Job object
|
|
171
|
+
"""
|
|
83
172
|
ctrl_id = Library.framework().MaaControllerPostStartApp(
|
|
84
173
|
self._handle, intent.encode()
|
|
85
174
|
)
|
|
86
175
|
return self._gen_ctrl_job(ctrl_id)
|
|
87
176
|
|
|
88
177
|
def post_stop_app(self, intent: str) -> Job:
|
|
178
|
+
"""关闭应用 / Stop app
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
intent: 目标应用 (Adb 控制器: package name) / Target app (Adb controller: package name)
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
Job: 作业对象 / Job object
|
|
185
|
+
"""
|
|
89
186
|
ctrl_id = Library.framework().MaaControllerPostStopApp(
|
|
90
187
|
self._handle, intent.encode()
|
|
91
188
|
)
|
|
@@ -94,6 +191,17 @@ class Controller:
|
|
|
94
191
|
def post_touch_down(
|
|
95
192
|
self, x: int, y: int, contact: int = 0, pressure: int = 1
|
|
96
193
|
) -> Job:
|
|
194
|
+
"""按下 / Touch down
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
x: x 坐标 / x coordinate
|
|
198
|
+
y: y 坐标 / y coordinate
|
|
199
|
+
contact: 触点编号 (Adb 控制器: 手指编号; Win32 控制器: 鼠标按键 0:左键, 1:右键, 2:中键) / Contact number (Adb controller: finger number; Win32 controller: mouse button 0:left, 1:right, 2:middle)
|
|
200
|
+
pressure: 触点力度 / Contact pressure
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
Job: 作业对象 / Job object
|
|
204
|
+
"""
|
|
97
205
|
ctrl_id = Library.framework().MaaControllerPostTouchDown(
|
|
98
206
|
self._handle, contact, x, y, pressure
|
|
99
207
|
)
|
|
@@ -102,16 +210,57 @@ class Controller:
|
|
|
102
210
|
def post_touch_move(
|
|
103
211
|
self, x: int, y: int, contact: int = 0, pressure: int = 1
|
|
104
212
|
) -> Job:
|
|
213
|
+
"""移动 / Move
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
x: x 坐标 / x coordinate
|
|
217
|
+
y: y 坐标 / y coordinate
|
|
218
|
+
contact: 触点编号 (Adb 控制器: 手指编号; Win32 控制器: 鼠标按键 0:左键, 1:右键, 2:中键) / Contact number (Adb controller: finger number; Win32 controller: mouse button 0:left, 1:right, 2:middle)
|
|
219
|
+
pressure: 触点力度 / Contact pressure
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
Job: 作业对象 / Job object
|
|
223
|
+
"""
|
|
105
224
|
ctrl_id = Library.framework().MaaControllerPostTouchMove(
|
|
106
225
|
self._handle, contact, x, y, pressure
|
|
107
226
|
)
|
|
108
227
|
return self._gen_ctrl_job(ctrl_id)
|
|
109
228
|
|
|
110
229
|
def post_touch_up(self, contact: int = 0) -> Job:
|
|
230
|
+
"""抬起 / Touch up
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
contact: 触点编号 (Adb 控制器: 手指编号; Win32 控制器: 鼠标按键 0:左键, 1:右键, 2:中键) / Contact number (Adb controller: finger number; Win32 controller: mouse button 0:left, 1:right, 2:middle)
|
|
234
|
+
|
|
235
|
+
Returns:
|
|
236
|
+
Job: 作业对象 / Job object
|
|
237
|
+
"""
|
|
111
238
|
ctrl_id = Library.framework().MaaControllerPostTouchUp(self._handle, contact)
|
|
112
239
|
return self._gen_ctrl_job(ctrl_id)
|
|
113
240
|
|
|
241
|
+
def post_scroll(self, dx: int, dy: int) -> Job:
|
|
242
|
+
"""滚动 / Scroll
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
dx: 水平滚动距离,正值向右滚动,负值向左滚动 / Horizontal scroll distance, positive for right, negative for left
|
|
246
|
+
dy: 垂直滚动距离,正值向上滚动,负值向下滚动 / Vertical scroll distance, positive for up, negative for down
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
Job: 作业对象 / Job object
|
|
250
|
+
|
|
251
|
+
Note:
|
|
252
|
+
不是所有控制器都支持滚动操作 / Not all controllers support scroll operation
|
|
253
|
+
建议使用 120 的整数倍(WHEEL_DELTA)以获得最佳兼容性 / Using multiples of 120 (WHEEL_DELTA) is recommended
|
|
254
|
+
"""
|
|
255
|
+
ctrl_id = Library.framework().MaaControllerPostScroll(self._handle, dx, dy)
|
|
256
|
+
return self._gen_ctrl_job(ctrl_id)
|
|
257
|
+
|
|
114
258
|
def post_screencap(self) -> JobWithResult:
|
|
259
|
+
"""截图 / Screenshot
|
|
260
|
+
|
|
261
|
+
Returns:
|
|
262
|
+
JobWithResult: 作业对象,可通过 result 获取截图 / Job object, can get screenshot via result
|
|
263
|
+
"""
|
|
115
264
|
ctrl_id = Library.framework().MaaControllerPostScreencap(self._handle)
|
|
116
265
|
return JobWithResult(
|
|
117
266
|
ctrl_id,
|
|
@@ -122,6 +271,22 @@ class Controller:
|
|
|
122
271
|
|
|
123
272
|
@property
|
|
124
273
|
def cached_image(self) -> numpy.ndarray:
|
|
274
|
+
"""获取最新一次截图 / Get the latest screenshot
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
numpy.ndarray: 截图图像 / Screenshot image
|
|
278
|
+
|
|
279
|
+
Raises:
|
|
280
|
+
RuntimeError: 如果获取失败
|
|
281
|
+
|
|
282
|
+
Note:
|
|
283
|
+
返回的图像是经过缩放的,尺寸根据截图目标尺寸设置(长边/短边)而定,可能与设备原始分辨率不同。
|
|
284
|
+
使用 resolution 属性可获取设备的原始(未缩放)分辨率。
|
|
285
|
+
|
|
286
|
+
The returned image is scaled according to the screenshot target size settings (long side / short side).
|
|
287
|
+
The image dimensions may differ from the raw device resolution.
|
|
288
|
+
Use the resolution property to get the raw (unscaled) device resolution.
|
|
289
|
+
"""
|
|
125
290
|
image_buffer = ImageBuffer()
|
|
126
291
|
if not Library.framework().MaaControllerCachedImage(
|
|
127
292
|
self._handle, image_buffer._handle
|
|
@@ -129,18 +294,101 @@ class Controller:
|
|
|
129
294
|
raise RuntimeError("Failed to get cached image.")
|
|
130
295
|
return image_buffer.get()
|
|
131
296
|
|
|
297
|
+
def post_shell(self, cmd: str, timeout: int = 20000) -> JobWithResult:
|
|
298
|
+
"""执行 shell 命令 (仅 ADB 控制器) / Execute shell command (ADB only)
|
|
299
|
+
|
|
300
|
+
Args:
|
|
301
|
+
cmd: shell 命令 / shell command
|
|
302
|
+
timeout: 超时时间(毫秒),默认 20000 / Timeout in milliseconds, default 20000
|
|
303
|
+
|
|
304
|
+
Returns:
|
|
305
|
+
JobWithResult: 作业对象,可通过 result 获取命令输出 / Job object, can get output via result
|
|
306
|
+
"""
|
|
307
|
+
ctrl_id = Library.framework().MaaControllerPostShell(
|
|
308
|
+
self._handle, cmd.encode("utf-8"), timeout
|
|
309
|
+
)
|
|
310
|
+
return JobWithResult(
|
|
311
|
+
ctrl_id,
|
|
312
|
+
self._status,
|
|
313
|
+
self._wait,
|
|
314
|
+
self._get_shell_output,
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
@property
|
|
318
|
+
def shell_output(self) -> str:
|
|
319
|
+
"""获取最近一次 shell 命令输出 / Get the latest shell command output
|
|
320
|
+
|
|
321
|
+
Returns:
|
|
322
|
+
str: shell 命令输出 / shell command output
|
|
323
|
+
|
|
324
|
+
Raises:
|
|
325
|
+
RuntimeError: 如果获取失败
|
|
326
|
+
"""
|
|
327
|
+
string_buffer = StringBuffer()
|
|
328
|
+
if not Library.framework().MaaControllerGetShellOutput(
|
|
329
|
+
self._handle, string_buffer._handle
|
|
330
|
+
):
|
|
331
|
+
raise RuntimeError("Failed to get shell output.")
|
|
332
|
+
return string_buffer.get()
|
|
333
|
+
|
|
132
334
|
@property
|
|
133
335
|
def connected(self) -> bool:
|
|
336
|
+
"""判断是否已连接 / Check if connected
|
|
337
|
+
|
|
338
|
+
Returns:
|
|
339
|
+
bool: 是否已连接 / Whether connected
|
|
340
|
+
"""
|
|
134
341
|
return bool(Library.framework().MaaControllerConnected(self._handle))
|
|
135
342
|
|
|
136
343
|
@property
|
|
137
344
|
def uuid(self) -> str:
|
|
345
|
+
"""获取设备 uuid / Get device uuid
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
str: 设备 uuid / Device uuid
|
|
349
|
+
|
|
350
|
+
Raises:
|
|
351
|
+
RuntimeError: 如果获取失败
|
|
352
|
+
"""
|
|
138
353
|
buffer = StringBuffer()
|
|
139
354
|
if not Library.framework().MaaControllerGetUuid(self._handle, buffer._handle):
|
|
140
355
|
raise RuntimeError("Failed to get UUID.")
|
|
141
356
|
return buffer.get()
|
|
142
357
|
|
|
358
|
+
@property
|
|
359
|
+
def resolution(self) -> Tuple[int, int]:
|
|
360
|
+
"""获取设备原始(未缩放)分辨率 / Get the raw (unscaled) device resolution
|
|
361
|
+
|
|
362
|
+
Returns:
|
|
363
|
+
Tuple[int, int]: (宽度, 高度),获取失败时返回 (0, 0) / (width, height), returns (0, 0) on failure
|
|
364
|
+
|
|
365
|
+
Note:
|
|
366
|
+
返回的是设备屏幕的实际分辨率,未经任何缩放处理。
|
|
367
|
+
而通过 cached_image 获取的截图是经过缩放的,其尺寸可能与此原始分辨率不同。
|
|
368
|
+
需要在首次截图后才能获取到有效值,否则返回 (0, 0)。
|
|
369
|
+
|
|
370
|
+
This returns the actual device screen resolution before any scaling.
|
|
371
|
+
The screenshot obtained via cached_image is scaled according to the screenshot target size settings,
|
|
372
|
+
so its dimensions may differ from this raw resolution.
|
|
373
|
+
Valid values are only available after the first screenshot is taken, otherwise returns (0, 0).
|
|
374
|
+
"""
|
|
375
|
+
width = ctypes.c_int32()
|
|
376
|
+
height = ctypes.c_int32()
|
|
377
|
+
if not Library.framework().MaaControllerGetResolution(
|
|
378
|
+
self._handle, ctypes.byref(width), ctypes.byref(height)
|
|
379
|
+
):
|
|
380
|
+
return (0, 0)
|
|
381
|
+
return (width.value, height.value)
|
|
382
|
+
|
|
143
383
|
def set_screenshot_target_long_side(self, long_side: int) -> bool:
|
|
384
|
+
"""设置截图缩放长边到指定长度 / Set screenshot scaling long side to specified length
|
|
385
|
+
|
|
386
|
+
Args:
|
|
387
|
+
long_side: 长边长度 / Long side length
|
|
388
|
+
|
|
389
|
+
Returns:
|
|
390
|
+
bool: 是否成功 / Whether successful
|
|
391
|
+
"""
|
|
144
392
|
cint = ctypes.c_int32(long_side)
|
|
145
393
|
return bool(
|
|
146
394
|
Library.framework().MaaControllerSetOption(
|
|
@@ -152,6 +400,14 @@ class Controller:
|
|
|
152
400
|
)
|
|
153
401
|
|
|
154
402
|
def set_screenshot_target_short_side(self, short_side: int) -> bool:
|
|
403
|
+
"""设置截图缩放短边到指定长度 / Set screenshot scaling short side to specified length
|
|
404
|
+
|
|
405
|
+
Args:
|
|
406
|
+
short_side: 短边长度 / Short side length
|
|
407
|
+
|
|
408
|
+
Returns:
|
|
409
|
+
bool: 是否成功 / Whether successful
|
|
410
|
+
"""
|
|
155
411
|
cint = ctypes.c_int32(short_side)
|
|
156
412
|
return bool(
|
|
157
413
|
Library.framework().MaaControllerSetOption(
|
|
@@ -163,6 +419,17 @@ class Controller:
|
|
|
163
419
|
)
|
|
164
420
|
|
|
165
421
|
def set_screenshot_use_raw_size(self, enable: bool) -> bool:
|
|
422
|
+
"""设置截图不缩放 / Set screenshot use raw size without scaling
|
|
423
|
+
|
|
424
|
+
注意:此选项可能导致在不同分辨率的设备上坐标不正确
|
|
425
|
+
Note: This option may cause incorrect coordinates on devices with different resolutions
|
|
426
|
+
|
|
427
|
+
Args:
|
|
428
|
+
enable: 是否启用 / Whether to enable
|
|
429
|
+
|
|
430
|
+
Returns:
|
|
431
|
+
bool: 是否成功 / Whether successful
|
|
432
|
+
"""
|
|
166
433
|
cbool = MaaBool(enable)
|
|
167
434
|
return bool(
|
|
168
435
|
Library.framework().MaaControllerSetOption(
|
|
@@ -173,6 +440,41 @@ class Controller:
|
|
|
173
440
|
)
|
|
174
441
|
)
|
|
175
442
|
|
|
443
|
+
_sink_holder: Dict[int, "ControllerEventSink"] = {}
|
|
444
|
+
|
|
445
|
+
def add_sink(self, sink: "ControllerEventSink") -> Optional[int]:
|
|
446
|
+
"""添加控制器事件监听器 / Add controller event listener
|
|
447
|
+
|
|
448
|
+
Args:
|
|
449
|
+
sink: 事件监听器 / Event sink
|
|
450
|
+
|
|
451
|
+
Returns:
|
|
452
|
+
Optional[int]: 监听器 id,失败返回 None / Listener id, or None if failed
|
|
453
|
+
"""
|
|
454
|
+
sink_id = int(
|
|
455
|
+
Library.framework().MaaControllerAddSink(
|
|
456
|
+
self._handle, *EventSink._gen_c_param(sink)
|
|
457
|
+
)
|
|
458
|
+
)
|
|
459
|
+
if sink_id == MaaInvalidId:
|
|
460
|
+
return None
|
|
461
|
+
|
|
462
|
+
self._sink_holder[sink_id] = sink
|
|
463
|
+
return sink_id
|
|
464
|
+
|
|
465
|
+
def remove_sink(self, sink_id: int) -> None:
|
|
466
|
+
"""移除控制器事件监听器 / Remove controller event listener
|
|
467
|
+
|
|
468
|
+
Args:
|
|
469
|
+
sink_id: 监听器 id / Listener id
|
|
470
|
+
"""
|
|
471
|
+
Library.framework().MaaControllerRemoveSink(self._handle, sink_id)
|
|
472
|
+
self._sink_holder.pop(sink_id)
|
|
473
|
+
|
|
474
|
+
def clear_sinks(self) -> None:
|
|
475
|
+
"""清除所有控制器事件监听器 / Clear all controller event listeners"""
|
|
476
|
+
Library.framework().MaaControllerClearSinks(self._handle)
|
|
477
|
+
|
|
176
478
|
### private ###
|
|
177
479
|
|
|
178
480
|
def _status(self, maaid: int) -> MaaStatus:
|
|
@@ -184,6 +486,9 @@ class Controller:
|
|
|
184
486
|
def _get_screencap(self, _: int) -> numpy.ndarray:
|
|
185
487
|
return self.cached_image
|
|
186
488
|
|
|
489
|
+
def _get_shell_output(self, _: int) -> str:
|
|
490
|
+
return self.shell_output
|
|
491
|
+
|
|
187
492
|
def _gen_ctrl_job(self, ctrlid: MaaCtrlId) -> Job:
|
|
188
493
|
return Job(
|
|
189
494
|
ctrlid,
|
|
@@ -220,6 +525,15 @@ class Controller:
|
|
|
220
525
|
c_int32,
|
|
221
526
|
]
|
|
222
527
|
|
|
528
|
+
Library.framework().MaaControllerPostClickV2.restype = MaaCtrlId
|
|
529
|
+
Library.framework().MaaControllerPostClickV2.argtypes = [
|
|
530
|
+
MaaControllerHandle,
|
|
531
|
+
c_int32,
|
|
532
|
+
c_int32,
|
|
533
|
+
c_int32,
|
|
534
|
+
c_int32,
|
|
535
|
+
]
|
|
536
|
+
|
|
223
537
|
Library.framework().MaaControllerPostSwipe.restype = MaaCtrlId
|
|
224
538
|
Library.framework().MaaControllerPostSwipe.argtypes = [
|
|
225
539
|
MaaControllerHandle,
|
|
@@ -230,6 +544,18 @@ class Controller:
|
|
|
230
544
|
c_int32,
|
|
231
545
|
]
|
|
232
546
|
|
|
547
|
+
Library.framework().MaaControllerPostSwipeV2.restype = MaaCtrlId
|
|
548
|
+
Library.framework().MaaControllerPostSwipeV2.argtypes = [
|
|
549
|
+
MaaControllerHandle,
|
|
550
|
+
c_int32,
|
|
551
|
+
c_int32,
|
|
552
|
+
c_int32,
|
|
553
|
+
c_int32,
|
|
554
|
+
c_int32,
|
|
555
|
+
c_int32,
|
|
556
|
+
c_int32,
|
|
557
|
+
]
|
|
558
|
+
|
|
233
559
|
Library.framework().MaaControllerPostClickKey.restype = MaaCtrlId
|
|
234
560
|
Library.framework().MaaControllerPostClickKey.argtypes = [
|
|
235
561
|
MaaControllerHandle,
|
|
@@ -292,6 +618,14 @@ class Controller:
|
|
|
292
618
|
MaaControllerHandle,
|
|
293
619
|
c_int32,
|
|
294
620
|
]
|
|
621
|
+
|
|
622
|
+
Library.framework().MaaControllerPostScroll.restype = MaaCtrlId
|
|
623
|
+
Library.framework().MaaControllerPostScroll.argtypes = [
|
|
624
|
+
MaaControllerHandle,
|
|
625
|
+
c_int32,
|
|
626
|
+
c_int32,
|
|
627
|
+
]
|
|
628
|
+
|
|
295
629
|
Library.framework().MaaControllerStatus.restype = MaaStatus
|
|
296
630
|
Library.framework().MaaControllerStatus.argtypes = [
|
|
297
631
|
MaaControllerHandle,
|
|
@@ -319,8 +653,37 @@ class Controller:
|
|
|
319
653
|
MaaStringBufferHandle,
|
|
320
654
|
]
|
|
321
655
|
|
|
656
|
+
Library.framework().MaaControllerGetResolution.restype = MaaBool
|
|
657
|
+
Library.framework().MaaControllerGetResolution.argtypes = [
|
|
658
|
+
MaaControllerHandle,
|
|
659
|
+
ctypes.POINTER(ctypes.c_int32),
|
|
660
|
+
ctypes.POINTER(ctypes.c_int32),
|
|
661
|
+
]
|
|
662
|
+
|
|
663
|
+
Library.framework().MaaControllerAddSink.restype = MaaSinkId
|
|
664
|
+
Library.framework().MaaControllerAddSink.argtypes = [
|
|
665
|
+
MaaControllerHandle,
|
|
666
|
+
MaaEventCallback,
|
|
667
|
+
ctypes.c_void_p,
|
|
668
|
+
]
|
|
669
|
+
|
|
670
|
+
Library.framework().MaaControllerRemoveSink.restype = None
|
|
671
|
+
Library.framework().MaaControllerRemoveSink.argtypes = [
|
|
672
|
+
MaaControllerHandle,
|
|
673
|
+
MaaSinkId,
|
|
674
|
+
]
|
|
675
|
+
|
|
676
|
+
Library.framework().MaaControllerClearSinks.restype = None
|
|
677
|
+
Library.framework().MaaControllerClearSinks.argtypes = [MaaControllerHandle]
|
|
678
|
+
|
|
322
679
|
|
|
323
680
|
class AdbController(Controller):
|
|
681
|
+
"""Adb 控制器 / Adb controller
|
|
682
|
+
|
|
683
|
+
截图方式和输入方式会在启动时进行测速, 选择最快的方案
|
|
684
|
+
Screenshot and input methods will be speed tested at startup, selecting the fastest option
|
|
685
|
+
"""
|
|
686
|
+
|
|
324
687
|
AGENT_BINARY_PATH = os.path.join(
|
|
325
688
|
os.path.dirname(__file__),
|
|
326
689
|
"../MaaAgentBinary",
|
|
@@ -334,13 +697,23 @@ class AdbController(Controller):
|
|
|
334
697
|
input_methods: int = MaaAdbInputMethodEnum.Default,
|
|
335
698
|
config: Dict[str, Any] = {},
|
|
336
699
|
agent_path: Union[str, Path] = AGENT_BINARY_PATH,
|
|
337
|
-
notification_handler: Optional[NotificationHandler] = None,
|
|
338
700
|
):
|
|
701
|
+
"""创建 Adb 控制器 / Create Adb controller
|
|
702
|
+
|
|
703
|
+
Args:
|
|
704
|
+
adb_path: adb 路径 / adb path
|
|
705
|
+
address: 连接地址 / connection address
|
|
706
|
+
screencap_methods: 所有可使用的截图方式 / all available screenshot methods
|
|
707
|
+
input_methods: 所有可使用的输入方式 / all available input methods
|
|
708
|
+
config: 额外配置 / extra config
|
|
709
|
+
agent_path: MaaAgentBinary 路径 / MaaAgentBinary path
|
|
710
|
+
|
|
711
|
+
Raises:
|
|
712
|
+
RuntimeError: 如果创建失败
|
|
713
|
+
"""
|
|
339
714
|
super().__init__()
|
|
340
715
|
self._set_adb_api_properties()
|
|
341
716
|
|
|
342
|
-
self._notification_handler = notification_handler
|
|
343
|
-
|
|
344
717
|
self._handle = Library.framework().MaaAdbControllerCreate(
|
|
345
718
|
str(adb_path).encode(),
|
|
346
719
|
address.encode(),
|
|
@@ -348,7 +721,6 @@ class AdbController(Controller):
|
|
|
348
721
|
MaaAdbInputMethod(input_methods),
|
|
349
722
|
json.dumps(config, ensure_ascii=False).encode(),
|
|
350
723
|
str(agent_path).encode(),
|
|
351
|
-
*NotificationHandler._gen_c_param(self._notification_handler)
|
|
352
724
|
)
|
|
353
725
|
|
|
354
726
|
if not self._handle:
|
|
@@ -364,29 +736,38 @@ class AdbController(Controller):
|
|
|
364
736
|
MaaAdbInputMethod,
|
|
365
737
|
ctypes.c_char_p,
|
|
366
738
|
ctypes.c_char_p,
|
|
367
|
-
MaaNotificationCallback,
|
|
368
|
-
ctypes.c_void_p,
|
|
369
739
|
]
|
|
370
740
|
|
|
371
741
|
|
|
372
742
|
class Win32Controller(Controller):
|
|
743
|
+
"""Win32 控制器 / Win32 controller"""
|
|
373
744
|
|
|
374
745
|
def __init__(
|
|
375
746
|
self,
|
|
376
747
|
hWnd: Union[ctypes.c_void_p, int, None],
|
|
377
|
-
screencap_method: int = MaaWin32ScreencapMethodEnum.
|
|
378
|
-
|
|
379
|
-
|
|
748
|
+
screencap_method: int = MaaWin32ScreencapMethodEnum.PrintWindow,
|
|
749
|
+
mouse_method: int = MaaWin32InputMethodEnum.Seize,
|
|
750
|
+
keyboard_method: int = MaaWin32InputMethodEnum.Seize,
|
|
380
751
|
):
|
|
752
|
+
"""创建 Win32 控制器 / Create Win32 controller
|
|
753
|
+
|
|
754
|
+
Args:
|
|
755
|
+
hWnd: 窗口句柄 / window handle
|
|
756
|
+
screencap_method: 使用的截图方式 / screenshot method used
|
|
757
|
+
mouse_method: 使用的鼠标输入方式 / mouse input method used
|
|
758
|
+
keyboard_method: 使用的键盘输入方式 / keyboard input method used
|
|
759
|
+
|
|
760
|
+
Raises:
|
|
761
|
+
RuntimeError: 如果创建失败
|
|
762
|
+
"""
|
|
381
763
|
super().__init__()
|
|
382
764
|
self._set_win32_api_properties()
|
|
383
765
|
|
|
384
|
-
self._notification_handler = notification_handler
|
|
385
766
|
self._handle = Library.framework().MaaWin32ControllerCreate(
|
|
386
767
|
hWnd,
|
|
387
768
|
MaaWin32ScreencapMethod(screencap_method),
|
|
388
|
-
MaaWin32InputMethod(
|
|
389
|
-
|
|
769
|
+
MaaWin32InputMethod(mouse_method),
|
|
770
|
+
MaaWin32InputMethod(keyboard_method),
|
|
390
771
|
)
|
|
391
772
|
|
|
392
773
|
if not self._handle:
|
|
@@ -398,12 +779,52 @@ class Win32Controller(Controller):
|
|
|
398
779
|
ctypes.c_void_p,
|
|
399
780
|
MaaWin32ScreencapMethod,
|
|
400
781
|
MaaWin32InputMethod,
|
|
401
|
-
|
|
402
|
-
|
|
782
|
+
MaaWin32InputMethod,
|
|
783
|
+
]
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
class PlayCoverController(Controller):
|
|
787
|
+
"""PlayCover 控制器 / PlayCover controller
|
|
788
|
+
|
|
789
|
+
用于在 macOS 上控制通过 PlayCover 运行的 iOS 应用
|
|
790
|
+
For controlling iOS apps running via PlayCover on macOS
|
|
791
|
+
"""
|
|
792
|
+
|
|
793
|
+
def __init__(
|
|
794
|
+
self,
|
|
795
|
+
address: str,
|
|
796
|
+
uuid: str,
|
|
797
|
+
):
|
|
798
|
+
"""创建 PlayCover 控制器 / Create PlayCover controller
|
|
799
|
+
|
|
800
|
+
Args:
|
|
801
|
+
address: PlayTools 服务地址 (host:port) / PlayTools service endpoint (host:port)
|
|
802
|
+
uuid: 目标应用 bundle identifier / Target app bundle identifier
|
|
803
|
+
|
|
804
|
+
Raises:
|
|
805
|
+
RuntimeError: 如果创建失败
|
|
806
|
+
"""
|
|
807
|
+
super().__init__()
|
|
808
|
+
self._set_playcover_api_properties()
|
|
809
|
+
|
|
810
|
+
self._handle = Library.framework().MaaPlayCoverControllerCreate(
|
|
811
|
+
address.encode(),
|
|
812
|
+
uuid.encode(),
|
|
813
|
+
)
|
|
814
|
+
|
|
815
|
+
if not self._handle:
|
|
816
|
+
raise RuntimeError("Failed to create PlayCover controller.")
|
|
817
|
+
|
|
818
|
+
def _set_playcover_api_properties(self):
|
|
819
|
+
Library.framework().MaaPlayCoverControllerCreate.restype = MaaControllerHandle
|
|
820
|
+
Library.framework().MaaPlayCoverControllerCreate.argtypes = [
|
|
821
|
+
ctypes.c_char_p,
|
|
822
|
+
ctypes.c_char_p,
|
|
403
823
|
]
|
|
404
824
|
|
|
405
825
|
|
|
406
826
|
class DbgController(Controller):
|
|
827
|
+
"""调试控制器 / Debug controller"""
|
|
407
828
|
|
|
408
829
|
def __init__(
|
|
409
830
|
self,
|
|
@@ -411,18 +832,26 @@ class DbgController(Controller):
|
|
|
411
832
|
write_path: Union[str, Path],
|
|
412
833
|
dbg_type: int,
|
|
413
834
|
config: Dict[str, Any] = {},
|
|
414
|
-
notification_handler: Optional[NotificationHandler] = None,
|
|
415
835
|
):
|
|
836
|
+
"""创建调试控制器 / Create debug controller
|
|
837
|
+
|
|
838
|
+
Args:
|
|
839
|
+
read_path: 输入路径, 包含通过 Recording 选项记录的操作 / Input path, includes operations recorded via Recording option
|
|
840
|
+
write_path: 输出路径, 包含执行结果 / Output path, includes execution results
|
|
841
|
+
dbg_type: 控制器模式 / Controller mode
|
|
842
|
+
config: 额外配置 / Extra config
|
|
843
|
+
|
|
844
|
+
Raises:
|
|
845
|
+
RuntimeError: 如果创建失败
|
|
846
|
+
"""
|
|
416
847
|
super().__init__()
|
|
417
848
|
self._set_dbg_api_properties()
|
|
418
849
|
|
|
419
|
-
self._notification_handler = notification_handler
|
|
420
850
|
self._handle = Library.framework().MaaDbgControllerCreate(
|
|
421
851
|
str(read_path).encode(),
|
|
422
852
|
str(write_path).encode(),
|
|
423
853
|
MaaDbgControllerType(dbg_type),
|
|
424
854
|
json.dumps(config, ensure_ascii=False).encode(),
|
|
425
|
-
*NotificationHandler._gen_c_param(self._notification_handler)
|
|
426
855
|
)
|
|
427
856
|
|
|
428
857
|
if not self._handle:
|
|
@@ -435,27 +864,77 @@ class DbgController(Controller):
|
|
|
435
864
|
ctypes.c_char_p,
|
|
436
865
|
MaaDbgControllerType,
|
|
437
866
|
ctypes.c_char_p,
|
|
438
|
-
MaaNotificationCallback,
|
|
439
|
-
ctypes.c_void_p,
|
|
440
867
|
]
|
|
441
868
|
|
|
442
869
|
|
|
443
|
-
class
|
|
870
|
+
class GamepadController(Controller):
|
|
871
|
+
"""虚拟手柄控制器 (仅 Windows) / Virtual gamepad controller (Windows only)
|
|
444
872
|
|
|
445
|
-
|
|
873
|
+
通过 ViGEm 模拟 Xbox 360 或 DualShock 4 手柄,用于控制需要手柄输入的游戏。
|
|
874
|
+
Emulates Xbox 360 or DualShock 4 gamepad via ViGEm for controlling games that require gamepad input.
|
|
875
|
+
|
|
876
|
+
需要安装 ViGEm Bus Driver: https://github.com/ViGEm/ViGEmBus/releases
|
|
877
|
+
Requires ViGEm Bus Driver: https://github.com/ViGEm/ViGEmBus/releases
|
|
878
|
+
|
|
879
|
+
手柄操作映射:
|
|
880
|
+
- click_key/key_down/key_up: 数字按键 (使用 MaaGamepadButtonEnum)
|
|
881
|
+
- touch_down/touch_move/touch_up: 摇杆和扳机 (contact 使用 MaaGamepadContactEnum)
|
|
882
|
+
- contact 0: 左摇杆 (x, y: -32768~32767)
|
|
883
|
+
- contact 1: 右摇杆 (x, y: -32768~32767)
|
|
884
|
+
- contact 2: 左扳机 (pressure: 0~255)
|
|
885
|
+
- contact 3: 右扳机 (pressure: 0~255)
|
|
886
|
+
"""
|
|
446
887
|
|
|
447
888
|
def __init__(
|
|
448
889
|
self,
|
|
449
|
-
|
|
890
|
+
hWnd: Union[ctypes.c_void_p, int, None],
|
|
891
|
+
gamepad_type: int = MaaGamepadTypeEnum.Xbox360,
|
|
892
|
+
screencap_method: int = MaaWin32ScreencapMethodEnum.PrintWindow,
|
|
450
893
|
):
|
|
894
|
+
"""创建虚拟手柄控制器 / Create virtual gamepad controller
|
|
895
|
+
|
|
896
|
+
Args:
|
|
897
|
+
hWnd: 窗口句柄,用于截图 (可为 None,不需要截图时) / Window handle for screencap (can be None if screencap not needed)
|
|
898
|
+
gamepad_type: 手柄类型 (MaaGamepadTypeEnum.Xbox360 或 MaaGamepadTypeEnum.DualShock4) / Gamepad type
|
|
899
|
+
screencap_method: 截图方式 (当 hWnd 不为 None 时使用) / Screencap method (used when hWnd is not None)
|
|
900
|
+
|
|
901
|
+
Raises:
|
|
902
|
+
RuntimeError: 如果创建失败
|
|
903
|
+
"""
|
|
451
904
|
super().__init__()
|
|
452
|
-
self.
|
|
905
|
+
self._set_gamepad_api_properties()
|
|
906
|
+
|
|
907
|
+
self._handle = Library.framework().MaaGamepadControllerCreate(
|
|
908
|
+
hWnd,
|
|
909
|
+
MaaGamepadType(gamepad_type),
|
|
910
|
+
MaaWin32ScreencapMethod(screencap_method),
|
|
911
|
+
)
|
|
912
|
+
|
|
913
|
+
if not self._handle:
|
|
914
|
+
raise RuntimeError("Failed to create Gamepad controller.")
|
|
915
|
+
|
|
916
|
+
def _set_gamepad_api_properties(self):
|
|
917
|
+
Library.framework().MaaGamepadControllerCreate.restype = MaaControllerHandle
|
|
918
|
+
Library.framework().MaaGamepadControllerCreate.argtypes = [
|
|
919
|
+
ctypes.c_void_p,
|
|
920
|
+
MaaGamepadType,
|
|
921
|
+
MaaWin32ScreencapMethod,
|
|
922
|
+
]
|
|
923
|
+
|
|
924
|
+
|
|
925
|
+
class CustomController(Controller):
|
|
926
|
+
|
|
927
|
+
_callbacks: MaaCustomControllerCallbacks
|
|
453
928
|
|
|
454
|
-
|
|
929
|
+
def __init__(self):
|
|
930
|
+
super().__init__()
|
|
931
|
+
self._set_custom_api_properties()
|
|
455
932
|
|
|
456
933
|
self._callbacks = MaaCustomControllerCallbacks(
|
|
457
934
|
CustomController._c_connect_agent,
|
|
935
|
+
CustomController._c_connected_agent,
|
|
458
936
|
CustomController._c_request_uuid_agent,
|
|
937
|
+
CustomController._c_get_features_agent,
|
|
459
938
|
CustomController._c_start_app_agent,
|
|
460
939
|
CustomController._c_stop_app_agent,
|
|
461
940
|
CustomController._c_screencap_agent,
|
|
@@ -468,12 +947,12 @@ class CustomController(Controller):
|
|
|
468
947
|
CustomController._c_input_text_agent,
|
|
469
948
|
CustomController._c_key_down_agent,
|
|
470
949
|
CustomController._c_key_up_agent,
|
|
950
|
+
CustomController._c_scroll_agent,
|
|
471
951
|
)
|
|
472
952
|
|
|
473
953
|
self._handle = Library.framework().MaaCustomControllerCreate(
|
|
474
954
|
self.c_handle,
|
|
475
955
|
self.c_arg,
|
|
476
|
-
*NotificationHandler._gen_c_param(self._notification_handler)
|
|
477
956
|
)
|
|
478
957
|
|
|
479
958
|
if not self._handle:
|
|
@@ -491,10 +970,20 @@ class CustomController(Controller):
|
|
|
491
970
|
def connect(self) -> bool:
|
|
492
971
|
raise NotImplementedError
|
|
493
972
|
|
|
973
|
+
def connected(self) -> bool:
|
|
974
|
+
"""检查是否已连接(可选实现,默认返回 True)"""
|
|
975
|
+
return True
|
|
976
|
+
|
|
494
977
|
@abstractmethod
|
|
495
978
|
def request_uuid(self) -> str:
|
|
496
979
|
raise NotImplementedError
|
|
497
980
|
|
|
981
|
+
def get_features(self) -> int:
|
|
982
|
+
return (
|
|
983
|
+
MaaControllerFeatureEnum.UseMouseDownAndUpInsteadOfClick
|
|
984
|
+
| MaaControllerFeatureEnum.UseKeyboardDownAndUpInsteadOfClick
|
|
985
|
+
)
|
|
986
|
+
|
|
498
987
|
@abstractmethod
|
|
499
988
|
def start_app(self, intent: str) -> bool:
|
|
500
989
|
raise NotImplementedError
|
|
@@ -555,6 +1044,10 @@ class CustomController(Controller):
|
|
|
555
1044
|
def key_up(self, keycode: int) -> bool:
|
|
556
1045
|
raise NotImplementedError
|
|
557
1046
|
|
|
1047
|
+
@abstractmethod
|
|
1048
|
+
def scroll(self, dx: int, dy: int) -> bool:
|
|
1049
|
+
raise NotImplementedError
|
|
1050
|
+
|
|
558
1051
|
@staticmethod
|
|
559
1052
|
@MaaCustomControllerCallbacks.ConnectFunc
|
|
560
1053
|
def _c_connect_agent(
|
|
@@ -570,6 +1063,21 @@ class CustomController(Controller):
|
|
|
570
1063
|
|
|
571
1064
|
return int(self.connect())
|
|
572
1065
|
|
|
1066
|
+
@staticmethod
|
|
1067
|
+
@MaaCustomControllerCallbacks.ConnectedFunc
|
|
1068
|
+
def _c_connected_agent(
|
|
1069
|
+
trans_arg: ctypes.c_void_p,
|
|
1070
|
+
) -> int:
|
|
1071
|
+
if not trans_arg:
|
|
1072
|
+
return int(False)
|
|
1073
|
+
|
|
1074
|
+
self: CustomController = ctypes.cast(
|
|
1075
|
+
trans_arg,
|
|
1076
|
+
ctypes.py_object,
|
|
1077
|
+
).value
|
|
1078
|
+
|
|
1079
|
+
return int(self.connected())
|
|
1080
|
+
|
|
573
1081
|
@staticmethod
|
|
574
1082
|
@MaaCustomControllerCallbacks.RequestUuidFunc
|
|
575
1083
|
def _c_request_uuid_agent(
|
|
@@ -590,6 +1098,19 @@ class CustomController(Controller):
|
|
|
590
1098
|
uuid_buffer.set(uuid)
|
|
591
1099
|
return int(True)
|
|
592
1100
|
|
|
1101
|
+
@staticmethod
|
|
1102
|
+
@MaaCustomControllerCallbacks.GetFeaturesFunc
|
|
1103
|
+
def _c_get_features_agent(trans_arg: ctypes.c_void_p) -> int:
|
|
1104
|
+
if not trans_arg:
|
|
1105
|
+
return int(MaaControllerFeatureEnum.Null)
|
|
1106
|
+
|
|
1107
|
+
self: CustomController = ctypes.cast(
|
|
1108
|
+
trans_arg,
|
|
1109
|
+
ctypes.py_object,
|
|
1110
|
+
).value
|
|
1111
|
+
|
|
1112
|
+
return int(self.get_features())
|
|
1113
|
+
|
|
593
1114
|
@staticmethod
|
|
594
1115
|
@MaaCustomControllerCallbacks.StartAppFunc
|
|
595
1116
|
def _c_start_app_agent(
|
|
@@ -800,11 +1321,65 @@ class CustomController(Controller):
|
|
|
800
1321
|
|
|
801
1322
|
return int(self.input_text(c_text.decode()))
|
|
802
1323
|
|
|
1324
|
+
@staticmethod
|
|
1325
|
+
@MaaCustomControllerCallbacks.ScrollFunc
|
|
1326
|
+
def _c_scroll_agent(
|
|
1327
|
+
c_dx: ctypes.c_int32,
|
|
1328
|
+
c_dy: ctypes.c_int32,
|
|
1329
|
+
trans_arg: ctypes.c_void_p,
|
|
1330
|
+
) -> int:
|
|
1331
|
+
if not trans_arg:
|
|
1332
|
+
return int(False)
|
|
1333
|
+
|
|
1334
|
+
self: CustomController = ctypes.cast(
|
|
1335
|
+
trans_arg,
|
|
1336
|
+
ctypes.py_object,
|
|
1337
|
+
).value
|
|
1338
|
+
|
|
1339
|
+
return int(self.scroll(int(c_dx), int(c_dy)))
|
|
1340
|
+
|
|
803
1341
|
def _set_custom_api_properties(self):
|
|
804
1342
|
Library.framework().MaaCustomControllerCreate.restype = MaaControllerHandle
|
|
805
1343
|
Library.framework().MaaCustomControllerCreate.argtypes = [
|
|
806
1344
|
ctypes.POINTER(MaaCustomControllerCallbacks),
|
|
807
1345
|
ctypes.c_void_p,
|
|
808
|
-
MaaNotificationCallback,
|
|
809
|
-
ctypes.c_void_p,
|
|
810
1346
|
]
|
|
1347
|
+
|
|
1348
|
+
|
|
1349
|
+
class ControllerEventSink(EventSink):
|
|
1350
|
+
|
|
1351
|
+
@dataclass
|
|
1352
|
+
class ControllerActionDetail:
|
|
1353
|
+
ctrl_id: int
|
|
1354
|
+
uuid: str
|
|
1355
|
+
action: str
|
|
1356
|
+
param: dict
|
|
1357
|
+
|
|
1358
|
+
def on_controller_action(
|
|
1359
|
+
self,
|
|
1360
|
+
controller: Controller,
|
|
1361
|
+
noti_type: NotificationType,
|
|
1362
|
+
detail: ControllerActionDetail,
|
|
1363
|
+
):
|
|
1364
|
+
pass
|
|
1365
|
+
|
|
1366
|
+
def on_raw_notification(self, controller: Controller, msg: str, details: dict):
|
|
1367
|
+
pass
|
|
1368
|
+
|
|
1369
|
+
def _on_raw_notification(self, handle: ctypes.c_void_p, msg: str, details: dict):
|
|
1370
|
+
|
|
1371
|
+
controller = Controller(handle=handle)
|
|
1372
|
+
self.on_raw_notification(controller, msg, details)
|
|
1373
|
+
|
|
1374
|
+
noti_type = EventSink._notification_type(msg)
|
|
1375
|
+
if msg.startswith("Controller.Action"):
|
|
1376
|
+
detail = self.ControllerActionDetail(
|
|
1377
|
+
ctrl_id=details["ctrl_id"],
|
|
1378
|
+
uuid=details["uuid"],
|
|
1379
|
+
action=details["action"],
|
|
1380
|
+
param=details["param"],
|
|
1381
|
+
)
|
|
1382
|
+
self.on_controller_action(controller, noti_type, detail)
|
|
1383
|
+
|
|
1384
|
+
else:
|
|
1385
|
+
self.on_unknown_notification(controller, msg, details)
|