Makale Özeti

Bu makalemizde DirectX'in kullanıcılar ile etkileşimi sağlayan Direct.Input sınıfını inceleyeceğiz. Ayrıca şimdiye kadar öğrendiğimiz DirectX mimarisi ile oluşturacağımız projeyi screen saver(ekran koruyucu) olarak tasarlayacağız.

Makale

DirectX Direct.Input Alt Yapısı

Bu makalemizde directX'in kullanıcılar ile etkileşimi sağlayan Direct.Input sınıfını inceleyeceğiz. Ayrıca şimdiye kadar öğrendiğimiz DirectX mimarisi  ile oluşturacağımız projeyi screen saver(ekran koruyucu) olarak tasarlayacağız.
Uzun süre sabit görüntü gösteren monitörlerde bir süre sonra görüntülerde bozukluk başlar. Bunun ana nedeni monitörde uzun süre aynı bölgenin aynı ışığı vermesidir. Bunun önlenmesi için ekran koruyucular tasarlanmıştır. Ekran koruyucuların görevi devamlı olarak aynı görüntünün monitör üzerinde kalıp monitörün kalıcı bir hasar almasını önlemektir. Ekran koruyucuların bir diğer faydası ise eğer ekran koruyucunuza parola girişi yaptıysanız, siz bilgisayarın başında değilken başka bir kişinin ilgili parolayı girmeden monitörü açamaması ve ekranda olabilecek önemli bilgileri okuyamaması, sizin adınıza kritik işlemler yapamamasıdır. Tüm ekran koruyucu programları WINDOWS\system32 dosyası altında .scr uzantılı olarak bulunurlar. Bir ekran koruyucu program kendini masaüstünde sağ tuşa basıp özellikler dedikten sonra ekran koruyucu bölümüne atması için kendini bilgisayarın kütüğüne kayıt etmesi gerekmektedir(register). Programlar bu işlemi yapabilmek için Start/Run/Regedit komutuyla sizin regedit üzerinden ellede yapabileceğiniz gibi HKEY_CURRENT_USER\Control Panel\Desktop.scrnsave.exe kayıdına kendi yollarını girmek zorundadırlar. Kendi yollarını girerkende yolu WINDOWS\system32 altına ve dosya uzantısı olarak da .scr olarak vermeleri gerekmektedir. Bu işlem yapıldıktan sonra ilgili program kendini ekran koruyucu olarak kaydetmiş olacaktır. Ekran koruyucu olarak bir programı ayarlayabilmek için programı tam ekran ve taskbar gözükmeyecek şekilde ayarlamak gerekmektedir. Ekran koruyucu herhangibir tuşa basıldığında ya da mouse koordinatları üzerinde bir değişiklik yapıldığında otomatik olarak kendini kapatacaktır. DirectX ile oluşturduğumuz yazılıma setup projesi ekletip setup projesinde yukarıdaki anlatılan işlemler yapıldığında, görüntü özelliklerine yazdığımız ekran koruyucunun eklenmiş olduğunu görebiliriz.

this.WindowState= FormWindowState.Maximized;
this.Text = "mehmet ali ecer";
ShowInTaskbar = false;
this.ShowIcon=false;
this.TopMost=true;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
 this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.ScreenSaverForm_MouseMove);
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ScreenSaverForm_KeyDown);

 

 

Bunun için ise program içerisinde mouse'da ya da klavyede bir işlem yapılıp yapılmadığı kontrol edilmelidir. Bu kontrol işleminde DirectX'in bize sunduğu Direct.Input uzayını kullanacağız. Direct.Input içerisinde kullanıcı ile etkileşimi sağlayan üç temel  giriş elemanını yönetirsiniz. Bunlar fare,klavye ve joystick'dir.  Bu giriş elemanları için şimdi Direct.Input alt yapısını tasarlayalım.

//klavye aygıtı
    keyboard = new Device(SystemGuid.Keyboard);
    if(keyboard == null)
        throw new Exception("Klavye aygıtı bulunamadı..");

//fare Aygıtı
    mouse = new Device(SystemGuid.Mouse);
    if(mouse == null)
    {
        throw new Exception("Fare aygıtı bulunamadı.");
    }

//joystick aygıtı
    foreach(
        DeviceInstance di in
        Manager.GetDevices(
        DeviceClass.GameControl,
        EnumDevicesFlags.AttachedOnly))
        {
            joystick = new Device(di.InstanceGuid);
            break;
        }

   if(joystick == null)
    {
    throw new Exception("joystick aygıtı bulunamadı.");
}
 

Bu üç temel bilgisayar giriş elemanı bilgisayar üzerinde başka yapılar tarafından kullanıldığı ya da kullanılabileceği için sistem kaynakları ayarlaması gerekmektedir. Bu üç aygıtın SetCooperativeLevel fonksiyonu ile CooperativeLevelFlags özellikleri verilmelidir.
 

Bu özelliklerle kaynağın nasıl kullanılacağını yönetir.

 CooperativeLevelFlags'leri;

CooperativeLevelFlags.Background Bu aygıt arka planda kullanılır, eğer program masaüstü üzerinde aktif bile olmasa gerektiğinde alınılır ve kullanılır.
CooperativeLevelFlags.Foreground Sadece çalışan ekran arka planında kullanılır.Eğer ekran seçim özelliğini yitirirse aygıtada erişim gider.
CooperativeLevelFlags.Exclusive Çok mecburi durumlarda kullanılır. Kaynağı tek başına kullanır ve başka istekleri reddeder. Fare ve klavye için bu bayrak kullanılamaz.
CooperativeLevelFlags.NonExclusive Aygıt diğer kaynaklarla paylaşılır.Paylaşılan durumlarda aygıt hemen alınamaz.
CooperativeLevelFlags.NoWindowsKey Window kısayollarını kapatır.

Aygıtların Flag'lere göre aygıtların SetCooperativeLevel ve duyarlıkları da ayarlanması aşağıdaki gibi yapılabilir.



foreach(DeviceObjectInstance doi in joystick.Objects)//Joystick duyarlığı ayarlanıyor.
{
    if((doi.ObjectId & (int)DeviceObjectTypeFlags.Axis) != 0)
    {
        joystick.Properties.SetRange(
        ParameterHow.ById,
        doi.ObjectId,
        new InputRange(-5000,5000));
}
}

joystick.Properties.AxisModeAbsolute = true;

keyboard.SetCooperativeLevel(
    this,
    CooperativeLevelFlags.NonExclusive |
    CooperativeLevelFlags.Background);

mouse.SetCooperativeLevel(
    this,
    CooperativeLevelFlags.NonExclusive |
    CooperativeLevelFlags.Background);

joystick.SetCooperativeLevel(
    this,
    CooperativeLevelFlags.NonExclusive |
    CooperativeLevelFlags.Background);

//Acquire devices for capturing.
keyboard.Acquire();
mouse.Acquire();
joystick.Acquire();
 

Üç temel giriş elemanını tanımladıktan sonra bu üç eleman üzerinden gelen girişleri yakalamak için bu aygıtların nasıl kullanılacağı aşağıda gösterilmiştir.

Klavye Girişleri İçin

    foreach(Key k in keyboard.GetPressedKeys())
    {
        info += k.ToString() + " ";
    }

Fare Girişleri İçin

MouseState state = mouse.CurrentMouseState;//fare konum koordinatlarını almak için

    info += "X:" + state.X + " ";
    info += "Y:" + state.Y + " ";
    info += "Z:" + state.Z + " ";
    byte[] buttons = state.GetMouseButtons();//fare üzerinde bulunan butonlar için
    for(int i = 0; i < buttons.Length; i++)
    {
        if(buttons[i] != 0)
        {
            info += "Button:" + i + " ";
        }
    }

Joystick Girişleri İçin

    JoystickState state = joystick.CurrentJoystickState;

    info += "X:" + state.X + " ";    //koordinat noktaları için
    info += "Y:" + state.Y + " ";
    info += "Z:" + state.Z + " ";

    //buton hareketleri
    byte[] buttons = state.GetButtons();
    for(int i = 0; i < buttons.Length; i++)
    {
        if(buttons[i] != 0)
        {
            info += "Button:" + i + " ";
        }
    }

Ayrıca Joystick için state içerisinde, Rx: X eksenine dönüş açısı, ARx: X eksenin dönüş ivmesi, AX: X ekseni ivmesi, FRx: X eksenine göre tork, FX: X ekseni hareket gücü, VRx: X ekseni açısal hız, VX: X ekseni hız bilgilerine ulaşılabilir.

Makale ya da kodlarda bulunan hatalar ya da sorularınız için mehmetaliecer@gmail.com adresinden bana ulaşabilirsiniz. İyi çalışmalar.

Mehmet Ali ECER

www.mehmetaliecer.com

using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
namespace CubeExample
{
    static class Program
    {
        public class Form1 : System.Windows.Forms.Form
        {
        private Device device = null;
        private VertexBuffer vb = null;
        private System.ComponentModel.Container components = null;
        private float angle = 0.0f;
        public Form1()
        {
        InitializeComponent();
        this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);
    }
    public void InitializeGraphics()
    {
        PresentParameters presentParams = new PresentParameters();
        presentParams.Windowed = true;
        presentParams.SwapEffect = SwapEffect.Discard;
        device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);
        vb = new VertexBuffer(typeof(CustomVertex.PositionColored), 36, device, Usage.Dynamic | Usage.WriteOnly, CustomVertex.PositionColored.Format, Pool.Default);
        vb.Created += new EventHandler(this.OnVertexBufferCreate);
        OnVertexBufferCreate(vb, null);
       }

    private void OnVertexBufferCreate(object sender, EventArgs e)
    {
    VertexBuffer buffer = (VertexBuffer)sender;
    CustomVertex.PositionColored[] verts = new CustomVertex.PositionColored[36];

verts[0] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Red.ToArgb());
verts[1] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, Color.Red.ToArgb());
verts[2] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Red.ToArgb());
verts[3] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, Color.Red.ToArgb());
verts[4] = new CustomVertex.PositionColored(1.0f, -1.0f, -1.0f, Color.Red.ToArgb());
verts[5] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Red.ToArgb());
verts[6] = new CustomVertex.PositionColored(-1.0f, 1.0f, 1.0f, Color.Blue.ToArgb());
verts[7] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Blue.ToArgb());
verts[8] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Blue.ToArgb());
verts[9] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Blue.ToArgb());
verts[10] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Blue.ToArgb());
verts[11] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Blue.ToArgb());
verts[12] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Yellow.ToArgb());
verts[13] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Yellow.ToArgb());
verts[14] = new CustomVertex.PositionColored(-1.0f, 1.0f, 1.0f, Color.Yellow.ToArgb());
verts[15] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Yellow.ToArgb());
verts[16] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Yellow.ToArgb());
verts[17] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Yellow.ToArgb());
verts[18] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, System.Drawing.Color.Black.ToArgb());
verts[19] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Black.ToArgb());
verts[20] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Black.ToArgb());
verts[21] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, Color.Black.ToArgb());
verts[22] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Black.ToArgb());
verts[23] = new CustomVertex.PositionColored(1.0f, -1.0f, -1.0f, Color.Black.ToArgb());
verts[24] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Gray.ToArgb());
verts[25] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Gray.ToArgb());
verts[26] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, Color.Gray.ToArgb());
verts[27] = new CustomVertex.PositionColored(-1.0f, 1.0f, 1.0f, Color.Gray.ToArgb());
verts[28] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Gray.ToArgb());
verts[29] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Gray.ToArgb());
verts[30] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Green.ToArgb());
verts[31] = new CustomVertex.PositionColored(1.0f, -1.0f, -1.0f, Color.Green.ToArgb());
verts[32] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Green.ToArgb());
verts[33] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Green.ToArgb());
verts[34] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Green.ToArgb());
verts[35] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Green.ToArgb());
    buffer.SetData(verts, 0, LockFlags.None);
}
private void SetupCamera()
{
    device.RenderState.Lighting = false;
    angle = angle + 0.01f;
    device.Transform.World=Matrix.RotationYawPitchRoll(angle,angle,angle);
    device.Transform.View = Matrix.LookAtRH( new Vector3(0.0f, 0.0f, -5.0f), new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f));
    device.Transform.Projection = Matrix.PerspectiveOffCenterRH(-1.0f * (float)this.Width /(float)this.Height, 1.0f * (float)this.Width / (float)this.Height, -1.0f, 1.0f, 1.0f, 100.0f);
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
    device.Clear(ClearFlags.Target, Color.CornflowerBlue, 1.0f, 0);
    SetupCamera();
    device.BeginScene();
    drawingFont.DrawText(60, 100, Color.Red, "GraphicsFont.DrawText");

    device.VertexFormat = CustomVertex.PositionColored.Format;
    device.SetStreamSource(0, vb, 0);
    device.DrawPrimitives(PrimitiveType.TriangleList,0, 12);
    device.EndScene();
    device.Present();
    this.Invalidate();
}

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
    if (components != null)
      {
        components.Dispose();
    }
}
base.Dispose(disposing);
}

#region Windows Form Designer generated code

private void InitializeComponent()
{
    this.components = new System.ComponentModel.Container();
    this.Size = new Size(800, 600);
    this.WindowState= FormWindowState.Maximized;
    this.Text = "mehmet ali ecer";
    ShowInTaskbar = false;
    this.ShowIcon=false;
    this.TopMost=true;
    this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
    this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ScreenSaverForm_KeyDown);
    this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.ScreenSaverForm_MouseDown);
}
#endregion
static void Main()
{
using (Form1 frm = new Form1())
{
    frm.Show();
    frm.InitializeGraphics();
    Application.Run(frm);
    }
}
private void ScreenSaverForm_KeyDown(object sender, KeyEventArgs e)
{
 Close();
}
private void ScreenSaverForm_MouseDown(object sender, MouseEventArgs e)
{
Close();
}}}}