Skip to content

Commit

Permalink
feat: 初步支持win32窗口调试
Browse files Browse the repository at this point in the history
  • Loading branch information
MistEO committed May 8, 2024
1 parent 0115e1d commit a61712d
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 22 deletions.
6 changes: 3 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
"version": "0.2.0",
"configurations": [
{
"name": "Main File",
"name": "MaaDebugger 本地调试",
"type": "debugpy",
"request": "launch",
"program": "main.py",
"console": "integratedTerminal"
"module": "MaaDebugger",
"cwd": "${workspaceFolder}/src"
}
]
}
32 changes: 31 additions & 1 deletion src/MaaDebugger/maafw/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import asyncio
from dataclasses import dataclass
from pathlib import Path
from typing import Callable, List, Optional

from maa.controller import AdbController
from maa.controller import AdbController, Win32Controller
from maa.instance import Instance
from maa.resource import Resource
from maa.toolkit import Toolkit
Expand Down Expand Up @@ -35,6 +36,23 @@ def __init__(
async def detect_adb() -> List["AdbDevice"]:
return await Toolkit.adb_devices()

@dataclass
class Window:
hwnd: int
class_name: str
window_name: str

@staticmethod
async def detect_win32hwnd(class_regex: str, window_regex: str) -> List[Window]:
hwnds = Toolkit.search_window(class_regex, window_regex)
windows = []
for hwnd in hwnds:
class_name = Toolkit.get_class_name(hwnd)
window_name = Toolkit.get_window_name(hwnd)
windows.append(MaaFW.Window(hwnd, class_name, window_name))

return windows

async def connect_adb(self, path: Path, address: str) -> bool:
self.controller = AdbController(path, address)
connected = await self.controller.connect()
Expand All @@ -44,6 +62,18 @@ async def connect_adb(self, path: Path, address: str) -> bool:

return True

async def connect_win32hwnd(self, hwnd: int | str) -> bool:
if isinstance(hwnd, str):
hwnd = int(hwnd, 16)

self.controller = Win32Controller(hwnd)
connected = await self.controller.connect()
if not connected:
print(f"Failed to connect {hwnd}")
return False

return True

async def load_resource(self, dir: Path) -> bool:
if not self.resource:
self.resource = Resource()
Expand Down
123 changes: 105 additions & 18 deletions src/MaaDebugger/webpage/index_page/master_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,16 @@


class GlobalStatus:
adb_connecting: Status = Status.PENDING
adb_detecting: Status = Status.PENDING # not required
ctrl_connecting: Status = Status.PENDING
ctrl_detecting: Status = Status.PENDING # not required
res_loading: Status = Status.PENDING
task_running: Status = Status.PENDING


async def main():
with ui.row():
with ui.column():
with ui.row().style("align-items: center;"):
await connect_adb_control()
await connect_control()
with ui.row().style("align-items: center;"):
await load_resource_control()
with ui.row().style("align-items: center;"):
Expand All @@ -30,8 +29,24 @@ async def main():
await screenshot_control()


async def connect_control():
with ui.tabs() as tabs:
adb = ui.tab("Adb")
win32 = ui.tab("Win32")

with ui.tab_panels(tabs, value="Adb").bind_value(
app.storage.general, "controller_type"
):
with ui.tab_panel(adb):
with ui.row().style("align-items: center;"):
await connect_adb_control()
with ui.tab_panel(win32):
with ui.row().style("align-items: center;"):
await connect_win32_control()


async def connect_adb_control():
StatusIndicator(GlobalStatus, "adb_connecting")
StatusIndicator(GlobalStatus, "ctrl_connecting")

adb_path_input = (
ui.input(
Expand Down Expand Up @@ -63,37 +78,37 @@ async def connect_adb_control():
{}, on_change=lambda e: on_change_devices_select(e)
).bind_visibility_from(
GlobalStatus,
"adb_detecting",
"ctrl_detecting",
backward=lambda s: s == Status.SUCCESS,
)

StatusIndicator(GlobalStatus, "adb_detecting").label().bind_visibility_from(
StatusIndicator(GlobalStatus, "ctrl_detecting").label().bind_visibility_from(
GlobalStatus,
"adb_detecting",
"ctrl_detecting",
backward=lambda s: s == Status.RUNNING or s == Status.FAILURE,
)

async def on_click_connect():
GlobalStatus.adb_connecting = Status.RUNNING
GlobalStatus.ctrl_connecting = Status.RUNNING

if not adb_path_input.value or not adb_address_input.value:
GlobalStatus.adb_connecting = Status.FAILURE
GlobalStatus.ctrl_connecting = Status.FAILURE
return

connected = await maafw.connect_adb(
Path(adb_path_input.value), adb_address_input.value
)
if not connected:
GlobalStatus.adb_connecting = Status.FAILURE
GlobalStatus.ctrl_connecting = Status.FAILURE
return

GlobalStatus.adb_connecting = Status.SUCCESS
GlobalStatus.adb_detecting = Status.PENDING
GlobalStatus.ctrl_connecting = Status.SUCCESS
GlobalStatus.ctrl_detecting = Status.PENDING

await maafw.screenshotter.refresh(True)

async def on_click_detect():
GlobalStatus.adb_detecting = Status.RUNNING
GlobalStatus.ctrl_detecting = Status.RUNNING

devices = await maafw.detect_adb()
options = {}
Expand All @@ -105,17 +120,89 @@ async def on_click_detect():
devices_select.options = options
devices_select.update()
if not options:
GlobalStatus.adb_detecting = Status.FAILURE
GlobalStatus.ctrl_detecting = Status.FAILURE
return

devices_select.value = next(iter(options))
GlobalStatus.adb_detecting = Status.SUCCESS
GlobalStatus.ctrl_detecting = Status.SUCCESS

def on_change_devices_select(e):
adb_path_input.value = str(e.value[0])
adb_address_input.value = e.value[1]


async def connect_win32_control():
StatusIndicator(GlobalStatus, "ctrl_connecting")

hwnd_input = (
ui.input("HWND").props("size=30").bind_value(app.storage.general, "hwnd")
)
ui.button(
"Connect",
on_click=lambda: on_click_connect(),
)
window_name_input = (
ui.input("Window Regex")
.props("size=30")
.bind_value(app.storage.general, "window_name")
)
ui.button(
icon="wifi_find",
on_click=lambda: on_click_detect(),
)

devices_select = ui.select(
{}, on_change=lambda e: on_change_devices_select(e)
).bind_visibility_from(
GlobalStatus,
"ctrl_detecting",
backward=lambda s: s == Status.SUCCESS,
)

StatusIndicator(GlobalStatus, "ctrl_detecting").label().bind_visibility_from(
GlobalStatus,
"ctrl_detecting",
backward=lambda s: s == Status.RUNNING or s == Status.FAILURE,
)

async def on_click_connect():
GlobalStatus.ctrl_connecting = Status.RUNNING

if not hwnd_input.value:
GlobalStatus.ctrl_connecting = Status.FAILURE
return

connected = await maafw.connect_win32hwnd(hwnd_input.value)
if not connected:
GlobalStatus.ctrl_connecting = Status.FAILURE
return

GlobalStatus.ctrl_connecting = Status.SUCCESS
GlobalStatus.ctrl_detecting = Status.PENDING

await maafw.screenshotter.refresh(True)

async def on_click_detect():
GlobalStatus.ctrl_detecting = Status.RUNNING

windows = await maafw.detect_win32hwnd("", window_name_input.value)
options = {}
for w in windows:
options[hex(w.hwnd)] = hex(w.hwnd) + " " + w.window_name

devices_select.options = options
devices_select.update()
if not options:
GlobalStatus.ctrl_detecting = Status.FAILURE
return

devices_select.value = next(iter(options))
GlobalStatus.ctrl_detecting = Status.SUCCESS

def on_change_devices_select(e):
hwnd_input.value = e.value


async def screenshot_control():
with ui.row().style("align-items: flex-end;"):
with ui.card().tight():
Expand All @@ -125,13 +212,13 @@ async def screenshot_control():
).bind_source_from(maafw.screenshotter, "source").style(
"height: 200px;"
).bind_visibility_from(
GlobalStatus, "adb_connecting", backward=lambda s: s == Status.SUCCESS
GlobalStatus, "ctrl_connecting", backward=lambda s: s == Status.SUCCESS
)

ui.button(
icon="refresh", on_click=lambda: on_click_refresh()
).bind_visibility_from(
GlobalStatus, "adb_connecting", backward=lambda s: s == Status.SUCCESS
GlobalStatus, "ctrl_connecting", backward=lambda s: s == Status.SUCCESS
).bind_enabled_from(
GlobalStatus, "task_running", backward=lambda s: s != Status.RUNNING
)
Expand Down

0 comments on commit a61712d

Please sign in to comment.