ok-script 0.0.8__tar.gz → 0.0.10__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. {ok-script-0.0.8 → ok-script-0.0.10}/PKG-INFO +10 -7
  2. {ok-script-0.0.8 → ok-script-0.0.10}/README.md +9 -6
  3. {ok-script-0.0.8 → ok-script-0.0.10}/ok/OK.py +13 -6
  4. {ok-script-0.0.8 → ok-script-0.0.10}/ok/capture/HwndWindow.py +6 -2
  5. ok-script-0.0.10/ok/capture/adb/ADBCaptureMethod.py +57 -0
  6. {ok-script-0.0.8 → ok-script-0.0.10}/ok/capture/adb/DeviceManager.py +90 -76
  7. {ok-script-0.0.8 → ok-script-0.0.10}/ok/capture/windows/WindowsGraphicsCaptureMethod.py +4 -2
  8. {ok-script-0.0.8 → ok-script-0.0.10}/ok/feature/Box.py +24 -9
  9. {ok-script-0.0.8 → ok-script-0.0.10}/ok/feature/FeatureSet.py +1 -1
  10. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/App.py +9 -7
  11. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/Communicate.py +6 -2
  12. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/MainWindow.py +5 -1
  13. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/__init__.py +2 -0
  14. ok-script-0.0.10/ok/gui/about/AboutTab.py +16 -0
  15. ok-script-0.0.10/ok/gui/debug/DebugTab.py +31 -0
  16. ok-script-0.0.10/ok/gui/debug/FrameWidget.py +58 -0
  17. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/debug/LoggerWidget.py +1 -0
  18. ok-script-0.0.10/ok/gui/debug/Screenshot.py +140 -0
  19. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/loading/LoadingWindow.py +46 -11
  20. ok-script-0.0.10/ok/gui/loading/SelectCaptureListView.py +31 -0
  21. ok-script-0.0.10/ok/gui/loading/SelectHwndWindow.py +70 -0
  22. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/resources.py +140 -128
  23. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/widget/RoundCornerContainer.py +1 -0
  24. ok-script-0.0.10/ok/interaction/BaseInteraction.py +24 -0
  25. {ok-script-0.0.8 → ok-script-0.0.10}/ok/logging/Logger.py +0 -1
  26. {ok-script-0.0.8 → ok-script-0.0.10}/ok/ocr/OCR.py +2 -2
  27. {ok-script-0.0.8 → ok-script-0.0.10}/ok/scene/Scene.py +0 -5
  28. {ok-script-0.0.8 → ok-script-0.0.10}/ok/task/BaseTask.py +8 -3
  29. {ok-script-0.0.8 → ok-script-0.0.10}/ok/task/ExecutorOperation.py +26 -22
  30. {ok-script-0.0.8 → ok-script-0.0.10}/ok/task/TaskExecutor.py +19 -14
  31. ok-script-0.0.10/ok/util/__init__.py +0 -0
  32. ok-script-0.0.10/ok/util/path.py +77 -0
  33. {ok-script-0.0.8 → ok-script-0.0.10}/ok_script.egg-info/PKG-INFO +10 -7
  34. {ok-script-0.0.8 → ok-script-0.0.10}/ok_script.egg-info/SOURCES.txt +5 -0
  35. {ok-script-0.0.8 → ok-script-0.0.10}/setup.py +2 -2
  36. ok-script-0.0.8/ok/capture/adb/ADBCaptureMethod.py +0 -29
  37. ok-script-0.0.8/ok/gui/debug/DebugTab.py +0 -37
  38. ok-script-0.0.8/ok/gui/debug/FrameWidget.py +0 -125
  39. ok-script-0.0.8/ok/interaction/BaseInteraction.py +0 -36
  40. ok-script-0.0.8/ok/util/path.py +0 -37
  41. {ok-script-0.0.8 → ok-script-0.0.10}/ok/__init__.py +0 -0
  42. {ok-script-0.0.8 → ok-script-0.0.10}/ok/capture/BaseCaptureMethod.py +0 -0
  43. {ok-script-0.0.8 → ok-script-0.0.10}/ok/capture/__init__.py +0 -0
  44. {ok-script-0.0.8 → ok-script-0.0.10}/ok/capture/adb/__init__.py +0 -0
  45. {ok-script-0.0.8 → ok-script-0.0.10}/ok/capture/adb/bin/__init__.py +0 -0
  46. {ok-script-0.0.8 → ok-script-0.0.10}/ok/capture/adb/targets.py +0 -0
  47. {ok-script-0.0.8 → ok-script-0.0.10}/ok/capture/adb/vbox.py +0 -0
  48. {ok-script-0.0.8 → ok-script-0.0.10}/ok/capture/windows/__init__.py +0 -0
  49. {ok-script-0.0.8 → ok-script-0.0.10}/ok/capture/windows/d3d11.py +0 -0
  50. {ok-script-0.0.8 → ok-script-0.0.10}/ok/capture/windows/utils.py +0 -0
  51. {ok-script-0.0.8 → ok-script-0.0.10}/ok/capture/windows/window.py +0 -0
  52. {ok-script-0.0.8 → ok-script-0.0.10}/ok/color/Color.py +0 -0
  53. {ok-script-0.0.8 → ok-script-0.0.10}/ok/color/__init__.py +0 -0
  54. {ok-script-0.0.8 → ok-script-0.0.10}/ok/config/Config.py +0 -0
  55. {ok-script-0.0.8 → ok-script-0.0.10}/ok/config/InfoDict.py +0 -0
  56. {ok-script-0.0.8 → ok-script-0.0.10}/ok/config/__init__.py +0 -0
  57. {ok-script-0.0.8 → ok-script-0.0.10}/ok/feature/Feature.py +0 -0
  58. {ok-script-0.0.8 → ok-script-0.0.10}/ok/feature/FindFeature.py +0 -0
  59. {ok-script-0.0.8 → ok-script-0.0.10}/ok/feature/__init__.py +0 -0
  60. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/TabTitles.py +0 -0
  61. {ok-script-0.0.8/ok/gui/debug → ok-script-0.0.10/ok/gui/about}/__init__.py +0 -0
  62. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/debug/AspectRatioWidget.py +0 -0
  63. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/debug/InfoWidget.py +0 -0
  64. {ok-script-0.0.8/ok/gui/i18n → ok-script-0.0.10/ok/gui/debug}/__init__.py +0 -0
  65. {ok-script-0.0.8/ok/gui/icon → ok-script-0.0.10/ok/gui/i18n}/__init__.py +0 -0
  66. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/i18n/path.py +0 -0
  67. {ok-script-0.0.8/ok/gui/loading → ok-script-0.0.10/ok/gui/icon}/__init__.py +0 -0
  68. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/icon/icon.py +0 -0
  69. {ok-script-0.0.8/ok/gui/overlay → ok-script-0.0.10/ok/gui/loading}/__init__.py +0 -0
  70. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/overlay/OverlayWindow.py +0 -0
  71. {ok-script-0.0.8/ok/gui/tasks → ok-script-0.0.10/ok/gui/overlay}/__init__.py +0 -0
  72. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/tasks/ConfigItemFactory.py +0 -0
  73. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/tasks/StartButton.py +0 -0
  74. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/tasks/TaskOpButton.py +0 -0
  75. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/tasks/TaskTab.py +0 -0
  76. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/tasks/TooltipTableWidget.py +0 -0
  77. {ok-script-0.0.8/ok/gui/util → ok-script-0.0.10/ok/gui/tasks}/__init__.py +0 -0
  78. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/util/Alert.py +0 -0
  79. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/util/InitWorker.py +0 -0
  80. {ok-script-0.0.8/ok/gui/widget → ok-script-0.0.10/ok/gui/util}/__init__.py +0 -0
  81. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/widget/ListTableWidgetItem.py +0 -0
  82. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/widget/NumericTableWidgetItem.py +0 -0
  83. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/widget/TabWidget.py +0 -0
  84. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/widget/UpdateConfigWidgetItem.py +0 -0
  85. {ok-script-0.0.8 → ok-script-0.0.10}/ok/gui/widget/YesNonWidgetItem.py +0 -0
  86. {ok-script-0.0.8/ok/interaction → ok-script-0.0.10/ok/gui/widget}/__init__.py +0 -0
  87. {ok-script-0.0.8 → ok-script-0.0.10}/ok/interaction/ADBInteraction.py +0 -0
  88. {ok-script-0.0.8 → ok-script-0.0.10}/ok/interaction/Win32Interaction.py +0 -0
  89. {ok-script-0.0.8/ok/logging → ok-script-0.0.10/ok/interaction}/__init__.py +0 -0
  90. {ok-script-0.0.8/ok/ocr → ok-script-0.0.10/ok/logging}/__init__.py +0 -0
  91. {ok-script-0.0.8/ok/predict → ok-script-0.0.10/ok/ocr}/__init__.py +0 -0
  92. {ok-script-0.0.8/ok/rotypes/Windows/Media → ok-script-0.0.10/ok/predict}/__init__.py +0 -0
  93. {ok-script-0.0.8 → ok-script-0.0.10}/ok/predict/predict.py +0 -0
  94. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/Windows/Foundation/Collections.py +0 -0
  95. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/Windows/Foundation/__init__.py +0 -0
  96. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/Windows/Globalization/__init__.py +0 -0
  97. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/Windows/Graphics/Capture/__init__.py +0 -0
  98. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/Windows/Graphics/DirectX/Direct3D11/__init__.py +0 -0
  99. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/Windows/Graphics/DirectX/__init__.py +0 -0
  100. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/Windows/Graphics/Imaging/__init__.py +0 -0
  101. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/Windows/Graphics/__init__.py +0 -0
  102. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/Windows/Media/Ocr/__init__.py +0 -0
  103. {ok-script-0.0.8/ok/rotypes/Windows/Security → ok-script-0.0.10/ok/rotypes/Windows/Media}/__init__.py +0 -0
  104. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/Windows/Security/Cryptography/__init__.py +0 -0
  105. {ok-script-0.0.8/ok/rotypes/Windows/Storage → ok-script-0.0.10/ok/rotypes/Windows/Security}/__init__.py +0 -0
  106. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/Windows/Storage/Streams/__init__.py +0 -0
  107. {ok-script-0.0.8/ok/rotypes/Windows → ok-script-0.0.10/ok/rotypes/Windows/Storage}/__init__.py +0 -0
  108. {ok-script-0.0.8/ok/save → ok-script-0.0.10/ok/rotypes/Windows}/__init__.py +0 -0
  109. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/__init__.py +0 -0
  110. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/delegate.py +0 -0
  111. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/export.py +0 -0
  112. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/idldsl.py +0 -0
  113. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/inspectable.py +0 -0
  114. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/roapi.py +0 -0
  115. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/types.py +0 -0
  116. {ok-script-0.0.8 → ok-script-0.0.10}/ok/rotypes/winstring.py +0 -0
  117. {ok-script-0.0.8 → ok-script-0.0.10}/ok/save/BlackBarProcessor.py +0 -0
  118. {ok-script-0.0.8 → ok-script-0.0.10}/ok/save/PostProcessor.py +0 -0
  119. {ok-script-0.0.8 → ok-script-0.0.10}/ok/save/SaveByInterval.py +0 -0
  120. {ok-script-0.0.8 → ok-script-0.0.10}/ok/save/SaveByKeyPress.py +0 -0
  121. {ok-script-0.0.8 → ok-script-0.0.10}/ok/save/SaveMethodBase.py +0 -0
  122. {ok-script-0.0.8/ok/scene → ok-script-0.0.10/ok/save}/__init__.py +0 -0
  123. {ok-script-0.0.8 → ok-script-0.0.10}/ok/scene/FeatureScene.py +0 -0
  124. {ok-script-0.0.8/ok/stats → ok-script-0.0.10/ok/scene}/__init__.py +0 -0
  125. {ok-script-0.0.8 → ok-script-0.0.10}/ok/stats/StreamStats.py +0 -0
  126. {ok-script-0.0.8/ok/task → ok-script-0.0.10/ok/stats}/__init__.py +0 -0
  127. {ok-script-0.0.8 → ok-script-0.0.10}/ok/task/FindFeatureTask.py +0 -0
  128. {ok-script-0.0.8/ok/util → ok-script-0.0.10/ok/task}/__init__.py +0 -0
  129. {ok-script-0.0.8 → ok-script-0.0.10}/ok/util/json.py +0 -0
  130. {ok-script-0.0.8 → ok-script-0.0.10}/ok/util/list.py +0 -0
  131. {ok-script-0.0.8 → ok-script-0.0.10}/ok/util/thread.py +0 -0
  132. {ok-script-0.0.8 → ok-script-0.0.10}/ok/util/win32_process.py +0 -0
  133. {ok-script-0.0.8 → ok-script-0.0.10}/ok/util/yaml.py +0 -0
  134. {ok-script-0.0.8 → ok-script-0.0.10}/ok_script.egg-info/dependency_links.txt +0 -0
  135. {ok-script-0.0.8 → ok-script-0.0.10}/ok_script.egg-info/requires.txt +0 -0
  136. {ok-script-0.0.8 → ok-script-0.0.10}/ok_script.egg-info/top_level.txt +0 -0
  137. {ok-script-0.0.8 → ok-script-0.0.10}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ok-script
3
- Version: 0.0.8
3
+ Version: 0.0.10
4
4
  Summary: Automation with Computer Vision for Python
5
5
  Home-page: https://github.com/ok-oldking/ok-script
6
6
  Author: ok-oldking
@@ -18,15 +18,18 @@ Requires-Dist: pywin32==306
18
18
  Requires-Dist: typing-extensions~=4.10.0
19
19
  Requires-Dist: PySide6~=6.6.2
20
20
 
21
- # autoui
21
+ # ok-script
22
22
 
23
- This project aims to provide a universal framework for developing automation tool for PC/Android games, running in
24
- windows,
25
- emulator, or physical Android Phone. Currently still working in progress, there is a working
23
+ 类似于AirScript, 使用Python
26
24
 
27
- ## Showcase
25
+ ## 优势
28
26
 
29
- ![docs/img_showcase.png](docs/img_showcase.png)
27
+ 1. 开源免费, 依赖库均为开源方案, 支持pip install任何第三方库
28
+ 2. 代码和打包流程完全由开发者控制, 不会上传服务器, 没有安全性隐患, 不容易被侦测和识别
29
+ 3. 一套代码即可支持Windows安卓模拟器/ADB连接的虚拟机, Windows客户端游戏, 安卓系统直接运行(开发中)
30
+ 4. 支持GUI以及Console运行, 也可以完全自己开发GUI
31
+ 5. 支持Python3.7以上版本
32
+ 6. 学习成本低, 自定义函数少, 也可以直接使用opencv, RapidOCR等api
30
33
 
31
34
  ## Example Usage
32
35
 
@@ -1,12 +1,15 @@
1
- # autoui
1
+ # ok-script
2
2
 
3
- This project aims to provide a universal framework for developing automation tool for PC/Android games, running in
4
- windows,
5
- emulator, or physical Android Phone. Currently still working in progress, there is a working
3
+ 类似于AirScript, 使用Python
6
4
 
7
- ## Showcase
5
+ ## 优势
8
6
 
9
- ![docs/img_showcase.png](docs/img_showcase.png)
7
+ 1. 开源免费, 依赖库均为开源方案, 支持pip install任何第三方库
8
+ 2. 代码和打包流程完全由开发者控制, 不会上传服务器, 没有安全性隐患, 不容易被侦测和识别
9
+ 3. 一套代码即可支持Windows安卓模拟器/ADB连接的虚拟机, Windows客户端游戏, 安卓系统直接运行(开发中)
10
+ 4. 支持GUI以及Console运行, 也可以完全自己开发GUI
11
+ 5. 支持Python3.7以上版本
12
+ 6. 学习成本低, 自定义函数少, 也可以直接使用opencv, RapidOCR等api
10
13
 
11
14
  ## Example Usage
12
15
 
@@ -9,6 +9,7 @@ import ok
9
9
  from ok.feature.FeatureSet import FeatureSet
10
10
  from ok.gui.App import App
11
11
  from ok.gui.Communicate import communicate
12
+ from ok.gui.debug.Screenshot import Screenshot
12
13
  from ok.gui.overlay.OverlayWindow import OverlayWindow
13
14
  from ok.gui.util.InitWorker import InitWorker
14
15
  from ok.logging.Logger import get_logger, config_logger
@@ -27,27 +28,33 @@ class OK:
27
28
  ocr = None
28
29
  overlay_window = None
29
30
  app = None
31
+ screenshot = None
30
32
 
31
33
  def __init__(self, config: Dict[str, Any]):
32
34
  print(f"AutoHelper init, config: {config}")
35
+ ok.gui.ok = self
33
36
  self.debug = config.get("debug", False)
34
37
  self.exit_event = threading.Event()
35
38
  self.config = config
36
39
  self.init_device_manager()
40
+ self.screenshot = Screenshot()
37
41
  if config.get("use_gui"):
38
- self.app = App(self.config.get('gui_icon'), self.debug, self.config.get('gui_title'),
39
- self.config['tasks'], self.exit_event)
42
+ self.app = App(config, self.exit_event)
40
43
  ok.gui.app = self.app
44
+ else:
45
+ self.device_manager.set_preferred_device()
46
+ self.device_manager.start()
47
+ self.do_init()
48
+
49
+ def start(self):
50
+ if self.config.get("use_gui"):
41
51
  self.app.show_loading()
42
52
  self.worker = InitWorker(self.do_init)
43
53
  self.worker.start()
44
54
  self.app.exec()
45
55
  else:
46
- self.device_manager.set_preferred_device()
47
- self.device_manager.start()
48
- self.do_init()
49
56
  self.task_executor.start()
50
- if config.get("debug"):
57
+ if self.config.get("debug"):
51
58
  self.app = QApplication(sys.argv)
52
59
  self.overlay_window = OverlayWindow(ok.gui.device_manager.hwnd)
53
60
  self.app.exec()
@@ -54,6 +54,7 @@ class HwndWindow:
54
54
  self.title = re.compile(title)
55
55
 
56
56
  def update_frame_size(self, width, height):
57
+ logger.debug(f"update_frame_size:{self.frame_width}x{self.frame_height} to {width}x{height}")
57
58
  if width != self.frame_width or height != self.frame_height:
58
59
  self.frame_width = width
59
60
  self.frame_height = height
@@ -127,8 +128,11 @@ def find_hwnds_by_title(title):
127
128
  hwnds = []
128
129
 
129
130
  def enum_windows_proc(hwnd, lParam):
130
- if win32gui.IsWindowVisible(hwnd) and win32gui.GetWindowText(hwnd):
131
- if re.search(title, win32gui.GetWindowText(hwnd)):
131
+ text = win32gui.GetWindowText(hwnd)
132
+ if text and win32gui.IsWindowVisible(hwnd):
133
+ if isinstance(title, str) and title == text:
134
+ hwnds.append(hwnd)
135
+ elif re.search(title, text):
132
136
  hwnds.append(hwnd)
133
137
 
134
138
  win32gui.EnumWindows(enum_windows_proc, None)
@@ -0,0 +1,57 @@
1
+ # original https://github.com/Toufool/AutoSplit/blob/master/src/capture_method/WindowsGraphicsCaptureMethod.py
2
+ import cv2
3
+ import numpy as np
4
+ from typing_extensions import override
5
+
6
+ from ok.capture.BaseCaptureMethod import BaseCaptureMethod
7
+ from ok.logging.Logger import get_logger
8
+
9
+ logger = get_logger(__name__)
10
+
11
+
12
+ class ADBCaptureMethod(BaseCaptureMethod):
13
+ name = "ADB command line Capture"
14
+ description = "use the adb screencap command, slow but works when in background/minimized, takes 300ms per frame"
15
+
16
+ def __init__(self, device, exit_event, width=0, height=0):
17
+ super().__init__()
18
+ self.exit_event = exit_event
19
+ self._size = (width, height)
20
+ self.device = device
21
+
22
+ @property
23
+ def width(self):
24
+ if self._size[0] == 0:
25
+ self.screencap()
26
+ return self._size[0]
27
+
28
+ @property
29
+ def height(self):
30
+ if self._size[1] == 0:
31
+ self.screencap()
32
+ return self._size[1]
33
+
34
+ @override
35
+ def get_frame(self) -> np.ndarray | None:
36
+ return self.screencap()
37
+
38
+ def screencap(self):
39
+ if self.exit_event.is_set():
40
+ return None
41
+ frame = do_screencap(self.device)
42
+ if frame is not None:
43
+ height, width, _ = frame.shape
44
+ self._size = (width, height)
45
+ return frame
46
+
47
+
48
+ def do_screencap(device) -> np.ndarray | None:
49
+ if device is not None:
50
+ png_bytes = device.shell("screencap -p", encoding=None)
51
+ if png_bytes is not None and len(png_bytes) > 0:
52
+ image_data = np.frombuffer(png_bytes, dtype=np.uint8)
53
+ image = cv2.imdecode(image_data, cv2.IMREAD_COLOR)
54
+ if image is not None:
55
+ return image
56
+ else:
57
+ logger.error(f"Screencap image decode error, probably disconnected")
@@ -1,11 +1,9 @@
1
1
  import threading
2
2
 
3
3
  import adbutils
4
- import cv2
5
- import numpy as np
6
4
 
7
5
  from ok.capture.HwndWindow import HwndWindow
8
- from ok.capture.adb.ADBCaptureMethod import ADBCaptureMethod
6
+ from ok.capture.adb.ADBCaptureMethod import ADBCaptureMethod, do_screencap
9
7
  from ok.capture.adb.vbox import installed_emulator
10
8
  from ok.capture.windows.WindowsGraphicsCaptureMethod import WindowsGraphicsCaptureMethod
11
9
  from ok.config.Config import Config
@@ -29,7 +27,6 @@ class DeviceManager:
29
27
  if hwnd_title is not None:
30
28
  self.hwnd = HwndWindow(hwnd_title, exit_event)
31
29
  self.config = Config({"devices": {}}, config_folder, "DeviceManager")
32
- self._size = (0, 0)
33
30
  self.thread = None
34
31
  self.capture_method = None
35
32
  self.refresh()
@@ -68,8 +65,7 @@ class DeviceManager:
68
65
 
69
66
  device_list = sorted(device_list, key=lambda x: x.serial)
70
67
 
71
- for device in self.device_dict.values():
72
- device['connected'] = False
68
+ adb_connected = []
73
69
 
74
70
  for device in device_list:
75
71
  imei = device.shell("settings get secure android_id") or device.shell(
@@ -78,7 +74,8 @@ class DeviceManager:
78
74
  width, height = 0, 0
79
75
  if frame is not None:
80
76
  height, width, _ = frame.shape
81
- adb_device = {"address": device.serial, "imei": imei, "method": "adb",
77
+ adb_device = {"address": device.serial, "imei": imei, "device": "adb", "capture": "adb", "width": width,
78
+ "height": height,
82
79
  "model": device.prop.model, "nick": device.prop.model, "connected": True, "preferred": False,
83
80
  "resolution": f"{width}x{height}"}
84
81
  found = False
@@ -88,21 +85,32 @@ class DeviceManager:
88
85
  found = True
89
86
  if self.device_dict.get(imei):
90
87
  if found or not self.device_dict[imei]['connected']:
88
+ old_capture = self.device_dict[imei].get("capture")
89
+ old_hwnd = self.device_dict[imei].get("hwnd")
91
90
  self.device_dict[imei] = adb_device
91
+ if old_capture is not None:
92
+ self.device_dict[imei]['capture'] = old_capture
93
+ if old_hwnd is not None:
94
+ self.device_dict[imei]['hwnd'] = old_hwnd
92
95
  else:
93
96
  self.device_dict[imei] = adb_device
97
+ adb_connected.append(imei)
98
+ for imei in self.device_dict:
99
+ if imei not in adb_connected:
100
+ self.device_dict[imei]['connected'] = False
94
101
  if self.hwnd_title:
95
- nick = self.hwnd_title
102
+ nick = ""
96
103
  width = 0
97
104
  height = 0
98
105
  if self.hwnd:
99
106
  nick = self.hwnd.title_text()
100
107
  width = self.hwnd.width
101
108
  height = self.hwnd.height
102
- self.device_dict[self.hwnd_title] = {"address": "", "imei": self.hwnd_title, "method": "windows",
103
- "model": "", "nick": nick or self.hwnd_title,
109
+ self.device_dict[self.hwnd_title] = {"address": "", "imei": self.hwnd_title, "device": "windows",
110
+ "model": "", "nick": nick or self.hwnd_title, "width": width,
111
+ "height": height,
112
+ "hwnd": nick, "capture": "windows",
104
113
  "connected": self.hwnd is not None and self.hwnd.exists,
105
- "preferred": False,
106
114
  "resolution": f"{width}x{height}"}
107
115
  communicate.adb_devices.emit()
108
116
  self.config.save_file()
@@ -110,70 +118,98 @@ class DeviceManager:
110
118
 
111
119
  def set_preferred_device(self, imei=None):
112
120
  logger.debug(f"set_preferred_device {imei}")
113
- preferred = None
114
121
  if imei is None:
115
- for device in self.device_dict.values():
116
- if device.get('preferred'):
117
- preferred = device
118
- imei = preferred['imei']
119
- else:
120
- preferred = self.device_dict.get(imei)
121
- for key in self.device_dict.keys():
122
- if imei == key:
123
- self.device_dict[imei]["preferred"] = False
122
+ imei = self.config.get("preferred")
123
+ preferred = self.device_dict.get(imei)
124
124
  if preferred is None and len(self.device_dict) > 0:
125
125
  preferred = next(iter(self.device_dict.values()))
126
- if preferred is not None:
127
- preferred['preferred'] = True
128
- if preferred['method'] == 'windows':
126
+ imei = preferred['imei']
127
+ if self.config.get("preferred") != imei:
128
+ self.config["preferred"] = imei
129
+ self.config.save_file()
130
+ logger.debug(f'preferred device: {preferred}')
131
+
132
+ def get_preferred_device(self):
133
+ imei = self.config.get("preferred")
134
+ preferred = self.device_dict.get(imei)
135
+ if preferred is None:
136
+ raise ValueError(f"preferred device {imei} is none")
137
+ return preferred
138
+
139
+ def set_hwnd_name(self, hwnd_name):
140
+ preferred = self.get_preferred_device()
141
+ if preferred.get("hwnd") != hwnd_name:
142
+ preferred['hwnd'] = hwnd_name
143
+ self.config.save_file()
144
+
145
+ def set_capture(self, capture):
146
+ preferred = self.get_preferred_device()
147
+ preferred['capture'] = capture
148
+ self.config.save_file()
149
+
150
+ def get_hwnd_name(self):
151
+ preferred = self.get_preferred_device()
152
+ return preferred.get('hwnd')
153
+
154
+ def start(self):
155
+ preferred = self.get_preferred_device()
156
+ if preferred['device'] == 'windows':
157
+ if not isinstance(self.capture_method, WindowsGraphicsCaptureMethod):
158
+ if self.capture_method is not None:
159
+ self.capture_method.close()
160
+ self.capture_method = WindowsGraphicsCaptureMethod(self.hwnd)
161
+ self.interaction = Win32Interaction(self.capture_method)
162
+ self.capture_method.hwnd_window = self.hwnd
163
+ else:
164
+ for adb_device in self.adb.device_list():
165
+ if adb_device.serial == preferred.get('address'):
166
+ self._device = adb_device
167
+ hwnd_name = preferred.get('hwnd')
168
+ width = preferred.get('width', 0)
169
+ height = preferred.get('height', 0)
170
+ if preferred.get('capture') == "windows":
171
+ if not hwnd_name:
172
+ raise ValueError(f"adb device preferred hwnd is none, capture is windows {preferred}")
173
+ if self.hwnd is None:
174
+ self.hwnd = HwndWindow(hwnd_name, self.exit_event, width, height)
129
175
  if not isinstance(self.capture_method, WindowsGraphicsCaptureMethod):
130
176
  if self.capture_method is not None:
131
177
  self.capture_method.close()
132
178
  self.capture_method = WindowsGraphicsCaptureMethod(self.hwnd)
133
- self.interaction = Win32Interaction(self.capture_method)
179
+ self.hwnd.title = hwnd_name
134
180
  self.capture_method.hwnd_window = self.hwnd
135
- else:
136
- for adb_device in self.adb.device_list():
137
- if adb_device.serial == preferred.get('address'):
138
- self._device = adb_device
139
- if not isinstance(self.capture_method, ADBCaptureMethod):
140
- if self.capture_method is not None:
141
- self.capture_method.close()
142
- self.capture_method = ADBCaptureMethod(self)
143
- self.interaction = ADBBaseInteraction(self, self.capture_method)
144
- self.config.save_file()
145
- logger.debug(f'preferred device: {preferred}')
146
-
147
- def start(self):
148
- if isinstance(self.capture_method, ADBCaptureMethod):
181
+ elif not isinstance(self.capture_method, ADBCaptureMethod):
182
+ if self.capture_method is not None:
183
+ self.capture_method.close()
184
+ self.capture_method = ADBCaptureMethod(self._device, self.exit_event, width=width,
185
+ height=height)
186
+ self.interaction = ADBBaseInteraction(self, self.capture_method)
149
187
  if self.debug:
150
- if self.hwnd is not None:
151
- self.hwnd.update_title_re("autohelper_debug")
152
- self.hwnd.update_frame_size(self.capture_method.width, self.capture_method.height)
153
- else:
154
- self.hwnd = HwndWindow("autohelper_debug", self.exit_event, self.capture_method.width,
155
- self.capture_method.height)
156
- else:
188
+ if self.hwnd is None and hwnd_name:
189
+ if self.hwnd is None:
190
+ self.hwnd = HwndWindow(hwnd_name, self.exit_event, width, height)
191
+ self.hwnd.title = hwnd_name
192
+ elif self.hwnd is not None:
157
193
  self.hwnd.stop()
158
194
  self.hwnd = None
195
+ if self.hwnd:
196
+ self.hwnd.update_frame_size(width, height)
159
197
 
160
198
  @property
161
199
  def device(self):
162
- if self._device is None:
163
- self.set_preferred_device()
164
200
  return self._device
165
201
 
166
202
  @property
167
203
  def width(self):
168
- if self._size[0] == 0:
169
- self.screencap()
170
- return self._size[0]
204
+ if self.capture_method is not None:
205
+ return self.capture_method.width
206
+ return 0
171
207
 
172
208
  @property
173
209
  def height(self):
174
- if self._size[1] == 0:
175
- self.screencap()
176
- return self._size[1]
210
+ if self.capture_method is not None:
211
+ return self.capture_method.height
212
+ return 0
177
213
 
178
214
  def update_device_list(self):
179
215
  pass
@@ -185,25 +221,3 @@ class DeviceManager:
185
221
  return device.shell(*args, **kwargs)
186
222
  except Exception as e:
187
223
  logger.error(f"shell_wrapper error occurred: {e}")
188
-
189
- def screencap(self):
190
- if self.exit_event.is_set():
191
- return None
192
- self._size = (0, 0)
193
- frame = do_screencap(self.device)
194
- if frame is not None:
195
- height, width, _ = frame.shape
196
- self._size = (width, height)
197
- return frame
198
-
199
-
200
- def do_screencap(device) -> np.ndarray | None:
201
- if device is not None:
202
- png_bytes = device.shell("screencap -p", encoding=None)
203
- if png_bytes is not None and len(png_bytes) > 0:
204
- image_data = np.frombuffer(png_bytes, dtype=np.uint8)
205
- image = cv2.imdecode(image_data, cv2.IMREAD_COLOR)
206
- if image is not None:
207
- return image
208
- else:
209
- logger.error(f"Screencap image decode error, probably disconnected")
@@ -162,8 +162,10 @@ class WindowsGraphicsCaptureMethod(BaseCaptureMethod):
162
162
  self.session.Close() # E_UNEXPECTED ???
163
163
  self.session = None
164
164
  self.item = None
165
- self.rtdevice.Release()
166
- self.dxdevice.Release()
165
+ if self.rtdevice:
166
+ self.rtdevice.Release()
167
+ if self.dxdevice:
168
+ self.dxdevice.Release()
167
169
  if self.cputex:
168
170
  self.cputex.Release()
169
171
 
@@ -6,10 +6,10 @@ import re
6
6
  class Box:
7
7
  def __init__(self, x: int, y: int, width: int, height: int, confidence: float = 1, name=None) -> None:
8
8
  self.name = name
9
- self.x = x
10
- self.y = y
11
- self.width = width
12
- self.height = height
9
+ self.x = int(x)
10
+ self.y = int(y)
11
+ self.width = int(width)
12
+ self.height = int(height)
13
13
  self.confidence = confidence
14
14
 
15
15
  def __eq__(self, other):
@@ -24,6 +24,14 @@ class Box:
24
24
  self.confidence == other.confidence and
25
25
  self.name == other.name)
26
26
 
27
+ def in_boundary(self, boxes):
28
+ in_boundary_boxes = []
29
+ for box in boxes:
30
+ if (self.x <= box.x and self.x + self.width >= box.x + box.width and
31
+ self.y <= box.y and self.y + self.height >= box.y + box.height):
32
+ in_boundary_boxes.append(box)
33
+ return in_boundary_boxes
34
+
27
35
  def __repr__(self):
28
36
  return self.name
29
37
 
@@ -80,7 +88,7 @@ class Box:
80
88
  def center(self):
81
89
  return self.x + self.width / 2, self.y + self.height / 2
82
90
 
83
- def find_closest_box(self, direction: str, boxes: list):
91
+ def find_closest_box(self, direction: str, boxes: list, condition=None):
84
92
  orig_center_x, orig_center_y = self.center()
85
93
 
86
94
  def distance_criteria(box):
@@ -91,14 +99,21 @@ class Box:
91
99
  dy = box_center_y - orig_center_y
92
100
  distance = math.sqrt(dx ** 2 + dy ** 2)
93
101
  if box == self:
94
- return float('inf')
102
+ distance = float('inf')
95
103
  elif direction == 'up' and self.y - (box.y + box.height / 2) >= 0:
96
- return distance
104
+ pass
97
105
  elif direction == 'down' and box.y - (self.y + self.height / 2) >= 0:
98
- return distance
106
+ pass
99
107
  elif direction == 'left' and self.x - (box.x + box.width / 2) >= 0:
100
- return distance
108
+ pass
101
109
  elif direction == 'right' and box.x - (self.x + self.width / 2) >= 0:
110
+ pass
111
+ else:
112
+ distance = float('inf')
113
+ return check_condition(box, distance)
114
+
115
+ def check_condition(box, distance):
116
+ if condition is None or condition(box):
102
117
  return distance
103
118
  else:
104
119
  return float('inf')
@@ -184,7 +184,7 @@ class FeatureSet:
184
184
  # cv2.imwrite("images/test.jpg", mat)
185
185
 
186
186
  result = sort_boxes(boxes)
187
- communicate.draw_box.emit(category_name, result, "red")
187
+ communicate.emit_draw_box(category_name, result, "red")
188
188
  return result
189
189
 
190
190
 
@@ -18,19 +18,21 @@ logger = get_logger(__name__)
18
18
 
19
19
 
20
20
  class App:
21
- def __init__(self, icon=None, overlay=False, title="AutoUI", tasks=None,
21
+ def __init__(self, config,
22
22
  exit_event=None):
23
23
  super().__init__()
24
+ self.config = config
24
25
  self.app = QApplication(sys.argv)
25
26
  self.app.setStyle(QStyleFactory.create("Fusion"))
26
- self.tasks = tasks
27
- self.title = title
28
- self.overlay = overlay
27
+ self.tasks = self.config['tasks']
28
+ self.about = self.config.get('about')
29
+ self.title = self.config.get('gui_title')
30
+ self.overlay = self.config.get('debug')
29
31
  self.loading_window = None
30
32
  self.overlay_window = None
31
33
  self.main_window = None
32
34
  self.exit_event = exit_event
33
- self.icon = QIcon(icon or ":/icon/icon.ico")
35
+ self.icon = QIcon(self.config.get('gui_icon') or ":/icon/icon.ico")
34
36
  self.tray = QSystemTrayIcon(self.icon)
35
37
 
36
38
  locale = QLocale.system().name()
@@ -63,7 +65,7 @@ class App:
63
65
 
64
66
  def show_loading(self):
65
67
  self.loading_window = LoadingWindow(self, self.exit_event)
66
- size = self.size_relative_to_screen(width=0.4, height=0.4)
68
+ size = self.size_relative_to_screen(width=0.6, height=0.4)
67
69
  self.loading_window.resize(size)
68
70
  self.loading_window.setMinimumSize(size)
69
71
  self.center_window(self.loading_window)
@@ -86,7 +88,7 @@ class App:
86
88
 
87
89
  def show_main_window(self):
88
90
  self.loading_window.close()
89
- self.main_window = MainWindow(self.tasks, self.overlay, exit_event=self.exit_event)
91
+ self.main_window = MainWindow(self.tasks, self.overlay, self.about, exit_event=self.exit_event)
90
92
  self.main_window.setWindowTitle(self.title) # Set the window title here
91
93
  self.main_window.setWindowIcon(self.icon)
92
94
  if self.overlay and ok.gui.device_manager.hwnd is not None:
@@ -3,12 +3,11 @@ from PySide6.QtCore import Signal, QObject
3
3
 
4
4
 
5
5
  class Communicate(QObject):
6
- frame = Signal(np.ndarray)
7
6
  log = Signal(int, str)
8
7
  fps = Signal(int)
9
8
  frame_time = Signal(int)
10
9
  scene = Signal(str)
11
- draw_box = Signal(str, object, str)
10
+ draw_box = Signal(str, object, str, np.ndarray)
12
11
  tasks = Signal()
13
12
  task_info = Signal()
14
13
  window = Signal(bool, int, int, int, int, int, int, float)
@@ -16,7 +15,12 @@ class Communicate(QObject):
16
15
  init = Signal(bool, str)
17
16
  notification = Signal(str, str)
18
17
  executor_paused: Signal = Signal(bool)
18
+ screenshot = Signal(np.ndarray, str)
19
+ update_overlay = Signal()
19
20
  adb_devices: Signal = Signal()
20
21
 
22
+ def emit_draw_box(self, key: str = None, boxes=None, color=None, frame=None):
23
+ self.draw_box.emit(key, boxes, color, frame)
24
+
21
25
 
22
26
  communicate = Communicate()
@@ -1,6 +1,7 @@
1
1
  from PySide6.QtCore import QObject, Signal, Slot
2
2
  from PySide6.QtWidgets import QMessageBox, QTabWidget
3
3
 
4
+ from ok.gui.about.AboutTab import AboutTab
4
5
  from ok.gui.debug.DebugTab import DebugTab
5
6
  from ok.gui.tasks.TaskTab import TaskTab
6
7
  from ok.logging.Logger import get_logger
@@ -13,7 +14,7 @@ class Communicate(QObject):
13
14
 
14
15
 
15
16
  class MainWindow(QTabWidget):
16
- def __init__(self, tasks, debug=False, exit_event=None):
17
+ def __init__(self, tasks, debug=False, about=None, exit_event=None):
17
18
  super().__init__()
18
19
  self.exit_event = exit_event
19
20
  task_tab = TaskTab(tasks)
@@ -22,6 +23,9 @@ class MainWindow(QTabWidget):
22
23
  debug_tab = DebugTab()
23
24
  self.addTab(debug_tab, self.tr("Debug"))
24
25
  # ... Add other tabs similarly
26
+ if about:
27
+ about_tab = AboutTab(about)
28
+ self.addTab(about_tab, self.tr("About"))
25
29
 
26
30
  # Styling the tabs and content if needed, for example:
27
31
  self.setStyleSheet("""
@@ -1,5 +1,7 @@
1
+ from ok.OK import OK
1
2
  from ok.capture.adb.DeviceManager import DeviceManager
2
3
 
4
+ ok: OK | None = None
3
5
  executor = None
4
6
  app = None
5
7
  device_manager: DeviceManager | None = None
@@ -0,0 +1,16 @@
1
+ from PySide6.QtWidgets import QWidget, QTextEdit, QVBoxLayout
2
+
3
+
4
+ class AboutTab(QWidget):
5
+ def __init__(self, text=""):
6
+ super().__init__()
7
+ layout = QVBoxLayout()
8
+
9
+ # Create a QTextEdit instance
10
+ text_edit = QTextEdit()
11
+ text_edit.setHtml(text)
12
+ text_edit.setReadOnly(True)
13
+ layout.addWidget(text_edit)
14
+
15
+ # Set the layout on the widget
16
+ self.setLayout(layout)