定义一个结构
class MyPoint
{
public:
float fx;
float fy;
USHORT depth;
};
然后将骨骼各节点信息保存起来:(其实这里只用到了左右手的节点信息)
for (i = 0; i < NUI_SKELETON_POSITION_COUNT; i++)
{
// Add new position to the history buffer
m_History[i].push_front(point);
// Keep size of history buffer
if (m_History[i].size() > m_nThreshold)
m_History[i].pop_back();
}
从保存的数据中取出信息,控制鼠标:
void CKinect::HandleMouseMoveAndClick( )
{
if( m_History[NUI_SKELETON_POSITION_HAND_RIGHT].size( ) >= m_nThreshold )
{
// 新点;
MyPoint newPoint;
newPoint.fx = m_History[NUI_SKELETON_POSITION_HAND_RIGHT].front().fx;
newPoint.fy = m_History[NUI_SKELETON_POSITION_HAND_RIGHT].front().fy;
newPoint.depth = m_History[NUI_SKELETON_POSITION_HAND_RIGHT].front().depth;
// 旧点;
MyPoint oldPoint;
std::list< MyPoint >::iterator iter= m_History[NUI_SKELETON_POSITION_HAND_RIGHT].begin( );
iter++;
oldPoint.fx = iter->fx;
oldPoint.fy = iter->fy;
oldPoint.depth = iter->depth;
// 左手新点;
MyPoint newPointLeft;
newPointLeft.fx = m_History[NUI_SKELETON_POSITION_HAND_LEFT].front().fx;
newPointLeft.fy = m_History[NUI_SKELETON_POSITION_HAND_LEFT].front().fy;
newPointLeft.depth = m_History[NUI_SKELETON_POSITION_HAND_LEFT].front().depth;
// 屏幕坐标系 转换因子;
int screenWidth = rcWorkArea.Width(); // GetSystemMetrics(SM_CXSCREEN);
int screenHeight = rcWorkArea.Height();// GetSystemMetrics(SM_CYSCREEN);
newPoint.fx = newPoint.fx * screenWidth ;
newPoint.fy = newPoint.fy * screenHeight ;
oldPoint.fx = oldPoint.fx * screenWidth ;
oldPoint.fy = oldPoint.fy * screenHeight ;
// 求位差;
float xOffset = newPoint.fx - oldPoint.fx;
float yOffset = newPoint.fy - oldPoint.fy;
// 计算位移结果;
POINT currentPoint;
POINT resultPoint;
::GetCursorPos( ¤tPoint );// 获取当前鼠标位置
if(xOffset < 30 || yOffset < 30)
{
resultPoint.x = static_cast(currentPoint.x + xOffset*2.5+0.5);
resultPoint.y = static_cast(currentPoint.y + yOffset*2.2+0.5);
}else if(xOffset < 80 || yOffset < 80)
{
resultPoint.x = static_cast(currentPoint.x + xOffset*2.8 +0.5);
resultPoint.y = static_cast(currentPoint.y + yOffset*2.5 +0.5);
}else
{
resultPoint.x = static_cast(currentPoint.x + xOffset*3.1+0.5);
resultPoint.y = static_cast(currentPoint.y + yOffset*3.1+0.5);
}
// 评价;
if( resultPoint.x <= 0 )
resultPoint.x = 0;
if( resultPoint.x >= screenWidth )
resultPoint.x = screenWidth;
if( resultPoint.y <=0 )
resultPoint.y = 0;
if( resultPoint.y >= screenHeight )
resultPoint.y = screenHeight;
SetCursorPos( resultPoint.x , resultPoint.y );// 设置鼠标位置
// 处理鼠标点击;
// 将特定的控件存放到容器中,使得只在指定的控件上实施点击:MousePointInCtrRect(m_hWnd,vecItemIDs,currentPoint)
vector vecItemIDs;
vecItemIDs.push_back(IDC_HANDCTR);
vecItemIDs.push_back(IDC_PPTCTR);
vecItemIDs.push_back(IDC_BUTTON1);
vecItemIDs.push_back(IDC_BUTTON3);
vecItemIDs.push_back(IDC_LIST_MER);
// 不存在位移比较大的点;
if((abs(newPoint.fx-oldPoint.fx) < 5
|| abs(newPoint.fy-oldPoint.fy) < 5)
&& MousePointInCtrRect(m_hWnd,vecItemIDs,currentPoint) )
{
if(m_flagRecordBegin == 1)
{
m_start = clock();// 记录单击起始时间;
m_flagRecordBegin = 0;
}
if(m_flagRecordBeginDoubleClick == 1)
{
m_startDoubleClick = clock(); // 记录双击起始时间;
m_flagRecordBeginDoubleClick = 0;
}
clock_t now = clock();
if(now - m_start > 700 && now - m_start <= 1400)
{
if(m_flagRightClick == false)//只记一次;
{
oldPointRight = newPoint;
oldPointLeft = newPointLeft;
m_flagRightClick = true;
}
}
// 右手在指定控件的时间达到一定时间长度且左手向前移动,右击
if(now - m_start > 1000 && now - m_start <= 3500 && (oldPointLeft.depth - newPointLeft.depth) > 2000 )
{
m_flagRecordBegin = 1;
m_flagRecordBeginDoubleClick = 1;
this->RightClick();
m_flagRightClick = false;
}
// 右手在指定控件的时间达到一定时间长度,左击
if(now - m_start > 3500 )
{
this->LeftClick() ;
m_flagRecordBegin = 1;
m_flagRightClick = false;
}
// 右手在指定控件的时间达到一定时间长度,双击
if(now - m_startDoubleClick > 6000 )
{
this->LeftClick() ;
this->LeftClick() ;
m_flagRecordBegin = 1;
m_flagRecordBeginDoubleClick = 1;
}
}else{// 操作位移较大的点,重新计时;
m_flagRecordBegin = 1;
m_flagRecordBeginDoubleClick = 1;
}
}
}
判断鼠标当前是否在指定控件上函数(MFC)
bool CKinect::MousePointInCtrRect(HWND hwnd,vector nItemNo,POINT point)
{
for (size_t i=0; i < nItemNo.size(); i++)
{
CRect rect;
GetWindowRect(GetDlgItem(m_hWnd,nItemNo[i]),&rect);
if(point.x> rect.left&&point.x <rect.right&&point.y rect.top)
{
return true;
}
}
return false;
}
左击、右击:
void CKinect::LeftClick () {
INPUT Input = {0};
// left down
Input.type = INPUT_MOUSE;
Input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
::SendInput(1,&Input,sizeof(INPUT));
// left up
::ZeroMemory(&Input,sizeof(INPUT));
Input.type = INPUT_MOUSE;
Input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
::SendInput(1,&Input,sizeof(INPUT));
}
void CKinect::RightClick () {
INPUT Input = {0};
// left down
Input.type = INPUT_MOUSE;
Input.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
::SendInput(1,&Input,sizeof(INPUT));
// left up
::ZeroMemory(&Input,sizeof(INPUT));
Input.type = INPUT_MOUSE;
Input.mi.dwFlags = MOUSEEVENTF_RIGHTUP;
::SendInput(1,&Input,sizeof(INPUT));
}
鼠标移动如果不够平滑,可以考虑线性插值? 要想实现使用kinect来控制ppt,可以在定义好手势后发送PageUp,PageDown,F5,Shift+F5,以及ESC等键盘信息。
这样就可以了,代码就不贴了。