用Kinect来控制鼠标的移动、单击、双击和右击 (Windows sdk)

 定义一个结构
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<int>(currentPoint.x + xOffset*2.5+0.5);
			resultPoint.y = static_cast<int>(currentPoint.y + yOffset*2.2+0.5);
		}else if(xOffset < 80 || yOffset < 80)
		{
			resultPoint.x = static_cast<int>(currentPoint.x + xOffset*2.8 +0.5);
			resultPoint.y = static_cast<int>(currentPoint.y + yOffset*2.5 +0.5);
		}else  
		{
			resultPoint.x = static_cast<int>(currentPoint.x + xOffset*3.1+0.5);
			resultPoint.y = static_cast<int>(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<int> 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<int> 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.bottom&&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 2.0是微软公司推出的一款运动感应设备,它可以以全身动作控制并感应人体姿态,用于与电脑进行互动。要实现使用Kinect 2.0控制鼠标移动和点击,需要通过相应的软件和编程技术来实现。 首先,我们需要连接并设置Kinect 2.0设备。将Kinect 2.0摄像头通过USB接口连接到电脑上,并安装相关的驱动程序。然后,使用Kinect SDK(软件开发工具包)或其他相关的编程语言和库来编写程序进行控制。 接下来,需要编写控制鼠标移动和点击的代码。借助Kinect 2.0的深度感应和运动追踪功能,我们可以获取到用户的手部、头部和身体的动作信息。通过对这些信息的分析和处理,可以将用户的手势转化为鼠标移动的动作。 例如,当用户将手伸直并向左移动时,可以将这个手势解析为鼠标向左移动的指令;当用户做出点击的手势时,可以将这个手势解析为鼠标点击的动作。通过编写相应的代码逻辑,将Kinect获取到的用户手势信息与鼠标控制命令相结合,实现控制鼠标移动和点击。 在编写完控制代码后,将其编译并运行。当用户通过Kinect 2.0设备进行身体动作时,程序将解析这些动作并进行相应的鼠标控制操作。用户只需站在Kinect 2.0的感应范围内,并做出指定的手势,就能实现控制鼠标移动和点击的功能。 总之,通过连接Kinect 2.0设备并编写相应的控制代码,我们可以实现使用Kinect 2.0来控制鼠标移动和点击。这种方式可以在一定程度上提供更加直观、自然的人机交互体验。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值