Merge multi-touch gestures event branch

This is a squashed commit of the SOC2017_GESTURES branch from
https://github.com/prashantkn94/wxWidgets.git

Closes https://github.com/wxWidgets/wxWidgets/pull/551
This commit is contained in:
prashantkn94
2017-09-10 21:13:32 +05:30
committed by Vadim Zeitlin
parent aef4edb969
commit 261b04b5a3
21 changed files with 2318 additions and 10 deletions

View File

@@ -205,6 +205,85 @@ bool gs_insideCaptureChanged = false;
} // anonymous namespace
namespace
{
// Class used to dynamically load gestures related API functions.
#ifdef WM_GESTURE
class GestureFuncs
{
public:
static bool IsOk()
{
if ( !ms_gestureSymbolsLoaded )
LoadGestureSymbols();
return ms_pfnGetGestureInfo && ms_pfnCloseGestureInfoHandle && ms_pfnSetGestureConfig;
}
typedef BOOL (WINAPI *GetGestureInfo_t)(HGESTUREINFO, PGESTUREINFO);
static GetGestureInfo_t GetGestureInfo()
{
if ( !ms_gestureSymbolsLoaded )
LoadGestureSymbols();
return ms_pfnGetGestureInfo;
}
typedef BOOL (WINAPI *CloseGestureInfoHandle_t)(HGESTUREINFO);
static CloseGestureInfoHandle_t CloseGestureInfoHandle()
{
if ( !ms_gestureSymbolsLoaded )
LoadGestureSymbols();
return ms_pfnCloseGestureInfoHandle;
}
typedef BOOL (WINAPI *SetGestureConfig_t)(HWND, DWORD, UINT, PGESTURECONFIG, UINT);
static SetGestureConfig_t SetGestureConfig()
{
if ( !ms_gestureSymbolsLoaded )
LoadGestureSymbols();
return ms_pfnSetGestureConfig;
}
private:
static void LoadGestureSymbols()
{
wxDynamicLibrary dll("User32.dll");
wxDL_INIT_FUNC(ms_pfn, GetGestureInfo, dll);
wxDL_INIT_FUNC(ms_pfn, CloseGestureInfoHandle, dll);
wxDL_INIT_FUNC(ms_pfn, SetGestureConfig, dll);
ms_gestureSymbolsLoaded = true;
}
static GetGestureInfo_t ms_pfnGetGestureInfo;
static CloseGestureInfoHandle_t ms_pfnCloseGestureInfoHandle;
static SetGestureConfig_t ms_pfnSetGestureConfig;
static bool ms_gestureSymbolsLoaded;
};
GestureFuncs::GetGestureInfo_t
GestureFuncs::ms_pfnGetGestureInfo = NULL;
GestureFuncs::CloseGestureInfoHandle_t
GestureFuncs::ms_pfnCloseGestureInfoHandle = NULL;
GestureFuncs::SetGestureConfig_t
GestureFuncs::ms_pfnSetGestureConfig = NULL;
bool GestureFuncs::ms_gestureSymbolsLoaded = false;
#endif // WM_GESTURE
} // anonymous namespace
// ---------------------------------------------------------------------------
// private functions
// ---------------------------------------------------------------------------
@@ -3124,6 +3203,97 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
}
break;
#ifdef WM_GESTURE
case WM_GESTURE:
{
if ( !GestureFuncs::IsOk() )
{
processed = false;
break;
}
// gestureInfo will contain the information about the gesture
GESTUREINFO gestureInfo = {0};
gestureInfo.cbSize = sizeof(GESTUREINFO);
// This should fill gestureInfo with the gesture details
if ( !GestureFuncs::GetGestureInfo()((HGESTUREINFO)lParam, &gestureInfo) )
{
wxLogLastError("GetGestureInfo");
processed = false;
break;
}
if ( gestureInfo.hwndTarget != GetHWND() )
{
wxLogDebug("This is Not the window targeted by this gesture!");
}
int x = gestureInfo.ptsLocation.x;
int y = gestureInfo.ptsLocation.y;
ScreenToClient(&x, &y);
// dwID field is used to determine the type of gesture
switch ( gestureInfo.dwID )
{
// Pan gesture
case GID_PAN:
{
// (x,y) is the current position of the pan
processed = HandlePanGesture(x, y, gestureInfo.dwFlags);
break;
}
// Zoom gesture
case GID_ZOOM:
{
// (x,y) is the mid-point of 2 fingers
// ullArgument field is a 64-bit unsigned integer, but the relevant information
// is in it's lower 4 bytes and represents distance between the fingers
// this is used to extract those lower 4 bytes
DWORD fingerDistance = (DWORD)((gestureInfo.ullArguments) & 0x00000000ffffffff);
processed = HandleZoomGesture(x, y, fingerDistance, gestureInfo.dwFlags);
break;
}
// Rotate gesture
case GID_ROTATE:
{
// (x,y) is the center point of rotation
// Again, we need the lower 4 bytes and this will used as an argument
// to obtain the angle to rotate
DWORD angleArgument = (DWORD)((gestureInfo.ullArguments) & 0x00000000ffffffff);
processed = HandleRotateGesture(x, y, angleArgument, gestureInfo.dwFlags);
break;
}
// Two Finger tap gesture
case GID_TWOFINGERTAP:
{
processed = HandleTwoFingerTap(x, y, gestureInfo.dwFlags);
break;
}
// Press and Tap gesture
case GID_PRESSANDTAP:
{
processed = HandlePressAndTap(x, y, gestureInfo.dwFlags);
break;
}
}
if ( processed )
{
// If processed, we must call this to avoid memory leaks
if ( !GestureFuncs::CloseGestureInfoHandle()((HGESTUREINFO)lParam) )
{
wxLogLastError("CloseGestureInfoHandle");
}
}
}
break;
#endif // WM_GESTURE
// CTLCOLOR messages are sent by children to query the parent for their
// colors
case WM_CTLCOLORMSGBOX:
@@ -3660,6 +3830,20 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
return false;
}
#ifdef WM_GESTURE
if ( GestureFuncs::IsOk() )
{
// Configure to receive all gestures
GESTURECONFIG gestureConfig = {0, GC_ALLGESTURES, 0};
// This functions sets the configuration to the window. Second argument is reserved to be 0.
// Third argument is the number of elements in gestureConfig array, currently equal to 1
if ( !GestureFuncs::SetGestureConfig()(m_hWnd, 0, 1, &gestureConfig, sizeof(GESTURECONFIG)) )
{
wxLogLastError("SetGestureConfig");
}
}
#endif // WM_GESTURE
SubclassWin(m_hWnd);
@@ -5470,6 +5654,181 @@ void wxWindowMSW::GenerateMouseLeave()
(void)HandleWindowEvent(event);
}
#ifdef WM_GESTURE
// ---------------------------------------------------------------------------
// Gesture events
// ---------------------------------------------------------------------------
bool wxWindowMSW::HandlePanGesture(int x, int y, WXDWORD flags)
{
// wxEVT_GESTURE_PAN
wxPanGestureEvent event(GetId());
// These are used to calculate the pan delta
static int s_previousLocationX, s_previousLocationY;
// This flag indicates that the gesture has just started
// Store the current point to determine the pan delta later on
if ( flags & GF_BEGIN )
{
s_previousLocationX = x;
s_previousLocationY = y;
event.SetGestureStart();
}
if ( flags & GF_END )
{
event.SetGestureEnd();
}
// Determine the horizontal and vertical changes
int DeltaX = x - s_previousLocationX, DeltaY = y - s_previousLocationY;
event.SetEventObject(this);
event.SetTimestamp(::GetMessageTime());
event.SetPosition(wxPoint(x, y));
event.SetDeltaX(DeltaX);
event.SetDeltaY(DeltaY);
// Update the last gesture event point
s_previousLocationX = x;
s_previousLocationY = y;
return HandleWindowEvent(event);
}
bool wxWindowMSW::HandleZoomGesture(int x, int y, WXDWORD fingerDistance, WXDWORD flags)
{
// wxEVT_GESTURE_ZOOM
wxZoomGestureEvent event(GetId());
// These are used to calculate the center of the zoom and zoom factor
static int s_previousLocationX, s_previousLocationY, s_intialFingerDistance;
// This flag indicates that the gesture has just started
// Store the current point and distance between the fingers for future calculations
if ( flags & GF_BEGIN )
{
s_previousLocationX = x;
s_previousLocationY = y;
s_intialFingerDistance = fingerDistance;
event.SetGestureStart();
}
if ( flags & GF_END )
{
event.SetGestureEnd();
}
// Calculate center point of the zoom
// Human beings are not very good at moving two fingers at exactly the same rate outwards/inwards
// There is usually some error, which can cause the center to shift slightly
// So, it is recommended to take the average of center of fingers in the current and last positions
wxPoint pt;
pt.x = (s_previousLocationX + x) / 2;
pt.y = (s_previousLocationY + y) / 2;
double zoomFactor = (double) fingerDistance / (double) s_intialFingerDistance;
event.SetZoomFactor(zoomFactor);
event.SetEventObject(this);
event.SetTimestamp(::GetMessageTime());
// This is not a gesture point but the center of a zoom
event.SetPosition(pt);
// Update gesture event point
s_previousLocationX = x;
s_previousLocationY = y;
return HandleWindowEvent(event);
}
bool wxWindowMSW::HandleRotateGesture(int x, int y, WXDWORD angleArgument, WXDWORD flags)
{
// wxEVT_GESTURE_ROTATE
wxRotateGestureEvent event(GetId());
// This flag indicates that the gesture has just started
if ( flags & GF_BEGIN )
{
event.SetGestureStart();
}
else
{
// Use angleArgument to obtain the cumulative angle since the gesture was first
// started. This angle is in radians
// MSW returns negative angle for clockwise rotation and positive otherwise
// So, multiply angle by -1 for positive angle for clockwise and negative in case of counterclockwise
double angle = -GID_ROTATE_ANGLE_FROM_ARGUMENT(angleArgument);
// If the rotation is anti-clockwise convert the angle to its corresponding positive value in a clockwise sense.
if ( angle < 0 )
{
angle += 2 * M_PI;
}
// Set the angle
event.SetRotationAngle(angle);
}
if ( flags & GF_END )
{
event.SetGestureEnd();
}
event.SetEventObject(this);
event.SetTimestamp(::GetMessageTime());
event.SetPosition(wxPoint(x, y));
return HandleWindowEvent(event);
}
bool wxWindowMSW::HandleTwoFingerTap(int x, int y, WXDWORD flags)
{
// wxEVT_TWO_FINGER_TAP
wxTwoFingerTapEvent event(GetId());
if ( flags & GF_BEGIN )
{
event.SetGestureStart();
}
event.SetEventObject(this);
event.SetTimestamp(::GetMessageTime());
event.SetPosition(wxPoint(x, y));
if ( flags & GF_END )
{
event.SetGestureEnd();
}
return HandleWindowEvent(event);
}
bool wxWindowMSW::HandlePressAndTap(int x, int y, WXDWORD flags)
{
wxPressAndTapEvent event(GetId());
if ( flags & GF_BEGIN )
{
event.SetGestureStart();
}
event.SetEventObject(this);
event.SetTimestamp(::GetMessageTime());
event.SetPosition(wxPoint(x, y));
if ( flags & GF_END )
{
event.SetGestureEnd();
}
return HandleWindowEvent(event);
}
#endif // WM_GESTURE
// ---------------------------------------------------------------------------
// keyboard handling
// ---------------------------------------------------------------------------