104 lines
3.2 KiB
Python
104 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
|
"""从 DFHack 文本截图中按文字定位控件,并生成点击坐标。
|
|
|
|
配合 dfannals/screentext 与 dfannals/click 使用:
|
|
1) dfhack-run dfannals/screentext
|
|
2) scripts/df-screen.py click --label "History length" --text "250 years"
|
|
|
|
屏幕文本文件里第 1 行是表头,因此 屏幕 y = 文件行号 - 2。
|
|
坐标为 0 起始的字符网格坐标,与 dfannals/click 一致。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
SCREEN = Path("/mnt/c/Users/23518/DwarfFortress/dfannals-screen.txt")
|
|
|
|
|
|
def read_screen(path: Path) -> list[str]:
|
|
if not path.is_file():
|
|
sys.exit(f"找不到截图文件:{path}")
|
|
raw = path.read_text(encoding="utf-8", errors="replace").splitlines()
|
|
return raw[1:] # 去掉 "# focus=..." 表头,使下标 = 屏幕 y
|
|
|
|
|
|
def char_index(line: str, needle: str) -> int:
|
|
return line.find(needle)
|
|
|
|
|
|
def find_row(lines: list[str], needle: str, start: int = 0) -> int:
|
|
for i in range(start, len(lines)):
|
|
if needle in lines[i]:
|
|
return i
|
|
return -1
|
|
|
|
|
|
def cmd_list(args: argparse.Namespace) -> int:
|
|
lines = read_screen(args.file)
|
|
for y, line in enumerate(lines):
|
|
if line.strip():
|
|
print(f"{y:3} | {line.rstrip()}")
|
|
return 0
|
|
|
|
|
|
def cmd_click(args: argparse.Namespace) -> int:
|
|
lines = read_screen(args.file)
|
|
start = 0
|
|
if args.label:
|
|
label_row = find_row(lines, args.label)
|
|
if label_row < 0:
|
|
sys.exit(f"界面上找不到标签:{args.label}")
|
|
start = label_row
|
|
row = find_row(lines, args.text, start)
|
|
if row < 0:
|
|
sys.exit(f"找不到文字:{args.text}" + (f"(在 {args.label} 之下)" if args.label else ""))
|
|
|
|
line = lines[row]
|
|
idx = char_index(line, args.text)
|
|
x = idx + len(args.text) // 2
|
|
y = row
|
|
print(f"{x} {y}")
|
|
if args.verbose:
|
|
print(f"# 第 {row} 行,列 {idx},点击中心 ({x}, {y})", file=sys.stderr)
|
|
return 0
|
|
|
|
|
|
def cmd_where(args: argparse.Namespace) -> int:
|
|
lines = read_screen(args.file)
|
|
for pattern in args.patterns:
|
|
row = find_row(lines, pattern)
|
|
if row < 0:
|
|
print(f"{pattern}: 未找到")
|
|
continue
|
|
idx = char_index(lines[row], pattern)
|
|
print(f"{pattern}: x={idx + len(pattern) // 2} y={row}")
|
|
return 0
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description="DF 文本截图定位工具")
|
|
parser.add_argument("--file", type=Path, default=SCREEN)
|
|
sub = parser.add_subparsers(dest="cmd", required=True)
|
|
|
|
p = sub.add_parser("list", help="列出非空行(带屏幕 y 坐标)")
|
|
p.set_defaults(func=cmd_list)
|
|
|
|
p = sub.add_parser("click", help="输出某段文字的中心坐标")
|
|
p.add_argument("--label", help="先定位这个标签,再在它下面找目标文字")
|
|
p.add_argument("--text", required=True, help="要点击的文字")
|
|
p.add_argument("-v", "--verbose", action="store_true")
|
|
p.set_defaults(func=cmd_click)
|
|
|
|
p = sub.add_parser("where", help="批量定位若干文字")
|
|
p.add_argument("patterns", nargs="+")
|
|
p.set_defaults(func=cmd_where)
|
|
|
|
args = parser.parse_args()
|
|
return args.func(args)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|