日別アーカイブ: 2009年4月7日

Windows7 Multitouch API

タッチ関連の API は 2種類あります。
WM_TOUCH 系と WM_GESTURE 系

WM_TOUCH 系の方が低レベルで、直接複数のタッチ座標を取り出すことが出来ます。
WM_GESTURE の方はいくつかの決まった操作を容易に受け取ることができます。

WM_TOUCH 系のメッセージを有効にするには RegisterTouchWindow() を呼び出します。
これを実行しておかないと WM_TOUCH~ が送られて来ません。

データを受け取るのは簡単です。

WM_TOUCHDOWN
WM_TOUCHUP
WM_TOUCHMOVE

などマウスとよく似ているメッセージが来るので、さらに
GetTouchInputInfo() を使って詳細な情報を読み取ります。

起動時の判定

// ハードがマルチタッチをサポートしているかどうか
int  value= ~GetSystemMetrics( SM_DIGITIZER );
if( !(value & 0xc0) ){
    RegisterTouchWindow( hwnd, 0 );
}

メッセージ

    case WM_TOUCHDOWN:
    case WM_TOUCHUP:
    case WM_TOUCHMOVE:
	WM_Touch( mes, wparam, lparam );
	return	FALSE;

読み出しの例

void WM_Touch( UINT mes, WPARAM wparam, LPARAM lparam )
{
    int	inputs= LOWORD( wparam );
    TOUCHINPUT	tbuf[TOUCHMAX];
    HANDLE	hinput= reinterpret_cast( lparam );
    if( GetTouchInputInfo( hinput, inputs, tbuf, sizeof(TOUCHINPUT) ) ){
	TOUCHINPUT*	tp= tbuf;
	for( int i= 0 ; i< inputs ; i++, tp++ ){
	    ...
	}
    }
    CloseTouchInputHandle( hinput );
}

座標値そのままなので、これを元にズームや回転などの操作を検出するには
さらに一手間いります。

WM_GESTURE 系はそのあたりを簡単にしてくれます。
下記の操作が定義されています。

GID_ZOOM
GID_PAN
GID_ROTATE
GID_TWOFINGERTAP
GID_ROLLOVER

これらのメッセージは RegisterTouchWindow() を実行すると来なくなるので
WM_GESTURE 系を使う場合は RegisterTouchWindow() を実行してはいけません。

WM_GESTURE が送られてきたらさらに追加情報を受け取ります。

    case WM_GESTURE:
	WM_Gesture( mes, wparam, lparam );
	return	FALSE;
void WM_Gesture( UINT mes, WPARAM wparam, LPARAM lparam )
{
    GESTUREINFO	ginfo;
    memset( &ginfo, 0, sizeof(GESTUREINFO) );
    ginfo.cbSize= sizeof(GESTUREINFO);
    HGESTUREINFO	hgesture= reinterpret_cast( lparam );

    if( GetGestureInfo( hgesture, &ginfo ) ){
        ...
    }
    CloseGestureInfoHandle( hgesture );
}

WM_GESTURE 系の仕様は若干変更があったようで、資料によっては記載内容が
異なっていることがあります。例えば今でも

MSDN WM_GESTURE Message

このページにある dwCommand は存在しておらず GESTUREINFO 構造体の
dwID のことだと思われます。
同じように dwArgument も 64bit の ullArguments に変更されているようです。

・dwCommand → GESTUREINFO dwID
・dwArgument → GESTUREINFO ullArguments
・lParam → GESTUREINFO ptsLocation

その他いくつか気が付いた点。

初期状態では GID_ROTATE などのメッセージが来ませんでした。
SetGestureConfig() を使って送って欲しいメッセージの登録が出来るようです。

const int	ConfigCount= 5;
GESTURECONFIG	config[ConfigCount];
memset( config, 0, sizeof(GESTURECONFIG) * ConfigCount );

config[0].dwID= GID_ZOOM;
config[0].dwWant= GC_ZOOM;

config[1].dwID= GID_PAN;
config[1].dwWant= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY
	|GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY
	|GC_PAN_WITH_GUTTER
	|GC_PAN_WITH_INERTIA;

config[2].dwID= GID_ROTATE;
config[2].dwWant= GC_ROTATE;

config[3].dwID= GID_TWOFINGERTAP;
config[3].dwWant= GC_TWOFINGERTAP;

config[4].dwID= GID_ROLLOVER;
config[4].dwWant= GC_ROLLOVER;

SetGestureConfig( hwnd, 0, 5, config, sizeof(GESTURECONFIG) );

これで全部のメッセージとオプションが有効になるはずです。

座標は ptsLocation に、追加パラメータは ullArguments に入ります。
GID_PAN + GF_INERTIA フラグが ON の場合は、ullArguments の上位 32bit に
慣性のパラメータが格納されているようです。
GID_INERTIA というのは存在していません。

なお、これらの動作を確認するには

・Windows7 Beta
・Windows SDK for Windows 7 BETA
・MultiTouch 対応 PC

が必要です。Vista では起動時に DLL の互換性が無くエラーになります。
HP の TouchSmart PC IQ800 を使いました。

Windows7 SDK の設定には少々注意が必要です。
新しい DirectX SDK もリリースされているので、DirectX SDK March 2009 を
併用する場合は特に。基本的にあとからリリースされた方を上にします。

・DirectX SDK March 2009
・Windows SDK for Windows 7 BETA
・VisualStudio 2008

VisualStudio の Tools → Options → Projects and Solutions → VC++ DIrectories の設定

Include files

$(DXSDK_DIR)include
$(WindowsSdkDir)\include
$(VCInstallDir)include
~

Library files (x64)

$(DXSDK_DIR)lib\x64
$(WindowsSdkDir)lib\x64
$(VCInstallDir)lib\amd64
~

Library files (x86)

$(DXSDK_DIR)lib\x86
$(WindowsSdkDir)lib
$(VCInstallDir)lib
~

またあらかじめスタートメニュー Microsoft Windows SDK v7.0 から
Windows SDK Configuration Tool を起動して v7.0 を選択しておきます。

関連エントリ
DirectX SDK March 2009
Windows7 とマルチタッチ / HP TouchSmart PC IQ800
Direct2D と Direct3D10.1 の下位互換