65.9K
CodeProject 正在变化。 阅读更多。
Home

鼠标模拟软件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (14投票s)

2011 年 5 月 10 日

CPOL

3分钟阅读

viewsIcon

46593

downloadIcon

8148

一个简单的基于软件的鼠标模拟器

您可以在这里找到本文的俄语版本

如何实现

引言

本项目演示了使用编程钩子技术通过键盘来模拟鼠标。鼠标模拟软件在“真实”鼠标损坏(或不存在)并且您需要执行一些需要鼠标指针设备的操作时非常有用。

背景

有一天,在旧电脑上工作时,我遇到了一个问题……USB端口坏了,并且没有PS/2鼠标。我决定编写一个简单的程序来代替鼠标设备。

Using the Code

“虚拟鼠标”软件的思路如下。 首先,需要选择并分配键以对应鼠标动作。 选择的分配如下

  • 向左移动指针(NUM4
  • 向右移动指针(NUM6
  • 向上移动指针(NUM8
  • 向下移动指针(NUM5
  • 鼠标左键单击(NUM7
  • 鼠标右键单击(NUM9

这些分配的源代码如下所示

// keys to control cursor
#define KeyMoveLeft                VK_NUMPAD4
#define KeyMoveRight               VK_NUMPAD6
#define KeyMoveUP                  VK_NUMPAD8
#define KeyMoveDown                VK_NUMPAD5
 
// keys to emulate mouse buttons
#define KeyClickLeft               VK_NUMPAD7
#define KeyClickRight              VK_NUMPAD9

另一件必要的事情是分配一个按钮(它可以是按键的组合),该按钮将控制“虚拟鼠标”的状态。 如有必要,可以将其打开和关闭。 为此,代码中存在以下定义

// key to switch on/off MouseEmulate software
#define KeyMouseEmulateEnDis       VK_F7

接下来的显而易见的动作是

  • 创建用于按键处理的函数
  • 从“main”函数启动键盘钩子

什么是键盘钩子? 钩子是一种机制,应用程序可以通过该机制拦截事件,例如消息,鼠标动作和击键。 拦截特定类型事件的函数称为钩子过程。 钩子过程可以作用于其接收的每个事件,然后修改或丢弃该事件[1]。 要启动键盘钩子,必须编写在按下键时将处理的回调函数。 回调函数是

LRESULT CALLBACK KeyboardHook (int nCode, WPARAM wParam, LPARAM lParam)
{
     if (nCode == HC_ACTION)
         if (wParam == WM_SYSKEYDOWN || wParam == WM_KEYDOWN || 
             wParam == WM_SYSKEYUP || wParam == WM_KEYUP)
            CheckKey (nCode, wParam, lParam);
     return CallNextHookEx(hHook, nCode, wParam, lParam);
}

在此,CheckKey(…)函数正是“键处理器”。 此函数的内容(骨架)如下所示

void CheckKey( int nCode, WPARAM wParam, LPARAM lParam )
{
     …
     // switch on/off the MouseEmulate program
     if (wParam == WM_SYSKEYUP || wParam == WM_KEYUP)
     {                
         if( hookStruct->vkCode == KeyMouseEmulateEnDis )
         {
            bEmulEn = bEmulEn ? false: true;
         }
     }
 
     if(bEmulEn)
     {
         switch ( hookStruct->vkCode )
         {
              case KeyClickLeft:
              {
                // emulating left mouse button click
              }
              break;
              case KeyClickRight:
              {
                // emulating right mouse button click
              }
              break;
              case KeyMoveLeft:
              {
                // move cursor left
              }
              break;
              case KeyMoveUP:
              {
                 // move cursor up
              }
              break;
              case KeyMoveRight:
              {                
                // move cursor right
              }
              break;
              case KeyMoveDown:
              {
                 // move cursor down
              }
              break;
         }
    }
}

可以从“main”函数启动钩子

int APIENTRY WinMain( HINSTANCE hInstance, 
    HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
     hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHook, hInstance , 0);
     while (GetMessage(NULL,NULL,0,0)) ; // NOP while not WM_QUIT
     return UnhookWindowsHookEx(hHook);
}

有关函数SetWindowsHookEx(…)的更多详细信息,请参见[2]。

最好使用确定移动光标的步长值的技术,具体取决于是否长按(或短按)负责移动光标的按钮。 以下函数负责该想法

void StepCalculate()
{
     unsigned short speedMax = 40;
     unsigned short dt = tNow-tBefore;
     float dtMax = 30.0f;
 
     step = (int)(speedMax * dtMax/(tNow-tBefore));
}

在此,speedMax变量是通过长按键动作移动光标时的最大步长(40像素)。 dt值表示两个相同的按键(长按键被视为多次按键)之间的时间差。

技巧

要使此软件每次Windows启动时都运行,只需将“.exe”文件放入“启动”目录中即可。

在文本编辑器中使用此软件时,请按下CTRL按钮以避免输入意外的char值。

关注点

我第一次编写此软件时,将鼠标左键单击模拟为“向左移动光标”-“向右移动光标”键的快速单击组合。 鼠标右键单击也类似地模拟为“向右移动光标”-“向左移动光标”键的单击组合。 这非常好,但是仍然存在一些错误。 很高兴将来实现(或恢复)这样的想法。

参考文献

  1. http://msdn.microsoft.com/en-us/library/ms644959(v=vs.85).aspx
  2. http://msdn.microsoft.com/en-us/library/ms644990(v=vs.85).aspx

历史

  • 2011年5月10日:初始版本
© . All rights reserved.