Okay, so I bought the spiffy new Microsoft Arc Mouse from Microsoft at the Company Store. It’s sweet! I can fold it, put it in my pocket, show up at a meeting and still have a full-sized mouse. It’s awesome! I was the envy of my co-meeting-attendees for a day or so.
However, these laser mice are more sensitive then the typical mouse. Even with the IntelliMouse support installed I still have to adjust the sensitivity down so that it stops going so fast across the screen.
Now, the problem is that I SOMETIMES use the mouse, and sometimes still want to use the built-in touch-pad on my laptop. However, when I do, the touch-pad is so slow compared to the mouse, the first thing I need to do is increase the sensitivity of the pad.
So, after 24 hours of dealing with this, I decided that I needed a one-click application to deal with this. I figured, “It can’t be hard.” So faster than you can say Google (because “Bing” is one syllable) I figured out how I could write my own app to deal with this!
It’s all Win32 programming (though portable to 64-bit). I could not find a managed wrapper for this stuff, but it’s not hard to port this.
The key is SystemParametersInfo(). It’s this cute little API that wraps all the stuff that used to be in your WIN.INI file 18 years ago. It’s still relevant today – just like De Morgan’s Law. The two items we’re interested in are SPI_GETMOUSESPEED and SPI_SETMOUSESPEED.
The spec here is trivial: I want to vacillate between two mouse speeds: slow and fast. I want this to work in ONE CLICK – therefore no matter which mouse I am on, I can get the right speed immediately – with one click. So I settled on this simple command-line design:
SetMouseSpeed [1-20] [1-20]
What this will do is:
Figure out the current speed
If the current speed is one specified on the command-line, pick the other one
Otherwise, set the new speed to the new number
Nice thing here is that these calls do not required elevated permissions, so no UAC (User Account Control) warnings popping up during my one-click program.
So, armed with this new, useful information I busted out Visual Studio 2010 Beta 2 and started coding.
First I started with a simple get routine.
int iMouseSpeed = 0;
if (0 != SystemParametersInfo(SPI_GETMOUSESPEED, 0,
(LPVOID)&iMouseSpeed, 0))
_tprintf(_T("Current Speed: %d\n"), iMouseSpeed);
I tried this on both 32 and 64 bit to affirm that the documentation was correct and the API really accepted a 32-bit int (passed though the not-so-safe LPVOID cast). of course this worked just fine.
The next step is to make sure we’re able to set correctly:
if (0 != SystemParametersInfo(SPI_SETMOUSESPEED, 0,
(LPVOID)iRequestSpeed, 0))
_tprintf(_T("New Speed: %d\n"), iRequestSpeed);
You’ve got to love LPVOID for polymorphic types, right? :-)
So, tested… works great. Wrapped these two babies up in a couple functions… and then came making sure the rest of the program works reliably – and plays nicely with stupidity.
Now for some input checking:
int iSpeed1 = _ttoi(argv[1]);
int iSpeed2 = 0;
int iNewSpeed = iSpeed1;
if (argc > 2)
iSpeed2 = _ttoi(argv[2]);
Now for some limit checking:
if (iCurrentSpeed == iSpeed1 && iSpeed2 > 0)
iNewSpeed = iSpeed2;
iNewSpeed = min(max(iNewSpeed, 0), 20);
And we’re just about done. Add some handling for GetLastError, and you’re DONE! I did update the Error code based on the sample here. LocalAlloc is now inefficient according to the MSDN documentation, so I allocated the 64k buffer max needed by FormatMessage(). I could be faster by allocating on the stack, but that’s both fun and dangerous.
I also cleaned up the blind casts with C++ casts that at least admit to the world they are blind.
64k still seems silly. But then, it’s a mouse settings program – for ME. I have real code the ship.
Here’s the finished code. Trivial.
The cool thing now is that I made a shortcut to the program in my Windows 7 task bar, and a set the settings at 5 and 10 (SetMouseSpeed 5 10), and I show up at a meeting now with or without this AWESOME Arc Mouse and get the settings corrected in ONE CLICK – every time!
The impact to me made a difference in my daily activities, and it gave me a chance to check out the new features in C++ in VS010… like the code definition feature.
By the way, this should work on all platforms back to Windows 2000, both 32 and 64-bit.
NO WARRANTY IS EXPRESSED OR IMPLIED IN THIS CODE.
Enjoy.
// SetMouseSpeed.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "winuser.h"
void DisplayWinError(LPCTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code
const DWORD cchBuff = 65635;
TCHAR* lpMsgBuf = new TCHAR[cchBuff];
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
lpMsgBuf,
cchBuff, NULL );
// Display the error message and exit the process
size_t cch = lstrlen(lpMsgBuf) + lstrlen(lpszFunction) + 40;
TCHAR* lpDisplayBuf = new TCHAR[cch];
StringCchPrintf(lpDisplayBuf,
cch,
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
_tprintf(lpDisplayBuf);
delete lpMsgBuf;
delete lpDisplayBuf;
}
int IGetAndDisplayCurrentMouseSpeed()
{
int iMouseSpeed = 0;
if (0 != SystemParametersInfo(SPI_GETMOUSESPEED, 0,
static_cast<void*>(&iMouseSpeed), 0))
_tprintf(_T("Current Speed: %d\n"), iMouseSpeed);
else
DisplayWinError(_T("SPI_GETMOUSESPEED"));
return iMouseSpeed;
}
void SetAndDisplayNewMouseSpeed(const INT iRequestSpeed)
{
if (0 != SystemParametersInfo(SPI_SETMOUSESPEED, 0,
reinterpret_cast<void*>(iRequestSpeed), 0))
_tprintf(_T("New Speed: %d\n"), iRequestSpeed);
else
DisplayWinError(_T("SPI_SETMOUSESPEED"));
}
bool FCheckInput(int argc, _TCHAR* argv[])
{
return (argc > 1);
}
int _tmain(int argc, _TCHAR* argv[])
{
if (FCheckInput(argc, argv))
{
int iCurrentSpeed = IGetAndDisplayCurrentMouseSpeed();
int iSpeed1 = _ttoi(argv[1]);
int iSpeed2 = 0;
int iNewSpeed = iSpeed1;
if (argc > 2)
iSpeed2 = _ttoi(argv[2]);
if (iCurrentSpeed == iSpeed1 && iSpeed2 > 0)
iNewSpeed = iSpeed2;
iNewSpeed = min(max(iNewSpeed, 0), 20);
SetAndDisplayNewMouseSpeed(iNewSpeed);
}
else
{
_tprintf(_T("Usage: SetMouseSpeed [1-20] [1-20]\n"));
}
return 0;
}
- Art
Copyright © 2009, Microsoft, Corp. All rights reserved.