feat: M6.44+M6.45 收编 — 真机 0.8.45 现场保全(reader章节/key_router按键路由/WiFi连接修复/ncm bench+IME修复)

脏工作区现场收编:devdocs/local/m6_44_45_dirty_tracked.patch(46 个已跟踪文本文件,
+3090/-585, 已对 M6.43 基线干净适配) + m6_44_45_untracked_src.tar.gz 中 patch_v2/ 下
13 个新增源文件, 合成单个提交, 内容与容器工作树(R3ProII/patch_v2)逐字节一致。

- reader 章节: 新增 core/rdchapter.{h,c} — TXT 章节规范解析器, 扫描 512KB 码位对齐段文件
  逐段流式识别标题行(行首缩进≤4/显示宽≤40/行内标点≤1 三重约束防误判), 输出标题+全书字符
  偏移+段号/段内偏移+阿拉伯章号(中文数字归一), 首章前内容归"卷首"; book/reader/rdenc/
  rdlayout/settings 接入章节跳转与进度锚点, 附 chapter_smoke/turn_repro/build_turn_repro.sh
- key_router 按键路由: 新增 meow_launcherd/key_router.{h,c} — launcher-UI 页物理键统一路由
  (P1 仅音量键), 把读取边沿+防抖+长按 held+ramp 推进从 5 个会话收敛为进程内单开;
  各页每圈 key_router_pump() 取防抖后边沿, 动作(调音量/光标导航)仍由调用页决定,
  保留 run_menu 的 meow_mode 分支; App 前台 volume_page 武装时边沿抑制;
  main_menu/now_playing/notif_center/settings_page/subpage 接入, 附 test_key_router_vol/test_np_keys
- WiFi 连接修复: meow_netmgrd connect 有界等待 wpa_state=COMPLETED(普通 10s/隐藏网络 15s,
  env 可调)修设置页连接无响应; list_networks/scan_results 的 \xNN 转义还原始字节, 修中文 SSID
  永不命中致新建同名 open 记录顶影; launcher netmgr_ipc 配读超时; 附 test_wifi_connect(桩
  wpa_cli 驱动 static wifi_connect_ex), test_netmgrd.sh 补用例; wifi_page 同步
- ncm bench: 新增 bench/lyric_sim.c、bench/plpage_sim.c, vol_sync_sim 与 ncm core/app 同步
- SDK IME 修复: shift 大小写、K_ENTER 只提交不关、阻塞 IME 循环喂 on_tick 不被遮挡、
  IME 打开 ~200ms TAP 冷却窗吞 stray-TAP; 附 sdk/test_ime_fix.c
- 同期: meow_audiod 音量异步 ACK 线程(代际防 fd/槽复用竞态)、watchdog 音量收编(首选 audiod
  权威, settings.conf 覆盖路径)、panel 文件搜索(F1-④)与蓝牙只读详情(F1-③)、各类 build 脚本同步

范围红线: third_party/legado-E-main 原开发者未跟踪, 本次不入库(保留 devdocs/local tar 参考);
二进制不入库(后续重编); devdocs/ 不入库。59 文件全部在 patch_v2/ 下, 无 third_party/devdocs。
验证: git apply --check 干净; 59 文件 md5 与容器 patch_v2 逐一比对 59/59 一致(含
key_router.c/rdchapter.c/meow_ui_ime.c/test_wifi_connect.c 抽查); 可执行位保守
(check_lgpl_release.sh 100755, build_turn_repro.sh 100644 与容器一致)。
This commit is contained in:
AskaEth committed 2026-11-04 20:02:28 +08:00
1 parent e87ccdf061
commit 7c7d891570
59 files changed
+5305 -590

No files matched your search

+20
View File
@@ -75,6 +75,16 @@ static int g_ime_done = 0;
static int g_ime_result = 0;
static int g_shift = 0;
/* WiFi 设置页 bug3(2026-09-15):IME 打开瞬间 TAP 冷却窗。触发打开的那次点按,其「抬起
* TAP」(含 goodix 抬起长尾)可能由 SDK 输入线程在打开 drain 之后才读出并入队(子页自有
* tfd 与 SDK 输入线程独立读同一 evdev,节奏可滞后 ~20ms+)——阻塞循环把它当「点背景=取消」
* 瞬间关键盘(y<KB_TOP)或幻影按键(y≥KB_TOP)。窗口期内的 TAP 一律消费丢弃(镜像
* meow_ui_run 的 STARTUP_COOLDOWN_MS 500 先例,取 200 兼顾手感;正常打字第一键必在窗后)。
* 防御为双保险:drain 已复位触摸状态机(在途按压不再产 TAP),冷却窗再兜住 drain 前已入队
* 未及清/时序竞争残漏的 TAP。 */
#define IME_TAP_COOLDOWN_MS 200
static uint64_t g_ime_open_ms = 0; /* meow_ui_time_ms() 单调毫秒;0=未记录 */
static meow_ime_ctx g_ime_ctx; /* 拷贝(on_change 回调用) */
static meow_ime_ctx *g_ime_orig = NULL; /* 应用真实 ctx(buf 回填用) */
static char g_ime_buf[256];
@@ -570,6 +580,11 @@ int meow_ime_long_press(int x, int y)
int meow_ime_handle_event(const meow_input_ev *e)
{
if (!g_ime_active || g_ime_done) return 0;
/* 打开冷却窗(bug3):窗口内 TAP 一律消费丢弃——防触发打开那次点按的迟到「抬起 TAP」
* 被当「点背景=取消」或幻影按键。消费(return 1)而非透传:事件已属 IME 会话期。 */
if (e->type == MEOW_EV_TAP && g_ime_open_ms &&
meow_ui_time_ms() - g_ime_open_ms < IME_TAP_COOLDOWN_MS)
return 1;
switch (e->type) {
case MEOW_EV_TAP: return meow_ime_handle_tap(e->a, e->b);
case MEOW_EV_TOUCH_DOWN: g_ime_swipe_y = e->b; return 1; /* 记录压点(候选栏滑动判定);覆盖层消费 */
@@ -605,6 +620,11 @@ void meow_ui_text_input_async(meow_ime_ctx *ctx)
ime_capture(); /* M2.71-bug7:打开前拍下键盘区背景(关闭即还原) */
meow_input_start();
meow_input_drain();
/* bug3 加固(对齐 s_dd_modal/subpage 吸收 goodix 抬起长尾的「排空→40ms→再排空」惯例):
* 第一遍 drain 后等 40ms 让输入线程读出迟到事件,第二遍 drain 连状态机一并复位。 */
usleep(40000);
meow_input_drain();
g_ime_open_ms = meow_ui_time_ms(); /* TAP 冷却窗起点(见 IME_TAP_COOLDOWN_MS) */
}
int meow_ui_text_input(meow_ime_ctx *ctx)
+20 -3
View File
@@ -68,6 +68,8 @@
/* §6.4 事件分发形式化:手势捕获终点前向声明(meow_input_drain 之前定义后置,见下方实现)。 */
void meow_ui_gesture_end(void);
/* 触摸状态机复位(定义在触摸状态机变量之后,meow_input_drain 内调用)。 */
void meow_input_touch_reset(void);
/* ── 内部事件:系统级「下拉展开通知中心」(M2.5x 接线)──
* 触摸状态机在抬手判定处识别「SWIPE_DOWN 起始于顶部热区」后压入;事件循环按系统手势处理
@@ -212,6 +214,10 @@ void meow_input_drain(void)
g_qh = 0; g_qt = 0;
pthread_mutex_unlock(&g_qm);
meow_ui_gesture_end(); /* §6.4:清空队列=丢弃未完成手势(如开 IME/模态前),释放捕获防悬垂 */
/* WiFi 设置页 bug3(2026-09-15):drain 同时复位触摸状态机——语义自洽:drain=丢弃在途
* 手势。否则 drain 前已开始、drain 后才被输入线程读出的「抬起」仍会按残留原点产生
* 一个迟到 TAP 入队(IME 打开瞬间被当「点背景=取消」或幻影按键,键盘开即关)。 */
meow_input_touch_reset();
}
static void push_ev(int type, int a, int b)
@@ -260,6 +266,19 @@ static int t_mv_x = -1, t_mv_y = -1;
/* §6.3 通用长按:本次按压是否已触发过长按(触发后抬手不再产生 TAP/SWIPE)。 */
static int t_long_fired = 0;
/* 触摸状态机整体复位:丢弃在途手势(down/原点/坐标/长按触发标记全部归零)。
* 调用点:① meow_input_drain(drain=丢弃在途手势,IME/模态打开前);② §10.5 叠加抑制
* 进入沿(防抑制期丢失抬手致 t_down 卡死)。效果:复位前已开始、复位后才抬起的按压
* 不再产生 TAP/SWIPE(WiFi 设置页 bug3:IME 打开 drain 之后才入队的迟到「抬起 TAP」
* 曾把键盘当「点背景=取消」瞬间关闭)。 */
void meow_input_touch_reset(void)
{
t_down = 0; t_press_valid = 0; t_origin_valid = 0;
t_cx = -1; t_cy = -1; t_dx = 0; t_dy = 0; t_down_ms = 0;
t_mv_x = -1; t_mv_y = -1;
t_long_fired = 0;
}
/* §6.3 通用长按:阈值(默认 MEOW_LONG_PRESS_MS;App 可经 meow_ui_set_long_press_ms 配)。 */
static int g_long_press_ms = MEOW_LONG_PRESS_MS;
/* §6.3 注册的长按回调(NULL=未注册;触发时以 (x,y) 调用,坐标=触发时刻按下点)。 */
@@ -592,9 +611,7 @@ static void *input_thread(void *arg)
if (overlay_input_suppressed()) {
if (!overlay_was) { /* 进入沿:复位触摸状态机,防抑制期丢失抬手致 t_down 卡死 */
overlay_was = 1;
t_down = 0; t_press_valid = 0; t_origin_valid = 0;
t_cx = t_cy = -1; t_dx = t_dy = 0; t_down_ms = 0; t_mv_x = t_mv_y = -1;
t_long_fired = 0;
meow_input_touch_reset();
}
if (r > 0)
for (int i = 0; i < nfd; i++) {
+3 -1
View File
@@ -207,8 +207,10 @@ void meow_input_start(void);
int meow_input_pop(meow_input_ev *ev);
/* 注入一条语义事件(宿主验证手势分发/进度条用;设备上无调用方)。 */
void meow_input_inject(int type, int a, int b);
/* 清空队列(IME 打开前丢弃残留触摸,避免误敲)。 */
/* 清空队列(IME 打开前丢弃残留触摸,避免误敲);同时复位触摸状态机(drain=丢弃在途手势)。 */
void meow_input_drain(void);
/* 触摸状态机整体复位(丢弃在途手势;drain/叠加抑制进入沿调用;宿主单测可直调)。 */
void meow_input_touch_reset(void);
/* ---- M2.71-bug5:App 活动 → 通知 launcher 重置息屏计时 ----
* launcher 前台 app 会话的 app_last_input 只在物理键边沿重置(它看不到应用内触摸)。SDK 在
+39 -4
View File
@@ -3,14 +3,18 @@
* ② K_ENTER 只提交不关(meow_ime_active() 仍真),ESC 后关;
* ③ 阻塞 IME 循环喂 on_tick(动态内容重绘)且 IME 面板仍在最上
* (On_tick 在 IME 面板区画红色哨兵行,IME 绘制后应盖回面板色,不被 App 覆盖)。
* ④ bug3(2026-09-15):IME 打开 ~200ms TAP 冷却窗——打开后立即注入的 stray-TAP
* (背景/键区)被吞不取消;冷却窗后背景 TAP=取消语义保留。
*
* 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/widget/input/activity/dialog/ime + 打桩 font/global):
* gcc -Wall -Wextra -o test_ime_fix test_ime_fix.c test_host_stub.c \
* meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
* meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_notify_ipc.c stb_image.c \
* meow_ui_anim.c meow_ui_media.c meow_ui_nav.c meow_pinyin.c meow_ui_box.c meow_ui_scroll.c \
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
* (meow_ui_widget.c 新 W_LISTVIEW 引用 meow_ui_img_scaled → 需链 meow_ui_img.c+stb_image.c+-lm)
* (meow_ui_widget.c 新 W_LISTVIEW 引用 meow_ui_img_scaled → 需链 meow_ui_img.c+stb_image.c+-lm;
* widget/input/ime/view 后续又引入 anim/media/nav/pinyin/box/scroll 依赖,一并链接)
*/
#include "meow_ui.h"
#include "meow_ui_internal.h"
@@ -54,6 +58,38 @@ static int near(int a, int b) { int d = a - b; if (d < 0) d = -d; return d <= 14
/* ---- ① 异步 shift 测试(直接 handle_tap,确定语义,无阻塞循环) ---- */
static char g_echo[64] = "";
static void ime_cb(const char *t, void *ctx) { (void)ctx; snprintf(g_echo, sizeof g_echo, "%s", t); }
/* ④ WiFi 设置页 bug3(2026-09-15):IME 打开 ~200ms TAP 冷却窗——触发打开那次点按的迟到
* 「抬起 TAP」(goodix 长尾,经 SDK 输入线程 drain 后才入队)不得把键盘当「点背景=取消」
* 瞬间关掉;冷却窗后点背景=取消的语义保留。 */
static void test_stray_tap(void)
{
meow_ime_ctx c; memset(&c, 0, sizeof c);
c.mode = MEOW_IME_ASCII; c.maxlen = 32; c.on_change = ime_cb;
meow_ui_text_input_async(&c);
assert(meow_ime_active() == 1);
/* 打开后立即注入背景 TAP(y<KB_TOP=420):冷却窗内必须被吞——不取消、键盘仍 active */
meow_input_ev stray = { MEOW_EV_TAP, 240, 100 };
assert(meow_ime_handle_event(&stray) == 1); /* 消费(吞掉) */
assert(meow_ime_active() == 1); /* 键盘未被关(修复前此处已 done=取消) */
/* 窗口内键区 TAP 也丢弃(防幻影按键) */
meow_input_ev key = { MEOW_EV_TAP, K_Q_X, K_Q_Y };
assert(meow_ime_handle_event(&key) == 1);
assert(meow_ime_active() == 1);
assert(meow_ime_text()[0] == 0); /* 无幻影字符入缓冲 */
/* 冷却窗(200ms)后:点背景=取消 语义保留 */
usleep(250000);
assert(meow_ime_handle_event(&stray) == 1);
assert(meow_ime_active() == 0); /* 已取消(g_ime_done) */
printf("PASS stray-tap: 窗内背景/键区 TAP 吞掉不取消, 窗后背景 TAP 取消\n"); fflush(stdout);
meow_ime_close(0); /* 复位(清 g_ime_done/active) */
assert(meow_ime_active() == 0);
}
static void test_shift(void)
{
meow_ime_ctx c; memset(&c, 0, sizeof c);
@@ -94,8 +130,6 @@ static char g_drv_text[64] = ""; /* shift 序列后 meow_ime_text()(期
/* 把 back_buf 写成 PPM(视觉目检 IME 面板渲染/最上;在 IME 空闲时调用,back_buf 稳定) */
static void dump_ppm(const char *path)
{
unsigned char *bb = meow_ui_back_buf();
int line = meow_ui_back_buf_pitch(), bpp = meow_ui_back_buf_bpp();
int W = meow_ui_width(), H = meow_ui_height();
FILE *f = fopen(path, "wb");
if (!f) return;
@@ -134,7 +168,7 @@ static void *driver(void *arg)
(void)arg;
usleep(600000); /* 等 meow_ui_run 起动(startup cooldown=500ms) */
meow_input_inject(MEOW_EV_TAP, 150, 322); /* 点 TextField → 阻塞 IME */
usleep(160000);
usleep(350000); /* 等过 IME 打开 TAP 冷却窗(200ms,bug3)+ drain 40ms */
meow_input_inject(MEOW_EV_TAP, K_Q_X, K_Q_Y); /* shift 关 → 'q' */
usleep(90000);
meow_input_inject(MEOW_EV_TAP, K_SHIFT_X, K_SHIFT_Y); /* shift 开 */
@@ -169,6 +203,7 @@ int main(void)
const meow_theme *th = meow_theme_get();
test_shift(); /* ① */
test_stray_tap(); /* ④ bug3:打开冷却窗吞 stray-TAP */
/* ②③ 在 meow_ui_run 里驱动(g_events 仅 meow_ui_run 能设置) */
g_tf = meow_textfield_create(10, 300, 300, 44, "Type here...", g_tfbuf, 32, MEOW_IME_ASCII);