feat(desktop-wake): add wecom_search profile for SearchResultWindow2 (1.2.6)
All checks were successful
Publish Python Package to Gitea / publish (push) Successful in 27s
All checks were successful
Publish Python Package to Gitea / publish (push) Successful in 27s
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "jiangchang-platform-kit"
|
name = "jiangchang-platform-kit"
|
||||||
version = "1.2.5"
|
version = "1.2.6"
|
||||||
description = "匠厂平台共享组件:Skill 实体 SDK + 桌面应用自动化 SDK + 桌面 UIA 暖树"
|
description = "匠厂平台共享组件:Skill 实体 SDK + 桌面应用自动化 SDK + 桌面 UIA 暖树"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
# jiangchang_desktop_wake 验收(ensure 主路径,1.2.5+)
|
# jiangchang_desktop_wake 验收(ensure 主路径,1.2.6+)
|
||||||
|
|
||||||
正式对外路径是 **`ensure`**(内部:`activate` → `desktop-wake --mode n2-wake` → `probe`)。
|
正式对外路径是 **`ensure`**(内部:`activate` → `desktop-wake --mode n2-wake` → `probe`)。
|
||||||
`n2-wake`:**仅 OBJID_CLIENT** 走 DuiLib;不做进程内 FindAll、不同步 GETOBJECT、不 SPI 读屏;判暖只看进程外 probe。
|
`n2-wake`:**仅 OBJID_CLIENT** 走 DuiLib;不做进程内 FindAll、不同步 GETOBJECT、不 SPI 读屏;判暖只看进程外 probe。
|
||||||
`c2` / `inject` 仅诊断用。
|
`c2` / `inject` 仅诊断用。
|
||||||
|
|
||||||
|
| profile | 窗 | 1.2.6 |
|
||||||
|
|---|---|---|
|
||||||
|
| `wecom` | `WeWorkWindow` | 主窗(原有) |
|
||||||
|
| `wecom_search` | `SearchResultWindow2` | 搜索联系人浮层;不 Maximize;markers=`search_result`,`user_item` |
|
||||||
|
|
||||||
## 0. 编译(企微先完全退出,含托盘)
|
## 0. 编译(企微先完全退出,含托盘)
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
@@ -72,7 +77,28 @@ python -m jiangchang_desktop_wake probe --profile wecom
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## C. 单测(不依赖企微窗)
|
## C. 搜索浮层 wecom_search(1.2.6+)
|
||||||
|
|
||||||
|
1. 打开企微主窗并登录;在搜索框输入联系人,**保持搜索结果浮层打开**(标题/类名 `SearchResultWindow2`)。
|
||||||
|
2. 验收:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd D:\OpenClaw\client-jiangchang\jiangchang-platform-kit
|
||||||
|
$env:PYTHONPATH = ".\src"
|
||||||
|
python -m jiangchang_desktop_wake probe --profile wecom_search
|
||||||
|
python -m jiangchang_desktop_wake ensure --profile wecom_search
|
||||||
|
python -m jiangchang_desktop_wake probe --profile wecom_search
|
||||||
|
```
|
||||||
|
|
||||||
|
| 期望 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| ensure 退出码 `0` | 浮层已暖 |
|
||||||
|
| `warm=true` | markers 含 `search_result` / `user_item`(或 findall 足够) |
|
||||||
|
| `WINDOW_NOT_FOUND` | 浮层未打开——先展开搜索结果再测 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## D. 单测(不依赖企微窗)
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
cd D:\OpenClaw\client-jiangchang\jiangchang-platform-kit
|
cd D:\OpenClaw\client-jiangchang\jiangchang-platform-kit
|
||||||
@@ -82,7 +108,7 @@ python -m unittest discover -s tests/desktop_wake -v
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## D. 诊断命令(非主路径)
|
## E. 诊断命令(非主路径)
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
python -m jiangchang_desktop_wake inject --profile wecom
|
python -m jiangchang_desktop_wake inject --profile wecom
|
||||||
|
|||||||
@@ -22,15 +22,28 @@ pip install uiautomation
|
|||||||
|
|
||||||
# 正式 API(技能 / 拾取应调这个)
|
# 正式 API(技能 / 拾取应调这个)
|
||||||
python -m jiangchang_desktop_wake ensure --profile wecom
|
python -m jiangchang_desktop_wake ensure --profile wecom
|
||||||
|
|
||||||
|
# 搜索结果浮层(先在企微搜索框输入并展开联系人列表)
|
||||||
|
python -m jiangchang_desktop_wake ensure --profile wecom_search
|
||||||
|
python -m jiangchang_desktop_wake probe --profile wecom_search
|
||||||
```
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from jiangchang_desktop_wake import ensure_ui_ready, probe
|
from jiangchang_desktop_wake import ensure_ui_ready, probe
|
||||||
|
|
||||||
r = ensure_ui_ready("wecom") # 仍冷则抛 DesktopWakeError
|
r = ensure_ui_ready("wecom") # 主窗;仍冷则抛 DesktopWakeError
|
||||||
print(r.warm, r.probe_after.findall_count)
|
print(r.warm, r.probe_after.findall_count)
|
||||||
|
|
||||||
|
# 搜索浮层 SearchResultWindow2(需已打开搜索结果)
|
||||||
|
rs = ensure_ui_ready("wecom_search")
|
||||||
|
print(rs.warm, rs.probe_after.findall_count, rs.probe_after.markers_found)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
| profile | 窗 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `wecom` | `WeWorkWindow` | 主窗;markers=`con_op`,`searchedit` |
|
||||||
|
| `wecom_search` | `SearchResultWindow2` | 搜索联系人浮层;markers=`search_result`,`user_item`;不 Maximize |
|
||||||
|
|
||||||
| CLI | 退出码 |
|
| CLI | 退出码 |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `ensure` | `0` 已暖;非 0 仍冷或异常 |
|
| `ensure` | `0` 已暖;非 0 仍冷或异常 |
|
||||||
|
|||||||
@@ -42,6 +42,17 @@ _BUILTIN = {
|
|||||||
"native_helper": "desktop-wake.exe",
|
"native_helper": "desktop-wake.exe",
|
||||||
"native_args": ["wecom", "0x{hwnd_hex}", "--mode", "n1"],
|
"native_args": ["wecom", "0x{hwnd_hex}", "--mode", "n1"],
|
||||||
},
|
},
|
||||||
|
"wecom_search": {
|
||||||
|
"id": "wecom_search",
|
||||||
|
"description": "企业微信搜索结果浮层 SearchResultWindow2",
|
||||||
|
"window_class": "SearchResultWindow2",
|
||||||
|
"warm_min_findall": 20,
|
||||||
|
"warm_markers": ["search_result", "user_item"],
|
||||||
|
"activate_maximize": False,
|
||||||
|
"wake_strategies": ["activate", "native_helper"],
|
||||||
|
"native_helper": "desktop-wake.exe",
|
||||||
|
"native_args": ["wecom", "0x{hwnd_hex}", "--mode", "n2-wake"],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
14
src/jiangchang_desktop_wake/profiles/wecom_search.json
Normal file
14
src/jiangchang_desktop_wake/profiles/wecom_search.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"id": "wecom_search",
|
||||||
|
"description": "企业微信搜索结果浮层 SearchResultWindow2(联系人列表 user_item)",
|
||||||
|
"window_class": "SearchResultWindow2",
|
||||||
|
"warm_min_findall": 20,
|
||||||
|
"warm_markers": ["search_result", "user_item"],
|
||||||
|
"activate_maximize": false,
|
||||||
|
"wake_strategies": [
|
||||||
|
"activate",
|
||||||
|
"native_helper"
|
||||||
|
],
|
||||||
|
"native_helper": "desktop-wake.exe",
|
||||||
|
"native_args": ["wecom", "0x{hwnd_hex}", "--mode", "n2-wake"]
|
||||||
|
}
|
||||||
@@ -27,9 +27,14 @@ class Profile:
|
|||||||
)
|
)
|
||||||
native_helper: Optional[str] = None
|
native_helper: Optional[str] = None
|
||||||
native_args: list[str] = field(default_factory=list)
|
native_args: list[str] = field(default_factory=list)
|
||||||
|
# 浮层窗(如搜索结果)禁止 Maximize,避免打乱搜索态
|
||||||
|
activate_maximize: bool = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, data: dict[str, Any]) -> "Profile":
|
def from_dict(cls, data: dict[str, Any]) -> "Profile":
|
||||||
|
maximize = data.get("activate_maximize")
|
||||||
|
if maximize is None:
|
||||||
|
maximize = True
|
||||||
return cls(
|
return cls(
|
||||||
id=str(data.get("id") or "unknown"),
|
id=str(data.get("id") or "unknown"),
|
||||||
description=str(data.get("description") or ""),
|
description=str(data.get("description") or ""),
|
||||||
@@ -49,6 +54,7 @@ class Profile:
|
|||||||
),
|
),
|
||||||
native_helper=data.get("native_helper"),
|
native_helper=data.get("native_helper"),
|
||||||
native_args=list(data.get("native_args") or []),
|
native_args=list(data.get("native_args") or []),
|
||||||
|
activate_maximize=bool(maximize),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,9 @@ StrategyFn = Callable[[int, Profile], Tuple[str, str]]
|
|||||||
|
|
||||||
|
|
||||||
def _strategy_activate(hwnd: int, profile: Profile) -> Tuple[str, str]:
|
def _strategy_activate(hwnd: int, profile: Profile) -> Tuple[str, str]:
|
||||||
activate_hwnd(hwnd, maximize=True)
|
maximize = bool(getattr(profile, "activate_maximize", True))
|
||||||
return "foreground+maximize", "ok"
|
activate_hwnd(hwnd, maximize=maximize)
|
||||||
|
return ("foreground+maximize" if maximize else "foreground"), "ok"
|
||||||
|
|
||||||
|
|
||||||
def _strategy_wm_getobject(hwnd: int, _profile: Profile) -> Tuple[str, str]:
|
def _strategy_wm_getobject(hwnd: int, _profile: Profile) -> Tuple[str, str]:
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ class ProfileTests(unittest.TestCase):
|
|||||||
ids = list_profiles()
|
ids = list_profiles()
|
||||||
self.assertIn("wecom", ids)
|
self.assertIn("wecom", ids)
|
||||||
self.assertIn("generic", ids)
|
self.assertIn("generic", ids)
|
||||||
|
self.assertIn("wecom_search", ids)
|
||||||
|
|
||||||
def test_load_wecom(self):
|
def test_load_wecom(self):
|
||||||
p = load_profile("wecom")
|
p = load_profile("wecom")
|
||||||
@@ -24,6 +25,17 @@ class ProfileTests(unittest.TestCase):
|
|||||||
self.assertGreaterEqual(p.warm_min_findall, 50)
|
self.assertGreaterEqual(p.warm_min_findall, 50)
|
||||||
self.assertIn("native_helper", p.wake_strategies)
|
self.assertIn("native_helper", p.wake_strategies)
|
||||||
self.assertIn("n2-wake", p.native_args or [])
|
self.assertIn("n2-wake", p.native_args or [])
|
||||||
|
self.assertTrue(p.activate_maximize)
|
||||||
|
|
||||||
|
def test_load_wecom_search(self):
|
||||||
|
p = load_profile("wecom_search")
|
||||||
|
self.assertEqual(p.id, "wecom_search")
|
||||||
|
self.assertEqual(p.window_class, "SearchResultWindow2")
|
||||||
|
self.assertIn("search_result", p.warm_markers)
|
||||||
|
self.assertIn("user_item", p.warm_markers)
|
||||||
|
self.assertFalse(p.activate_maximize)
|
||||||
|
self.assertIn("native_helper", p.wake_strategies)
|
||||||
|
self.assertIn("n2-wake", p.native_args or [])
|
||||||
|
|
||||||
def test_unknown_profile(self):
|
def test_unknown_profile(self):
|
||||||
from jiangchang_desktop_wake.errors import DesktopWakeError
|
from jiangchang_desktop_wake.errors import DesktopWakeError
|
||||||
|
|||||||
Reference in New Issue
Block a user