Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
697 changes: 567 additions & 130 deletions source/MaaFramework/Controller/ControllerAgent.cpp

Large diffs are not rendered by default.

12 changes: 10 additions & 2 deletions source/MaaFramework/Controller/ControllerAgent.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,14 +271,15 @@ class ControllerAgent : public MaaController
bool handle_shell(const ShellParam& param);
bool handle_inactive();

MaaCtrlId post(Action action);
MaaCtrlId focus_id(MaaCtrlId id);
MaaCtrlId post(Action action, bool notify = false);
bool check_stop();

private:
bool run_action(typename AsyncRunner<Action>::Id id, Action action);
cv::Point preproc_touch_point(const cv::Point& p);
bool postproc_screenshot(const cv::Mat& raw);
void notify_hdr_screenshot_mode(bool hdr_capture_active, bool gpu_processed, bool hdr_display_compensated);
void save_hdr_probe_image(const cv::Mat& image, int probe_index);
bool calc_target_image_size();
void clear_target_image_size();
bool request_uuid();
Expand All @@ -293,6 +294,7 @@ class ControllerAgent : public MaaController
bool set_background_managed_keys_option(MaaOptionValue value, MaaOptionValueSize val_size);

private:
mutable std::mutex stop_mutex_;
bool need_to_stop_ = false;

private:
Expand All @@ -303,6 +305,7 @@ class ControllerAgent : public MaaController
cv::Mat image_;
mutable std::mutex shell_output_mutex_;
std::string shell_output_;
mutable std::mutex uuid_mutex_;

bool image_use_raw_size_ = false;
int image_target_long_side_ = 0;
Expand All @@ -314,6 +317,11 @@ class ControllerAgent : public MaaController
int image_resize_method_ = 3; // cv::INTER_AREA

std::string uuid_cache_;
bool hdr_screenshot_mode_notified_ = false;
bool last_hdr_capture_active_ = false;
bool last_hdr_gpu_processed_ = false;
bool last_hdr_display_compensated_ = false;
int hdr_probe_images_remaining_ = 0;

std::set<AsyncRunner<Action>::Id> focus_ids_;
std::mutex focus_ids_mutex_;
Expand Down
11 changes: 11 additions & 0 deletions source/MaaWin32ControlUnit/Base/UnitBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,31 @@

#include <optional>

#include "MaaControlUnit/ControlUnitAPI.h"
#include "MaaFramework/MaaDef.h"
#include "MaaUtils/NoWarningCVMat.hpp"

#include "Common/Conf.h"

MAA_CTRL_UNIT_NS_BEGIN

struct ScreencapInfo
{
bool hdr_capture_active = false;
bool hdr_preprocessed = false;
bool gpu_processed = false;
bool display_hdr_active = false;
bool display_hdr_compensated = false;
};

class ScreencapBase
{
public:
virtual ~ScreencapBase() = default;

public:
virtual std::optional<cv::Mat> screencap() = 0;
virtual ScreencapInfo last_screencap_info() const { return {}; }

virtual void inactive() { }

Expand Down
51 changes: 48 additions & 3 deletions source/MaaWin32ControlUnit/Manager/Win32ControlUnitMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ bool Win32ControlUnitMgr::connect()
{
connected_ = false;
screencap_.reset();
active_screencap_method_ = ScreencapMethod::UnknownYet;
last_screencap_info_ = {};

#ifndef MAA_WIN32_COMPATIBLE
// 设置 Per-Monitor DPI Aware V2,确保 GetClientRect/GetWindowRect 等 API 返回物理像素。
Expand Down Expand Up @@ -107,6 +109,27 @@ std::unordered_map<Win32ControlUnitMgr::ScreencapMethod, std::shared_ptr<Screenc
return units;
}

std::string_view Win32ControlUnitMgr::screencap_method_name(ScreencapMethod method)
{
switch (method) {
case ScreencapMethod::GDI:
return "GDI";
case ScreencapMethod::FramePool:
return "FramePool";
case ScreencapMethod::DXGI_DesktopDup:
return "DXGI_DesktopDup";
case ScreencapMethod::DXGI_DesktopDup_Window:
return "DXGI_DesktopDup_Window";
case ScreencapMethod::PrintWindow:
return "PrintWindow";
case ScreencapMethod::ScreenDC:
return "ScreenDC";
case ScreencapMethod::UnknownYet:
default:
return "UnknownYet";
}
}

bool Win32ControlUnitMgr::init_screencap()
{
if (screencap_method_ == MaaWin32ScreencapMethod_None) {
Expand Down Expand Up @@ -166,7 +189,7 @@ std::shared_ptr<InputBase> Win32ControlUnitMgr::make_input(MaaWin32InputMethod m
}

std::shared_ptr<ScreencapBase>
Win32ControlUnitMgr::speed_test(const std::unordered_map<ScreencapMethod, std::shared_ptr<ScreencapBase>>& units) const
Win32ControlUnitMgr::speed_test(const std::unordered_map<ScreencapMethod, std::shared_ptr<ScreencapBase>>& units)
{
LogFunc;

Expand Down Expand Up @@ -202,6 +225,7 @@ std::shared_ptr<ScreencapBase>
return nullptr;
}

active_screencap_method_ = fastest;
LogInfo << "The fastest method is" << fastest << VAR(cost);
return units.at(fastest);
}
Expand Down Expand Up @@ -270,11 +294,25 @@ bool Win32ControlUnitMgr::screencap(cv::Mat& image)

auto opt = screencap_->screencap();
if (!opt) {
LogError << "failed to screencap";
return false;
LogWarn << "failed to screencap, reinitializing screencap method";
if (!init_screencap()) {
LogError << "failed to reinitialize screencap method";
return false;
}
if (!screencap_) {
LogError << "screencap_ is null after reinitialization";
return false;
}

opt = screencap_->screencap();
if (!opt) {
LogError << "failed to screencap after reinitialization";
return false;
}
}

image = std::move(opt).value();
last_screencap_info_ = screencap_->last_screencap_info();

return true;
}
Expand Down Expand Up @@ -485,8 +523,15 @@ json::object Win32ControlUnitMgr::get_info() const
info["type"] = "win32";
info["hwnd"] = reinterpret_cast<uint64_t>(hwnd_);
info["screencap_method"] = static_cast<int64_t>(screencap_method_);
info["active_screencap_method"] = static_cast<int64_t>(active_screencap_method_);
info["active_screencap_method_name"] = screencap_method_name(active_screencap_method_);
info["mouse_method"] = static_cast<int64_t>(mouse_method_);
info["keyboard_method"] = static_cast<int64_t>(keyboard_method_);
info["hdr_capture_active"] = last_screencap_info_.hdr_capture_active;
info["hdr_preprocessed"] = last_screencap_info_.hdr_preprocessed;
info["hdr_gpu_processed"] = last_screencap_info_.gpu_processed;
info["display_hdr_active"] = last_screencap_info_.display_hdr_active;
info["display_hdr_compensated"] = last_screencap_info_.display_hdr_compensated;
return info;
}

Expand Down
7 changes: 5 additions & 2 deletions source/MaaWin32ControlUnit/Manager/Win32ControlUnitMgr.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <filesystem>
#include <string_view>
#include <ostream>
#include <unordered_map>
#include <unordered_set>
Expand Down Expand Up @@ -76,8 +77,8 @@ class Win32ControlUnitMgr : public Win32ControlUnitAPI
std::unordered_map<ScreencapMethod, std::shared_ptr<ScreencapBase>> build_screencap_units() const;
bool init_screencap();
std::shared_ptr<InputBase> make_input(MaaWin32InputMethod method) const;

std::shared_ptr<ScreencapBase> speed_test(const std::unordered_map<ScreencapMethod, std::shared_ptr<ScreencapBase>>& units) const;
static std::string_view screencap_method_name(ScreencapMethod method);
std::shared_ptr<ScreencapBase> speed_test(const std::unordered_map<ScreencapMethod, std::shared_ptr<ScreencapBase>>& units);

private:
HWND hwnd_ = nullptr;
Expand All @@ -89,6 +90,8 @@ class Win32ControlUnitMgr : public Win32ControlUnitAPI
std::shared_ptr<InputBase> mouse_ = nullptr;
std::shared_ptr<InputBase> keyboard_ = nullptr;
std::shared_ptr<ScreencapBase> screencap_ = nullptr;
ScreencapMethod active_screencap_method_ = ScreencapMethod::UnknownYet;
ScreencapInfo last_screencap_info_ {};

std::shared_ptr<BackgroundManagedKeyInput> background_keyboard_ = nullptr;
std::unordered_set<int> managed_keys_;
Expand Down
65 changes: 59 additions & 6 deletions source/MaaWin32ControlUnit/Screencap/DesktopDupWindowScreencap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,59 @@
#include "HwndUtils.hpp"
#include "MaaUtils/Logger.h"

namespace
{
struct MonitorCountEnumContext
{
int count = 0;
};

BOOL CALLBACK count_intersecting_monitors_proc(HMONITOR, HDC, LPRECT, LPARAM lparam)
{
auto& context = *reinterpret_cast<MonitorCountEnumContext*>(lparam);
++context.count;
return TRUE;
}

bool rect_spans_multiple_monitors(const RECT& rect)
{
if (rect.right <= rect.left || rect.bottom <= rect.top) {
return false;
}

MonitorCountEnumContext context { };
if (!EnumDisplayMonitors(nullptr, &rect, count_intersecting_monitors_proc, reinterpret_cast<LPARAM>(&context))) {
LogWarn << "EnumDisplayMonitors failed" << GetLastError();
return false;
}

return context.count > 1;
}
} // namespace

MAA_CTRL_UNIT_NS_BEGIN

std::optional<cv::Mat> DesktopDupWindowScreencap::screencap()
{
if (!hwnd_) {
LogError << "hwnd_ is nullptr";
last_screencap_info_ = {};
return std::nullopt;
}

RECT initial_client_rect_screen = get_window_client_rect_screen();
if (initial_client_rect_screen.right <= initial_client_rect_screen.left || initial_client_rect_screen.bottom <= initial_client_rect_screen.top) {
LogError << "Invalid initial client rect" << VAR(initial_client_rect_screen.left) << VAR(initial_client_rect_screen.top)
<< VAR(initial_client_rect_screen.right) << VAR(initial_client_rect_screen.bottom);
last_screencap_info_ = {};
return std::nullopt;
}

if (rect_spans_multiple_monitors(initial_client_rect_screen)) {
LogInfo << "Client rect spans multiple monitors, falling back to screen DC capture";
return screencap_from_screen_dc();
}

// Ensure the window is fully visible on the monitor before screencap
if (!ensure_window_on_screen(hwnd_)) {
LogWarn << "Failed to ensure window on screen";
Expand All @@ -22,6 +66,7 @@ std::optional<cv::Mat> DesktopDupWindowScreencap::screencap()
// 调用基类方法获取全屏截图(BGR格式)
auto opt_img = DesktopDupScreencap::screencap();
if (!opt_img) {
last_screencap_info_ = {};
return std::nullopt;
}
const cv::Mat& img = *opt_img;
Expand All @@ -31,14 +76,15 @@ std::optional<cv::Mat> DesktopDupWindowScreencap::screencap()
if (client_rect_screen.right <= client_rect_screen.left || client_rect_screen.bottom <= client_rect_screen.top) {
LogError << "Invalid client rect" << VAR(client_rect_screen.left) << VAR(client_rect_screen.top) << VAR(client_rect_screen.right)
<< VAR(client_rect_screen.bottom);
last_screencap_info_ = {};
return std::nullopt;
}

// 获取当前输出(显示器)的桌面坐标
RECT output_desktop = get_output_desktop_coordinates();
if (output_desktop.right <= output_desktop.left || output_desktop.bottom <= output_desktop.top) {
LogError << "Failed to get output desktop coordinates";
return std::nullopt;
LogWarn << "Failed to get output desktop coordinates, falling back to screen DC capture";
return screencap_from_screen_dc();
}

// 将窗口坐标转换为相对于该显示器的坐标
Expand All @@ -49,18 +95,26 @@ std::optional<cv::Mat> DesktopDupWindowScreencap::screencap()

// 检查裁剪区域是否在图像范围内
if (crop_x < 0 || crop_y < 0 || crop_x + client_width > img.cols || crop_y + client_height > img.rows) {
LogError << "Client rect out of bounds" << VAR(crop_x) << VAR(crop_y) << VAR(client_width) << VAR(client_height) << VAR(img.cols)
<< VAR(img.rows) << VAR(output_desktop.left) << VAR(output_desktop.top);
return std::nullopt;
LogWarn << "Client rect out of bounds, falling back to screen DC capture" << VAR(crop_x) << VAR(crop_y) << VAR(client_width)
<< VAR(client_height) << VAR(img.cols) << VAR(img.rows) << VAR(output_desktop.left) << VAR(output_desktop.top);
return screencap_from_screen_dc();
}

// 裁剪出窗口客户区
cv::Rect roi(crop_x, crop_y, client_width, client_height);
cv::Mat cropped = img(roi);

last_screencap_info_ = {};
return cropped;
}

std::optional<cv::Mat> DesktopDupWindowScreencap::screencap_from_screen_dc()
{
auto fallback = screen_dc_fallback_.screencap();
last_screencap_info_ = screen_dc_fallback_.last_screencap_info();
return fallback;
}

RECT DesktopDupWindowScreencap::get_window_client_rect_screen() const
{
RECT client_rect = { 0 };
Expand Down Expand Up @@ -110,4 +164,3 @@ RECT DesktopDupWindowScreencap::get_output_desktop_coordinates() const
}

MAA_CTRL_UNIT_NS_END

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "Base/UnitBase.h"
#include "DesktopDupScreencap.h"
#include "ScreenDCScreencap.h"

MAA_CTRL_UNIT_NS_BEGIN

Expand All @@ -13,18 +14,23 @@ class DesktopDupWindowScreencap : public DesktopDupScreencap
public:
explicit DesktopDupWindowScreencap(HWND hwnd)
: DesktopDupScreencap(hwnd)
, screen_dc_fallback_(hwnd)
{
}

virtual ~DesktopDupWindowScreencap() override = default;

public: // from ScreencapBase
virtual std::optional<cv::Mat> screencap() override;
virtual ScreencapInfo last_screencap_info() const override { return last_screencap_info_; }

private:
std::optional<cv::Mat> screencap_from_screen_dc();
RECT get_window_client_rect_screen() const;
RECT get_output_desktop_coordinates() const;

ScreenDCScreencap screen_dc_fallback_;
ScreencapInfo last_screencap_info_ {};
};

MAA_CTRL_UNIT_NS_END

Loading
Loading