0

I have a question on setting timer in Windows Forms when the user is idle or Inactive using Static Class and call static method. Since static will be there for the lifetime period of the exe file. I need the timer to set even on any Mouse Events. If the user makes any moment then I need to reset the timer. So this is the requirement. Here goes the code.

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace StaticApplicationTimeOut
{
    public static class SetApplicationTimeOut
    {
        #region
        /// <summary>
        /// Private Timer Property
        /// </summary>
        private static Timer _timer;

        /// <summary>
        /// Timer Property
        /// </summary>
        public static Timer Timer
        {
            get
            {
                return _timer;
            }
            set
            {
                if (_timer != null)
                {
                    _timer.Tick -= Timer_Tick;
                }

                _timer = value;

                if (_timer != null)
                {
                    _timer.Tick += Timer_Tick;
                }
            }
        }
        #endregion

        #region Events
        public static event EventHandler UserActivity;
        #endregion

        #region Constructor

        #endregion

        #region Inherited Methods
        /// <summary>
        /// 
        /// </summary>
        public static void SetTimeOut()
        {
            // postpone auto-logout by 30 minutes
            _timer = new Timer
            {
                Interval = 500 // Timer set for 30 minutes
            };

            Application.Idle += Application_Idle;

            _timer.Tick += new EventHandler(Timer_Tick);
        }

        /// <summary>
        /// 
        /// </summary>
        public static void StopTimer()
        {
            // Stops the timer
            _timer.Stop();
        }

        #endregion

        #region Private Methods
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void Application_Idle(object sender, EventArgs e)
        {
            _timer.Stop();
            _timer.Start();
        }

        [DllImport("user32.dll")]
        static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);

        [StructLayout(LayoutKind.Sequential)]
        struct LASTINPUTINFO
        {
            public static readonly int SizeOf = Marshal.SizeOf(typeof(LASTINPUTINFO));

            [MarshalAs(UnmanagedType.U4)]
            public UInt32 cbSize;
            [MarshalAs(UnmanagedType.U4)]
            public UInt32 dwTime;
        }

        static uint GetLastInputTime()
        {
            uint idleTime = 0;
            LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
            lastInputInfo.cbSize = (uint)Marshal.SizeOf(lastInputInfo);
            lastInputInfo.dwTime = 0;

            uint envTicks = (uint)Environment.TickCount;

            if (GetLastInputInfo(ref lastInputInfo))
            {
                uint lastInputTick = lastInputInfo.dwTime;

                idleTime = envTicks - lastInputTick;
            }

            return ((idleTime > 0) ? (idleTime / 1000) : 0);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void Timer_Tick(object sender, EventArgs e)
        {
            if (GetLastInputTime() > 180)
            {
                _timer.Stop();
                Application.Idle -= Application_Idle;
                MessageBox.Show("Application Terminating");
                Application.Exit();
            }
        }
        #endregion
    }
}

Like if I want to stop the timer I need to call

 SetApplicationTimeOut.StopTimer();

and for starting the timer

SetApplicationTimeOut.SetTimeOut();

And if there is any moment simply it should reset the timer. How can I achieve this in static class?

Sandeep
  • 105
  • 1
  • 1
  • 14
  • What is not working in your code right now? – Pavel Anikhouski Jun 09 '20 at 16:08
  • If you see in my code it is not detecting the mouse movements, and key strokes. Whenever there is a movement it has to reset the timer like _timer.Stop(); _timer.Start();. – Sandeep Jun 09 '20 at 16:35
  • [GetLastInputInfo](https://www.pinvoke.net/default.aspx/user32.getlastinputinfo) –  Jun 09 '20 at 16:56
  • @JQSOFT In this example it is detecting the idle time but not detecting any moments and resetting the timer. Thanks though. – Sandeep Jun 09 '20 at 18:06
  • Use the function shown there `GetLastInputTime()` in a Timert.Tick event and check for example `if (GetLastInputTime() > 180) { //do whatever you want... };` which means there were no activities (key press, mouse move, ...etc) in the last 3 minutes. You should detect the idle state of the **system** not your app. –  Jun 09 '20 at 18:37
  • [Here's](https://stackoverflow.com/q/13210142/10216583) some snippets... –  Jun 09 '20 at 18:50
  • @JQSOFT I have updated the code as you said but unfortunately it is not working either. – Sandeep Jun 09 '20 at 20:18
  • Why not define a global variable timer and bind all mouse events to a same method to reset the timer? – 大陸北方網友 Jun 10 '20 at 02:18
  • **Application-Wide:** You can implement the [IMessageFilter](https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.imessagefilter?view=netcore-3.1) interface to detect the keyboard and mouse messages and restart the timer. This won't work if you have your app minimized/not active while working on something else which means that the system is not idle. **System-Wde:** to reset the timer when the system exits the idle state. then you need to utilize the global mouse and keyboard low-level hooks. See [this](https://stackoverflow.com/a/604417/10216583) for the keyboard part. –  Jun 11 '20 at 10:22

0 Answers0