简易鼠标连击修正工具原理与实现
1、起因近日鼠标的微动开关出问题了,偶尔单击鼠标变成双击,测试了下10次单击有2-3次会变为双击,网上买的鼠标还要两三天的时间才能到,于是就做了个简单的小工具先应付着。本程序原理较为简单,但由于本人水平有限,代码写的较烂,请各位多多指点。
2、原理
利用鼠标钩子获取鼠标按下和弹起的操作,计算两次点击的时间差,如果太快了,那肯定就是微动开关的问题造成的,然后屏蔽掉第二次点击操作就可以了。
3、实现
3.1、主要API介绍
1、设置钩子SetWindowsHookEx
HHOOK SetWindowsHookEx( int idHook,
HOOKPROC lpfn,
HINSTANCE hMod,
DWORD dwThreadId
);
参数:idHook:消息类型 lpfn:消息处理函数hMod:模块句柄dwThreadId:关联的线程ID
2、取消钩子UnhookWindowsHookEx
BOOL UnhookWindowsHookEx( HHOOK hhk
);
参数:hhk:SetWindowsHookEx的返回值
3、查询计数器频率QueryPerformanceFrequency
BOOL QueryPerformanceFrequency( LARGE_INTEGER *lpFrequency
);
参数:lpFrequency:计数器频率
4、查询计数器QueryPerformanceCounter
BOOL QueryPerformanceCounter( LARGE_INTEGER *lpPerformanceCount
);
参数:lpPerformanceCount:计数器计数
3.2、基本流程
3.2.1主程序流程
程序启动,获取命令行参数,得到设置的延迟时间,启动钩子进行消息处理。
3.2.2消息处理流程
区分是否为第一次按下,第一次按下:记录按下时间A。非第一次按下:将上次按下时间设为A。
记录当前时间B,若B-A大于设置的间隔,则放行。若小于则取消本次按下操作,并设置一个标记,让对应的弹起操作也取消。
弹起操作与之类似。
3.3、代码实现
3.3.1、启动钩子
//启动钩子
BOOL StartHook()
{
//获取计数器频率
QueryPerformanceFrequency(&TimeFreq);
//设置鼠标底层钩子
hHook = SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)HookProc, NULL, 0);
if (hHook) return TRUE;
return FALSE;
}
3.3.2、取消钩子
//卸载钩子
BOOL UnLoadHook()
{
return(UnhookWindowsHookEx(hHook));
}
3.3.3、消息处理
//消息处理
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
int time = 0;
switch (wParam)
{
//左键按下
case WM_LBUTTONDOWN:
//初始化点击时间
if (LClkTimeStart.QuadPart == 0)
QueryPerformanceCounter(&LClkTimeStart);
else
LClkTimeStart.QuadPart = LClkTimeNext.QuadPart;
//获取本次的按下时间
QueryPerformanceCounter(&LClkTimeNext);
//计算两次左键按下间隔时间,单位ms
time = (((LClkTimeNext.QuadPart - LClkTimeStart.QuadPart) * 1000) / TimeFreq.QuadPart);
//若已经设置弹起无效,则恢复。
if (LBtnUPCancel)
{
LBtnUPCancel = FALSE;
}
//在屏蔽范围内,屏蔽此次按下消息,并设置下次弹起消息无效
if (time < BnDelay && time>0)
{
LBtnUPCancel = TRUE;
//输出调试信息
if (Debug)
{
MyOutputDebugString("LDtime=%d————LDNCancel\n", time);
}
return TRUE;
}
else
{
if (Debug)
{
MyOutputDebugString("LDtime=%d\n", time);
}
}
break;
//左键弹起
case WM_LBUTTONUP:
//初始化点击时间
if (LClkTimeStart.QuadPart == 0)
QueryPerformanceCounter(&LClkTimeStart);
else
LClkTimeStart.QuadPart = LClkTimeNext.QuadPart;
//获取本次弹起时间
QueryPerformanceCounter(&LClkTimeNext);
//计算两次间隔
time = (((LClkTimeNext.QuadPart - LClkTimeStart.QuadPart) * 1000) / TimeFreq.QuadPart);
//若已经设置弹起取消,则取消标记并取消本次弹起
if (LBtnUPCancel)
{
LBtnUPCancel = FALSE;
if (Debug)
{
MyOutputDebugString("LUtime=%d————LUPCancel\n", time);
}
return TRUE;
}
else
{
if (Debug)
{
MyOutputDebugString("LUtime=%d\n", time);
}
}
break;
default:
return(CallNextHookEx(hHook, nCode, wParam, lParam));
break;
}
}
return(CallNextHookEx(hHook, nCode, wParam, lParam));
}
3.3.4、主程序
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{
MSG msg;
BOOL bRet;
char Cmd = { 0 };
//设置互斥体,防止多开
if (CreateMutex(NULL, TRUE, "_FixMouse_") != NULL)
{
if (ERROR_ALREADY_EXISTS == GetLastError())
{
return 0;
}
}
//提取命令行
if (NULL== lpCmdLine)
{
MessageBox(NULL, "正确命令行为:40,0 延迟取值范围为1-499", "不正确的取值", MB_OK);
return 0;
}
strcpy_s(Cmd, 20, lpCmdLine);
char *s,*next;
s = strtok_s(Cmd, ",",&next);
if (NULL!=s)
{
BnDelay = strtol(s, NULL, 10);
if (!(BnDelay > 0 && BnDelay < 500))
{
MessageBox(NULL, "正确命令行为:40,0 延迟取值范围为1-499", "不正确的取值", MB_OK);
return 0;
}
}
s = strtok_s(next,",",&next);
if (NULL != s)
{
Debug = strtol(s, NULL, 10);
}
//启动钩子
Flag = StartHook();
//进入消息循环
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != -1)
{
if (bRet == 0)
{
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam; //WinMain函数结束, 整个程序退出
}
4、添加其他部分
按照上面的代码,便可以做一个简易的鼠标连击修正工具,但是却无法操控,结束程序只能靠任务管理器结束进程。于是我做了一个托盘图标来控制,在这里代码不再赘述,有兴趣可以在附件中查看。
ps:本源码用VS2015编译通过,WIN10 X64 1709版本运行正常
天若幽心 发表于 2018-4-3 20:22
win10 64位,尝试添加注册表,开机时软件没有启动。是否是因为开机时一些程序加载不完整导致的?
我也不清楚什么问题,是不是杀软拦截了,按说应该可以开机启动的 加油 发表于 2019-5-5 06:37
请教下 ,鼠标钩子做热键、拦截操作(误按)等玩各种游戏会被反外挂关照吗?
各家游戏保护不同,并不排除会被反外挂检测的可能。 大神,膜拜 硬件出问题,软件来搞定
小白看不懂,真心来膜拜 可以的,支持大神 为啥子按住不连点 支持发布原创 呵呵,这个历害了,还是换个鼠标比较好吧! gunxsword 发表于 2018-4-3 18:50
呵呵,这个历害了,还是换个鼠标比较好吧!
是的,但是这不是买的鼠标还没到么 610100 发表于 2018-4-3 18:11
硬件出问题,软件来搞定
小白看不懂,真心来膜拜
然而软件也就是暂时解决一下,bug还有很多,还是换硬件比较好