Skip to content

Commit 464c454

Browse files
committed
修正HotKeyAction
1 parent ad29e54 commit 464c454

8 files changed

+180
-35
lines changed

src/Snap.Hutao.Remastered.Native/CustomImplements.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ template<typename T>
3030
struct IsIUnknown : std::false_type {};
3131

3232
template<>
33-
struct IsIUnknown<IUnknown> : std::true_type {};
33+
struct IsIUnknown<::IUnknown> : std::true_type {};
3434

3535
// Helper to get IUnknown pointer from interface
3636
template<typename Interface>
37-
inline IUnknown* GetIUnknownFromInterface(Interface* pInterface) {
38-
return static_cast<IUnknown*>(static_cast<void*>(pInterface));
37+
inline ::IUnknown* GetIUnknownFromInterface(Interface* pInterface) {
38+
return static_cast<::IUnknown*>(static_cast<void*>(pInterface));
3939
}
4040

4141
// CustomImplements class template
@@ -55,9 +55,9 @@ class CustomImplements : public Interfaces... {
5555
*ppvObject = nullptr;
5656

5757
// Check for IUnknown
58-
if (IsEqualIID(riid, __uuidof(IUnknown))) {
58+
if (IsEqualIID(riid, __uuidof(::IUnknown))) {
5959
// 使用reinterpret_cast避免多重继承导致的转换不明确
60-
*ppvObject = reinterpret_cast<IUnknown*>(this);
60+
*ppvObject = reinterpret_cast<::IUnknown*>(this);
6161
AddRef();
6262
return S_OK;
6363
}

src/Snap.Hutao.Remastered.Native/HutaoNative.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "types.h"
2020
#include "CustomImplements.h"
2121
#include "Error.h"
22+
#include "HutaoNativeHotKeyActionCallback.h"
2223
#include <Windows.h>
2324
#include <hstring.h>
2425
#include <winternl.h>
@@ -151,11 +152,11 @@ HRESULT STDMETHODCALLTYPE HutaoNative::MakeHotKeyAction(HutaoNativeHotKeyActionK
151152
{
152153
AssertNonNullAndReturn(ppv);
153154

154-
// Convert nint to appropriate types
155-
WNDPROC wndProc = reinterpret_cast<WNDPROC>(callback);
156-
LONG_PTR userDataPtr = static_cast<LONG_PTR>(userData);
155+
HutaoNativeHotKeyActionCallback cb = {};
156+
cb.value = reinterpret_cast<HutaoNativeHotKeyActionCallbackFunc>(callback);
157+
GCHandle userDataHandle = static_cast<GCHandle>(userData);
157158

158-
hutao::com_ptr<IHutaoNativeHotKeyAction> hotKeyAction = hutao::make_com_ptr<HutaoNativeHotKeyAction>(kind, wndProc, userDataPtr);
159+
hutao::com_ptr<IHutaoNativeHotKeyAction> hotKeyAction = hutao::make_com_ptr<HutaoNativeHotKeyAction>(kind, cb, userDataHandle);
159160
*ppv = hotKeyAction.detach();
160161

161162
return S_OK;

src/Snap.Hutao.Remastered.Native/HutaoNativeHotKeyAction.cpp

Lines changed: 118 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,38 @@
11
#include "HutaoNativeHotKeyAction.h"
22
#include "Error.h"
33
#include <Windows.h>
4+
#include <chrono>
45

56
const wchar_t* WINDOW_CLASS_NAME = L"HutaoNativeHotKeyActionWindowClass";
67
const UINT WM_HOTKEY_MESSAGE = WM_APP + 2;
78

89
UINT HutaoNativeHotKeyAction::s_nextHotKeyId = 0x4000; // 从0x4000开始,避免与系统热键冲突
910

10-
HutaoNativeHotKeyAction::HutaoNativeHotKeyAction()
11-
: m_callback(nullptr)
12-
, m_modifiers(0)
13-
, m_vk(0)
14-
, m_enabled(false)
15-
, m_hotKeyId(0)
16-
, m_hWnd(nullptr)
17-
{
18-
m_hotKeyId = static_cast<int>(++s_nextHotKeyId);
19-
}
20-
21-
HutaoNativeHotKeyAction::HutaoNativeHotKeyAction(HutaoNativeHotKeyActionKind kind, WNDPROC callback, LONG_PTR userData)
11+
HutaoNativeHotKeyAction::HutaoNativeHotKeyAction(HutaoNativeHotKeyActionKind kind, HutaoNativeHotKeyActionCallback callback, GCHandle userData)
2212
: m_callback(callback)
13+
, m_userData(userData)
14+
, m_kind(kind)
2315
, m_modifiers(0)
2416
, m_vk(0)
2517
, m_enabled(false)
2618
, m_hotKeyId(0)
2719
, 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)
2825
{
2926
m_hotKeyId = static_cast<int>(++s_nextHotKeyId);
30-
(void)kind;
31-
(void)userData;
3227
}
3328

3429
HutaoNativeHotKeyAction::~HutaoNativeHotKeyAction()
3530
{
3631
SetIsEnabled(FALSE);
32+
33+
StopAutoClick();
34+
StopAutoKeyPress();
35+
3736
if (m_hWnd != nullptr)
3837
{
3938
DestroyWindow(m_hWnd);
@@ -71,7 +70,7 @@ HWND HutaoNativeHotKeyAction::CreateMessageWindow()
7170
nullptr,
7271
nullptr,
7372
GetModuleHandle(nullptr),
74-
this // 将this指针传递给窗口
73+
reinterpret_cast<LPVOID>(this)
7574
);
7675

7776
return hWnd;
@@ -89,9 +88,29 @@ LRESULT CALLBACK HutaoNativeHotKeyAction::WndProc(HWND hWnd, UINT message, WPARA
8988
HutaoNativeHotKeyAction* pThis = reinterpret_cast<HutaoNativeHotKeyAction*>(GetWindowLongPtrW(hWnd, GWLP_USERDATA));
9089
if (pThis != nullptr)
9190
{
92-
if (message == WM_HOTKEY && pThis->m_callback != nullptr)
91+
if (message == WM_HOTKEY)
9392
{
94-
pThis->m_callback(hWnd, message, wParam, lParam);
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)
99+
{
100+
BOOL isOn = newState ? TRUE : FALSE;
101+
pThis->m_callback.value(isOn, pThis->m_userData);
102+
}
103+
104+
// Start/stop auto actions based on kind
105+
if (pThis->m_kind == HutaoNativeHotKeyActionKind::MouseClickRepeatForever)
106+
{
107+
if (pThis->m_active.load()) pThis->StartAutoClick(); else pThis->StopAutoClick();
108+
}
109+
else if (pThis->m_kind == HutaoNativeHotKeyActionKind::KeyPressRepeatForever)
110+
{
111+
if (pThis->m_active.load()) pThis->StartAutoKeyPress(); else pThis->StopAutoKeyPress();
112+
}
113+
95114
return 0;
96115
}
97116
}
@@ -117,6 +136,87 @@ void HutaoNativeHotKeyAction::RegisterHotKey()
117136
::RegisterHotKey(m_hWnd, m_hotKeyId, m_modifiers, m_vk);
118137
}
119138

139+
// Auto-click implementation
140+
void HutaoNativeHotKeyAction::StartAutoClick()
141+
{
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())
150+
{
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));
164+
}
165+
});
166+
}
167+
168+
void HutaoNativeHotKeyAction::StopAutoClick()
169+
{
170+
bool expected = true;
171+
if (!m_clicking.compare_exchange_strong(expected, false))
172+
return; // not clicking
173+
174+
if (m_clickThread.joinable())
175+
{
176+
m_clickThread.join();
177+
}
178+
}
179+
180+
// Auto-keypress implementation
181+
void HutaoNativeHotKeyAction::StartAutoKeyPress()
182+
{
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+
});
206+
}
207+
208+
void HutaoNativeHotKeyAction::StopAutoKeyPress()
209+
{
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+
}
218+
}
219+
120220
HRESULT STDMETHODCALLTYPE HutaoNativeHotKeyAction::Update(int modifiers, uint vk)
121221
{
122222
bool wasEnabled = m_enabled;
@@ -180,5 +280,6 @@ HRESULT STDMETHODCALLTYPE HutaoNativeHotKeyAction::SetIsEnabled(BOOL isEnabled)
180280
}
181281

182282
m_enabled = newEnabled;
283+
183284
return S_OK;
184285
}

src/Snap.Hutao.Remastered.Native/HutaoNativeHotKeyAction.h

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,17 @@
33
#include "IHutaoNativeHotKeyAction_h.h"
44
#include "Types_h.h"
55
#include "CustomImplements.h"
6+
#include "HutaoNativeHotKeyActionCallback.h"
67
#include <Windows.h>
8+
#include <thread>
9+
#include <atomic>
710

811
class HutaoNativeHotKeyAction : public hutao::CustomImplements<
912
HutaoNativeHotKeyAction,
1013
IHutaoNativeHotKeyAction>
1114
{
1215
public:
13-
HutaoNativeHotKeyAction();
14-
HutaoNativeHotKeyAction(HutaoNativeHotKeyActionKind kind, WNDPROC callback, LONG_PTR userData);
16+
HutaoNativeHotKeyAction(HutaoNativeHotKeyActionKind kind, HutaoNativeHotKeyActionCallback callback, GCHandle userData);
1517
~HutaoNativeHotKeyAction();
1618

1719
// IHutaoNativeHotKeyAction methods
@@ -20,17 +22,40 @@ class HutaoNativeHotKeyAction : public hutao::CustomImplements<
2022
virtual HRESULT STDMETHODCALLTYPE SetIsEnabled(BOOL isEnabled) override;
2123

2224
private:
23-
WNDPROC m_callback;
25+
HutaoNativeHotKeyActionCallback m_callback;
26+
GCHandle m_userData;
27+
HutaoNativeHotKeyActionKind m_kind;
2428
int m_modifiers;
2529
uint m_vk;
2630
bool m_enabled;
2731
int m_hotKeyId;
2832
HWND m_hWnd;
2933
static UINT s_nextHotKeyId;
3034

31-
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
32-
static ATOM RegisterWindowClass();
33-
HWND CreateMessageWindow();
35+
// running state toggled by WM_HOTKEY
36+
std::atomic<bool> m_active;
37+
3438
void UnregisterHotKey();
3539
void RegisterHotKey();
40+
41+
// Window helpers
42+
static ATOM RegisterWindowClass();
43+
HWND CreateMessageWindow();
44+
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
45+
46+
// Auto-click support
47+
std::thread m_clickThread;
48+
std::atomic<bool> m_clicking;
49+
int m_clickIntervalMs;
50+
51+
void StartAutoClick();
52+
void StopAutoClick();
53+
54+
// Auto-keypress support (for KeyPressRepeatForever)
55+
std::thread m_keyThread;
56+
std::atomic<bool> m_keyPressing;
57+
int m_keyIntervalMs;
58+
59+
void StartAutoKeyPress();
60+
void StopAutoKeyPress();
3661
};
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#pragma once
2+
3+
#include "Types.h"
4+
#include <Windows.h>
5+
6+
typedef void (__stdcall *HutaoNativeHotKeyActionCallbackFunc)(BOOL, GCHandle);
7+
8+
struct HutaoNativeHotKeyActionCallback
9+
{
10+
HutaoNativeHotKeyActionCallbackFunc value;
11+
};

src/Snap.Hutao.Remastered.Native/HutaoNativeNotifyIconCallback.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#include "Types.h"
44
#include <Windows.h>
55

6-
// 通知图标回调种类枚举
76
enum class HutaoNativeNotifyIconCallbackKind : int
87
{
98
TaskbarCreated = 0,
@@ -12,10 +11,8 @@ enum class HutaoNativeNotifyIconCallbackKind : int
1211
LeftButtonDoubleClick = 3,
1312
};
1413

15-
// 通知图标回调函数指针类型
1614
typedef void (*HutaoNativeNotifyIconCallbackFunc)(HutaoNativeNotifyIconCallbackKind kind, RECT rect, POINT point, nint userData);
1715

18-
// 通知图标回调结构体(模仿项目风格)
1916
struct HutaoNativeNotifyIconCallback
2017
{
2118
HutaoNativeNotifyIconCallbackFunc value;

src/Snap.Hutao.Remastered.Native/Snap.Hutao.Remastered.Native.vcxproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@
7070
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
7171
</ImportGroup>
7272
<PropertyGroup Label="UserMacros" />
73+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
74+
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(OutDir);$(LibraryPath)</LibraryPath>
75+
</PropertyGroup>
76+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
77+
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(OutDir);$(LibraryPath)</LibraryPath>
78+
</PropertyGroup>
7379
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
7480
<ClCompile>
7581
<WarningLevel>Level3</WarningLevel>
@@ -172,6 +178,7 @@
172178
<ItemGroup>
173179
<ClInclude Include="CustomImplements.h" />
174180
<ClInclude Include="Error.h" />
181+
<ClInclude Include="HutaoNativeHotKeyActionCallback.h" />
175182
<ClInclude Include="HutaoNativeNotifyIconCallback.h" />
176183
<ClInclude Include="WindowUtils.h" />
177184
<ClInclude Include="DllInjectionUtils.h" />

src/Snap.Hutao.Remastered.Native/Snap.Hutao.Remastered.Native.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,9 @@
302302
<ClInclude Include="Error.h">
303303
<Filter>头文件</Filter>
304304
</ClInclude>
305+
<ClInclude Include="HutaoNativeHotKeyActionCallback.h">
306+
<Filter>头文件\core\struct</Filter>
307+
</ClInclude>
305308
</ItemGroup>
306309
<ItemGroup>
307310
<Midl Include="IHutaoString.idl">

0 commit comments

Comments
 (0)