#!/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())