Windows 7 için Multitouch programlama.

0 dakikada yazıldı

11563 defa okundu

Düzenle

Windows 7 ile beraber gelen Multitouch desteği bugünlerde çok yeni
donanımlar ile daha da hayatımızın içine giriyor. Artık birden çok
dokunma noktasını destekleyen ekranlar dizüstü bilgisayarlara kadar
girdi ve Windows 7'nin yardımı ile donanımdan bağımsız olarak Windows7
API'lerini kullanarak Multitouch desteğine sahip uygulamalar yazabilir
durumdayız. Bu yazımızda Multitouch dünyasına bir giriş yaparak
Multitouch uygulama geliştirirken Windows7 API'lerini nasıl
kullanabileceğimize göz atacağız.

Windows7 ile beraber gelen Multitouch API'lerine ait managed
wrapper'ları aşağıdaki adresten bilgisayarınıza indirebilirsiniz.
İndirme işlemi sonrası paket içerisinden Windows7.Multitouch.dll ve
Windows7.Multitouch.WPF.dll dosyalarını yeni yaratacağımız bir WPF
uygulamasına referans alarak hemen Multitouch programlamaya geçebiliriz.

http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=WindowsTouch&DownloadId=5038

Donanım desteği var mı?

DLL'lerimizi referans aldığımıza göre uygulamamızı yazmaya başlamadan
önce ilk yapmamız gereken uygulamanın çalışacağı hedef bilgisayarda
Multitouch donanım var mı, yok mu sorusuna bir cevap bulmak. Belki de
Multitouch donanım yoksa programımızı çalıştırmanın hiçbir anlamı
kalmayacaktır o nedenle kullanıcılara uygun bir uyarı vererek
programımızın Multitouch donanım gerektirdiğini söyleyebiliriz.

[VB]

    Private Sub Window1_Loaded(ByVal sender As Object,
ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        If Not
Windows7.Multitouch.TouchHandler.DigitizerCapabilities.IsMultiTouchReady
Then

            MsgBox("Multitouch
yok!"
)

            Environment.Exit(1)

        End If

    End Sub

[C#]

        public Window1()

        {

            InitializeComponent();

            this.Loaded += new RoutedEventHandler(Window1_Loaded);

        }

 

        void Window1_Loaded(object sender, RoutedEventArgs e)

        {

            if
(!Windows7.Multitouch.TouchHandler.DigitizerCapabilities.IsMultiTouchReady)
{

                MessageBox.Show("Multitouch yok!");

                Environment.Exit(1);

            }

        }

Hemen referans aldığımız Assembly'lerden birindeki IsMultiTouchReady
propertysine göz atarak eğer geriye False dönüyorsa kullanıcıya
uygun mesajı gösterip programımızı kapatıyoruz. Bu kadarını yaptıktan
sonra uygulamamızın Multitouch dokunuşlarını algılayabilmesi için
gerekli Stylus Event'larını da geçerli hale getirmek için aşağıdaki kodu
hemen uygulamanın Multitouch kullanacak olan penceresinin Loaded
event listener'ına ekliyoruz.

[VB]

        Windows7.Multitouch.WPF.Factory.EnableStylusEvents(Me)

EnableStylusEvents derken parametre olarak eventların yaratılacağı
Window nesnesi isteniyor biz de kendi elimizdeki ana pencereyi
kendisine aktarıyoruz. Bu noktadan sonra artık her dokunuş (Stylus) ile
ilgili eventları yakalayabiliriz. Şimdilik bu örneğimizde kullanacağımız
event'ın adı StylusMove olacak. Amacımız kullanıcıların uygulamamız
üzerinde herhangi bir parmaklarını gezdirdikçe arkada bir iz
bırakıyormuş gibi çizgi çizdirmek. Böylece kullanıcıların birden çok
parmak kullanarak aynı anda birden fazla çizgi çizebilecekler.

[VB]

    Private Sub Window1_StylusMove(ByVal sender As Object,
ByVal e As System.Windows.Input.StylusEventArgs)
Handles Me.StylusMove

        Dim Daire
As New Ellipse

        Daire.Fill = New
SolidColorBrush(Colors.Red)

        Daire.Height = 10

        Daire.Width = 10

        Daire.HorizontalAlignment = Windows.HorizontalAlignment.Left

        Daire.VerticalAlignment = Windows.VerticalAlignment.Top

        Daire.Margin = New
Thickness(e.GetPosition(Me).X,
e.GetPosition(Me).Y, 0, 0)

        Me.Root.Children.Add(Daire)

    End Sub

[C#]

        void Window1_StylusMove(object sender, StylusEventArgs e)

        {

            Ellipse
Daire =
new Ellipse();

            Daire.Fill = new SolidColorBrush(Colors.Red);

            Daire.Height = 10;

            Daire.Width = 10;

            Daire.HorizontalAlignment =
HorizontalAlignment.Left;

            Daire.VerticalAlignment =
VerticalAlignment.Top;

            Daire.Margin = new Thickness(e.GetPosition(this).X, e.GetPosition(this).Y, 0, 0);

            this.Root.Children.Add(Daire);

        }

Yukarıdaki kod içerisinde konumuzla ilgisiz olan kodları gri renkte
yazdım. Geri kalan kısma bakarsak aslında yaptığımız şey StylusMove
eventını yakalayarak bir Ellipse nesnesi yaratıp onun da pozisyonunu
ayarlamak. Bu event her Stylus için çalışacağı için basit bir
şekilde o anda gelen Stylus'ın pozisyonunu alarak elimizde yeni
yarattığımız Ellipse'e set ediyoruz. İşte bu kadar! Aynı normal bir
fare imlecinin pozisyonunu yakalamak gibi.

Eğer burada konuyu biraz daha ilerleterek StylusMove'da o anki
parmakları birbirinden ayırt edip farklı renklerde daireler koymak
isterseniz tabi ki bu da mümkün. Fakat o noktada ufak bir uyarıda
bulunmam gerek. Birincisi ekrana tıklayan parmakları aslında tanıma
şansımız yok. Yani şu anda dokunan parmak ile biraz sonra dokunan parmak
aynı mı yoksa değil mi hiçbir zaman bilemeyiz. Aynı şekilde ekrana o
anda dokunmakta olan bir parmak varsa ikinci gelen parmağın sadece
ikinci olduğunu algılayabiliriz. Sonrasında o ikinci parmak gibip başka
bir ikinci parmak gelirse bu ikisinin de aynı olup olmadığını hiçbir
zaman bilemeyiz. O nedenle konunun özüne dönersek bizim kodumuzun
algılayabileceği şey ancak ekrana tıklayan parmakların kaçıncı dokunan
parmak oldukları. Bu çerçevede StylusMove gibi Stylus eventların da
birer StylusID gönderiliyor.

[VB]

    Private Sub Window1_StylusMove(ByVal sender As Object,
ByVal e As System.Windows.Input.StylusEventArgs)
Handles Me.StylusMove

        Dim Daire
As New Ellipse

        If e.StylusDevice.Id = 10
Then

            Daire.Fill = New
SolidColorBrush(Colors.Red)

        Else

            Daire.Fill = New
SolidColorBrush(Colors.Green)

        End If

        Daire.Height = 10

        Daire.Width = 10

        Daire.HorizontalAlignment = Windows.HorizontalAlignment.Left

        Daire.VerticalAlignment = Windows.VerticalAlignment.Top

        Daire.Margin = New
Thickness(e.GetPosition(
Me).X, e.GetPosition(Me).Y, 0,
0)

        Me.Root.Children.Add(Daire)

    End Sub

[C#]

        void Window1_StylusMove(object sender, StylusEventArgs e)

        {

            Ellipse
Daire =
new Ellipse();

            if (e.StylusDevice.Id ==
10)

            {

                Daire.Fill = new SolidColorBrush(Colors.Red);

            }

            else

            {

                Daire.Fill = new SolidColorBrush(Colors.Green);

            }

            Daire.Height = 10;

            Daire.Width = 10;

            Daire.HorizontalAlignment =
HorizontalAlignment.Left;

            Daire.VerticalAlignment =
VerticalAlignment.Top;

            Daire.Margin = new Thickness(e.GetPosition(this).X,
e.GetPosition(
this).Y, 0, 0);

            this.Root.Children.Add(Daire);

        }

Yukarıda görebileceğiniz şekilde Stylus eventlarımıza gelen argümanlar
üzerinden StylusDevice'a ve onun ID'sine ulaşabiliyoruz. Bu
noktada ID'ler 10'dan başlıyor ve aynı anda dokunan her parmak için
birer artarak devam ediyor. Bizim basit örneğimizde her zaman ilk
dokunan parmak için kırmızı daireler koyarken ikinci dokunan parmak için
de yeşil daireler koyarak bu her iki parmağı ayrı ayrı
algılayabildiğimizi görebiliyoruz.

Manipulation İşlemleri

Bir sonraki aşamada birden çok dokunma noktası ile yapılabilen
manipülasyon işlemleri göz atacağız. Bu çerçevede en tanıdık örnek bir
ekranda var olan resmin kullanıcının iki parmağı ile tekrar
boyutlandırılabiliyor, yer değiştiriyor ve döndürülebiliyor olması. Tüm
bunlar için artık elimizde her dokunuş koordinatlarının olduğunu
düşünürsek geriye sadece gerekli hesaplamaları yaparak ekrandaki bir
resme veya farklı bir nesneye sonucu yansıtmak kalıyor. Fakat merak
etmeyin, o hesaplamaları da bizim yapmamıza gerek yok. Bunun yerine
Managed Wrapper'lar ile beraber gelen ManipulationProcessor sınıfıdan
faydalanabiliriz.

Yeni bir WPF projesi yarattıktan sonra gerekli DLL'lerimizi de referans
alarak sonrasında hemen projemize bir resim dosyası ekleyelim. Bu arada
bir sonraki adımda ihtiyacımız olacağı için System.Drawing assemblysini
de projeye referans olarak eklemeyi unutmayın. Projeye eklediğimiz resmi
göstermesi için XAML tarafına da bir Image nesnesi koymayı
unutmayalım. Tabi bu Image nesnesini yerine göre tekrar
boyutlandıracağımız, ekrandaki yerini değiştireceğimiz veya belirli bir
açıya göre döndüreceğimiz için Image nesnesinin içine de gerekli
Transform objelerini şimdiden koymakta fayda var.

[XAML]

<Window
x
:Class="Window1"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Title="Window1"
Height
="300" Width="300">

    <Grid>

        <Image
Source
="Koala.jpg" RenderTransformOrigin="0.5, 0.5">

            <Image.RenderTransform>

                <TransformGroup>

                    <TranslateTransform x:Name="Konum"
/>

                    <RotateTransform
x
:Name="Aci"
/>

                    <ScaleTransform
x
:Name="Boyut"
/>

                </TransformGroup>

            </Image.RenderTransform>

        </Image>

    </Grid>

</Window>

Transform nesnelerine kod tarafından rahat ulaşabilelim diye şimdiden
yukarıdaki gibi birer isim verebiliriz. Sıra geldi arka tarafta
yazacağımız kodlara. Her zamanki gibi ilk olarak Stylus event'larını
Enable edelim ve bu sefer StylusMove, StylusDown ve StylusUp
eventlarının hepsini de yakalayalım. Bizim tüm manipülasyon işlemlerini
yapacak olan nesneyi de yaratarak gerekli tüm eventlarda bilgileri
hesaplama için kendisine aktarmamız gerekecek.

[VB]

    Private Sub Window1_Loaded(ByVal sender As Object,
ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Windows7.Multitouch.WPF.Factory.EnableStylusEvents(Me)

    End Sub

 

    WithEvents ManiProc As New
Windows7.Multitouch.Manipulation.ManipulationProcessor(Windows7.Multitouch.Manipulation.ProcessorManipulations.ALL)

[C#]

        private void Window1_Loaded(object sender, System.Windows.RoutedEventArgs e)

        {

            Windows7.Multitouch.WPF.Factory.EnableStylusEvents(this);

        }

 

        Windows7.Multitouch.Manipulation.ManipulationProcessor ManiProc = new Windows7.Multitouch.Manipulation.ManipulationProcessor(Windows7.Multitouch.Manipulation.ProcessorManipulations.ALL);

ManipulationProcessor nesnemizi yaratırken parametre olan bir
Enum alıyor ve söz konusu Enumaration içerisindeki seçeneklerimiz
bizim ne tür manipülasyon hesaplaması istediğimizi belirtiyor. Sadece
tekrar boyutlandırma veya sadece döndürme ile ilgili manipülasyonlar da
isteyebiliriz. Bizim örneğimizde tüm manipülasyonları kullanacağımız
için ALL diyerek devam ediyoruz. Sıra geldi daha önce yakaladığımız
Stylus eventlarında gerekli datayı alıp ManipulationProcessor 'a
aktarmaya.

[VB]

    Private Sub Window1_StylusDown(ByVal sender As Object,
ByVal e As System.Windows.Input.StylusDownEventArgs)
Handles Me.StylusDown

        ManiProc.ProcessDown(e.StylusDevice.Id, e.GetPosition(Me).ToDrawingPointF())

    End Sub

 

    Private Sub Window1_StylusMove(ByVal sender As Object,
ByVal e As System.Windows.Input.StylusEventArgs)
Handles Me.StylusMove

        ManiProc.ProcessMove(e.StylusDevice.Id, e.GetPosition(Me).ToDrawingPointF())

    End Sub

 

    Private Sub Window1_StylusUp(ByVal sender As Object,
ByVal e As System.Windows.Input.StylusEventArgs)
Handles Me.StylusUp

        ManiProc.ProcessUp(e.StylusDevice.Id, e.GetPosition(Me).ToDrawingPointF())

    End Sub

[C#]

        private void Window1_StylusDown(object sender, System.Windows.Input.StylusDownEventArgs e)

        {

            ManiProc.ProcessDown((uint)e.StylusDevice.Id, e.GetPosition(this).ToDrawingPointF());

        }

 

        private void Window1_StylusMove(object sender, System.Windows.Input.StylusEventArgs e)

        {

            ManiProc.ProcessMove((uint)e.StylusDevice.Id, e.GetPosition(this).ToDrawingPointF());

        }

 

        private void Window1_StylusUp(object sender, System.Windows.Input.StylusEventArgs e)

        {

            ManiProc.ProcessUp((uint)e.StylusDevice.Id, e.GetPosition(this).ToDrawingPointF());

        }

Yukarıdaki kodda da görebileceğiniz üzere aslında bizim yaptığımız
birşey yok. Gelen StylusID ile pozisyonu doğrudan Processor'ımıza
aktarıyoruz. Processor hesaplamaları tamamladıktan sonra kendine özel
ayrı bir event çalıştırarak bize sonucu aktaracak.

[VB]

    Private Sub ManiProc_ManipulationDelta(ByVal sender As Object,
ByVal e As
Windows7.Multitouch.Manipulation.ManipulationDeltaEventArgs) Handles ManiProc.ManipulationDelta

        Konum.X += e.TranslationDelta.Width

        Konum.Y += e.TranslationDelta.Height

 

        Aci.Angle += e.RotationDelta * 180 / Math.PI

 

        Boyut.ScaleX *= e.ScaleDelta

        Boyut.ScaleY *= e.ScaleDelta

    End Sub

[C#]

        private void ManiProc_ManipulationDelta(object sender,
Windows7.Multitouch.Manipulation.ManipulationDeltaEventArgs e)

        {

            Konum.X += e.TranslationDelta.Width;

            Konum.Y += e.TranslationDelta.Height;

 

            Aci.Angle += e.RotationDelta * 180 / Math.PI;

 

            Boyut.ScaleX *= e.ScaleDelta;

            Boyut.ScaleY *= e.ScaleDelta;

        }

İşte geldik en can alıcı noktaya. Processor'ımızın ManipulationDelta
event'ı çalıştığında artık gerekli hesaplamalar yapılmış demektir.
Geriye kalıyor hesaplamaları uygun şekilde ekrandaki resmimize
yansıtmak. Bunun için zaten daha önce resmimize ait Transform
nesnelerine özel isimler vermiştik. Bu durumda eldeki Delta değerlerini
doğrudan uygun Transform nesnelerinin özelliklerine ekleyebiliriz.

Uygulamamız bitti. Artık programı çalıştırarak iki parmağınız ile
rahatlıkla resmi tutup sürükleyebilir veya boyutlandırabilir,
döndürebilirsiniz. Herşey bu kadar basit.

Hepinize kolay gelsin.

Örneklere ait kaynak kodları - 13082009_1.rar (1,59
MB)