ok-script 0.0.85__tar.gz → 0.0.87__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 (186) hide show
  1. {ok-script-0.0.85 → ok-script-0.0.87}/PKG-INFO +1 -1
  2. {ok-script-0.0.85 → ok-script-0.0.87}/ok/OK.py +1 -1
  3. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/HwndWindow.py +7 -2
  4. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/adb/DeviceManager.py +13 -14
  5. ok-script-0.0.87/ok/capture/adb/WindowsCaptureFactory.py +42 -0
  6. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/WindowsGraphicsCaptureMethod.py +66 -59
  7. {ok-script-0.0.85 → ok-script-0.0.87}/ok/config/Config.py +3 -1
  8. ok-script-0.0.87/ok/feature/CompressCoco.py +57 -0
  9. {ok-script-0.0.85 → ok-script-0.0.87}/ok/feature/FeatureSet.py +68 -53
  10. {ok-script-0.0.85 → ok-script-0.0.87}/ok/feature/FindFeature.py +2 -2
  11. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/App.py +6 -0
  12. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/MainWindow.py +3 -6
  13. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/debug/DebugTab.py +0 -3
  14. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/debug/FrameWidget.py +4 -6
  15. ok-script-0.0.87/ok/gui/debug/LogWindow.py +190 -0
  16. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/debug/Screenshot.py +0 -1
  17. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/TaskCard.py +5 -5
  18. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/TaskOpButton.py +2 -8
  19. {ok-script-0.0.85 → ok-script-0.0.87}/ok/interaction/BaseInteraction.py +3 -3
  20. {ok-script-0.0.85 → ok-script-0.0.87}/ok/ocr/OCR.py +1 -1
  21. {ok-script-0.0.85 → ok-script-0.0.87}/ok/task/BaseTask.py +30 -13
  22. {ok-script-0.0.85 → ok-script-0.0.87}/ok/task/ExecutorOperation.py +8 -5
  23. {ok-script-0.0.85 → ok-script-0.0.87}/ok/task/TaskExecutor.py +33 -35
  24. {ok-script-0.0.85 → ok-script-0.0.87}/ok/task/TriggerTask.py +1 -2
  25. ok-script-0.0.87/ok/util/list.py +9 -0
  26. {ok-script-0.0.85 → ok-script-0.0.87}/ok_script.egg-info/PKG-INFO +1 -1
  27. {ok-script-0.0.85 → ok-script-0.0.87}/ok_script.egg-info/SOURCES.txt +2 -2
  28. {ok-script-0.0.85 → ok-script-0.0.87}/setup.py +1 -1
  29. ok-script-0.0.85/ok/capture/adb/WindowsCaptureFactory.py +0 -41
  30. ok-script-0.0.85/ok/gui/debug/LoggerWidget.py +0 -77
  31. ok-script-0.0.85/ok/task/OneTimeTask.py +0 -35
  32. ok-script-0.0.85/ok/util/list.py +0 -2
  33. {ok-script-0.0.85 → ok-script-0.0.87}/README.md +0 -0
  34. {ok-script-0.0.85 → ok-script-0.0.87}/ok/__init__.py +0 -0
  35. {ok-script-0.0.85 → ok-script-0.0.87}/ok/alas/__init__.py +0 -0
  36. {ok-script-0.0.85 → ok-script-0.0.87}/ok/alas/emulator_base.py +0 -0
  37. {ok-script-0.0.85 → ok-script-0.0.87}/ok/alas/emulator_windows.py +0 -0
  38. {ok-script-0.0.85 → ok-script-0.0.87}/ok/alas/platform_base.py +0 -0
  39. {ok-script-0.0.85 → ok-script-0.0.87}/ok/alas/platform_windows.py +0 -0
  40. {ok-script-0.0.85 → ok-script-0.0.87}/ok/alas/utils.py +0 -0
  41. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/BaseCaptureMethod.py +0 -0
  42. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/__init__.py +0 -0
  43. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/adb/ADBCaptureMethod.py +0 -0
  44. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/adb/__init__.py +0 -0
  45. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/adb/bin/__init__.py +0 -0
  46. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/image/ImageCaptureMethod.py +0 -0
  47. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/image/__init__.py +0 -0
  48. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/BaseWindowsCaptureMethod.py +0 -0
  49. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/BitBltCaptureMethod.py +0 -0
  50. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/DesktopDuplicationCaptureMethod.py +0 -0
  51. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/__init__.py +0 -0
  52. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/d3d11.py +0 -0
  53. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/dump.py +0 -0
  54. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/utils.py +0 -0
  55. {ok-script-0.0.85 → ok-script-0.0.87}/ok/capture/windows/window.py +0 -0
  56. {ok-script-0.0.85 → ok-script-0.0.87}/ok/color/Color.py +0 -0
  57. {ok-script-0.0.85 → ok-script-0.0.87}/ok/color/__init__.py +0 -0
  58. {ok-script-0.0.85 → ok-script-0.0.87}/ok/config/InfoDict.py +0 -0
  59. {ok-script-0.0.85 → ok-script-0.0.87}/ok/config/__init__.py +0 -0
  60. {ok-script-0.0.85 → ok-script-0.0.87}/ok/feature/Box.py +0 -0
  61. {ok-script-0.0.85 → ok-script-0.0.87}/ok/feature/Feature.py +0 -0
  62. {ok-script-0.0.85 → ok-script-0.0.87}/ok/feature/__init__.py +0 -0
  63. {ok-script-0.0.85 → ok-script-0.0.87}/ok/firebase/Analytics.py +0 -0
  64. {ok-script-0.0.85 → ok-script-0.0.87}/ok/firebase/__init__.py +0 -0
  65. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/Communicate.py +0 -0
  66. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/MessageWindow.py +0 -0
  67. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/StartController.py +0 -0
  68. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/TabTitles.py +0 -0
  69. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/__init__.py +0 -0
  70. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/about/AboutTab.py +0 -0
  71. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/about/HttpTextEdit.py +0 -0
  72. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/about/VersionCard.py +0 -0
  73. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/about/__init__.py +0 -0
  74. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/common/OKIcon.py +0 -0
  75. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/common/__init__.py +0 -0
  76. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/common/config.py +0 -0
  77. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/common/style_sheet.py +0 -0
  78. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/debug/AspectRatioWidget.py +0 -0
  79. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/debug/InfoWidget.py +0 -0
  80. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/debug/__init__.py +0 -0
  81. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/i18n/__init__.py +0 -0
  82. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/i18n/path.py +0 -0
  83. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/i18n/update.py +0 -0
  84. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/icon/__init__.py +0 -0
  85. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/icon/icon.py +0 -0
  86. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/overlay/OverlayWindow.py +0 -0
  87. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/overlay/__init__.py +0 -0
  88. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/qss/__init__.py +0 -0
  89. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/resources.py +0 -0
  90. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/settings/SettingTab.py +0 -0
  91. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/settings/__init__.py +0 -0
  92. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/start/SelectCaptureListView.py +0 -0
  93. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/start/StartCard.py +0 -0
  94. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/start/StartTab.py +0 -0
  95. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/start/__init__.py +0 -0
  96. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/ConfigItemFactory.py +0 -0
  97. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/ConfigLabelAndWidget.py +0 -0
  98. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/LabelAndDoubleSpinBox.py +0 -0
  99. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/LabelAndDropDown.py +0 -0
  100. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/LabelAndLineEdit.py +0 -0
  101. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/LabelAndList.py +0 -0
  102. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/LabelAndSpinBox.py +0 -0
  103. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/LabelAndSwitchButton.py +0 -0
  104. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/LabelAndWidget.py +0 -0
  105. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/ModifyListDialog.py +0 -0
  106. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/ModifyListItem.py +0 -0
  107. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/OneTimeTaskTab.py +0 -0
  108. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/StartButton.py +0 -0
  109. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/TooltipTableWidget.py +0 -0
  110. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/TriggerTaskTab.py +0 -0
  111. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/tasks/__init__.py +0 -0
  112. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/util/Alert.py +0 -0
  113. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/util/InitWorker.py +0 -0
  114. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/util/__init__.py +0 -0
  115. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/Card.py +0 -0
  116. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/EmptyCard.py +0 -0
  117. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/FramelessDialog.py +0 -0
  118. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/ListTableWidgetItem.py +0 -0
  119. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/NumericTableWidgetItem.py +0 -0
  120. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/StartLoadingDialog.py +0 -0
  121. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/StatusBar.py +0 -0
  122. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/Tab.py +0 -0
  123. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/TabWidget.py +0 -0
  124. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/UpdateConfigWidgetItem.py +0 -0
  125. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/YesNonWidgetItem.py +0 -0
  126. {ok-script-0.0.85 → ok-script-0.0.87}/ok/gui/widget/__init__.py +0 -0
  127. {ok-script-0.0.85 → ok-script-0.0.87}/ok/interaction/ADBInteraction.py +0 -0
  128. {ok-script-0.0.85 → ok-script-0.0.87}/ok/interaction/DoNothingInteraction.py +0 -0
  129. {ok-script-0.0.85 → ok-script-0.0.87}/ok/interaction/Win32Interaction.py +0 -0
  130. {ok-script-0.0.85 → ok-script-0.0.87}/ok/interaction/__init__.py +0 -0
  131. {ok-script-0.0.85 → ok-script-0.0.87}/ok/logging/Logger.py +0 -0
  132. {ok-script-0.0.85 → ok-script-0.0.87}/ok/logging/__init__.py +0 -0
  133. {ok-script-0.0.85 → ok-script-0.0.87}/ok/ocr/__init__.py +0 -0
  134. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Foundation/Collections.py +0 -0
  135. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Foundation/__init__.py +0 -0
  136. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Globalization/__init__.py +0 -0
  137. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Graphics/Capture/__init__.py +0 -0
  138. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Graphics/DirectX/Direct3D11/__init__.py +0 -0
  139. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Graphics/DirectX/__init__.py +0 -0
  140. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Graphics/Imaging/__init__.py +0 -0
  141. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Graphics/__init__.py +0 -0
  142. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Media/Ocr/__init__.py +0 -0
  143. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Media/__init__.py +0 -0
  144. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Security/Cryptography/__init__.py +0 -0
  145. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Security/__init__.py +0 -0
  146. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Storage/Streams/__init__.py +0 -0
  147. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/Storage/__init__.py +0 -0
  148. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/Windows/__init__.py +0 -0
  149. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/__init__.py +0 -0
  150. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/delegate.py +0 -0
  151. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/export.py +0 -0
  152. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/idldsl.py +0 -0
  153. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/inspectable.py +0 -0
  154. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/roapi.py +0 -0
  155. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/types.py +0 -0
  156. {ok-script-0.0.85 → ok-script-0.0.87}/ok/rotypes/winstring.py +0 -0
  157. {ok-script-0.0.85 → ok-script-0.0.87}/ok/save/BlackBarProcessor.py +0 -0
  158. {ok-script-0.0.85 → ok-script-0.0.87}/ok/save/PostProcessor.py +0 -0
  159. {ok-script-0.0.85 → ok-script-0.0.87}/ok/save/SaveByInterval.py +0 -0
  160. {ok-script-0.0.85 → ok-script-0.0.87}/ok/save/SaveByKeyPress.py +0 -0
  161. {ok-script-0.0.85 → ok-script-0.0.87}/ok/save/SaveMethodBase.py +0 -0
  162. {ok-script-0.0.85 → ok-script-0.0.87}/ok/save/__init__.py +0 -0
  163. {ok-script-0.0.85 → ok-script-0.0.87}/ok/scene/FeatureScene.py +0 -0
  164. {ok-script-0.0.85 → ok-script-0.0.87}/ok/scene/Scene.py +0 -0
  165. {ok-script-0.0.85 → ok-script-0.0.87}/ok/scene/__init__.py +0 -0
  166. {ok-script-0.0.85 → ok-script-0.0.87}/ok/stats/StreamStats.py +0 -0
  167. {ok-script-0.0.85 → ok-script-0.0.87}/ok/stats/__init__.py +0 -0
  168. {ok-script-0.0.85 → ok-script-0.0.87}/ok/task/__init__.py +0 -0
  169. {ok-script-0.0.85 → ok-script-0.0.87}/ok/update/GithubMultiDownloader.py +0 -0
  170. {ok-script-0.0.85 → ok-script-0.0.87}/ok/update/Updater.py +0 -0
  171. {ok-script-0.0.85 → ok-script-0.0.87}/ok/update/__init__.py +0 -0
  172. {ok-script-0.0.85 → ok-script-0.0.87}/ok/update/gen_md5.py +0 -0
  173. {ok-script-0.0.85 → ok-script-0.0.87}/ok/util/Handler.py +0 -0
  174. {ok-script-0.0.85 → ok-script-0.0.87}/ok/util/__init__.py +0 -0
  175. {ok-script-0.0.85 → ok-script-0.0.87}/ok/util/exit_event.py +0 -0
  176. {ok-script-0.0.85 → ok-script-0.0.87}/ok/util/json.py +0 -0
  177. {ok-script-0.0.85 → ok-script-0.0.87}/ok/util/path.py +0 -0
  178. {ok-script-0.0.85 → ok-script-0.0.87}/ok/util/thread.py +0 -0
  179. {ok-script-0.0.85 → ok-script-0.0.87}/ok/util/win32_process.py +0 -0
  180. {ok-script-0.0.85 → ok-script-0.0.87}/ok/util/yaml.py +0 -0
  181. {ok-script-0.0.85 → ok-script-0.0.87}/ok_script.egg-info/dependency_links.txt +0 -0
  182. {ok-script-0.0.85 → ok-script-0.0.87}/ok_script.egg-info/requires.txt +0 -0
  183. {ok-script-0.0.85 → ok-script-0.0.87}/ok_script.egg-info/top_level.txt +0 -0
  184. {ok-script-0.0.85 → ok-script-0.0.87}/setup.cfg +0 -0
  185. {ok-script-0.0.85 → ok-script-0.0.87}/tests/__init__.py +0 -0
  186. {ok-script-0.0.85 → ok-script-0.0.87}/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.85
3
+ Version: 0.0.87
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
@@ -97,7 +97,7 @@ class OK:
97
97
  if template_matching is not None:
98
98
  coco_feature_json = self.config.get('template_matching').get('coco_feature_json')
99
99
  from ok.feature.FeatureSet import FeatureSet
100
- self.feature_set = FeatureSet(coco_feature_json,
100
+ self.feature_set = FeatureSet(self.debug, coco_feature_json,
101
101
  default_horizontal_variance=template_matching.get(
102
102
  'default_horizontal_variance', 0),
103
103
  default_vertical_variance=template_matching.get('default_vertical_variance',
@@ -160,6 +160,8 @@ def find_hwnd(title, exe_name, frame_width, frame_height, player_id=-1):
160
160
  elif not re.search(title, text):
161
161
  return True
162
162
  name, full_path, cmdline = get_exe_by_hwnd(hwnd)
163
+ if not name:
164
+ return True
163
165
  x, y, border, title_height, width, height, scaling, ext_left_bounds, ext_top_bounds = get_window_bounds(
164
166
  hwnd)
165
167
  ret = (hwnd, full_path, width, height, x, y, text)
@@ -246,8 +248,11 @@ def get_exe_by_hwnd(hwnd):
246
248
  _, pid = win32process.GetWindowThreadProcessId(hwnd)
247
249
 
248
250
  # Get the process name and executable path
249
- process = psutil.Process(pid)
250
- return process.name(), process.exe(), process.cmdline()
251
+ if pid > 0:
252
+ process = psutil.Process(pid)
253
+ return process.name(), process.exe(), process.cmdline()
254
+ else:
255
+ return None, None, None
251
256
 
252
257
 
253
258
  if __name__ == '__main__':
@@ -1,4 +1,4 @@
1
- from adbutils import AdbTimeout
1
+ from adbutils import AdbTimeout, AdbError
2
2
 
3
3
  from ok.alas.platform_windows import get_emulator_exe
4
4
  from ok.capture.HwndWindow import HwndWindow, find_hwnd
@@ -53,27 +53,25 @@ class DeviceManager:
53
53
  logger.debug(f'connect adb')
54
54
  return self._adb
55
55
 
56
- def adb_connect(self, addr):
56
+ def adb_connect(self, addr, try_connect=True):
57
57
  try:
58
- for info in self.adb.list():
58
+ for device in self.adb.device_list():
59
59
  if self.exit_event.is_set():
60
60
  logger.error(f"adb_connect exit_event is set")
61
61
  return None
62
- if info.serial == addr:
63
- if info.state == 'offline':
62
+ if device.serial == addr:
63
+ if device.info['state'] == 'offline':
64
64
  logger.debug(f'adb_connect offline disconnect first {addr}')
65
65
  self.adb.disconnect(addr)
66
66
  else:
67
67
  logger.debug(f'adb_connect already connected {addr}')
68
- return self.adb.device(addr)
69
- self.adb.connect(addr, timeout=5)
70
- device = self.adb.device(addr)
71
- logger.debug(f'adb_connect {addr} device {device}')
72
- return device
68
+ return device
69
+ if try_connect:
70
+ self.adb.connect(addr, timeout=5)
71
+ logger.debug(f'adb_connect {addr}')
72
+ return self.adb_connect(addr, try_connect=False)
73
73
  except AdbTimeout as e:
74
74
  logger.error(f"adb connect error try kill server {addr}", e)
75
- # self.adb.server_kill()
76
- # self._adb = None
77
75
  except Exception as e:
78
76
  logger.error(f"adb connect error return none {addr}", e)
79
77
 
@@ -145,7 +143,7 @@ class DeviceManager:
145
143
  logger.debug(f"refresh current only skip others {preferred['imei']} != {emulator.name}")
146
144
  break
147
145
  adb_device = self.adb_connect(emulator.serial)
148
- width, height = self.get_resolution(adb_device)
146
+ width, height = self.get_resolution(adb_device) if adb_device is not None else 0, 0
149
147
  name, hwnd, full_path, x, y, width, height = find_hwnd(None,
150
148
  emulator.path, width, height, emulator.player_id)
151
149
  connected = adb_device is not None and name is not None
@@ -339,12 +337,13 @@ class DeviceManager:
339
337
  if device is not None:
340
338
  try:
341
339
  return device.shell(*args, **kwargs)
340
+ except AdbError as e:
341
+ logger.debug(f'shell adb error {args} {e}')
342
342
  except Exception as e:
343
343
  addr = self.get_preferred_device()['address']
344
344
  self.refresh_emulators()
345
345
  new_addr = self.get_preferred_device()['address']
346
346
  logger.error(f"shell_wrapper error occurred, try refresh_emulators {addr} {new_addr}", e)
347
- return None
348
347
  else:
349
348
  raise Exception('Device is none')
350
349
 
@@ -0,0 +1,42 @@
1
+ from ok.logging.Logger import get_logger
2
+
3
+ logger = get_logger(__name__)
4
+
5
+
6
+ def update_capture_method(config, capture_method, hwnd, require_bg=False, use_bit_blt_only=False):
7
+ try:
8
+ if config.get('can_bit_blt'):
9
+ logger.debug(
10
+ f"try BitBlt method {config} {hwnd} current_type:{type(capture_method)}")
11
+ from ok.capture.windows.BitBltCaptureMethod import BitBltCaptureMethod
12
+ target_method = BitBltCaptureMethod
13
+ capture_method = get_capture(capture_method, target_method, hwnd)
14
+ if capture_method.test_exclusive_full_screen():
15
+ return capture_method
16
+ else:
17
+ logger.info("test_exclusive_full_screen failed, can't use BitBlt")
18
+ if use_bit_blt_only:
19
+ return None
20
+ from ok.capture.windows.WindowsGraphicsCaptureMethod import windows_graphics_available
21
+ if windows_graphics_available():
22
+ from ok.capture.windows.WindowsGraphicsCaptureMethod import WindowsGraphicsCaptureMethod
23
+ target_method = WindowsGraphicsCaptureMethod
24
+ capture_method = get_capture(capture_method, target_method, hwnd)
25
+ return capture_method
26
+
27
+ if not require_bg:
28
+ from ok.capture.windows.DesktopDuplicationCaptureMethod import DesktopDuplicationCaptureMethod
29
+ target_method = DesktopDuplicationCaptureMethod
30
+ capture_method = get_capture(capture_method, target_method, hwnd)
31
+ return capture_method
32
+ except Exception as e:
33
+ logger.error(f'update_capture_method exception, return None: ', e)
34
+
35
+
36
+ def get_capture(capture_method, target_method, hwnd):
37
+ if not isinstance(capture_method, target_method):
38
+ if capture_method is not None:
39
+ capture_method.close()
40
+ capture_method = target_method(hwnd)
41
+ capture_method.hwnd_window = hwnd
42
+ return capture_method
@@ -23,7 +23,7 @@ logger = get_logger(__name__)
23
23
  class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
24
24
  name = "Windows Graphics Capture"
25
25
  description = "fast, most compatible, capped at 60fps"
26
- last_frame = None
26
+ last_dx_frame = None
27
27
  last_frame_time = 0
28
28
  frame_pool = None
29
29
  item = None
@@ -38,67 +38,71 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
38
38
 
39
39
  def frame_arrived_callback(self, x, y):
40
40
  try:
41
- frame = self.frame_pool.TryGetNextFrame()
41
+ self.last_frame_time = time.time()
42
+ self.last_dx_frame = self.frame_pool.TryGetNextFrame()
42
43
  except Exception as e:
43
44
  logger.error(f"TryGetNextFrame error {e}")
44
45
  self.close()
45
46
  return
47
+
48
+ def convert_dx_frame(self):
49
+ frame = self.last_dx_frame
46
50
  if not frame:
51
+ return None
52
+
53
+ need_reset_framepool = False
54
+ if frame.ContentSize.Width != self.last_size.Width or frame.ContentSize.Height != self.last_size.Height:
55
+ need_reset_framepool = True
56
+ self.last_size = frame.ContentSize
57
+
58
+ if need_reset_framepool:
59
+ logger.info('need_reset_framepool')
60
+ self.reset_framepool(frame.ContentSize)
47
61
  return
48
- self.last_frame_time = time.time()
49
- img = None
50
- with frame:
51
- need_reset_framepool = False
52
- need_reset_device = False
53
- if frame.ContentSize.Width != self.last_size.Width or frame.ContentSize.Height != self.last_size.Height:
54
- need_reset_framepool = True
55
- self.last_size = frame.ContentSize
62
+ need_reset_device = False
56
63
 
57
- if need_reset_framepool:
58
- self.reset_framepool(frame.ContentSize)
59
- return
60
- tex = None
64
+ tex = None
61
65
 
62
- cputex = None
63
- try:
64
- from ok.rotypes.Windows.Graphics.DirectX.Direct3D11 import IDirect3DDxgiInterfaceAccess
65
- from ok.rotypes.roapi import GetActivationFactory
66
- tex = frame.Surface.astype(IDirect3DDxgiInterfaceAccess).GetInterface(
67
- d3d11.ID3D11Texture2D.GUID).astype(d3d11.ID3D11Texture2D)
68
- desc = tex.GetDesc()
69
- desc2 = d3d11.D3D11_TEXTURE2D_DESC()
70
- desc2.Width = desc.Width
71
- desc2.Height = desc.Height
72
- desc2.MipLevels = desc.MipLevels
73
- desc2.ArraySize = desc.ArraySize
74
- desc2.Format = desc.Format
75
- desc2.SampleDesc = desc.SampleDesc
76
- desc2.Usage = d3d11.D3D11_USAGE_STAGING
77
- desc2.CPUAccessFlags = d3d11.D3D11_CPU_ACCESS_READ
78
- desc2.BindFlags = 0
79
- desc2.MiscFlags = 0
80
- cputex = self.dxdevice.CreateTexture2D(ctypes.byref(desc2), None)
81
- self.immediatedc.CopyResource(cputex, tex)
82
- mapinfo = self.immediatedc.Map(cputex, 0, d3d11.D3D11_MAP_READ, 0)
83
- img = np.ctypeslib.as_array(ctypes.cast(mapinfo.pData, PBYTE),
84
- (desc.Height, mapinfo.RowPitch // 4, 4))[
85
- :, :desc.Width].copy()
86
- self.immediatedc.Unmap(cputex, 0)
87
- except OSError as e:
88
- if e.winerror == d3d11.DXGI_ERROR_DEVICE_REMOVED or e.winerror == d3d11.DXGI_ERROR_DEVICE_RESET:
89
- need_reset_framepool = True
90
- need_reset_device = True
91
- else:
92
- raise
93
- finally:
94
- if tex is not None:
95
- tex.Release()
96
- if cputex is not None:
97
- cputex.Release()
98
- if need_reset_framepool:
99
- self.reset_framepool(frame.ContentSize, need_reset_device)
100
- return self.get_frame()
101
- self.last_frame = img
66
+ cputex = None
67
+ try:
68
+ from ok.rotypes.Windows.Graphics.DirectX.Direct3D11 import IDirect3DDxgiInterfaceAccess
69
+ from ok.rotypes.roapi import GetActivationFactory
70
+ tex = frame.Surface.astype(IDirect3DDxgiInterfaceAccess).GetInterface(
71
+ d3d11.ID3D11Texture2D.GUID).astype(d3d11.ID3D11Texture2D)
72
+ desc = tex.GetDesc()
73
+ desc2 = d3d11.D3D11_TEXTURE2D_DESC()
74
+ desc2.Width = desc.Width
75
+ desc2.Height = desc.Height
76
+ desc2.MipLevels = desc.MipLevels
77
+ desc2.ArraySize = desc.ArraySize
78
+ desc2.Format = desc.Format
79
+ desc2.SampleDesc = desc.SampleDesc
80
+ desc2.Usage = d3d11.D3D11_USAGE_STAGING
81
+ desc2.CPUAccessFlags = d3d11.D3D11_CPU_ACCESS_READ
82
+ desc2.BindFlags = 0
83
+ desc2.MiscFlags = 0
84
+ cputex = self.dxdevice.CreateTexture2D(ctypes.byref(desc2), None)
85
+ self.immediatedc.CopyResource(cputex, tex)
86
+ mapinfo = self.immediatedc.Map(cputex, 0, d3d11.D3D11_MAP_READ, 0)
87
+ img = np.ctypeslib.as_array(ctypes.cast(mapinfo.pData, PBYTE),
88
+ (desc.Height, mapinfo.RowPitch // 4, 4))[
89
+ :, :desc.Width].copy()
90
+ self.immediatedc.Unmap(cputex, 0)
91
+ return img
92
+ except OSError as e:
93
+ if e.winerror == d3d11.DXGI_ERROR_DEVICE_REMOVED or e.winerror == d3d11.DXGI_ERROR_DEVICE_RESET:
94
+ need_reset_framepool = True
95
+ need_reset_device = True
96
+ else:
97
+ raise e
98
+ finally:
99
+ if tex is not None:
100
+ tex.Release()
101
+ if cputex is not None:
102
+ cputex.Release()
103
+ if need_reset_framepool:
104
+ self.reset_framepool(frame.ContentSize, need_reset_device)
105
+ return self.get_frame()
102
106
 
103
107
  @property
104
108
  def hwnd_window(self):
@@ -139,7 +143,7 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
139
143
  self.evtoken = item.add_Closed(delegate)
140
144
  self.frame_pool = Direct3D11CaptureFramePool.CreateFreeThreaded(self.rtdevice,
141
145
  DirectXPixelFormat.B8G8R8A8UIntNormalized,
142
- 1, item.Size)
146
+ 2, item.Size)
143
147
  self.session = self.frame_pool.CreateCaptureSession(item)
144
148
  pool = self.frame_pool
145
149
  pool.add_FrameArrived(
@@ -193,10 +197,11 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
193
197
  @override
194
198
  def do_get_frame(self):
195
199
  if self.start_or_stop():
196
- frame = self.last_frame
197
- self.last_frame = None
200
+ frame = self.convert_dx_frame()
201
+ if frame is None:
202
+ return
203
+ self.last_dx_frame = None
198
204
  latency = time.time() - self.last_frame_time
199
- self.last_frame_time = time.time()
200
205
 
201
206
  frame = self.crop_image(frame)
202
207
 
@@ -209,14 +214,16 @@ class WindowsGraphicsCaptureMethod(BaseWindowsCaptureMethod):
209
214
  logger.warning(f"latency too large return None frame: {latency}")
210
215
  return None
211
216
  else:
217
+ # logger.debug(f'frame latency: {latency}')
212
218
  return frame
213
219
 
214
220
  def reset_framepool(self, size, reset_device=False):
221
+ logger.info(f'reset_framepool')
215
222
  from ok.rotypes.Windows.Graphics.DirectX import DirectXPixelFormat
216
223
  if reset_device:
217
224
  self.create_device()
218
225
  self.frame_pool.Recreate(self.rtdevice,
219
- DirectXPixelFormat.B8G8R8A8UIntNormalized, 1, size)
226
+ DirectXPixelFormat.B8G8R8A8UIntNormalized, 2, size)
220
227
 
221
228
  def crop_image(self, frame):
222
229
  if frame is not None:
@@ -78,8 +78,10 @@ class Config(dict):
78
78
 
79
79
  def __setitem__(self, key, value):
80
80
  if self.validate(key, value):
81
+ old_value = self.get(key)
81
82
  super().__setitem__(key, value)
82
- self.save_file()
83
+ if old_value != value:
84
+ self.save_file()
83
85
 
84
86
  def __getitem__(self, key):
85
87
  try:
@@ -0,0 +1,57 @@
1
+ import json
2
+ import os
3
+ import sys
4
+
5
+ import cv2
6
+ from PIL import Image
7
+
8
+
9
+ def compress_coco(coco_json) -> None:
10
+ coco_folder = os.path.dirname(coco_json)
11
+
12
+ image_dict = {}
13
+ with open(coco_json, 'r') as file:
14
+ data = json.load(file)
15
+
16
+ image_map = {image['id']: image['file_name'] for image in data['images']}
17
+ category_map = {category['id']: category['name'] for category in data['categories']}
18
+
19
+ for annotation in data['annotations']:
20
+ image_id = annotation['image_id']
21
+ category_id = annotation['category_id']
22
+ bbox = annotation['bbox']
23
+
24
+ # Load and scale the image
25
+ image_path = str(os.path.join(coco_folder, image_map[image_id]))
26
+ image = cv2.imread(image_path)
27
+ original_height, original_width = image.shape[:2]
28
+ if image is None:
29
+ print(f'Could not read image {image_path}')
30
+ continue
31
+ x, y, w, h = bbox
32
+ # Crop the image to the bounding box
33
+ image = image[round(y):round(y + h), round(x):round(x + w), :3]
34
+
35
+ image_features = image_dict.get(image_path, [])
36
+ image_features.append((round(x), round(y), image, original_width, original_height))
37
+ image_dict[image_path] = image_features
38
+
39
+ # Loop through the image_dict and write all the image_feature associated with it in a new PNG
40
+ for image_path, features in image_dict.items():
41
+ background = None
42
+ for feature in features:
43
+ x, y, image, original_width, original_height = feature
44
+ # Create a white background
45
+ if not background:
46
+ background = Image.new('RGBA', (original_width, original_height), (255, 255, 255, 255))
47
+ # Convert the OpenCV image (numpy array) to a PIL image
48
+ image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGBA))
49
+ # Paste the image onto the background
50
+ background.paste(image, (x, y), image)
51
+ # Save the image with compression level 9
52
+ background.save(image_path, 'PNG', optimize=True, compress_level=9)
53
+
54
+
55
+ if __name__ == '__main__':
56
+ json_file = sys.argv[1]
57
+ compress_coco(json_file)
@@ -1,6 +1,7 @@
1
1
  import json
2
2
  import os
3
3
  import sys
4
+ import threading
4
5
  from typing import Dict
5
6
  from typing import List
6
7
 
@@ -21,7 +22,7 @@ class FeatureSet:
21
22
  feature_dict: Dict[str, Feature] = {}
22
23
  box_dict: Dict[str, Box] = {}
23
24
 
24
- def __init__(self, coco_json: str, default_horizontal_variance=0,
25
+ def __init__(self, debug, coco_json: str, default_horizontal_variance=0,
25
26
  default_vertical_variance=0, default_threshold=0.95) -> None:
26
27
  """
27
28
  Initialize the FeatureSet by loading images and annotations from a COCO dataset.
@@ -33,6 +34,7 @@ class FeatureSet:
33
34
  """
34
35
  self.coco_json = resource_path(coco_json)
35
36
  self.coco_folder = os.path.dirname(self.coco_json)
37
+ self.debug = debug
36
38
 
37
39
  logger.debug(f'Loading features from {self.coco_json}')
38
40
 
@@ -44,6 +46,7 @@ class FeatureSet:
44
46
  self.default_threshold = default_threshold
45
47
  self.default_horizontal_variance = default_horizontal_variance
46
48
  self.default_vertical_variance = default_vertical_variance
49
+ self.lock = threading.Lock()
47
50
 
48
51
  def check_size(self, frame):
49
52
  height, width = frame.shape[:2]
@@ -52,6 +55,8 @@ class FeatureSet:
52
55
  self.width = width
53
56
  self.height = height
54
57
  self.process_data()
58
+ elif not self.feature_dict:
59
+ self.process_data()
55
60
 
56
61
  def process_data(self) -> None:
57
62
  """
@@ -61,49 +66,60 @@ class FeatureSet:
61
66
  width (int): Target width for scaling images.
62
67
  height (int): Target height for scaling images.
63
68
  """
64
- self.feature_dict.clear()
65
- self.box_dict.clear()
66
- with open(self.coco_json, 'r') as file:
67
- data = json.load(file)
68
-
69
- # Create a map from image ID to file name
70
- image_map = {image['id']: image['file_name'] for image in data['images']}
71
-
72
- # Create a map from category ID to category name
73
- category_map = {category['id']: category['name'] for category in data['categories']}
74
-
75
- for annotation in data['annotations']:
76
- image_id = annotation['image_id']
77
- category_id = annotation['category_id']
78
- bbox = annotation['bbox']
79
-
80
- # Load and scale the image
81
- image_path = str(os.path.join(self.coco_folder, image_map[image_id]))
82
- image = cv2.imread(image_path)
83
- _, original_width = image.shape[:2]
84
- if image is None:
85
- logger.error(f'Could not read image {image_path}')
86
- continue
87
- x, y, w, h = bbox
88
- if self.width != image.shape[1] or self.height != image.shape[0]:
89
- scale_x, scale_y = self.width / image.shape[1], self.height / image.shape[0]
90
- logger.debug(f'scaling images {scale_x}, {scale_y}')
91
- image = cv2.resize(image, (self.width, self.height))
92
- # Calculate the scaled bounding box
93
- x, y, w, h = x * scale_x, y * scale_y, w * scale_x, h * scale_y
94
-
95
- # Crop the image to the bounding box
96
- image = image[int(y):int(y + h), int(x):int(x + w), :3]
97
-
98
- # Store in featureDict using the category name
99
- category_name = category_map[category_id]
100
- logger.debug(
101
- f"loaded {category_name} resized width {self.width} / original_width:{original_width},scale_x:{self.width / original_width}")
102
- if category_name in self.feature_dict:
103
- raise ValueError(f"Multiple boxes found for category {category_name}")
104
- if not category_name.startswith('box_'):
105
- self.feature_dict[category_name] = Feature(image, x, y, w, h)
106
- self.box_dict[category_name] = Box(x, y, w, h, name=category_name)
69
+ with self.lock:
70
+ if self.debug:
71
+ folder_size = sum(os.path.getsize(os.path.join(dirpath, filename))
72
+ for dirpath, dirnames, filenames in os.walk(self.coco_folder)
73
+ for filename in filenames)
74
+ # Convert size to MB
75
+ folder_size_mb = folder_size / (1024 * 1024)
76
+ if folder_size_mb > 5:
77
+ from ok.feature.CompressCoco import compress_coco
78
+ logger.info(f'template folder greater than 5MB try to compress the COCO dataset')
79
+ compress_coco(self.coco_json)
80
+ self.feature_dict.clear()
81
+ self.box_dict.clear()
82
+ with open(self.coco_json, 'r') as file:
83
+ data = json.load(file)
84
+
85
+ # Create a map from image ID to file name
86
+ image_map = {image['id']: image['file_name'] for image in data['images']}
87
+
88
+ # Create a map from category ID to category name
89
+ category_map = {category['id']: category['name'] for category in data['categories']}
90
+
91
+ for annotation in data['annotations']:
92
+ image_id = annotation['image_id']
93
+ category_id = annotation['category_id']
94
+ bbox = annotation['bbox']
95
+
96
+ # Load and scale the image
97
+ image_path = str(os.path.join(self.coco_folder, image_map[image_id]))
98
+ image = cv2.imread(image_path)
99
+ _, original_width = image.shape[:2]
100
+ if image is None:
101
+ logger.error(f'Could not read image {image_path}')
102
+ continue
103
+ x, y, w, h = bbox
104
+ if self.width != image.shape[1] or self.height != image.shape[0]:
105
+ scale_x, scale_y = self.width / image.shape[1], self.height / image.shape[0]
106
+ logger.debug(f'scaling images {scale_x}, {scale_y}')
107
+ image = cv2.resize(image, (self.width, self.height))
108
+ # Calculate the scaled bounding box
109
+ x, y, w, h = x * scale_x, y * scale_y, w * scale_x, h * scale_y
110
+
111
+ # Crop the image to the bounding box
112
+ image = image[round(y):round(y + h), round(x):round(x + w), :3]
113
+
114
+ # Store in featureDict using the category name
115
+ category_name = category_map[category_id]
116
+ logger.debug(
117
+ f"loaded {category_name} resized width {self.width} / original_width:{original_width},scale_x:{self.width / original_width}")
118
+ if category_name in self.feature_dict:
119
+ raise ValueError(f"Multiple boxes found for category {category_name}")
120
+ if not category_name.startswith('box_'):
121
+ self.feature_dict[category_name] = Feature(image, x, y, w, h)
122
+ self.box_dict[category_name] = Box(x, y, w, h, name=category_name)
107
123
 
108
124
  def get_box_by_name(self, mat, category_name: str) -> Box:
109
125
  self.check_size(mat)
@@ -130,7 +146,6 @@ class FeatureSet:
130
146
 
131
147
  # Save the image
132
148
  cv2.imwrite(file_path, image.mat)
133
- print(f"Saved {file_path}")
134
149
 
135
150
  def find_one(self, mat: np.ndarray, category_name: str, horizontal_variance: float = 0,
136
151
  vertical_variance: float = 0,
@@ -183,16 +198,16 @@ class FeatureSet:
183
198
  width = to_x - x
184
199
  if height == -1:
185
200
  height = to_y - y
186
- search_x1 = int(x * frame_width)
187
- search_y1 = int(y * frame_height)
188
- search_x2 = int((x + width) * frame_width)
189
- search_y2 = int((y + height) * frame_height)
201
+ search_x1 = round(x * frame_width)
202
+ search_y1 = round(y * frame_height)
203
+ search_x2 = round((x + width) * frame_width)
204
+ search_y2 = round((y + height) * frame_height)
190
205
  else:
191
206
  # Define search area using variance
192
- search_x1 = max(0, int(feature.x - self.width * horizontal_variance))
193
- search_y1 = max(0, int(feature.y - self.height * vertical_variance))
194
- search_x2 = min(self.width, int(feature.x + feature_width + self.width * horizontal_variance))
195
- search_y2 = min(self.height, int(feature.y + feature_height + self.height * vertical_variance))
207
+ search_x1 = max(0, round(feature.x - self.width * horizontal_variance))
208
+ search_y1 = max(0, round(feature.y - self.height * vertical_variance))
209
+ search_x2 = min(self.width, round(feature.x + feature_width + self.width * horizontal_variance))
210
+ search_y2 = min(self.height, round(feature.y + feature_height + self.height * vertical_variance))
196
211
 
197
212
  search_area = mat[search_y1:search_y2, search_x1:search_x2, :3]
198
213
  # Crop the search area from the image
@@ -44,9 +44,9 @@ class FindFeature:
44
44
  return False
45
45
 
46
46
  def find_one(self, feature_name, horizontal_variance=0, vertical_variance=0, threshold=0,
47
- use_gray_scale=False) -> Box:
47
+ use_gray_scale=False, box=None) -> Box:
48
48
  boxes = self.find_feature(feature_name, horizontal_variance, vertical_variance, threshold,
49
- use_gray_scale=use_gray_scale)
49
+ use_gray_scale=use_gray_scale, box=box)
50
50
  if len(boxes) > 0:
51
51
  if len(boxes) > 1:
52
52
  print(f"find_one:found {feature_name} too many {len(boxes)}", file=sys.stderr)
@@ -13,6 +13,7 @@ from ok.gui.Communicate import communicate
13
13
  from ok.gui.MainWindow import MainWindow
14
14
  from ok.gui.MessageWindow import MessageWindow
15
15
  from ok.gui.StartController import StartController
16
+ from ok.gui.debug.LogWindow import LogWindow
16
17
  from ok.gui.i18n.path import i18n_path
17
18
  from ok.gui.overlay.OverlayWindow import OverlayWindow
18
19
  from ok.logging.Logger import get_logger
@@ -47,6 +48,7 @@ class App:
47
48
  self.loading_window = None
48
49
  self.overlay_window = None
49
50
  self.main_window = None
51
+ self.log_window = None
50
52
  self.exit_event = exit_event
51
53
  self.icon = QIcon(self.config.get('gui_icon') or ":/icon/icon.ico")
52
54
  if self.config.get('analytics'):
@@ -109,6 +111,10 @@ class App:
109
111
  self.main_window.show()
110
112
  self.main_window.raise_()
111
113
  self.main_window.activateWindow()
114
+ if self.config.get('debug'):
115
+ self.log_window = LogWindow(self.config)
116
+ self.log_window.show()
117
+ logger.debug('showing log_window')
112
118
 
113
119
  def size_relative_to_screen(self, width, height):
114
120
  screen = self.app.primaryScreen()
@@ -43,10 +43,7 @@ class MainWindow(MSFluentWindow):
43
43
  if self.first_tab is None:
44
44
  self.first_tab = self.trigger_tab
45
45
  self.addSubInterface(self.trigger_tab, FluentIcon.ROBOT, self.tr('Triggers'))
46
- # if debug:
47
- # debug_tab = DebugTab()
48
- # self.addSubInterface(debug_tab, FluentIcon.COMMAND_PROMPT, self.tr('Debug'))
49
- # ... Add other tabs similarly
46
+
50
47
  self.addSubInterface(self.start_tab, FluentIcon.PLAY, self.tr('Capture'))
51
48
 
52
49
  if debug:
@@ -77,8 +74,8 @@ class MainWindow(MSFluentWindow):
77
74
  self.tray.setContextMenu(menu)
78
75
  self.tray.show()
79
76
 
80
- if ok.gui.device_manager.get_preferred_device() is not None and self.onetime_tab is not None:
81
- self.switchTo(self.onetime_tab)
77
+ if ok.gui.device_manager.config.get("preferred") is None or self.onetime_tab is None:
78
+ self.switchTo(self.start_tab)
82
79
 
83
80
  communicate.capture_error.connect(self.capture_error)
84
81
  communicate.notification.connect(self.show_notification)
@@ -49,9 +49,6 @@ class DebugTab(Tab):
49
49
  capture_button.clicked.connect(lambda: self.handler.post(self.capture))
50
50
  layout.addWidget(capture_button)
51
51
 
52
- # self.shortcut = QShortcut(QKeySequence("Ctrl+Alt+S"), self)
53
- # self.shortcut.activated.connect(lambda: self.handler.post(self.capture))
54
-
55
52
  ocr_button = PushButton("OCR")
56
53
  ocr_button.clicked.connect(lambda: self.handler.post(self.ocr))
57
54
  layout.addWidget(ocr_button)