윈도우7의 멀티터치 기능을 활용한 앨범 편집
한손으로 iphone들고 찍으니, 눈의 초점이 어긋나서 제대로 안됨.
쪼그만 삼각대라고 하나 사던지....
멀티터치 제스추어의 가능성을 보여주는 시연으로 ...
- UI 튜닝이 필요한 베타 단계
// ----------------------------------------------------------------------------
//
// Multi touch Implementation
//
// 크레딕스 최원식 (simonsayz@naver.com)
// - www.kredix.com
// - www.maxpaper.com
//
// History ------------------------------------------------------------------
// 2010.02.18 : 개발 시작 ( Based on Delphi7 ) ver 0.1
// 2010.02.18 : Rotate 버그 있음 (WM_touch에서도 동일하게 발생)
// (삼성 매직스테이션 DM-U200 문제로 판단됨)
// ----------------------------------------------------------------------------
Unit VCl_ObjViewer_Base_Touch;
Interface
Uses
Windows,Types,SysUtils;
Const
WM_GESTURENOTIFY = $011A;
WM_GESTURE = $0119;
WM_TOUCH = $0240;
//
WM_TABLET_DEFBASE = $02C0;
WM_TABLET_FLICK = WM_TABLET_DEFBASE + 11;
TOUCHEVENTF_UP = $0004;
//
TWF_FINETOUCH = $00000001;
TWF_WANTPALM = $00000002;
Type
HGESTUREINFO = type LongInt;// LongWord
HTouchInput = THandle;
UInt = DWord;
ULONGLONG = Int64;
ULONG_PTR = LongWord;
//
TGestureType = (gtNone,
gtBegin,
gtEnd,
gtZoom,
gtPan,
gtRotate,
gtTwoFingerTap,
gtPressAndTap);
TGestureState = (gsNone,
gsBegin,
gsWork,
gsEnd);
TGesture = Record
Type_ : TGestureType; // Gesture 형태
State : TGestureState; // Gesture 상태
XY : TPoint; // 위치
Value : Single; // 각도,확대
End;
// For window ----------------------------------------------------------------
TGestureNotifyStruct = Record
cbSize : UINT; // size, in bytes, of this structure
dwFlags : DWORD; // unused
hwndTarget : HWND; // handle to window targeted by the gesture
ptsLocation : TSmallPoint; // starting location
dwInstanceID : DWORD; // internally used
end;
PGestureNotifyStruct = ^TGestureNotifyStruct;
TWMGestureNotify = Packed record
Msg : Cardinal;
Unused : WPARAM;
NotifyStruct : PGestureNotifyStruct;
Result : Integer;
end;
TTouchInput = Record
x : Integer;
y : Integer;
hSource : THandle;
dwID : DWORD;
dwFlags : DWORD;
dwMask : DWORD;
dwTime : DWORD;
dwExtraInfo : ULONG_PTR;
cxContact : DWORD;
cyContact : DWORD;
End;
PTouchInput = ^TTouchInput;
// For Internal Operation & Dbg ----------------------------------------------
TGestureSet = (gsZoom,
gsZoomRotate,
gsAll);
TGestureSav = Record
Cnt : Integer;
State : TGestureState;
ullArguments : ULongLong;
//
ZoomPtPrev : TPoint;
ZoomFac : Single;
//
AngleSnap : Integer; // 화면 Snap Angle 임시저장
AnglePrev : Single; // Touch에서 받은 Angle
//
DbgAngle : Single;
DbgAngleSum : Single;
End;
Var
GestureSav : TGestureSav;
//
Function Gesture_Set (gsHandle : THandle;gsSet : TGestureSet) : Boolean;
Function Gesture_Get (_wParam : wParam; _lParam :lParam) : TGesture;
Function Gesture_Str (Gstr : TGesture) : String;
//
Function RegisterTouchWindow ( Handle : HWND;
ulFlags : Cardinal ): BOOL;
Function UnRegisterTouchWindow( Handle : HWND ): BOOL;
//
Function CloseTouchInputHandle( hTouchInput_ : HTOUCHINPUT ): BOOL;
Function GetTouchInputInfo ( hTouchInput : HTOUCHINPUT;
cInputs : UINT;
pInputs : PTOUCHINPUT;
cbSize : Integer ): BOOL;
Implementation
// http://wiki.helpmvp.com/home/notes/touch
Const
//
GF_Begin = $00000001;
GF_Inertia = $00000002;
GF_End = $00000004;
//
GC_ALLGESTURES = $00000001;
GC_ZOOM = $00000001;
GC_PAN = $00000001;
GC_PAN_WITH_SINGLE_FINGER_VERTICALLY = $00000002;
GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY = $00000004;
GC_PAN_WITH_GUTTER = $00000008;
GC_PAN_WITH_INERTIA = $00000010;
GC_ROTATE = $00000001;
GC_TWOFINGERTAP = $00000001;
GC_PRESSANDTAP = $00000001;
GC_ROLLOVER = GC_PRESSANDTAP;
//
GID_BEGIN = 1; // a generic gesture is beginning.
GID_END = 2; // a generic gesture end.
GID_ZOOM = 3; // zoom start, zoom move, or zoom stop.
GID_PAN = 4; // pan move or pan start.
GID_ROTATE = 5; // rotate move or rotate start.
GID_TWOFINGERTAP = 6; // two-finger tap gesture.
GID_PRESSANDTAP = 7; //
GID_RollOver = GID_PressAndTap;
Type
//
TGestureConfig = Record
dwID : DWORD; // gesture ID
dwWant : DWORD; // settings related to gesture ID that are to be turned on
dwBlock : DWORD; // settings related to gesture ID that are to be turned off
end;
PGestureConfig = ^TGestureConfig;
TConfigs = Array of TGestureConfig;
//
TGestureInfo = Record
cbSize : Longword;
dwFlags : DWord;
dwID : DWord;
hwndTarget : Hwnd;
ptsLocation : TSmallPoint;
dwInstanceID : DWord;
dwSequenceID : DWord;
ullArguments : ULongLong;
cbExtraArgs : UInt;
end;
PGestureInfo = ^TGestureInfo;
Var
_User32Handle : THandle;
_GetGestureInfo : Function ( hGestureInfo : HGESTUREINFO;
Var pGestureInfo : TGestureInfo): BOOL; stdcall;
_CloseGestureInfoHandle : Function ( hGestureInfo : HGESTUREINFO): BOOL; stdcall;
_SetGestureConfig : Function ( hwnd : HWND;
dwReserved : DWORD;
cIDs : UINT;
pGestureConfig: PGESTURECONFIG;
cbSize : UINT ): BOOL; stdcall;
_RegisterTouchWindow : Function ( hwnd : HWND;
ulFlags : Cardinal ): BOOL; stdcall;
_UnRegisterTouchWindow : Function ( hwnd : HWND ): BOOL; stdcall;
_CloseTouchInputHandle : Function ( hTouchInput_ : HTOUCHINPUT ): BOOL; stdcall;
_GetTouchInputInfo : Function ( hTouchInput : HTOUCHINPUT;
cInputs : UINT;
pInputs : PTOUCHINPUT;
cbSize : Integer ): BOOL; stdcall;
//
_GestureSav : TGestureSav;
//
Function GetGestureInfo ( hGestureInfo : HGESTUREINFO;
Var pGestureInfo : TGestureInfo): BOOL;
begin
Case Assigned(_GetGestureInfo) of
True : Result := _GetGestureInfo(hGestureInfo,pGestureInfo);
False : begin
If _User32Handle = 0 then _User32Handle := LoadLibrary('User32.DLL');
Result := False;
If _User32Handle > 0 then
begin
_GetGestureInfo := GetProcAddress(_User32Handle, 'GetGestureInfo');
If Assigned(_GetGestureInfo) then
Result := _GetGestureInfo(hGestureInfo,pGestureInfo);
end;
end;
end;
end;
//
Function CloseGestureInfoHandle (hGestureInfo: HGESTUREINFO): BOOL;
begin
Case Assigned(_CloseGestureInfoHandle) of
True : Result := _CloseGestureInfoHandle(hGestureInfo);
False : begin
If _User32Handle = 0 then _User32Handle := LoadLibrary('User32.DLL');
Result := False;
If _User32Handle > 0 then
begin
_CloseGestureInfoHandle := GetProcAddress(_User32Handle, 'CloseGestureInfoHandle');
If Assigned(_CloseGestureInfoHandle) then
Result := _CloseGestureInfoHandle(hGestureInfo);
end;
end;
end;
end;
//
Function SetGestureConfig ( hwnd : HWND;
dwReserved : DWORD;
cIDs : UINT;
pGestureConfig: PGESTURECONFIG;
cbSize : UINT ): BOOL;
begin
Case Assigned(_SetGestureConfig) of
True : Result := _SetGestureConfig(hwnd,dwReserved,cIDs,pGestureConfig,cbSize);
False : begin
If _User32Handle = 0 then _User32Handle := LoadLibrary('User32.DLL');
Result := False;
If _User32Handle > 0 then
begin
_SetGestureConfig := GetProcAddress(_User32Handle, 'SetGestureConfig');
If Assigned(_SetGestureConfig) then
Result := _SetGestureConfig(hwnd,dwReserved,cIDs,pGestureConfig,cbSize);
end;
end;
end;
end;
//
Function RegisterTouchWindow ( Handle : HWND;
ulFlags : Cardinal ): BOOL;
begin
Case Assigned(_RegisterTouchWindow) of
True : Result := _RegisterTouchWindow(Handle,ulFlags);
False : begin
If _User32Handle = 0 then _User32Handle := LoadLibrary('User32.DLL');
Result := False;
If _User32Handle > 0 then
begin
_RegisterTouchWindow := GetProcAddress(_User32Handle, 'RegisterTouchWindow');
If Assigned(_RegisterTouchWindow) then
Result := _RegisterTouchWindow(Handle,ulFlags);
end;
end;
end;
end;
//
Function UnRegisterTouchWindow ( Handle : HWND ): BOOL;
begin
Case Assigned(_UnRegisterTouchWindow) of
True : Result := _UnRegisterTouchWindow(Handle);
False : begin
If _User32Handle = 0 then _User32Handle := LoadLibrary('User32.DLL');
Result := False;
If _User32Handle > 0 then
begin
_UnRegisterTouchWindow := GetProcAddress(_User32Handle, 'UnregisterTouchWindow');
If Assigned(_UnRegisterTouchWindow) then
Result := _UnRegisterTouchWindow(Handle);
end;
end;
end;
end;
//
Function CloseTouchInputHandle ( hTouchInput_ : HTOUCHINPUT ): BOOL;
begin
Case Assigned(_CloseTouchInputHandle) of
True : Result := _CloseTouchInputHandle(hTouchInput_);
False : begin
If _User32Handle = 0 then _User32Handle := LoadLibrary('User32.DLL');
Result := False;
If _User32Handle > 0 then
begin
_CloseTouchInputHandle := GetProcAddress(_User32Handle, 'CloseTouchInputHandle');
If Assigned(_CloseTouchInputHandle) then
Result := _CloseTouchInputHandle(hTouchInput_);
end;
end;
end;
end;
//
Function GetTouchInputInfo ( hTouchInput : HTOUCHINPUT;
cInputs : UINT;
pInputs : PTOUCHINPUT;
cbSize : Integer ): BOOL;
begin
Case Assigned(_GetTouchInputInfo) of
True : Result := _GetTouchInputInfo(hTouchInput,cInputs,pInputs,cbSize);
False : begin
If _User32Handle = 0 then _User32Handle := LoadLibrary('User32.DLL');
Result := False;
If _User32Handle > 0 then
begin
_GetTouchInputInfo := GetProcAddress(_User32Handle, 'GetTouchInputInfo');
If Assigned(_GetTouchInputInfo) then
Result := _GetTouchInputInfo(hTouchInput,cInputs,pInputs,cbSize);
end;
end;
end;
end;
//
Function GID_ROTATE_ANGLE_FROM_ARGUMENT( Arg: ULONGLONG): Double;
begin
Result := (((Arg / 65535.0) * 4.0 * 3.14159265) - 2.0 * 3.14159265);
end;
//
Function GID_GestureType(GID : Cardinal ) : TGestureType;
begin
Case GID of
GID_BEGIN : Result := gtBegin;
GID_END : Result := gtEnd;
GID_ZOOM : Result := gtZoom;
GID_PAN : Result := gtPan;
GID_ROTATE : Result := gtRotate;
GID_TWOFINGERTAP : Result := gtTwoFingerTap;
GID_PRESSANDTAP : Result := gtPressAndTap;
else Result := gtNone;
end;
end;
//
Function Get_Angle(gaArg : ULongLong) : Double;
begin
Result := gID_Rotate_Angle_From_Argument(gaArg) * 180 / pi;
end;
//
Function Flag_Check(fcValue,fcFlag : DWord) : Boolean;
begin
Result := (fcValue and fcFlag) = fcFlag;
end;
//
Function Flag_State(fcValue : DWord) : TGestureState;
begin
// 초기화
Result := gsNone;
//
If Flag_Check(fcValue,GF_Begin ) then Result := gsBegin;
If Flag_Check(fcValue,GF_End ) then Result := gsEnd;
If Result = gsNone then Result := gsWork;
end;
// ----------------------------------------------------------------------------
//
//
//
//
//
// ----------------------------------------------------------------------------
//
Function Gesture_Set (gsHandle : THandle;gsSet : TGestureSet) : Boolean;
Var
GestureConfig : TGestureConfig;
Configs : Array [0..1] of TGestureConfig;
ConfigCnt : Integer;
begin
Case gsSet of
gsAll : // Gesture 전체 사용
begin
FillChar(GestureConfig,SizeOf(GestureConfig),#0);
GestureConfig.dwWant := GC_AllGestures;
Result := Integer(SetGestureConfig(gsHandle,0,1,@GestureConfig,
SizeOf(GestureConfig))) <> 0;
end;
gsZoom,
gsZoomRotate
: //
begin
FillChar(Configs,SizeOf(Configs),#0);
//
Configs[0].dwID := GID_Zoom;
Configs[0].dwWant := GC_Zoom;
Configs[0].dwBlock := 0;
Configs[1].dwID := GID_ROTATE;
Configs[1].dwWant := GC_ROTATE;
Configs[1].dwBlock := 0;
//
Case gsSet of
gsZoom : ConfigCnt := 1;
gsZoomRotate : ConfigCnt := 2;
End;
Result := Integer(SetGestureConfig(gsHandle,0,ConfigCnt,@Configs[0],
Sizeof(TGestureConfig))) <> 0;
end;
end;
end;
// http://msdn.microsoft.com/ko-kr/magazine/ee336016.aspx
Function Gesture_Get(_wParam :wParam; _lParam :lParam) : TGesture;
Var
GI : TGestureInfo;
Str : String;
begin
// Step #1. 초기화 ----------------------------------------------------------
FillChar(Result,SizeOf(TGesture),#0);
FillChar(Gi,SizeOf(Gi),#0);
ZeroMemory(@gi, sizeof(TGestureInfo));
gi.cbSize := Sizeof(gi);
// Step #2. 멀티터치 정보 얻기 ----------------------------------------------
GetGestureInfo(_lParam, gi);
//
Result.Type_ := GID_GestureType(gi.dwID);
Result.XY := Point(gi.ptsLocation.x,gi.ptsLocation.y);
Case gi.dwID of
// Event Style [Simple] ----------------------------------------------------
GID_Pan : Result.State := Flag_State(gi.dwFlags);
GID_TWOFINGERTAP : Result.State := Flag_State(gi.dwFlags);
GID_PRESSANDTAP : Result.State := Flag_State(gi.dwFlags);
// Event Style [Complex] ---------------------------------------------------
GID_Zoom : Begin
Result.State := Flag_State(gi.dwFlags);
// Zoom 계산을 위하여, 초기값 저장
If Result.State = gsBegin then
_GestureSav.ullArguments := gi.ullArguments;
Result.Value := gi.ullArguments / _GestureSav.ullArguments;
End;
GID_Rotate : Begin
Case Flag_State(gi.dwFlags) of
gsNone : Result.State := gsNone;
gsBegin : begin
_GestureSav.Cnt := 0;
_GestureSav.State := gsNone;
Result.State := gsNone;
end;
gsWork,
gsEnd : begin
Inc(_GestureSav.Cnt);
Result.State := gsNone;
If _Gesturesav.Cnt > 2 then
begin
Case _GestureSav.State of
gsNone : begin
Result.State := gsBegin;
_GestureSav.State := gsWork;
_GestureSav.AnglePrev := Get_Angle(gi.ullArguments);
If Flag_State(gi.dwFlags) = gsEnd then
Result.State := gsNone;
end;
gsWork : Case Flag_State(gi.dwFlags) = gsWork of
True : Result.State := gsWork;
False : Result.State := gsEnd;
end;
End;
end;
Result.Value := Get_Angle(gi.ullArguments);
GestureSav.AnglePrev := Result.Value;
{
Case Result.Value > 0 of
True : Result.Value := 2;
False: Result.Value := -2;
End;
}
end;
End;
End;
End;
//
CloseGestureInfoHandle(_lParam);
end;
//
Function Gesture_Str (Gstr : TGesture) : String;
Function State2Str(fsFlag : TGestureState) : String;
begin
Case fsFlag of
gsNone : Result := '... ';
gsBegin : Result := 'Begin ';
gsWork : Result := 'Work ';
gsEnd : Result := 'End ';
End;
end;
Function XY2Str(xy : TPoint) : String;
begin
Result := IntToStr(xy.x)+','+ IntToStr(xy.Y) + ' ';
end;
begin
Case Gstr.Type_ of
gtBegin : Result := 'Begin ';
gtEnd : Result := 'End ';
gtZoom : Result := 'Zoom ' + State2Str(Gstr.State) + XY2Str(Gstr.XY) + Format('%3.1f',[Gstr.Value]);
gtPan : Result := 'Pan ' + State2Str(Gstr.State) + XY2Str(Gstr.XY);
gtRotate : Result := 'Rotate ' + State2Str(Gstr.State) + XY2Str(Gstr.XY) + Format('%3.1f',[Gstr.Value]);
gtTwoFingerTap : Result := '2FngrTap' + State2Str(Gstr.State) + XY2Str(Gstr.XY);
gtPressAndTap : Result := 'Prs &Tap' + State2Str(Gstr.State) + XY2Str(Gstr.XY);
End;
end;
Initialization
//
_User32Handle := 0;
_GetGestureInfo := nil;
_CloseGestureInfoHandle := nil;
_SetGestureConfig := nil;
_RegisterTouchWindow := nil;
_UnRegisterTouchWIndow := nil;
_CloseTouchInputHandle := nil;
//
FillChar(GestureSav,SizeOf(GestureSav),#0);
end.
댓글 없음:
댓글 쓰기