1 (изменено: sabir.yanin2014, 2017-12-28 06:53:57)

Тема: AHK:Умная мышь или да здравствует хэдшот!

Известно что для более точного прицеливания нужно устанавливать меньшее DPI. С другой стороны при низком DPI перемещение курсора затратное(трудное) и становится сложно попадать по движущимся целям так как тупо не успеваешь за целью. Я постарался для себя игровой процесс сделать комфортным и за одно улучшить свои игровые достижения. Данный скрипт позволяет модифицировать мышь и сделать управление более гибким и удобным(эффективным). Что мне не нравилось в базовом интерфейсе(и что я устранил для себя):
1)Во время прицеливания чувствительность камеры в играх меняется слабо, не так как хотелось бы (претензии к разработчикам игр).
2)Первый пункт хотелось бы решить аппаратным способом, а именно изменяя настройки мыши(было бы хорошо если бы при нажатии ПКМ или даже клавиатуры чувствительность мыши снижалась требуемым образом -но таких мышей я не видел/претензии к разработчикам мышей).
3)Даже если бы и был возможен второй пункт то снижение чувствительности не решает проблему точного прицеливания так как в играх нужно стрелять по движущимся целям. А это сложно при низкой скорости мыши.Парадокс.
Наблюдая за собой я увидел что прицеливание я осуществляю в два этапа: 1)Приблизительное(быстрое) прицеливание;2)"Доцеливание"-точное прицеливание. Во время первого этапа мышь перемещается по коврику значительно -изменяя свое положение. Во время второго этапа мышь замирает и либо смещается незначительно либо вообще не двигается когда ловишь прицел с помощью WASD. Тут меня и осенило: что если скрипт сам будет проводить статистику поведения мыши и будет сам вычислять второй этап-для которого автоматически будет выбрано низкое DPI. Так мой код изменяет базовое значение DPI=800 на 400 во время прицеливания и позволяет ускорить мышь (DPI=800) при стрельбе по быстрым целям. Алгоритм следующий: в режиме прицеливания если мышь я смещаю слабо (DPI=400), если я ускоряю мышь выше заданного порога (хочу догнать цель) мышь ускоряется (DPI=800).После того как я обгоняю цель(упреждение) наступает второй этап -мышь замирает(DPI снова снижается до 400).Все -завершаю прицеливание и стреляю.
На англоязычном сайте нашел код который корректно измеряет движения мыши в играх.Он фиксирует пакеты которые формирует мышь и которые в итоге смещают камеру (MouseGetPos в играх работает неправильно).Немного доработал его.
Здесь нужно обратить внимание: что при использовании скрипта частоту опроса мыши нужно выставлять на минимум: так для моей мыши по умолчанию стоит 1000Гц -пакеты получаются маленькие, я выставил 125Гц -скрипт начал работать.
Код разбит на две части основной файл и подгружаемый "MouseDelta.ahk" который нужно расположить в директории основного.
Основной:


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                      --Умная мышь--                  ;;;
;;;                  EasyHard, 29/11/2017г.              ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SMX:=OldSMX:=SMY:=OldSMY:=DSX:=DSY:=0
#SingleInstance force
#Persistent
#include MouseDelta.ahk
md:=new MouseDelta("MouseEvent").Start()
md.SetState(0)
SetTimer, SpeedMouse, 100


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;   Вычисление скорости перемещения физической мыши    ;;;
;;;    /автоматический выбор режима(авт.смена DPI)       ;;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SpeedMouse:
DSX:=abs(OldSMX-SMX),OldSMX:=SMX,DSY:=abs(OldSMY-SMY),OldSMY:=SMY
if (DSX>30 or DSY>30) ;настраиваемые параметры-можно поэкспериментировать
Focus:=0 ;"быстрая мышь"-"режим-упреждение"-DPI базовый(настройка чувств.мыши/у меня 800DPI)
else 
Focus:=1 ;"точная мышь"-"режим-прицеливание"-измененный DPI(800/2=400)
Return 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;         ПКМ-Включение режима прицеливания        ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
*RButton::md.SetState(1)
*RButton up::md.SetState(0)

End::ExitApp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;         Мышь-Регулирование скорости обзора       ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MouseEvent(MouseID, x := 0, y := 0){
global SMX,SMY,Focus
	if (MouseID)
	{
	SMX+=x,SMY+=y
	if Focus
		{
		ShiftX:=x//2,ShiftY:=y//2
		DllCall("mouse_event",uint,1,int,-ShiftX,int,-ShiftY,uint,0,int,0)
		}
	}
}

MouseDelta.ahk:



; Instantiate this class and pass it a func name or a Function Object
; The specified function will be called with the delta move for the X and Y axes
; Normally, there is no windows message "mouse stopped", so one is simulated.
; After 10ms of no mouse movement, the callback is called with 0 for X and Y
Class MouseDelta {
	State := 0
	__New(callback){
		;~ this.TimeoutFn := this.TimeoutFunc.Bind(this)
		this.MouseMovedFn := this.MouseMoved.Bind(this)

		this.Callback := callback
	}

	Start(){
		static DevSize := 8 + A_PtrSize, RIDEV_INPUTSINK := 0x00000100
		; Register mouse for WM_INPUT messages.
		VarSetCapacity(RAWINPUTDEVICE, DevSize)
		NumPut(1, RAWINPUTDEVICE, 0, "UShort")
		NumPut(2, RAWINPUTDEVICE, 2, "UShort")
		NumPut(RIDEV_INPUTSINK, RAWINPUTDEVICE, 4, "Uint")
		; WM_INPUT needs a hwnd to route to, so get the hwnd of the AHK Gui.
		; It doesn't matter if the GUI is showing, it still exists
		Gui +hwndhwnd
		NumPut(hwnd, RAWINPUTDEVICE, 8, "Uint")
 
		this.RAWINPUTDEVICE := RAWINPUTDEVICE
		DllCall("RegisterRawInputDevices", "Ptr", &RAWINPUTDEVICE, "UInt", 1, "UInt", DevSize )
		OnMessage(0x00FF, this.MouseMovedFn)
		this.State := 1
		return this	; allow chaining
	}
	
	Stop(){
		static RIDEV_REMOVE := 0x00000001
		static DevSize := 8 + A_PtrSize
		OnMessage(0x00FF, this.MouseMovedFn, 0)
		RAWINPUTDEVICE := this.RAWINPUTDEVICE
		NumPut(RIDEV_REMOVE, RAWINPUTDEVICE, 4, "Uint")
		DllCall("RegisterRawInputDevices", "Ptr", &RAWINPUTDEVICE, "UInt", 1, "UInt", DevSize )
		this.State := 0
		return this	; allow chaining
	}
	
	SetState(state){
		if (state && !this.State)
			this.Start()
		else if (!state && this.State)
			this.Stop()
		return this	; allow chaining
	}

	Delete(){
		this.Stop()
		;~ this.TimeoutFn := ""
		this.MouseMovedFn := ""
	}
	
	; Called when the mouse moved.
	; Messages tend to contain small (+/- 1) movements, and happen frequently (~20ms)
	MouseMoved(wParam, lParam){
		Critical
		; RawInput statics
		static DeviceSize := 2 * A_PtrSize, iSize := 0, sz := 0, pcbSize:=8+2*A_PtrSize, offsets := {x: (20+A_PtrSize*2), y: (24+A_PtrSize*2)}, uRawInput
 
		static axes := {x: 1, y: 2}
 
		; Get hDevice from RAWINPUTHEADER to identify which mouse this data came from
		VarSetCapacity(header, pcbSize, 0)
		If (!DllCall("GetRawInputData", "UPtr", lParam, "uint", 0x10000005, "UPtr", &header, "Uint*", pcbSize, "Uint", pcbSize) or ErrorLevel)
			Return 0
		ThisMouse := NumGet(header, 8, "UPtr")

		; Find size of rawinput data - only needs to be run the first time.
		if (!iSize){
			r := DllCall("GetRawInputData", "UInt", lParam, "UInt", 0x10000003, "Ptr", 0, "UInt*", iSize, "UInt", 8 + (A_PtrSize * 2))
			VarSetCapacity(uRawInput, iSize)
		}
		sz := iSize	; param gets overwritten with # of bytes output, so preserve iSize
		; Get RawInput data
		r := DllCall("GetRawInputData", "UInt", lParam, "UInt", 0x10000003, "Ptr", &uRawInput, "UInt*", sz, "UInt", 8 + (A_PtrSize * 2))
 
		x := 0, y := 0	; Ensure we always report a number for an axis. Needed?
		x := NumGet(&uRawInput, offsets.x, "Int")
		y := NumGet(&uRawInput, offsets.y, "Int")
 
		this.Callback.(ThisMouse, x, y)
 
		;~ ; There is no message for "Stopped", so simulate one
		;~ fn := this.TimeoutFn
		;~ SetTimer, % fn, -50
	}
 
	;~ TimeoutFunc(){
		;~ this.Callback.("", 0, 0)
	;~ }
 
}

2

Re: AHK:Умная мышь или да здравствует хэдшот!

Под какую игру делался скрипт?

3

Re: AHK:Умная мышь или да здравствует хэдшот!

Dworkin пишет:

Под какую игру делался скрипт?

Непринципиально, под любую.

4

Re: AHK:Умная мышь или да здравствует хэдшот!

Проверить можно в тире. Я проверял в The Evil Within 2. Результат на 2000 больше набил чем без скрипта.

5

Re: AHK:Умная мышь или да здравствует хэдшот!

Извините за вопрос, но какие переменные в скрипте отвечают за величину автозамедления и порог когда оно срабатывает. Неплохо бы сделать скрипт настраиваемым, прикрутить гуи я могу, но прочитать и понять код, моих познаний не хватает. Замедление по нажатию правой кнопки заметно, а вот автосмена DPI чето совсем не чувствуется.

6

Re: AHK:Умная мышь или да здравствует хэдшот!

Dimaryo, я же закомментировал: "настраиваемые параметры" в данном случае 30.
Фрагмент кода:


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;   Вычисление скорости перемещения физической мыши    ;;;
;;;    /автоматический выбор режима(авт.смена DPI)       ;;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SpeedMouse:
DSX:=abs(OldSMX-SMX),OldSMX:=SMX,DSY:=abs(OldSMY-SMY),OldSMY:=SMY
if (DSX>30 or DSY>30) ;настраиваемые параметры-можно поэкспериментировать
Focus:=0 ;"быстрая мышь"-"режим-упреждение"-DPI базовый(настройка чувств.мыши/у меня 800DPI)
else 
Focus:=1 ;"точная мышь"-"режим-прицеливание"-измененный DPI(800/2=400)
....


Если вы хотите увеличить "чувствительность" скрипта нужно уменьшить величину порога. Смысл: скрипт через каждые 100 мс проверяет на сколько сместилась физическая мышь. Условно говоря 30 это пороговая скорость мыши 30пкс/100мс. Если вместо 30 выставить 10 то мышь будет "срываться" -ускоряться до 800 DPI при меньшем смещении мыши. Если выставить 60 то мышь станет более "грубая" т.е. чтобы включить автоускорение нужно сильно и быстро сместить мышь. Поэтому экспериментируйте -меняйте оба параметра так: "if (DSX>60 or DSY>60)".
И снизьте частоту опроса мыши на минимум.

7 (изменено: sabir.yanin2014, 2017-12-28 07:00:38)

Re: AHK:Умная мышь или да здравствует хэдшот!

Dimaryo, возможно вы были правы и мой код у вас не работал. Я отредактировал скрипт и вы можете проверить.
Нужно было в начале кода обнулить переменные.

8 (изменено: sabir.yanin2014, 2017-12-28 07:30:20)

Re: AHK:Умная мышь или да здравствует хэдшот!

Мышь-Джойстик

Возникла идея превратить мышь в "джойстик": при нажатии ключевой клавиши-блокировать камеру, а на смещение мыши реагировать нажатием клавиши. Таким образом получается аналог джойстика с четырьмя направлениями которые можно "забиндить" под четыре клавиши:


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                     -Мышь-Джойстик-                  ;;;
;;;                  EasyHard, 28/12/2017г.              ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SMX:=OldSMX:=SMY:=OldSMY:=DSX:=DSY:=0
#SingleInstance force
#Persistent
#include MouseDelta.ahk
md:=new MouseDelta("MouseEvent").Start()
md.SetState(0)
SetTimer, SpeedMouse, 100


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;                Мышь-режим джойстика              ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SpeedMouse:
DSX:=SMX-OldSMX,OldSMX:=SMX,DSY:=SMY-OldSMY,OldSMY:=SMY
if (DSX>50) ;смещение вправо
send {vk33}
if (DSX<-50) ;смещение влево
send {vk31}
if (DSY>50) ;смещение вниз
send {vk34}
if (DSY<-50) ;смещение вверх
send {vk32}
Return 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;          Пробел-Включение мыши-джойстика         ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
*Space::md.SetState(1)
*Space up::md.SetState(0)

End::ExitApp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;               Мышь-блокировка камеры             ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MouseEvent(MouseID, x := 0, y := 0){
global SMX,SMY
	if (MouseID)
	{
	SMX+=x,SMY+=y
	DllCall("mouse_event",uint,1,int,-x,int,-y,uint,0,int,0)
	}
}

В этом коде частота опроса мыши роли почти не играет, но мышь работает лучше (меньше смещение камеры во время блокировки) на частоте 1000Гц. Здесь также нужен в директории скрипта файл MouseDelta.ahk.

9

Re: AHK:Умная мышь или да здравствует хэдшот!

Мышь-джойстик
Вот рабочий вариант предыдущего кода:

 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                     -Мышь-Джойстик-                  ;;;
;;;                  EasyHard, 28/12/2017г.              ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SMX:=OldSMX:=SMY:=OldSMY:=DSX:=DSY:=0
#SingleInstance force
#Persistent
#include MouseDelta.ahk
md:=new MouseDelta("MouseEvent").Start()
md.SetState(0)
SetTimer, SpeedMouse, 100


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;                Мышь-режим джойстика              ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SpeedMouse:
DSX:=SMX-OldSMX,OldSMX:=SMX,DSY:=SMY-OldSMY,OldSMY:=SMY
if (DSX>50)
{
send {e down}
SetTimer, SpeedMouse, Off
SetTimer, Right1, -50
}

if (DSX<-50)
{
send {q down}
SetTimer, SpeedMouse, Off
SetTimer, Left1, -50
}

if (DSY>50)
{
send {s down}
SetTimer, SpeedMouse, Off
SetTimer, Down1, -50
}

if (DSY<-50)
{
send {w down}
SetTimer, SpeedMouse, Off
SetTimer, Up1, -50
}
Return 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;                        Метки                     ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Right1:
send {e up}
SetTimer, Right2, -250
Return 
Right2: 
OldSMX:=SMX
SetTimer, SpeedMouse, On
Return  

Left1:
send {q up}
SetTimer, Left2, -250
Return 
Left2: 
OldSMX:=SMX
SetTimer, SpeedMouse, On
Return  

Down1:
send {s up}
SetTimer, Down2, -250
Return 
Down2: 
OldSMY:=SMY
SetTimer, SpeedMouse, On
Return

Up1:
send {w up}
SetTimer, Up2, -250
Return 
Up2: 
OldSMY:=SMY
SetTimer, SpeedMouse, On
Return   
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;              Включение мыши-джойстика            ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
*x::
send {LAlt Down}
md.SetState(1)
Return 
*x up::
send {LAlt Up}
md.SetState(0)
Return 

End::ExitApp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;               Мышь-блокировка камеры             ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MouseEvent(MouseID, x := 0, y := 0){
global SMX,SMY
	if (MouseID)
	{
	SMX+=x,SMY+=y
	DllCall("mouse_event",uint,1,int,-x,int,-y,uint,0,int,0)
	}
}

10

Re: AHK:Умная мышь или да здравствует хэдшот!

Моя древняя мышь не поддерживает почему-то деление DPI, за то прекрасно умножает его. sabir.yanin2014 Немного переделал твой скрипт, теперь он постоянно ускоряет мышь, а по нажатию кнопки, возвращает ей нормальную скорость. В итоге выкручиваю в игре чувствительность на минимум и настраиваю переменные скрипта под свои нужды, получается подобие SniperButton. Двойное нажатие LWin выключает данную ф-ию.


SMX:=OldSMX:=SMY:=OldSMY:=DSX:=DSY:=0
#SingleInstance force
#Persistent
#include MouseDelta.ahk
md:=new MouseDelta("MouseEvent").Start()
md.SetState(1)
SetTimer, SpeedMouse, 10

slow:=1		;Пониженная скорость(slow <= 1)
smid:=2.5 	;Средняя множитель скорости мыши
shig:=5 	;Повышенный множитель скорости мыши
sstand:=smid	;Постоянный множитель скорости мыши


Focus := 0
sp := sstand
LWin:: Gosub, PressCount            ; Запускается счётчик нажатий.

LWin(1):                            ; Код для одиночного нажатия LWin.
  Focus := 1
Return

LWin(2):                            ; Код для двойного нажатия LWin.
  Focus := 0
Return

XButton2:: sp := slow
XButton2 up:: sp := sstand

~LAlt:: sp := shig
~LAlt up:: sp := sstand

SpeedMouse:
DSX:=abs(OldSMX-SMX),OldSMX:=SMX
DSY:=abs(OldSMY-SMY),OldSMY:=SMY
Return
MouseEvent(MouseID, x := 0, y := 0){
global SMX,SMY,Focus,sp
	if (MouseID)
	{
	SMX+=x
	SMY+=y
	if Focus
		{
		ShiftX:=x*sp
		ShiftY:=y*sp
		DllCall("mouse_event",uint,1,int,ShiftX,int,ShiftY,uint,0,int,0)
		}
	}
}




PressCount:
  Pause_=200     ; Если пауза меньше этого количества миллисекунд, то нажатие
                 ; двойное. Если больше, то оно расценивается как 2 одиночных.
  If not Second
  {
    Second=1
    SetTimer, DoublePress, -%Pause_%
  }
  Else
  {
    Second=0
    SetTimer, %A_ThisHotkey%(2), -1
  }
Return

DoublePress:
  If not Second
    Return
  Second=0
  SetTimer, %A_ThisHotkey%(1), -1
Return

Insert::Reload
End::ExitApp

11 (изменено: sabir.yanin2014, 2018-01-02 16:04:08)

Re: AHK:Умная мышь или да здравствует хэдшот!

Yasen', в принципе так и было задумано автором. Но мне не понравилось умножение потому что картинка постоянно дергается-раздражает. При делении такое меньше происходит. Картинка плавнее, практически незаметно вмешательство. Я думаю все таки возможно мой код, незначительно переделав, приспособить под деление и на высоких частотах опроса мыши - для этого нужно формировать пакеты: суммировать их до тех пор пока не станет возможным деление.

12

Re: AHK:Умная мышь или да здравствует хэдшот!

Доработал код, теперь частоту опроса мыши можно не настраивать- работает с любой мышью.


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                      --Умная мышь--                  ;;;
;;;                  EasyHard, 21/12/2018г.              ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SMX:=OldSMX:=SMY:=OldSMY:=DSX:=DSY:=PacX:=PacY:=0
#SingleInstance force
#Persistent
#include MouseDelta.ahk
md:=new MouseDelta("MouseEvent").Start()
md.SetState(0)
SetTimer, SpeedMouse, 50

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;   Вычисление скорости перемещения физической мыши    ;;;
;;;    /автоматический выбор режима(авт.смена DPI)       ;;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SpeedMouse:
DSX:=abs(OldSMX-SMX),OldSMX:=SMX,DSY:=abs(OldSMY-SMY),OldSMY:=SMY
if (DSX>30 or DSY>30) ;настраиваемые параметры-можно поэкспериментировать
Focus:=0 ;"быстрая мышь"-"режим-упреждение"-DPI базовый(настройка чувств.мыши/у меня 800DPI)
else 
Focus:=1 ;"точная мышь"-"режим-прицеливание"-измененный DPI(800/2=400)
Return 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;         ПКМ-Включение режима прицеливания        ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
*RButton::md.SetState(1)
*RButton up::md.SetState(0)

End::ExitApp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;         Мышь-Регулирование скорости обзора       ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MouseEvent(MouseID, x := 0, y := 0){
global SMX,SMY,Focus,PacX,PacY
	if (MouseID)
	{
	SMX+=x,SMY+=y
	if Focus
	PacX+=x,PacY+=y
	else
	PacX:=0,PacY:=0
	if (Focus and abs(PacX)>=4)
		{
		ShiftX:=PacX//2
		DllCall("mouse_event",uint,1,int,-ShiftX,int,0,uint,0,int,0)
		PacX:=0
		}
	if (Focus and abs(PacY)>=4)
		{
		ShiftY:=PacY//2
		DllCall("mouse_event",uint,1,int,0,int,-ShiftY,uint,0,int,0)
		PacY:=0
		}
	}
}

13

Re: AHK:Умная мышь или да здравствует хэдшот!

Что интересно все тачпады ноутбуков работают по такому же алгоритму:
скорость курсора = скорости перемещения пальца в квадрате.
Причем там это все сделано на уровне драйверов и никак не регулируется.

14 (изменено: sabir.yanin2014, 2018-04-15 16:51:40)

Re: AHK:Умная мышь или да здравствует хэдшот!

Новый улучшенный код.
В основе лежит все та же идея - автоматический мониторинг активности мыши: при быстром перемещении мыши скрипт не вмешивается в её работу; при замедленном движении скрипт снижает чувствительность мыши что позволяет делать ее более точной. Данный код я настраивал на сайте, что позволило мне объективно увидеть эффективность кода: я набил на 7000 больше чем обычно.
Мышь стала более точной, и теперь я могу попадать в более мелкие цели. Базовая настройка DPI=800. В режиме фокуса этот параметр скрипт снижает до 400 (точная мышь).
В отличии от предыдущих версий кода режим прицеливания включается автоматически, а не при нажатии горячей клавиши (т.е. скрипт работает постоянно с момента запуска). Данный подход дает преимущества в играх где нет явного прицеливания например: "Prey" или  онлайн-игры ("Doom" и др.).


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                    --Умная мышь--                  ;;;
;;;                 Claus555, 15/04/2018г.             ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#Persistent
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;              Создание  таймера 7,8(мс)           ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ZX:=0
;приближение к таймеру 10 мс 
SetTimer, S1, 15 
loop {
++ZX
if (ZX=18720) 
Break   
}
SetTimer, S2, 15

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;                      MouseDelta                  ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PacX:=PacY:=SMX:=SMY:=0,ArrSMX:=[],ArrSMY:=[],Focus:=1
#include MouseDelta.ahk
md:=new MouseDelta("MouseEvent").Start()
md.SetState(1)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;              Мышь-Переключение фокуса            ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
S1:
S2:
ArrSMX.Push(SMX),ArrSMY.Push(SMY),SpTime:=40 ; 40*7,8 = 312мс-период расчета скорости
if (ArrSMX.Length()=SpTime and ArrSMY.Length()=SpTime){
DSX:=ArrSMX[SpTime]-ArrSMX[1],DSY:=ArrSMY[SpTime]-ArrSMY[1]
Speed:=sqrt(DSX*DSX+DSY*DSY)
ArrSMX.RemoveAt(1),ArrSMY.RemoveAt(1)
}
While if (ArrSMX.Length()>SpTime-1)
ArrSMX.RemoveAt(1)
While if (ArrSMY.Length()>SpTime-1)
ArrSMY.RemoveAt(1)

if (Speed>=50)
Focus:=0

START1:=(Speed<50)?1:0 ;пуск таймера
START:=T(D("START1"),"START",100) ;таймер 100мс
if (U("START") and Speed<50) ;если по оканчании 100мс скорость ниже 50
Focus:=1 ;мышь замедлилась-включить фокус

Return

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;         Мышь-Регулирование скорости обзора       ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MouseEvent(MouseID, x := 0, y := 0){
global SMX,SMY,Focus,PacX,PacY
	if (MouseID)
	{
	SMX+=x,SMY+=y
	if Focus
	PacX+=x,PacY+=y
	else
	PacX:=0,PacY:=0
	if (Focus and abs(PacX)>=2)
		{
		ShiftX:=PacX//2
		DllCall("mouse_event",uint,1,int,-ShiftX,int,0,uint,0,int,0)
		PacX:=0
		}
	if (Focus and abs(PacY)>=2)
		{
		ShiftY:=PacY//2
		DllCall("mouse_event",uint,1,int,0,int,-ShiftY,uint,0,int,0)
		PacY:=0
		}
	}
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;                    Срабатывание                  ;;;;                                                                                                                                                                                                                                      ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
D(X)
{
local Z
Z:=(%X%!=d%X% and %X%)?1:0,d%X%:=%X%
Return Z
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;                      Отпадание                   ;;;;                                                                                                                                                                                                                                      ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
U(X)
{
local Z
Z:=(%X%!=u%X% and u%X%)?1:0,u%X%:=%X%
Return Z
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;                       Таймер                     ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
T(X,Y,V)
{
global 
if (X and !T1%Y%)
T1%Y%:=1,T2%Y%:=A_TickCount

if (T2%Y%="" or A_TickCount-T2%Y%>=V)
T1%Y%:=0

Return T1%Y%
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;            Завершение работы скрипта             ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
End::ExitApp 

Код разбит на две части основной файл и подгружаемый "MouseDelta.ahk" который нужно расположить в директории основного.
"MouseDelta.ahk":



; Instantiate this class and pass it a func name or a Function Object
; The specified function will be called with the delta move for the X and Y axes
; Normally, there is no windows message "mouse stopped", so one is simulated.
; After 10ms of no mouse movement, the callback is called with 0 for X and Y
Class MouseDelta {
	State := 0
	__New(callback){
		;~ this.TimeoutFn := this.TimeoutFunc.Bind(this)
		this.MouseMovedFn := this.MouseMoved.Bind(this)

		this.Callback := callback
	}

	Start(){
		static DevSize := 8 + A_PtrSize, RIDEV_INPUTSINK := 0x00000100
		; Register mouse for WM_INPUT messages.
		VarSetCapacity(RAWINPUTDEVICE, DevSize)
		NumPut(1, RAWINPUTDEVICE, 0, "UShort")
		NumPut(2, RAWINPUTDEVICE, 2, "UShort")
		NumPut(RIDEV_INPUTSINK, RAWINPUTDEVICE, 4, "Uint")
		; WM_INPUT needs a hwnd to route to, so get the hwnd of the AHK Gui.
		; It doesn't matter if the GUI is showing, it still exists
		Gui +hwndhwnd
		NumPut(hwnd, RAWINPUTDEVICE, 8, "Uint")
 
		this.RAWINPUTDEVICE := RAWINPUTDEVICE
		DllCall("RegisterRawInputDevices", "Ptr", &RAWINPUTDEVICE, "UInt", 1, "UInt", DevSize )
		OnMessage(0x00FF, this.MouseMovedFn)
		this.State := 1
		return this	; allow chaining
	}
	
	Stop(){
		static RIDEV_REMOVE := 0x00000001
		static DevSize := 8 + A_PtrSize
		OnMessage(0x00FF, this.MouseMovedFn, 0)
		RAWINPUTDEVICE := this.RAWINPUTDEVICE
		NumPut(RIDEV_REMOVE, RAWINPUTDEVICE, 4, "Uint")
		DllCall("RegisterRawInputDevices", "Ptr", &RAWINPUTDEVICE, "UInt", 1, "UInt", DevSize )
		this.State := 0
		return this	; allow chaining
	}
	
	SetState(state){
		if (state && !this.State)
			this.Start()
		else if (!state && this.State)
			this.Stop()
		return this	; allow chaining
	}

	Delete(){
		this.Stop()
		;~ this.TimeoutFn := ""
		this.MouseMovedFn := ""
	}
	
	; Called when the mouse moved.
	; Messages tend to contain small (+/- 1) movements, and happen frequently (~20ms)
	MouseMoved(wParam, lParam){
		Critical
		; RawInput statics
		static DeviceSize := 2 * A_PtrSize, iSize := 0, sz := 0, pcbSize:=8+2*A_PtrSize, offsets := {x: (20+A_PtrSize*2), y: (24+A_PtrSize*2)}, uRawInput
 
		static axes := {x: 1, y: 2}
 
		; Get hDevice from RAWINPUTHEADER to identify which mouse this data came from
		VarSetCapacity(header, pcbSize, 0)
		If (!DllCall("GetRawInputData", "UPtr", lParam, "uint", 0x10000005, "UPtr", &header, "Uint*", pcbSize, "Uint", pcbSize) or ErrorLevel)
			Return 0
		ThisMouse := NumGet(header, 8, "UPtr")

		; Find size of rawinput data - only needs to be run the first time.
		if (!iSize){
			r := DllCall("GetRawInputData", "UInt", lParam, "UInt", 0x10000003, "Ptr", 0, "UInt*", iSize, "UInt", 8 + (A_PtrSize * 2))
			VarSetCapacity(uRawInput, iSize)
		}
		sz := iSize	; param gets overwritten with # of bytes output, so preserve iSize
		; Get RawInput data
		r := DllCall("GetRawInputData", "UInt", lParam, "UInt", 0x10000003, "Ptr", &uRawInput, "UInt*", sz, "UInt", 8 + (A_PtrSize * 2))
 
		x := 0, y := 0	; Ensure we always report a number for an axis. Needed?
		x := NumGet(&uRawInput, offsets.x, "Int")
		y := NumGet(&uRawInput, offsets.y, "Int")
 
		this.Callback.(ThisMouse, x, y)
 
		;~ ; There is no message for "Stopped", so simulate one
		;~ fn := this.TimeoutFn
		;~ SetTimer, % fn, -50
	}
 
	;~ TimeoutFunc(){
		;~ this.Callback.("", 0, 0)
	;~ }
 
}

Для тех кто не знает что такое #include, вот полный код c "MouseDelta". Он работоспособен и не требует дополнительных файлов.


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                    --Умная мышь--                  ;;;
;;;                 Claus555, 15/04/2018г.             ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#Persistent
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;              Создание  таймера 7,8(мс)           ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ZX:=0
;приближение к таймеру 10 мс 
SetTimer, S1, 15 
loop {
++ZX
if (ZX=18720) 
Break   
}
SetTimer, S2, 15

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;                      MouseDelta                  ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PacX:=PacY:=SMX:=SMY:=0,ArrSMX:=[],ArrSMY:=[],Focus:=1

; Instantiate this class and pass it a func name or a Function Object
; The specified function will be called with the delta move for the X and Y axes
; Normally, there is no windows message "mouse stopped", so one is simulated.
; After 10ms of no mouse movement, the callback is called with 0 for X and Y
Class MouseDelta {
	State := 0
	__New(callback){
		;~ this.TimeoutFn := this.TimeoutFunc.Bind(this)
		this.MouseMovedFn := this.MouseMoved.Bind(this)

		this.Callback := callback
	}

	Start(){
		static DevSize := 8 + A_PtrSize, RIDEV_INPUTSINK := 0x00000100
		; Register mouse for WM_INPUT messages.
		VarSetCapacity(RAWINPUTDEVICE, DevSize)
		NumPut(1, RAWINPUTDEVICE, 0, "UShort")
		NumPut(2, RAWINPUTDEVICE, 2, "UShort")
		NumPut(RIDEV_INPUTSINK, RAWINPUTDEVICE, 4, "Uint")
		; WM_INPUT needs a hwnd to route to, so get the hwnd of the AHK Gui.
		; It doesn't matter if the GUI is showing, it still exists
		Gui +hwndhwnd
		NumPut(hwnd, RAWINPUTDEVICE, 8, "Uint")
 
		this.RAWINPUTDEVICE := RAWINPUTDEVICE
		DllCall("RegisterRawInputDevices", "Ptr", &RAWINPUTDEVICE, "UInt", 1, "UInt", DevSize )
		OnMessage(0x00FF, this.MouseMovedFn)
		this.State := 1
		return this	; allow chaining
	}
	
	Stop(){
		static RIDEV_REMOVE := 0x00000001
		static DevSize := 8 + A_PtrSize
		OnMessage(0x00FF, this.MouseMovedFn, 0)
		RAWINPUTDEVICE := this.RAWINPUTDEVICE
		NumPut(RIDEV_REMOVE, RAWINPUTDEVICE, 4, "Uint")
		DllCall("RegisterRawInputDevices", "Ptr", &RAWINPUTDEVICE, "UInt", 1, "UInt", DevSize )
		this.State := 0
		return this	; allow chaining
	}
	
	SetState(state){
		if (state && !this.State)
			this.Start()
		else if (!state && this.State)
			this.Stop()
		return this	; allow chaining
	}

	Delete(){
		this.Stop()
		;~ this.TimeoutFn := ""
		this.MouseMovedFn := ""
	}
	
	; Called when the mouse moved.
	; Messages tend to contain small (+/- 1) movements, and happen frequently (~20ms)
	MouseMoved(wParam, lParam){
		Critical
		; RawInput statics
		static DeviceSize := 2 * A_PtrSize, iSize := 0, sz := 0, pcbSize:=8+2*A_PtrSize, offsets := {x: (20+A_PtrSize*2), y: (24+A_PtrSize*2)}, uRawInput
 
		static axes := {x: 1, y: 2}
 
		; Get hDevice from RAWINPUTHEADER to identify which mouse this data came from
		VarSetCapacity(header, pcbSize, 0)
		If (!DllCall("GetRawInputData", "UPtr", lParam, "uint", 0x10000005, "UPtr", &header, "Uint*", pcbSize, "Uint", pcbSize) or ErrorLevel)
			Return 0
		ThisMouse := NumGet(header, 8, "UPtr")

		; Find size of rawinput data - only needs to be run the first time.
		if (!iSize){
			r := DllCall("GetRawInputData", "UInt", lParam, "UInt", 0x10000003, "Ptr", 0, "UInt*", iSize, "UInt", 8 + (A_PtrSize * 2))
			VarSetCapacity(uRawInput, iSize)
		}
		sz := iSize	; param gets overwritten with # of bytes output, so preserve iSize
		; Get RawInput data
		r := DllCall("GetRawInputData", "UInt", lParam, "UInt", 0x10000003, "Ptr", &uRawInput, "UInt*", sz, "UInt", 8 + (A_PtrSize * 2))
 
		x := 0, y := 0	; Ensure we always report a number for an axis. Needed?
		x := NumGet(&uRawInput, offsets.x, "Int")
		y := NumGet(&uRawInput, offsets.y, "Int")
 
		this.Callback.(ThisMouse, x, y)
 
		;~ ; There is no message for "Stopped", so simulate one
		;~ fn := this.TimeoutFn
		;~ SetTimer, % fn, -50
	}
 
	;~ TimeoutFunc(){
		;~ this.Callback.("", 0, 0)
	;~ }
 
}

md:=new MouseDelta("MouseEvent").Start()
md.SetState(1)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;              Мышь-Переключение фокуса            ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
S1:
S2:
ArrSMX.Push(SMX),ArrSMY.Push(SMY),SpTime:=40 ; 40*7,8 = 312мс-период расчета скорости
if (ArrSMX.Length()=SpTime and ArrSMY.Length()=SpTime){
DSX:=ArrSMX[SpTime]-ArrSMX[1],DSY:=ArrSMY[SpTime]-ArrSMY[1]
Speed:=sqrt(DSX*DSX+DSY*DSY)
ArrSMX.RemoveAt(1),ArrSMY.RemoveAt(1)
}
While if (ArrSMX.Length()>SpTime-1)
ArrSMX.RemoveAt(1)
While if (ArrSMY.Length()>SpTime-1)
ArrSMY.RemoveAt(1)

if (Speed>=50)
Focus:=0

START1:=(Speed<50)?1:0 ;пуск таймера
START:=T(D("START1"),"START",100) ;таймер 100мс
if (U("START") and Speed<50) ;если по оканчании 100мс скорость ниже 50
Focus:=1 ;мышь замедлилась-включить фокус

Return

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;         Мышь-Регулирование скорости обзора       ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MouseEvent(MouseID, x := 0, y := 0){
global SMX,SMY,Focus,PacX,PacY
	if (MouseID)
	{
	SMX+=x,SMY+=y
	if Focus
	PacX+=x,PacY+=y
	else
	PacX:=0,PacY:=0
	if (Focus and abs(PacX)>=2)
		{
		ShiftX:=PacX//2
		DllCall("mouse_event",uint,1,int,-ShiftX,int,0,uint,0,int,0)
		PacX:=0
		}
	if (Focus and abs(PacY)>=2)
		{
		ShiftY:=PacY//2
		DllCall("mouse_event",uint,1,int,0,int,-ShiftY,uint,0,int,0)
		PacY:=0
		}
	}
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;                    Срабатывание                  ;;;;                                                                                                                                                                                                                                      ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
D(X)
{
local Z
Z:=(%X%!=d%X% and %X%)?1:0,d%X%:=%X%
Return Z
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;                      Отпадание                   ;;;;                                                                                                                                                                                                                                      ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
U(X)
{
local Z
Z:=(%X%!=u%X% and u%X%)?1:0,u%X%:=%X%
Return Z
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;                       Таймер                     ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
T(X,Y,V)
{
global 
if (X and !T1%Y%)
T1%Y%:=1,T2%Y%:=A_TickCount

if (T2%Y%="" or A_TickCount-T2%Y%>=V)
T1%Y%:=0

Return T1%Y%
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;            Завершение работы скрипта             ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
End::ExitApp 

Пусть кто нибудь ответит. Интересно чужое мнение .

15 (изменено: Leone_Galante, 2018-04-17 21:22:00)

Re: AHK:Умная мышь или да здравствует хэдшот!

Очень интересная идея! Но боюсь моих знаний не хватит хотя бы попробовать данный скрипт.  Принцип понял, наверное )) попробую. По результатам отпишусь.

16

Re: AHK:Умная мышь или да здравствует хэдшот!

Потестил в игре, комфортней играть.

17

Re: AHK:Умная мышь или да здравствует хэдшот!

Скрипт очень полезен не только для игр, но и приятней попадать мышкой по кнопкам интерфеса страиниц, окон и тд. Как  еще больше уменьшить степень чувствительности при выцеливании?

18

Re: AHK:Умная мышь или да здравствует хэдшот!

Существует аналог - GGGlide - Mouse Pointer Momentum.