2010-07-20 110 views
10

我需要計算我的WPF應用程序的空閒時間(空閒時間=當沒有鍵盤輸入,鼠標輸入(移動+點擊)發生時)。 到目前爲止,我嘗試過2個辦法,但他們都不是工作:WPF:應用程序空閒時間

  1. 使用調度每次它得到contextIdle優先調用委託,問題是結合等多項操作調用它,從而我無法真正使用它。
  2. 使用輸入管理器我註冊到「System.Windows.Input.InputManager.Current.PostProcessInput」事件和每次它被調用我重新啓動空閒時間計數。 第二種方法看起來很有前途,但問題在於,當鼠標懸停在應用程序上(它有焦點)時,我不斷收到事件。

任何其他想法?或者可能是修改第二個解決方案的方法?

回答

13

我用了幾個不同的技術捲起給我一個很好的解決方案解決了這個問題。我用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; 
    } 
} 

這只是告訴我,當系統處於空閒狀態,而不是應用程序。如果用戶點擊進入Word並在那裏工作一個小時,我仍然想要超時。爲了處理這種情況下,我只記得當我的應用程序通過重寫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); 
    } 

我IsIdle程序添加到應用程序對象。它可以處理其中的應用程序具有焦點,但什麼都沒有發生(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; 
     } 
    } 

我做的最後一件事是創建一個定時器循環,幾秒鐘內輪詢該標誌事件。

這似乎工作正常。

+0

請記住,_lostFocusTime應該聲明爲DateTime?變量。如果您試圖聲明爲DateTime,則不能將該值清空。 – Saren 2013-12-09 17:13:33

+0

Environment.TickCount具有int類型,並且每24.9天被強制包裝。 LASTINPUTINFO.dwTime具有類型uint,所以它不會換到49.7天。如果機器運行時間超過24.9天,則示例中的數學問題被搞砸了。我通過調用WINAPI函數GetTickCount替換Environment.TickCount來緩解該問題,該函數也返回一個uint值。我不確定如果上次輸入的時間是49.5天,並且當前的滴答計數是50.0天,會發生什麼情況。 [根據另一個問題的這個答案](http://stackoverflow.com/a/1078089/2998072)它應該沒問題。 – 2016-11-02 00:50:27

5

好吧,似乎沒有人回答,所以我繼續挖掘,並找到一個相對簡單的解決方案,使用操作系統上次輸入+時間。代碼非常簡單,但是這個解決方案使我可以進行數據輪詢,這是我從來不推薦的,也不是在應用程序級別,而是在操作系統級別,而不是我需要的確切解決方案。 如果有人打開過這個線程這是代碼,只需使用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; 
    } 


} 
+0

你好,我試圖解決你原來的問題,並找到你的解決方案時遇到同樣的問題:它是系統範圍。你最終研究出瞭如何進行應用程序範圍的空閒檢測? – dave 2011-04-11 07:39:00

+0

不是真的,我仍然堅持系統解決方案,但如果你以某種方式找到解決方案,它會很好,如果你可以發佈它。 – Clueless 2011-04-13 08:37:23

+0

我添加了我的解決方案作爲答案。如果您有任何問題或者您認爲它很愚蠢,請給我一個ping。 – dave 2011-04-15 05:56:12