Skip to content

Commit c46967d

Browse files
authored
feat: win32 click popup for MessageInput (#1230)
1 parent 8520de9 commit c46967d

2 files changed

Lines changed: 85 additions & 32 deletions

File tree

source/MaaWin32ControlUnit/Input/MessageInput.cpp

Lines changed: 79 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -82,22 +82,29 @@ MessageInput::~MessageInput()
8282
}
8383
}
8484

85-
void MessageInput::send_activate()
85+
HWND MessageInput::send_activate()
8686
{
87+
HWND target = get_active_hwnd();
8788
bool use_post = (config_.mode == Mode::PostMessage);
88-
::MaaNS::CtrlUnitNs::send_activate_message(hwnd_, use_post);
89+
::MaaNS::CtrlUnitNs::send_activate_message(target, use_post);
90+
return target;
8991
}
9092

91-
bool MessageInput::send_or_post_w(UINT message, WPARAM wParam, LPARAM lParam)
93+
bool MessageInput::send_or_post_w(HWND target, UINT message, WPARAM wParam, LPARAM lParam)
9294
{
95+
if (!target || !IsWindow(target)) {
96+
LogError << "Invalid target window" << VAR(target) << VAR(message);
97+
return false;
98+
}
99+
93100
bool success = false;
94101

95102
if (config_.mode == Mode::PostMessage) {
96-
success = PostMessageW(hwnd_, message, wParam, lParam) != 0;
103+
success = PostMessageW(target, message, wParam, lParam) != 0;
97104
}
98105
else {
99-
SendMessageW(hwnd_, message, wParam, lParam);
100-
success = true; // SendMessage 总是返回,除非窗口句柄无效
106+
SendMessageW(target, message, wParam, lParam);
107+
success = true;
101108
}
102109

103110
if (!success) {
@@ -108,6 +115,37 @@ bool MessageInput::send_or_post_w(UINT message, WPARAM wParam, LPARAM lParam)
108115
return success;
109116
}
110117

118+
HWND MessageInput::get_active_hwnd()
119+
{
120+
HWND root = GetAncestor(hwnd_, GA_ROOTOWNER);
121+
if (!root) {
122+
LogWarn << "GetAncestor returned nullptr, hwnd_ may be invalid" << VAR(hwnd_);
123+
return hwnd_;
124+
}
125+
HWND popup = GetLastActivePopup(root);
126+
if (popup && popup != hwnd_ && IsWindowVisible(popup)) {
127+
return popup;
128+
}
129+
return hwnd_;
130+
}
131+
132+
LPARAM MessageInput::make_mouse_lparam(HWND target, int x, int y)
133+
{
134+
if (target == hwnd_) {
135+
return MAKELPARAM(x, y);
136+
}
137+
POINT pt = { x, y };
138+
if (!ClientToScreen(hwnd_, &pt)) {
139+
LogError << "ClientToScreen failed in make_mouse_lparam" << VAR(hwnd_) << VAR(GetLastError());
140+
return MAKELPARAM(x, y);
141+
}
142+
if (!ScreenToClient(target, &pt)) {
143+
LogError << "ScreenToClient failed in make_mouse_lparam" << VAR(target) << VAR(GetLastError());
144+
return MAKELPARAM(x, y);
145+
}
146+
return MAKELPARAM(pt.x, pt.y);
147+
}
148+
111149
POINT MessageInput::client_to_screen(int x, int y)
112150
{
113151
POINT point = { x, y };
@@ -708,24 +746,27 @@ bool MessageInput::touch_down(int contact, int x, int y, int pressure)
708746
return false;
709747
}
710748

711-
send_activate();
749+
HWND target = send_activate();
750+
gesture_target_ = target;
712751

713752
check_and_block_input();
714753

715754
save_pos();
716755

717-
// 准备位置并发送 MOVE 消息
718-
LPARAM lParam = prepare_mouse_position(x, y);
756+
prepare_mouse_position(x, y);
719757

720-
if (!send_or_post_w(move_info.message, move_info.w_param, lParam)) {
758+
LPARAM lParam = make_mouse_lparam(target, x, y);
759+
760+
if (!send_or_post_w(target, move_info.message, move_info.w_param, lParam)) {
761+
gesture_target_ = nullptr;
721762
finish_pos();
722763
return false;
723764
}
724765

725766
std::this_thread::sleep_for(std::chrono::milliseconds(10));
726767

727-
// 发送 DOWN 消息
728-
if (!send_or_post_w(down_info.message, down_info.w_param, lParam)) {
768+
if (!send_or_post_w(target, down_info.message, down_info.w_param, lParam)) {
769+
gesture_target_ = nullptr;
729770
finish_pos();
730771
return false;
731772
}
@@ -754,10 +795,13 @@ bool MessageInput::touch_move(int contact, int x, int y, int pressure)
754795
return false;
755796
}
756797

757-
// 准备位置并发送 MOVE 消息
758-
LPARAM lParam = prepare_mouse_position(x, y);
798+
prepare_mouse_position(x, y);
799+
800+
HWND target = (gesture_target_ && IsWindow(gesture_target_)) ? gesture_target_ : get_active_hwnd();
801+
LPARAM lParam = make_mouse_lparam(target, x, y);
759802

760-
if (!send_or_post_w(msg_info.message, msg_info.w_param, lParam)) {
803+
if (!send_or_post_w(target, msg_info.message, msg_info.w_param, lParam)) {
804+
gesture_target_ = nullptr;
761805
return false;
762806
}
763807

@@ -776,19 +820,27 @@ bool MessageInput::touch_up(int contact)
776820
return false;
777821
}
778822

779-
send_activate();
823+
bool reuse_gesture = gesture_target_ && IsWindow(gesture_target_);
824+
HWND target = reuse_gesture ? gesture_target_ : send_activate();
825+
gesture_target_ = nullptr;
780826

781827
OnScopeLeave([this]() { unblock_input(); });
782828

829+
if (reuse_gesture) {
830+
bool use_post = (config_.mode == Mode::PostMessage);
831+
::MaaNS::CtrlUnitNs::send_activate_message(target, use_post);
832+
}
833+
783834
MouseMessageInfo msg_info;
784835
if (!contact_to_mouse_up_message(contact, msg_info)) {
785836
LogError << VAR(config_.mode) << VAR(config_.with_cursor_pos) << VAR(config_.with_window_pos) << "contact out of range"
786837
<< VAR(contact);
787838
return false;
788839
}
789-
790840
auto target_pos = get_target_pos();
791-
if (!send_or_post_w(msg_info.message, msg_info.w_param, MAKELPARAM(target_pos.first, target_pos.second))) {
841+
LPARAM lParam = make_mouse_lparam(target, target_pos.first, target_pos.second);
842+
843+
if (!send_or_post_w(target, msg_info.message, msg_info.w_param, lParam)) {
792844
finish_pos();
793845
return false;
794846
}
@@ -823,13 +875,12 @@ bool MessageInput::input_text(const std::string& text)
823875
return false;
824876
}
825877

826-
send_activate();
878+
HWND target = send_activate();
827879

828880
bool success = true;
829881

830-
// 文本输入仅发送 WM_CHAR
831882
for (const auto ch : to_u16(text)) {
832-
success &= send_or_post_w(WM_CHAR, static_cast<WPARAM>(ch), 0);
883+
success &= send_or_post_w(target, WM_CHAR, static_cast<WPARAM>(ch), 0);
833884
std::this_thread::sleep_for(std::chrono::milliseconds(50));
834885
}
835886
return success;
@@ -844,10 +895,10 @@ bool MessageInput::key_down(int key)
844895
return false;
845896
}
846897

847-
send_activate();
898+
HWND target = send_activate();
848899

849900
LPARAM lParam = make_keydown_lparam(key);
850-
return send_or_post_w(WM_KEYDOWN, static_cast<WPARAM>(key), lParam);
901+
return send_or_post_w(target, WM_KEYDOWN, static_cast<WPARAM>(key), lParam);
851902
}
852903

853904
bool MessageInput::key_up(int key)
@@ -859,10 +910,10 @@ bool MessageInput::key_up(int key)
859910
return false;
860911
}
861912

862-
send_activate();
913+
HWND target = send_activate();
863914

864915
LPARAM lParam = make_keyup_lparam(key);
865-
return send_or_post_w(WM_KEYUP, static_cast<WPARAM>(key), lParam);
916+
return send_or_post_w(target, WM_KEYUP, static_cast<WPARAM>(key), lParam);
866917
}
867918

868919
bool MessageInput::scroll(int dx, int dy)
@@ -874,7 +925,7 @@ bool MessageInput::scroll(int dx, int dy)
874925
return false;
875926
}
876927

877-
send_activate();
928+
HWND target = send_activate();
878929

879930
check_and_block_input();
880931
OnScopeLeave([this]() { unblock_input(); });
@@ -883,21 +934,19 @@ bool MessageInput::scroll(int dx, int dy)
883934

884935
save_pos();
885936

886-
// prepare_mouse_position 用于移动光标/窗口(副作用),但 WM_MOUSEWHEEL 的 lParam 需要屏幕坐标
887937
prepare_mouse_position(target_pos.first, target_pos.second);
888938
POINT screen_pos = client_to_screen(target_pos.first, target_pos.second);
889939
LPARAM lParam = MAKELPARAM(screen_pos.x, screen_pos.y);
890-
891940
bool success = true;
892941

893942
if (dy != 0) {
894943
WPARAM wParam = MAKEWPARAM(0, static_cast<short>(dy));
895-
success &= send_or_post_w(WM_MOUSEWHEEL, wParam, lParam);
944+
success &= send_or_post_w(target, WM_MOUSEWHEEL, wParam, lParam);
896945
}
897946

898947
if (dx != 0) {
899948
WPARAM wParam = MAKEWPARAM(0, static_cast<short>(dx));
900-
success &= send_or_post_w(WM_MOUSEHWHEEL, wParam, lParam);
949+
success &= send_or_post_w(target, WM_MOUSEHWHEEL, wParam, lParam);
901950
}
902951

903952
if (config_.with_window_pos) {

source/MaaWin32ControlUnit/Input/MessageInput.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,11 @@ class MessageInput : public RelativeMoveInput
6464
using TrackingClock = std::chrono::steady_clock;
6565
using TrackingDeadlineTicks = TrackingClock::duration::rep;
6666

67-
void send_activate();
68-
bool send_or_post_w(UINT message, WPARAM wParam, LPARAM lParam);
67+
HWND send_activate();
68+
bool send_or_post_w(HWND target, UINT message, WPARAM wParam, LPARAM lParam);
69+
70+
HWND get_active_hwnd();
71+
LPARAM make_mouse_lparam(HWND target, int x, int y);
6972

7073
// 在发鼠标消息前把系统状态调整到目标窗口愿意接受的位置。
7174
LPARAM prepare_mouse_position(int x, int y);
@@ -130,6 +133,7 @@ class MessageInput : public RelativeMoveInput
130133

131134
std::pair<int, int> last_pos_;
132135
bool last_pos_set_ = false;
136+
HWND gesture_target_ = nullptr;
133137

134138
POINT saved_cursor_pos_ = { 0, 0 };
135139
bool cursor_pos_saved_ = false;

0 commit comments

Comments
 (0)