From cae03feb7ca9adc6b3c362e2ded4c3e5b3d8c6e4 Mon Sep 17 00:00:00 2001 From: yibo Date: Mon, 25 May 2026 16:04:44 +0800 Subject: [PATCH] feat: A11y chat list 滚动查找(方案 A + C 兜底) --- wechat_plain/scripts/lsposed-wechat-sendmsg/app/src/main/java/com/hermes/wechat/xposed/accessibility/HermesAccessibilityService.java | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/wechat_plain/scripts/lsposed-wechat-sendmsg/app/src/main/java/com/hermes/wechat/xposed/accessibility/HermesAccessibilityService.java b/wechat_plain/scripts/lsposed-wechat-sendmsg/app/src/main/java/com/hermes/wechat/xposed/accessibility/HermesAccessibilityService.java index 7be720c..38282c5 100644 --- a/wechat_plain/scripts/lsposed-wechat-sendmsg/app/src/main/java/com/hermes/wechat/xposed/accessibility/HermesAccessibilityService.java +++ b/wechat_plain/scripts/lsposed-wechat-sendmsg/app/src/main/java/com/hermes/wechat/xposed/accessibility/HermesAccessibilityService.java @@ -54,6 +54,8 @@ public class HermesAccessibilityService extends AccessibilityService { private String pendingContent = null; private String pendingQuoteText = null; // 要引用的消息片段(substring 匹配 bkl text),null=不引用 private String pendingAtSender = null; // 要 @ 的群成员显示名,null=不 @ + private int chatListScrolls = 0; // chat list 滚动查找次数(每条消息重置) + private static final int MAX_CHATLIST_SCROLLS = 6; // 滚动上限,超了才退搜索 @Override protected void onServiceConnected() { @@ -108,6 +110,7 @@ public class HermesAccessibilityService extends AccessibilityService { pendingContent = content; pendingQuoteText = (quoteText != null && !quoteText.isEmpty()) ? quoteText : null; pendingAtSender = (atSender != null && !atSender.isEmpty()) ? atSender : null; + chatListScrolls = 0; // 拉起微信主界面(如果不在则会启动;如果在则保留当前 fragment 状态) Intent launch = getPackageManager().getLaunchIntentForPackage("com.tencent.mm"); @@ -210,9 +213,19 @@ public class HermesAccessibilityService extends AccessibilityService { row.recycle(); root.recycle(); mainHandler.postDelayed(() -> driveStateMachine(transitionCount + 1), 2200); + } else if (chatListScrolls < MAX_CHATLIST_SCROLLS) { + // A 方案:目标不在可见列表 → 滚动列表逐屏找(会话一定在列表里,只是被挤下去) + chatListScrolls++; + Log.i(TAG, "FSM: " + pendingToUserDisplayName + " not visible, scrolling chat list (" + + chatListScrolls + "/" + MAX_CHATLIST_SCROLLS + ")"); + root.recycle(); + // 滚动不计入 transitionCount(用 chatListScrolls 自己的上限防死循环) + scrollChatListDown(() -> mainHandler.postDelayed( + () -> driveStateMachine(transitionCount), 700)); } else { + // C 方案:滚到底还找不到 → 退回搜索 Log.w(TAG, "FSM: " + pendingToUserDisplayName - + " not in visible chat list, falling back to search"); + + " not found after " + chatListScrolls + " scrolls, falling back to search"); performSearch(root); // performSearch owns root from here } @@ -502,6 +515,22 @@ public class HermesAccessibilityService extends AccessibilityService { } } + /** 上滑会话列表(露出下面更多会话),用合成手势。完成后回调。 */ + private void scrollChatListDown(Runnable onCompleted) { + Path path = new Path(); + // 从屏幕中下部往上滑(露出列表下方的会话);坐标按竖屏估算,避开顶部搜索栏和底部 nav + path.moveTo(540, 1500); + path.lineTo(540, 600); + GestureDescription gesture = new GestureDescription.Builder() + .addStroke(new GestureDescription.StrokeDescription(path, 0, 300)) + .build(); + boolean dispatched = dispatchGesture(gesture, new GestureResultCallback() { + @Override public void onCompleted(GestureDescription g) { if (onCompleted != null) onCompleted.run(); } + @Override public void onCancelled(GestureDescription g) { if (onCompleted != null) onCompleted.run(); } + }, mainHandler); + if (!dispatched && onCompleted != null) onCompleted.run(); + } + /** 在长按菜单中点击「引用」 — 搜索所有可见窗口(菜单可能在 popup window 里) */ private void clickQuoteMenuItem() { AccessibilityNodeInfo menuItem = findClickableByTextAllWindows(MENU_QUOTE_TEXT); -- libgit2 0.21.4