DIY属于自己的鼠标侧键

现在的鼠标功能越来越强大,不单单只有左右中三键,有更多的按键,比如5键,7键,20+键、、、我也顺便淘了一个5键的鼠标。但是无奈国产货(Understand?),鼠标侧面的两个键完全白费了,只能用来当前进后退键。看到罗技、Razor的鼠标按键自定义爽爽的,心里就不舒服,然后萌生了这个想法——自己来重新DIY下这俩个鸡肋按键。

网上资料倒是一大堆,先分析下这个工程怎么实现。

由于是从打开软件开始这两个按键一直要处于DIY的条件下,所以远程注入不能实现,否则要一一注入那还不麻烦死?杀毒软件也要来一直阻止你的。丢个例子,试试就知道有多蛋疼了:

#include <windows.h>

#include <iostream.h>

 

bool EnableDebugPriv()

{

    HANDLE hToken;

    LUID sedebugnameValue;

    TOKEN_PRIVILEGES tkp;

 

    if (!OpenProcessToken(GetCurrentProcess(),

        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {

        return false;

    }

 

    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue)) {

        CloseHandle(hToken);

        return false;

    }

 

    tkp.PrivilegeCount = 1;

    tkp.Privileges[0].Luid = sedebugnameValue;

    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

 

    if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) {

        CloseHandle(hToken);

        return false;

    }

 

    return true;

}

 

BOOL InitDll(const char *DllFullPath, const DWORD dwRemoteProcessId)

{

EnableDebugPriv();

 

HANDLE hRemoteProcess;

 

    //打开远程线程

    hRemoteProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, dwRemoteProcessId );

 

char *pszLibFileRemote;

 

    //使用VirtualAllocEx函数在远程进程的内存地址空间分配DLL文件名空间

    pszLibFileRemote = (char *) VirtualAllocEx( hRemoteProcess, NULL, lstrlen(DllFullPath)+1,

MEM_COMMIT, PAGE_READWRITE);

 

    //使用WriteProcessMemory函数将DLL的路径名写入到远程进程的内存空间

    WriteProcessMemory(hRemoteProcess, pszLibFileRemote, (void *) DllFullPath,

lstrlen(DllFullPath)+1, NULL);

 

DWORD dwID;

LPVOID pFunc = LoadLibraryA;

HANDLE hRemoteThread = CreateRemoteThread(hRemoteProcess, NULL, 0,

(LPTHREAD_START_ROUTINE)pFunc, pszLibFileRemote, 0, &dwID );

 

 

if(hRemoteThread == NULL)

{

cout<<"注入线程失败!"<<endl;

return 0;

}

    CloseHandle(hRemoteProcess);

    CloseHandle(hRemoteThread);

 

    return TRUE;

}

 

int main()

{

    InitDll("E:\\工作区间\\源程序\\远程注入\\Debug\\iGazeU.dll", 576) ;//这个dll你所要注入的dll文件,这个数字是你想注入的进程的PID

    return 0;

}

 

所以另寻方法了。

熟悉Windows的童鞋也许能通过修改注册表实现小部分功能,比方说把按键映射,连编写都省了,但是绝对做不出自定义想要的功能,比方说复制粘贴什么的。

最后,只有靠一种方法了,就是用全局钩子。

全局钩子?没怎么看过的童鞋一定觉得很神秘,360有时候也会提示带有Hook字样的内容,其实钩子只是一个纸老虎。

Windows和DOS最大的区别就是消息。现在学编程的童鞋肯定知道一个面向过程的程序是怎么编的,但是可能并不清楚面向对象的程序是怎么写的,比方说一个状态栏带有动态时间显示的记事本是怎么显示的?如果用面向过程写,记事本要输入文字,又要定时刷新时间,两个事情怎么可能同时做?所以说,消息就是Windows提醒程序什么时候做什么事情,程序只要循环不断接收消息就行了。就像这样:

while (GetMessage(&msg, NULL, 0, 0))  //程序永远在接收消息

{

if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

我们现在研究的核心,就是怎么让Windows在向程序发送鼠标侧键消息的时候把这个消息拦截掉,改掉并换成自定义的消息,这就是钩子的本来面目。

最重要的一关被我们跨过去了,现在是实战阶段了。

打开你的VS2010,或者VC6也一样,由于MFC比较方便,很多代码都是自动添加好的,所以我们以MFC为例:

1、新建一个 MFC AppWizarddll) 工程,选择 MFC扩展DLL(使用共享MFC DLL),建立工程名为TestHook

为什么要建立DLL(动态连接库)?Windows坑爹的规定,没办法,人家是老大,只能听他的,Linux没试过,应该会好很多。

DLL是什么?普及下,就是独立出来的库,比方说你有n+1个程序都要使用 void max(int *a, int *b)

{

a ^= b ^= a ^= b;

}

那么你只需写一个这样的功能,做成DLL,你就可以让n+1个程序都可以用它了,是不是很方便?

2、打开stdafx.h,在#include <afxwin.h>上面加入:

#define _WIN32_WINNT 0x500

stdafx.h最后面加上:

#include <windows.h>

#include <winuser.h>

这是什么意思呢?你可以打开winuser.h看看,原来_WIN32_WINNT是用来区分系统版本的,我们的程序只能在Windows 2000和以上版本的电脑才能运行。

3、打开TestHook.def,在最下面加入:

SECTIONS

mydata READ WRITE SHARED

4、现在来做几个函数了,用类来管理比较方便,应该说是一个好习惯。先来定义一个类:新建头文件MouseHook.h,写上:

class AFX_EXT_CLASS CMouseHook:public CObject

{

public:

CMouseHook();

~CMouseHook();

 

BOOL startHook();

BOOL stopHook();

static LRESULT CALLBACK MouseProc(int nCode,WPARAM wParam,LPARAM lParam);

};

再新建一个MouseHook.cpp,添加以下代码:

#include "stdafx.h"

#include "MouseHook.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

 

#pragma data_seg("mydata")

HHOOK glhHook = NULL;

HINSTANCE glhInstance = NULL;

#pragma data_seg()

 

CMouseHook::CMouseHook()

{

}

 

CMouseHook::~CMouseHook()

{

stopHook();

}

LRESULT CALLBACK CMouseHook::MouseProc(int nCode,WPARAM wParam,LPARAM lParam)

{

return CallNextHookEx(glhHook, nCode, wParam, lParam);

}

BOOL CMouseHook::startHook()

{

BOOL bResult = FALSE; 

glhHook = SetWindowsHookEx(WH_MOUSE_LL, CMouseHook::MouseProc, glhInstance, 0); 

 

if(glhHook != NULL) 

bResult = TRUE; 

 

return bResult; 

}

 

BOOL CMouseHook::stopHook()

{

if (glhHook == NULL)

{

MessageBox(NULL, _T("NULL HOOK"), _T("glhHook"), MB_OK);

}

 

BOOL bResult = FALSE; 

 

bResult = UnhookWindowsHookEx(glhHook); 

if(bResult) 

MessageBox(NULL, _T("UnhookWindowsHookEx Success"), _T("glhHook"), MB_OK);

glhHook = NULL; 

}

 

return bResult;

}

5、现在是关键代码了,我们的代码都在

LRESULT CALLBACK CMouseHook::MouseProc(int nCode,WPARAM wParam,LPARAM lParam)

{

return CallNextHookEx(glhHook, nCode, wParam, lParam);

}

中完成,具体代码如下:

LRESULT CALLBACK CMouseHook::MouseProc(int nCode,WPARAM wParam,LPARAM lParam)

{

LPMSLLHOOKSTRUCT pMouseHook = (MSLLHOOKSTRUCT*)lParam;

if (nCode >= 0)

{

If (wParam==WM_XBUTTONDOWN && HIWORD(pMouseHook->mouseData)==XBUTTON1)

{

//写上自己代码

return TRUE;

}

 

if (wParam == WM_XBUTTONUP && HIWORD(pMouseHook->mouseData)==XBUTTON1)

{

//写上自己代码

return TRUE;

}

 

if (wParam == WM_XBUTTONDOWN && HIWORD(pMouseHook->mouseData)==XBUTTON2)

{

//写上自己代码

return TRUE;

}

 

if (wParam == WM_XBUTTONUP && HIWORD(pMouseHook->mouseData)==XBUTTON2)

{

//写上自己代码

return TRUE;

}

}

return CallNextHookEx(glhHook, nCode, wParam, lParam);

}

VC6的童鞋会说了,为什么我编译下后程序出现N多错误?其实是VC6太老了,有些库比较新,没有得到更新。只要在cpp#include "stdafx.h"下加上这些:

#define WM_XBUTTONDOWN 0x020B

#define WM_XBUTTONUP 0x020C

#define XBUTTON1 0x1

#define XBUTTON2 0x2

是不是行了呢?

 

注意:VC6要把_T()去掉,比方说_T("glhHook")变成"glhHook"。

由于5键鼠标不是常规鼠标,而我们使用的是低级钩子(Low-Level Hook)因此要用MSLLHOOKSTRUCT结构体。

 

6、做完DLL当然要有程序去调用啊,接下来做一个调用程序(以VC6为例):

(1)新建一个MFC EXE工程Mouse,把做完的Dll工程下的Debug目录下的TestHook.lib和Dll工程目录中的MouseHook.h拷贝到新建工程的目录下,按快捷键Alt+F7打开工程设置,点击 连接 选项卡,在对象/库模块中填写TestHook.lib,打开MouseDlg.h,在#include "stdafx.h"下方加入

#include "MouseHook.h",

然后在class CMouseDlg : public CDialog下的public:下加入:

CMouseHook m_hook;

切换到MouseDlg.cpp,在BOOL CMouseDlg::OnInitDialog()下的SetIcon(m_hIcon, FALSE); // Set small icon

下加入

m_hook.startHook();

然后编译链接吧。

 

现在,把做完的TestHook.dll和Mouse.exe放在同一个目录下,打开是不是发现鼠标的侧键被屏蔽了?因为我们到现在都没有加入自己想要的功能,又是运行了直接return TRUE; 所以截取的消息直接被吃掉了!

加个小功能吧,有些童鞋的鼠标左右键不好用了,可以临时代替应急:

LRESULT CALLBACK CMouseHook::MouseProc(int nCode,WPARAM wParam,LPARAM lParam)

{

int cx=GetSystemMetrics(SM_CXSCREEN);//得到屏幕宽度

int cy=GetSystemMetrics(SM_CYSCREEN);//得到屏幕高度

LONG ldx = pMouseHook->pt.x * 65535 / cx;

LONG ldy = pMouseHook->pt.y * 65535 / cy;

 

LPMSLLHOOKSTRUCT pMouseHook = (MSLLHOOKSTRUCT*)lParam;

 

if (nCode >= 0)

{

If (wParam==WM_XBUTTONDOWN && HIWORD(pMouseHook->mouseData)==XBUTTON1)

{

INPUT input[1];

ZeroMemory(&input, sizeof(INPUT));

 

//鼠标左键弹起

input[0].type = INPUT_MOUSE;

input[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;

input[0].mi.dx = ldx;

input[0].mi.dy = ldy;

 

SendInput(

1, // count of input events

input, // array of input events

sizeof(INPUT) // size of structure

);

 

return TRUE;

}

 

if (wParam == WM_XBUTTONUP && HIWORD(pMouseHook->mouseData)==XBUTTON1)

{

INPUT input[1];

ZeroMemory(&input, sizeof(INPUT));

 

//鼠标左键弹起

input[0].type = INPUT_MOUSE;

input[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;

input[0].mi.dx = ldx;

input[0].mi.dy = ldy;

 

SendInput(

1, // count of input events

input, // array of input events

sizeof(INPUT) // size of structure

);

 

return TRUE;

}

 

if (wParam == WM_XBUTTONDOWN && HIWORD(pMouseHook->mouseData)==XBUTTON2)

{

INPUT input[1];

ZeroMemory(&input, sizeof(INPUT));

 

//鼠标左键弹起

input[0].type = INPUT_MOUSE;

input[0].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;

input[0].mi.dx = ldx;

input[0].mi.dy = ldy;

 

SendInput(

1, // count of input events

input, // array of input events

sizeof(INPUT) // size of structure

);

 

return TRUE;

}

 

if (wParam == WM_XBUTTONUP && HIWORD(pMouseHook->mouseData)==XBUTTON2)

{

INPUT input[1];

ZeroMemory(&input, sizeof(INPUT));

 

//鼠标左键弹起

input[0].type = INPUT_MOUSE;

input[0].mi.dwFlags = MOUSEEVENTF_RIGHTUP;

input[0].mi.dx = ldx;

input[0].mi.dy = ldy;

 

SendInput(

1, // count of input events

input, // array of input events

sizeof(INPUT) // size of structure

);

 

return TRUE;

}

}

return CallNextHookEx(glhHook, nCode, wParam, lParam);

}

 

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注