惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Project Zero
Project Zero
Y
Y Combinator Blog
雷峰网
雷峰网
Last Week in AI
Last Week in AI
人人都是产品经理
人人都是产品经理
F
Fortinet All Blogs
Microsoft Azure Blog
Microsoft Azure Blog
有赞技术团队
有赞技术团队
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - Franky
博客园 - 聂微东
S
SegmentFault 最新的问题
Engineering at Meta
Engineering at Meta
罗磊的独立博客
M
MIT News - Artificial intelligence
B
Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
大猫的无限游戏
大猫的无限游戏
V
V2EX
I
InfoQ
The Cloudflare Blog
Cloudbric
Cloudbric
Stack Overflow Blog
Stack Overflow Blog
V
Vulnerabilities – Threatpost
博客园_首页
Google DeepMind News
Google DeepMind News
Jina AI
Jina AI
T
The Exploit Database - CXSecurity.com
宝玉的分享
宝玉的分享
H
Hackread – Cybersecurity News, Data Breaches, AI and More
The GitHub Blog
The GitHub Blog
The Register - Security
The Register - Security
美团技术团队
K
Kaspersky official blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tor Project blog
P
Privacy International News Feed
P
Privacy & Cybersecurity Law Blog
G
GRAHAM CLULEY
博客园 - 三生石上(FineUI控件)
Cyberwarzone
Cyberwarzone
Vercel News
Vercel News
Cisco Talos Blog
Cisco Talos Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Cisco Blogs
G
Google Developers Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
A
Arctic Wolf
MongoDB | Blog
MongoDB | Blog

博客园 - 我才是银古

第16章:常见问题、排错与最佳实践 第15章:扩展生态、MCAD 与外部集成 第12章:实战案例:机械结构与 3D 打印零件 第14章:构建、测试、调试与贡献流程 第13章:OpenSCAD 源码架构与核心执行流程 第11章:预览、渲染、网格精度与性能优化 第09章:列表推导、递归与算法建模 第08章:参数化零件库与复用设计 第10章:导入导出、命令行与自动化 第06章:CSG 布尔建模方法 第07章:二维图形、拉伸、旋转与投影 第05章:基础几何、坐标系与变换 第04章:参数、变量、函数、模块与作用域 OpenSCAD 教程目录 第03章:OpenSCAD 语言基础 第02章:安装、环境配置与开发工作流 第01章:OpenSCAD 项目全景与学习路线 第02章:源码获取、编译与开发环境配置 第01章:OCCT项目全景与学习路线 第18章:二次开发实战与综合案例 第18章:综合实战案例 第17章:数据交换与协同 第16章:源码架构与二次开发 第15章:插件与自定义工作台开发 第14章:Python脚本宏与自动化 第13章:FEM仿真分析 第12章:CAM数控加工 第11章:SurfaceMesh与逆向工程 第10章:Draft二维绘图与BIM建筑 第09章:工程图TechDraw 第07章:参数化表达式与Spreadsheet 第08章:装配设计Assembly 第06章:Part工作台与几何内核 第05章:PartDesign实体特征建模 第04章:草图Sketcher约束建模 第02章:安装版本与工作环境配置 第03章:界面工作台与基础操作 第01章:项目全景与学习路线 第十二章:插件开发、研究功能与最佳实践 第十章:定时任务与自动化(Cron) 第七章:技能、记忆与自学习闭环 第八章:MCP 集成与上下文文件 第六章:工具系统与终端后端 第五章:模型供应商与配置体系 Hermes Agent 教程目录 第十一章:语音、视觉、浏览器与子代理协作 第四章:CLI/TUI 与会话管理 第十二章:学习路线、实战方案与最佳实践 第十一章:源码结构、开发调试与插件开发 第十章:自动化、远程访问、日志与排障 第九章:Control UI、节点、Canvas 与语音能力 第七章:工具、技能、插件与能力扩展 第八章:安全模型、访问控制与沙箱实践 第六章:Agent 工作区、会话与多智能体路由 第五章:多通道消息接入与聊天平台配置 第四章:配置体系、模型接入与认证管理 第三章:Gateway 架构、协议与运行机制 第二章:安装、环境准备与快速上手 第一章:OpenClaw 项目概览与核心定位 oh-my-openagent 教程目录 09-命令模型回退与配置参考 10-实战案例最佳实践与故障排除 05-工作模式-Ultrawork-Prometheus-Atlas 08-Hooks与MCP系统 06-Category与Skill系统 07-核心工具链 04-智能体全景详解 03-安装与环境配置 02-整体架构与多模型编排机制 01-项目简介与核心理念 01-项目概览与学习路线 02-安装部署与工具适配 03-Skill机制与using-superpowers 05-TDD系统化调试与完成前验证 04-需求澄清方案设计与计划编写 07-并行智能体子智能体与Git-Worktree 第六章:代码审查、反馈处理与分支收尾 08-中国特色Skills与本土团队落地 09-MCP构建工作流执行与自定义Skill 第23章:FreeCAD-Python-API Clipper2 C# 源码解读教程 第19章:PolyTree 多边形树结构 第20章:实际应用与最佳实践 第18章:Minkowski 和与差 第17章:RectClip 矩形裁剪优化 第16章:ClipperOffset 偏移类详解 第15章:填充规则详解 第14章:布尔运算执行流程 第13章:ClipperD 浮点裁剪类 第11章:OutRec 与 OutPt 输出结构 第9章:Active 活动边结构 第10章:Vertex 顶点与 LocalMinima 局部极小值 第12章:Clipper64 裁剪类详解 第7章:高精度运算与128位整数 第8章:ClipperBase 基类详解 第5章:枚举类型与常量定义 第6章:InternalClipper 内部工具类 第2章:核心数据结构 - Point64、PointD 第3章:路径与多边形表示 - Path64、PathD、Paths64、PathsD 第4章:矩形边界 - Rect64、RectD
第10章 - 进程与窗口管理
我才是银古 · 2026-06-24 · via 博客园 - 我才是银古

第10章 - 进程与窗口管理

真实的自动化往往需要面向“某个具体的应用程序”:找到它的进程、激活它的窗口、向它发送输入、读取它的标题,甚至在必要时结束它。RobotGo 提供了一组进程与窗口管理函数来满足这些需求。本章系统讲解进程查找、窗口激活、定向输入、窗口信息读取与系统对话框。

10.1 进程查找

10.1.1 按名称查找进程 ID:FindIds

FindIds 根据进程名(支持部分匹配)查找所有匹配的进程 PID:

fpid, err := robotgo.FindIds("Google")
if err == nil {
    fmt.Println("找到的 PID 列表:", fpid)
}

返回的是一个 PID 切片,因为同名进程可能有多个(例如浏览器的多个进程)。

10.1.2 获取所有进程:Process

Process 返回系统当前所有进程的信息列表(包含 PID 与名称等),可用于自行遍历筛选:

ps, err := robotgo.Process()
if err == nil {
    for _, p := range ps {
        fmt.Println(p.Pid, p.Name)
    }
}

10.1.3 判断进程是否存在:PidExists

exists, err := robotgo.PidExists(1234)
if err == nil && exists {
    fmt.Println("进程 1234 存在")
}

10.1.4 获取进程名:FindName / FindNames

name, err := robotgo.FindName(1234)
if err == nil {
    fmt.Println("PID 1234 的进程名:", name)
}

names, err := robotgo.FindNames()
if err == nil {
    fmt.Println("所有进程名:", names)
}

10.2 窗口激活

找到目标进程后,常常需要把它的窗口切换到前台(激活),以便后续输入。

10.2.1 按 PID 激活:ActivePid

fpid, err := robotgo.FindIds("Google")
if err == nil && len(fpid) > 0 {
    robotgo.ActivePid(fpid[0]) // 激活第一个匹配进程的窗口
}

10.2.2 按名称激活:ActiveName

ActiveName 是更便捷的一步到位写法,内部会先按名称找进程再激活:

robotgo.ActiveName("chrome")

激活窗口后,后续的 Type / KeyTap / Click 等操作就会作用于该窗口(因为它现在是前台焦点窗口)。

10.3 向特定窗口/进程发送输入

RobotGo 的一些输入函数支持额外的 PID 参数,可以把输入定向发送给指定进程的窗口,而不依赖“当前焦点”。这在后台操作、并发控制多个窗口时很有用:

fpid, err := robotgo.FindIds("Google")
if err == nil && len(fpid) > 0 {
    pid := fpid[0]

    // 向指定进程输入文本
    robotgo.Type("Hi galaxy!", pid)

    // 向指定进程发送组合键(Cmd + A)
    robotgo.KeyTap("a", pid, "cmd")

    // 向指定进程切换按键状态
    robotgo.KeyToggle("a", pid)
    robotgo.KeyToggle("a", pid, "up")
}

注意这些“带 PID 的输入”在不同平台上的支持程度和行为可能有所不同,建议在目标平台实测。对于大多数场景,更稳妥的做法仍然是“先 ActivePid 激活窗口,再做普通输入”。

10.4 窗口信息读取

10.4.1 获取窗口标题:GetTitle

title := robotgo.GetTitle()
fmt.Println("当前活动窗口标题:", title)

GetTitle 默认返回当前活动窗口的标题,也可以传入 PID 获取指定进程窗口的标题。

10.4.2 获取窗口位置与尺寸

RobotGo 提供了获取活动窗口边界的函数,例如 GetBounds,可用于读取窗口的位置与大小(具体可用函数以你所用的 RobotGo 版本为准):

x, y, w, h := robotgo.GetBounds(pid)
fmt.Printf("窗口位置(%d,%d) 尺寸 %dx%d\n", x, y, w, h)

结合窗口边界,可以把“相对窗口的坐标”换算为“屏幕绝对坐标”,让点击操作不依赖窗口在屏幕上的具体位置。

10.5 结束进程:Kill

Kill 用于结束指定 PID 的进程:

exists, err := robotgo.PidExists(100)
if err == nil && exists {
    robotgo.Kill(100)
    fmt.Println("已结束进程 100")
}

谨慎使用:Kill 会强制结束进程,可能导致目标程序未保存的数据丢失。在自动化脚本中调用前,请确认 PID 正确、确实需要结束该进程。

10.6 系统对话框:Alert

虽然不属于“窗口管理”,但 Alert 能弹出原生系统对话框,常用于脚本与用户的简单交互或调试提示:

ok := robotgo.Alert("标题", "提示内容")
if ok {
    fmt.Println("用户点击了确定")
} else {
    fmt.Println("用户点击了取消")
}

Alert 返回布尔值表示用户点了确定还是取消,可据此控制脚本流程。

10.7 完整示例

下面是官方窗口示例的整理版,串联了进程查找、定向输入、激活、判断存在、结束进程、弹框与读取标题:

package main

import (
    "fmt"

    "github.com/go-vgo/robotgo"
)

func main() {
    fpid, err := robotgo.FindIds("Google")
    if err == nil {
        fmt.Println("pids:", fpid)

        if len(fpid) > 0 {
            pid := fpid[0]

            // 向指定进程发送输入
            robotgo.Type("Hi galaxy!", pid)
            robotgo.KeyTap("a", pid, "cmd")
            robotgo.KeyToggle("a", pid)
            robotgo.KeyToggle("a", pid, "up")

            // 激活窗口
            robotgo.ActivePid(pid)

            // 结束进程(演示,谨慎使用)
            robotgo.Kill(pid)
        }
    }

    // 按名称激活
    robotgo.ActiveName("chrome")

    // 判断进程是否存在
    isExist, err := robotgo.PidExists(100)
    if err == nil && isExist {
        fmt.Println("pid 存在:", isExist)
        robotgo.Kill(100)
    }

    // 弹出对话框
    abool := robotgo.Alert("test", "robotgo")
    if abool {
        fmt.Println("ok")
    }

    // 读取窗口标题
    title := robotgo.GetTitle()
    fmt.Println("title:", title)
}

10.8 实战工作流:定位并操作目标应用

把本章能力串成一个典型工作流:

func operateApp(appName string) error {
    // 1. 查找进程
    pids, err := robotgo.FindIds(appName)
    if err != nil || len(pids) == 0 {
        return fmt.Errorf("未找到应用: %s", appName)
    }

    // 2. 激活窗口
    robotgo.ActivePid(pids[0])
    robotgo.MilliSleep(300) // 等待窗口切到前台

    // 3. 确认标题
    fmt.Println("当前窗口:", robotgo.GetTitle())

    // 4. 执行操作
    robotgo.KeyTap("l", "ctrl") // 例如浏览器定位地址栏
    robotgo.Type("https://github.com/go-vgo/robotgo")
    robotgo.KeyTap("enter")
    return nil
}

10.9 实战技巧与注意事项

  1. 优先“激活 + 普通输入”:相比带 PID 的定向输入,先 ActivePid 再做普通操作通常更稳定、跨平台兼容性更好。
  2. 激活后留延时:窗口从后台切到前台需要时间,ActivePid 后加 MilliSleep 再操作。
  3. 同名进程要甄别FindIds 可能返回多个 PID,必要时结合 GetTitle、进程信息进一步确认哪个才是目标窗口。
  4. Kill 要谨慎:强制结束进程有数据丢失风险,务必确认 PID。
  5. 平台差异:进程与窗口相关 API 在 Windows / macOS / Linux 上的行为可能存在差异,关键逻辑请在目标平台实测验证。

10.10 小结

本章我们掌握了 RobotGo 的进程与窗口管理:用 FindIds / Process / PidExists / FindName 查找进程,用 ActivePid / ActiveName 激活窗口,向指定进程定向发送输入,用 GetTitle / GetBounds 读取窗口信息,用 Kill 结束进程,以及用 Alert 弹出系统对话框。我们还梳理了“定位并操作目标应用”的实战工作流。下一章将进入一个全新维度——全局事件监听,让程序能够“感知”用户的键盘鼠标动作。