7

I know this question must have been asked hundreds of times before and so, maybe, I'm just doing something wrong. But I have a WinForms program I'm writing to try and keep the system appearing active so as to stop it as registering idle.

I figured that having a Timer on my form and doing something as simple as either moving the mouse via System.Windows.Forms.Cursor.Position or using the SendKeys.Send method would be enough to register user interaction, but it's not registering as user action and still letting the system appear as inactive after a set amount of time.

My code is fairly straightforward... Either:

Private Sub Updater_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Updater.Tick
    SendKeys.Send("+")
End Sub

Or doing something along the lines of:

Private Sub Updater_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Updater.Tick
    Dim MyMousePosition As Point
    MyMousePosition = Windows.Forms.Cursor.Position

    Windows.Forms.Cursor.Position = New Point(MyMousePosition.X - 10, MyMousePosition.Y)
End Sub

But neither is doing the trick... How can I get this to work AND preferably in a way that would be of least inconvnience to a user if they are actually using the system? (Meaning that I don't want to send a bunch of keys that may mess up the user if they're actually being active or move the mouse clear across the screen)

I know this coce is in VB, but I'm good with VB / C# solutions.

Thanks!!!


EDIT

As an addition to this question, I used the GetLastInputInfo from the User32.dll to check on the system activity.

Even with my mouse / keyboard events linked to the Timer_Tick event, GetLastInputInfo only gets reset if I physically move the mouse / perform some action on the computer...

I guess my question is What events can I add to my Timer_Tick event that will reset the GetLastInputInfo - In other words, have windows believe the user actually did something on the machine??

Thanks!!!

John Bustos
  • 19,036
  • 17
  • 89
  • 151
  • 1
    What is your reason for wanting the system not to appear idle? – Brian Rogers Aug 13 '13 at 16:13
  • I don't really get what you want. – King King Aug 13 '13 at 16:15
  • 3
    Possibly use [SetThreadExecutionState](http://msdn.microsoft.com/en-us/library/aa373208%28VS.85%29.aspx): http://stackoverflow.com/questions/6302185/how-to-prevent-windows-from-entering-idle-state – valverij Aug 13 '13 at 16:25
  • I have used the `SetThreadExecutionState` and it stops the system from going to sleep, but some users on my network have a program that registers user idle time (and we can't get rid of the program) that has messed up some processes in the past and `SetThreadExecutionState(EXECUTION_STATE.ES_SYSTEM_REQUIRED Or EXECUTION_STATE.ES_DISPLAY_REQUIRED Or EXECUTION_STATE.ES_CONTINUOUS)` doesn't stop this from occurring... Apparently (I THINK) it is looking for mouse movement / keystrokes to decide if the user is active or not.... – John Bustos Aug 13 '13 at 16:38
  • 1
    If that program is using a low-level Windows hook, you're going to have a very difficult time fooling it. You'll have to hook your program in *before* that program, and send simulated events. No, I don't know how to do that. I suspect that you don't want to try. – Jim Mischel Aug 13 '13 at 18:39
  • Please see my update to the question... Simply put, using the `User32.dll` > `GetLastInputInfo` function, what code can I put into my timer_tick event that will leave the system believing the user actually did something?... **ANY HELP - PLEASE!!** – John Bustos Aug 13 '13 at 20:12
  • What is the program MS Communicator? – Bit Aug 13 '13 at 20:17
  • 2
    The documentation for [GetLastInputInfo](http://msdn.microsoft.com/en-us/library/windows/desktop/ms646302%28v=vs.85%29.aspx) indicates that you can update it by sending information via the [SendInput](http://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx) function. Have you tried that? – Jim Mischel Aug 13 '13 at 20:19
  • @JimMischel, `SendInput` seems like it should do the trick!! - Thanks!! - I'm having a challenge finding any sample code to do something as simple as move the mouse a pixel or 2 so as not to annoy a user... Any suggestions??? – John Bustos Aug 13 '13 at 20:49
  • I would suggest something innocuous like a left shift key down event followed by a left shift key up event. So it looks like the user pressed the left shift key and then let it go. – Jim Mischel Aug 13 '13 at 20:58
  • @JohnBustos, I know it can be done, a guy got fired for it in my company, so I don't want to no how to do it. – Bit Aug 13 '13 at 20:59
  • @JimMischel, do you have any sample code to do that?? It's kicking my a$$ :( – John Bustos Aug 14 '13 at 14:42
  • Try http://stackoverflow.com/q/12761169/56778. Other than that, Google is your friend. Search for [SendInput C#]. – Jim Mischel Aug 14 '13 at 18:17

3 Answers3

9

After a lot of playing around, I came up with a solution that worked and I'm answering this question so as to help anyone out there that may be looking for the same information.

(Coded in VB):

In Declarations Section:

Private Declare Function SendInput Lib "user32.dll" (ByVal nInputs As Integer, ByRef pInputs As INPUT_TYPE, ByVal cbSize As Integer) As Integer
Const INPUT_MOUSE = 0
Const MOUSEEVENTF_MOVE = &H1

Public Structure MOUSEINPUT
    Public dx As Integer
    Public dy As Integer
    Public mouseData As Integer
    Public dwFlags As Integer
    Public dwtime As Integer
    Public dwExtraInfo As Integer
End Structure

Public Structure INPUT_TYPE
    Public dwType As Integer
    Public xi As MOUSEINPUT
End Structure

The Sub to move the mouse:

Public Sub MoveMouse(ByVal x As Integer, ByVal y As Integer, ByVal flag As Integer)

    Dim inputEvents As INPUT_TYPE
    Dim xi As New MOUSEINPUT

    xi.dx = x
    xi.dy = y
    xi.mouseData = 0
    xi.dwtime = 0
    xi.dwFlags = flag
    xi.dwExtraInfo = 0

    inputEvents.dwType = INPUT_MOUSE
    inputEvents.xi = xi

    SendInput(1, inputEvents, Len(inputEvents))
End Sub

The Code in the Timer_Tick Event:

Private Sub Updater_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Updater.Tick

    ' Move the mouse (relatively) 1 pixel away and then back
    MoveMouse(1, 1, MOUSEEVENTF_MOVE)
    MoveMouse(-1, -1, MOUSEEVENTF_MOVE)

End Sub

I tested this using the GetLastInputInfo API function and it works!!

... The most helpful link I found was this one: http://homeofcox-cs.blogspot.com/2008/07/c-simulate-mouse-and-keyboard-events.html

Thank you all for all your help and I hope this helps other people too!!

John Bustos
  • 19,036
  • 17
  • 89
  • 151
  • I used your solution and it works on my laptop well, but it doesn't work on our remote servers, is there any limitation for your solution? – Ehsan Zand Jul 13 '19 at 12:52
1

when we needed the system not to go idle (in WM 6.0 when we ha long logic and the device went idle the logic stopped working) we used

  [DllImport("CoreDll.dll")]
  public static extern void SystemIdleTimerReset();

it reset the idle timer, not interfering with the user's actions and it worked like charm

No Idea For Name
  • 11,411
  • 10
  • 42
  • 70
  • Thanks. Seems about right in terms of the functionality I need, but CoreDll is only for mobile platforms... Any idea at all for desktop??? – John Bustos Aug 14 '13 at 14:40
  • 1
    @JohnBustos look what i have found for you - http://stackoverflow.com/questions/6302185/how-to-prevent-windows-from-entering-idle-state – No Idea For Name Aug 15 '13 at 10:35
  • Thank you so much for finding this.. For whatever reason, you'd think that the `ES_SYSTEM_REQUIRED ` flag would reset the timer (as it says it does), but it doesn't :( ... I'm still stuck on this and it seems the only solution is the `SendInput` function... If you do know of any others, PLEASE do let me know, though!!!! DARN ANNOYING, but thank you SO much for looking for me.... – John Bustos Aug 15 '13 at 12:58
  • 1
    @JohnBustos i can't find it right now, but i remember that i saw there were some registery values that can be changed to prevent idle state. Can't find it when i need it though – No Idea For Name Aug 15 '13 at 13:03
  • Also a cool idea, but the network setting have those values getting changed back.... NUTS, huh?? - I'm working on the SendInout solution now... I'm still thinking that'll be the most robust.... – John Bustos Aug 15 '13 at 17:34
  • as did we... i guess microsoft didn't want us to do it @JohnBustos – No Idea For Name Aug 15 '13 at 20:27
1

There is a much simpler way, that consists in calling the Win32 function:

EXECUTION_STATE WINAPI SetThreadExecutionState(
  _In_  EXECUTION_STATE esFlags
);

with ES_SYSTEM_REQUIRED | ES_CONTINUOUS as argument. Anyway, from this SO issue, it seems that the effect will not persist, even if ES_CONTINUOUS is used. In that case, you should call the function periodically, say every minute, to reset the idle timer. An important thing is that the function only applies to the thread that called it, and its effect terminates when the thread terminates.

When you're done, you should call SetThreadExecutionState(ES_CONTINUOUS) to allow the system to go idle again.

Community
  • 1
  • 1
Giulio Franco
  • 3,170
  • 15
  • 18