Link to home
Start Free TrialLog in
Avatar of SINEtist
SINEtist

asked on

VB.NET - need to detect inactivity in program with multiple forms - 500pts

Hello Experts,

This seems to be a somewhat common task based on my searches, but I have not found a solution that I have been able to get working propely.  I am trying to implement a feature where if the program is idle, the "home page" is launched  --essentially, this is a screensaver feature for my program.  This application will run on a touch-screen kiosk, so I am mainly concerned with detecting "mouse" inactivity.  The most straightforward way of doing this appears to be through the Windows API, but I haven't been able to get those implementations to work.

I need to be able to disable and enable the inactivity feature at will.  ( I want to disable it while the user is recording a video,  which is one of the features of my program, but then reenable it.  --there is a seperate timer used on the video recording feature).

One problem I have encountered  is related to the use of the on screen keyboard which I have implemented.  I discovered that the keyboard would not send values to the form that it was located on, so what I ended up doing was creating a dedicated, small little form for the on screen keyboard.  The on screen keyboard form is then drawn on top of the form in which I need the data to be entered on, which solved the issue with the keyboard form not being able to send keystrokes to itself.  This workaround seemed to cause problems with my inactivity timer though (inactivity was not detected properly with both of the forms on the screen at the same time).  Because of this issue, I was thinking that the API function would be better for solving my idle time issue.


I am a beginner at programming, so I am looking for the exact code I would need to use.


some of the topics I have looked at that have not panned out for me are:
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
https://www.experts-exchange.com/questions/21164935/Detect-user-inactivity-in-a-VB-NET-Windows-Application-multiple-forms.html?query=vb.net+detect+idle+time+multiple+forms&clearTAFilter=true

https://www.experts-exchange.com/questions/21544476/Screen-saver-in-vb-net-application.html?query=vb.net+detect+idle&clearTAFilter=true

https://www.experts-exchange.com/questions/21671061/Application-Idle-Time.html?query=vb.net+GetLastInputInfo+API&clearTAFilter=true
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------



Thank you,

SINEtist

ASKER CERTIFIED SOLUTION
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of SINEtist
SINEtist

ASKER

Idle_Mind,

Q: Since this is a kiosk, and most likely only your application is running, is it safe to say that ANY mouse/keyboard activity is related to your app?
A: yes, that is correct.

I implemented the low level mouse hook from the link you provided.  I added a class to my project and pasted in the code.  I get 1 error, which occurs at the following line of code:

     Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly.GetModules()(0)).ToInt32, 0)

Error: "Name 'Marshal' is not decalred."

I have seen other solutions, some I'm pretty sure were even provided by you, that other people seem to have no problem with, but I always get that same error whren trying to use the "Marshal" thing.  I say 'thing', because I'm really not sure what to call it.


Assuming that the 'Marshal' issue can be fixed, I just want to verify that in order to start detecting for idle time, I call the Hook() function and to stop detecting, the Unhook() function.

Also, I wanted to verify that my action (which is go to formA, btw) would go under your comment that says 'do something....'  (code from your example below)

        If (nCode = HC_ACTION) Then
            Select Case wParam
                Case WM_MOUSEMOVE
                    ' using GetCursorPos() API because a service might not
                    ' have access to System.Windows.Forms.Cursor.Position()
                    GetCursorPos(curPos)
                    If curPos.x = 500 AndAlso curPos.y = 250 Then
                        ' do something...
                    End If

            End Select
        End If


And finally, I was not sure how I could incorporate my form_activity_timeoutInteger value with the code you provided.  Will I somehow need to invoke a timer?  



here is my outline of what I'm trying to accomplish is psuedocode.  I don't even think it is really psuedocode, but I think you'll get the idea.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
IF no mouse movement for form_activity_timeoutInteger THEN show inactivity_panel

[inactivity_panel is shown]: if "i am here, but just not actively entering information" button is NOT hit in 30 seconds THEN goto homepage.

Otherwise: "i am here, but just not actively entering information" button is hit, then

[no mouse movement is st back to 0]
[inactivity_panel is hidden]
 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------




Thank you,

and I'm sorry Im such a noob.


I'm using VB.NET 2003 by the way
For the Marshal error, you need this line at the top of your code (outside the Class):

Imports System.Runtime.InteropServices

So after you have installed the hook, anytime the mouse is moved you will get a WM_MOUSEMOVE message.  What you can do is make the LowLevelMouseHook() class raise a custom event each time the mouse is moved.  From your main form, you can trap the event and reset a Timer each time the event is raised.  If the Timer event fires, then there must not have been any activity for the Interval of the Timer.

Something like...

    Public Class LowLevelMouseHook

        Public Event MouseMoved()  '  <--- your custom event

        ...
                    Case WM_MOUSEMOVE
                        RaiseEvent MouseMoved()   ' <--- raise custom event whenver mouse is moved

    End Class




    Public Class formA

        Private WithEvents llm As LowLevelMouseHook   ' <-- declared WithEvents so we can trap the custom event

        Private Sub formA_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            llm = New LowLevelMouseHook
            Timer1.Interval = 30000 ' 30 seconds
            Timer1.Start()
        End Sub

        Private Sub llm_MouseMoved() Handles llm.MouseMoved
            ' reset the Timer everytime the mouse is moved...
            Timer1.Stop()
            Timer1.Start()
        End Sub

        Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
            ' if the code here runs then there was NO mouse movement for the
            ' interval of the Timer...
        End Sub

    End Class
Thanks Idle_Mind.

You really know how to take care of business!

SINEtist
Hi Idle Mind,

I am using vb.net 2008 and the hook still does not work in IDE mode, is there any MS update or patches to make it work in IDE mode?

I am using your solution for a kiosk application, and your solution is just what i need!

Hi BSKhoo,

I've never gone digging real deep to find a fix that allows hooks to be trapped while in the IDE.  I believe it has something to do with how the debugger attaches to the process so there is already a hook in place and they interfere with each other...not exactly sure though.

I just always run the EXE in the bin folder...makes troubleshooting problems a bit tricker though.  =\
Ok, thanks a lot Idle Mind!