ok-script 0.0.81__tar.gz → 0.0.83__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 (183) hide show
  1. {ok-script-0.0.81 → ok-script-0.0.83}/PKG-INFO +1 -1
  2. {ok-script-0.0.81 → ok-script-0.0.83}/ok/alas/emulator_windows.py +1 -1
  3. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/HwndWindow.py +9 -6
  4. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/adb/DeviceManager.py +22 -10
  5. ok-script-0.0.83/ok/color/Color.py +148 -0
  6. {ok-script-0.0.81 → ok-script-0.0.83}/ok/feature/Box.py +8 -8
  7. {ok-script-0.0.81 → ok-script-0.0.83}/ok/feature/FeatureSet.py +7 -2
  8. {ok-script-0.0.81 → ok-script-0.0.83}/ok/feature/FindFeature.py +4 -5
  9. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/StartController.py +16 -8
  10. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/debug/DebugTab.py +4 -2
  11. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/resources.py +605 -584
  12. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/start/StartTab.py +1 -1
  13. {ok-script-0.0.81 → ok-script-0.0.83}/ok/interaction/BaseInteraction.py +6 -0
  14. {ok-script-0.0.81 → ok-script-0.0.83}/ok/interaction/Win32Interaction.py +31 -2
  15. {ok-script-0.0.81 → ok-script-0.0.83}/ok/ocr/OCR.py +3 -6
  16. {ok-script-0.0.81 → ok-script-0.0.83}/ok/task/ExecutorOperation.py +28 -5
  17. {ok-script-0.0.81 → ok-script-0.0.83}/ok/task/TaskExecutor.py +7 -4
  18. {ok-script-0.0.81 → ok-script-0.0.83}/ok/task/TriggerTask.py +2 -1
  19. {ok-script-0.0.81 → ok-script-0.0.83}/ok_script.egg-info/PKG-INFO +1 -1
  20. {ok-script-0.0.81 → ok-script-0.0.83}/setup.py +1 -1
  21. ok-script-0.0.81/ok/color/Color.py +0 -42
  22. {ok-script-0.0.81 → ok-script-0.0.83}/README.md +0 -0
  23. {ok-script-0.0.81 → ok-script-0.0.83}/ok/OK.py +0 -0
  24. {ok-script-0.0.81 → ok-script-0.0.83}/ok/__init__.py +0 -0
  25. {ok-script-0.0.81 → ok-script-0.0.83}/ok/alas/__init__.py +0 -0
  26. {ok-script-0.0.81 → ok-script-0.0.83}/ok/alas/emulator_base.py +0 -0
  27. {ok-script-0.0.81 → ok-script-0.0.83}/ok/alas/platform_base.py +0 -0
  28. {ok-script-0.0.81 → ok-script-0.0.83}/ok/alas/platform_windows.py +0 -0
  29. {ok-script-0.0.81 → ok-script-0.0.83}/ok/alas/utils.py +0 -0
  30. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/BaseCaptureMethod.py +0 -0
  31. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/__init__.py +0 -0
  32. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/adb/ADBCaptureMethod.py +0 -0
  33. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/adb/WindowsCaptureFactory.py +0 -0
  34. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/adb/__init__.py +0 -0
  35. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/adb/bin/__init__.py +0 -0
  36. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/image/ImageCaptureMethod.py +0 -0
  37. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/image/__init__.py +0 -0
  38. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/BaseWindowsCaptureMethod.py +0 -0
  39. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/BitBltCaptureMethod.py +0 -0
  40. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/DesktopDuplicationCaptureMethod.py +0 -0
  41. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/WindowsGraphicsCaptureMethod.py +0 -0
  42. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/__init__.py +0 -0
  43. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/d3d11.py +0 -0
  44. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/dump.py +0 -0
  45. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/utils.py +0 -0
  46. {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/window.py +0 -0
  47. {ok-script-0.0.81 → ok-script-0.0.83}/ok/color/__init__.py +0 -0
  48. {ok-script-0.0.81 → ok-script-0.0.83}/ok/config/Config.py +0 -0
  49. {ok-script-0.0.81 → ok-script-0.0.83}/ok/config/InfoDict.py +0 -0
  50. {ok-script-0.0.81 → ok-script-0.0.83}/ok/config/__init__.py +0 -0
  51. {ok-script-0.0.81 → ok-script-0.0.83}/ok/feature/Feature.py +0 -0
  52. {ok-script-0.0.81 → ok-script-0.0.83}/ok/feature/__init__.py +0 -0
  53. {ok-script-0.0.81 → ok-script-0.0.83}/ok/firebase/Analytics.py +0 -0
  54. {ok-script-0.0.81 → ok-script-0.0.83}/ok/firebase/__init__.py +0 -0
  55. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/App.py +0 -0
  56. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/Communicate.py +0 -0
  57. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/MainWindow.py +0 -0
  58. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/MessageWindow.py +0 -0
  59. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/TabTitles.py +0 -0
  60. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/__init__.py +0 -0
  61. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/about/AboutTab.py +0 -0
  62. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/about/HttpTextEdit.py +0 -0
  63. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/about/VersionCard.py +0 -0
  64. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/about/__init__.py +0 -0
  65. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/common/OKIcon.py +0 -0
  66. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/common/__init__.py +0 -0
  67. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/common/config.py +0 -0
  68. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/common/style_sheet.py +0 -0
  69. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/debug/AspectRatioWidget.py +0 -0
  70. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/debug/FrameWidget.py +0 -0
  71. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/debug/InfoWidget.py +0 -0
  72. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/debug/LoggerWidget.py +0 -0
  73. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/debug/Screenshot.py +0 -0
  74. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/debug/__init__.py +0 -0
  75. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/i18n/__init__.py +0 -0
  76. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/i18n/path.py +0 -0
  77. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/i18n/update.py +0 -0
  78. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/icon/__init__.py +0 -0
  79. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/icon/icon.py +0 -0
  80. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/overlay/OverlayWindow.py +0 -0
  81. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/overlay/__init__.py +0 -0
  82. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/qss/__init__.py +0 -0
  83. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/settings/SettingTab.py +0 -0
  84. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/settings/__init__.py +0 -0
  85. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/start/SelectCaptureListView.py +0 -0
  86. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/start/StartCard.py +0 -0
  87. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/start/__init__.py +0 -0
  88. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/ConfigItemFactory.py +0 -0
  89. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/ConfigLabelAndWidget.py +0 -0
  90. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/LabelAndDoubleSpinBox.py +0 -0
  91. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/LabelAndDropDown.py +0 -0
  92. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/LabelAndLineEdit.py +0 -0
  93. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/LabelAndList.py +0 -0
  94. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/LabelAndSpinBox.py +0 -0
  95. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/LabelAndSwitchButton.py +0 -0
  96. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/LabelAndWidget.py +0 -0
  97. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/ModifyListDialog.py +0 -0
  98. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/ModifyListItem.py +0 -0
  99. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/OneTimeTaskTab.py +0 -0
  100. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/StartButton.py +0 -0
  101. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/TaskCard.py +0 -0
  102. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/TaskOpButton.py +0 -0
  103. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/TooltipTableWidget.py +0 -0
  104. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/TriggerTaskTab.py +0 -0
  105. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/__init__.py +0 -0
  106. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/util/Alert.py +0 -0
  107. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/util/InitWorker.py +0 -0
  108. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/util/__init__.py +0 -0
  109. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/Card.py +0 -0
  110. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/EmptyCard.py +0 -0
  111. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/FramelessDialog.py +0 -0
  112. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/ListTableWidgetItem.py +0 -0
  113. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/NumericTableWidgetItem.py +0 -0
  114. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/StartLoadingDialog.py +0 -0
  115. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/StatusBar.py +0 -0
  116. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/Tab.py +0 -0
  117. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/TabWidget.py +0 -0
  118. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/UpdateConfigWidgetItem.py +0 -0
  119. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/YesNonWidgetItem.py +0 -0
  120. {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/__init__.py +0 -0
  121. {ok-script-0.0.81 → ok-script-0.0.83}/ok/interaction/ADBInteraction.py +0 -0
  122. {ok-script-0.0.81 → ok-script-0.0.83}/ok/interaction/DoNothingInteraction.py +0 -0
  123. {ok-script-0.0.81 → ok-script-0.0.83}/ok/interaction/__init__.py +0 -0
  124. {ok-script-0.0.81 → ok-script-0.0.83}/ok/logging/Logger.py +0 -0
  125. {ok-script-0.0.81 → ok-script-0.0.83}/ok/logging/__init__.py +0 -0
  126. {ok-script-0.0.81 → ok-script-0.0.83}/ok/ocr/__init__.py +0 -0
  127. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Foundation/Collections.py +0 -0
  128. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Foundation/__init__.py +0 -0
  129. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Globalization/__init__.py +0 -0
  130. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Graphics/Capture/__init__.py +0 -0
  131. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Graphics/DirectX/Direct3D11/__init__.py +0 -0
  132. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Graphics/DirectX/__init__.py +0 -0
  133. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Graphics/Imaging/__init__.py +0 -0
  134. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Graphics/__init__.py +0 -0
  135. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Media/Ocr/__init__.py +0 -0
  136. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Media/__init__.py +0 -0
  137. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Security/Cryptography/__init__.py +0 -0
  138. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Security/__init__.py +0 -0
  139. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Storage/Streams/__init__.py +0 -0
  140. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Storage/__init__.py +0 -0
  141. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/__init__.py +0 -0
  142. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/__init__.py +0 -0
  143. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/delegate.py +0 -0
  144. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/export.py +0 -0
  145. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/idldsl.py +0 -0
  146. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/inspectable.py +0 -0
  147. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/roapi.py +0 -0
  148. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/types.py +0 -0
  149. {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/winstring.py +0 -0
  150. {ok-script-0.0.81 → ok-script-0.0.83}/ok/save/BlackBarProcessor.py +0 -0
  151. {ok-script-0.0.81 → ok-script-0.0.83}/ok/save/PostProcessor.py +0 -0
  152. {ok-script-0.0.81 → ok-script-0.0.83}/ok/save/SaveByInterval.py +0 -0
  153. {ok-script-0.0.81 → ok-script-0.0.83}/ok/save/SaveByKeyPress.py +0 -0
  154. {ok-script-0.0.81 → ok-script-0.0.83}/ok/save/SaveMethodBase.py +0 -0
  155. {ok-script-0.0.81 → ok-script-0.0.83}/ok/save/__init__.py +0 -0
  156. {ok-script-0.0.81 → ok-script-0.0.83}/ok/scene/FeatureScene.py +0 -0
  157. {ok-script-0.0.81 → ok-script-0.0.83}/ok/scene/Scene.py +0 -0
  158. {ok-script-0.0.81 → ok-script-0.0.83}/ok/scene/__init__.py +0 -0
  159. {ok-script-0.0.81 → ok-script-0.0.83}/ok/stats/StreamStats.py +0 -0
  160. {ok-script-0.0.81 → ok-script-0.0.83}/ok/stats/__init__.py +0 -0
  161. {ok-script-0.0.81 → ok-script-0.0.83}/ok/task/BaseTask.py +0 -0
  162. {ok-script-0.0.81 → ok-script-0.0.83}/ok/task/OneTimeTask.py +0 -0
  163. {ok-script-0.0.81 → ok-script-0.0.83}/ok/task/__init__.py +0 -0
  164. {ok-script-0.0.81 → ok-script-0.0.83}/ok/update/GithubMultiDownloader.py +0 -0
  165. {ok-script-0.0.81 → ok-script-0.0.83}/ok/update/Updater.py +0 -0
  166. {ok-script-0.0.81 → ok-script-0.0.83}/ok/update/__init__.py +0 -0
  167. {ok-script-0.0.81 → ok-script-0.0.83}/ok/update/gen_md5.py +0 -0
  168. {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/Handler.py +0 -0
  169. {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/__init__.py +0 -0
  170. {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/exit_event.py +0 -0
  171. {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/json.py +0 -0
  172. {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/list.py +0 -0
  173. {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/path.py +0 -0
  174. {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/thread.py +0 -0
  175. {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/win32_process.py +0 -0
  176. {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/yaml.py +0 -0
  177. {ok-script-0.0.81 → ok-script-0.0.83}/ok_script.egg-info/SOURCES.txt +0 -0
  178. {ok-script-0.0.81 → ok-script-0.0.83}/ok_script.egg-info/dependency_links.txt +0 -0
  179. {ok-script-0.0.81 → ok-script-0.0.83}/ok_script.egg-info/requires.txt +0 -0
  180. {ok-script-0.0.81 → ok-script-0.0.83}/ok_script.egg-info/top_level.txt +0 -0
  181. {ok-script-0.0.81 → ok-script-0.0.83}/setup.cfg +0 -0
  182. {ok-script-0.0.81 → ok-script-0.0.83}/tests/__init__.py +0 -0
  183. {ok-script-0.0.81 → ok-script-0.0.83}/tests/test_updater.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ok-script
3
- Version: 0.0.81
3
+ Version: 0.0.83
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
@@ -467,7 +467,7 @@ class EmulatorManager(EmulatorManagerBase):
467
467
  try:
468
468
  exe = proc.cmdline()
469
469
  exe = exe[0]
470
- except (psutil.AccessDenied, IndexError):
470
+ except (psutil.AccessDenied, psutil.NoSuchProcess, IndexError):
471
471
  # psutil.AccessDenied
472
472
  continue
473
473
 
@@ -180,22 +180,25 @@ def find_hwnd(title, exe_name, frame_width, frame_height):
180
180
  win32gui.EnumWindows(callback, None)
181
181
  biggest = None
182
182
  if len(results) > 0:
183
+ biggest = results[0]
183
184
  for result in results:
184
185
  from ok.capture.windows.BitBltCaptureMethod import bit_blt_test_hwnd
185
186
  if (biggest is None or (result[2] * result[3]) > biggest[2] * biggest[3]) and bit_blt_test_hwnd(result[0]):
186
187
  biggest = result
187
188
  x_offset = 0
188
189
  y_offset = 0
189
- real_width, real_height = 0, 0
190
- if biggest is not None and frame_aspect_ratio != 0:
190
+ real_width = 0
191
+ real_height = 0
192
+ if frame_aspect_ratio != 0:
191
193
  real_width, real_height = biggest[2], biggest[3]
192
194
  matching_child = enum_child_windows(biggest, frame_aspect_ratio)
193
195
  if matching_child is not None:
194
196
  x_offset, y_offset, real_width, real_height = matching_child
195
- logger.info(f'find_hwnd {frame_width, frame_height} {biggest} {x_offset, y_offset, real_width, real_height}')
196
- return biggest[6], biggest[0], biggest[1], x_offset, y_offset, real_width, real_height,
197
- else:
198
- return None, None, None, 0, 0, 0, 0
197
+ logger.info(
198
+ f'find_hwnd {frame_width, frame_height} {biggest} {x_offset, y_offset, real_width, real_height}')
199
+ return biggest[6], biggest[0], biggest[1], x_offset, y_offset, real_width, real_height
200
+
201
+ return None, None, None, 0, 0, 0, 0
199
202
 
200
203
 
201
204
  def enum_child_windows(biggest, frame_aspect_ratio):
@@ -19,8 +19,9 @@ class DeviceManager:
19
19
  def __init__(self, app_config, exit_event=None):
20
20
  self._device = None
21
21
  self._adb = None
22
- self.supported_ratio = parse_ratio(app_config.get(
23
- 'supported_screen_ratio'))
22
+ supported_resolution = app_config.get(
23
+ 'supported_resolution', {})
24
+ self.supported_ratio = parse_ratio(supported_resolution.get('ratio'))
24
25
  self.windows_capture_config = app_config.get('windows')
25
26
  self.adb_capture_config = app_config.get('adb')
26
27
  self.debug = app_config.get('debug')
@@ -98,12 +99,12 @@ class DeviceManager:
98
99
  pc_device["resolution"] = f"{width}x{height}"
99
100
  self.device_dict['pc'] = pc_device
100
101
 
101
- def do_refresh(self, fast=False):
102
+ def do_refresh(self, current=False):
102
103
  self.update_pc_device()
103
104
 
104
- self.refresh_emulators()
105
+ self.refresh_emulators(current)
105
106
 
106
- self.refresh_phones()
107
+ self.refresh_phones(current)
107
108
 
108
109
  if self.exit_event.is_set():
109
110
  return
@@ -111,10 +112,16 @@ class DeviceManager:
111
112
 
112
113
  logger.debug(f'refresh {self.device_dict}')
113
114
 
114
- def refresh_phones(self):
115
+ def refresh_phones(self, current=False):
116
+ if self.adb_capture_config is None:
117
+ return
115
118
  for adb_device in self.adb.iter_device():
116
119
  imei = self.adb_get_imei(adb_device)
117
120
  if imei is not None:
121
+ preferred = self.get_preferred_device()
122
+ if current and preferred is not None and preferred['imei'] != imei:
123
+ logger.debug(f"refresh current only skip others {preferred['imei']} != imei")
124
+ break
118
125
  found = False
119
126
  for device in self.device_dict.values():
120
127
  if device.get('adb_imei') == imei:
@@ -128,13 +135,17 @@ class DeviceManager:
128
135
  "resolution": f'{width}x{height}'}
129
136
  self.device_dict[imei] = phone_device
130
137
 
131
- def refresh_emulators(self):
138
+ def refresh_emulators(self, current=False):
132
139
  if self.adb_capture_config is None:
133
140
  return
134
141
  from ok.alas.emulator_windows import EmulatorManager
135
142
  manager = EmulatorManager()
136
143
  installed_emulators = manager.all_emulator_instances
137
144
  for emulator in installed_emulators:
145
+ preferred = self.get_preferred_device()
146
+ if current and preferred is not None and preferred['imei'] != emulator.name:
147
+ logger.debug(f"refresh current only skip others {preferred['imei']} != {emulator.name}")
148
+ break
138
149
  adb_device = self.adb_connect(emulator.serial)
139
150
  width, height = self.get_resolution(adb_device)
140
151
  name, hwnd, full_path, x, y, width, height = find_hwnd(None,
@@ -142,10 +153,10 @@ class DeviceManager:
142
153
  connected = adb_device is not None and name is not None
143
154
  emulator_device = {"address": emulator.serial, "device": "adb",
144
155
  "full_path": emulator.path, "connected": connected,
156
+ "imei": emulator.name,
145
157
  "nick": name or emulator.name, "emulator": emulator}
146
158
  if adb_device is not None:
147
159
  emulator_device["resolution"] = f"{width}x{height}"
148
- emulator_device["imei"] = emulator.name
149
160
  emulator_device["adb_imei"] = self.adb_get_imei(adb_device)
150
161
  self.device_dict[emulator.name] = emulator_device
151
162
  logger.debug(f'refresh emulators {self.device_dict}')
@@ -191,12 +202,13 @@ class DeviceManager:
191
202
  self.start()
192
203
  logger.debug(f'preferred device: {preferred}')
193
204
 
194
- def adb_get_imei(self, device):
205
+ @staticmethod
206
+ def adb_get_imei(device):
195
207
  try:
196
208
  return device.shell("settings get secure android_id") or device.shell(
197
209
  "service call iphonesubinfo 4") or device.prop.model
198
210
  except Exception as e:
199
- logger.error(f"adb_get_imei error {device}", e)
211
+ logger.error(f"adb_get_imei error maybe offline {device}")
200
212
  return None
201
213
 
202
214
  def get_preferred_device(self):
@@ -0,0 +1,148 @@
1
+ import cv2
2
+ import numpy as np
3
+
4
+ from ok.feature.Box import Box
5
+
6
+ black_color = {
7
+ 'r': (0, 0), # Red range
8
+ 'g': (0, 0), # Green range
9
+ 'b': (0, 0) # Blue range
10
+ }
11
+
12
+ white_color = {
13
+ 'r': (255, 255), # Red range
14
+ 'g': (255, 255), # Green range
15
+ 'b': (255, 255) # Blue range
16
+ }
17
+
18
+
19
+ def calculate_colorfulness(image, box=None):
20
+ if box is not None:
21
+ image = image[box.y:box.y + box.height, box.x:box.x + box.width, :3]
22
+ # Split the image into its respective RGB components
23
+ (B, G, R) = cv2.split(image.astype("float"))
24
+
25
+ # Compute rg = R - G
26
+ rg = np.absolute(R - G)
27
+
28
+ # Compute yb = 0.5 * (R + G) - B
29
+ yb = np.absolute(0.5 * (R + G) - B)
30
+
31
+ # Compute the mean and standard deviation of both rg and yb
32
+ (rbMean, rbStd) = (np.mean(rg), np.std(rg))
33
+ (ybMean, ybStd) = (np.mean(yb), np.std(yb))
34
+
35
+ # Combine the mean and standard deviation
36
+ stdRoot = np.sqrt((rbStd ** 2) + (ybStd ** 2))
37
+ meanRoot = np.sqrt((rbMean ** 2) + (ybMean ** 2))
38
+
39
+ # Derive the "colorfulness" metric
40
+ colorfulness = stdRoot + (0.3 * meanRoot)
41
+
42
+ return colorfulness / 100
43
+
44
+
45
+ def get_saturation(image, box=None):
46
+ # Load the image
47
+
48
+ # Check if image loaded successfully
49
+ if image is None:
50
+ raise ValueError("Image not found or path is incorrect")
51
+
52
+ if box is not None:
53
+ if (box.x >= 0 and box.y >= 0 and
54
+ box.x + box.width <= image.shape[1] and # image.shape[1] is the width of the image
55
+ box.y + box.height <= image.shape[
56
+ 0]) and box.width > 0 and box.height > 0: # image.shape[0] is the height of the image
57
+
58
+ # Extract the region of interest (ROI) using slicing
59
+
60
+ image = image[box.y:box.y + box.height, box.x:box.x + box.width, :3]
61
+
62
+ # Convert image to HSV color space
63
+ hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
64
+
65
+ # Extract the saturation channel
66
+ saturation_channel = hsv_image[:, :, 1]
67
+
68
+ # Calculate the mean saturation
69
+ mean_saturation = saturation_channel.mean() / 255
70
+
71
+ # If the mean saturation is above the threshold, the image is colored; otherwise, it is grayscale
72
+ return mean_saturation
73
+
74
+
75
+ def find_color_rectangles(image, color_range, min_width, min_height, max_width=-1, max_height=-1, threshold=0.95,
76
+ box=None):
77
+ if image is None:
78
+ raise ValueError("Image not found or path is incorrect")
79
+ if box is not None:
80
+ image = image[box.y:box.y + box.height, box.x:box.x + box.width, :3]
81
+
82
+ # Convert color range to BGR format for OpenCV
83
+ lower_bound = np.array([color_range['b'][0], color_range['g'][0], color_range['r'][0]], dtype="uint8")
84
+ upper_bound = np.array([color_range['b'][1], color_range['g'][1], color_range['r'][1]], dtype="uint8")
85
+
86
+ # Create a mask for the color range
87
+ mask = cv2.inRange(image, lower_bound, upper_bound)
88
+
89
+ # Find contours in the mask
90
+ contours, _ = cv2.findContours(mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
91
+
92
+ results = []
93
+
94
+ for contour in contours:
95
+ # Get the bounding rectangle
96
+ x, y, w, h = cv2.boundingRect(contour)
97
+
98
+ # Check if the rectangle meets the size criteria
99
+ if w >= min_width and h >= min_height and (max_height == -1 or h <= max_height) and (
100
+ max_width == -1 or w <= max_width):
101
+
102
+ # Extract the region of interest (ROI) from the mask
103
+ roi_mask = mask[y:y + h, x:x + w]
104
+
105
+ # Calculate the total number of pixels in the ROI
106
+ total_pixels = roi_mask.size
107
+
108
+ # Calculate the number of matching pixels (value 255)
109
+ matching_pixels = np.sum(roi_mask == 255)
110
+
111
+ # Check if the percentage of matching pixels is greater than or equal to 90%\
112
+ percent = (matching_pixels / total_pixels)
113
+ if percent >= threshold:
114
+ # Store the result
115
+ results.append(
116
+ Box(x, y, w, h, confidence=percent)
117
+ )
118
+
119
+ return results
120
+
121
+
122
+ def calculate_color_percentage(image, color_ranges, box=None):
123
+ # Check if the ROI is within the image bounds
124
+ if box is not None:
125
+ if (box.x >= 0 and box.y >= 0 and
126
+ box.x + box.width <= image.shape[1] and # image.shape[1] is the width of the image
127
+ box.y + box.height <= image.shape[
128
+ 0]) and box.width > 0 and box.height > 0: # image.shape[0] is the height of the image
129
+
130
+ # Extract the region of interest (ROI) using slicing
131
+
132
+ image = image[box.y:box.y + box.height, box.x:box.x + box.width, :3]
133
+ else:
134
+ # Return some error value or raise an exception
135
+ # For example, return 0 or None
136
+ return 0 # or None, or raise an exception
137
+ else:
138
+ image = image[:, :, :3]
139
+ # Create a mask for the pixels within the desired color range
140
+ mask = cv2.inRange(image,
141
+ (color_ranges['b'][0], color_ranges['g'][0], color_ranges['r'][0]),
142
+ (color_ranges['b'][1], color_ranges['g'][1], color_ranges['r'][1]))
143
+
144
+ # Calculate the percentage of pixels within the color range
145
+ target_pixels = cv2.countNonZero(mask)
146
+ total_pixels = image.size / 3 # Divide by 3 for an RGB image
147
+ percentage = target_pixels / total_pixels
148
+ return percentage
@@ -10,14 +10,14 @@ class Box:
10
10
  confidence: float = 1,
11
11
  name=None, to_x: int | float = -1, to_y: int | float = -1) -> None:
12
12
  self.name = name
13
- self.x = int(x)
14
- self.y = int(y)
13
+ self.x = round(x)
14
+ self.y = round(y)
15
15
  if to_x != -1 and to_y != -1:
16
- self.width = int(to_x - x)
17
- self.height = int(to_y - y)
16
+ self.width = round(to_x - x)
17
+ self.height = round(to_y - y)
18
18
  else:
19
- self.width = int(width)
20
- self.height = int(height)
19
+ self.width = round(width)
20
+ self.height = round(height)
21
21
  if self.width <= 0 or self.height <= 0:
22
22
  raise ValueError(f'width and height must be greater than zero {x} {y} {width} {height} {to_x} {to_y}')
23
23
  self.confidence = confidence
@@ -265,6 +265,6 @@ def relative_box(frame_width, frame_height, x, y, to_x=1, to_y=1, width=0, heigh
265
265
  width = to_x - x
266
266
  if height == 0:
267
267
  height = to_y - y
268
- return Box(int(x * frame_width), int(y * frame_height),
269
- int(width * frame_width), int(height * frame_height),
268
+ return Box(round(x * frame_width), round(y * frame_height),
269
+ round(width * frame_width), round(height * frame_height),
270
270
  name=name)
@@ -145,7 +145,7 @@ class FeatureSet:
145
145
 
146
146
  def find_feature(self, mat: np.ndarray, category_name: str, horizontal_variance: float = 0,
147
147
  vertical_variance: float = 0, threshold: float = 0, use_gray_scale: bool = False, x=-1, y=-1,
148
- to_x=-1, to_y=-1, width=-1, height=-1) -> List[Box]:
148
+ to_x=-1, to_y=-1, width=-1, height=-1, box=None) -> List[Box]:
149
149
  """
150
150
  Find a feature within a given variance.
151
151
 
@@ -172,7 +172,12 @@ class FeatureSet:
172
172
  raise ValueError(f"FeatureSet: " + category_name + " not found in featureDict")
173
173
  feature = self.feature_dict[category_name]
174
174
  feature_width, feature_height = feature.width, feature.height
175
- if x != -1 and y != -1:
175
+ if box is not None:
176
+ search_x1 = box.x
177
+ search_y1 = box.y
178
+ search_x2 = box.x + box.width
179
+ search_y2 = box.y + box.height
180
+ elif x != -1 and y != -1:
176
181
  frame_height, frame_width, *_ = mat.shape
177
182
  if width == -1:
178
183
  width = to_x - x
@@ -11,11 +11,9 @@ class FindFeature:
11
11
  self.executor = None
12
12
 
13
13
  def find_feature(self, feature_name, horizontal_variance=0, vertical_variance=0, threshold=0,
14
- use_gray_scale=False, x=-1, y=-1, to_x=-1, to_y=-1, width=-1, height=-1) -> List[Box]:
15
- if self.executor.frame is None:
16
- return list()
14
+ use_gray_scale=False, x=-1, y=-1, to_x=-1, to_y=-1, width=-1, height=-1, box=None) -> List[Box]:
17
15
  return self.feature_set.find_feature(self.executor.frame, feature_name, horizontal_variance, vertical_variance,
18
- threshold, use_gray_scale, x, y, to_x, to_y, width, height)
16
+ threshold, use_gray_scale, x, y, to_x, to_y, width, height, box=box)
19
17
 
20
18
  def get_box_by_name(self, name):
21
19
  return self.feature_set.get_box_by_name(self.executor.frame, name)
@@ -47,7 +45,8 @@ class FindFeature:
47
45
 
48
46
  def find_one(self, feature_name, horizontal_variance=0, vertical_variance=0, threshold=0,
49
47
  use_gray_scale=False) -> Box:
50
- boxes = self.find_feature(feature_name, horizontal_variance, vertical_variance, threshold, use_gray_scale=False)
48
+ boxes = self.find_feature(feature_name, horizontal_variance, vertical_variance, threshold,
49
+ use_gray_scale=use_gray_scale)
51
50
  if len(boxes) > 0:
52
51
  if len(boxes) > 1:
53
52
  print(f"find_one:found {feature_name} too many {len(boxes)}", file=sys.stderr)
@@ -24,7 +24,7 @@ class StartController(QObject):
24
24
 
25
25
  def do_start(self, task=None):
26
26
  communicate.starting_emulator.emit(False, None, 30)
27
- ok.gui.device_manager.do_refresh()
27
+ ok.gui.device_manager.do_refresh(True)
28
28
 
29
29
  device = ok.gui.device_manager.get_preferred_device()
30
30
 
@@ -35,7 +35,7 @@ class StartController(QObject):
35
35
  execute(path)
36
36
  wait_until = time.time() + 30
37
37
  while not self.exit_event.is_set():
38
- ok.gui.device_manager.do_refresh()
38
+ ok.gui.device_manager.do_refresh(True)
39
39
  error = self.check_device_error()
40
40
  if error is None:
41
41
  break
@@ -73,13 +73,21 @@ class StartController(QObject):
73
73
  if not ok.gui.device_manager.capture_method.connected():
74
74
  logger.error(f'Game window is not connected {ok.gui.device_manager.capture_method}')
75
75
  return self.tr("Game window is not connected, please select the game window and capture method.")
76
- supported_ratio = self.config.get(
77
- 'supported_screen_ratio')
78
- supported, resolution = ok.gui.executor.check_frame_and_resolution(supported_ratio)
76
+ supported_resolution = self.config.get(
77
+ 'supported_resolution', {})
78
+ supported_ratio = supported_resolution.get('ratio')
79
+ min_size = supported_resolution.get('min_size')
80
+ supported, resolution = ok.gui.executor.check_frame_and_resolution(supported_ratio, min_size)
79
81
  if not supported:
80
- return self.tr(
81
- "Window resolution {resolution} is not supported, the supported ratio is {supported_ratio}, check if game windows is minimized, resized or out of screen.",
82
- ).format(resolution=resolution, supported_ratio=supported_ratio)
82
+ error = self.tr(
83
+ "Game resolution {resolution} is not supported").format(resolution=resolution)
84
+ if supported_ratio:
85
+ error += self.tr(', the supported ratio is {supported_ratio}').format(supported_ratio=supported_ratio)
86
+ if supported_ratio:
87
+ error += self.tr(', the supported min resolution is {min_size}').format(
88
+ min_size=f'{min_size[0]}x{min_size[1]}')
89
+ error += self.tr(', check if game windows is minimized, resized or out of screen.')
90
+ return error
83
91
  if device and device['device'] == "windows" and not is_admin():
84
92
  return self.tr(
85
93
  f"PC version requires admin privileges, Please restart this app with admin privileges!")
@@ -88,6 +88,7 @@ class DebugTab(Tab):
88
88
  self.task_changed(self.config.get('target_task'))
89
89
  else:
90
90
  self.tasks_combo_box.setCurrentIndex(0)
91
+ self.config['target_task'] = class_names[0]
91
92
 
92
93
  self.call_button = PushButton(self.tr("Call"))
93
94
  self.call_button.clicked.connect(lambda: self.handler.post(self.call))
@@ -146,8 +147,9 @@ class DebugTab(Tab):
146
147
  old_interaction = ok.gui.device_manager.interaction
147
148
  try:
148
149
  images = self.config.get("target_images")
149
- ok.gui.device_manager.capture_method = ImageCaptureMethod(images)
150
- ok.gui.device_manager.interaction = DoNothingInteraction(ok.gui.device_manager.capture_method)
150
+ if images:
151
+ ok.gui.device_manager.capture_method = ImageCaptureMethod(images)
152
+ ok.gui.device_manager.interaction = DoNothingInteraction(ok.gui.device_manager.capture_method)
151
153
  ok.gui.executor.debug_mode = True
152
154
  attr = getattr(task, func_name)
153
155
  if callable(attr):