Russian version of the article you can find here:
Introduction
This project demonstrates the use of a programming hook technique to emulate mouse by means of the keyboard. The mouse emulator software is useful in cases when the “real” mouse is broken (or absent) and you need to perform some operations which require the mouse pointing device.
Background
One day while working on an old computer, I ran into a problem... the USB port was broken and the mouse PS/2 was absent. I decided to write a simple program which could take the place of the mouse device.
Using the Code
The idea of “virtual mouse” software is the following. First of all, it is necessary to choose and assign keys for the corresponding mouse actions. The chosen assignment is as follows:
- move pointer left (NUM4);
- move pointer right (NUM6);
- move pointer up (NUM8);
- move pointer down (NUM5);
- left mouse button click (NUM7);
- right mouse button click (NUM9).
The source code for these assignments looks as follows:
#define KeyMoveLeft VK_NUMPAD4
#define KeyMoveRight VK_NUMPAD6
#define KeyMoveUP VK_NUMPAD8
#define KeyMoveDown VK_NUMPAD5
#define KeyClickLeft VK_NUMPAD7
#define KeyClickRight VK_NUMPAD9
One more necessary thing is to assign a button (it may be a combination of keys) which would control the state of the “virtual mouse”. It could be switched on and off, if necessary. For this purpose, the following definition is present in the code:
#define KeyMouseEmulateEnDis VK_F7
The next obvious actions are:
- creation of the function for keys processing;
- starting keyboard hook from the “main” function;
What is a keyboard hook? A hook is a mechanism by which an application can intercept events, such as messages, mouse actions, and keystrokes. A function that intercepts a particular type of event is known as a hook procedure. A hook procedure can act on each event it receives, and then modify or discard the event [1]. To start a keyboard hook, it is necessary to write the callback function which will be handled on key pressed. The callback function is:
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);
}
Here, the CheckKey(…)
function it is exactly a “key processor”. The content (skeleton) of this function is presented below:
void CheckKey( int nCode, WPARAM wParam, LPARAM lParam )
{
…
if (wParam == WM_SYSKEYUP || wParam == WM_KEYUP)
{
if( hookStruct->vkCode == KeyMouseEmulateEnDis )
{
bEmulEn = bEmulEn ? false: true;
}
}
if(bEmulEn)
{
switch ( hookStruct->vkCode )
{
case KeyClickLeft:
{
}
break;
case KeyClickRight:
{
}
break;
case KeyMoveLeft:
{
}
break;
case KeyMoveUP:
{
}
break;
case KeyMoveRight:
{
}
break;
case KeyMoveDown:
{
}
break;
}
}
}
It is possible to start the hook from the “main” function:
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)) ; return UnhookWindowsHookEx(hHook);
}
More details of the function SetWindowsHookEx(…)
is available in [2].
It is preferable to use the technique of determining the step for moving the cursor depending on whether the button (which is responsible for moving the cursor) is long-pressed or not (short-pressed). The following function is responsible for that idea:
void StepCalculate()
{
unsigned short speedMax = 40;
unsigned short dt = tNow-tBefore;
float dtMax = 30.0f;
step = (int)(speedMax * dtMax/(tNow-tBefore));
}
Here, the speedMax
variable is the biggest step (40 pixels) when moving the cursor by means of a key long-pressed action. The dt
value characterizes the time difference between two identical key pressing (long-pressed key is considered as multiple key pressing).
Tips
To run this software each time Windows starts up, just place the “.exe” file into the “startup” directory.
When using this software in text redactors, push the CTRL button to avoid the typing of unexpected char values.
Points of Interest
The first time I wrote this software, the left mouse button click was emulated as a fast click combination of the “move cursor left”-“move cursor right” keys. The right button mouse click was emulated similarly, as a “move cursor right” -“move cursor left” keys click combination. It was very suitable but some bugs remained. It would be nice to realize (or recover) such an idea in the future.
References
- http://msdn.microsoft.com/en-us/library/ms644959(v=vs.85).aspx
- http://msdn.microsoft.com/en-us/library/ms644990(v=vs.85).aspx
History
- 10 May, 2011: Initial version.