08 keyflow 按键模块集成 Skill 设计方案
版本:v1.0.0
状态:已实现(Python CLI 工具,约 70% 设计覆盖率)
适用范围:C 语言嵌入式工程(STM32 / 51 / ESP32 / Linux / 裸机)
实现路径:.trae/skills/keyflow-integrator/keyflow_integrator.py(1019 行)
1. Skill 定位与目标
Skill 名称:keyflow-integrator
核心能力:让 Agent 在任意嵌入式/C 工程中,一键完成:
- Install(安装) — 将 keyflow 的核心代码作为子模块/拷贝集成到项目
- Configure(配置) — 选择硬件平台(STM32 / 51 / ESP32 / Linux / 裸机)、分配 GPIO 引脚
- Integrate(对接) — 生成按键配置表、回调函数、扫描周期配置,并与业务逻辑对接
- Verify(验证) — 生成最小可运行示例/测试代码,编译并输出验证报告
设计原则:
- ✅ 零破坏性:不会删除/重写用户代码,仅在必要处追加最小补丁
- ✅ 可回滚:所有修改前自动备份关键文件为
.bak - ✅ 显式决策:存在歧义时(如引脚选择、按键数量),必须通过对话明确而非猜测
- ✅ 幂等:同一项目多次执行不产生重复代码
2. 输入 / 输出契约
2.1 用户输入(自然语言或结构化描述)
project:
path: /absolute/path/to/project # 用户工程根目录
build_system: make|cmake|keil|iar|other # 构建系统
platform: stm32|51|esp32|linux|baremetal
compiler: armcc|gcc|sdcc|other
button_count: <N> # 按键数量
button_list: # (可选)按键描述列表
- name: "KEY_OK"
pin: "GPIOA,5" # 或自定义描述
active_level: low # low / high
debounce_ms: 15
long_press_ms: 1000
event_handler: "on_ok_pressed" # 业务回调函数名
- ...
scan_period_ms: 10 # 主循环扫描周期
features: # 需要启用的扩展模块
- matrix_keypad: {rows: 4, cols: 4} # (可选)矩阵键盘
- exti_driven # (可选)中断驱动
- event_queue # (可选)事件队列
- combo_keys # (可选)组合键
integration_style: table_driven # table_driven(推荐) | manual
code_output_dir: src/app/buttons # 生成文件输出目录
business_hooks: # 业务层回调映射
- event: PRESSED
handler: "app_on_button_pressed(idx)"
- event: LONG_PRESS
handler: "app_on_button_long_press(idx)"
2.2 Skill 输出
files_created:
- /project/src/app/buttons/keyflow_config.h # 按键配置表 + 回调声明
- /project/src/app/buttons/keyflow_integration.c # glue code(初始化 + 扫描循环)
- /project/src/app/buttons/keyflow_port.c # 平台端口实现(GPIO 读写)
- /project/src/app/buttons/README.md # 说明文档(中文,自动生成)
files_modified:
- Makefile 或 CMakeLists.txt # 追加 keyflow 源码路径
- main.c / xxx_init.c # 追加初始化调用
verification:
- build_status: success|failed
- test_output: "7/7 tests passed"
3. 核心流程设计(5 阶段)
阶段 1:项目探查(Exploration)
目标:在不修改任何文件的前提下,识别工程结构与约定。
探查内容:
| 探查项 | 探查方法 | 示例 |
|---|---|---|
| 构建系统 | ls *.c Makefile CMakeLists.txt project.uvprojx |
识别为 Make / CMake / Keil |
| 源码目录结构 | find . -name "*.c" -type d | head -30 |
src/ app/ main hw/ 等 |
| 头文件目录 | 定位 #include 模式 |
#include "stm32f1xx_hal.h" / #include "main.h" |
| GPIO HAL 接口类型 | grep -rn "HAL_GPIO|digitalRead|P1\s*&\s*(1|PORT_WritePin" src 等 |
判断 STM32 HAL / Arduino / 51 / ESP-IDF / Linux sysfs |
| 主循环入口 | grep -n "while\s*(\s*1\s*)|main\s*(" src/main* |
定位扫描代码放入何处 |
| 已有按键代码 | grep -rn "button|key|按键" src/ |
判断是否需要迁移已有按键 |
| 编译器/平台 | 从 Makefile / CMakeLists.txt 中提取 | arm-none-eabi-gcc / sdcc / gcc |
输出:结构化 JSON project_profile.json(仅内存使用,不写文件)
阶段 2:安装(Installation)
目标:把 keyflow 源码按工程约定放置。
安装策略(二选一):
| 策略 | 适用场景 | 操作 |
|---|---|---|
| A. Git 子模块 | Git 仓库已初始化 | git submodule add keyflow 仓库到 third_party/keyflow/ |
| B. 文件拷贝 | 非 Git / 简单工程 | 拷贝 include/button/*.h 和 src/button/*.c 到 third_party/keyflow/ |
安装产物位置约定:
project/
├── third_party/
│ └── keyflow/ ← keyflow 完整仓库或仅需要的文件
│ ├── include/button/*.h
│ └── src/button/*.c
└── src/app/buttons/ ← Skill 生成的 glue code(见阶段 4)
CMake/Makefile 修改策略:
- CMake 工程:在顶层 CMakeLists.txt 追加
add_subdirectory(third_party/keyflow/src/button)并target_link_libraries(your_app keyflow::button)(demo 可选项,与 keyflow 当前项目类似) - Makefile 工程:定义
BUTTON_DIR := third_party/keyflow,在SRCS += ...追加$(BUTTON_DIR)/src/button/*.c,并CFLAGS += -I$(BUTTON_DIR)/include - Keil/IAR:基于
.uvprojx/.ewp添加源文件条目(XML 解析/追加)
阶段 3:配置(Configuration)
目标:根据探查结果,生成 keyflow_port.c。
平台判定规则:
| 平台 | 判定条件 | 生成内容 |
|---|---|---|
| STM32 | 包含 stm32fxxx_hal.h 头文件 |
ButtonPort_ReadPin 实现 → HAL_GPIO_ReadPin;GetTickMs → HAL_GetTick |
| 51 单片机 | 包含 reg51.h / stc*.h,且编译器为 sdcc/keil c51 |
P1 & (1 << pin) 方式;GetTickMs → 基于定时器 systick |
| ESP32 | 包含 freertos/FreeRTOS.h / driver/gpio.h |
gpio_get_level(pin);GetTickMs → xTaskGetTickCount * portTICK_PERIOD_MS |
| Linux | 包含 unistd.h 且无 MCU 头文件 |
Linux sysfs GPIO 或 /dev/gpiochipN |
| 裸机 | 以上均不满足 | 生成模板 + extern uint32_t SystemTick; |
引脚抽象约定:
引脚编码 port_pin_code 为 uint16_t,高 8 位为 port(如 A=0, B=1, …),低 8 位为 pin 编号。
阶段 4:对接(Integration)
核心生成策略:
A. 生成配置表(keyflow_config.h + keyflow_integration.c)
/* 示例(STM32) */
static ButtonManager g_keyflow_mgr;
/* 按键配置表 — 从用户输入的 button_list 转换而成 */
static const KeyflowEntry s_keyflow_keys[] = {
{
.cfg = {
.pin = KEYFLOW_MAKE_PIN(KEYFLOW_PORT_A, 5), /* GPIOA,5 */
.active_level = 0, /* 低电平有效 */
.debounce_ms = 15,
.release_debounce_ms = 15,
.long_press_ms = 1000,
.double_click_ms = 250,
.stable_cnt_required = 2,
.long_press_repeat_ms = 0,
},
.name = "KEY_OK",
.on_pressed = app_on_key_ok_pressed,
.on_long_press = app_on_key_ok_long_press,
.on_clicked = app_on_key_ok_clicked,
},
/* ... more keys ... */
};
/* 统一事件分发回调 */
static void keyflow_event_cb(Button *btn, ButtonEventType ev, void *ud) {
const KeyflowEntry *entry = (const KeyflowEntry *)ud;
switch (ev) {
case BUTTON_EVENT_PRESSED:
if (entry->on_pressed) entry->on_pressed(entry->idx);
break;
case BUTTON_EVENT_LONG_PRESS:
if (entry->on_long_press) entry->on_long_press(entry->idx);
break;
/* ... other events ... */
}
}
/* 初始化 */
void keyflow_init(void) {
ButtonManager_Init(&g_keyflow_mgr);
for (int i = 0; i < ARRAY_SIZE(s_keyflow_keys); ++i) {
ButtonManager_AddButton(&g_keyflow_mgr,
s_keyflow_keys[i].cfg,
keyflow_event_cb,
&s_keyflow_keys[i]);
}
}
/* 主循环扫描 — 用户在主循环调用 */
void keyflow_task(void) {
ButtonManager_UpdateAuto(&g_keyflow_mgr);
}
B. 矩阵键盘 / 中断驱动 / 事件队列 / 组合键
若用户在 features 中声明启用,分别生成:
| 功能 | 生成文件 | 核心内容 |
|---|---|---|
| 矩阵键盘 | keyflow_matrix.c |
MatrixKeyScanner 初始化 + MatrixKey_Scan 在扫描任务内调用 |
| 中断驱动 | keyflow_exti.c |
ExtiButton_OnInterrupt() 在 EXTI ISR 中调用,ExtiButton_Dispatch() 在主循环调用 |
| 事件队列 | keyflow_queue.c |
ButtonEventQueue_Push 回调 + 主循环 ButtonEventQueue_Pop |
| 组合键 | keyflow_combo.c |
ComboKeyDetector 初始化 + 修饰键掩码匹配表 |
C. 业务层对接
在 business_hooks 中列出的业务函数,生成弱符号(__attribute__((weak)))或 extern 声明,让业务层自行实现:
/* keyflow_integration.h — 业务层需实现的回调 */
extern void app_on_key_ok_pressed(uint8_t idx);
extern void app_on_key_ok_long_press(uint8_t idx);
/* ... */
阶段 5:验证(Verification)
验证步骤:
- 生成最小可运行示例
keyflow_demo.c— 单按键 + 长按连发测试 - 构建验证:执行用户项目的构建命令,捕获错误并仅打印,不修改非必要代码
- 静态检查:
gcc -Wall -Wextra -fsyntax-only语法检查(不链接) - 日志输出验证报告:
keyflow_integration_report.md— 中文,列出:按键数、事件类型、回调函数、编译状态、测试输出
3.6 实现状态对照
| 设计要求 | 实现状态 | 说明 |
|---|---|---|
| Phase 1: 项目探查 | ✅ 完全实现 | explore_project() 扫描构建系统/平台/GPIO HAL/main 入口 |
| Phase 2: 源码安装 | ✅ 实现 | 支持 copy-local 和 git-submodule 两种方式 |
| Phase 3: 端口生成 | ✅ 完全实现 | 5 个平台模板(STM32/51/ESP32/Linux/baremetal) |
| Phase 4a: 配置表生成 | ✅ 完全实现 | 动态生成按键配置表 + 弱符号回调声明 |
| Phase 4b: 集成代码 | ✅ 完全实现 | 模板包含 init + 循环注册 + 统一事件分发 |
| Phase 4c: 扩展模块 | ✅ 完全实现 | matrix/exti/queue/combo 4 个独立模板 |
| Phase 4d: Demo 示例 | ✅ 完全实现 | mock 端口注入 + 短按/长按自测试 |
| Phase 5: 编译验证 | ⚠️ 部分实现 | Linux/baremetal 执行 gcc 语法检查,其他平台仅文件检查 |
| Phase 0: Git 分支隔离 | ✅ 完全实现 | 自动创建 feature 分支,失败可回滚 |
| CMake/Makefile 修改 | ❌ 未实现 | 需用户手动将生成的 .c 文件添加到编译列表 |
| main.c 注入调用 | ❌ 未实现 | 需用户手动在 main 中添加 keyflow_init() 和 keyflow_task() |
| .bak 备份策略 | ❌ 未实现 | 改用 Git 分支隔离替代 |
| 交互式模式 | ❌ 未实现 | 当前仅支持命令行参数 |
| 幂等性检测 | ⚠️ 部分实现 | 检测已存在目录时警告并覆盖,但不检测重复注册 |
当前版本使用须知:集成完成后,用户需手动完成两步:
- 将
src/third_party/keyflow/下的.c文件添加到编译系统(CMakeLists.txt / Makefile) - 在 main 函数中调用
keyflow_init()和keyflow_task()
3.7 实际文件结构
.trae/skills/keyflow-integrator/
├── SKILL.md # Skill 使用说明
├── keyflow_integrator.py # 核心实现(1019 行)
└── templates/
├── keyflow_config_template.h # 按键配置表模板
├── keyflow_integration_template.c # init + task 集成模板
├── keyflow_port_stm32_template.c # STM32 HAL 端口
├── keyflow_port_51_template.c # 51 单片机端口
├── keyflow_port_esp32_template.c # ESP32 IDF 端口
├── keyflow_port_linux_template.c # Linux sysfs GPIO 端口
├── keyflow_port_baremetal_template.c # 裸机/自定义端口
├── keyflow_matrix_template.c # 矩阵键盘扩展
├── keyflow_exti_template.c # 中断驱动扩展
├── keyflow_queue_template.c # 事件队列扩展
├── keyflow_combo_template.c # 组合键/序列键扩展
└── keyflow_demo_template.c # 最小可运行示例
4. 安全性与幂等性设计
| 风险 | 防护策略 |
|---|---|
| 重复安装 | third_party/keyflow/ 已存在时跳过安装,仅提示更新 |
| 重复生成 | src/app/buttons/ 已存在时先 .bak 备份再覆盖,或提示用户选择覆盖/跳过 |
| 破坏已有按键实现 | 先扫描 grep -rn "button|key",若已存在按键代码,不删除仅追加补丁:把新实现放在独立目录,并在 README 中说明迁移建议 |
| 路径不完整 | 所有路径相对 project.path |
| Git 未初始化 | B 策略(文件拷贝)自动降级 |
| 平台识别失败 | 生成模板占位符代码 + 在验证阶段提供多平台模板,让用户手动选择 |
| 业务回调不存在 | 弱符号 + 编译链接警告,验证阶段输出缺失列表 |
5. 示例运行流程(伪代码)
┌────────────────────────────────────────────┐
│ 用户输入:"把 keyflow 装到 /my_project" │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ Phase 1: 项目探查(read-only) │
│ - ls /my_project │
│ - grep 构建系统 / GPIO 头文件 / 按键关键字 │
│ 输出: project_profile = { │
│ build_system: cmake, │
│ platform: stm32, │
│ compiler: arm-none-eabi-gcc │
│ } │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ Phase 2: 安装 keyflow │
│ - git submodule add keyflow 到 third_party/│
│ 或: cp keyflow/include/button/*.{h,c} │
│ - CMakeLists.txt 追加 add_subdirectory │
│ 或: Makefile 追加 BUTTON_DIR + CFLAGS │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ Phase 3: 生成端口 │
│ - 生成 keyflow_port.c(基于 platform) │
│ - 生成 keyflow_config.h(按键配置表) │
│ - 生成 keyflow_integration.c(主循环扫描) │
│ - 生成 keyflow_<feature>.c(扩展模块) │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ Phase 4: 业务对接 │
│ - 生成 business_hooks → 弱符号 extern │
│ - 让用户实现业务回调 │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ Phase 5: 验证 │
│ - cmake --build . │
│ - 语法检查 │
│ - 生成验证报告 keyflow_integration_report.md │
└────────────────────────────────────────────┘
│
▼
┌────────────────┐
│ 完成! │
└────────────────┘
6. 文件命名约定(与当前 keyflow 项目保持一致)
| 生成文件 | 路径(相对 project.path) | 说明 |
|---|---|---|
keyflow_config.h |
src/app/buttons/ |
按键配置表 + 回调声明 |
keyflow_port.c |
src/app/buttons/ |
GPIO 读写 + 时间戳 |
keyflow_integration.c |
src/app/buttons/ |
初始化 + 主循环扫描 |
keyflow_demo.c |
src/app/buttons/ |
最小可运行示例 |
keyflow_integration_report.md |
src/app/buttons/ |
中文验证报告 |
7. 与当前 keyflow 项目的接口映射
| keyflow API | Skill 生成的 glue code |
|---|---|
ButtonConfig |
keyflow_config.h → 结构体数组 |
ButtonManager_Init |
keyflow_integration.c → keyflow_init() |
ButtonManager_AddButton |
keyflow_integration.c → 循环注册 |
ButtonManager_UpdateAuto |
keyflow_task() |
MatrixKey_Init / Scan |
keyflow_matrix.c → 矩阵键盘 |
ExtiButton_OnInterrupt / Dispatch |
keyflow_exti.c → 中断驱动 |
ButtonEventQueue_Init / Push / Pop |
keyflow_queue.c → 事件队列 |
ComboKey_Init / Detect |
keyflow_combo.c → 组合键 / 序列键 |
8. 错误处理与用户交互策略
| 场景 | Skill 行为 | 对用户的反馈 |
|---|---|---|
| 无法识别构建系统 | 停止并询问 | “你的工程使用什么构建系统?(make/cmake/keil/…)” |
| 无法识别平台 | 停止并询问 | “你的目标硬件平台是?(stm32/51/esp32/linux/baremetal)” |
| button_list 为空 | 询问并生成参考 | “请描述你的按键列表(名称/引脚/有效电平/消抖/长按阈值/回调函数名)”,或默认 3 按键示例 |
| GPIO 语法无法解析 | 把 pin 标记为"需手动确认" | 在报告中列出所有"需手动确认的 pin 映射" |
| 编译失败 | 不修改代码,打印完整编译日志 | “编译失败,错误日志已输出” |
9. 回滚策略
-
每次执行前自动:
- 备份
CMakeLists.txt/Makefile→.bak - 备份
src/app/buttons/若已存在 →.bak/ - 记录操作日志
keyflow_integration.log
- 备份
-
回滚命令(Skill 可执行):若用户说"撤销刚才的操作",执行
git checkout -- <files>或mv .bak文件恢复
10. Skill 元数据
skill:
name: keyflow-integrator
version: 1.0.0
description: 将 keyflow 按键模块安装到目标 C/嵌入式工程,并生成配置表、端口抽象、业务对接代码与验证报告
inputs:
- 项目路径(绝对路径)
- 构建系统(make/cmake/keil/iar/other)
- 平台(stm32/51/esp32/linux/baremetal)
- 按键数量 + 按键描述列表(可选)
- 启用的扩展功能(矩阵/中断/事件队列/组合键)
- 业务回调函数映射(可选)
outputs:
- third_party/keyflow/ 源码
- src/app/buttons/*.{h,c} 业务对接代码
- 修改后的构建文件(CMake/Makefile)
- 中文集成报告 keyflow_integration_report.md
11. 与 keyflow 当前代码的关联
Skill 在生成代码时,严格遵循 keyflow 当前项目中 include/button/button.h 的 API 契约,不做任何 API 扩展或修改。生成的 glue code 仅做三件事:
- 调用现有 API
- 把业务层的业务逻辑通过回调与 keyflow 事件分发器连接
- 为目标平台实现
ButtonPort_*的具体实现
实际实现中的关键映射:
| keyflow API | 模板中使用方式 | 模板文件 |
|---|---|---|
ButtonConfig |
keyflow_config_template.h → 结构体数组 |
keyflow_config_template.h |
ButtonManager_Init |
keyflow_integration_template.c → keyflow_init() |
keyflow_integration_template.c |
ButtonManager_AddButton |
循环注册 + keyflow_event_cb 统一分发 |
keyflow_integration_template.c |
ButtonManager_UpdateAuto |
keyflow_task() 中调用 |
keyflow_integration_template.c |
ButtonPort_ReadPin/WritePin/GetTickMs |
5 个平台模板分别实现 | keyflow_port_*.c |
MatrixKey_* / ExtiButton_* / ButtonEventQueue_* / ComboKey_* |
4 个扩展模块独立实现 | keyflow_*_template.c |
12. 设计确认记录
以下为设计阶段提出的待确认事项及其最终处理结果:
| # | 待确认事项 | 最终决策 | 实现情况 |
|---|---|---|---|
| 1 | Skill 名称 | keyflow-integrator ✅ |
已采用 |
| 2 | 生成文件位置 | src/third_party/keyflow/(源码)+ src/app/buttons/(glue code)✅ |
已调整路径约定 |
| 3 | 业务回调策略 | 弱符号 extern 声明 ✅ | 已实现 |
| 4 | 扩展模块策略 | 用户声明时才生成 ✅ | 已实现(4 个独立模板) |
| 5 | 验证深度 | 仅编译 + 日志输出 ✅ | 已实现(gcc 语法检查) |
| 6 | 备份策略 | Git 分支隔离替代 .bak ✅ |
已实现(feature/keyflow-integration-<timestamp>) |
尚未实现的设计项(待后续版本补充):
- CMake/Makefile 自动修改
- main.c 自动注入
keyflow_init()/keyflow_task() - 交互式参数收集模式
项目仓库
- GitCode 仓库:https://gitcode.com/AZE-BlackCore/keyflow
免责声明
本文内容仅作为技术研究与学习交流之用,不构成任何形式的产品设计建议、电子工程建议或商业推荐。文中涉及的代码片段、状态机模型、消抖策略等技术方案,基于特定嵌入式场景与硬件条件设计,直接用于生产环境前请务必进行充分的测试与验证。
使用本文内容所导致的任何直接或间接后果(包括但不限于设备损坏、数据丢失、商业损失等),作者及 AZE-BlackCore 不承担任何责任。 请根据你的实际项目需求,结合硬件手册、行业规范与最佳实践进行独立判断和决策。
版权声明:本文版权归 AZE-BlackCore 所有,转载请注明出处。封面与示意图由 AI 生成,仅供示意参考。
更多推荐


所有评论(0)