Page 1 of 1

How to detect user is inactive

Posted: Thu Aug 23, 2018 1:21 pm
by LogicG8
I am attempting to change screens based on system state and whether a user has interacted with the display within a period of time. I have not found a way to detect user inactivity.

I am using a T7A and have tried using GetLastInputInfo and SetWindowsHookEx P/Invokes without success (code below).

The GetLastInputInfo implementation works on my PC when user32.dll is specified and crashes on the T7A. The delegate does not get run when the touch screen is touched with the SetWindowsHookEx attempt.

Have I done something wrong with either implementation or is there an alternate method, maybe hooking into power management or getting an event when the "Automatically turn off backlight" feature activates that can be used instead?

Code: Select all

	public partial class ScreenSaver
	{
		public delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);
	
		private const int WH_MOUSE_LL = 14;
		private const UInt32 activity_timeout = 10 * 60 * 1000; // 10 minutes

		private static System.Threading.Timer idle = null;
		private static HookProc hookDelegate;
		private static IntPtr hookId = IntPtr.Zero;
		private static UInt32 timestamp = 0;

		// Poll activity and show screensaver screen when idle
		private static void enter(Object state)
		{
			UInt32 dt = (UInt32)Environment.TickCount - timestamp;
			if (dt >= system_timeout) {
				// Show screensaver
			}
		}

		public void leave()
		{
			// Stop showing screensaver
		}

		// Setup timer and hook to monitor user activity
		void ScreenSaver_Created(System.Object sender, System.EventArgs e)
		{
			hookDelegate = new HookProc(HookProcedure);
			hookId = SetWindowsHookEx(WH_MOUSE_LL, hookDelegate, IntPtr.Zero, 0);
			idle = new System.Threading.Timer(enter, null, 10000, 10000);
		}

		// Record user activity and pass processing on
		private IntPtr HookProcedure(int code, IntPtr wParam, IntPtr lParam)
		{
			timestamp = (UInt32)Environment.TickCount;
			return CallNextHookEx(hookId, code, wParam, lParam);
		}

		[DllImport("coredll.dll")]
		private static extern IntPtr GetModuleHandle(string mod);
		[DllImport("coredll.dll")]
		private static extern IntPtr SetWindowsHookEx(
			int type, HookProc hookProc, IntPtr hInstance, int m);
		[DllImport("coredll.dll")]
		private static extern IntPtr CallNextHookEx(
			IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
	}

	public partial class ScreenSaver
	{
		private const UInt32 activity_timeout = 10 * 60 * 1000; // 10 minutes

		private static System.Threading.Timer idle = null;

		// Time since the last input time in milliseconds
		private static UInt32 lastTouch()
		{
			UInt32 dt = 0; // Make input time delta zero on failure

			LASTINPUTINFO last = new LASTINPUTINFO();
			last.cbSize = (uint)Marshal.SizeOf(last);
			if (GetLastInputInfo(ref last)) {
				dt = (UInt32)Environment.TickCount - last.dwTime;
			}
	
			return dt;
		}
		
		// Poll activity screensaver screen if idle
		private static void enter(Object state)
		{
			if (lastTouch() >= activity_timeout) {
				// Show screensaver
			}
		}

		public void leave()
		{
			// Stop showing screensaver
		}

		void ScreenSaver_Created(System.Object sender, System.EventArgs e)
		{
			// Check if idle once per 10 seconds starting 10 seconds from now
			idle = new System.Threading.Timer(enter, null, 1000, 1000);
		}

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

		[StructLayout( LayoutKind.Sequential )]
		struct LASTINPUTINFO
		{
			[MarshalAs(UnmanagedType.U4)]
			public uint cbSize;
			[MarshalAs(UnmanagedType.U4)]
			public UInt32 dwTime;
		}
	}

Re: How to detect user is inactive

Posted: Wed Sep 05, 2018 9:54 am
by Russ C.
If you're requiring users to login, there is a setting to do this in the Security -> Settings -> General
user-inactivity.png
user-inactivity.png (34.84 KiB) Viewed 5094 times
This will not switch screens, but if you add the SystemSecond and SystemCurrentLoggedinUser tags you can do a check every second that says if the user == "" (logged out) then show screen X