MaaFw 4.4.0b1__py3-none-manylinux2014_x86_64.whl → 5.4.0__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.
Potentially problematic release.
This version of MaaFw might be problematic. Click here for more details.
- 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.408 → 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 +685 -44
- maa/custom_action.py +43 -0
- maa/custom_recognition.py +61 -9
- maa/define.py +450 -20
- 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 -90
- maa/toolkit.py +52 -91
- {maafw-4.4.0b1.dist-info → maafw-5.4.0.dist-info}/METADATA +90 -45
- maafw-5.4.0.dist-info/RECORD +35 -0
- {maafw-4.4.0b1.dist-info → maafw-5.4.0.dist-info}/WHEEL +1 -1
- maa/bin/libMaaDbgControlUnit.so +0 -0
- maa/notification_handler.py +0 -197
- maafw-4.4.0b1.dist-info/RECORD +0 -30
- {maafw-4.4.0b1.dist-info → maafw-5.4.0.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,36 +44,145 @@ 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
|
|
|
58
107
|
def post_press_key(self, key: int) -> Job:
|
|
59
|
-
|
|
108
|
+
"""
|
|
109
|
+
Deprecated: Use post_click_key instead.
|
|
110
|
+
"""
|
|
111
|
+
return self.post_click_key(key)
|
|
112
|
+
|
|
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
|
+
"""
|
|
122
|
+
ctrl_id = Library.framework().MaaControllerPostClickKey(self._handle, key)
|
|
123
|
+
return self._gen_ctrl_job(ctrl_id)
|
|
124
|
+
|
|
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
|
+
"""
|
|
134
|
+
ctrl_id = Library.framework().MaaControllerPostKeyDown(self._handle, key)
|
|
135
|
+
return self._gen_ctrl_job(ctrl_id)
|
|
136
|
+
|
|
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
|
+
"""
|
|
146
|
+
ctrl_id = Library.framework().MaaControllerPostKeyUp(self._handle, key)
|
|
60
147
|
return self._gen_ctrl_job(ctrl_id)
|
|
61
148
|
|
|
62
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
|
+
"""
|
|
63
158
|
ctrl_id = Library.framework().MaaControllerPostInputText(
|
|
64
159
|
self._handle, text.encode()
|
|
65
160
|
)
|
|
66
161
|
return self._gen_ctrl_job(ctrl_id)
|
|
67
162
|
|
|
68
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
|
+
"""
|
|
69
172
|
ctrl_id = Library.framework().MaaControllerPostStartApp(
|
|
70
173
|
self._handle, intent.encode()
|
|
71
174
|
)
|
|
72
175
|
return self._gen_ctrl_job(ctrl_id)
|
|
73
176
|
|
|
74
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
|
+
"""
|
|
75
186
|
ctrl_id = Library.framework().MaaControllerPostStopApp(
|
|
76
187
|
self._handle, intent.encode()
|
|
77
188
|
)
|
|
@@ -80,6 +191,17 @@ class Controller:
|
|
|
80
191
|
def post_touch_down(
|
|
81
192
|
self, x: int, y: int, contact: int = 0, pressure: int = 1
|
|
82
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
|
+
"""
|
|
83
205
|
ctrl_id = Library.framework().MaaControllerPostTouchDown(
|
|
84
206
|
self._handle, contact, x, y, pressure
|
|
85
207
|
)
|
|
@@ -88,16 +210,57 @@ class Controller:
|
|
|
88
210
|
def post_touch_move(
|
|
89
211
|
self, x: int, y: int, contact: int = 0, pressure: int = 1
|
|
90
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
|
+
"""
|
|
91
224
|
ctrl_id = Library.framework().MaaControllerPostTouchMove(
|
|
92
225
|
self._handle, contact, x, y, pressure
|
|
93
226
|
)
|
|
94
227
|
return self._gen_ctrl_job(ctrl_id)
|
|
95
228
|
|
|
96
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
|
+
"""
|
|
97
238
|
ctrl_id = Library.framework().MaaControllerPostTouchUp(self._handle, contact)
|
|
98
239
|
return self._gen_ctrl_job(ctrl_id)
|
|
99
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
|
+
|
|
100
258
|
def post_screencap(self) -> JobWithResult:
|
|
259
|
+
"""截图 / Screenshot
|
|
260
|
+
|
|
261
|
+
Returns:
|
|
262
|
+
JobWithResult: 作业对象,可通过 result 获取截图 / Job object, can get screenshot via result
|
|
263
|
+
"""
|
|
101
264
|
ctrl_id = Library.framework().MaaControllerPostScreencap(self._handle)
|
|
102
265
|
return JobWithResult(
|
|
103
266
|
ctrl_id,
|
|
@@ -108,6 +271,22 @@ class Controller:
|
|
|
108
271
|
|
|
109
272
|
@property
|
|
110
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
|
+
"""
|
|
111
290
|
image_buffer = ImageBuffer()
|
|
112
291
|
if not Library.framework().MaaControllerCachedImage(
|
|
113
292
|
self._handle, image_buffer._handle
|
|
@@ -115,18 +294,101 @@ class Controller:
|
|
|
115
294
|
raise RuntimeError("Failed to get cached image.")
|
|
116
295
|
return image_buffer.get()
|
|
117
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
|
+
|
|
118
334
|
@property
|
|
119
335
|
def connected(self) -> bool:
|
|
336
|
+
"""判断是否已连接 / Check if connected
|
|
337
|
+
|
|
338
|
+
Returns:
|
|
339
|
+
bool: 是否已连接 / Whether connected
|
|
340
|
+
"""
|
|
120
341
|
return bool(Library.framework().MaaControllerConnected(self._handle))
|
|
121
342
|
|
|
122
343
|
@property
|
|
123
344
|
def uuid(self) -> str:
|
|
345
|
+
"""获取设备 uuid / Get device uuid
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
str: 设备 uuid / Device uuid
|
|
349
|
+
|
|
350
|
+
Raises:
|
|
351
|
+
RuntimeError: 如果获取失败
|
|
352
|
+
"""
|
|
124
353
|
buffer = StringBuffer()
|
|
125
354
|
if not Library.framework().MaaControllerGetUuid(self._handle, buffer._handle):
|
|
126
355
|
raise RuntimeError("Failed to get UUID.")
|
|
127
356
|
return buffer.get()
|
|
128
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
|
+
|
|
129
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
|
+
"""
|
|
130
392
|
cint = ctypes.c_int32(long_side)
|
|
131
393
|
return bool(
|
|
132
394
|
Library.framework().MaaControllerSetOption(
|
|
@@ -138,6 +400,14 @@ class Controller:
|
|
|
138
400
|
)
|
|
139
401
|
|
|
140
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
|
+
"""
|
|
141
411
|
cint = ctypes.c_int32(short_side)
|
|
142
412
|
return bool(
|
|
143
413
|
Library.framework().MaaControllerSetOption(
|
|
@@ -149,6 +419,17 @@ class Controller:
|
|
|
149
419
|
)
|
|
150
420
|
|
|
151
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
|
+
"""
|
|
152
433
|
cbool = MaaBool(enable)
|
|
153
434
|
return bool(
|
|
154
435
|
Library.framework().MaaControllerSetOption(
|
|
@@ -159,6 +440,41 @@ class Controller:
|
|
|
159
440
|
)
|
|
160
441
|
)
|
|
161
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
|
+
|
|
162
478
|
### private ###
|
|
163
479
|
|
|
164
480
|
def _status(self, maaid: int) -> MaaStatus:
|
|
@@ -170,6 +486,9 @@ class Controller:
|
|
|
170
486
|
def _get_screencap(self, _: int) -> numpy.ndarray:
|
|
171
487
|
return self.cached_image
|
|
172
488
|
|
|
489
|
+
def _get_shell_output(self, _: int) -> str:
|
|
490
|
+
return self.shell_output
|
|
491
|
+
|
|
173
492
|
def _gen_ctrl_job(self, ctrlid: MaaCtrlId) -> Job:
|
|
174
493
|
return Job(
|
|
175
494
|
ctrlid,
|
|
@@ -206,6 +525,15 @@ class Controller:
|
|
|
206
525
|
c_int32,
|
|
207
526
|
]
|
|
208
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
|
+
|
|
209
537
|
Library.framework().MaaControllerPostSwipe.restype = MaaCtrlId
|
|
210
538
|
Library.framework().MaaControllerPostSwipe.argtypes = [
|
|
211
539
|
MaaControllerHandle,
|
|
@@ -216,12 +544,34 @@ class Controller:
|
|
|
216
544
|
c_int32,
|
|
217
545
|
]
|
|
218
546
|
|
|
219
|
-
Library.framework().
|
|
220
|
-
Library.framework().
|
|
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
|
+
|
|
559
|
+
Library.framework().MaaControllerPostClickKey.restype = MaaCtrlId
|
|
560
|
+
Library.framework().MaaControllerPostClickKey.argtypes = [
|
|
221
561
|
MaaControllerHandle,
|
|
222
562
|
c_int32,
|
|
223
563
|
]
|
|
224
564
|
|
|
565
|
+
Library.framework().MaaControllerPostKeyDown.restype = MaaCtrlId
|
|
566
|
+
Library.framework().MaaControllerPostKeyDown.argtypes = [
|
|
567
|
+
MaaControllerHandle,
|
|
568
|
+
c_int32,
|
|
569
|
+
]
|
|
570
|
+
Library.framework().MaaControllerPostKeyUp.restype = MaaCtrlId
|
|
571
|
+
Library.framework().MaaControllerPostKeyUp.argtypes = [
|
|
572
|
+
MaaControllerHandle,
|
|
573
|
+
c_int32,
|
|
574
|
+
]
|
|
225
575
|
Library.framework().MaaControllerPostInputText.restype = MaaCtrlId
|
|
226
576
|
Library.framework().MaaControllerPostInputText.argtypes = [
|
|
227
577
|
MaaControllerHandle,
|
|
@@ -268,6 +618,14 @@ class Controller:
|
|
|
268
618
|
MaaControllerHandle,
|
|
269
619
|
c_int32,
|
|
270
620
|
]
|
|
621
|
+
|
|
622
|
+
Library.framework().MaaControllerPostScroll.restype = MaaCtrlId
|
|
623
|
+
Library.framework().MaaControllerPostScroll.argtypes = [
|
|
624
|
+
MaaControllerHandle,
|
|
625
|
+
c_int32,
|
|
626
|
+
c_int32,
|
|
627
|
+
]
|
|
628
|
+
|
|
271
629
|
Library.framework().MaaControllerStatus.restype = MaaStatus
|
|
272
630
|
Library.framework().MaaControllerStatus.argtypes = [
|
|
273
631
|
MaaControllerHandle,
|
|
@@ -295,8 +653,37 @@ class Controller:
|
|
|
295
653
|
MaaStringBufferHandle,
|
|
296
654
|
]
|
|
297
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
|
+
|
|
298
679
|
|
|
299
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
|
+
|
|
300
687
|
AGENT_BINARY_PATH = os.path.join(
|
|
301
688
|
os.path.dirname(__file__),
|
|
302
689
|
"../MaaAgentBinary",
|
|
@@ -310,13 +697,23 @@ class AdbController(Controller):
|
|
|
310
697
|
input_methods: int = MaaAdbInputMethodEnum.Default,
|
|
311
698
|
config: Dict[str, Any] = {},
|
|
312
699
|
agent_path: Union[str, Path] = AGENT_BINARY_PATH,
|
|
313
|
-
notification_handler: Optional[NotificationHandler] = None,
|
|
314
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
|
+
"""
|
|
315
714
|
super().__init__()
|
|
316
715
|
self._set_adb_api_properties()
|
|
317
716
|
|
|
318
|
-
self._notification_handler = notification_handler
|
|
319
|
-
|
|
320
717
|
self._handle = Library.framework().MaaAdbControllerCreate(
|
|
321
718
|
str(adb_path).encode(),
|
|
322
719
|
address.encode(),
|
|
@@ -324,7 +721,6 @@ class AdbController(Controller):
|
|
|
324
721
|
MaaAdbInputMethod(input_methods),
|
|
325
722
|
json.dumps(config, ensure_ascii=False).encode(),
|
|
326
723
|
str(agent_path).encode(),
|
|
327
|
-
*NotificationHandler._gen_c_param(self._notification_handler)
|
|
328
724
|
)
|
|
329
725
|
|
|
330
726
|
if not self._handle:
|
|
@@ -340,29 +736,38 @@ class AdbController(Controller):
|
|
|
340
736
|
MaaAdbInputMethod,
|
|
341
737
|
ctypes.c_char_p,
|
|
342
738
|
ctypes.c_char_p,
|
|
343
|
-
MaaNotificationCallback,
|
|
344
|
-
ctypes.c_void_p,
|
|
345
739
|
]
|
|
346
740
|
|
|
347
741
|
|
|
348
742
|
class Win32Controller(Controller):
|
|
743
|
+
"""Win32 控制器 / Win32 controller"""
|
|
349
744
|
|
|
350
745
|
def __init__(
|
|
351
746
|
self,
|
|
352
747
|
hWnd: Union[ctypes.c_void_p, int, None],
|
|
353
|
-
screencap_method: int = MaaWin32ScreencapMethodEnum.
|
|
354
|
-
|
|
355
|
-
|
|
748
|
+
screencap_method: int = MaaWin32ScreencapMethodEnum.FramePool,
|
|
749
|
+
mouse_method: int = MaaWin32InputMethodEnum.Seize,
|
|
750
|
+
keyboard_method: int = MaaWin32InputMethodEnum.Seize,
|
|
356
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
|
+
"""
|
|
357
763
|
super().__init__()
|
|
358
764
|
self._set_win32_api_properties()
|
|
359
765
|
|
|
360
|
-
self._notification_handler = notification_handler
|
|
361
766
|
self._handle = Library.framework().MaaWin32ControllerCreate(
|
|
362
767
|
hWnd,
|
|
363
768
|
MaaWin32ScreencapMethod(screencap_method),
|
|
364
|
-
MaaWin32InputMethod(
|
|
365
|
-
|
|
769
|
+
MaaWin32InputMethod(mouse_method),
|
|
770
|
+
MaaWin32InputMethod(keyboard_method),
|
|
366
771
|
)
|
|
367
772
|
|
|
368
773
|
if not self._handle:
|
|
@@ -374,12 +779,52 @@ class Win32Controller(Controller):
|
|
|
374
779
|
ctypes.c_void_p,
|
|
375
780
|
MaaWin32ScreencapMethod,
|
|
376
781
|
MaaWin32InputMethod,
|
|
377
|
-
|
|
378
|
-
|
|
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,
|
|
379
823
|
]
|
|
380
824
|
|
|
381
825
|
|
|
382
826
|
class DbgController(Controller):
|
|
827
|
+
"""调试控制器 / Debug controller"""
|
|
383
828
|
|
|
384
829
|
def __init__(
|
|
385
830
|
self,
|
|
@@ -387,18 +832,26 @@ class DbgController(Controller):
|
|
|
387
832
|
write_path: Union[str, Path],
|
|
388
833
|
dbg_type: int,
|
|
389
834
|
config: Dict[str, Any] = {},
|
|
390
|
-
notification_handler: Optional[NotificationHandler] = None,
|
|
391
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
|
+
"""
|
|
392
847
|
super().__init__()
|
|
393
848
|
self._set_dbg_api_properties()
|
|
394
849
|
|
|
395
|
-
self._notification_handler = notification_handler
|
|
396
850
|
self._handle = Library.framework().MaaDbgControllerCreate(
|
|
397
851
|
str(read_path).encode(),
|
|
398
852
|
str(write_path).encode(),
|
|
399
853
|
MaaDbgControllerType(dbg_type),
|
|
400
854
|
json.dumps(config, ensure_ascii=False).encode(),
|
|
401
|
-
*NotificationHandler._gen_c_param(self._notification_handler)
|
|
402
855
|
)
|
|
403
856
|
|
|
404
857
|
if not self._handle:
|
|
@@ -411,27 +864,77 @@ class DbgController(Controller):
|
|
|
411
864
|
ctypes.c_char_p,
|
|
412
865
|
MaaDbgControllerType,
|
|
413
866
|
ctypes.c_char_p,
|
|
414
|
-
MaaNotificationCallback,
|
|
415
|
-
ctypes.c_void_p,
|
|
416
867
|
]
|
|
417
868
|
|
|
418
869
|
|
|
419
|
-
class
|
|
870
|
+
class GamepadController(Controller):
|
|
871
|
+
"""虚拟手柄控制器 (仅 Windows) / Virtual gamepad controller (Windows only)
|
|
420
872
|
|
|
421
|
-
|
|
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
|
+
"""
|
|
422
887
|
|
|
423
888
|
def __init__(
|
|
424
889
|
self,
|
|
425
|
-
|
|
890
|
+
hWnd: Union[ctypes.c_void_p, int, None],
|
|
891
|
+
gamepad_type: int = MaaGamepadTypeEnum.Xbox360,
|
|
892
|
+
screencap_method: int = MaaWin32ScreencapMethodEnum.FramePool,
|
|
426
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
|
+
"""
|
|
427
904
|
super().__init__()
|
|
428
|
-
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
|
+
)
|
|
429
912
|
|
|
430
|
-
self.
|
|
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
|
|
928
|
+
|
|
929
|
+
def __init__(self):
|
|
930
|
+
super().__init__()
|
|
931
|
+
self._set_custom_api_properties()
|
|
431
932
|
|
|
432
933
|
self._callbacks = MaaCustomControllerCallbacks(
|
|
433
934
|
CustomController._c_connect_agent,
|
|
935
|
+
CustomController._c_connected_agent,
|
|
434
936
|
CustomController._c_request_uuid_agent,
|
|
937
|
+
CustomController._c_get_features_agent,
|
|
435
938
|
CustomController._c_start_app_agent,
|
|
436
939
|
CustomController._c_stop_app_agent,
|
|
437
940
|
CustomController._c_screencap_agent,
|
|
@@ -440,14 +943,16 @@ class CustomController(Controller):
|
|
|
440
943
|
CustomController._c_touch_down_agent,
|
|
441
944
|
CustomController._c_touch_move_agent,
|
|
442
945
|
CustomController._c_touch_up_agent,
|
|
443
|
-
CustomController.
|
|
946
|
+
CustomController._c_click_key_agent,
|
|
444
947
|
CustomController._c_input_text_agent,
|
|
948
|
+
CustomController._c_key_down_agent,
|
|
949
|
+
CustomController._c_key_up_agent,
|
|
950
|
+
CustomController._c_scroll_agent,
|
|
445
951
|
)
|
|
446
952
|
|
|
447
953
|
self._handle = Library.framework().MaaCustomControllerCreate(
|
|
448
954
|
self.c_handle,
|
|
449
955
|
self.c_arg,
|
|
450
|
-
*NotificationHandler._gen_c_param(self._notification_handler)
|
|
451
956
|
)
|
|
452
957
|
|
|
453
958
|
if not self._handle:
|
|
@@ -465,10 +970,20 @@ class CustomController(Controller):
|
|
|
465
970
|
def connect(self) -> bool:
|
|
466
971
|
raise NotImplementedError
|
|
467
972
|
|
|
973
|
+
def connected(self) -> bool:
|
|
974
|
+
"""检查是否已连接(可选实现,默认返回 True)"""
|
|
975
|
+
return True
|
|
976
|
+
|
|
468
977
|
@abstractmethod
|
|
469
978
|
def request_uuid(self) -> str:
|
|
470
979
|
raise NotImplementedError
|
|
471
980
|
|
|
981
|
+
def get_features(self) -> int:
|
|
982
|
+
return (
|
|
983
|
+
MaaControllerFeatureEnum.UseMouseDownAndUpInsteadOfClick
|
|
984
|
+
| MaaControllerFeatureEnum.UseKeyboardDownAndUpInsteadOfClick
|
|
985
|
+
)
|
|
986
|
+
|
|
472
987
|
@abstractmethod
|
|
473
988
|
def start_app(self, intent: str) -> bool:
|
|
474
989
|
raise NotImplementedError
|
|
@@ -514,13 +1029,25 @@ class CustomController(Controller):
|
|
|
514
1029
|
raise NotImplementedError
|
|
515
1030
|
|
|
516
1031
|
@abstractmethod
|
|
517
|
-
def
|
|
1032
|
+
def click_key(self, keycode: int) -> bool:
|
|
518
1033
|
raise NotImplementedError
|
|
519
1034
|
|
|
520
1035
|
@abstractmethod
|
|
521
1036
|
def input_text(self, text: str) -> bool:
|
|
522
1037
|
raise NotImplementedError
|
|
523
1038
|
|
|
1039
|
+
@abstractmethod
|
|
1040
|
+
def key_down(self, keycode: int) -> bool:
|
|
1041
|
+
raise NotImplementedError
|
|
1042
|
+
|
|
1043
|
+
@abstractmethod
|
|
1044
|
+
def key_up(self, keycode: int) -> bool:
|
|
1045
|
+
raise NotImplementedError
|
|
1046
|
+
|
|
1047
|
+
@abstractmethod
|
|
1048
|
+
def scroll(self, dx: int, dy: int) -> bool:
|
|
1049
|
+
raise NotImplementedError
|
|
1050
|
+
|
|
524
1051
|
@staticmethod
|
|
525
1052
|
@MaaCustomControllerCallbacks.ConnectFunc
|
|
526
1053
|
def _c_connect_agent(
|
|
@@ -536,6 +1063,21 @@ class CustomController(Controller):
|
|
|
536
1063
|
|
|
537
1064
|
return int(self.connect())
|
|
538
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
|
+
|
|
539
1081
|
@staticmethod
|
|
540
1082
|
@MaaCustomControllerCallbacks.RequestUuidFunc
|
|
541
1083
|
def _c_request_uuid_agent(
|
|
@@ -556,6 +1098,19 @@ class CustomController(Controller):
|
|
|
556
1098
|
uuid_buffer.set(uuid)
|
|
557
1099
|
return int(True)
|
|
558
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
|
+
|
|
559
1114
|
@staticmethod
|
|
560
1115
|
@MaaCustomControllerCallbacks.StartAppFunc
|
|
561
1116
|
def _c_start_app_agent(
|
|
@@ -703,8 +1258,8 @@ class CustomController(Controller):
|
|
|
703
1258
|
return int(self.touch_up(int(c_contact)))
|
|
704
1259
|
|
|
705
1260
|
@staticmethod
|
|
706
|
-
@MaaCustomControllerCallbacks.
|
|
707
|
-
def
|
|
1261
|
+
@MaaCustomControllerCallbacks.ClickKeyFunc
|
|
1262
|
+
def _c_click_key_agent(
|
|
708
1263
|
c_keycode: ctypes.c_int32,
|
|
709
1264
|
trans_arg: ctypes.c_void_p,
|
|
710
1265
|
) -> int:
|
|
@@ -716,7 +1271,39 @@ class CustomController(Controller):
|
|
|
716
1271
|
ctypes.py_object,
|
|
717
1272
|
).value
|
|
718
1273
|
|
|
719
|
-
return int(self.
|
|
1274
|
+
return int(self.click_key(int(c_keycode)))
|
|
1275
|
+
|
|
1276
|
+
@staticmethod
|
|
1277
|
+
@MaaCustomControllerCallbacks.KeyDownFunc
|
|
1278
|
+
def _c_key_down_agent(
|
|
1279
|
+
c_keycode: ctypes.c_int32,
|
|
1280
|
+
trans_arg: ctypes.c_void_p,
|
|
1281
|
+
) -> int:
|
|
1282
|
+
if not trans_arg:
|
|
1283
|
+
return int(False)
|
|
1284
|
+
|
|
1285
|
+
self: CustomController = ctypes.cast(
|
|
1286
|
+
trans_arg,
|
|
1287
|
+
ctypes.py_object,
|
|
1288
|
+
).value
|
|
1289
|
+
|
|
1290
|
+
return int(self.key_down(int(c_keycode)))
|
|
1291
|
+
|
|
1292
|
+
@staticmethod
|
|
1293
|
+
@MaaCustomControllerCallbacks.KeyUpFunc
|
|
1294
|
+
def _c_key_up_agent(
|
|
1295
|
+
c_keycode: ctypes.c_int32,
|
|
1296
|
+
trans_arg: ctypes.c_void_p,
|
|
1297
|
+
) -> int:
|
|
1298
|
+
if not trans_arg:
|
|
1299
|
+
return int(False)
|
|
1300
|
+
|
|
1301
|
+
self: CustomController = ctypes.cast(
|
|
1302
|
+
trans_arg,
|
|
1303
|
+
ctypes.py_object,
|
|
1304
|
+
).value
|
|
1305
|
+
|
|
1306
|
+
return int(self.key_up(int(c_keycode)))
|
|
720
1307
|
|
|
721
1308
|
@staticmethod
|
|
722
1309
|
@MaaCustomControllerCallbacks.InputTextFunc
|
|
@@ -734,11 +1321,65 @@ class CustomController(Controller):
|
|
|
734
1321
|
|
|
735
1322
|
return int(self.input_text(c_text.decode()))
|
|
736
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
|
+
|
|
737
1341
|
def _set_custom_api_properties(self):
|
|
738
1342
|
Library.framework().MaaCustomControllerCreate.restype = MaaControllerHandle
|
|
739
1343
|
Library.framework().MaaCustomControllerCreate.argtypes = [
|
|
740
1344
|
ctypes.POINTER(MaaCustomControllerCallbacks),
|
|
741
1345
|
ctypes.c_void_p,
|
|
742
|
-
MaaNotificationCallback,
|
|
743
|
-
ctypes.c_void_p,
|
|
744
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)
|