fix(sdk+launcher): M39 点击输入门 — 固定时长吞窗改为「启动排空 + 短系统手势防穿透」
根因(M36 已查实):不是布局竞态,而是固定时长的输入封闭窗口且窗口起点在首帧之后。 - SDK meow_ui_run:M2.22(C) 500ms 内丢弃 TAP/SWIPE/HOME/NOTIF_PULL/TOUCH_DOWN/MOVE/LONG_PRESS, 窗口在 App 画完首帧后才 arm → 用户看到界面后第一下必被吞。 改为入口 meow_input_drain() 排空一次(清环形队列 + 复位触摸状态机), TAP/TOUCH_DOWN/TOUCH_MOVE/LONG_PRESS 立即生效;仅系统手势(左缘 SWIPE、底部上滑 HOME、 顶部下拉 NOTIF_PULL、SWIPE_PROGRESS)保留 STARTUP_GESTURE_GUARD_MS=150 防穿透。 - launcher:menu_after_app_exit 1200ms→150ms;子页返回 800ms→150ms;菜单/子页打开 300ms→150ms(统一 MENU_TOUCH_GUARD_MS)。menu_drain_touch() 同时复位 t_down/原点/坐标: 只清队列会把「按下已被 drain、抬手稍后才到」误判成一次 tap(幽灵重放的另一半)。 历史理由已核对:旧窗口是为 Bug2/4(App 运行期事件堆积在 launcher 自身 touch_fd 里被重放) 加的,真正的机制就是排空本进程 fd —— evdev 每 fd 各收一份,App/子页运行期全量事件都在 这个 fd 里,drain 后无历史事件可重放;窗口只兜面板重配尾巴。 - 单测:test_meow_ui_home_gesture 新增 T4(11 断言:立即点击生效/立即上滑被守卫挡+守卫后生效/ 立即左缘 SWIPE 同理/TOUCH_DOWN+MOVE 立即下发/LONG_PRESS 立即下发/run 入口 drain 丢弃预置残留; 旧 SDK 下 8 条红、新 SDK 30 pass/0 fail);test_meow_ui_dispatch 新增 M5(drain 清队列+复位在途 手势+新点击不受影响,ALL PASS);swipe 35/0、view_event ALL PASS(回归)。 - 重编重链(铁律):meow_ui.a 8525aa6b(meow_ui_input.o 8248a6c6,旧 e54903ca)→ meow_launcherd e342d24f(891164) / files 17edac0f(383072) / hello 65c1c575(499380) / ncm 1c2f5ff7(1225676) / reader a463645f(1716212,gitignore 不入库)。 picbrowser 仓库内 0 个 tracked 文件(源码不存在)→ 无法重链,见 finding。 - 真机:未验证(纪律禁止覆盖设备已装组件;uinput 注入是 M36 设备失联诱因)。
This commit is contained in:
1 parent
46278fd051
commit
837cd47e7c
11 files changed
+256
-52
No files matched your search
@@ -56,17 +56,28 @@ static int menu_live_open_pending = 0;
|
||||
* fresh menu taps. A replayed tap on an app row relaunches the app (symptom:
|
||||
* BYE then the app's main screen — Bug 2); a replayed tap on the "BACK TO
|
||||
* PLAYER" row closes the menu and SIGCONTs the player (symptom: whole screen
|
||||
* flashes back to the player — Bug 4). We drain the queue immediately after
|
||||
* the app exits and ignore touches for a short cooldown that covers the
|
||||
* measured 1.2-2.25s ghost window (matches the watchdog's COOLDOWN_MS). */
|
||||
* flashes back to the player — Bug 4).
|
||||
*
|
||||
* M39:真正的机制是「排空本进程 touch_fd」——evdev 每个 fd 各收一份事件副本,App 运行期间
|
||||
* (launcher 不读)的全部事件都堆在这个 fd 里,app 一退出就会作为「新菜单 tap」重放。
|
||||
* menu_drain_touch() 把它们全读掉(含按下沿)+ 复位手势状态机,历史上用于兜底的
|
||||
* 1.2–2.25s 冷却窗口因此可以收窄到 MENU_TOUCH_GUARD_MS:那个窗口是从「App 退出」开始计时
|
||||
* 的,用户看到菜单后伸手的第一下必然落在里面被吞(用户实测「首页点图标要点两次」根因之一)。
|
||||
* 现在只留极短的驱动尾巴守卫,不再按时间吞真实输入。 */
|
||||
static unsigned long long menu_touch_cooldown_until = 0;
|
||||
|
||||
/* 排空本进程触摸队列(非阻塞读到 EAGAIN)+ 复位手势状态机。
|
||||
* 队列/down 边沿都要清:只清队列而保留 t_down,会让「按下已被 drain 掉、抬手稍后才到」的
|
||||
* 这次手势被当成一次有效 tap(ghost touch 重放的另一半)。 */
|
||||
static void menu_drain_touch(void)
|
||||
{
|
||||
if (touch_fd >= 0) {
|
||||
unsigned char ev[16];
|
||||
while (read(touch_fd, ev, sizeof ev) == (ssize_t)sizeof ev) { /* discard */ }
|
||||
}
|
||||
t_down = 0; t_down_valid = 0;
|
||||
t_down_x = t_down_y = -1;
|
||||
t_last_x = t_last_y = -1;
|
||||
}
|
||||
|
||||
static void menu_arm_touch(long ms)
|
||||
@@ -76,18 +87,19 @@ static void menu_arm_touch(long ms)
|
||||
}
|
||||
|
||||
|
||||
/* Drain the touch queue + arm the post-app cooldown (call right after the
|
||||
* app exits, before the menu resumes polling touch). The drain always runs so
|
||||
* touches queued by the launch-attempt tail are cleared; the cooldown only
|
||||
* arms when an app actually ran (app_ran) so a failed launch doesn't lock the
|
||||
* menu out for 2.5s. */
|
||||
/* Drain the touch queue + arm the post-app guard (call right after the app
|
||||
* exits, before the menu resumes polling touch). The drain always runs so
|
||||
* touches queued by the launch-attempt tail are cleared; the guard only arms
|
||||
* when an app actually ran (app_ran) so a failed launch doesn't lock the menu
|
||||
* out. */
|
||||
static void menu_after_app_exit(int app_ran)
|
||||
{
|
||||
menu_drain_touch();
|
||||
/* M2.22(D):2500ms 冷却把正常的「app 退出后立即点下一个应用」也吞掉(点几下才进)。
|
||||
* 用户要求点一下就能进 → 调窄到 1200ms,仍覆盖 goodix ghost 窗口(1.2–2.25s 实测略短,
|
||||
* 与 watchdog COOLDOWN_MS 同阶),防启动重放。只调窄,保留 cooldown 本身。 */
|
||||
if (app_ran) menu_touch_cooldown_until = now_ms() + 1200;
|
||||
/* M39:M2.6 的 2500ms → M2.22 的 1200ms → 现在的 MENU_TOUCH_GUARD_MS(150ms)。
|
||||
* 依据:重放的来源是本进程 fd 里 App 运行期的事件,menu_drain_touch() 已一次性清空
|
||||
* (含 t_down/原点,见上),窗口只兜「面板重配后驱动补发的幽灵尾巴」。1200ms 会稳定吞掉
|
||||
* 用户「返回桌面后立即点下一个图标」——正是要修的症状。 */
|
||||
if (app_ran) menu_touch_cooldown_until = now_ms() + MENU_TOUCH_GUARD_MS;
|
||||
}
|
||||
|
||||
|
||||
@@ -1207,8 +1219,9 @@ static void run_menu(struct app apps[MAX_APPS], int napps, int state,
|
||||
/* touch: event reads (event1 is not grabbed) */
|
||||
touch_fd = open(DEV_TOUCH, O_RDONLY | O_NONBLOCK);
|
||||
if (touch_fd < 0) logmsg("touch open failed: %s", strerror(errno));
|
||||
/* M2.6 幽灵触摸防护:菜单激活(启动)即 drain + 冷却 */
|
||||
menu_arm_touch(TAP_ARM_DELAY_MS);
|
||||
/* M39:菜单激活(启动)即 drain + 极短守卫(M2.6 原为 300ms;界面此时已整帧画完,
|
||||
* 窗口只会吞用户看到首页后的第一下,故收窄到 MENU_TOUCH_GUARD_MS) */
|
||||
menu_arm_touch(MENU_TOUCH_GUARD_MS);
|
||||
|
||||
/* key polling */
|
||||
struct keypoll kp_power, kp_keys;
|
||||
@@ -1335,7 +1348,7 @@ static void run_menu(struct app apps[MAX_APPS], int napps, int state,
|
||||
sim_exit_tap_done = 1;
|
||||
if (meow_mode) {
|
||||
int rb = confirm_reboot_player();
|
||||
menu_arm_touch(TAP_ARM_DELAY_MS);
|
||||
menu_arm_touch(MENU_TOUCH_GUARD_MS);
|
||||
dirty = 1;
|
||||
logmsg("meow mode: BACK TO PLAYER -> confirm reboot (rb=%d)", rb);
|
||||
} else {
|
||||
@@ -1482,7 +1495,7 @@ static void run_menu(struct app apps[MAX_APPS], int napps, int state,
|
||||
pwr_hold_at = 0; pwr_menu_state = 0; pwr_woke = 0;
|
||||
pwr_suppress_click = 1; /* M2.34:菜单返回后抑制本次电源松开被误判单击熄屏 */
|
||||
dirty = 1; /* 取消后重绘应用列表 */
|
||||
menu_arm_touch(800); /* M2.6 幽灵触摸防护:菜单关闭后忽略触摸 */
|
||||
menu_arm_touch(MENU_TOUCH_GUARD_MS); /* M39:drain + 短守卫(原 M2.6 800ms) */
|
||||
/* M2.25 黑屏修复:阻塞式 show_power_menu() 期间 kd_* 防抖状态冻结。
|
||||
* 用户常「松开电源 → 用触摸点取消」,返回后 kd_pwr.stable 仍是旧的「按住=1」,
|
||||
* 而 m_prev_pwr 已按 raw 重播为 0 → 二者错配误判「新按下」刷新 pwr_hold_at,
|
||||
@@ -1666,7 +1679,7 @@ static void run_menu(struct app apps[MAX_APPS], int napps, int state,
|
||||
logmsg("menu: top-edge live drag-down -> notification center (dy=%d)",
|
||||
t_last_y - loy);
|
||||
t_down = 0; t_down_valid = 0; /* 消费本次手势:返回后不再判 tap/滑动/重开 */
|
||||
menu_arm_touch(TAP_ARM_DELAY_MS);
|
||||
menu_arm_touch(MENU_TOUCH_GUARD_MS);
|
||||
notif_click_t click;
|
||||
memset(&click, 0, sizeof click);
|
||||
click.app_idx = -1;
|
||||
@@ -1682,7 +1695,7 @@ static void run_menu(struct app apps[MAX_APPS], int napps, int state,
|
||||
m_prev_pwr = kp_is_down(&kp_power, KEY_POWER);
|
||||
m_prev_play = kp_is_down(&kp_keys, KEY_PLAYPAUSE);
|
||||
last_input_ms = now_ms();
|
||||
menu_arm_touch(800);
|
||||
menu_arm_touch(MENU_TOUCH_GUARD_MS);
|
||||
dirty = 1;
|
||||
/* M5:通知点击按 route_status 产出 click(0 跳转 / 1 NO ROUTE / 2 SOURCE NOT FOUND) */
|
||||
if (click.status == NOTIF_CLICK_STATUS_OK &&
|
||||
@@ -1764,7 +1777,7 @@ static void run_menu(struct app apps[MAX_APPS], int napps, int state,
|
||||
* 本函数只在顶部热区(down_y<SB_BAR_H)+向下主导时返回 1,与左缘互斥。 */
|
||||
if (mnp_top_swipe_down(tx, ty, dx, dy, SB_BAR_H, MENU_SWIPE_THRESH)) {
|
||||
logmsg("menu: top-edge swipe-down -> notification center (release edge, fallback)");
|
||||
menu_arm_touch(TAP_ARM_DELAY_MS);
|
||||
menu_arm_touch(MENU_TOUCH_GUARD_MS);
|
||||
notif_click_t click;
|
||||
memset(&click, 0, sizeof click);
|
||||
click.app_idx = -1;
|
||||
@@ -1780,7 +1793,7 @@ static void run_menu(struct app apps[MAX_APPS], int napps, int state,
|
||||
m_prev_pwr = kp_is_down(&kp_power, KEY_POWER);
|
||||
m_prev_play = kp_is_down(&kp_keys, KEY_PLAYPAUSE);
|
||||
last_input_ms = now_ms();
|
||||
menu_arm_touch(800);
|
||||
menu_arm_touch(MENU_TOUCH_GUARD_MS);
|
||||
dirty = 1;
|
||||
/* M5:通知点击按 route_status 产出 click(0 跳转 / 1 NO ROUTE / 2 SOURCE NOT FOUND) */
|
||||
if (click.status == NOTIF_CLICK_STATUS_OK &&
|
||||
@@ -1818,7 +1831,7 @@ static void run_menu(struct app apps[MAX_APPS], int napps, int state,
|
||||
if (dx <= -MENU_SWIPE_THRESH && adx > ady &&
|
||||
tx >= MEOW_EDGE_W && ty >= SB_BAR_H) {
|
||||
logmsg("menu: left-swipe -> Now Playing (dx=%d,dy=%d)", dx, dy);
|
||||
menu_arm_touch(TAP_ARM_DELAY_MS);
|
||||
menu_arm_touch(MENU_TOUCH_GUARD_MS);
|
||||
run_now_playing(apps, napps);
|
||||
/* 重播按键防抖基线,防播放页内电源/音量边沿被 run_menu 误判 */
|
||||
/* 重播音量基线(key_router)+ 本页播放/电源基线 */
|
||||
@@ -1830,7 +1843,7 @@ static void run_menu(struct app apps[MAX_APPS], int napps, int state,
|
||||
m_prev_pwr = kp_is_down(&kp_power, KEY_POWER);
|
||||
m_prev_play = kp_is_down(&kp_keys, KEY_PLAYPAUSE);
|
||||
last_input_ms = now_ms();
|
||||
menu_arm_touch(800);
|
||||
menu_arm_touch(MENU_TOUCH_GUARD_MS);
|
||||
dirty = 1;
|
||||
continue;
|
||||
}
|
||||
@@ -1840,7 +1853,7 @@ static void run_menu(struct app apps[MAX_APPS], int napps, int state,
|
||||
/* 批③:顶栏居右「后台管理」按钮(最高优先级;阻挡非阻塞,返回后重画) */
|
||||
if (menu_hit_bgm_btn(tx, ty)) {
|
||||
logmsg("menu: touch topbar bg-manager button");
|
||||
menu_arm_touch(TAP_ARM_DELAY_MS); /* 幽灵触摸防护 */
|
||||
menu_arm_touch(MENU_TOUCH_GUARD_MS); /* M39:drain + 短守卫 */
|
||||
run_bg_page(apps, napps);
|
||||
/* 重播音量基线(key_router)+ 本页播放/电源基线 */
|
||||
key_router_rebase();
|
||||
@@ -1851,7 +1864,7 @@ static void run_menu(struct app apps[MAX_APPS], int napps, int state,
|
||||
m_prev_pwr = kp_is_down(&kp_power, KEY_POWER);
|
||||
m_prev_play = kp_is_down(&kp_keys, KEY_PLAYPAUSE);
|
||||
last_input_ms = now_ms();
|
||||
menu_arm_touch(800);
|
||||
menu_arm_touch(MENU_TOUCH_GUARD_MS);
|
||||
dirty = 1;
|
||||
continue;
|
||||
}
|
||||
@@ -1863,7 +1876,7 @@ static void run_menu(struct app apps[MAX_APPS], int napps, int state,
|
||||
* 绝不恢复到播放器死帧、绝不对死进程 SIGCONT。 */
|
||||
logmsg("meow mode: BACK TO PLAYER -> confirm reboot");
|
||||
int rb = confirm_reboot_player();
|
||||
menu_arm_touch(TAP_ARM_DELAY_MS); /* 幽灵触摸防护 */
|
||||
menu_arm_touch(MENU_TOUCH_GUARD_MS); /* M39:drain + 短守卫 */
|
||||
dirty = 1;
|
||||
if (rb) { logmsg("reboot-to-player: yes, rebooting"); }
|
||||
/* rb==1 时 reboot 已发起,通常不回;rb==0 留在菜单 */
|
||||
@@ -1878,7 +1891,7 @@ static void run_menu(struct app apps[MAX_APPS], int napps, int state,
|
||||
* 返回」的抬起边沿在 run_menu 被误判为面板单击而熄屏。 */
|
||||
else if (ty >= EXIT_ROW - ROW_H - 4 && ty < EXIT_ROW - ROW_H + ROW_H - 8) {
|
||||
logmsg("menu: touch settings row -> settings page");
|
||||
menu_arm_touch(TAP_ARM_DELAY_MS); /* 幽灵触摸防护:吃掉打开此行的那次触摸 */
|
||||
menu_arm_touch(MENU_TOUCH_GUARD_MS); /* M39:drain + 短守卫 */
|
||||
run_settings_page();
|
||||
/* 重播音量基线(key_router)+ 本页播放/电源基线 */
|
||||
key_router_rebase();
|
||||
@@ -1889,7 +1902,7 @@ static void run_menu(struct app apps[MAX_APPS], int napps, int state,
|
||||
m_prev_pwr = kp_is_down(&kp_power, KEY_POWER);
|
||||
m_prev_play = kp_is_down(&kp_keys, KEY_PLAYPAUSE);
|
||||
last_input_ms = now_ms(); /* 回主界面即视为输入 */
|
||||
menu_arm_touch(800); /* 设置页返回后再忽略近期触摸 */
|
||||
menu_arm_touch(MENU_TOUCH_GUARD_MS); /* M39:drain + 短守卫(原设置页返回 800ms) */
|
||||
dirty = 1; /* 全帧重画应用列表 */
|
||||
}
|
||||
/* M2.18 排查乱跳:改为 else if —— 原为两个独立 if,退出行与
|
||||
|
||||
@@ -178,7 +178,12 @@ static inline const char *meow_str_zh(const char *id, const char *zh)
|
||||
#define MENU_SWIPE_THRESH 65 /* px:抬手位移 >= 阈值判为滑动,不启动行(同 SDK SWIPE_THRESH) */
|
||||
#define NCP_DRAG_ENTER_SLOP 16
|
||||
#define NCP_DRAG_THR_PCT 40
|
||||
#define TAP_ARM_DELAY_MS 300
|
||||
/* M39:launcher 触摸守卫窗口(取代 M2.6「菜单关闭后忽略触摸」800ms / M2.22 的 App 退出后
|
||||
* 1200ms / M2.6 打开子页 300ms)。语义只剩「drain 队列后仍防面板重配尾巴的幽灵按下」,
|
||||
* 不再吞用户看到界面后的第一下:窗口起点固定在 drain 之后,且只覆盖极短的驱动尾巴。
|
||||
* 依据:每次 arm 前都先 menu_drain_touch() 清本进程 touch_fd 队列(evdev 每 fd 各收一份,
|
||||
* App/子页运行期间的全量事件都在本 fd 里,drain 后已无历史事件可重放)。 */
|
||||
#define MENU_TOUCH_GUARD_MS 150
|
||||
#define PM_NUM 6
|
||||
#define PM_R 50 /* 圆钮半径(直径 100) */
|
||||
#define PM_GAPX 130 /* 两列圆心 x 间距(175->305,居中 240) */
|
||||
|
||||
Binary file not shown.
Reference in new issue
Block a user