Files
MeowOS-For-R3P2/KEY_CONTROL_DESIGN.md
T
MeowOS 4bafdb5d69 fix(keys): 插孔消抖 + 音量 ramp 3s 上限 + 亮度写日志 — 耳机插拔 ADC 幽灵音量键修复
真机实证(meow_20260901_034946.log): 4.4 插入瞬间电气瞬态在 jz_adc_aux(event2)
产生 VOL_UP 幽灵按住, vol_ramp 24%→上限50 (225391 ramp 起→227213 爬满,
紧随 audiod jack changed). 修(限 meow_launcherd/+meow_watchdog/):
① launcher audio.c + watchdog 各自读 /sys/class/switch/{headset,balance}/state
  (节流缓存 1s/500ms, 热路径不每圈读文件), 变化后 800ms 内忽略音量键边沿
  (vol_ramp_begin 不起/在爬 ramp 中止/wd_vol_adj 单步忽略)
② ramp 总时长上限 VOL_RAMP_MAX_MS=3000 兜底防一次幽灵打满(正常长按 24→50 ~1.4s 不伤)
③ write_brightness(val,src) 全 10 调用点带源+逐写 logmsg, 亮度跳上限下次可定位
  (grep 全库: 写 backlight 仅 launcher/watchdog/svc_power/bootmenu, 无确定 255 路径)
宿主: 新 test_vol_ramp_jack 15/15 PASS(单击/长按回归+3s cap+消抖忽略/中止/恢复);
test_wd_fw 17/17 + test_settings_brightness + test_notif_tf PASS; MIPS -Wall -Wextra 0 warning
(顺带修 watchdog 既有 sys/poll.h→poll.h 重定向 warning).
watchdog 已热更设备 /usr/data(baa997ea); launcher 7be1d4eb 待固件. fw_content.conf 已更新.
遗留: SDK meow_ui_input.c 音量键路径需同款消抖(sdk/ 有主未动)
2026-09-01 04:28:10 +08:00

103 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MeowOS 全面按键接管设计(Key Control)
> 状态:已落地(M2.24,2026-08-29,见 §9 落地记录)。目标:**所有按键信号全部由系统接管**,任何界面(launcher 菜单 / MeowAPP / 息屏)都统一响应系统语义。应用侧绝不碰物理键(APPS.md §3.4.1 规范)。本设计是「全面按键接管专项」的蓝本。
---
## 1. 原则
1. **按键是系统资源**,语义由系统组件(launcher / watchdog / 内核)统一决定。
2. **任何界面按键行为一致**:电源=息屏/长按菜单、音量=系统音量、播放/上下曲=活跃媒体会话(现阶段先"抓住"不路由)。
3. **应用绝不映射物理键**:MeowAPP 只接收 SDK 语义事件(tap/swipe/tick),不读 `/dev/input`、不把任何物理键映射成确认/exit/返回/翻页。只有 MeowOS 界面(launcher 菜单/选单/电源菜单)允许处理物理键语义。
## 2. 按键 → 系统行为映射表(所有界面统一)
| 键 | code | 系统行为 | 现阶段 | 依赖 |
|---|---|---|---|---|
| 电源 单击 | 116 | 息屏/亮屏 | ✅ 实现(watchdog 接管) | 无 |
| 电源 长按 3s | 116 | 打开电源菜单(关机/重启/回HibyOS/取消) | ✅ 实现 | 无 |
| 电源 长按 8s | 116 | 强制关机 | ✅ 实现 | 无 |
| 音量 + | 115 | 调系统音量(CS43198 DAC) | ✅ 实现 | 无 |
| 音量 − | 114 | 调系统音量 | ✅ 实现 | 无 |
| 播放/暂停 | 164 | 活跃媒体会话 播放/暂停 | 🔵 **先抓住(不泄漏给应用)** | 阶段D媒体会话 |
| 上一曲 | 165 | 活跃媒体会话 上一曲 | 🔵 **先抓住** | 阶段D媒体会话 |
| 下一曲 | 163 | 活跃媒体会话 下一曲 | 🔵 **先抓住** | 阶段D媒体会话 |
> 🔵 “先抓住”:watchdog 捕获该键信号并**消费掉**(记录日志、暂不执行动作),确保不泄漏给 MeowAPP(防止应用误用/误响应),也不产生"按键被吞"的观感空洞。等阶段 D 媒体会话落地,在**同一点**直接转给活跃会话(无需改键处理层)。
## 3. 实现:统一监听点
**关键**:所有界面的按键语义集中在**一个常驻系统组件**里判断,不分散。
- **launcher 菜单/列表界面**:已有 `run_menu` 主循环读键(音量/电源/播放)。**保留**,作为 MeowOS 界面的键处理。
- **MeowAPP 运行界面**:launcher 卡在 `waitpid(app)`,主循环不跑 → **由 `meow_watchdog` 接管按键**(watchdog fork 出来陪跑 app、读 `/dev/input/event*`)。
- **共同原则**:watchdog 与 launcher 用**同一套按键语义逻辑**(电源单击=息屏、长按=菜单、音量=调音量、播放/上下曲=抓住/路由),从代码层面保证"任何界面一致"。
### watchdog 按键语义(应用运行期,重点新增)
watchdog 主循环(`for(;;)`)加按键轮询(`read /dev/input/event0/event2`):
- **KEY_POWER(116)**:
- 按下计时,≤某阈值单击 → 息屏/亮屏(复用 launcher `meow_panel_off/on`:背光 0 + FBIOBLANK(4) / FBIOBLANK(0)+亮度恢复);
- 按住 ≥3s → 电源菜单(复用 launcher 的电源菜单 UI/逻辑——但 watchdog 是独立进程,需把电源菜单绘制/交互自包含,或经 IPC 通知 launcher);**为避免双进程抢屏,建议:watchdog 把"长按电源"事件经 IPC 上报 launcher,由 launcher 弹电源菜单**(launcher 仍在 waitpid 但可被 eventfd 唤醒处理菜单)。
- 按住 ≥8s → 强制关机(`syscall(SYS_reboot, ...POWER_OFF)`)。
- **KEY_VOLUMEUP(115) / KEY_VOLUMEDOWN(114)** → 调系统音量(复用 launcher 的 `settings_volume_adj` / CS43198 DAC 写路径)。
- **KEY_PLAYPAUSE(164) / KEY_PREVIOUSSONG(165) / KEY_NEXTSONG(163)** → **先抓住**:捕获、logmsg、消费,暂不路由;媒体会话落地后转活跃会话。
- **KEY_PREVIOUS(19)**:`KEY_PREVIOUSSONG` 是 165;19 是另一码(`KEY_PREVIOUSSONG` 统一用 165,见 launcher `DEV_POWER` 注释 event0 含 POWER/PREVIOUS)。
## 4. 电源菜单在应用内如何弹出(关键设计决策)
应用运行时 watchdog 捕获长按电源。电源菜单**由谁画**?两方案:
- **方案 A(推荐)**:watchdog 长按 3s → 写 `/tmp/meowapp_state`/或 SIGUSR1 通知 → **launcher 从 waitpid 被 eventfd 唤醒 → SIGSTOP app → 弹电源菜单**(复用 launcher 现有电源菜单代码,不重复实现)。菜单关闭 → SIGCONT app。
- 方案 B:watchdog 自绘电源菜单(独立实现,重复代码,且与 launcher 抢屏时序复杂)。
**选 A**:电源菜单始终由 launcher 统一绘制(一处实现),watchdog 只负责"检测到长按电源→唤醒 launcher"。这符合"系统接管要统一、不分散"。
## 5. 与应用/将来会话的衔接
- **现阶段**:播放/上下曲"抓住"(消费日志,不路由)。应用拿不到这些键 → 不会误操作。
- **阶段 D**:媒体会话(`MSG_REGISTER svc=media_session` / `MF_PLAYBACK`,见 FRAMEWORK_DESIGN §5/附录 B)落地后,**在 watchdog 抓住键的同一点**直接 `route_to_active_media_session()`。键处理层结构不变,只加路由调用。
## 6. 涉及文件
| 文件 | 改动 |
|---|---|
| `patch_v2/meow_watchdog/meow_watchdog.c` | 主循环加按键轮询:电源(单击息屏/长按菜单/8s关机)、音量(调音量)、播放/上下曲(抓住);长按电源 → 唤醒 launcher |
| `patch_v2/meow_launcherd/app_launcher.c`(`launch_app` waitpid 循环) | 应用运行时(waitpid 中)能被 eventfd 唤醒处理电源菜单;复用现有电源菜单/panel/音量逻辑 |
| `patch_v2/sdk/meow_ui_input.c` | 不接管物理键语义(仅触摸 tap/swipe),排除误读事件1以外的键 |
| `APPS.md §3.4.1` | 已写规范(应用禁映射物理键)——保持 |
| `FRAMEWORK_DESIGN.md` | 阶段 D 媒体会话:播放/上下曲路由到活跃会话(附录 B) |
## 7. 真机验收(用户)
1. 应用内:电源键**单击=息屏、长按 3s=电源菜单、长按 8s=关机**;
2. 应用内:音量 ± = 调音量(状态栏可见);
3. 应用内:播放/上一曲/下一曲**不引起应用任何反应**(被系统抓住);
4. launcher 菜单 / 应用列表:同样电源/音量行为一致;
5. 电源菜单在任何界面都能弹出(含应用内);
6. 息屏后任意键唤醒。
## 8. 依赖与顺序
- **前置**:agent-46(应用输入接管修复,电源键息屏奠基)完成。
- **本轮**:全面按键接管专项(✅ 已落地 M2.24:watchdog 全键接管 + launcher 唤醒弹电源菜单 + 播放键抓住)。
- **下期**:阶段 D 媒体会话 → 播放/上下曲路由。
*本设计为蓝本,实现以代码注释+KEY_CONTROL_DESIGN.md 为准;与 APPS.md §3.4.1、FRAMEWORK_DESIGN §5/附录 B 对齐。*
## 9. 落地记录(M2.24,2026-08-29,MeowOS 0.7.19)
完成项(相对本蓝本):
- ✅ 电源 单击=息屏/亮屏:`meow_watchdog.c handle_power`(沿用 M2.22,短按<3s)。
- ✅ 电源 长按≥3s=电源菜单:`meow_watchdog.c wd_power_tick` 写 `/tmp/meow_power_menu` → `app_launcher.c`(`launch_app` waitpid 循环)消费 → `SIGSTOP app` + 写 `/tmp/meow_power_menu_active` → `power_menu.c show_power_menu()`(launcher 一处绘制)→ 关菜单清标记 → `SIGCONT app`。方案 A。
- ✅ 音量±:`meow_watchdog.c wd_vol_adj` 自实现(写 CS43198 amixer numid=1/2 + 持久化 `/usr/data/meow/settings.conf` 与 launcher 同源);launcher `launch_app` 末尾 `settings_load()` 刷新。
- ✅ 播放/上下曲(164/165/163/19):`meow_watchdog.c` 捕获+日志+消费,不路由;SDK `meow_ui_input.c` 吞噬全部物理键,应用绝不碰。
- ✅ 应用内电源菜单弹出中断恢复:`show_power_menu` 复用(含触摸/音量导航/电源确认/8s 强关/pm_interacted 保护)。
偏差(实现以稳妥为准,记录如下):
1. **8s 强关拆分**:设计给 watchdog,但为避免与菜单内 `pm_interacted` 冲突(用户正点选时被强关抢先),落地为「launcher 菜单内 8s 强关(pm_interacted 保护)+ watchdog 8s 兜底(仅当菜单未接管,即 `/tmp/meow_power_menu_active` 未出现)」。
2. **音量跳步**:watchdog 每按下边沿按 `audio.volume_step` 一步(不做 launcher 的线性渐变);短按与 launcher 菜单一致,长按不连续爬(媒体落地后可补)。launcher 应用返回时 `settings_load()` 同步。
3. **左右滑切屏**:**已落地(M2.81 Now Playing 横划页)**——主界面左滑进 Now Playing 大页;左缘返回手势保留。此处旧注「未实现切换逻辑」作废。
4. **媒体键**:**已落地(M2.81 起路由最近活跃媒体会话)**——播放/上下曲路由到最近活跃媒体会话(MSG_PLAYCTL),无会话时「抓住」不动作。此处旧注「路由待阶段 D」作废。
5. **插孔消抖(2026-09-01,真机日志实证)**:4.4/3.5 插拔的电气瞬态在音量键 ADC(jz_adc_aux,event2)上产生 VOL_UP 幽灵按住,launcher vol_ramp 曾从 24% 一路爬到上限 50(日志 225391 ramp 起 → 227213 爬满 → 紧随 audiod「jack changed」)。修:launcher 与 watchdog 音量键处理统一读 `/sys/class/switch/{headset,balance}/state`(节流读缓存:launcher 1s / watchdog 500ms,绝不在热路径每圈读文件),插孔状态变化后 **800ms 内忽略音量键边沿**(vol_ramp_begin 不起、在爬 ramp 中止、watchdog 单步忽略);另有 **ramp 总时长上限 VOL_RAMP_MAX_MS=3000** 兜底,防任何「持续按住」假象一次打满。SDK 输入层(框架 App 前台时的音量路径)需同款消抖——sdk/ 归其主,另行落地。
真机验收要点(§7):应用内电源单击/长按菜单/8s 强关、音量±调音量、播放/上下曲无反应(被抓住)、launcher 菜单同样一致、电源菜单任何界面可弹(含应用内)、息屏后任意键唤醒。