views:

621

answers:

6

Some background: I am writing a application with several forms, etc. Users have to log in in order to use most of the features, and this worked fine until now. However, now, client has requested that the user would be logged out after a certain amount of inactive time. The problem is that the user can still be active on the computer, just not in my application,. To be clear, I have to log the user out when he is inactive in my application, even if he is still interacting with the desktop.

First I thought this would be fairly simple. Just remember the time of the last action, compare it continually in a timer with current time and log out the user if the time passed is greater than the allowed time. However I have realised that finding out the last action time may not be so simple...

Of course I could copy paste something like

Program.LastActionTime = DateTime.Now;

in every OnChange, OnClick, etc, event ... However not only that this would be a great amount of work because of the size of the application ... It would also be a very bad practice and I'm sure it would be forgot at least once, making the whole thing unreliable (And appear broken, the bug would be almost impossible to reproduce!)

So, is there a better way?

A: 

Hook an event handler on the MouseMove and KeyPressed events, and then check for focus inside that event?

Lars Mæhlum
A: 

In general it would be the best idea to derive this information from your application logic instead of raw user input, but I assume you have no flexible infrastructure (maybe using the command pattern) that could provide this information.

So I suggest just to register handlers with your main form - if you receive clicks or key events (enable Form.KeyPreview for this), your user is active and you can reset the inactivity time.

Daniel Brückner
A: 

You could create a base class that all your window forms inherits from. In the base class you check and reset your timeout on every KeyPress or Click.

Jonas Elfström
+1  A: 

One approach that I've used in the past, create a MessageFilter on your application form and check for certain types of events that indicate user activity:

 public class UserActivityFilter : IMessageFilter
 {
        // Define WinAPI window message values (see pinvoke.net)
        private int WM_LBUTTONDOWN = 0x0201;
        private int WM_MBUTTONDOWN = 0x0207;
        private int WM_RBUTTONDOWN = 0x0204;
        private int WM_MOUSEWHEEL = 0x020A;
        private int WM_MOUSEMOVE = 0x0200;
        private int WM_KEYDOWN = 0x0100;

        public bool PreFilterMessage(ref Message m)
        {
            if (m.Msg == WM_LBUTTONDOWN || m.Msg == WM_MBUTTONDOWN || m.Msg == WM_RBUTTONDOWN || m.Msg == WM_MOUSEWHEEL || m.Msg == WM_MOUSEMOVE || m.Msg == WM_KEYDOWN)
            {
                //User activity has occurred
                // Reset a flag / timer etc.
            }
            return false;
        }
  }

Then in the Main() method of the form, BEFORE the call to Run():

Application.AddMessageFilter(new UserActivityFilter());

One caveat, adding a complex message filter or adding multiple separate filters can slow down the responsiveness of your application.

Ash
+1  A: 

You can override WndProc, update Program.LastActionTime on each relevant Keyboard/Mouse event message.

najmeddine
+1  A: 

In your Program.CS file, you can handle the Application.Idle event and reset your timer there. See:

http://msdn.microsoft.com/en-us/library/system.windows.forms.application.idle.aspx

MusiGenesis
That's exactly what I was looking for!
Rekreativc