sdk: 事件分发形式化(§6.4)—— 统一命中/捕获/消费/层间隔离/焦点
根治「焦点/事件穿透」一类反复 bug。此前命中/捕获/消费/层间隔离各处 ad-hoc; 现上收为单一仲裁者(meow_ui_input.c),公共 API 只追加、不删改既有签名。 分发模型: - 触摸沿 z 序自顶向下命中(meow_draw_hit_topdown,owner==active+enable 过滤); - 命中即消费;模态层永远先审(meow_ui_modal_begin/end/active/depth); - down 捕获(meow_ui_gesture_begin/owner/end):命中目标捕获手势直到 up,防滑出误触下层; - 模态存在时下层完全收不到事件——hit_topdown 恒返回模态哨兵(背板消费,不透传); - meow_ui_run 在 TOUCH_DOWN 自动 begin、TAP/SWIPE/LONG_PRESS/NOTIF_PULL 自动 end。 焦点模型: - 唯一持有者(meow_ui_focus_acquire/release/owner/tap); - 点非 focus 区域→释放并通知(meow_ui_focus_tap,list 焦点残留根治); - 滚动容器(list/listview)tap_at 命中行自动 acquire,点外由 run 的 focus_tap 释放; - lost 回调(meow_ui_focus_set_lost_cb)通知转移。 迁移(行为修复,正常交互语义不变): - dialog/sheet → meow_ui_modal_begin/end(模态期下层收不到;叠黑由既有整帧快照+卡片仅重绘保证); - list/listview tap → meow_ui_focus_acquire; - 注入/叠加让位(overlay_input_suppressed)与模态层隔离互补,语义不变。 验证:新穿透矩阵 test_meow_ui_dispatch(M1 模态点下层不触发 / M2 弹层叠开两层层隔离 / M3 捕获手势滑出不误触 / M4 list 焦点点外释放)ALL PASS; 全量回归 widgets/ime_fix/pinyin/overlay_suppress/notif_gesture/sdk_fixes/sb_collapse/ p1p2p3_repro/box/anim/scroll/sdk_input_keys 全 PASS;交叉 -Wall -Wextra 0 warning。 meow_ui.a 新 md5:a9fcfb6eeb07ddbdd48039df4f8f18ce(主会话统一重链,本仓未重链 App)
This commit is contained in:
1 parent
c3abc3fee4
commit
54d2791f48
8 files changed
+428
-3
No files matched your search
@@ -62,6 +62,9 @@
|
||||
#define MAX_DEVS 8
|
||||
#define MEOW_APP_ACTIVITY_FILE "/tmp/meow_app_activity" /* M2.71-bug5:App 活动→launcher 重置息屏计时 */
|
||||
|
||||
/* §6.4 事件分发形式化:手势捕获终点前向声明(meow_input_drain 之前定义后置,见下方实现)。 */
|
||||
void meow_ui_gesture_end(void);
|
||||
|
||||
/* ── 内部事件:系统级「下拉展开通知中心」(M2.5x 接线)──
|
||||
* 触摸状态机在抬手判定处识别「SWIPE_DOWN 起始于顶部热区」后压入;事件循环按系统手势处理
|
||||
* (路由 meow_ui_sys_notif_pull),不下发给 APP 的 on_swipe(顶部热区为系统保留手势)。
|
||||
@@ -197,6 +200,7 @@ void meow_input_drain(void)
|
||||
pthread_mutex_lock(&g_qm);
|
||||
g_qh = 0; g_qt = 0;
|
||||
pthread_mutex_unlock(&g_qm);
|
||||
meow_ui_gesture_end(); /* §6.4:清空队列=丢弃未完成手势(如开 IME/模态前),释放捕获防悬垂 */
|
||||
}
|
||||
|
||||
static void push_ev(int type, int a, int b)
|
||||
@@ -404,6 +408,89 @@ int meow_input_long_press_poll(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ============================================================ */
|
||||
/* §6.4 事件分发形式化:模态作用域 / 自上而下命中 / 手势捕获 / 唯一焦点
|
||||
* ------------------------------------------------------------
|
||||
* 统一仲裁者:把 ad-hoc 的「命中/捕获/消费/层间隔离/焦点」收敛为单一模型。
|
||||
* 兼容:本节 API 只追加;未调用者行为与之前完全一致(命中/捕获仍由 App 自理)。 */
|
||||
/* ============================================================ */
|
||||
|
||||
/* ---- 模态作用域栈(弹层叠开,depth 递增;存在则下层完全收不到触摸)---- */
|
||||
#define MEOW_MODAL_SCOPE_MAX 8
|
||||
static void *g_modal_stack[MEOW_MODAL_SCOPE_MAX];
|
||||
static int g_modal_depth = 0;
|
||||
static char g_modal_sentinel; /* 「模态哨兵」地址:模态存在时 hit_topdown 的返回占位 */
|
||||
|
||||
meow_ui_modal *meow_ui_modal_begin(void)
|
||||
{
|
||||
if (g_modal_depth >= MEOW_MODAL_SCOPE_MAX) return NULL; /* 栈满:不弹(骨架级静默) */
|
||||
void *h = &g_modal_stack[g_modal_depth];
|
||||
g_modal_stack[g_modal_depth++] = h;
|
||||
return (meow_ui_modal *)h;
|
||||
}
|
||||
void meow_ui_modal_end(meow_ui_modal *m)
|
||||
{
|
||||
if (!m) return;
|
||||
for (int i = 0; i < g_modal_depth; i++)
|
||||
if (g_modal_stack[i] == (void *)m) {
|
||||
g_modal_depth = i; /* 弹到 m(含),一次性关上嵌套上层 */
|
||||
return;
|
||||
}
|
||||
}
|
||||
int meow_ui_modal_active(void) { return g_modal_depth > 0; }
|
||||
int meow_ui_modal_depth(void) { return g_modal_depth; }
|
||||
|
||||
/* ---- 自上而下命中(模态门控 + z 降序控件命中)---- */
|
||||
void *meow_ui_hit_topdown(int x, int y)
|
||||
{
|
||||
if (meow_ui_modal_active()) return &g_modal_sentinel; /* 模态存在:恒由模态/背板消费,不透传 */
|
||||
return meow_draw_hit_topdown(x, y);
|
||||
}
|
||||
int meow_ui_widget_hit(meow_widget *w, int x, int y) { return meow_widget_hit(w, x, y); }
|
||||
|
||||
/* ---- 手势捕获(down 捕获直到 up)---- */
|
||||
static void *g_capture = NULL;
|
||||
void *meow_ui_gesture_begin(int x, int y)
|
||||
{
|
||||
void *t = meow_ui_hit_topdown(x, y);
|
||||
g_capture = t; /* 覆盖旧捕获(一次手势至多一个目标;命中 NULL=未捕获,move/up 照旧) */
|
||||
return g_capture;
|
||||
}
|
||||
void *meow_ui_gesture_owner(void) { return g_capture; }
|
||||
void meow_ui_gesture_end(void) { g_capture = NULL; }
|
||||
|
||||
/* ---- 唯一焦点(list 焦点残留根治 / 滚动容器间转移)---- */
|
||||
static void *g_focus = NULL;
|
||||
static meow_ui_focus_lost_fn g_focus_lost = NULL;
|
||||
static void *g_focus_lost_ctx = NULL;
|
||||
|
||||
void meow_ui_focus_set_lost_cb(meow_ui_focus_lost_fn cb, void *ctx)
|
||||
{ g_focus_lost = cb; g_focus_lost_ctx = ctx; }
|
||||
void *meow_ui_focus_owner(void) { return g_focus; }
|
||||
int meow_ui_focus_acquire(void *owner)
|
||||
{
|
||||
if (!owner) return 0;
|
||||
void *prev = g_focus;
|
||||
g_focus = owner;
|
||||
if (prev && prev != owner && g_focus_lost) g_focus_lost(prev, g_focus_lost_ctx);
|
||||
return 1;
|
||||
}
|
||||
int meow_ui_focus_release(void *owner)
|
||||
{
|
||||
if (!g_focus) return 0;
|
||||
if (owner && owner != g_focus) return 0;
|
||||
void *prev = g_focus;
|
||||
g_focus = NULL;
|
||||
if (g_focus_lost) g_focus_lost(prev, g_focus_lost_ctx);
|
||||
return 1;
|
||||
}
|
||||
void meow_ui_focus_tap(int x, int y)
|
||||
{
|
||||
if (!g_focus) return;
|
||||
void *hit = meow_ui_hit_topdown(x, y);
|
||||
if (hit != g_focus) meow_ui_focus_release(g_focus); /* 点非焦点区 → 释放并通知 */
|
||||
}
|
||||
|
||||
/* ---- 系统键(音量/媒体)去重 + EVIOCGKEY 状态轮询 ----
|
||||
* M2.55/agent-217 之后 SDK 在输入线程消化系统键语义;但真机物理键(jz adc keyboard event2、
|
||||
* md-gpio-keys event0、earpods_adc event3)的按下不一定进入 evdev 事件流(事件流可被其它进程
|
||||
@@ -620,6 +707,10 @@ void meow_ui_run(const meow_ui_events *ev)
|
||||
meow_ui_swipe_hint(-1);
|
||||
meow_ui_flush_region(0, meow_ui_statusbar_height(), meow_ui_width(), 6);
|
||||
if (meow_ime_active() && meow_ime_handle_event(&e)) continue;
|
||||
/* §6.4 手势结束(抬手边沿)+ 焦点点外释放:先释放手势捕获(move/up 已结束),
|
||||
* 再对落点做「命中焦点所有者→保位;否则释放并通知」(list 焦点残留根治)。 */
|
||||
meow_ui_gesture_end();
|
||||
meow_ui_focus_tap(e.a, e.b);
|
||||
/* §6.1 触摸分流:③ 系统全局(IME/状态栏…已在上面消费) → ② App 全局控件
|
||||
* (命中返回 1=消费,否则落到 ① active Activity 页面控件)。 */
|
||||
if (meow_ui_global_hit(e.a, e.b)) continue;
|
||||
@@ -633,6 +724,7 @@ void meow_ui_run(const meow_ui_events *ev)
|
||||
meow_ui_flush_region(0, meow_ui_statusbar_height(), meow_ui_width(), 6);
|
||||
/* 拼音 IME 候选栏横滑翻页(英文模式 handle_event 返回 0 → 沿用既有行为)。 */
|
||||
if (meow_ime_active() && meow_ime_handle_event(&e)) continue;
|
||||
meow_ui_gesture_end(); /* §6.4:抬手(滑动)边沿,释放手势捕获 */
|
||||
/* A-0 全局左缘返回(方案A):
|
||||
* - APP 注册 on_swipe → APP 接管,自行决定(meow_ui_request_exit / 页内返回);
|
||||
* - APP 未注册 on_swipe 且非全屏(sb_active)→ SDK 默认退出 app(返回=退出);
|
||||
@@ -652,6 +744,7 @@ void meow_ui_run(const meow_ui_events *ev)
|
||||
* 起点若同时落在左缘,拖动期可能已画过 MEOW_EV_SWIPE_PROGRESS 左缘指示条,
|
||||
* 抬手定判为 NOTIF_PULL 后须清掉(否则通知中心打开后残留返回条)。 */
|
||||
meow_ui_swipe_hint(-1);
|
||||
meow_ui_gesture_end(); /* §6.4:抬手边沿,释放手势捕获 */
|
||||
meow_ui_sys_notif_pull(e.a); /* e.a = 手势按下原点 Y */
|
||||
} else if (e.type == MEOW_EV_TOUCH_DOWN || e.type == MEOW_EV_TOUCH_MOVE) {
|
||||
/* M2.71-bug2/6:拖动过程(跟手)。IME 弹出时触摸优先喂键盘(键盘覆盖层拦截,
|
||||
@@ -660,6 +753,9 @@ void meow_ui_run(const meow_ui_events *ev)
|
||||
* IME 打开时先把压点喂给拼音(候选栏滑动翻页判定 g_ime_swipe_y),再丢弃。 */
|
||||
if (in_startup) continue;
|
||||
if (meow_ime_active()) { meow_ime_handle_event(&e); continue; }
|
||||
/* §6.4:down 捕获——命中目标捕获整个手势直到 up;随后 move/up 只发给该目标
|
||||
* (防滑出后误触发下层)。真实触发放置捕获(宿主直调 on_touch_* 不受影响)。 */
|
||||
if (e.type == MEOW_EV_TOUCH_DOWN) meow_ui_gesture_begin(e.a, e.b);
|
||||
if (g_events_set && g_events.on_touch_down && e.type == MEOW_EV_TOUCH_DOWN)
|
||||
g_events.on_touch_down(e.a, e.b);
|
||||
if (g_events_set && g_events.on_touch_move && e.type == MEOW_EV_TOUCH_MOVE)
|
||||
@@ -686,6 +782,7 @@ void meow_ui_run(const meow_ui_events *ev)
|
||||
if (in_startup) continue;
|
||||
/* 拼音 IME 打开:长按退格清空字段(英文模式 handle_event 返回 0 → 走既有长按回调)。 */
|
||||
if (meow_ime_active() && meow_ime_handle_event(&e)) continue;
|
||||
meow_ui_gesture_end(); /* §6.4:长按已触发,其抬手不再 TAP/SWIPE——顺手释放捕获 */
|
||||
if (g_long_press_cb) g_long_press_cb(e.a, e.b);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user