简体   繁体   English

WPF:应用程序空闲时间

[英]WPF: application Idle Time

I need to count the idle time of my WPF application (Idle time = when no keyboard input,mouse input (movement + clicks ) had occurred ). 我需要计算我的WPF应用程序的空闲时间(空闲时间=没有键盘输入,鼠标输入(移动+点击))。 So far I tried 2 approaches but none of them seem to be working: 到目前为止,我尝试了两种方法,但似乎没有一种方法可行:

  1. Using the dispatcher to invoke a delegate each time it get a contextIdle priority, the problem is that binding and many other operations invoke it and thus I can't really use that. 使用调度程序在每次获取contextIdle优先级时调用委托,问题是绑定和许多其他操作调用它,因此我不能真正使用它。
  2. using the input manager I registered to the "System.Windows.Input.InputManager.Current.PostProcessInput" event and each time it was invoked I restarted the idle time count. 使用我在“System.Windows.Input.InputManager.Current.PostProcessInput”事件中注册的输入管理器,每次调用它时,我重新启动空闲时间计数。 The second approach seemed promising but the problem is that when the mouse is over the application (it has focus) I keep getting the event. 第二种方法似乎很有希望,但问题是,当鼠标在应用程序上方(它有焦点)时,我不断得到这个事件。

Any Other ideas? 还有其他想法吗? or maybe a way to modify the 2nd solution to work? 或者可能是修改第二个解决方案的方法?

I solved the problem using a few different techniques rolled up to give me a pretty good solution. 我用一些不同的技术解决了这个问题,为我提供了一个很好的解决方案。 I use GetLastInput to work out when the system was last touched This is well documented elsewhere, but here's my method: 我使用GetLastInput来解决系统上次触摸的问题这在其他地方有详细记载,但这是我的方法:

public static class User32Interop
{
    public static TimeSpan GetLastInput() 
    { 
        var plii = new LASTINPUTINFO();
        plii.cbSize = (uint)Marshal.SizeOf(plii); 
        if (GetLastInputInfo(ref plii))       
            return TimeSpan.FromMilliseconds(Environment.TickCount - plii.dwTime); 
        else       
            throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); 
    }

    [DllImport("user32.dll", SetLastError = true)]
    static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
    struct LASTINPUTINFO { 
        public uint cbSize; 
        public uint dwTime;   
    }
}

This only tells me when the system has been idle, not the application. 这只告诉我系统何时处于空闲状态,而不是应用程序。 If the user clicks into Word and works there for an hour, I still want a timeout. 如果用户点击Word并在那里工作了一个小时,我仍然想要超时。 To handle this case, I simply remember when my application loses focus by overriding the OnDeactivated and OnActivated methods on the application object: 为了处理这种情况,我只记得当我的应用程序通过覆盖应用程序对象上的OnDeactivated和OnActivated方法而失去焦点时:

    override protected void OnDeactivated(EventArgs e)
    {
        this._lostFocusTime = DateTime.Now;
        base.OnDeactivated(e);
    }

    protected override void OnActivated(EventArgs e)
    {
        this._lostFocusTime = null;
        base.OnActivated(e);
    }

My IsIdle routine was added to the application object. 我的IsIdle例程已添加到应用程序对象中。 It handles the global case where the app has focus but nothing happened (IsMachineIdle) and the specific case where the application lost focus while the user is doing other stuff (isAppIdle ): 它处理应用程序具有焦点但未发生任何事情的全局情况(IsMachineIdle)以及应用程序在用户执行其他操作时失去焦点的特定情况(isAppIdle):

    public bool IsIdle
    {
        get
        {
            TimeSpan activityThreshold = TimeSpan.FromMinutes(1);
            TimeSpan machineIdle = Support.User32Interop.GetLastInput();
            TimeSpan? appIdle = this._lostFocusTime == null ? null : (TimeSpan?)DateTime.Now.Subtract(_lostFocusTime.Value);
            bool isMachineIdle = machineIdle > activityThreshold ;
            bool isAppIdle = appIdle != null && appIdle > activityThreshold ;
            return isMachineIdle || isAppIdle;
        }
    }

The last thing I did was create a timer loop that polled this flag event few seconds. 我做的最后一件事是创建一个定时器循环,在几秒钟内轮询这个标志事件。

This seems to work fine. 这似乎工作正常。

Well no one seemed to answer so I continued digging and found a relatively simple solution using the OS last input + up time. 好吧没有人回答所以我继续挖掘并找到一个相对简单的解决方案,使用操作系统最后输入+运行时间。 the code is really simple but this solution make me do data polling which I never recommend and also instead of being in the application level it's in the OS level which is not the exact solution I needed. 代码非常简单但是这个解决方案让我进行数据轮询,这是我从不推荐的,而且不是在应用程序级别,而是在操作系统级别,这不是我需要的确切解决方案。 If someone ever opens this thread this is the code, just use GetIdleTime(): 如果有人打开这个线程这是代码,只需使用GetIdleTime():

 public class IdleTimeService
{
    //Importing the Dll & declaring the necessary function
    [DllImport("user32.dll")]
    private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);


    /// <summary>
    /// return the current idle time (in ms)
    /// </summary>
    /// <returns>current idle time in ms</returns>
    public static int GetIdleTime()
    {

        //Creating the object of the structure
        LASTINPUTINFO lastone = new LASTINPUTINFO();

        //Initialising  
        lastone.cbSize = (uint)Marshal.SizeOf(lastone);
        lastone.dwTime = 0;

        int idleTime = 0;

        //To get the total time after starting the system.
        int tickCount = System.Environment.TickCount;

        //Calling the dll function and getting the last input time.
        if (GetLastInputInfo(ref lastone))
        {
            idleTime = tickCount - (int)lastone.dwTime;
            return idleTime;
        }
        else
            return 0;
    }


}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM