Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate

Mouse Acceleration (Enhance Pointer Precision)


  • Please log in to reply
15 replies to this topic
  • Guests
  • Last active:
  • Joined: --
Thanks to the kind folks here, I've figured out how to adjust my pointer speed using DllCall:

SPI_SETMOUSESPEED = 0x0070
DllCall("SystemParametersInfo", UInt, SPI_SETMOUSESPEED, UInt, 0, UInt, 10, UInt, 0)

However, I'm now trying to turn "Enhance Pointer Precision" on and off. I've been doing some half-blind searching, not really knowing what I'm looking for, but I thought I had finally figured out how to get and set the precision setting:

SPI_GETMOUSE = 0x0003
DllCall("SystemParametersInfo", UInt, SPI_GETMOUSE, UintP, Precision, UInt, 0, UInt, 0)
MsgBox, Setting is %Precision%.

SPI_SETMOUSE = 0x0004
DllCall("SystemParametersInfo", UInt, SPI_SETMOUSE, Uint, 1, UInt, 6, UInt, 10)

But neither works. SPI_GETMOUSE always returns 0 and SPI_SETMOUSE doesn't work. (Retrieving all three parameters of SPI_GETMOUSE returns 0, [blank] and 0.)

I really don't know what I'm doing here, so any help is welcome.

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
The SPI_SETMOUSE item of SystemParametersInfo says, "Sets the two mouse threshold values and the mouse acceleration. The pvParam parameter must point to an array of three integers..."

Assuming "mouse acceleration" is the value you're after, I think you would have to build an array of three integers using the structure steps described on the DllCall page, then pass that array via DllCall("SystemParametersInfo", ...)

If you get stuck, post again and maybe someone will try to get it working.

Wesley
  • Members
  • 12 posts
  • Last active: May 12 2006 10:43 PM
  • Joined: 08 May 2006
Me again -- decided I'd go ahead and register.

It took me 90 minutes of blind trial and error until something magically clicked and I was able to understand what I was supposed to be doing. Bing!

The following will turn off "Enhance pointer precision" as seen in XP's Mouse Properties > Pointer Options:

SPI_SETMOUSE = 0x0004

VarSetCapacity(MySet, 12, 0)

DllCall("SystemParametersInfo", UInt, SPI_SETMOUSE, UInt, 0, Str, MySet, UInt, 1)

The value "1" in DllCall's last parameter makes sure the setting writes to the registry.

The following will set the appropriate registry keys to the default values Windows uses when you turn on "Enhance pointer precision":

SPI_SETMOUSE = 0x0004

VarSetCapacity(MySet, 12, 0)

InsertInteger(6, MySet, 0)	; MouseThreshold1
InsertInteger(10, MySet, 4)	; MouseThreshold2
InsertInteger(1, MySet, 8)	; MouseSpeed

InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
; The caller must ensure that pDest has sufficient capacity.  To preserve any existing contents in pDest,
; only pSize number of bytes starting at pOffset are altered in it.
{
	Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
		DllCall("RtlFillMemory", "UInt", &pDest + pOffset + A_Index-1, "UInt", 1, "UChar", pInteger >> 8*(A_Index-1) & 0xFF)
}

DllCall("SystemParametersInfo", UInt, SPI_SETMOUSE, UInt, 0, Str, MySet, UInt, 1)

You can verify these settings in HKEY_CURRENT_USER/Control Panel/Mouse.

Note that MouseSpeed does not refer to "Select a pointer speed," but simply sets whether or not "Enhance pointer precision" is on (1 or 0). For "Select a pointer speed," you would refer to MouseSensitivity (in the same registry branch), which should be a number between 1 and 20.

To change that, you can use:

SPI_SETMOUSESPEED = 0x0071

MySpeed = 10 ; A number between 1-20.

DllCall("SystemParametersInfo", UInt, SPI_SETMOUSESPEED, UInt, 0, UInt, MySpeed, UInt, 0)

Note also that I've only tried this on XP.

Thanks for pointing me in the right direction!

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Thanks for posting your work. I'm sure it will be useful to others when they search the forum for such a solution.

Wesley
  • Members
  • 12 posts
  • Last active: May 12 2006 10:43 PM
  • Joined: 08 May 2006
No problem. I like to imagine someone somewhere diffusing a bomb and the deranged contraption that was designed to trigger it requires exactly the snippet I posted in order to deactivate it, which the bomb squad is now able to find, resulting in many lives being saved.

By the way, the reason I'm doing this is because I want different settings on my laptop for both my touch pad and for my mouse.

My initial solution is simply to create a shortcut that will run the script; the script will detect what the current settings are and change them to the alternate settings. I just toggle them, depending on what I want to use.

Now that my mind is going, though, I'm wondering if there's some way I can automate it by detecting the moment a mouse is plugged in, but without continually repeating SM_MOUSEPRESENT on a SetTimer. (Depending on where I and my laptop are, I may or may not bother to plug in the mouse.)

Even better, it would be nice to have the script detect which one I'm using at the time and reflect the settings accordingly. (Say, if I have the mouse plugged, but I happen to be using the touch pad, anyway.)

evl
  • Members
  • 1237 posts
  • Last active: Oct 20 2010 11:41 AM
  • Joined: 24 Aug 2005
Nice work on the code above - I was already using SPI_SETMOUSESPEED to toggle between a fast and slow mouse and this will make the perfect addition.

Regarding your other questions, if you're using a usb mouse it is possible to receive usb event notifications (plugged in/unplugged - try searching the forum for that and my user name) but no one on the forum has found a way of differentiating between input from one mouse and another (the same goes for keyboards).

foom
  • Members
  • 386 posts
  • Last active: Jul 04 2007 04:53 PM
  • Joined: 19 Apr 2006

Note that MouseSpeed does not refer to "Select a pointer speed," but simply sets whether or not "Enhance pointer precision" is on (1 or 0). For "Select a pointer speed," you would refer to MouseSensitivity (in the same registry branch), which should be a number between 1 and 20.


Regarding the MoiuseSpeed and Threshold parameter i found following info at MSDN:

[...]The movement is a delta in the X and Y range.

During acceleration, if the delta is larger than MouseThreshold1, it is doubled.

During acceleration, if the delta is larger than MouseThreshold1 and MouseThreshold2, and if MouseSpeed is 2, it is doubled again.

Depending on the size of the mouse movement and the settings of MouseThreshold1, MouseThreshold2, and MouseSpeed, the actual position delta will be unchanged, doubled, or quadrupled. This calculation is carried out independently for the X and Y coordinates.



Wesley
  • Members
  • 12 posts
  • Last active: May 12 2006 10:43 PM
  • Joined: 08 May 2006
foom -

Thanks, I should have mentioned that. It looks like you can actually customize the sensitivity of the acceleration, too.


evl -

I found this topic; that looks basically like what I'm looking for.

Now if I can only figure out how to detect whether it's been plugged in or unplugged.


Whoa - now that's weird. I just got another notification like I got before, but I didn't unplug the mouse. I wonder what caused that. :?: It's no good to me if it does that randomly like that ...

evl
  • Members
  • 1237 posts
  • Last active: Oct 20 2010 11:41 AM
  • Joined: 24 Aug 2005
(bother, just lost the reply I typed out, well here goes again...)

Yes there are a few "phantom" events, but still fairly rare and better than using a timer to check. If you check the registry you can find the device enumeration (i.e. list):
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Mouclass\Enum
I think that one should change before/after you connect the mouse - don't forget to refresh the view to see the changes in the registry editor. You can then use a registry loop to scan for the device you want (in this case, one containing "HID" (or you could use the Product ID (PID)) and Vendor ID (VID) if you want to be more specific).

Wesley
  • Members
  • 12 posts
  • Last active: May 12 2006 10:43 PM
  • Joined: 08 May 2006
Ah, I see now. Check for the existence of the device in the registry, but only when I receive a hardware-change message. I guess I can create a variable that will remember the current state (plugged in or not) and even if I receive a phantom message, the script will only mess with the mouse settings if the state of the mouse in the registry has changed.

Thanks for the help. If I don't have any more problems, I'll try to post what I come up with.

Wesley
  • Members
  • 12 posts
  • Last active: May 12 2006 10:43 PM
  • Joined: 08 May 2006
Here we go. It appears to work pretty well, but I can't guarantee anything. It may be a little sloppy or redundant, too; I don't really have a programmer's mind.

Review the section under "User Pointer Settings" to see what can be changed.

The Alps Touch Pad icon location is accurate for the default installation on my Dell. I made an educated guess on the Synaptics location, which I believe is used on ThinkPads. You can change them, of course.

/*
AutoHotkey Version: 1.x
Language:	English
Platform:	WinXP

Title:		Laptop Mouse Monitor
Author:		Wesley Treat, www.wesleytreat.com
Date:		May 2006

Script Function:
If a USB mouse is plugged into the laptop, optimize the pointer speed and
precision settings for the mouse. If it's not, optimize the settings
for the touch pad. Monitor for changes in mouse's presence.
*/


; ============================================================
; CONFIGURATION
; ============================================================

; ------------------------------------------------------------
; USER POINTER SETTINGS

; Mouse ID
; Check HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Mouclass\Enum
; to determine the ID of your mouse. This should be the value of the key that
; appears and disappears when you plug in and unplug your mouse. You can
; probably just use "HID."

MouseID = HID


; Pointer Speed (1-20)
PadSpeed = 10
MouseSpeed = 12

; Enhance Pointer Precision
PadEnhance = 1
MouseEnhance = 0

; Precision Thresholds
PadThreshold1 = 6
PadThreshold2 = 10
MouseThreshold1 = 0
MouseThreshold2 = 0

; For details on precision and threshold settings, see
; http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceui40/html/cerefSystemParametersInfo.asp
; under SPI_SETMOUSE. By default, thresholds 1 and 2 are "6" and "10" respectively.


; Use a tray icon?
TrayIcon = 1

; Tray Icons
; If you want the tray icon to reflect the current settings, enter a valid
; PadIcon and PadIconGroup. To use the only standard AutoHotkey icon, comment
; out all the icon locations.

MouseIcon = %A_WinDir%\system32\main.cpl
MouseIconGroup = 1

; The likely location of the Alps Touch Pad icon.
; PadIcon = %ProgramFiles%\Apoint\Apoint.exe
; PadIconGroup = 1

; The likely location of the Synaptics Touch Pad icon.
; PadIcon = %ProgramFiles%\Synaptics\SynTP\SynTPEnh.exe
; PadIconGroup = 1


; If you like, you can change the names for your devices. These names are
; reflected in the tooltips.
MouseName = Mouse
PadName = Touch Pad

; ------------------------------------------------------------
; SCRIPT SETTINGS - YOU SHOULDN'T NEED TO CHANGE ANYTHING BELOW THIS LINE.

If !TrayIcon
	Menu, Tray, NoIcon

; Constants
; Read more at the following:
; http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/systemparametersinfo.asp
; http://www.pinvoke.net/search.aspx?search=SPI&namespace=%5BAll%5D
SPI_GETMOUSE =		0x0003
SPI_SETMOUSE =		0x0004
SPI_GETMOUSESPEED =	0x0070
SPI_SETMOUSESPEED =	0x0071

; Watch for hardware changes
OnMessage(0x219, "HardwareUpdate")

; Check whether or not the mouse exists to begin with and make sure the pointer
; settings match.
	Gosub, MouseCheck
	Gosub, ChangeSettings
	If !MousePresent and !FileExist(PadIcon) and FileExist(MouseIcon)
		Menu, Tray, Icon, %MouseIcon%, %MouseIconGroup%
	MouseLast = %MousePresent%
	ToolTip, Pointer Settings Set To: %CurrentName%
	Sleep, 2000
	ToolTip
	Return


Exit ; Everything above this line is run when the script is loaded.


; ============================================================
; FUNCTIONS & SUBROUTINES
; ============================================================

HardwareUpdate()
{
	Global MouseLast
	Global MousePresent
	Global CurrentName
	Gosub, MouseCheck
	; We might get phantom hardware-change messages, so make sure the status
	; of the mouse has actually changed before changing any settings.
	If MousePresent = %MouseLast%
		Exit
	Else
	{
		Gosub, ChangeSettings
		MouseLast = %MousePresent%	; Update mouse status.
		ToolTip, Pointer Settings Changed To: %CurrentName%
		Sleep, 2000
		ToolTip
	}
	Return
}

MouseCheck:
	MousePresent = 0
	Sleep, 1000	; Give the registry a moment to update.
	Loop, HKEY_LOCAL_MACHINE, SYSTEM\CurrentControlSet\Services\Mouclass\Enum, 0, 0
	{
		RegRead, CurrentValue
		IfInString, CurrentValue, %MouseID%
		{
			MousePresent = 1
			Break	; Don't check any more values.
		}
	}
	Return

ChangeSettings:
	If MousePresent
	{
		CurrentName = %MouseName%
		DeviceSpeed = %MouseSpeed%
		DeviceEnhance = %MouseEnhance%
		DeviceThreshold1 = %MouseThreshold1%
		DeviceThreshold2 = %MouseThreshold2%
		If TrayIcon and FileExist(MouseIcon)
			Menu, Tray, Icon, %MouseIcon%, %MouseIconGroup%
		Menu, Tray, Tip, Current Pointer Settings: %CurrentName%
	}
	Else
	{
		CurrentName = %PadName%
		DeviceSpeed = %PadSpeed%
		DeviceEnhance = %PadEnhance%
		DeviceThreshold1 = %PadThreshold1%
		DeviceThreshold2 = %PadThreshold2%
		If TrayIcon and FileExist(PadIcon)
			Menu, Tray, Icon, %PadIcon%, %PadIconGroup%
		Menu, Tray, Tip, Current Pointer Settings: %CurrentName%
	}

	VarSetCapacity(DeviceArray, 12, 0)
	InsertInteger(DeviceThreshold1, DeviceArray, 0)	; Reg. Value MouseThreshold1
	InsertInteger(DeviceThreshold2, DeviceArray, 4)	; Reg. Value MouseThreshold2
	InsertInteger(DeviceEnhance, DeviceArray, 8)		; Reg. Value MouseSpeed

	InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
	; The caller must ensure that pDest has sufficient capacity.  To preserve any existing contents in pDest,
	; only pSize number of bytes starting at pOffset are altered in it.
	{
		Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
			DllCall("RtlFillMemory", "UInt", &pDest + pOffset + A_Index-1, "UInt", 1, "UChar", pInteger >> 8*(A_Index-1) & 0xFF)
	}

	; Keep this here for future reference.
	; DllCall("SystemParametersInfo", UInt, SPI_GETMOUSESPEED, UInt, 0, UIntP, SpeedCurrent, UInt, 0)

	; Change the pointer speed.
	DllCall("SystemParametersInfo", UInt, SPI_SETMOUSESPEED, UInt, 0, UInt, DeviceSpeed, UInt, 1)
	; Change the pointer precision settings.
	DllCall("SystemParametersInfo", UInt, SPI_SETMOUSE, UInt, 0, Str, DeviceArray, UInt, 1)
	Return


HappyGuest
  • Guests
  • Last active:
  • Joined: --
Thank you very much Wesley this was exactly what I looked for :)

cactus
  • Guests
  • Last active:
  • Joined: --
Wesley,

I tried the script, but I think it's always thinking I have a mouse hooked up. I'm using the "thinkoutside" stowaway travel mouse (bluetooth). In my registry, the HID is always there, in the same entry as the bluetooth mouse.

Can you help me?

Thanks,
Greg

cactus
  • Members
  • 1 posts
  • Last active: Jul 21 2007 05:08 AM
  • Joined: 21 Jul 2007
I didn't have my account yet. Sorry for the double post, but I just wanted to make sure I was notified if there were replies.

Thanks,
Greg

  • Guests
  • Last active:
  • Joined: --
Sorry to ressurect a dead thread but I have a question relevent to this conversation, and I'm hoping you guys can help. I use mouse accel in Windows XP. I have noticed a bug I want to fix. With a ps/2 mouse, mouse accel works perfectly for me. But with a USB mouse, mouse accel is buggy. When you move the mouse very slightly to the left and down, it will only go left. It doesn't register the down movement unless you move it faster. Thanks.