Uygulamanın Idle Modunu Yakalamak(C#, VB.NET)

C#, VB.NET, ASP.NET Add comments

“Idle” kavramı, bir uygulamanın tüm işlerini(process) bitirip atıl moda geçmesini temsil eder. Aynı kavram, işletim sistemleri için de kullanılarak işletim sisteminin tüm işlemlerini bitirip bekleme moduna geçmesi anlamına gelir. Birçoğumuzun kullandığı GTalk programında uzun süren bir hareketsizlik olduğu zaman kullanıcı idle durumuna geçirilir. Programımızın atıl durumdayken bazı özel işler yapmasını sağlamak için Idle olayı kullanılır. Programın atıl durumda olması demek, üzerinde herhangi bir klavye, mouse hareketi olmadığı için arka tarafta da kuyrukta herhangi bir processin işlenmiyor veya beklenmiyor olmasıdır. Kısacası programın tamamen, durağan moda geçmesidir. Windows uygulamaları, ne zaman Idle moduna geçtiklerini bilecek yeteneğe sahiptir. Özellikle gelişmiş programlama dillerinde uygulamanın Idle modunu yakalamak için belli componentler sunulur. Bu amaçla VB.NET, C# tarafında Windows formunu temsil eden Application nesnesinin Idle eventi mevcuttur. Uygulama tüm processlerini bitirip hareketsiz duruma geçtiği anda bu event tetiklenir. Bu event, herhangi bir kontrol tarafından değil doğrudan Windows tarafından tetiklenir.
Application.Idle eventini kullanmak çok kolay. Bunun için uygulama içerisinde bu event dolayısıyla çalışacak bir metod tanımlanır ve bu metodu delege aracılığıyla Idle eventine bağlanılır. Bu işlemi Main() metodu içerisinde yapabileceğimiz gibi formun Load() metodu içerisinde de yapabiliriz.

int Sayac = 0;
private void Form1_Idle(object sender, System.EventArgs e)
{
    Sayac++;
    this.Text = "Sayaç : "+ Sayac.ToString();
}//Form1_Idle

private void Form1_Load(object sender, System.EventArgs e)
{
    Application.Idle +=new EventHandler(Form1_Idle);
}//Form1_Load
Private Sayac As Integer = 0
Private Sub Form1_Idle(ByVal sender As Object, ByVal e As System.EventArgs)
    Sayac = Sayac + 1
    Me.Text = "Sayaç :" & Sayac.ToString()
End Sub 'Form1_Idle

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
    AddHandler Application.Idle, New EventHandler(AddressOf Form1_Idle)
End Sub 'Form1_Load

Idle olayını test etmek için programın Titlebar’ından bir süre sabit tutalım. Bu sürede sayaçın sabitlendiğini yani Idle modundan çıktığını görmüş oluruz.

Idle eventinin en çok kullanıldığı alanlardan biri, virtual-key olarak tanımlanan karakterlerin (yön tuşları, PageDown ,PageUp, End, Home, NumLock, CapsLock . . .) durumunun denetlenmesi ve programın ne kadar uzun süredir hareketsiz kaldığının tespit edilmesidir. Örneğin kullanıcının CapsLock’ı açıp açmadığını veya Delete tuşunun basılıp basılmadığını denetlemek isteyebiliriz. Virtual-key’lerin özelliği ASCII kodlarının olmamasıdır. Özellikle CapsLock, NumLock tuşlarının durumunu uygulama içerisinde öğrenmek için Idle() metodunu kullanılır. Bu amaç için user32.dll kütüphanesinin GetKeyState API’si kullanılır. Bu fonksiyon, hexidecimal türünde parametre olarak aldığı tuşun basılı olup olmadığını döndürür. Uygulamamızda DllImport’u kullanmak için using System.Runtime.InteropServices namespace’yi import etmeliyiz.

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
    InitializeComponent();
}

//user32.dll kütüphanesini import edip GetKeyState() metodunu çağıralım
[DllImport("user32.dll")]
extern static int GetKeyState(int key);

string FormTitle = "";
public void Form1_Idle(object sender, EventArgs e)
{
    FormTitle = "";
    if (GetKeyState('\x14') == 1)
		FormTitle += "CAPS ";//CapsLock açık
	else
		FormTitle += "";

    if (GetKeyState('\x90') == 1)
        FormTitle += "NUM ";//NumLock açık
    else
        FormTitle += "";

    if (GetKeyState('\x91') == 1)
        FormTitle += "SCRL ";//ScrollLock açık
    else
        FormTitle += "";

    this.Text = FormTitle;
}//OnIdle

private void Form1_Load(object sender, EventArgs e)
{
    Application.Idle += new EventHandler(Form1_Idle);
}//Form1_Load

}//Form1

}//WindowsApplication1
Imports System.Runtime.InteropServices

Public Class Form1

    'user32.dll kütüphanesini import edip GetKeyState() metodunu çağıralım
     _
    Shared Function GetKeyState(ByVal key As Integer) As Integer
    End Function

    Dim FormTitle As String = ""

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        AddHandler Application.Idle, New EventHandler(AddressOf Form1_Idle)
    End Sub 'Form1_Load

    Private Sub Form1_Idle(ByVal sender As Object, ByVal e As System.EventArgs)
        FormTitle = ""
        If GetKeyState(&H14) = 1 Then
            FormTitle &= "CAPS " 'CapsLock açık
        Else
            FormTitle &= ""
        End If

        If GetKeyState(&H90) = 1 Then
            FormTitle &= "NUM " 'NumLock açık
        Else
            FormTitle &= ""
        End If

        If GetKeyState(&H91) = 1 Then
            FormTitle &= "SCRL " 'ScrollLock açık
        Else
            FormTitle &= ""
        End If

        Me.Text = FormTitle
    End Sub 'Form1_Idle

End Class

Idle modunda ihtiyaç duyulan diğer konu da uygulamanın ne kadar süredir Idle modunda olduğudur. Bunu en doğru Windows’tan öğrenebiliriz. Bunun için aynı şekilde user32.dll kütüphanesi kullanılır. Bu kütüphanenin GetLastInputInfo() fonksiyonu, uygulamaya yapılmış en sonki input zamanını döndürür. Uygulamanın ne kadar süredir Idle modunda olduğunu öğrenmek için uygulamanın açık kaldığı süreden Idle modunda geçtiği andaki süreyi çıkarılır. Uygulamanın ne kadar süredir açık olduğu bilgisini System.Environment sınıfının TickCount property’siyle öğrenilebilir. Bu değerler millisaniye cinsindedir. Formun üzerindelabel1 isminde bir Label nesnesi ve bu nesneyi belli sürede güncellemek için tmrCheckIdleTime isminde bir Timer nesnesi kullanacağız.

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
    InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
    tmrCheckIdleTime.Start();
}//Form1_Load

internal struct LASTINPUTINFO
{
    public uint cbSize;
    public uint dwTime;
}//LASTINPUTINFO

[DllImport("user32.dll")]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);

int idleTime = 0;
LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
int lastInputTick;
int envTicks;

private void tmrCheckIdleTime_Tick(object sender, EventArgs e)
{
    lastInputInfo.cbSize = (uint)Marshal.SizeOf(lastInputInfo);
    lastInputInfo.dwTime = 0;

    envTicks = Environment.TickCount;//Toplam geçen süre

    if (GetLastInputInfo(ref lastInputInfo))
    {
        lastInputTick = (int)lastInputInfo.dwTime;
        //En son yapılmış input'un time değeri

        idleTime = envTicks - lastInputTick;
    }
    label1.Text = "Toplam geçen süre : " + envTicks.ToString()
        + "\n Last input time : " + lastInputTick
        + "\n Idle süresi :" + idleTime;
}//tmrCheckIdleTime_Tick

}//Form1

}//WindowsApplication1
Public Class Form1

    Structure LASTINPUTINFO
        Public cbSize As System.UInt32
        Public dwTime As System.UInt32
    End Structure 'LASTINPUTINFO

     _
    Shared Function GetLastInputInfo(ByRef plii As LASTINPUTINFO) As Boolean
    End Function

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        tmrCheckIdleTime.Start()
    End Sub 'Form1_Load

    Dim idleTime As Integer = 0
    Dim lastInputInf As LASTINPUTINFO = New LASTINPUTINFO()
    Dim lastInputTick As Integer
    Dim envTicks As Integer

    Private Sub tmrCheckIdleTime_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrCheckIdleTime.Tick
        lastInputInf.cbSize = Marshal.SizeOf(lastInputInf)
        lastInputInf.dwTime = 0

        envTicks = Environment.TickCount 'Toplam geçen süre

        If GetLastInputInfo(lastInputInf) Then
            lastInputTick = CInt(lastInputInf.dwTime)
            'En son yapılmış input'un time değeri

            idleTime = envTicks - lastInputTick
        End If
        Label1.Text = "Toplam geçen süre : " & envTicks.ToString() & Chr(10) & " Last input time : " & lastInputTick.ToString() & Chr(10) & " Idle süresi :" & idleTime.ToString()
    End Sub

End Class


Bu örneği biraz daha geliştirip uygulamanın, belirlenecek süre kadar Idle moduna beklemesi durumunda bilgisayar lock edebiliriz. Bunun için User32.dll kütüphanesinin LockWorkStation() metodu kullanılabilir.

NOT : Managed code içerisinde hangi API’leri nasıl kullanacağımız konusunda http://pinvoke.net sitesi iyi bir doküman sunmaktadır.

4 Responses to “Uygulamanın Idle Modunu Yakalamak(C#, VB.NET)”

  1. Hüseyin KÜÇÜK Says:

    Güzel makale..

  2. Zaim AKINÖZ Says:

    Her makalene tek tek çok güzelmiş yazmak uzun süreceğinden, buraya yazıyorum: “Sitedeki tüm makalelerin çok faydalı, seni tebrik ediyor ve başarılarının devamını diliyorum.”

  3. Hakan Fatih YILDIRIM Says:

    Gercekten cok faydalı ve acıklaması cok güzel basarılar dilerim.Aynen devam.

    Hakan Fatih YILDIRIM
    MCP

  4. goksenin Says:

    Çok işime yaradı gerçekten başarılı bir makale.Başarılarının devamını dilerim

Leave a Reply

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Giriş