Тема: AHK: Почему в моём скрипте иногда hotkey перестаёт работать?
Здравствуйте.
Наблюдаю проблему в своём скрипте, когда по какой-то причине hotkey перестаёт работать без видимых на то причин.
Весь скрипт состоит из инициализации, различных хоткеев, функций и меток.
Проблема происходит со вполне конкретными хоткеями, так что привожу только часть скрипта: инициализацию, проблемные хоткеи и одну используемую метку.
;{ Initialization
#SingleInstance, Force
#UseHook, On
SetWinDelay, 0
SendMode, Input ; Recommended For new scripts due to its superior speed and reliability.
#NoEnv ; Recommended For performance and compatibility with future AutoHotkey releases.
CoordMode, Mouse ; By default all coordinates are relative to the active window, changing them to be related to screen is required for proper work of some script's commands.
#MaxThreadsBuffer, Off
;{ Retrieve data from monitors.
SysGet, monCount, MonitorCount ; Retrieving the number of monitors.
Loop, %monCount%
{
SysGet, mon%A_Index%, Monitor, %A_Index% ; Retrieving monitors' positions data.
SysGet, UA%A_Index%, MonitorWorkArea, %A_Index% ; Getting Usable Area info.
; Defining variables' values for later use.
UA%A_Index%centerX := UA%A_Index%Left + (UA%A_Index%halfW := (UA%A_Index%Right - UA%A_Index%Left) / 2)
UA%A_Index%centerY := UA%A_Index%Top + (UA%A_Index%halfH := (UA%A_Index%Bottom - UA%A_Index%Top) / 2)
}
;}
; OnExit, Exit ; Remove hooks upon exit.
; Bind left click on tray icon to open menu like If you right clicked it.
Menu, Tray, Click, 1 ; Enable single click action on tray.
GoSub, AddMenu ; Add new default menu.
WS_CAPTION := 0xC00000
WS_SIZEBOX := 0x40000
Return
;}
;{ Scroll inactive windows without activating them
; Tab Wheel Scroll For Notepad++, Miranda IM (TabSRMM), AkelPad and Internet Explorer.
; Can't do the same For Google Chrome and Mozilla Firefox.
$WheelUp::
$WheelDown::
OutputDebug, % "A_ScriptName: '" A_ScriptName "' " "A_ThisHotkey: '" A_ThisHotkey "' start"
MouseGetPos, m_x, m_y, id, control, 1
If (A_PtrSize != 8) ; AHK is 32-bit.
hw_m_target := DllCall("WindowFromPoint", "Int", m_x, "Int", m_y)
Else ; AHK is 64-bit.
{
m_xy := ((m_y & 0xFFFFFFFF) << 32) | (m_x & 0xFFFFFFFF)
hw_m_target := DllCall("WindowFromPoint", "Int64", m_xy, "UPtr")
}
WinGetClass, class, ahk_id %id%
; WinGetClass, classA, A
WinGet, idA, ID, A
If (class == "Notepad++") && (control == "SysTabControl325") ; Notepad++: ahk_class Notepad++ tab-bar classNN: SysTabControl325 listener-window classNN: Scintilla1
{
OutputDebug, % "A_ScriptName: '" A_ScriptName "' " "A_ThisHotkey: '" A_ThisHotkey "' case: notepad++"
ControlGet, properTargetWin, Hwnd,, Scintilla1, ahk_id %id%
PostMessage 0x319, 0, (A_ThisHotkey == "$WheelUp") ? 0x10000 : 0x20000,, ahk_id %properTargetWin%
}
Else If (control == "TSTabCtrlClass1") ; Miranda IM, TabSRMM window's tab-bar classNN: TSTabCtrlClass1 listener-window classNN: RichEdit20W1
{
OutputDebug, % "A_ScriptName: '" A_ScriptName "' " "A_ThisHotkey: '" A_ThisHotkey "' case: tabsrmm"
ControlGet, properTargetWin, Hwnd,, RichEdit50W1, ahk_id %id%
PostMessage 0x319, 0, (A_ThisHotkey == "$WheelUp") ? 0x10000 : 0x20000,, ahk_id %properTargetWin%
}
Else If (class == "AkelPad4" && control == "SysTabControl321") || (class == "IEFrame" && control == "DirectUIHWND2") ; AkelPad tab bar
{
OutputDebug, % "A_ScriptName: '" A_ScriptName "' " "A_ThisHotkey: '" A_ThisHotkey "' case: akelpad tabbar"
ControlSend,, % (A_ThisHotkey == "$WheelUp") ? ("{Ctrl Down}{Shift Down}{Tab}{Shift Up}{Ctrl Up}") : ("{Ctrl Down}{Tab}{Ctrl Up}"), ahk_id %id%
}
Else If (id != idA) && (class != "Progman") ; If the cursor hovers an inactive window (and which is not the desktop) - that inactive window should receive a scrolling event (without the activation of that window).
{
OutputDebug, % "A_ScriptName: '" A_ScriptName "' " "A_ThisHotkey: '" A_ThisHotkey "' case: inactive window" " id: '" id "' " "control: '" control "' " "hw_m_target: '" hw_m_target "' " "m_x: '" m_x "' " "m_y: '" m_y "' " "class: '" class "' "
PostMessage, 0x20A, (A_ThisHotkey == "$WheelUp") ? 120 << 16 : -120 << 16, (m_y << 16) | (m_x & 0xFFFF),, ahk_id %hw_m_target%
; PostMessage, 0x20A, (A_ThisHotkey == "$WheelUp") ? 120 << 16 : -120 << 16, (m_y << 16) | (m_x & 0xFFFF),, ahk_id %id%
}
Else If (id == idA) || (class == "Progman") ; If the cursor hovers the active window or desktop - the regular scrolling event should get sent to the active window.
{
OutputDebug, % "A_ScriptName: '" A_ScriptName "' " "A_ThisHotkey: '" A_ThisHotkey "' case: active win"
If (A_ThisHotkey == "$WheelUp")
Send {WheelUp}
Else
Send {WheelDown}
}
GoSub, CleanVars
Return
;}
CleanVars:
currOpacity := hwndUnderCursor := x1 := y1 := winClass := maximized := winX1 := winY1 := x2 := y2 := winX2 := winY2 := ID := IDactive := control := key := value := Class := classA := properTargetWin := Hwnd := Height := m_x := m_y := hw_m_target := onTop := procName := XWin := YWin := title := ""
Return
;Open context menu via single left click on script's tray icon.
AddMenu: ; Add menuitem and make it default (bind to left click)
Menu Tray, Add, ShowMenu ; Add temporary menu item.
Menu Tray, Default, ShowMenu ; Set it to be default (it gets executed (or opened) just when you left click the tray icon).
Return
; Remove the created menuitem and show the normal menu. Then add the menuitem back The temporary menu item that
ShowMenu:
Menu Tray, Delete, ShowMenu ; If we don't delete that temporary menu item we created - it will be displayed in the tray icon's context menu and since clicking on it would just reopen the very same menu - we don't need it to be displayed, so we delete it.
MouseGetPos MouseX, MouseY
Menu Tray, Show, %MouseX%, % MouseY - 15 ; By default context menu gets opened at cursor's position and to let user be able to double click the tray icon - we move this menu a 15px higher.
GoSub, AddMenu ; We have to restore the deleted menu item for later use.
Return
;{ Exit
Exit: ; Removing hooks upon exit.
DllCall("UnhookWinEvent", Ptr, HWINEVENTHOOK1)
DllCall("UnhookWinEvent", Ptr, HWINEVENTHOOK2)
; Removing WS_EX_TOPMOST from every window we set it earlier.
For k, v in GUIs
WinSet, AlwaysOnTop, Off, % "ahk_id " v.Parent
GUIs := ""
ExitApp
;}Как видно из кода - в попытке разобраться что же чёрт возьми происходит - я добавил команды для отладки.
Это не помогло, т.к. когда происходит вышеописанный глюк - хоткеи тупо не срабатывают, так что в отладочном журнале в этот момент ничего не оседает.
Глюк исправляется только 2 способами: рестартом скрипта или же просто открытием меню его иконки в трее.
Журнал выполнения команд тоже не показывает ничего, что помогло бы в расследовании инцидента: судя по журналу, когда происходит глюк скрипт просто отдыхает: у строки Return хоткея просто продолжает тикать таймер, как будто новых нажатий хоткея не происходит.
Помогите разобраться, в чём может быть дело? Глюк появляется в произвольный момент, может прям во время кручения колеса (т.е. последовательного многократного wheelup/down), а может и в любой другой момент. Появляется не часто, несколько раз в день, никакого другого софта, который работал бы с колесом мыши - в системе не используется, да и "лечение" глюка тоже, в общем-то, странное.
p.s.: вырезанная часть скрипта никак не влияет на работу оставшегося куска кода.

