11#include " HutaoNativeHotKeyAction.h"
2+ #include " HutaoNativeHotKeyActionCallback.h"
23#include " Error.h"
34#include < Windows.h>
45#include < chrono>
6+ #include < thread>
57
68const wchar_t * WINDOW_CLASS_NAME = L" HutaoNativeHotKeyActionWindowClass" ;
79const UINT WM_HOTKEY_MESSAGE = WM_APP + 2 ;
810
911UINT HutaoNativeHotKeyAction::s_nextHotKeyId = 0x4000 ; // 从0x4000开始,避免与系统热键冲突
1012
11- HutaoNativeHotKeyAction::HutaoNativeHotKeyAction (HutaoNativeHotKeyActionKind kind, HutaoNativeHotKeyActionCallback callback, GCHandle userData)
12- : m_callback(callback)
13+ HutaoNativeHotKeyAction::HutaoNativeHotKeyAction (HutaoNativeHotKeyActionKind kind, HutaoNativeHotKeyActionCallback callback, nint userData)
14+ : m_kind(kind)
15+ , m_callback(callback)
1316 , m_userData(userData)
14- , m_kind(kind)
1517 , m_modifiers(0 )
1618 , m_vk(0 )
1719 , m_enabled(false )
1820 , m_hotKeyId(0 )
1921 , m_hWnd(nullptr )
20- , m_clicking(false )
21- , m_clickIntervalMs(50 ) // default 50ms interval
22- , m_keyPressing(false )
23- , m_keyIntervalMs(100 ) // default 100ms interval for key press
24- , m_active(false )
22+ , m_isRunning(false )
2523{
2624 m_hotKeyId = static_cast <int >(++s_nextHotKeyId);
2725}
2826
2927HutaoNativeHotKeyAction::~HutaoNativeHotKeyAction ()
3028{
3129 SetIsEnabled (FALSE );
32-
33- StopAutoClick ();
34- StopAutoKeyPress ();
35-
30+ StopAction ();
31+
3632 if (m_hWnd != nullptr )
3733 {
3834 DestroyWindow (m_hWnd);
@@ -90,27 +86,24 @@ LRESULT CALLBACK HutaoNativeHotKeyAction::WndProc(HWND hWnd, UINT message, WPARA
9086 {
9187 if (message == WM_HOTKEY)
9288 {
93- // Toggle active state on hotkey press
94- bool newState = !pThis->m_active .load ();
95- pThis->m_active .store (newState);
96-
97- // Notify managed side about toggled state
98- if (pThis->m_callback .value != nullptr )
89+ // 热键被触发,切换动作状态
90+ bool wasRunning = pThis->m_isRunning .load ();
91+
92+ if (wasRunning)
9993 {
100- BOOL isOn = newState ? TRUE : FALSE ;
101- pThis->m_callback .value (isOn, pThis->m_userData );
94+ pThis->StopAction ();
10295 }
103-
104- // Start/stop auto actions based on kind
105- if (pThis->m_kind == HutaoNativeHotKeyActionKind::MouseClickRepeatForever)
96+ else
10697 {
107- if ( pThis->m_active . load ()) pThis-> StartAutoClick (); else pThis-> StopAutoClick ();
98+ pThis->ExecuteAction ();
10899 }
109- else if (pThis->m_kind == HutaoNativeHotKeyActionKind::KeyPressRepeatForever)
100+
101+ // 调用回调函数通知状态变化
102+ if (pThis->m_callback .value != nullptr )
110103 {
111- if ( pThis->m_active . load ()) pThis-> StartAutoKeyPress (); else pThis->StopAutoKeyPress ( );
104+ pThis->m_callback . value (!wasRunning ? TRUE : FALSE , pThis->m_userData );
112105 }
113-
106+
114107 return 0 ;
115108 }
116109 }
@@ -136,85 +129,76 @@ void HutaoNativeHotKeyAction::RegisterHotKey()
136129 ::RegisterHotKey (m_hWnd, m_hotKeyId, m_modifiers, m_vk);
137130}
138131
139- // Auto-click implementation
140- void HutaoNativeHotKeyAction::StartAutoClick ()
132+ void HutaoNativeHotKeyAction::ExecuteAction ()
141133{
142- bool expected = false ;
143- if (!m_clicking.compare_exchange_strong (expected, true ))
144- return ; // already clicking
145-
146- // Launch thread
147- m_clickThread = std::thread ([this ]() {
148- // Continue clicking until stopped
149- while (m_clicking.load ())
134+ if (m_isRunning.load ())
135+ {
136+ return ; // 已经在运行
137+ }
138+
139+ m_isRunning.store (true );
140+
141+ // 启动新线程执行动作
142+ m_actionThread = std::thread ([this ]() {
143+ while (m_isRunning.load ())
150144 {
151- // Simulate left mouse down and up
152- INPUT inputs[2 ];
153- ZeroMemory (inputs, sizeof (inputs));
154-
155- inputs[0 ].type = INPUT_MOUSE;
156- inputs[0 ].mi .dwFlags = MOUSEEVENTF_LEFTDOWN;
157-
158- inputs[1 ].type = INPUT_MOUSE;
159- inputs[1 ].mi .dwFlags = MOUSEEVENTF_LEFTUP;
160-
161- SendInput (2 , inputs, sizeof (INPUT));
162-
163- std::this_thread::sleep_for (std::chrono::milliseconds (m_clickIntervalMs));
145+ if (m_kind == MouseClickRepeatForever)
146+ {
147+ SimulateMouseClick ();
148+ }
149+ else if (m_kind == KeyPressRepeatForever)
150+ {
151+ SimulateKeyPress ();
152+ }
153+
154+ // 延迟一段时间(例如50ms,即每秒20次)
155+ std::this_thread::sleep_for (std::chrono::milliseconds (50 ));
164156 }
165157 });
166158}
167159
168- void HutaoNativeHotKeyAction::StopAutoClick ()
160+ void HutaoNativeHotKeyAction::StopAction ()
169161{
170- bool expected = true ;
171- if (!m_clicking.compare_exchange_strong (expected, false ))
172- return ; // not clicking
173-
174- if (m_clickThread.joinable ())
162+ m_isRunning.store (false );
163+
164+ if (m_actionThread.joinable ())
175165 {
176- m_clickThread .join ();
166+ m_actionThread .join ();
177167 }
178168}
179169
180- // Auto-keypress implementation
181- void HutaoNativeHotKeyAction::StartAutoKeyPress ()
170+ void HutaoNativeHotKeyAction::SimulateMouseClick ()
182171{
183- bool expected = false ;
184- if (!m_keyPressing.compare_exchange_strong (expected, true ))
185- return ; // already pressing
186-
187- m_keyThread = std::thread ([this ]() {
188- // Repeatedly send configured vk or 'F'
189- WORD vkToSend = (WORD)m_vk ? (WORD)m_vk : 0x46 ;
190- INPUT inputs[2 ];
191- ZeroMemory (inputs, sizeof (inputs));
192- inputs[0 ].type = INPUT_KEYBOARD;
193- inputs[0 ].ki .wVk = vkToSend;
194- inputs[0 ].ki .dwFlags = 0 ; // key down
195-
196- inputs[1 ].type = INPUT_KEYBOARD;
197- inputs[1 ].ki .wVk = vkToSend;
198- inputs[1 ].ki .dwFlags = KEYEVENTF_KEYUP; // key up
199-
200- while (m_keyPressing.load ())
201- {
202- SendInput (2 , inputs, sizeof (INPUT));
203- std::this_thread::sleep_for (std::chrono::milliseconds (m_keyIntervalMs));
204- }
205- });
172+ // 模拟鼠标左键点击
173+ INPUT inputs[2 ] = {0 };
174+
175+ // 按下左键
176+ inputs[0 ].type = INPUT_MOUSE;
177+ inputs[0 ].mi .dwFlags = MOUSEEVENTF_LEFTDOWN;
178+
179+ // 释放左键
180+ inputs[1 ].type = INPUT_MOUSE;
181+ inputs[1 ].mi .dwFlags = MOUSEEVENTF_LEFTUP;
182+
183+ SendInput (2 , inputs, sizeof (INPUT));
206184}
207185
208- void HutaoNativeHotKeyAction::StopAutoKeyPress ()
186+ void HutaoNativeHotKeyAction::SimulateKeyPress ()
209187{
210- bool expected = true ;
211- if (!m_keyPressing.compare_exchange_strong (expected, false ))
212- return ; // not pressing
213-
214- if (m_keyThread.joinable ())
215- {
216- m_keyThread.join ();
217- }
188+ // 模拟F键按下(VK_F为0x46)
189+ INPUT inputs[2 ] = {0 };
190+
191+ // 按下F键
192+ inputs[0 ].type = INPUT_KEYBOARD;
193+ inputs[0 ].ki .wVk = 0x46 ; // VK_F
194+ inputs[0 ].ki .dwFlags = 0 ;
195+
196+ // 释放F键
197+ inputs[1 ].type = INPUT_KEYBOARD;
198+ inputs[1 ].ki .wVk = 0x46 ; // VK_F
199+ inputs[1 ].ki .dwFlags = KEYEVENTF_KEYUP;
200+
201+ SendInput (2 , inputs, sizeof (INPUT));
218202}
219203
220204HRESULT STDMETHODCALLTYPE HutaoNativeHotKeyAction::Update (int modifiers, uint vk)
@@ -277,6 +261,7 @@ HRESULT STDMETHODCALLTYPE HutaoNativeHotKeyAction::SetIsEnabled(BOOL isEnabled)
277261 {
278262 // 禁用热键
279263 UnregisterHotKey ();
264+ StopAction ();
280265 }
281266
282267 m_enabled = newEnabled;
0 commit comments