sternr
sternr

Reputation: 6506

How Windows Decides to show the screensave

Windows has an internal mechanism that decides when to show the screensaver (or shut the screen off) by checking for user interactivity and other tasks (someone's watching a video, etc.).

Is there an Win API that allows me to ask whether or not the user is active, or when was the last time they were active?

Upvotes: 2

Views: 980

Answers (2)

Hans Passant
Hans Passant

Reputation: 941287

It is called the "idle timer". You can get its value by pinvoking CallNtPowerInformation(), asking for SystemPowerInformation. The returned SYSTEM_POWER_INFORMATION.TimeRemaining field tells you how much time is left on the idle timer. The SystemExecutionState request tells you if any thread has called SetThreadExecutionState() to stop the timer, as is done by apps that show videos.

using System;
using System.Runtime.InteropServices;

public static class PowerInfo {
    public static int GetIdleTimeRemaining() {
        var info = new SYSTEM_POWER_INFORMATION();
        int ret = GetSystemPowerInformation(SystemPowerInformation, IntPtr.Zero, 0, out info, Marshal.SizeOf(info));
        if (ret != 0) throw new System.ComponentModel.Win32Exception(ret);
        return info.TimeRemaining;
    }

    public static int GetExecutionState() {
        int state = 0;
        int ret = GetSystemExecutionState(SystemExecutionState, IntPtr.Zero, 0, out state, 4);
        if (ret != 0) throw new System.ComponentModel.Win32Exception(ret);
        return state;
    }

    private struct SYSTEM_POWER_INFORMATION {
        public int MaxIdlenessAllowed;
        public int Idleness;
        public int TimeRemaining;
        public byte CoolingMode;
    }
    private const int SystemPowerInformation = 12;
    private const int SystemExecutionState = 16;
    [DllImport("powrprof.dll", EntryPoint = "CallNtPowerInformation", CharSet = CharSet.Auto)]
    private static extern int GetSystemPowerInformation(int level, IntPtr inpbuf, int inpbuflen, out SYSTEM_POWER_INFORMATION info, int outbuflen);
    [DllImport("powrprof.dll", EntryPoint = "CallNtPowerInformation", CharSet = CharSet.Auto)]
    private static extern int GetSystemExecutionState(int level, IntPtr inpbuf, int inpbuflen, out int state, int outbuflen);

}

Upvotes: 6

Matt Sieker
Matt Sieker

Reputation: 9625

You should have a look at the GetLastInputInfo function, which returns a structure containing the tick count from the last user input, one tick being 1ms. You can then compare this to the value returend by Environment.TickCount to get the elapsed time in milliseconds since the last user input.

A P/Invoke definition for this function is available here: http://www.pinvoke.net/default.aspx/user32.GetLastInputInfo

Be aware though, that the tick value returned by GetLastInputInfo wraps back to zero just short of 50 days, but Environment.TickCount wraps just short of 25 days, due to the value returned by GetLastInputInfo being an unsigned int, and TickCount being signed. In most cases this probably won't be much of an issue, but it is worth keeping in mind that there might occasionally be somewhat odd behavior, on the order of once a month.

Upvotes: 0

Related Questions