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.
- {ok-script-0.0.81 → ok-script-0.0.83}/PKG-INFO +1 -1
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/alas/emulator_windows.py +1 -1
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/HwndWindow.py +9 -6
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/adb/DeviceManager.py +22 -10
- ok-script-0.0.83/ok/color/Color.py +148 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/feature/Box.py +8 -8
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/feature/FeatureSet.py +7 -2
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/feature/FindFeature.py +4 -5
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/StartController.py +16 -8
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/debug/DebugTab.py +4 -2
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/resources.py +605 -584
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/start/StartTab.py +1 -1
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/interaction/BaseInteraction.py +6 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/interaction/Win32Interaction.py +31 -2
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/ocr/OCR.py +3 -6
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/task/ExecutorOperation.py +28 -5
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/task/TaskExecutor.py +7 -4
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/task/TriggerTask.py +2 -1
- {ok-script-0.0.81 → ok-script-0.0.83}/ok_script.egg-info/PKG-INFO +1 -1
- {ok-script-0.0.81 → ok-script-0.0.83}/setup.py +1 -1
- ok-script-0.0.81/ok/color/Color.py +0 -42
- {ok-script-0.0.81 → ok-script-0.0.83}/README.md +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/OK.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/alas/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/alas/emulator_base.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/alas/platform_base.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/alas/platform_windows.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/alas/utils.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/BaseCaptureMethod.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/adb/ADBCaptureMethod.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/adb/WindowsCaptureFactory.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/adb/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/adb/bin/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/image/ImageCaptureMethod.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/image/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/BaseWindowsCaptureMethod.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/BitBltCaptureMethod.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/DesktopDuplicationCaptureMethod.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/WindowsGraphicsCaptureMethod.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/d3d11.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/dump.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/utils.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/capture/windows/window.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/color/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/config/Config.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/config/InfoDict.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/config/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/feature/Feature.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/feature/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/firebase/Analytics.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/firebase/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/App.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/Communicate.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/MainWindow.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/MessageWindow.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/TabTitles.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/about/AboutTab.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/about/HttpTextEdit.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/about/VersionCard.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/about/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/common/OKIcon.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/common/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/common/config.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/common/style_sheet.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/debug/AspectRatioWidget.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/debug/FrameWidget.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/debug/InfoWidget.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/debug/LoggerWidget.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/debug/Screenshot.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/debug/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/i18n/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/i18n/path.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/i18n/update.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/icon/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/icon/icon.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/overlay/OverlayWindow.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/overlay/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/qss/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/settings/SettingTab.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/settings/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/start/SelectCaptureListView.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/start/StartCard.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/start/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/ConfigItemFactory.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/ConfigLabelAndWidget.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/LabelAndDoubleSpinBox.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/LabelAndDropDown.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/LabelAndLineEdit.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/LabelAndList.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/LabelAndSpinBox.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/LabelAndSwitchButton.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/LabelAndWidget.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/ModifyListDialog.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/ModifyListItem.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/OneTimeTaskTab.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/StartButton.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/TaskCard.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/TaskOpButton.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/TooltipTableWidget.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/TriggerTaskTab.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/tasks/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/util/Alert.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/util/InitWorker.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/util/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/Card.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/EmptyCard.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/FramelessDialog.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/ListTableWidgetItem.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/NumericTableWidgetItem.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/StartLoadingDialog.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/StatusBar.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/Tab.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/TabWidget.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/UpdateConfigWidgetItem.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/YesNonWidgetItem.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/gui/widget/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/interaction/ADBInteraction.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/interaction/DoNothingInteraction.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/interaction/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/logging/Logger.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/logging/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/ocr/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Foundation/Collections.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Foundation/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Globalization/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Graphics/Capture/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Graphics/DirectX/Direct3D11/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Graphics/DirectX/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Graphics/Imaging/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Graphics/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Media/Ocr/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Media/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Security/Cryptography/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Security/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Storage/Streams/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/Storage/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/Windows/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/delegate.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/export.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/idldsl.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/inspectable.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/roapi.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/types.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/rotypes/winstring.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/save/BlackBarProcessor.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/save/PostProcessor.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/save/SaveByInterval.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/save/SaveByKeyPress.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/save/SaveMethodBase.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/save/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/scene/FeatureScene.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/scene/Scene.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/scene/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/stats/StreamStats.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/stats/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/task/BaseTask.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/task/OneTimeTask.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/task/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/update/GithubMultiDownloader.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/update/Updater.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/update/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/update/gen_md5.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/Handler.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/exit_event.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/json.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/list.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/path.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/thread.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/win32_process.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok/util/yaml.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok_script.egg-info/SOURCES.txt +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok_script.egg-info/dependency_links.txt +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok_script.egg-info/requires.txt +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/ok_script.egg-info/top_level.txt +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/setup.cfg +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/tests/__init__.py +0 -0
- {ok-script-0.0.81 → ok-script-0.0.83}/tests/test_updater.py +0 -0
|
@@ -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
|
|
190
|
-
|
|
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
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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
|
-
|
|
23
|
-
'
|
|
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,
|
|
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
|
-
|
|
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}"
|
|
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 =
|
|
14
|
-
self.y =
|
|
13
|
+
self.x = round(x)
|
|
14
|
+
self.y = round(y)
|
|
15
15
|
if to_x != -1 and to_y != -1:
|
|
16
|
-
self.width =
|
|
17
|
-
self.height =
|
|
16
|
+
self.width = round(to_x - x)
|
|
17
|
+
self.height = round(to_y - y)
|
|
18
18
|
else:
|
|
19
|
-
self.width =
|
|
20
|
-
self.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(
|
|
269
|
-
|
|
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
|
|
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,
|
|
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
|
-
|
|
77
|
-
'
|
|
78
|
-
|
|
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
|
-
|
|
81
|
-
"
|
|
82
|
-
|
|
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
|
-
|
|
150
|
-
|
|
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):
|