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:
1 parent
e87ccdf061
commit
7c7d891570
59 files changed
+5305
-590
No files matched your search
@@ -0,0 +1,229 @@
|
||||
/* test_key_router_vol.c — 宿主单测:launcher-UI 页物理键统一路由(KEY_ROUTER_UNIFY P1)。
|
||||
*
|
||||
* 测「key_router 自身的音量编排」——它只产「音量边沿 + 原始 held + ramp 状态」,
|
||||
* 由调用页决定 settings_volume_adj(±step) / 光标导航 / ramp 推进。本测用内存桩:
|
||||
* - kp_poll/kp_open/kp_is_down → 注入 raw 键位矩阵到 key_router 的静态 kp_keys.cur[];
|
||||
* - kd_tick → 用 keys.c 的真实现(40ms 防抖,V4 依赖);keys.c 内 kp_open/kp_poll/
|
||||
* kp_is_down/meow_volpage_armed 用宏重命名避开真实 ioctl 与桩冲突;
|
||||
* - settings_volume_adj/settings_volume_step/vol_ramp_dir/vol_ramp_tick → 内存桩;
|
||||
* - now_ms → 假时钟(手动推进,40ms 防抖可瞬时测);
|
||||
* - meow_ui_activity_* → 内存桩(V5 嵌套:真语义=纯静态数组,桩复刻)。
|
||||
*
|
||||
* 断言:
|
||||
* V1 音量减边沿 → settings_volume_adj(-step) 恰一次 + last_input 复位;
|
||||
* V2 同会话重复(同 raw 仍按住)→ 不再触发 settings_volume_adj;
|
||||
* V3 长按 held → vol_ramp_tick 被驱动(vol_ramp_dir!=0,held=正确方向 raw);松开 → dir=0;
|
||||
* V4 40ms 防抖:raw 在 40ms 内抖动 → 不产边沿;稳定按下 ≥40ms → 才产边沿;
|
||||
* V5 嵌套返回:page_enter(0x53)→page_exit(0x53)→page_enter(0x55),基线重播后 held 键不产假边沿;
|
||||
* V6 meow_volpage_armed() → 音量边沿被抑制(不下发,不调 settings_volume_adj)。
|
||||
*
|
||||
* 编译(在 patch_v2/meow_launcherd 下):
|
||||
* gcc -Wall -Wextra -I../sdk -I. -ffunction-sections -fdata-sections \
|
||||
* -Wl,--gc-sections test_key_router_vol.c -o test_key_router_vol
|
||||
* ./test_key_router_vol
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* ---- 假时钟 ---- */
|
||||
static unsigned long long g_now = 100000;
|
||||
unsigned long long now_ms(void) { return g_now; }
|
||||
static void advance_ms(unsigned long long d) { g_now += d; }
|
||||
|
||||
/* ---- 音量机外部符号桩(key_router 依赖)---- */
|
||||
int settings_volume_step = 5;
|
||||
static int g_adj_count = 0, g_adj_delta = 0;
|
||||
int vol_ramp_dir = 0; /* 桩全局:模拟 audio.c 的 ramp 状态 */
|
||||
static int g_tick_count = 0, g_tick_held = -1;
|
||||
|
||||
void settings_volume_adj(int delta)
|
||||
{
|
||||
g_adj_count++; g_adj_delta = delta;
|
||||
if (delta > 0) vol_ramp_dir = 1; else if (delta < 0) vol_ramp_dir = -1;
|
||||
}
|
||||
|
||||
int vol_ramp_tick(int key_held)
|
||||
{
|
||||
g_tick_count++; g_tick_held = key_held;
|
||||
if (!key_held) vol_ramp_dir = 0;
|
||||
return vol_ramp_dir != 0;
|
||||
}
|
||||
|
||||
static int g_volpage = 0; /* 桩:meow_volpage_armed */
|
||||
|
||||
/* ---- keys.c 内 kp_open/kp_poll/kp_is_down/meow_volpage_armed 用宏重命名,避开真实 ioctl ----
|
||||
* (宏在 #include keys.c 前生效,仅重命名 keys.c 体内的调用/定义) ---- */
|
||||
#define kp_open kp_open_rt_
|
||||
#define kp_poll kp_poll_rt_
|
||||
#define kp_is_down kp_is_down_rt_
|
||||
#define meow_volpage_armed meow_volpage_armed_rt_
|
||||
#include "keys.c" /* 真 kd_tick(40ms 防抖素材) */
|
||||
#undef kp_open
|
||||
#undef kp_poll
|
||||
#undef kp_is_down
|
||||
#undef meow_volpage_armed
|
||||
|
||||
/* host 桩声明(key_router.c 需要;恢复到正常名,与 keys.c 被更名后的定义不冲突) */
|
||||
struct keypoll;
|
||||
int kp_open(struct keypoll *kp, const char *dev);
|
||||
int kp_poll(struct keypoll *kp, int (*cb)(int code, int down, void *ctx), void *ctx);
|
||||
int kp_is_down(const struct keypoll *k, int code);
|
||||
int meow_volpage_armed(void);
|
||||
|
||||
#include "key_router.c" /* 同 TU #include:拿到静态 kp_keys/kp_power/kd_vold/kd_volu + 全部函数 */
|
||||
#include "key_router.h"
|
||||
|
||||
/* ---- meow_ui_activity_* 桩(复刻 sdk/meow_ui_activity.c:纯静态数组,真语义)---- */
|
||||
static int g_act[32]; static int g_act_n = 0;
|
||||
void meow_ui_activity_push(int id) { if (g_act_n < 32) g_act[g_act_n++] = id; }
|
||||
void meow_ui_activity_pop(void) { if (g_act_n > 0) g_act_n--; }
|
||||
int meow_ui_activity_active(void) { return g_act_n > 0 ? g_act[g_act_n - 1] : 0; }
|
||||
|
||||
/* ---- 注入 raw 到 key_router 静态 kp_keys ---- */
|
||||
static void set_vol(int vold, int volu)
|
||||
{
|
||||
for (int w = 0; w < KEYBUF_WORDS; w++) kp_keys.cur[w] = 0;
|
||||
if (vold) kp_keys.cur[KEY_VOLUMEDOWN / 32] |= (1UL << (KEY_VOLUMEDOWN % 32));
|
||||
if (volu) kp_keys.cur[KEY_VOLUMEUP / 32] |= (1UL << (KEY_VOLUMEUP % 32));
|
||||
}
|
||||
|
||||
/* ---- host 桩:kp_*(prev=cur 模拟真实 poll 的键位更新)+ meow_volpage_armed ---- */
|
||||
int kp_open(struct keypoll *kp, const char *dev)
|
||||
{ (void)dev; memset(kp, 0, sizeof *kp); kp->ok = 1; return 0; }
|
||||
int kp_poll(struct keypoll *kp, int (*cb)(int, int, void *), void *ctx)
|
||||
{
|
||||
(void)cb; (void)ctx;
|
||||
for (int w = 0; w < KEYBUF_WORDS; w++) kp->prev[w] = kp->cur[w];
|
||||
return 0;
|
||||
}
|
||||
int kp_is_down(const struct keypoll *k, int code)
|
||||
{ return (k->cur[code / 32] >> (code % 32)) & 1; }
|
||||
int meow_volpage_armed(void) { return g_volpage; }
|
||||
|
||||
/* 其它全局桩(keys.c 内被更名函数引用;本测 GC 后不保留,仅满足声明一致性) */
|
||||
uint32_t menu_bg = 0;
|
||||
int screen_off_timeout = 0, screen_off_mode = 0, power_longpress_menu_ms = 0;
|
||||
int power_forceoff_ms = 0, refresh_rate_cfg = 60, refresh_always_max = 0;
|
||||
|
||||
void logmsg(const char *fmt, ...) { (void)fmt; }
|
||||
|
||||
static int g_fails = 0;
|
||||
#define CHECK(cond, name) do { \
|
||||
if (cond) printf(" PASS %s\n", name); \
|
||||
else { printf(" FAIL %s (%s:%d)\n", name, __FILE__, __LINE__); g_fails++; } } while (0)
|
||||
|
||||
static void reset_router(void)
|
||||
{
|
||||
set_vol(0, 0);
|
||||
key_router_rebase();
|
||||
g_adj_count = 0; g_adj_delta = 0; g_tick_count = 0; g_tick_held = -1;
|
||||
vol_ramp_dir = 0; g_volpage = 0;
|
||||
g_act_n = 0;
|
||||
}
|
||||
|
||||
/* 按下并稳定:register(pump) → hold ≥40ms → pump(stable=1, 边沿)。 */
|
||||
static key_evt_t press_settle(int vold, int volu)
|
||||
{
|
||||
set_vol(vold, volu);
|
||||
key_router_pump(); /* 登记 raw 跳变(防抖窗口起点) */
|
||||
advance_ms(50); /* ≥KEY_DEBOUNCE_MS(40) */
|
||||
return key_router_pump(); /* stable→1,边沿 */
|
||||
}
|
||||
|
||||
/* 抬起并稳定:register(pump) → → pump(stable=0)。 */
|
||||
static key_evt_t release_settle(void)
|
||||
{
|
||||
set_vol(0, 0);
|
||||
key_router_pump(); /* 登记 release */
|
||||
advance_ms(50);
|
||||
return key_router_pump(); /* stable→0 */
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned long long last_input = 0;
|
||||
|
||||
/* ---- V1 音量减边沿 → settings_volume_adj(-step) 恰一次 + last_input 复位 ---- */
|
||||
reset_router();
|
||||
set_vol(0, 0); advance_ms(10); key_router_pump(); /* 全抬起基线 */
|
||||
last_input = 0;
|
||||
key_evt_t ev = press_settle(1, 0);
|
||||
CHECK(ev.vol_dn_edge == 1, "V1 vol-down edge fires");
|
||||
key_router_default_volume(&ev, &last_input);
|
||||
CHECK(g_adj_count == 1 && g_adj_delta == -settings_volume_step,
|
||||
"V1 vol-down -> settings_volume_adj(-step) exactly once");
|
||||
CHECK(last_input == g_now, "V1 last_input reset on edge");
|
||||
|
||||
/* ---- V2 同会话重复(同 raw 仍按住)→ 不再触发 ---- */
|
||||
reset_router();
|
||||
set_vol(0, 0); advance_ms(10); key_router_pump();
|
||||
ev = press_settle(1, 0);
|
||||
CHECK(ev.vol_dn_edge == 1, "V2a press edge fires");
|
||||
ev = key_router_pump(); /* 同 raw 仍按住,无新边沿 */
|
||||
CHECK(ev.vol_dn_edge == 0, "V2 held: no re-trigger edge");
|
||||
key_router_default_volume(&ev, &last_input);
|
||||
CHECK(g_adj_count == 0, "V2 held: no double settings_volume_adj");
|
||||
|
||||
/* ---- V3 长按 held → vol_ramp_tick 被驱动(held=正确方向 raw);松开 → dir=0 ---- */
|
||||
reset_router();
|
||||
set_vol(0, 0); advance_ms(10); key_router_pump(); last_input = 0;
|
||||
ev = press_settle(1, 0); /* 按下(vol down)并转稳定 */
|
||||
key_router_default_volume(&ev, &last_input);
|
||||
CHECK(g_tick_count == 1 && g_tick_held == ev.vol_held_dn && vol_ramp_dir != 0,
|
||||
"V3 hold vol-down -> ramp driven with held=raw down");
|
||||
advance_ms(50);
|
||||
ev = key_router_pump(); /* 继续长按(raw=1 仍按住) */
|
||||
key_router_default_volume(&ev, &last_input);
|
||||
CHECK(g_tick_count == 2 && g_tick_held == 1, "V3 long-press continues ramp");
|
||||
ev = release_settle(); /* 松开:raw held 立即为 0 */
|
||||
key_router_default_volume(&ev, &last_input);
|
||||
CHECK(vol_ramp_dir == 0, "V3 release -> ramp dir 0 (stops)");
|
||||
|
||||
/* ---- V4 40ms 防抖:raw 在 40ms 内抖动不产边沿;稳定 ≥40ms 才产 ---- */
|
||||
reset_router();
|
||||
set_vol(0, 0); advance_ms(10); key_router_pump();
|
||||
set_vol(1, 0); advance_ms(20); key_router_pump(); /* 按下未满 40ms */
|
||||
set_vol(0, 0); advance_ms(20); key_router_pump(); /* 40ms 内又抬起 */
|
||||
ev = key_router_pump();
|
||||
CHECK(ev.vol_dn_edge == 0, "V4 <40ms jitter -> no edge");
|
||||
ev = press_settle(1, 0); /* 稳定按下 ≥40ms */
|
||||
CHECK(ev.vol_dn_edge == 1, "V4 stable >=40ms press -> edge");
|
||||
ev = release_settle(); /* 抬起稳定 */
|
||||
CHECK(ev.vol_dn_edge == 0 && ev.vol_up_edge == 0, "V4 released -> no residual edge");
|
||||
ev = press_settle(0, 1); /* 稳定按音量加 */
|
||||
CHECK(ev.vol_up_edge == 1, "V4 vol-up stable press -> up edge");
|
||||
|
||||
/* ---- V5 嵌套返回:page_enter/exit 重播基线,held 键不产假边沿 ---- */
|
||||
reset_router();
|
||||
meow_ui_activity_push(0x55); key_router_page_enter(0x55); /* 主菜单 */
|
||||
set_vol(0, 0); advance_ms(10); key_router_pump();
|
||||
ev = press_settle(1, 0);
|
||||
CHECK(ev.vol_dn_edge == 1, "V5a press edge in menu");
|
||||
/* 嵌套进设置页:压栈 + 登记 */
|
||||
meow_ui_activity_push(0x53); key_router_page_enter(0x53);
|
||||
CHECK(meow_ui_activity_active() == 0x53, "V5b settings active sentinel");
|
||||
ev = release_settle(); /* 设置页内把键抬起 */
|
||||
CHECK(ev.vol_dn_edge == 0, "V5c settings-up: no fresh edge (consumer)");
|
||||
/* 设置页返回(模拟 run_settings_page 结束):弹栈 + 重播基线 → m_prev=当前 raw(0) */
|
||||
key_router_page_exit(0x53); meow_ui_activity_pop();
|
||||
key_router_page_enter(0x55);
|
||||
CHECK(meow_ui_activity_active() == 0x55, "V5d menu active again");
|
||||
/* 主菜单基线已重播;再次按下应为新边沿,而非残留/双发 */
|
||||
ev = press_settle(1, 0);
|
||||
CHECK(ev.vol_dn_edge == 1, "V5e fresh press after nest return -> single edge");
|
||||
|
||||
/* ---- V6 meow_volpage_armed() → 音量边沿被抑制(不下发)---- */
|
||||
reset_router();
|
||||
set_vol(0, 0); advance_ms(10); key_router_pump();
|
||||
g_volpage = 1;
|
||||
ev = press_settle(1, 0);
|
||||
CHECK(ev.vol_dn_edge == 0, "V6 volpage armed -> edge suppressed");
|
||||
key_router_default_volume(&ev, &last_input);
|
||||
CHECK(g_adj_count == 0, "V6 volpage armed -> settings_volume_adj NOT called");
|
||||
g_volpage = 0;
|
||||
|
||||
printf("\nRESULT: %s (%d fails)\n", g_fails ? "FAIL" : "ALL PASS", g_fails);
|
||||
return g_fails ? 1 : 0;
|
||||
}
|
||||
Reference in new issue
Block a user