Dienstag, 4. Mai 2010

Inaktivität des Anwenders über TIMEOUT prüfen / Using TIMEOUT to check user inactivity

Eine unangenehme Eigenschaft von VFP ist, dass eine Applikation, die aus einer EXE heraus gestartet wurde, solange für Updatevorgänge gesperrt bleibt, bis die aufrufende EXE beendet wird.

Jetzt stellt dies nicht wirklich ein Problem dar, denn üblicherweise genügt es, den Anwender zu informieren, das Programm für einen Updatevorgang zu beenden.

Dieser Gedankengang hat allerdings einen kleinen Haken, den Murphy sich nur zu gerne zu Nutzen macht. In einigen Fällen ist der Anwender, der eine Applikation sperrt, gerade nicht an seinem Arbeitsplatz...

Damit unsere Anwendung von sich aus feststellen kann, ob der Anwender eine 'Denkpause' eingelegt hat, benötigen wir eine systemweite Prüfung auf Aktivitäten bzw. in unserem Fall auf Inaktivitäten. Ist bspw. über einen Zeitraum von 15 Minuten keine Benutzereingabe erfolgt, dann können wir mit unserem Programm reagieren, und eine zeitgesteuerte Messagebox einblenden. Welche wiederum nach Ablauf ihres Timeouts ggf. das automatische und geordnete Beenden unserer Anwendung durchführen kann.

Im u.a. Beispiel wird mit einer PUBLIC Variablen gearbeitet. Alternativ kann das Objekt auch in einer Applikationsproperty erzeugt werden. Wichtig ist auf jeden Fall, dass der Timer jederzeit erreichbar ist.

Der Timer kann mit zwei Parametern versehen werden.
Parameter 1 definiert den Timeout Zeitraum in Minuten
Parameter 2 gibt den Timerzyklus in Sekunden vor

Wer die Parameter nicht nutzen möchte kann natürlich die entsprechenden Eigenschaften sozusagen 'ab Werk' vorbesetzen.

* // Funktionstext                                                    
CLEAR 
PUBLIC goTimer as Timer
* // 1 minütiger Timeout mit 15 Sekunden Prüfinterval                
* // Zum Beenden im Befehlsfenster 'Release goTimer' eingeben        
goTimer = CREATEOBJECT( [InactivityTimer] , 1 , 15 )

* // Bemerkt Benutzeraktivitäten und feuert ein Ereignis, nachdem    
* // der definierte Zeitraum für Inaktivität überschritten wurde.    
DEFINE CLASS InactivityTimer as Timer 

    * // Deklaration der API Konstanten                                
    #DEFINE WM_KEYUP        0x0101
    #DEFINE WM_SYSKEYUP     0x0105
    #DEFINE WM_MOUSEMOVE    0x0200
    #DEFINE GWL_WNDPROC     (-4)

    * // Interne Eigenschaften setzen und Timer setzen (5Sek.)        
    _iTimeoutInMinutes      = 0
    _tLastActivity          = {/:}
    Interval                = 5000
    Enabled                 = .T.

    * // Auf API Ereignisse horchen sobald die Form gestartet wurde    
    * // Optional wird ein Timeout Wert als Parameter übergeben        
    * // Zusätzlich kann als weiterer Parameter der Prüfinterval in    
    * // Sekunden übergeben werden.                                    
    PROCEDURE Init ( vTimeoutInMinutes as Integer , vIntervalInSeconds as Integer )

        WITH This
            ._iTimeoutInMinutes  = EVL( vTimeoutInMinutes , 1 )
            .Interval            = EVL( vIntervalInSeconds , 5 ) * 1000
            ._tLastActivity      = DATETIME()
        ENDWITH 
        BINDEVENT( 0 , WM_KEYUP ,     This , [WndProc] )
        BINDEVENT( 0 , WM_SYSKEYUP ,  This , [WndProc] )
        BINDEVENT( 0 , WM_MOUSEMOVE , This , [WndProc] )

    ENDPROC 

    * // mit dem Lauschen aufhören                                    
    PROCEDURE Unload 

        UNBINDEVENTS( 0 , WM_KEYUP )
        UNBINDEVENTS( 0 , WM_SYSKEYUP )
        UNBINDEVENTS( 0 , WM_MOUSEMOVE )

    ENDPROC 

    * // Jedes Ereignis zählt als Aktivität...                        
    PROCEDURE WndProc ( hWnd as Long, Msg as Long, wParam as Long, lParam as Long )

        This._tLastActivity = DATETIME()

    ENDPROC 

    * // Letzte Aktivität mit Timeout abgleichen                    
    PROCEDURE Timer

        WITH This
            LOCAL ltFireEvent as Datetime 
            ltFireEvent = ._tLastActivity + ( 60 * ._iTimeoutInMinutes )
            IF DATETIME() >= ltFireEvent
                .eventTimeout()
            ENDIF
        ENDWITH  

    ENDPROC 

    * // Diese Methode über BINDEVENT übersteuern oder enthaltenen    
    * // Code überschreiben...                                        
    * // Bspw. kann hier der Wert von iTimeoutInMinutes überschrie-    
    * // ben werden um einen mehrstufigen Timeout zu ermöglichen    
    PROCEDURE eventTimeout

        MESSAGEBOX( [<<< TIMEOUT >>>] , 0 , [Inaktiv] )

    ENDPROC 

ENDDEFINE 

Keine Kommentare:

Kommentar veröffentlichen