Settimer Causes Function to Crash ... Cant Figure Out why

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Roonyroo
Posts: 36
Joined: 29 Jan 2014, 20:29

Settimer Causes Function to Crash ... Cant Figure Out why

05 Apr 2014, 16:49

This script works great, it detects the key pressed & then uses settimer to detect the time of the next key

Until I added a settimer, it then freezes after it detects the first key, & after pressing around 20 keys the function stops detecting the keys, or the script crashes

No idea why, I'm no expert on functions ..

My script :

Code: Select all

#Persistent
#SingleInstance, force

global x := 0
global wParam := 0

global Param := 0

global KeyName := 0

OnExit, Unhook



hHookKeybd := SetWindowsHookEx(WH_KEYBOARD_LL	:= 13, RegisterCallback("Keyboard", "Fast"))
hHookMouse := SetWindowsHookEx(WH_MOUSE_LL	:= 14, RegisterCallback("MouseMove", "Fast"))
;gosub wx

SetTimer, wx,1

Return

Unhook:
UnhookWindowsHookEx(hHookKeybd)
UnhookWindowsHookEx(hHookMouse)
ExitApp


     

Keyboard(nCode, wParam, lParam)
{
	Critical
	SetFormat, Integer, H
	If ((wParam = 0x100)  ; WM_KEYDOWN
	|| (wParam = 0x101))  ; WM_KEYUP
	{
		KeyName := GetKeyName("vk" NumGet(lParam+0, 0))
                ;SingleKey := GetKeyName("vk" NumGet(lParam+0, 0))
		;Tooltip, % (wParam = 0x100) ? KeyName " Down" : KeyName " Up"
		 SetFormat, IntegerFast, D
		x:=x*10
		tooltip %x%
		sleep 1000
		SetFormat, Integer, H
		;sleep,10
		x:=0
		;CallNextHookEx(nCode, wParam, lParam)
		
                ;goto wx 
		return
	}
	CallNextHookEx(nCode, wParam, lParam)
}


SetWindowsHookEx(idHook, pfn)
{
	Return DllCall("SetWindowsHookEx", "int", idHook, "Ptr", pfn, "Uint", DllCall("GetModuleHandle", "Uint", 0), "Uint", 0)
}

UnhookWindowsHookEx(hHook)
{
	Return DllCall("UnhookWindowsHookEx", "Uint", hHook)
}

CallNextHookEx(nCode, wParam, lParam, hHook = 0)
{
	Return DllCall("CallNextHookEx", "Uint", hHook, "int", nCode, "Uint", wParam, "Uint", lParam)
}



wx:


x++
;sleep 100
tooltip %x% %Param% %KeyName%
Keyboard(nCode, wParam, lParam)

;CallNextHookEx(nCode, wParam, lParam)
return



Esc::ExitApp
 

jpginc
Posts: 124
Joined: 29 Sep 2013, 22:35

Re: Settimer Causes Function to Crash ... Cant Figure Out wh

06 Apr 2014, 00:32

My guess would be that your timer function is being called too often. You are calling it every milisecond and it might be taking longer than a milisecond to run?
Roonyroo
Posts: 36
Joined: 29 Jan 2014, 20:29

Re: Settimer Causes Function to Crash ... Cant Figure Out wh

06 Apr 2014, 06:12

The timer on the settimer has nothing to do with it, crashes on all intervals
RHCP
Posts: 202
Joined: 30 Sep 2013, 10:59

Re: Settimer Causes Function to Crash ... Cant Figure Out wh

06 Apr 2014, 06:18

Your timer subroutine was being called during the middle of your callback function causing the crash. I highly recommend you read up on these low level hooks and how a hook function is meant to be coded - MSDN is a good start. You should not be sleeping inside this function, and that's one of the reasons why a hook can get removed. For more complex scripts with many threads and timers, a "sleep 100" in no way guarantees that the code execution within this thread will be resumed after just 100 ms.

This doesn't crash for me.

Code: Select all

#Persistent
#SingleInstance, force
SetBatchLines, -1 
;global x := 0 ; I couldn't work out the purpose of X
global KeyName

OnExit, Unhook


; You shouldn't be using fast mode.
; also you have no MouseMove function
hHookKeybd := SetWindowsHookEx(WH_KEYBOARD_LL   := 13, RegisterCallback("Keyboard"))
;hHookMouse := SetWindowsHookEx(WH_MOUSE_LL  := 14, RegisterCallback("MouseMove"))

settimer, fastTimerTest, 1 ; this shouldnt crash the script
Return

Unhook:
UnhookWindowsHookEx(hHookKeybd)
;UnhookWindowsHookEx(hHookMouse)
ExitApp

fastTimerTest:
c++
if (c > 9000)
	c := 0
return 
     

Keyboard(nCode, wParam, lParam)
{
    Critical, 1000 	; This prevents other timers/messages interupting this function (and crashing the script) for 1000 ms.
    				; it also chages batchlines to -1 preventing unnecessary sleeps
    				; But this function must return a result in less than ~300ms, otherwise the LL hook will silently be removed 
    				; on windows 7 and up when it times out  multiple times
    if (nCode >= 0) 
    && (wParam = 0x100  ; WM_KEYDOWN
    || wParam = 0x101)  ; WM_KEYUP
    {
    	SetFormat, IntegerFast, H
        KeyName := GetKeyName("vk" NumGet(lParam+0, 0))
        global message := wParam = 0x100 ? "Down" : "Up"
        SetFormat, IntegerFast, D
        ;sleep 1000 ; You should NEVER sleep in a low level hook
      	settimer, wx, -5 ; use a negative timer so the function can return and you can take all the time you want to process the info
    }
    return CallNextHookEx(nCode, wParam, lParam) ; you should be returning the result of this function/value! not just call the function
    ; if you wish to block these key events, simple return a non-zero number and dont call CallNextHookEx
}


SetWindowsHookEx(idHook, pfn)
{
    Return DllCall("SetWindowsHookEx", "int", idHook, "Ptr", pfn, "Uint", DllCall("GetModuleHandle", "Uint", 0), "Uint", 0)
}

UnhookWindowsHookEx(hHook)
{
    Return DllCall("UnhookWindowsHookEx", "Uint", hHook)
}

CallNextHookEx(nCode, wParam, lParam, hHook = 0)
{
    Return DllCall("CallNextHookEx", "Uint", hHook, "int", nCode, "Uint", wParam, "Uint", lParam)
}



wx:
tooltip %message% %KeyName% %c%
; Keyboard(nCode, wParam, lParam) ; why would you call your own callBack function from inside the script????
return



Esc::ExitApp
lexikos
Posts: 9690
Joined: 30 Sep 2013, 04:07
Contact:

Re: Settimer Causes Function to Crash ... Cant Figure Out wh

07 Apr 2014, 02:36

My guess would be that it crashed because you called CallNextHookEx with invalid parameters, or that you called it when the system wasn't expecting it to be called (i.e. while a hook procedure is running).

Note that all parameters of all functions are local variables. The global variables nCode, lParam and wParam, which are used by the timer subroutine, are never assigned values (except wParam := 0).

Also, SetTimer, wx,1 will not cause the timer to execute every millisecond; more like every 15 milliseconds. If you're trying to measure time, don't use SetTimer; use A_TickCount (which is no more accurate, but less wasteful and more reliable).

Code: Select all

begin := A_TickCount
Sleep 1500 ; Let some time pass.
duration := A_TickCount - begin
MsgBox Took %duration% ms.
Roonyroo
Posts: 36
Joined: 29 Jan 2014, 20:29

Re: Settimer Causes Function to Crash ... Cant Figure Out wh

07 Apr 2014, 14:14

@RHCP

Thats great, exactly what I was trying to do, much appreciated

Thanks for the help guy & Thanks for the corrections

I basically copy & pasted someones function & tried to alter it, without knowing how functions work ...

The script works great, the only thing i need to know is how to set the timer to count the length of time the key is held down.

At the moment the timer resets continously if you hold a key down ...

Basically reset the timer on a key held down & time the key held down, then restart the timer again after it detects a keyup

I also need to save the reset time & key pressed to a fileappend

I can do all of the above in a regular ahk script, but no idea how to alter a function correctly ...

I'm pretty sure if I added some regular if (wParam = 0x100 ; WM_KEYDOWN goto countdown timer it'll return a cant use goto in a function or something

Also how would I detect a keyup or keydown using the function in a seperate subroutine

ie

how do I get it to reference a subroutine on a keydown ie. if (wParam = 0x100 ; WM_KEYDOWN goto countdown timer


& then create a timer which runs until a keyup event

ie.

countdown timer : ; timer runs & waits for a keyup event
loop
{
x++
if wParam = 0x101) ; WM_KEYUP
{
x:=0
break
return
}
}


This is the main thing I need this script to do

Again I dont know how functions or hooks, work or how to call them in subroutines like the above example, hence my inquiry ...

Oh yes how do I slow the script down, instead of using sleep? I basically need the script to detect at regular intervals of sleep 500 ...
RHCP
Posts: 202
Joined: 30 Sep 2013, 10:59

Re: Settimer Causes Function to Crash ... Cant Figure Out wh

07 Apr 2014, 15:45

So you just want to measure how long keys are pressed down for? i.e. when they are pressed down, and when they are released? What are you trying to achieve with this? As this will dictate the best way to code everything.

This should list the time a key was pressed and released and hence the duration. The alt key uses the WM_systemdown/up messages.

Code: Select all

#Persistent
#SingleInstance, force
SetBatchLines, -1 
global aKeyTimes := []
OnExit, Unhook

hHookKeybd := SetWindowsHookEx(WH_KEYBOARD_LL   := 13, RegisterCallback("Keyboard"))
Return

Unhook:
UnhookWindowsHookEx(hHookKeybd)
ExitApp


Keyboard(nCode, wParam, lParam)
{
    static aKeyDowns := [], WM_KEYDOWN := 0x100, WM_KEYUP := 0x101, WM_SYSKEYDOWN := 0x0104, WM_SYSKEYUP := 0x0105
    ,   aExtendedRemap := {  "NumpadIns": "Ins"
                            ,   "NumpadHome": "Home"
                            ,   "NumpadPgUp": "PgUp"
                            ,   "NumpadDel": "Delete"
                            ,   "NumpadEnd": "End"
                            ,   "NumpadPgDn": "PgDn"
                            ,   "NumpadLeft": "Left"
                            ,   "NumpadUp": "Up"
                            ,   "NumpadDown": "Down"
                            ,   "NumpadRight": "Right" }  
    Critical, 1000  

    if (nCode >= 0) 
    {
        SetFormat, IntegerFast, H
        KeyName := GetKeyName("vk" NumGet(lParam+0, 0))
        SetFormat, IntegerFast, D
        flags := NumGet(lParam+0, 8)
        extended := flags & 1
        if (extended && aExtendedRemap.HasKey(KeyName)) ;extended due to numlock
            KeyName:= aExtendedRemap[KeyName]
        if ((wParam = WM_KEYDOWN || wParam = WM_SYSKEYDOWN) && !aKeyDowns.HasKey(KeyName))
        {
             aKeyDowns[KeyName] := True ; The keyname is the important part - its used with .HasKey to check if this key is already down
             aKeyDowns["Count"] := round(aKeyDowns["Count"]) + 1
             aKeyTimes[KeyName, "Down"] :=  A_TickCount
             aKeyTimes[KeyName, "up"] :=  ""
             settimer, wx, -10 ; update the tooltip with new info
        }
        else if ((wParam = WM_KEYUP || wParam = WM_SYSKEYUP) && aKeyDowns.HasKey(KeyName))
        {
            aKeyTimes[KeyName, "up"] :=  A_TickCount
            aKeyDowns.Remove(KeyName)
            aKeyDowns["Count"] := round(aKeyDowns["Count"]) - 1
            ;if (aKeyDowns["Count"] < 0) ; if a key is already down when the hook is installed, can get a negative (if the keyup arrives before the keyboard autorepeat down message)
            ;    aKeyDowns["Count"] := 0 ; so reset the value to 0 - a better method would be to ensure no keys are down when the hook is installed or programmatically release them, install hook 
            ;if (aKeyDowns["Count"] = 0) ; No keys are down
            ;   do something
            settimer wx, -10 ; update the tooltip with new info

        }
    }
    return CallNextHookEx(nCode, wParam, lParam) ; you should be returning the result of this function/value! not just call the function
    ; if you wish to block these key events, simple return a non-zero number and dont call CallNextHookEx
}


SetWindowsHookEx(idHook, pfn)
{
    Return DllCall("SetWindowsHookEx", "int", idHook, "Ptr", pfn, "Uint", DllCall("GetModuleHandle", "Uint", 0), "Uint", 0)
}

UnhookWindowsHookEx(hHook)
{
    Return DllCall("UnhookWindowsHookEx", "Uint", hHook)
}

CallNextHookEx(nCode, wParam, lParam, hHook = 0)
{
    Return DllCall("CallNextHookEx", "Uint", hHook, "int", nCode, "Uint", wParam, "Uint", lParam)
}



wx:
keyTimes := ""
for key, object in aKeyTimes
{
    keyTimes .= (keyTimes ? "`n" : "") "Key: " A_Tab key
        . "`nDown: " A_Tab object.Down
        . "`nUp: " A_Tab object.up
        . "`nDuration: " A_Tab (object.up ? object.up - object.Down : "Still Down")
        . "`n=========================="

}
tooltip % keyTimes
return

Esc::ExitApp

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: peter_ahk and 365 guests