99
1010#include " InputUtils.h"
1111
12+ #include < algorithm>
1213#include < mmsystem.h>
1314
1415MAA_CTRL_UNIT_NS_BEGIN
@@ -28,44 +29,31 @@ struct ShcoreDllHolder : public LibraryHolder<ShcoreDllHolder>
2829{
2930};
3031
31- template <typename Holder>
32- void ensure_library_loaded (const wchar_t * libname)
33- {
34- static std::once_flag once;
35- std::call_once (once, [libname]() { Holder::load_library (libname); });
36- }
37-
38- template <typename Holder, typename Fn>
39- boost::function<Fn> resolve_library_function (const wchar_t * libname, const std::string& name)
40- {
41- ensure_library_loaded<Holder>(libname);
42- return Holder::template get_function<Fn>(name);
43- }
44-
4532void ensure_process_dpi_awareness_once ()
4633{
47- static std::once_flag once;
48- std::call_once (once, []() {
34+ [[maybe_unused]] static const int dpi_init_once = []() {
35+ User32DllHolder::load_library (L" user32.dll" );
36+
4937 using FnCtx = BOOL WINAPI (DPI_AWARENESS_CONTEXT);
50- auto fn_ctx = resolve_library_function< User32DllHolder, FnCtx>(L" user32.dll " , " SetProcessDpiAwarenessContext" );
38+ auto fn_ctx = User32DllHolder::get_function< FnCtx>(" SetProcessDpiAwarenessContext" );
5139 if (fn_ctx && fn_ctx (DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) {
52- return ;
40+ return 0 ;
5341 }
5442 if (fn_ctx && GetLastError () == ERROR_ACCESS_DENIED) {
55- return ;
43+ return 0 ;
5644 }
5745
46+ ShcoreDllHolder::load_library (L" shcore.dll" );
47+
5848 using FnAware = HRESULT WINAPI (int );
59- auto fn_aware = resolve_library_function< ShcoreDllHolder, FnAware>(L" shcore.dll " , " SetProcessDpiAwareness" );
49+ auto fn_aware = ShcoreDllHolder::get_function< FnAware>(" SetProcessDpiAwareness" );
6050 if (!fn_aware) {
61- return ;
51+ return 0 ;
6252 }
6353
64- auto hr = fn_aware (2 /* PROCESS_PER_MONITOR_DPI_AWARE*/ );
65- if (SUCCEEDED (hr) || hr == E_ACCESSDENIED) {
66- return ;
67- }
68- });
54+ fn_aware (2 /* PROCESS_PER_MONITOR_DPI_AWARE*/ );
55+ return 0 ;
56+ }();
6957}
7058
7159}
@@ -286,7 +274,6 @@ bool MessageInput::handle_hardware_mouse_move(const MSLLHOOKSTRUCT& mouse_info)
286274 pending_mouse_y_ += dy;
287275 has_pending_mouse_ = true ;
288276
289- // mouse_lock_follow 模式始终拦截
290277 return true ;
291278}
292279
@@ -398,8 +385,6 @@ LRESULT CALLBACK MessageInput::MouseHookProc(int nCode, WPARAM wParam, LPARAM lP
398385 return 1 ;
399386}
400387
401- // ======================== 目标进程挂起/恢复 ========================
402-
403388void MessageInput::open_target_process ()
404389{
405390 if (target_process_handle_ || !hwnd_) {
@@ -416,7 +401,10 @@ void MessageInput::open_target_process()
416401 target_process_handle_ = OpenProcess (PROCESS_SUSPEND_RESUME, FALSE , pid);
417402 if (!target_process_handle_) {
418403 LogWarn << " OpenProcess failed" << VAR (pid) << VAR (GetLastError ());
404+ return ;
419405 }
406+
407+ NtDllHolder::load_library (L" ntdll.dll" );
420408}
421409
422410void MessageInput::close_target_process ()
@@ -428,20 +416,14 @@ void MessageInput::close_target_process()
428416 target_process_handle_ = nullptr ;
429417}
430418
431- template <typename Fn>
432- static boost::function<Fn> resolve_nt_function (const std::string& name)
433- {
434- return resolve_library_function<NtDllHolder, Fn>(L" ntdll.dll" , name);
435- }
436-
437419void MessageInput::suspend_target_process ()
438420{
439421 if (!target_process_handle_) {
440422 return ;
441423 }
442424
443425 using NtSuspendProcessFn = LONG NTAPI (HANDLE);
444- static auto fn = resolve_nt_function <NtSuspendProcessFn>(" NtSuspendProcess" );
426+ static auto fn = NtDllHolder::get_function <NtSuspendProcessFn>(" NtSuspendProcess" );
445427 if (fn) {
446428 fn (target_process_handle_);
447429 }
@@ -454,14 +436,12 @@ void MessageInput::resume_target_process()
454436 }
455437
456438 using NtResumeProcessFn = LONG NTAPI (HANDLE);
457- static auto fn = resolve_nt_function <NtResumeProcessFn>(" NtResumeProcess" );
439+ static auto fn = NtDllHolder::get_function <NtResumeProcessFn>(" NtResumeProcess" );
458440 if (fn) {
459441 fn (target_process_handle_);
460442 }
461443}
462444
463- // ======================== 追踪线程 ========================
464-
465445void MessageInput::process_pending_mouse_frame ()
466446{
467447 has_pending_mouse_ = false ;
@@ -930,8 +910,6 @@ bool MessageInput::scroll(int dx, int dy)
930910 return success;
931911}
932912
933- // ======================== MouseLockFollow ========================
934-
935913bool MessageInput::relative_move (int dx, int dy)
936914{
937915 if (!mouse_lock_follow_active_) {
@@ -963,17 +941,17 @@ bool MessageInput::relative_move(int dx, int dy)
963941
964942bool MessageInput::set_mouse_lock_follow (bool enabled)
965943{
966- LogInfo << VAR (enabled) << VAR (mouse_lock_follow_active_);
944+ LogInfo << VAR (enabled) << VAR (mouse_lock_follow_active_. load () );
967945
968946 if (enabled && !mouse_lock_follow_active_) {
969947 return activate_mouse_lock_follow ();
970948 }
971- else if (!enabled && mouse_lock_follow_active_) {
949+
950+ if (!enabled && mouse_lock_follow_active_) {
972951 deactivate_mouse_lock_follow ();
973- return true ;
974952 }
975953
976- return true ; // 已经是目标状态
954+ return true ;
977955}
978956
979957bool MessageInput::ensure_tracking_thread ()
@@ -1026,6 +1004,36 @@ bool MessageInput::ensure_rawinput_window()
10261004 return rawinput_ensure_done_ && rawinput_ensure_ok_;
10271005}
10281006
1007+ bool MessageInput::compute_window_center_on_cursor (const POINT& cursor, int & out_left, int & out_top)
1008+ {
1009+ RECT client_rect;
1010+ if (!GetClientRect (hwnd_, &client_rect)) {
1011+ LogError << " GetClientRect failed" << VAR (GetLastError ());
1012+ return false ;
1013+ }
1014+
1015+ int client_w = client_rect.right - client_rect.left ;
1016+ int client_h = client_rect.bottom - client_rect.top ;
1017+
1018+ POINT client_origin = { 0 , 0 };
1019+ if (!ClientToScreen (hwnd_, &client_origin)) {
1020+ LogError << " ClientToScreen failed" << VAR (hwnd_) << VAR (GetLastError ());
1021+ return false ;
1022+ }
1023+
1024+ RECT win_rect;
1025+ if (!GetWindowRect (hwnd_, &win_rect)) {
1026+ LogError << " GetWindowRect failed" << VAR (hwnd_) << VAR (GetLastError ());
1027+ return false ;
1028+ }
1029+
1030+ int border_x = client_origin.x - win_rect.left ;
1031+ int border_y = client_origin.y - win_rect.top ;
1032+ out_left = cursor.x - client_w / 2 - border_x;
1033+ out_top = cursor.y - client_h / 2 - border_y;
1034+ return true ;
1035+ }
1036+
10291037bool MessageInput::activate_mouse_lock_follow ()
10301038{
10311039 LogInfo << " Activating mouse lock follow mode" ;
@@ -1042,7 +1050,6 @@ bool MessageInput::activate_mouse_lock_follow()
10421050 if (prev_dpi_ctx) SetThreadDpiAwarenessContext (prev_dpi_ctx);
10431051 });
10441052
1045- // 确保追踪线程在运行
10461053 if (!ensure_tracking_thread ()) {
10471054 LogError << " Failed to start mouse tracking thread for mouse lock follow" ;
10481055 return false ;
@@ -1053,7 +1060,6 @@ bool MessageInput::activate_mouse_lock_follow()
10531060 return false ;
10541061 }
10551062
1056- // 保存窗口位置以便恢复
10571063 save_window_pos ();
10581064 if (!window_pos_saved_) {
10591065 LogError << " Failed to save window position before activating mouse lock follow" << VAR (hwnd_);
@@ -1066,32 +1072,11 @@ bool MessageInput::activate_mouse_lock_follow()
10661072 return false ;
10671073 }
10681074
1069- RECT client_rect;
1070- if (!GetClientRect (hwnd_, &client_rect)) {
1071- LogError << " GetClientRect failed" << VAR (GetLastError ());
1075+ int new_left = 0 , new_top = 0 ;
1076+ if (!compute_window_center_on_cursor (cursor, new_left, new_top)) {
10721077 return false ;
10731078 }
10741079
1075- int client_w = client_rect.right - client_rect.left ;
1076- int client_h = client_rect.bottom - client_rect.top ;
1077-
1078- POINT client_origin = { 0 , 0 };
1079- if (!ClientToScreen (hwnd_, &client_origin)) {
1080- LogError << " ClientToScreen failed" << VAR (hwnd_) << VAR (GetLastError ());
1081- return false ;
1082- }
1083- RECT win_rect;
1084- if (!GetWindowRect (hwnd_, &win_rect)) {
1085- LogError << " GetWindowRect failed" << VAR (hwnd_) << VAR (GetLastError ());
1086- return false ;
1087- }
1088- int border_x = client_origin.x - win_rect.left ;
1089- int border_y = client_origin.y - win_rect.top ;
1090-
1091- // 将窗口中心对齐到当前光标位置
1092- int new_left = cursor.x - client_w / 2 - border_x;
1093- int new_top = cursor.y - client_h / 2 - border_y;
1094-
10951080 bool activated = false ;
10961081 bool window_moved = false ;
10971082 tracking_stop_generation_ = 0 ;
@@ -1117,18 +1102,19 @@ bool MessageInput::activate_mouse_lock_follow()
11171102 return false ;
11181103 }
11191104 window_moved = true ;
1120- // 等待 SetWindowPos 生效(最多 100ms)
1105+ bool settled = false ;
11211106 for (int i = 0 ; i < 10 ; ++i) {
11221107 RECT cur;
1123- if (GetWindowRect (hwnd_, &cur) &&
1124- std::abs (cur.left - new_left) <= 1 &&
1125- std::abs (cur.top - new_top) <= 1 ) {
1108+ if (GetWindowRect (hwnd_, &cur) && std::abs (cur.left - new_left) <= 1 && std::abs (cur.top - new_top) <= 1 ) {
1109+ settled = true ;
11261110 break ;
11271111 }
11281112 std::this_thread::sleep_for (std::chrono::milliseconds (10 ));
11291113 }
1114+ if (!settled) {
1115+ LogWarn << " SetWindowPos did not settle within 100ms" << VAR (hwnd_) << VAR (new_left) << VAR (new_top);
1116+ }
11301117
1131- // 记录锚点
11321118 lock_anchor_cursor_ = cursor;
11331119 if (!GetWindowRect (hwnd_, &lock_anchor_window_)) {
11341120 LogError << " GetWindowRect failed after mouse lock follow activation move" << VAR (hwnd_) << VAR (GetLastError ());
@@ -1137,24 +1123,20 @@ bool MessageInput::activate_mouse_lock_follow()
11371123 lock_offset_x_ = 0 ;
11381124 lock_offset_y_ = 0 ;
11391125
1140- // 发送激活消息
11411126 send_activate ();
11421127
1143- // 清空待处理的鼠标位移
11441128 pending_mouse_x_ = 0 ;
11451129 pending_mouse_y_ = 0 ;
11461130 has_pending_mouse_ = false ;
11471131 counter_pending_ = 0 ;
11481132
11491133 mouse_lock_follow_active_ = true ;
1150-
1151- // 设置追踪活跃状态
11521134 s_active_instance_ = this ;
11531135 tracking_active_ = true ;
11541136 activated = true ;
11551137
1156- LogInfo << " Mouse lock follow activated, anchor cursor= " << lock_anchor_cursor_.x << " , " << lock_anchor_cursor_.y
1157- << " window= " << lock_anchor_window_.left << " , " << lock_anchor_window_.top ;
1138+ LogInfo << " Mouse lock follow activated" << VAR ( lock_anchor_cursor_.x ) << VAR ( lock_anchor_cursor_.y )
1139+ << VAR ( lock_anchor_window_.left ) << VAR ( lock_anchor_window_.top ) ;
11581140 return true ;
11591141}
11601142
@@ -1174,7 +1156,6 @@ void MessageInput::deactivate_mouse_lock_follow()
11741156 stop_window_tracking ();
11751157 counter_pending_ = 0 ;
11761158
1177- // 恢复窗口位置
11781159 restore_window_pos ();
11791160
11801161 // 如果追踪线程是为 lock follow 单独启动的,停止它
@@ -1197,21 +1178,18 @@ void MessageInput::process_mouse_lock_follow_frame()
11971178 lock_offset_x_ += dx;
11981179 lock_offset_y_ += dy;
11991180
1200- // 目标鼠标位置(绝对锚点策略)
12011181 int mx = lock_anchor_cursor_.x + lock_offset_x_;
12021182 int my = lock_anchor_cursor_.y + lock_offset_y_;
12031183
1204- // 屏幕边界钳制
12051184 int vsx = GetSystemMetrics (SM_XVIRTUALSCREEN);
12061185 int vsy = GetSystemMetrics (SM_YVIRTUALSCREEN);
12071186 int vsw = GetSystemMetrics (SM_CXVIRTUALSCREEN);
12081187 int vsh = GetSystemMetrics (SM_CYVIRTUALSCREEN);
1209- mx = std::max (vsx, std::min (mx , vsx + vsw - 1 ) );
1210- my = std::max (vsy, std::min (my , vsy + vsh - 1 ) );
1188+ mx = std::clamp (mx, vsx , vsx + vsw - 1 );
1189+ my = std::clamp (my, vsy , vsy + vsh - 1 );
12111190 lock_offset_x_ = mx - lock_anchor_cursor_.x ;
12121191 lock_offset_y_ = my - lock_anchor_cursor_.y ;
12131192
1214- // 窗口目标位置
12151193 int new_left = lock_anchor_window_.left + lock_offset_x_;
12161194 int new_top = lock_anchor_window_.top + lock_offset_y_;
12171195
@@ -1231,8 +1209,6 @@ void MessageInput::process_mouse_lock_follow_frame()
12311209 resume_target_process ();
12321210}
12331211
1234- // ======================== RawInput 对冲 ========================
1235-
12361212bool MessageInput::create_rawinput_window ()
12371213{
12381214 WNDCLASSEXW wc = {};
@@ -1273,7 +1249,6 @@ void MessageInput::destroy_rawinput_window()
12731249 return ;
12741250 }
12751251
1276- // 取消注册 RawInput
12771252 RAWINPUTDEVICE rid = {};
12781253 rid.usUsagePage = 0x01 ;
12791254 rid.usUsage = 0x02 ;
0 commit comments