Jump to content
Sign in to follow this  
gte

Why would _Timer_GetIdleTime() return a negative value?

Recommended Posts

gte

I'm trying to write a very simple program that moves my mouse from one coordinate to another, if the mouse/keyboard has been idle for 5 minutes or more.

_Timer_GetIdleTime() is returning values of something like " -1349613781 "

and it just counts down by increments, which I believe is making the function useless for me because I can't have _Timer_GetIdleTime() and _Timer_GetIdleTime() + 500000 because the while statement cycles and constantly updates it.

Is my logic wrong? If not, is there an alternative?

Share this post


Link to post
Share on other sites
Melba23

gte,

_Timer_GetIdleTime works fine for me here:

#Include <Timers.au3>
While 1
    ConsoleWrite(_Timer_GetIdleTime() & @CRLF)
    Sleep(1000)
WEnd

Perhaps if you posted your "very simple" code we might be able to offer something more. :)

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
PsaltyDS

I wrote _Timer_GetIdleTime() (based on DLL calls by others).

Post the shortest reproducer script you can that shows your symptoms, as Melba23 suggested. Also, what OS/SP level?

:)

Edited by PsaltyDS

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites
Authenticity

The OP is right. Read this function, it's from the Timers.au3 library:

; #FUNCTION#;===============================================================================
; Name...........: _Timer_GetIdleTime
; Description ...: Returns the number of ticks since last user activity (i.e. KYBD/Mouse)
; Syntax.........: _Timer_GetIdleTime()
; Parameters ....: None
; Return values .: Success - integer ticks since last (approx. milliseconds) since last activity
;                  Failure - Sets @extended = 1 if rollover occurs (see remarks)
; Author ........: PsaltyDS at http://www.autoitscript.com/forum
; Modified.......:
; Remarks .......: The current ticks since last system restart will roll over to 0 every 50 days or so,
;                  which makes it possible for last user activity to be before the rollover, but run time
;                  of this function to be after the rollover.  If this happens, @extended = 1 and the
;                  returned value is ticks since rollover occured.
; Related .......:
; Link ..........;
; Example .......; Yes
;;==========================================================================================
Func _Timer_GetIdleTime()
    ; Get ticks at last activity
    Local $tStruct = DllStructCreate("uint;dword");
    DllStructSetData($tStruct, 1, DllStructGetSize($tStruct));
    DllCall("user32.dll", "int", "GetLastInputInfo", "ptr", DllStructGetPtr($tStruct))

    ; Get current ticks since last restart
    Local $avTicks = DllCall("Kernel32.dll", "int", "GetTickCount")

    ; Return time since last activity, in ticks (approx milliseconds)
    Local $iDiff = $avTicks[0] - DllStructGetData($tStruct, 2)
    If $iDiff >= 0 Then
        ; Normal return
        Return $iDiff
    Else
        ; Rollover of ticks counter has occured
        Return SetError(0, 1, $avTicks[0])
    EndIf
EndFunc   ;==>_Timer_GetIdleTime

Since in most cases, unsigned int can be used in signed int context some of the DllCall() function calls you may find among the UDFs are contextually incorrect but that is because autoit treat int and uint in the same context. It's the output that may differ. If this function for example was written as follows, it would never output negative numbers (presumably):

; Get current ticks since last restart
Local $avTicks = DllCall("Kernel32.dll", "uint", "GetTickCount")

..and this is why.

Non comprehensive example:

$uInt = DllStructCreate("uint")
DllStructSetData($uInt, 1, -55)
ConsoleWrite(DllStructGetData($uInt, 1) & @CRLF)

$Int = DllStructCreate("int")
DllStructSetData($Int, 1, -55)
ConsoleWrite(DllStructGetData($Int, 1) & @CRLF)

...and I might be wrong.

Edit: ..and who is this PsaltyDS? :)

Edited by Authenticity

Share this post


Link to post
Share on other sites
gte

This has broken all of my functions/code that used this, as it was working?

Simplest code that generates the screen shot below is as follows

#include <Timers.au3>


            global $idletime = _Timer_GetIdleTime()
            global $idletimeplus = ($idletime + 10000)
            MsgBox( 0, "Get idle time variable is ", $idletime)

Posted Image

Another example with multiple outputs

#include <Timers.au3>


while 1
            global $idletime = _Timer_GetIdleTime()
            global $idletimeplus = ($idletime + 10000)
            ConsoleWrite($idletime & ' . ')

            Sleep(1000)

WEnd

Posted Image

Thanks all!

Share this post


Link to post
Share on other sites
PsaltyDS

The OP is right. Read this function, it's from the Timers.au3 library:

Since in most cases, unsigned int can be used in signed int context some of the DllCall() function calls you may find among the UDFs are contextually incorrect but that is because autoit treat int and uint in the same context. It's the output that may differ. If this function for example was written as follows, it would never output negative numbers (presumably):

; Get current ticks since last restart
Local $avTicks = DllCall("Kernel32.dll", "uint", "GetTickCount")

..and this is why.

Non comprehensive example:

$uInt = DllStructCreate("uint")
DllStructSetData($uInt, 1, -55)
ConsoleWrite(DllStructGetData($uInt, 1) & @CRLF)

$Int = DllStructCreate("int")
DllStructSetData($Int, 1, -55)
ConsoleWrite(DllStructGetData($Int, 1) & @CRLF)

...and I might be wrong.

By the MSDN description, it should have been DWORD in any case, and that works in your example:
$Dword = DllStructCreate("dword")
DllStructSetData($Dword, 1, 2^32 - 1)
ConsoleWrite(DllStructGetData($Dword, 1) & @CRLF)

So the line should be (the dll call for the LASTINPUTINFO struct is already cast as dword):

Local $avTicks = DllCall("Kernel32.dll", "dword", "GetTickCount")

Testing that with the function requires a system up for over three weeks (to set the MSB or INT sign bit). I have to reboot for security patches more often than that, so I can't test. If the OP's system is still going, I would appreciate making that change (dword vice int), try it again, and report the results.

Edit: ..and who is this PsaltyDS? :)

Rakishly good looking Antarctic water fowl, at your service...

;)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites
PsaltyDS

This has broken all of my functions/code that used this, as it was working?

Please try it again with just the change of "dword" for "int" inside the UDF function:
Local $avTicks = DllCall("Kernel32.dll", "dword", "GetTickCount")

Report the results and I'll put in a BugTrac to change it in the next Beta if that works.

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites
Authenticity

Testing that with the function requires a system up for over three weeks (to set the MSB or INT sign bit). I have to reboot for security patches more often than that, so I can't test. If the OP's system is still going, I would appreciate making that change (dword vice int), try it again, and report the results.

Hmm... I'm positive that this is the case, you don't need to get your system idle for so long to confirm that a signed int value of 0x80000000 is negative whereas an unsigned int value of 0x80000000 is always positive.

Example:

#include <WinAPI.au3>

Local $hBrush = _WinAPI_CreateSolidHWND(0)
ConsoleWrite("HWND: " & $hBrush & @CRLF)
If $hBrush Then _WinAPI_DeleteObject($hBrush)

$hBrush = _WinAPI_CreateSolidBrushINT(0)
ConsoleWrite("INT: " & $hBrush & @CRLF)
If $hBrush Then _WinAPI_DeleteObject($hBrush)

$hBrush = _WinAPI_CreateSolidBrushUINT(0)
ConsoleWrite("UINT: " & $hBrush & @CRLF)
If $hBrush Then _WinAPI_DeleteObject($hBrush)

Func _WinAPI_CreateSolidHWND($nColor)
    Local $hBrush = DllCall('gdi32.dll', 'hwnd', 'CreateSolidBrush', 'int', $nColor)
    If @error Then Return SetError(@error, 0, 0)
    Return $hBrush[0]
EndFunc   ;==>_WinAPI_CreateSolidBrush

Func _WinAPI_CreateSolidBrushINT($nColor)
    Local $hBrush = DllCall('gdi32.dll', 'int', 'CreateSolidBrush', 'int', $nColor)
    If @error Then Return SetError(@error, 0, 0)
    Return $hBrush[0]
EndFunc   ;==>_WinAPI_CreateSolidBrush

Func _WinAPI_CreateSolidBrushUINT($nColor)
    Local $hBrush = DllCall('gdi32.dll', 'uint', 'CreateSolidBrush', 'int', $nColor)
    If @error Then Return SetError(@error, 0, 0)
    Return $hBrush[0]
EndFunc   ;==>_WinAPI_CreateSolidBrush

Run a few times you'll eventually get the int one to be negative.

Share this post


Link to post
Share on other sites
PsaltyDS

Hmm... I'm positive that this is the case, you don't need to get your system idle for so long to confirm that a signed int value of 0x80000000 is negative whereas an unsigned int value of 0x80000000 is always positive.

No argument with the principle. It OUGHT to work. I just want it tested with the subject issue directly, which is the dword returned from GetTickCount. To set the MSB on that requires system uptime of 2^31 milliseconds = over 25 days (since there is no SetTickCount to simulate uptime, that I know of).

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites
gte

You are the pimpin-est penguin I know! Woohoo!

Should I be even a little stoked that I found a bug? ;)

Posted Image

Please try it again with just the change of "dword" for "int" inside the UDF function:

Local $avTicks = DllCall("Kernel32.dll", "dword", "GetTickCount")

Report the results and I'll put in a BugTrac to change it in the next Beta if that works.

:)

Share this post


Link to post
Share on other sites
gte

The good thing about being a global admin is that you can remove patch admin reboot rights B)

I like to save my reboots for power fluctuations :)

No argument with the principle. It OUGHT to work. I just want it tested with the subject issue directly, which is the dword returned from GetTickCount. To set the MSB on that requires system uptime of 2^31 milliseconds = over 25 days (since there is no SetTickCount to simulate uptime, that I know of).

;)

Share this post


Link to post
Share on other sites
gte

And now my small anti - screen saver app works :)

#include <Timers.au3>


        global $idletime = _Timer_GetIdleTime()

            
            While 1

                $idletime = _Timer_GetIdleTime()
                If $idletime <= 570000 Then                             ; change this to alternate the time it looks for the keyboard/mouse to be inactive
                    ConsoleWrite("If . " & $idletime)                   ; console write variable

                Else                
                $pos = MouseGetPos()
;~              MsgBox(0, "Mouse x,y:", $pos[0] & "," & $pos[1])        ; message box to display coordinates
                MouseMove($pos[0]+50, $pos[1]+40, 50)
                        Sleep(500)
                $pos2 = MouseGetPos()
;~              MsgBox(0, "Mouse x,y:", $pos2[0] & "," & $pos2[1])      ; message box to display coordinates
                MouseMove($pos[0], $pos[1], 50)
;~              ConsoleWrite("Else" & $idletime)                        ; console write variable
                EndIf
            
                Sleep(10000)                                            ; sleep 10 seconds before checking again

            WEnd

Share this post


Link to post
Share on other sites
PsaltyDS

You know, I can be pretty dense sometimes... ;)

It's already been fixed in the current Beta. There was a general clean up of DLL calls in the UDFs by one of the Devs, to ensure correct type casting per MSDN. Evidently this error had already been caught as part of that effort.

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites
gte

Ah well, know and be proud that you were right, and I was able to slightly enjoy thinking I found a bug for about 40 minutes B)

You know, I can be pretty dense sometimes... ;)

It's already been fixed in the current Beta. There was a general clean up of DLL calls in the UDFs by one of the Devs, to ensure correct type casting per MSDN. Evidently this error had already been caught as part of that effort.

:)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×