2010-07-20 26 views
10

Necesito contar el tiempo de inactividad de mi aplicación WPF (tiempo de inactividad = cuando no se introdujo el teclado, se introdujo el mouse (movimiento + clic)). Hasta ahora he intentado 2 enfoques, pero ninguno de ellos parece estar funcionando:WPF: tiempo de inactividad de la aplicación

  1. Utilizando el despachador para invocar un delegado cada vez que se consigue una prioridad contextIdle, el problema es que si se entrelazan y muchas otras operaciones de la invocan y por lo tanto Realmente no puedo usar eso.
  2. usando el administrador de entrada que registré en el evento "System.Windows.Input.InputManager.Current.PostProcessInput" y cada vez que se invocaba reiniciaba el recuento de tiempo de inactividad. El segundo enfoque parecía prometedor, pero el problema es que cuando el mouse está sobre la aplicación (tiene foco) sigo obteniendo el evento.

¿Alguna otra idea? o tal vez una forma de modificar la segunda solución para que funcione?

Respuesta

13

me resolvió el problema utilizando algunas técnicas diferentes enrolladas que me diera una solución bastante buena. Yo uso GetLastInput a trabajar a cabo cuando el sistema fue tocado por último Esto está bien documentado en otros lugares, pero aquí está mi método:

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; 
    } 
} 

Esto sólo me dice que cuando el sistema ha estado inactivo, no de la aplicación. Si el usuario hace clic en Word y trabaja allí durante una hora, todavía quiero un tiempo de espera. Para manejar este caso, simplemente me acuerdo cuando mi aplicación pierde el foco reemplazando el OnDeactivated y OnActivated métodos en el objeto de aplicación: se añadió

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); 
    } 

Mi rutina IsIdle al objeto de aplicación. Maneja el caso global, donde la aplicación tiene el foco, pero no pasó nada (IsMachineIdle) y el caso específico en el que la aplicación pierde foco mientras que el usuario está haciendo otras cosas (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; 
     } 
    } 

Lo último que hice fue crear un bucle de temporizador que sondeó este evento de bandera unos segundos.

Esto parece funcionar bien.

+0

Tenga en cuenta que _lostFocusTime debe declararse como DateTime? variable. Si intenta declarar como DateTime, no puede NULL el valor. – Saren

+0

Environment.TickCount tiene tipo int, y se ve obligado a ajustar cada 24,9 días. LASTINPUTINFO.dwTime tiene type uint, por lo que no se ajusta hasta 49.7 días. Si la máquina ha estado encendida durante más de 24.9 días, entonces las matemáticas en el ejemplo están arruinadas. Alivié el problema reemplazando Environment.TickCount con una llamada a la función WINAPI GetTickCount, que también devuelve un valor de uint.No estoy seguro de lo que sucede si la última entrada fue a 49.5 días y el conteo de ticks actual es de 50.0 días. [Según esta respuesta a otra pregunta] (http://stackoverflow.com/a/1078089/2998072) debería estar bien. –

5

Bueno, parece que nadie respondió, así que continué cavando y encontré una solución relativamente simple utilizando el último tiempo de entrada y salida del sistema operativo. el código es realmente simple, pero esta solución me hace hacer un sondeo de datos que nunca recomiendo y, además, en lugar de estar en el nivel de aplicación, está en el nivel del sistema operativo, que no es la solución exacta que necesitaba. Si alguna vez alguien abre este hilo de esto es el código, sólo tiene que utilizar 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

Hola, estoy tratando de resolver su problema original y resolver el mismo problema que encontró con su solución: es todo el sistema. ¿Finalmente resolvió cómo hacer la detección inactiva en toda la aplicación? – dave

+0

No realmente, todavía estoy atascado con la solución del sistema, pero si de alguna manera encuentras la solución sería genial si puedes publicarla. – Clueless

+0

Agregué mi solución como una respuesta. Dame un ping si tienes algún problema o si crees que es estúpido. – dave

Cuestiones relacionadas