简单远程控制(仅传递鼠标和键盘消息)的实现

假设两个同样的应用程序,运行在相同的操作系统上,要实现远程控制,可以使用传递鼠标和键盘的消息给对方,对方收到后解析出鼠标和键盘消息如何执行即可。


下面是几处关键程序:


一是处理收到消息,下面应该放在套接字接收或者串口接收中:(小心下面的右键单击、双击几处没实现!)

//
// 解析从客户端发送过来的消息并发送到本机的消息队列
//
void DispatchWMMessage(char *szString, void *p)
{
	CTestDlg *pDlg = (CTestDlg *)p;

	//鼠标消息
	struct {char *szWMMouseMsg;} 
	WMMouseMsg[] = {"WM_MM","WM_LBD","WM_LBU","WM_LBK",
					"WM_MBD","WM_MBU","WM_MBK",
					"WM_RBD","WM_RBU","WM_RBK"};

	// 键盘消息
	struct {char *szWMKeyBdMsg;}
	WMKeyBdMsg[] = {"WM_KD","WM_KU"};

	// 通用消息:色彩模式,网格数和压缩消息
	struct {char *szMsg;}
	Msg[] = {"WM_COMP","WM_GRID","WM_CMOD"};

	int		nWMMouseMsg;
	int		nWMKeyBdMsg;
	int		nMsg;

	struct	CommandList	CommandStart;
	struct	CommandList	*pCommandNode;
	struct	CommandDS	Command;
	char	*pDest;
	int		iLoc,nChar;
	int		iLoop,iParms;
	char	szString2[2049];

	// 分别得到鼠标,键盘,通用消息的数目
	nWMMouseMsg = (int)(sizeof(WMMouseMsg)/sizeof(WMMouseMsg[0]));
	nWMKeyBdMsg = (int)(sizeof(WMKeyBdMsg)/sizeof(WMKeyBdMsg[0]));
	nMsg = (int)(sizeof(Msg)/sizeof(Msg[0]));

	// 初始化command链表
	CommandStart.pNext = NULL;
	pCommandNode = &CommandStart;

	// 分析command命令,截获命令的参数
	iParms = 0;
	while (pDest = strchr(szString,';'))
	{
		iLoc = pDest - szString;
		nChar = iLoc;
		memset(Command.szElement,'\0',sizeof(Command.szElement));
		strncpy(Command.szElement,szString,nChar);
		// 发送到命令栈中
		pCommandNode = Add_Command(pCommandNode,Command);
		memset(szString2,'\0',sizeof(szString2));
		strcpy(szString2,&szString[iLoc + 1]);
		strcpy(szString,szString2);

		iParms++;
		if (iParms == 5) // 每条命令5个参数
			break;
	}

	// 处理命令
	pCommandNode = CommandStart.pNext;
	if (pCommandNode)
	{
		// 鼠标消息
		UINT	keyFlags;
		int		iMessage;
		int		fWMMouseMsg;
		DWORD	dwX,dwY;

		// 键盘消息
		int		fWMKeyBdMsg;
		UINT	vk;
		int		fDown;
		int		cRepeat;
		UINT	flags;

		// 判断是否有鼠标消息
		fWMMouseMsg = FALSE;
		for (iLoop = 0;iLoop < nWMMouseMsg;iLoop++)
		{
			if (strcmp(pCommandNode->Command.szElement,WMMouseMsg[iLoop].szWMMouseMsg) == 0)
			{
				// 设置鼠标消息的标志
				fWMMouseMsg = TRUE;
				// 具体的鼠标消息
				if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_MM\0") == 0)
					iMessage = 1;
				else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_LBD\0") == 0)
					iMessage = 2;
				else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_LBU\0") == 0)
					iMessage = 3;
				else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_LBK\0") == 0)
					iMessage = 4;
				else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_MBD\0") == 0)
					iMessage = 5;
				else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_MBU\0") == 0)
					iMessage = 6;
				else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_MBK\0") == 0)
					iMessage = 7;
				else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_RBD\0") == 0)
					iMessage = 8;
				else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_RBU\0") == 0)
					iMessage = 9;
				else if (strcmp(WMMouseMsg[iLoop].szWMMouseMsg,"WM_RBK\0") == 0)
					iMessage = 10;

				// 移动到参数栈的下一个节点,x坐标
				pCommandNode = pCommandNode->pNext;
				dwX = (DWORD)atof(pCommandNode->Command.szElement);

				// 移动到参数栈的下一个节点,y坐标
				pCommandNode = pCommandNode->pNext;
				dwY = (DWORD)atof(pCommandNode->Command.szElement);

				// 移动到参数栈的下一个节点,辅助键
				pCommandNode = pCommandNode->pNext;
				keyFlags = atoi(pCommandNode->Command.szElement);

				// 退出循环
				break;
			}
		}

		// 如果有鼠标消息则对鼠标消息进行处理
		if (fWMMouseMsg)
		{
			// 处理鼠标消息
			if (iMessage == 1) //光标移动
			{
				//mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE,0,0,0,0);
				SetCursorPos(dwX,dwY);	
			}
			else if (iMessage == 2) //左键按下
			{
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTDOWN,0,0,0,0);
			}
			else if (iMessage == 3) //左键抬起
			{
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTUP,0,0,0,0);
			}
			//以下鼠标的消息还未处理!!!
			else if (iMessage == 4) 
			{
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTDOWN,0,0,0,0);
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTUP,0,0,0,0);
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTDOWN,0,0,0,0);
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTUP,0,0,0,0);
			}
			else if (iMessage == 5) 
			{
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MIDDLEDOWN,0,0,0,0);
			}
			else if (iMessage == 6) 
			{
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MIDDLEUP,0,0,0,0);
			}
			else if (iMessage == 7) 
			{
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MIDDLEDOWN,0,0,0,0);
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MIDDLEUP,0,0,0,0);
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MIDDLEDOWN,0,0,0,0);
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MIDDLEUP,0,0,0,0);
			}
			else if (iMessage == 8) 
			{
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_RIGHTDOWN,0,0,0,0);
			}
			else if (iMessage == 9) 
			{
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_RIGHTUP,0,0,0,0);
			}
			else if (iMessage == 10)
			{
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_RIGHTDOWN,0,0,0,0);
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_RIGHTUP,0,0,0,0);
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_RIGHTDOWN,0,0,0,0);
				mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_RIGHTUP,0,0,0,0);
			}
		}
		else
		{
			// 没有鼠标消息则判断是否有键盘消息
			fWMKeyBdMsg = FALSE;
			for (iLoop = 0;iLoop < nWMKeyBdMsg;iLoop++)
			{
				if (strcmp(pCommandNode->Command.szElement,WMKeyBdMsg[iLoop].szWMKeyBdMsg) == 0)
				{
					// 设置键盘消息标志
					fWMKeyBdMsg = TRUE;
					if (strcmp(WMKeyBdMsg[iLoop].szWMKeyBdMsg,"WM_KD\0") == 0)
						iMessage = 1;//按下键
					else if (strcmp(WMKeyBdMsg[iLoop].szWMKeyBdMsg,"WM_KU\0") == 0)
						iMessage = 2;//松开键

					// 移动到参数链表的下一个节点,Virtural 键码
					pCommandNode = pCommandNode->pNext;
					vk = atoi(pCommandNode->Command.szElement);

					//移动到参数链表的下一个节点,按下键标志
					pCommandNode = pCommandNode->pNext;
					fDown = atoi(pCommandNode->Command.szElement);

					// 移动到参数链表的下一个节点,按键重复数
					pCommandNode = pCommandNode->pNext;
					cRepeat = atoi(pCommandNode->Command.szElement);

					// 移动到参数链表的下一个节点,标志位
					pCommandNode = pCommandNode->pNext;
					flags = atoi(pCommandNode->Command.szElement);

					break;
				}
			}

			// 如果有键盘消息,则处理键盘消息
			if (fWMKeyBdMsg)
			{
				if (iMessage == 1) //模拟按键消息
				{
					keybd_event((BYTE)vk,(BYTE)vk,0,0);
				}
				else if (iMessage == 2) //模拟松开键的消息
				{
					keybd_event((BYTE)vk,(BYTE)vk,KEYEVENTF_KEYUP,0);
				}
			}
			else // 通用消息
			{
				for (iLoop = 0;iLoop < nMsg;iLoop++)
				{
					if (strcmp(pCommandNode->Command.szElement,Msg[iLoop].szMsg) == 0)
					{
						if (strcmp(Msg[iLoop].szMsg,"WM_COMP\0") == 0)
						{
							// 移动到参数链表的下一个节点,压缩级数
							pCommandNode = pCommandNode->pNext;
							//iCompressionLevel = atoi(pCommandNode->Command.szElement);
						}
						else if (strcmp(Msg[iLoop].szMsg,"WM_GRID\0") == 0)
						{
							// 移动到参数链表的下一个节点,x网格数
							pCommandNode = pCommandNode->pNext;
							//nGridX = atoi(pCommandNode->Command.szElement);

							// 移动到参数链表的下一个节点,y网格数
							pCommandNode = pCommandNode->pNext;
							//nGridY = atoi(pCommandNode->Command.szElement);

							// 清除当前的显示设置
							//ClearDisplay(hServerWnd);
							// 初始化新的显示设置
							//InitDisplay(hServerWnd);
						}
						else if (strcmp(Msg[iLoop].szMsg,"WM_CMOD\0") == 0)
						{
							// 移动到参数链表的下一个节点,每个屏幕点的字节数
							pCommandNode = pCommandNode->pNext;
							//bmBitsPixel = atoi(pCommandNode->Command.szElement);

							//ClearDisplay(hServerWnd);
							//InitDisplay(hServerWnd);
						}
					}
				}
			}
		}
	}
	// 清除命令队列
	Clear_Command(&CommandStart);
}



// 添加一个元素到命令栈中
struct CommandList *Add_Command(struct CommandList *pNode,struct CommandDS Command)
{
	if (pNode->pNext = (struct CommandList *)malloc(sizeof(struct CommandList)))
	{
		pNode = pNode->pNext;
		strcpy(pNode->Command.szElement,Command.szElement);
		pNode->pNext = NULL;
		return pNode;
	}
	return NULL;
}

//完全清除命令栈元素
void Clear_Command(struct CommandList *pStart)
{
	struct	CommandList	*pPrev;
	struct	CommandList	*pNode;
	while (pNode = pStart->pNext)
	{
		pPrev = pStart;
		pPrev->pNext = pNode->pNext;
		free(pNode);
	}
}


二是发送处代码,可以放在主对话框(窗口)的PreTranslateMessage,也可以放在App的PreTranslateMessage中:

BOOL CTestDlg::PreTranslateMessage(MSG* pMsg) 
{
	if (pMsg->message == WM_LBUTTONDOWN)//左键按下
	{
		if(m_bSend)
		{
			CPoint pt;
			GetCursorPos(&pt);

			memset(szMsg,'\0',sizeof(szMsg));
			sprintf(szMsg,"WM_LBD;%d;%d;%d;0;\0",pt.x, pt.y, keyFlags);
			LanSend(szMsg, strlen(szMsg));
		}
	}
	else if (pMsg->message == WM_LBUTTONUP)//左键抬起
	{
		if(m_bSend)
		{
			CPoint pt;
			GetCursorPos(&pt);
			
			memset(szMsg,'\0',sizeof(szMsg));
			sprintf(szMsg,"WM_LBU;%d;%d;%d;0;\0",pt.x, pt.y, keyFlags);
			
			LanSend(szMsg, strlen(szMsg));
		}
	}
	else if (pMsg->message == WM_MOUSEMOVE)	//光标移动
	{
		if(m_bSend)
		{
			POINT pt;
			::GetCursorPos(&pt);
			memset(szMsg,'\0',sizeof(szMsg));
			//sprintf(szMsg,"WM_MM;%d;%d;%d;0;\0", GET_X_LPARAM(pMsg->lParam), GET_Y_LPARAM(pMsg->lParam), 0);
			sprintf(szMsg,"WM_MM;%d;%d;%d;0;\0", pt.x, pt.y, 0);
			LanSend(szMsg, strlen(szMsg));
			return FALSE;
		}
	}
	else if (pMsg->message == WM_KEYDOWN)	//键盘按下
	{
		if(m_bSend)
		{
			memset(szMsg,'\0',sizeof(szMsg));
			sprintf(szMsg,"WM_KD;%d;%d;%d;%d;\0",pMsg->wParam, 0, 0, 0);
			LanSend(szMsg, strlen(szMsg));
		}
	}
	else if (pMsg->message == WM_KEYUP)		//键盘抬起
	{
		if(m_bSend)
		{
			memset(szMsg,'\0',sizeof(szMsg));
			sprintf(szMsg,"WM_KU;%d;%d;%d;%d;\0",pMsg->wParam, 0, 0, 0);
			LanSend(szMsg, strlen(szMsg));
		}
	}

	return CDialog::PreTranslateMessage(pMsg);
}

上述的LanSend是套接字发送(或者是串口发送)函数。




  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
当你有多台电脑的键盘鼠标放在狭窄的电脑桌上, 当你在每台电脑的键盘鼠标之间来回切换而焦头烂额时, 当你为了发送一段文本而不得不使用飞鸽或QQ甚至通过共享文件来时传递时, 你或许需要它:"远程虚拟控制" 这个软件实现了只使用一套键盘鼠标控制最多八台主机的功能, 并能在这些主机之间方便的传送文本内容, 实现在一台电脑上Ctrl + C 在另外一台电脑上Ctrl + V, 完成远程复制功能。 主机之间的切换无需进行任何附加操作, 你只需要将你的鼠标从这个显示移动到另一台显示器, 就如同将输入焦点从一个窗口移动到另一个窗口一样, 当完成鼠标切换后, 键盘也同时将输入焦点切换到相应的主机, 此后的大部分键盘输入操作均只对拥有鼠标的主机有效, 除了(Ctrl + ATL + DEL、WIN + L)这些组合键无法传送, 当按下这些组合键后, 主控机即刻获取输入焦点。 此软件只能在登陆后的默认桌面才可使用, 不能在登陆桌面, 屏保桌面下使用(等待解决这个问题), 在使用时如果系统安装有防火墙软件, 请将本程序加入防火墙的白名单或是相应配制文件中, 让防火墙放过检测。否则可能 给你的使用带来不便。 软件分为主控端和被控端, 可能存在多台被控端, 但是只能有一台主控端, 由主控端向其它被控端发送键盘鼠标指令, 以控制被控端的行为。 将程序分别解压到你每台的电脑上,依据配制说明将一台电脑配制成主控机, 将其它的电脑制成被控机。
### 回答1: WinForm批量远程控制桌面指的是使用WinForm技术实现批量控制远程桌面的功能。 在实现这个功能之前,我们需要了解远程桌面控制的基本原理。远程桌面控制是指通过网络连接远程计算机,并且能够在本地计算机上操作和控制远程计算机的桌面。通常,远程桌面控制涉及两个主要的角色,即服务端和客户端。 服务端是远程计算机上运行的软件,它负责提供远程访问的服务。客户端是本地计算机上运行的软件,它负责连接远程计算机,并且提供用户操作的界面。 在WinForm中实现批量远程控制桌面的基本步骤如下: 1. 创建一个WinForm应用程序,作为客户端的界面。 2. 使用WinForm的界面设计工具,设计一个用户界面,包括远程计算机列表、控制按钮等。 3. 实现远程计算机列表的管理功能,可以添加、删除和编辑远程计算机的信息。 4. 实现连接远程计算机的功能,可以通过网络连接到远程计算机,并且获取到远程桌面的图像数据。 5. 实现桌面控制的功能,可以在本地计算机上操作远程桌面的鼠标键盘等输入设备,并且将操作传递远程计算机上。 6. 实现批量控制的功能,可以选择多台远程计算机进行批量控制,可以同时进行多个远程桌面控制的操作。 7. 实现远程桌面的图像显示功能,可以将远程计算机的桌面图像实时显示在客户端的界面上。 8. 实现错误处理和异常处理的功能,保证程序的稳定性和安全性。 以上是用300字回答如何使用WinForm实现批量远程控制桌面的问题。希望以上内容对你有帮助。 ### 回答2: WinForm批量远程控制桌面是指通过使用WinForm技术来实现对多个远程桌面的同时控制。这项技术可用于一些需要同时管理多台远程计算机的场景,如企业级系统管理、网络维护等。 实现此功能的方法如下: 1. 建立服务器端:首先搭建一个服务器端程序,用于接收客户端连接和处理远程控制请求。可以基于WinForm开发,采用TCP/IP通信协议,通过监听服务器的IP地址和端口,等待客户端的连接请求。 2. 建立客户端:每个需要被控制的远程计算机都需要安装一个客户端程序,可以基于WinForm开发。客户端程序需要连接到服务器端,并向服务器发送远程控制请求。 3. 连接与通信:客户端请求连接服务器,服务器端接受连接请求后与客户端建立有效的双向通信。可以使用Socket进行数据传输实现双向的数据交互。 4. 桌面远程控制:服务器端在接受到来自客户端的远程控制请求后,通过使用相关的技术,如远程桌面协议(如RDP协议)、远程控制库(如OpenRPA)或远程桌面工具(如TeamViewer)等方式,实现远程计算机桌面的实时抓取、远程操作和控制。 5. 批量控制:通过在服务器端管理多个客户端的连接信息,可以实现对多个远程计算机的同时控制。可以通过列表或树形结构显示已连接的客户端,实时更新远程计算机的状态和活动。 总之,WinForm批量远程控制桌面功能的实现需要借助于服务器端和客户端的程序,并通过相关的远程控制技术实现对多台远程计算机的同时控制。这样可以方便地进行集中管理和维护,提高工作效率和减少成本。 ### 回答3: Winforms是一种用于开发Windows桌面应用程序的技术。要实现批量远程控制桌面,通常需要结合远程桌面协议(如RDP)和网络编程来实现。 首先,我们可以使用Winforms开发一个简单的应用程序,用于管理和控制远程桌面。这个程序可以提供用户界面,用于输入和管理要远程控制的目标机器的信息。 然后,我们可以使用远程桌面协议(如RDP)来远程连接到目标机器。在Winforms应用程序中,我们可以使用自带的Windows.Forms类库中的远程桌面控件(如RemoteDesktopControl)来实现桌面的远程访问和控制。 为了实现批量远程控制,我们可以在应用程序中提供一个列表或数据库,用于存储和管理要控制的目标机器的信息。用户可以通过UI界面进行添加、删除和编辑目标机器的信息。 用户可以选择一个或多个目标机器进行远程控制。通过远程桌面协议,我们可以在Winforms应用程序中创建多个远程连接,并将其显示在不同的窗口中,以便同时控制多台机器。 此外,我们还可以在应用程序中实现一些额外的功能,如屏幕共享、文件传输等。这些功能可以通过网络编程来实现,例如使用Socket或WCF通信机制。 在应用程序开发完成后,用户可以通过该应用程序方便地批量远程控制桌面。他们只需选择目标机器,并通过远程桌面控制来实现对这些机器的远程访问和控制。 总之,借助Winforms技术,并结合远程桌面协议和网络编程,我们可以开发一个功能强大的应用程序,实现批量远程控制桌面的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值