Тема: AHK: Замедление мыши
Мне было интересно найти код который помог бы мне в процессе игры облегчить прицеливание- а именно во время прицеливания снижать чувствительность мыши. Кто-то возразит мне что зачем изобретать велосипед, если на игровых девайсах уже предусмотрена возможность изменять DPI? Кому как удобно.
Для себя я придумал "внешний" способ переключения DPI, а именно-удерживая какую-то конкретную клавишу клавиатуры я уменьшаю чувствительность мыши, при отпускании клавиши чувствительность восстанавливается. Искал решения по этому вопросу на форуме, что-то похожее было:
F1::
SPI_GETMOUSESPEED = 0x70
SPI_SETMOUSESPEED = 0x71
; Retrieve the current speed so that it can be restored later:
DllCall("SystemParametersInfo", UInt, SPI_GETMOUSESPEED, UInt, 0, UIntP, OrigMouseSpeed, UInt, 0)
; Now set the mouse to the slower speed specified in the next-to-last parameter (the range is 1-20, 10 is default):
DllCall("SystemParametersInfo", UInt, SPI_SETMOUSESPEED, UInt, 0, UInt, 3, UInt, 0)
KeyWait F1 ; This prevents keyboard auto-repeat from doing the DllCall repeatedly.
return
F1 up::DllCall("SystemParametersInfo", UInt, 0x71, UInt, 0, UInt, OrigMouseSpeed, UInt, 0) ; Restore the original speed.
return
Но проблема в том что данный код не работает в играх!
Мое решение состояло в том чтобы по таймеру через период времени компенсировать 50% движения мыши (если мышь сдвинулась за период на 10 пикселей, то скрипт пусть вернет половину-5 пикселей назад. Таким способом я снижаю чувствительность вдвое).
Проще всего было бы использовать таймер, но оказалось что таймер не дает требуемую частоту опроса, так при заявленном 5 мс -
SetTimer, s1, 5 на деле таймер дает 15,6 мс. Это легко увидеть:
SetBatchLines -1
#Persistent
SetTimer, s1, 5
s1:
++DR
if (DR=100)
{
stop:=A_TickCount,DR:=0
dT:=(stop-start)/100
start:=A_TickCount
ToolTip, продолжительность периода=%dT%
}
Return
С такой низкой частотой мой код работал плохо, мышь перемещалась скачкообразно. Чтобы сделать эти скачки невидимыми глазу нужно увеличить частоту опроса. Оказывается есть способ снизить время периода но при этом нужно прибегнуть к DLL и отказаться от таймера.
SetBatchLines -1 ; Ensures maximum effectiveness of this method.
SleepDuration = 1 ; This can sometimes be finely adjusted (e.g. 2 is different than 3) depending on the value below.
TimePeriod = 3 ; Try 7 or 3. See comment below.
; On a PC whose sleep duration normally rounds up to 15.6 ms, try TimePeriod=7 to allow
; somewhat shorter sleeps, and try TimePeriod=3 or less to allow the shortest possible sleeps.
DllCall("Winmm\timeBeginPeriod", uint, TimePeriod) ; Affects all applications, not just this script's DllCall("Sleep"...), but does not affect SetTimer.
Iterations = 50
StartTime := A_TickCount
Loop %Iterations%
DllCall("Sleep", UInt, SleepDuration) ; Must use DllCall instead of the Sleep command.
DllCall("Winmm\timeEndPeriod", UInt, TimePeriod) ; Should be called to restore system to normal.
MsgBox % "Sleep duration = " . (A_TickCount - StartTime) / Iterations
Вот что у меня получилось:
SetBatchLines -1
SleepDuration:=1,TimePeriod:=3
DllCall("Winmm\timeBeginPeriod", uint, TimePeriod)
Loop
{
DllCall("Sleep", UInt, SleepDuration)
Gosub, s1
}
s1:
MouseGetPos, X, Y
if GetKeyState("n","P")
{
If (ABS(OldX-X)>=2)
dx:=Floor((OldX-X)/2)
else
dx:=0
If (ABS(OldY-Y)>=2)
dy:=Floor((OldY-Y)/2)
else
dy:=0
if (dx or dy)
DllCall("mouse_event", uint, 1, int, dx, int, dy, uint, 0, int, 0)
}
MouseGetPos, OldX, OldY
return
*n::Return
#Esc::
DllCall("Winmm\timeEndPeriod", UInt, TimePeriod)
ExitApp
При таком способе мне удалось снизить длительность периода до 0,9-1 мс. При нажатии клавиши N курсор замедляется и это справедливо не только в Windows но и в играх. Скачки практически незаметны. Я доволен, может кому-то тоже пригодится:).