11#include " Win32ControlUnitMgr.h"
22
3+ #include < chrono>
4+
35#include " MaaFramework/MaaMsg.h"
46#include " MaaUtils/Logger.h"
7+ #include " MaaUtils/Time.hpp"
58
69#include " Input/LegacyEventInput.h"
710#include " Input/MessageInput.h"
@@ -34,6 +37,7 @@ Win32ControlUnitMgr::Win32ControlUnitMgr(
3437bool Win32ControlUnitMgr::connect ()
3538{
3639 connected_ = false ;
40+ screencap_.reset ();
3741
3842#ifndef MAA_WIN32_COMPATIBLE
3943 // 设置 Per-Monitor DPI Aware V2,确保 GetClientRect/GetWindowRect 等 API 返回物理像素。
@@ -52,77 +56,14 @@ bool Win32ControlUnitMgr::connect()
5256 LogError << " hwnd_ is invalid" ;
5357 return false ;
5458 }
55-
56- // FramePool 和 PrintWindow 内置伪最小化支持,允许最小化窗口
57- bool supports_minimized =
58- screencap_method_ == MaaWin32ScreencapMethod_FramePool || screencap_method_ == MaaWin32ScreencapMethod_PrintWindow;
59- if (!supports_minimized && IsIconic (hwnd_)) {
60- LogError << " hwnd_ is minimized" ;
61- return false ;
62- }
6359 }
6460 else {
6561 LogWarn << " hwnd_ is nullptr" ;
6662 }
6763
68- switch (screencap_method_) {
69- case MaaWin32ScreencapMethod_GDI:
70- screencap_ = std::make_shared<GdiScreencap>(hwnd_);
71- break ;
72- case MaaWin32ScreencapMethod_FramePool:
73- screencap_ = std::make_shared<FramePoolWithPseudoMinimizeScreencap>(hwnd_);
74- break ;
75- case MaaWin32ScreencapMethod_DXGI_DesktopDup:
76- screencap_ = std::make_shared<DesktopDupScreencap>(hwnd_);
77- break ;
78- case MaaWin32ScreencapMethod_DXGI_DesktopDup_Window:
79- screencap_ = std::make_shared<DesktopDupWindowScreencap>(hwnd_);
80- break ;
81- case MaaWin32ScreencapMethod_PrintWindow:
82- screencap_ = std::make_shared<PrintWindowWithPseudoMinimizeScreencap>(hwnd_);
83- break ;
84- case MaaWin32ScreencapMethod_ScreenDC:
85- screencap_ = std::make_shared<ScreenDCScreencap>(hwnd_);
86- break ;
87-
88- default :
89- LogError << " Unknown screencap method: " << static_cast <int >(screencap_method_);
90- break ;
91- }
92-
93- auto make_input = [&](MaaWin32InputMethod method) -> std::shared_ptr<InputBase> {
94- switch (method) {
95- case MaaWin32InputMethod_Seize:
96- return std::make_shared<SeizeInput>(hwnd_, false );
97- case MaaWin32InputMethod_SendMessage:
98- return std::make_shared<MessageInput>(hwnd_, MessageInput::Config { .mode = MessageInput::Mode::SendMessage });
99- case MaaWin32InputMethod_PostMessage:
100- return std::make_shared<MessageInput>(hwnd_, MessageInput::Config { .mode = MessageInput::Mode::PostMessage });
101- case MaaWin32InputMethod_LegacyEvent:
102- return std::make_shared<LegacyEventInput>(hwnd_, true );
103- case MaaWin32InputMethod_PostThreadMessage:
104- return std::make_shared<PostThreadMessageInput>(hwnd_);
105- case MaaWin32InputMethod_SendMessageWithCursorPos:
106- return std::make_shared<MessageInput>(
107- hwnd_,
108- MessageInput::Config { .mode = MessageInput::Mode::SendMessage, .with_cursor_pos = true , .block_input = false });
109- case MaaWin32InputMethod_PostMessageWithCursorPos:
110- return std::make_shared<MessageInput>(
111- hwnd_,
112- MessageInput::Config { .mode = MessageInput::Mode::PostMessage, .with_cursor_pos = true , .block_input = false });
113- case MaaWin32InputMethod_SendMessageWithWindowPos:
114- return std::make_shared<MessageInput>(
115- hwnd_,
116- MessageInput::Config { .mode = MessageInput::Mode::SendMessage, .with_window_pos = true , .block_input = false });
117- case MaaWin32InputMethod_PostMessageWithWindowPos:
118- return std::make_shared<MessageInput>(
119- hwnd_,
120- MessageInput::Config { .mode = MessageInput::Mode::PostMessage, .with_window_pos = true , .block_input = false });
121- default :
122- LogError << " Unknown input method: " << static_cast <int >(method);
123- return nullptr ;
124- }
125- };
64+ if (!init_screencap ()) {
65+ return false ;
66+ }
12667
12768 if (mouse_method_ == keyboard_method_) {
12869 mouse_ = make_input (mouse_method_);
@@ -137,6 +78,132 @@ bool Win32ControlUnitMgr::connect()
13778 return true ;
13879}
13980
81+ std::unordered_map<Win32ControlUnitMgr::ScreencapMethod, std::shared_ptr<ScreencapBase>> Win32ControlUnitMgr::build_screencap_units () const
82+ {
83+ std::unordered_map<ScreencapMethod, std::shared_ptr<ScreencapBase>> units;
84+
85+ const auto add = [&](MaaWin32ScreencapMethod flag, ScreencapMethod method, auto factory) {
86+ if (screencap_method_ & flag) {
87+ units.emplace (method, factory ());
88+ }
89+ };
90+
91+ add (MaaWin32ScreencapMethod_GDI, ScreencapMethod::GDI, [this ] { return std::make_shared<GdiScreencap>(hwnd_); });
92+ add (MaaWin32ScreencapMethod_FramePool, ScreencapMethod::FramePool, [this ] {
93+ return std::make_shared<FramePoolWithPseudoMinimizeScreencap>(hwnd_);
94+ });
95+ add (MaaWin32ScreencapMethod_DXGI_DesktopDup, ScreencapMethod::DXGI_DesktopDup, [this ] {
96+ return std::make_shared<DesktopDupScreencap>(hwnd_);
97+ });
98+ add (MaaWin32ScreencapMethod_DXGI_DesktopDup_Window, ScreencapMethod::DXGI_DesktopDup_Window, [this ] {
99+ return std::make_shared<DesktopDupWindowScreencap>(hwnd_);
100+ });
101+ add (MaaWin32ScreencapMethod_PrintWindow, ScreencapMethod::PrintWindow, [this ] {
102+ return std::make_shared<PrintWindowWithPseudoMinimizeScreencap>(hwnd_);
103+ });
104+ add (MaaWin32ScreencapMethod_ScreenDC, ScreencapMethod::ScreenDC, [this ] { return std::make_shared<ScreenDCScreencap>(hwnd_); });
105+
106+ return units;
107+ }
108+
109+ bool Win32ControlUnitMgr::init_screencap ()
110+ {
111+ if (screencap_method_ == MaaWin32ScreencapMethod_None) {
112+ LogWarn << " No screencap method selected" ;
113+ return true ;
114+ }
115+
116+ auto units = build_screencap_units ();
117+ if (units.empty ()) {
118+ LogError << " No available screencap method to test" ;
119+ return false ;
120+ }
121+
122+ screencap_ = speed_test (units);
123+ if (!screencap_) {
124+ LogError << " failed to select screencap method" ;
125+ return false ;
126+ }
127+
128+ return true ;
129+ }
130+
131+ std::shared_ptr<InputBase> Win32ControlUnitMgr::make_input (MaaWin32InputMethod method) const
132+ {
133+ switch (method) {
134+ case MaaWin32InputMethod_Seize:
135+ return std::make_shared<SeizeInput>(hwnd_, false );
136+ case MaaWin32InputMethod_SendMessage:
137+ return std::make_shared<MessageInput>(hwnd_, MessageInput::Config { .mode = MessageInput::Mode::SendMessage });
138+ case MaaWin32InputMethod_PostMessage:
139+ return std::make_shared<MessageInput>(hwnd_, MessageInput::Config { .mode = MessageInput::Mode::PostMessage });
140+ case MaaWin32InputMethod_LegacyEvent:
141+ return std::make_shared<LegacyEventInput>(hwnd_, true );
142+ case MaaWin32InputMethod_PostThreadMessage:
143+ return std::make_shared<PostThreadMessageInput>(hwnd_);
144+ case MaaWin32InputMethod_SendMessageWithCursorPos:
145+ return std::make_shared<MessageInput>(
146+ hwnd_,
147+ MessageInput::Config { .mode = MessageInput::Mode::SendMessage, .with_cursor_pos = true , .block_input = false });
148+ case MaaWin32InputMethod_PostMessageWithCursorPos:
149+ return std::make_shared<MessageInput>(
150+ hwnd_,
151+ MessageInput::Config { .mode = MessageInput::Mode::PostMessage, .with_cursor_pos = true , .block_input = false });
152+ case MaaWin32InputMethod_SendMessageWithWindowPos:
153+ return std::make_shared<MessageInput>(
154+ hwnd_,
155+ MessageInput::Config { .mode = MessageInput::Mode::SendMessage, .with_window_pos = true , .block_input = false });
156+ case MaaWin32InputMethod_PostMessageWithWindowPos:
157+ return std::make_shared<MessageInput>(
158+ hwnd_,
159+ MessageInput::Config { .mode = MessageInput::Mode::PostMessage, .with_window_pos = true , .block_input = false });
160+ default :
161+ LogError << " Unknown input method: " << static_cast <int >(method);
162+ return nullptr ;
163+ }
164+ }
165+
166+ std::shared_ptr<ScreencapBase>
167+ Win32ControlUnitMgr::speed_test (const std::unordered_map<ScreencapMethod, std::shared_ptr<ScreencapBase>>& units) const
168+ {
169+ LogFunc;
170+
171+ ScreencapMethod fastest = ScreencapMethod::UnknownYet;
172+ auto cost = std::chrono::milliseconds::max ();
173+
174+ auto check = [&fastest, &cost](ScreencapMethod method, std::chrono::steady_clock::time_point start) {
175+ auto duration = duration_since (start);
176+ if (duration < cost) {
177+ fastest = method;
178+ cost = duration;
179+ }
180+ LogInfo << VAR (method) << VAR (duration);
181+ };
182+
183+ for (auto & [method, unit] : units) {
184+ LogInfo << " Warming up" << method;
185+ if (!unit->screencap ()) {
186+ LogWarn << " failed to warm up" << method;
187+ }
188+
189+ LogInfo << " Testing" << method;
190+ auto now = std::chrono::steady_clock::now ();
191+ if (!unit->screencap ()) {
192+ LogWarn << " failed to test" << method;
193+ continue ;
194+ }
195+ check (method, now);
196+ }
197+
198+ if (fastest == ScreencapMethod::UnknownYet) {
199+ LogError << " cannot find any method to screencap!" ;
200+ return nullptr ;
201+ }
202+
203+ LogInfo << " The fastest method is" << fastest << VAR (cost);
204+ return units.at (fastest);
205+ }
206+
140207bool Win32ControlUnitMgr::connected () const
141208{
142209 // 除了检查连接标志,还需要检查窗口是否仍然有效
0 commit comments