2010년 3월 17일 수요일

maxpaper scrapbook software

maxpaper scrapbook software

온라인 인화사이트인 맥스페이퍼 ( http://www.maxpaper.com )에서 공개한증명사진및 압축앨범 편집 소프트웨어인 맥스페이퍼(Maxpaper)의 개발 일기입니다.2007년부터 2010년까지 지난 4년간의 개발 일정을 중간 정리합니다.

- 편집프로그램은 맥스페이퍼(www.maxpaper.com) 에서 다운가능합니다.



2010년 2월 21일 일요일

Maxpaper for Multi touch based on win7





윈도우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.