真机 M6.3 反馈(bcef8e0 三连修复未好全,追加两问题):
P1 锁屏 PIN 输入穿透仍在(媒体保活 App 实时读 evdev)
根因:媒体保活 App(播放中)从不 SIGSTOP(保 PCM),SDK 输入线程实时读 evdev,不走缓冲。
bcef8e0 的「SIGCONT 排空」只作用于冻结 App;对未冻结 App,隔离全靠 /tmp/meow_notif_active
让 SDK 排空——若 App 的 meow_ui.a 缺该排空(或节流窗内漏网),锁屏期触摸依旧抵达 App。
修法:run_lock_screen() 与 lck_input_pin_modal() 打开 DEV_TOUCH 后 EVIOCGRAB 独占触控设备
(真机 goodix 实测 EVIOCGRAB 返回 0)——抓取期事件只投递抓取者、不为其它 fd 缓冲/回放,
故**任何**前台进程(冻结或未冻结)锁屏期都收不到触摸(真全模态)。失败时记日志降级
(仍靠标记+SIGSTOP 隔离)。overlay_gate.h 增 overlay_keepalive_needs_grab 判据。
P2 主界面应用名只显示 5 字(「流媒体客户」式,半字残形)
根因:app_launcher.c `strncpy(a->name, name, 16)` 仍把显示名硬截 16 字节——M6.3 只扩了
name[49]+json_str 整序列,漏改此二处。UTF-8 下 16B = 5 汉字 + 「端」首字节 + 无 NUL,
显示成「流媒体客户」+ 残形;main_menu.c menu_name_fit 按字节回退又停在半截字符、加 "..." 溢出。
修法:新增 meow_utf8.h(meow_utf8_char_len / meow_utf8_copy_bounded,纯决策可单测)——
app_launcher.c 两处 strncpy(16) 改 app_name_copy(=copy_bounded, 拷满 sizeof name=49);
menu_name_fit 改整字符前进 + 预留省略号宽度(mfont 用「…」/点阵用 "..."),总宽 ≤ maxw,
绝不劈开多字节字符。
新增 test_utf8_name.c(14 断言:整字符长/整序列有界拷贝,含 cap=16/17/12 边界不劈字)+
test_overlay_gate.c 扩展(S1b 未冻结 App 靠 EVIOCGRAB 隔离 4 断言)。launcher 全量宿主回归
+ SDK 叠加/状态栏/输入回归全 PASS;mipsel 交叉 -Wall -Wextra 0 warning。
md5 56dac860841c3884b4322707246e22af(/usr/bin 只读,待固件打包 M6.4;fw_content.conf 未动)。
58 lines
2.7 KiB
C
58 lines
2.7 KiB
C
/* meow_utf8.h — UTF-8 整序列有界拷贝/字符步进纯决策(宿主可单测;无 ui_width/mfont 依赖)。
|
|
*
|
|
* 背景(问题2,M6.3 真机):主界面应用名「流媒体客户端」被截成 5 字 + 半个字。两处根因:
|
|
* ① app_launcher.c `strncpy(a->name, name, 16)` 仍把显示名硬截 16 字节(UTF-8 下=5 汉字+ 半个
|
|
* 「端」)——M6.3 只扩了 name[49]+json_str 整序列,漏改此处;
|
|
* ② main_menu.c `menu_name_fit` 按字节回退、边界判定错(do..while 读的是刚清零的字节,恒停续字节),
|
|
* 停在半截多字节字符;再加 "..." 未为省略号留宽 → 溢出 maxw 被裁切。
|
|
* 本头把 UTF-8 整序列处理抽成纯函数(meow_utf8_char_len / meow_utf8_copy_bounded / 截断决策),
|
|
* 两处复用并可宿主单测(test_utf8_name.c)。
|
|
*/
|
|
#ifndef MEOW_UTF8_H
|
|
#define MEOW_UTF8_H
|
|
|
|
#include <stddef.h>
|
|
#include <stdio.h> /* snprintf(有界拷贝用) */
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* 由首字节 c0 求整字符 UTF-8 字节长(1..4)。非法首字节(0x80..0xBF 续字节)返回 1(按异常字节跳过,
|
|
* 绝不把孤立续字节与后字并成大字符)。纯按前导位,不看后续字节是否齐全(那由 copy_bounded 处理)。 */
|
|
static inline int meow_utf8_char_len(unsigned char c0)
|
|
{
|
|
if (c0 < 0x80) return 1;
|
|
if (c0 < 0xC0) return 1; /* 孤立续字节:兜底 1 */
|
|
if (c0 < 0xE0) return 2;
|
|
if (c0 < 0xF0) return 3;
|
|
return 4;
|
|
}
|
|
|
|
/* 有界拷贝:把 src 拷入 dst(容量 cap,含 NUL),**绝不劈开多字节字符**。snprintf 截断若落在字符
|
|
* 中间(或 src 本身尾部是半截字符),回退到整字符边界:删去最末不完整字符。返回拷贝后字节长(不含
|
|
* NUL)。源可为 NULL。持久化/展示名均用——保证 UTF-8 整序列,杜绝「5 汉字+半个字」式残字。 */
|
|
static inline int meow_utf8_copy_bounded(char *dst, int cap, const char *src)
|
|
{
|
|
if (!dst || cap <= 0) return 0;
|
|
if (cap == 1) { dst[0] = 0; return 0; }
|
|
if (!src) src = "";
|
|
snprintf(dst, (size_t)cap, "%s", src);
|
|
int n = (int)strlen(dst);
|
|
if (n <= 0) return 0;
|
|
/* 定位最末一个「起始字节」(非续字节):从尾部回退续字节。 */
|
|
int last_start = n - 1;
|
|
while (last_start > 0 && ((unsigned char)dst[last_start] & 0xC0) == 0x80)
|
|
last_start--;
|
|
/* 末字符:起始字节=last_start,实际字节数=have;字符应需 need。have<need → 不完整 → 删。 */
|
|
int need = meow_utf8_char_len((unsigned char)dst[last_start]);
|
|
int have = n - last_start;
|
|
if (have < need) { dst[last_start] = 0; n = last_start; }
|
|
return n;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#endif /* MEOW_UTF8_H */
|