DOBON.NET DOBON.NETプログラミング掲示板過去ログ

Windows タッチ メッセージの処理

環境/言語:[Windows 8 64bit NET Framework4.5]
分類:[.NET]

お世話になっております。

http://msdn.microsoft.com/ja-jp/library/windows/desktop/dd371581(v=vs.85).aspx

のLRESULT OnTouch関数をVB.netに翻訳したいです。

いくつか質問があるので教えてください。

4行名のPTOUCHINPUT pInputs = new TOUCHINPUT[cInputs];

のTOUCHINPUT構造体はVB.netに存在するのでしょうか?

ない場合は自作しないといけないのでしょうか?

また行目のGetTouchInputInfo関数の一番最初のパラメーターのHTOUCHINPUTが一体何なのかわかりません。何かの定数なのでしょうか?

あまり、windows apiにはなじみがなく、つまづいています・・・。

わかる方いらっしゃいましたらご教授ください。

お手数をおかけしますがよろしくお願いします。
> 4行名のPTOUCHINPUT pInputs = new TOUCHINPUT[cInputs];
> のTOUCHINPUT構造体はVB.netに存在するのでしょうか?
> ない場合は自作しないといけないのでしょうか?

基本ライブラリには存在していません。
自分で定義する必要があります。

> また行目のGetTouchInputInfo関数の一番最初のパラメーターのHTOUCHINPUTが一体何なのかわかりません。何かの定数なのでしょうか?

ハンドルです(Windows APIにおいてH接頭辞が付くのは大体そうです)。
オブジェクトを識別する何か、という感じですかね。
VB等ではobj.Method()という風にオブジェクト自身が自身に関するメソッドを持てますが、C言語等から扱われることを考慮したWindows APIではそういうわけにもいかないので、代わりにMethod(obj)という形にしているわけです。このobjがハンドル。
一般的にポインタ型(をtypedefしたもの)で、.NETではまとめてIntPtrで表現されます。
GetTouchInputInfoに渡すHTOUCHINPUTはWndProcのLPARAMとして渡ってきていますね。

// 適当に検索すれば定義済みのサンプルコードが引っかかりそうですが。
> 基本ライブラリには存在していません。
> 自分で定義する必要があります。

下記のページを参考にして構造体作成、変数を変換してみました。

http://www.nda.co.jp/memo/dim.html

HANDLE、ULONG_PTR型はSystem.IntPtrでいいのでしょうか?

Public Structure TOUCHINPUT

Dim x As Integer
Dim y As Integer
Dim hSource As IntPtr
Dim dwID As UInteger
Dim dwFlags As UInteger
Dim dwMask As UInteger
Dim dwTime As UInteger
Dim dwExtraInfo As IntPtr
Dim cxContact As UInteger
Dim cyContact As UInteger

End Structure

> 一般的にポインタ型(をtypedefしたもの)で、.NETではまとめてIntPtrで表現されます。
> GetTouchInputInfoに渡すHTOUCHINPUTはWndProcのLPARAMとして渡ってきていますね。

第一引数はLPARAMでいいということですね。

GetTouchInputInfo(lParam, cInputs, pInputs, Marshal.SizeOf(TOUCHINPUT))...?

> // 適当に検索すれば定義済みのサンプルコードが引っかかりそうですが。

そうですね。
下記のページが丸ごと使えそうで試してみたのですが、

http://dobon.net/cgi-bin/vbbbs/cbbs.cgi?mode=al2&namber=32095&no=0

当方の環境ではGetTouchInputInfoのif文でfor文の処理に入りません。

解析したいのですが何をやってるのかよくわからないので、自分で少し作ってみようとしているところです。
該当スレッドの質問者です。


TOUCHINPUT構造体ですが、以下のように宣言しております。

<StructLayout(LayoutKind.Sequential)> _
    Public Structure TOUCHINPUT
        Dim x As Int32
        Dim y As Int32
        Dim hSource As IntPtr
        Dim dwID As UInt32
        Dim dwFlags As UInt32
        Dim dwMask As UInt32
        Dim dwTime As UInt32
        Dim dwExtraInfo As IntPtr
        Dim cxContact As UInt32
        Dim cyContact As UInt32
    End Structure


>If GetTouchInputInfo(lParam, cInputs, b, 48) Then
のIF文でTrueにならないとのことですが、現状のソースを確認したところ

If GetTouchInputInfo(lParam, cInputs, b, Marshal.SizeOf(GetType(TOUCHINPUT))) Then
と変更しております。

現在、タッチパネルの環境がない為、確認出来ておりませんが、32bit,64bitの環境で
サイズが異なっているのではないでしょうか?

該当スレッドのDecodeTouch関数ですが、この中で行っていることは以下の通りです。

1.wParamよりタッチされている点数を取得
2.タッチ情報を格納する領域の確保
3.タッチ情報の取得
4.タッチされている点数分処理を行う
5.取得したタッチ情報の解放

私の経験上の注意点なのですが、Windows8とWindows7では微妙にイベントの発生が
異なりましたので、環境がWindows8とのことですが、Windows7でも動作させる場合は
お気を付けください。
■No32483に返信(ムーミンさんの記事)
> 下記のページが丸ごと使えそうで試してみたのですが、
> http://dobon.net/cgi-bin/vbbbs/cbbs.cgi?mode=al2&namber=32095&no=0
> 当方の環境ではGetTouchInputInfoのif文でfor文の処理に入りません。

ということは、cInputs の値が 0 以下だったりはしませんか?


当方環境では、AnyCPU ビルド/X64 ビルドのいずれにおいても、
以下のコードでタッチ操作を追跡できています。


Imports System.Windows.Forms
Imports System.Runtime.InteropServices

Public Class Form1
    Inherits System.Windows.Forms.Form

    Private Declare Function RegisterTouchWindow Lib "user32" _
            (ByVal hWnd As IntPtr, ByVal ulFlags As UInt32) As Boolean

    Private Declare Function UnregisterTouchWindow Lib "user32" _
            (ByVal hWnd As IntPtr) As Boolean

    Private Declare Function GetTouchInputInfo Lib "user32" _
            (ByVal hTouchInput As IntPtr, ByVal cInputs As UInt32, _
             ByVal pInputs As IntPtr, ByVal cbSize As Integer) As Boolean

    Private Declare Function CloseTouchInputHandle Lib "user32" _
            (ByVal hTouchInput As IntPtr) As Boolean

    Private Const WM_TOUCH As Integer = &H240

    <Flags> _
    Private Enum TouchEventF As UInt32
        Move = &H1UI
        Down = &H2UI
        Up = &H4UI
        InRange = &H8UI
        Primary = &H10UI
        NoCoalesce = &H20UI
        Pen = &H40UI
        Palm = &H80UI
    End Enum

    <Flags> _
    Private Enum TouchInputMaskF As UInt32
        TimeFromSystem = &H1UI
        ExtraInfo = &H2UI
        ContactArea = &H4UI
    End Enum

    <StructLayout(LayoutKind.Sequential)> _
    Private Structure TOUCHINPUT
        Dim x As Int32
        Dim y As Int32
        Dim hSource As IntPtr
        Dim dwID As UInt32
        Dim dwFlags As TouchEventF
        Dim dwMask As TouchInputMaskF
        Dim dwTime As UInt32
        Dim dwExtraInfo As IntPtr
        Dim cxContact As UInt32
        Dim cyContact As UInt32
    End Structure



    Private Const TOUCHEVENTF_DOWN As UInteger = &H2
    Private Const TOUCHEVENTF_UP As UInteger = &H4
    Private Const TOUCHEVENTF_INRANGE As UInteger = &H8

    Protected Overrides Sub OnHandleCreated(ByVal e As EventArgs)
        MyBase.OnHandleCreated(e)
        RegisterTouchWindow(Me.Handle, 0)
    End Sub

    Protected Overrides Sub OnHandleDestroyed(ByVal e As EventArgs)
        MyBase.OnHandleDestroyed(e)
        UnregisterTouchWindow(Me.Handle)
    End Sub

    Protected Overrides Sub WndProc(ByRef m As Message)
        If m.Msg = WM_TOUCH Then
            DecodeTouch(m.LParam, m.WParam)
        Else
            MyBase.WndProc(m)
        End If
    End Sub

    Private Sub DecodeTouch(ByVal lParam As IntPtr, ByVal wParam As IntPtr)
        Dim cInputs As UInt32 = CUInt(wParam.ToInt64() And &HFFFFL)

        Trace.WriteLine("cInputs=" & CStr(cInputs))
        If cInputs = 0 Then
            Return
        End If

        Dim iCount As Integer = CInt(cInputs)
        Dim inputs() As TOUCHINPUT = New TOUCHINPUT(iCount) {}
        Dim gch As GCHandle = GCHandle.Alloc(inputs, GCHandleType.Pinned)
        Dim b As IntPtr = gch.AddrOfPinnedObject()
        Dim sz As Integer = Marshal.SizeOf(GetType(TOUCHINPUT))

        If GetTouchInputInfo(lParam, cInputs, b, sz) Then
            For i As Integer = 0 To iCount - 1
                Trace.WriteLine(String.Format(" => TOUCHINPUT[{0}].dwFlags={1}", i, inputs(i).dwFlags))
            Next
        Else
            Trace.WriteLine(System.Runtime.InteropServices.Marshal.GetLastWin32Error())
        End If

        CloseTouchInputHandle(lParam)
        gch.Free()
    End Sub

End Class




以下は、当方での実行結果の抜粋です。


cInputs=1
 => TOUCHINPUT[0].dwFlags=Down, InRange, Primary
cInputs=2
 => TOUCHINPUT[0].dwFlags=Move, InRange, Primary
 => TOUCHINPUT[1].dwFlags=Down, InRange
cInputs=3
 => TOUCHINPUT[0].dwFlags=Move, InRange, Primary
 => TOUCHINPUT[1].dwFlags=Move, InRange
 => TOUCHINPUT[2].dwFlags=Down, InRange
cInputs=4
 => TOUCHINPUT[0].dwFlags=Move, InRange, Primary
 => TOUCHINPUT[1].dwFlags=Move, InRange
 => TOUCHINPUT[2].dwFlags=Move, InRange
 => TOUCHINPUT[3].dwFlags=Down, InRange

(中略)

cInputs=10
 => TOUCHINPUT[0].dwFlags=Move, InRange, Primary
 => TOUCHINPUT[1].dwFlags=Move, InRange
 => TOUCHINPUT[2].dwFlags=Move, InRange
 => TOUCHINPUT[3].dwFlags=Move, InRange
 => TOUCHINPUT[4].dwFlags=Move, InRange
 => TOUCHINPUT[5].dwFlags=Move, InRange
 => TOUCHINPUT[6].dwFlags=Move, InRange
 => TOUCHINPUT[7].dwFlags=Move, InRange
 => TOUCHINPUT[8].dwFlags=Move, InRange
 => TOUCHINPUT[9].dwFlags=Down, InRange
cInputs=10
 => TOUCHINPUT[0].dwFlags=Move, InRange, Primary
 => TOUCHINPUT[1].dwFlags=Move, InRange
 => TOUCHINPUT[2].dwFlags=Move, InRange
 => TOUCHINPUT[3].dwFlags=Move, InRange
 => TOUCHINPUT[4].dwFlags=Move, InRange
 => TOUCHINPUT[5].dwFlags=Move, InRange
 => TOUCHINPUT[6].dwFlags=Move, InRange
 => TOUCHINPUT[7].dwFlags=Move, InRange
 => TOUCHINPUT[8].dwFlags=Move, InRange
 => TOUCHINPUT[9].dwFlags=Move, InRange
cInputs=10
 => TOUCHINPUT[0].dwFlags=Move, InRange, Primary
 => TOUCHINPUT[1].dwFlags=Move, InRange
 => TOUCHINPUT[2].dwFlags=Move, InRange
 => TOUCHINPUT[3].dwFlags=Move, InRange
 => TOUCHINPUT[4].dwFlags=Move, InRange
 => TOUCHINPUT[5].dwFlags=Move, InRange
 => TOUCHINPUT[6].dwFlags=Up, InRange
 => TOUCHINPUT[7].dwFlags=Move, InRange
 => TOUCHINPUT[8].dwFlags=Move, InRange
 => TOUCHINPUT[9].dwFlags=Move, InRange

(中略)

cInputs=4
 => TOUCHINPUT[0].dwFlags=Move, InRange, Primary
 => TOUCHINPUT[1].dwFlags=Up
 => TOUCHINPUT[2].dwFlags=Move, InRange
 => TOUCHINPUT[3].dwFlags=Move, InRange
cInputs=3
 => TOUCHINPUT[0].dwFlags=Move, InRange, Primary
 => TOUCHINPUT[1].dwFlags=Move, InRange
 => TOUCHINPUT[2].dwFlags=Move, InRange
cInputs=3
 => TOUCHINPUT[0].dwFlags=Move, InRange, Primary
 => TOUCHINPUT[1].dwFlags=Move, InRange
 => TOUCHINPUT[2].dwFlags=Up
cInputs=2
 => TOUCHINPUT[0].dwFlags=Move, InRange, Primary
 => TOUCHINPUT[1].dwFlags=Move, InRange
cInputs=2
 => TOUCHINPUT[0].dwFlags=Up, Primary
 => TOUCHINPUT[1].dwFlags=Move, InRange
cInputs=1
 => TOUCHINPUT[0].dwFlags=Move, InRange
cInputs=1
 => TOUCHINPUT[0].dwFlags=Up

'==========================

なお上記の結果は、10本タッチした後は、7番目の指から離しているため、
TOUCHINPUT[6].dwFlags に Up フラグが立っています。
(当方のデバイスでは、最大10指までしか検出できません)
お世話になっております。
返信遅くなって申し訳ございません。

> TOUCHINPUT構造体ですが、以下のように宣言しております。
>
> <StructLayout(LayoutKind.Sequential)> _
> Public Structure TOUCHINPUT
> Dim x As Int32
> Dim y As Int32
> Dim hSource As IntPtr
> Dim dwID As UInt32
> Dim dwFlags As UInt32
> Dim dwMask As UInt32
> Dim dwTime As UInt32
> Dim dwExtraInfo As IntPtr
> Dim cxContact As UInt32
> Dim cyContact As UInt32
> End Structure

当方で定義した構造体とまりもんさんが定義した構造体どちらでも大丈夫でした。
重要なのはStructLayout属性みたいですね。
(http://www.atmarkit.co.jp/fdotnet/dotnettips/026w32struct/w32struct.html)

あと構造体にどこで値を入れてるのか全然わからなかったんですが、上記のように宣言して領域の確保をした後に関数のパラメーターにいれると値が入るみたいですね。

>if GetTouchInputInfo(lParam, cInputs, b, Marshal.SizeOf(GetType(TOUCHINPUT))) Then と変更しております。

こちらでif文のfor処理が通るようになりました。
ありがとうございました。
なお、当方の環境ではMarshal.SizeOf(GetType(TOUCHINPUT)は40を返しています。

・該当スレッドのDecodeTouch関数ですが、この中で行っていることは以下の通りです。.....

申し上げにくいのですが、ほぼ丸ごとコピーするようなソースになってしまいましたので、少し頭に残せるようソースをもう少し見て先に進むことにします。

この度はわざわざ時間を割いて投稿していただきありがとうございました。
お世話になっております
返信遅くなって申し訳ございません。

>>当方の環境ではGetTouchInputInfoのif文でfor文の処理に入りません。
>
> ということは、cInputs の値が 0 以下だったりはしませんか?

GetTouchInputInfoの戻り値がゼロを返しています。

>当方環境では、AnyCPU ビルド/X64 ビルドのいずれにおいても、
>以下のコードでタッチ操作を追跡できています。
>Imports System.Windows.Forms・・・・

こちらのサンプルプログラムも参考にさせていただきました。
感謝です。お手数をおかけしました。

また機会ありましたらよろしくお願いします。
Hongliang様、まりもん様、魔界の仮面弁士様、有益な情報をありがとうございました。これにて解決済みとさせていただきます。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板