Тема: AHK: Дополнительные кнопки USB устройств через HID-протокол
Став обладателем мышки "World of Warcraft® Cataclysm MMO Gaming Mouse",
столкнулся с проблемой программного обеспечения для нее, оно конечно есть,
но точно не соответствует названию "... Gaming Mouse", мало функциональное и не корректно работающее.
Альтернативных программ не нашел. Программы типа Mkey, KeyMan хоть и работаю с HID-протоколом, но тоже не подходят.
Так вот, изучив темы по AHK мной был составлен скрипт:
#NoEnv
SetKeyDelay, 61 ;задержка между нажатиями клавиш
SetMouseDelay, 61 ;задержка между нажатиями мыши
k:=0 ;Задается переменная для счета в части для чередования нажатий
But:=0x0000 ;Задается переменная счета нажатых клавиш, для возможности определения отжатия клавиши
ButAll:=0x0000 ;Задается переменная для суммы счета нажатых клавиш, для возможности определения отжатия клавиши
;////
; Задаются значения соответствующие отдельно нажатой кнопки устройства, для подсчета нажатий
Butk1:=0x0001
Butk2:=0x0100
Butk3:=0x0200
Butk4:=0x0400
Butk5:=0x0800
Butk6:=0x1000
Butk7:=0x2000
Butk8:=0x4000
Butk9:=0x8000
;////
DetectHiddenWindows, On
Process, Exist
hwnd := WinExist("ahk_class AutoHotkey ahk_pid " ErrorLevel)
DetectHiddenWindows, Off
OnMessage(0xFF, "WM_INPUT")
;////
;Данные HID устройства, можно взять из скрипта "AutoHotkeyRemoteControlDLL", требуется библиотека "AutohotkeyRemoteControl.dll"
Usage = 1
UsagePage = 65280
;////
;////
;Дальше взято из подобных программ, так что корректно описать действия не могу, далек до программиста
VarSetCapacity(dev, 12, 0)
NumPut(UsagePage, dev, 0, "UShort")
NumPut(Usage, dev, 2, "UShort")
NumPut(0x100, dev, 4) ; dwFlags = RIDEV_INPUTSINK (don't require foreground)
NumPut(hwnd, dev, 8)
ret := DllCall("RegisterRawInputDevices"
, "uint", &dev ; pRawInputDevices (pointer to an array of RAWINPUTDEVICE)
, "uint", 1 ; uiNumDevices
, "uint", 12) ; cbSize (size of a RAWINPUTDEVICE structure)
if (ErrorLevel or !ret) {
; MsgBox, RegisterRawInputDevices failed.
ExitApp
}
WM_INPUT(wParam, lParam)
{
Critical
; Get required buffer size.
DllCall("GetRawInputData", "uint", lParam, "uint", 0x10000003
, "uint", 0, "uint*", size, "uint", 16)
VarSetCapacity(raw, size, 0)
; Get raw input data from handle (lParam)
ret := DllCall("GetRawInputData", "uint", lParam, "uint", 0x10000003
, "uint", &raw, "uint*", size, "uint", 16, "int")
if (ErrorLevel or ret = -1) {
; MsgBox, Ошибка получения данных
return
}
SetFormat, INTEGER, H
count := NumGet(raw, 20) ; dwCount
n = 0
Loop, %count%
{
size := NumGet(raw, 16) ; dwSizeHid
VarSetCapacity(hex, size*3)
Loop, %size%
{
char := SubStr(NumGet(raw, 24+n+A_Index-1, "UChar"), 3)
StringUpper, char, char
if (StrLen(char) < 2)
char = 0%char%
hex = %hex%%char%
}
n += size
if !size
hex = "--"
;////
Cod1 := SubStr(hex, 3 , 4) ;Вырезается часть получаемого кода, достаточную для просчета клавиш,
;тут можно вырезать и другую информацию, соответствующую какой либо функции,
;например переключение профилей (аля мыши A-TECH серии XL)
Cod1 = 0x%Cod1% ;делаем символьную строку числовой, формата Hex
; Задаются значения соответствующие отдельно нажатой кнопки устройства, для вычисления нажатой кнопки или комбинации кнопок
k1:=0x0001
k2:=0x0100
k3:=0x0200
k4:=0x0400
k5:=0x0800
k6:=0x1000
k7:=0x2000
k8:=0x4000
k9:=0x8000
; Тут, что придумал, то придумал для вычисления нажатий, вроде работает нормально
if Cod1 = 0
gosub nol
if (Cod1-k9) >= 0
gosub kk9
else Cod1:=Cod1+k9
if (Cod1-(k9+k8)) >=0
gosub kk8
else Cod1:=Cod1+k8
if (Cod1-(k9+k8+k7)) >= 0
gosub kk7
else Cod1:=Cod1+k7
if (Cod1-(k9+k8+k7+k6)) >= 0
gosub kk6
else Cod1:=Cod1+k6
if (Cod1-(k9+k8+k7+k6+k5)) >= 0
gosub kk5
else Cod1:=Cod1+k5
if (Cod1-(k9+k8+k7+k6+k5+k4)) >= 0
gosub kk4
else Cod1:=Cod1+k4
if (Cod1-(k9+k8+k7+k6+k5+k4+k3)) >= 0
gosub kk3
else Cod1:=Cod1+k3
if (Cod1-(k9+k8+k7+k6+k5+k4+k3+k2)) >= 0
gosub kk2
else Cod1:=Cod1+k2
if (Cod1-(k9+k8+k7+k6+k5+k4+k3+k2+k1)) >= 0
gosub kk1
else Cod1:=Cod1+k1
; Ссылки на исполнение команд при нажатии
gosub kkk9 ;Клавиша 5
gosub kkk8 ;Клавиша 4
gosub kkk7 ;Клавиша 13
gosub kkk6 ;Клавиша 14
gosub kkk5 ;Клавиша 12
gosub kkk4 ;Клавиша 10
gosub kkk3 ;Клавиша 11
gosub kkk2 ;Клавиша 7
gosub kkk1 ;Клавиша 6
gosub nol1 ;ссылка на присвоение суммы нажатых клавиш и обнуления их счета
;это для возможности определения отжатия клавиш
}
}
return
;////
;Эта часть считает сумму нажатых кнопок, почему так, в цикле выше происходит сброс получаемых данных при каждом последующем исполнении
;и их сравнение с предыдущими данными не получается
nol1:
ButAll:=But
But=0x0000
return
nol:
But=0x0000
ButAll=0x0000
return
kk9:
But:=But+Butk9
return
kk8:
But:=But+Butk8
return
kk7:
But:=But+Butk7
return
kk6:
But:=But+Butk6
return
kk5:
But:=But+Butk5
return
kk4:
But:=But+Butk4
return
kk3:
But:=But+Butk3
return
kk2:
But:=But+Butk2
return
kk1:
But:=But+Butk1
return
;////
;////
;Тут сами действия для конкретной клавиши
kkk9:
if But-ButAll=Butk9
Send , {Numpad6}
return
kkk8:
if But-ButAll=Butk8
{
Send {Numpad5}
}
return
kkk7:
if But-ButAll=Butk7
Send , !^8
return
kkk6:
if But-ButAll=Butk6
Send , {Numpad8}
return
kkk5:
if But-ButAll=Butk5
{
if k=0
{
Send {NumpadMult}
k=1
SetTimer, Counter5, 3000
}
else
{
if k=1
{
Send {NumpadDiv}
k=0
SetTimer, Counter5, off
}
}
}
return
return
Counter5:
k=0
return
kkk4:
if But-ButAll=Butk4
{
Send , {Numpad9}
}
return
kkk3:
if But-ButAll=Butk3
{
Send , {Numpad0}
}
return
kkk2:
if But-ButAll=Butk2
Send {Numpad7}
return
kkk1:
if But-ButAll=Butk1
{
Send , {Numpad4}
}
return
MButton::
Send {Numpad3}
return
WheelUp::
send {Numpad1}
return
WheelDown::
send {Numpad2}
return
XButton1::
KeyWait, XButton1, D
Send {Space Down}
KeyWait, XButton1, U
Send {Space Up}
return
XButton2::
KeyWait, XButton2, D
SetTimer, CounterX2, 50
KeyWait, XButton2, U
SetTimer, CounterX2, off
return
CounterX2:
Send , {F12}
return
;////
CapsLock::Suspend
;///// Пример нажатия и отжатия кнопки
;kkk9:
; if But-ButAll=Butk9
; {
; Send {Numpad5 Down}
; }
; if ButAll-But=Butk9 or But=0
; Send {Numpad5 Up}
; return
; /////
;///// Пример цикличного нажатия при удержании кнопки
;kkk9:
; if But-ButAll=Butk9
; {
; SetTimer, Counter9, 200
; }
; if ButAll-But=Butk9 or But=0
; SetTimer, Counter9, off
; return
;Counter9:
; Send {Numpad5}
;return
;/////
;///// Пример при первом нажатии кномпки происходит нажатие Num7,
; при повторном нажатии кнопки, в течении 2 сек, происходит нажатие Num1 и дальнейшее чередование,
; после 2 сек, без нажатия, происходит снова первое нажатие Num7
;kkk9:
;if But-ButAll=Butk9
; {
; if k=0
; {
; Send {Numpad7}
; k=1
; SetTimer, Counter9, 2000
; }
; else
; {
; if k=1
; {
; Send {Numpad1}
; k=0
; SetTimer, Counter9, off
; }
; }
; }
;return
;return
;
;Counter9:
;k=0
;return
;/////
;///// Пример первым нажатием включается скрипт, повторным нажатием отключается
;kkk9:
; if But-ButAll=Butk9
; {
; if k=0
; {
; k=1
; SetTimer, Counter9, 500
; }
; else
; {
; if k=1
; {
; k=0
; SetTimer, Counter9, off
; }
; }
; }
;return
;return
;
;Counter9:
;Send , 9
;return
;/////
;XButton1::
; {
; Send {Space Down}
; SetTimer, CounterX, 32
; }
;return
;CounterX:
;Send {Space Up}
;SetTimer, CounterX, off
;returnСкрип вроде работает нормально, но при исполнении данной части скрипта,
;///// Пример цикличного нажатия при удержании кнопки
;kkk9:
; if But-ButAll=Butk9
; {
; SetTimer, Counter9, 200
; }
; if ButAll-But=Butk9 or But=0
; SetTimer, Counter9, off
; return
;Counter9:
; Send {Numpad5}
;return
;////для циклического нажатия Numpad5 при удержании нажатой кнопки устройства,
а при отпускании кнопки устройства - остановка, происходит не понятное.
Может и корректно работать, а может происходить "залипание" и при отжатии, остановка не происходит.
Вот тут и загвоздка. Подскажите как это можно решить эту проблему.
Приветствуются решения для возможности усовершенствования данного скрипта, желательно с пояснениями.

