4.鼠标事件处理
Strategist_MOUSE.h
#pragma once
class CStrategist_MOUSE
{
public:
CStrategist_MOUSE(){}
virtual void DealCommand() = 0;
~CStrategist_MOUSE(){}
};
Mouse.h
#pragma once
#include"ServerSocket.h"
#include"Strategist_MOUSE.h"
typedef struct MOUSEEVENT {//类型结构可以和函数重名
MOUSEEVENT() {
nAction = 0;
nButton = -1;
ptXY.x = 0;
ptXY.y = 0;
}
WORD nAction;//点击、移动、双击
WORD nButton;//左键右键中键
POINT ptXY;//坐标
}MOUSEEV, * PMOUSEEV;
class CMouse: public CStrategist_MOUSE
{
public:
CMouse() {
if (CServerSocket::GetInstance()->GetPacket().PacketCommand == 11) {
memcpy(&mouse, CServerSocket::GetInstance()->GetPacket().PacketData.c_str(), sizeof(MOUSEEV));
return;
}
OutputDebugString(_T("获取鼠标的控制命令失败,不匹配!"));
}
~CMouse() {}
public:
void DealCommand() override;
private:
void MouseEvent();
private:
MOUSEEV mouse;
};
Mouse.cpp
#include "pch.h"
#include "Mouse.h"
void CMouse::DealCommand()
{
if (CServerSocket::GetInstance()->GetPacket().PacketCommand == 11) {
MouseEvent();
}
}
void CMouse::MouseEvent()
{
DWORD nFlags = 0;
if (nFlags != 8)
switch (mouse.nButton)
{
case 0://左键
nFlags = 1;
break;
case 1:
nFlags = 2;
break;//右键
case 2://中键
nFlags = 4;
break;
case 4:
nFlags = 8;//没有按键
break;
}
if (nFlags != 8)
SetCursorPos(mouse.ptXY.x, mouse.ptXY.y);
switch (mouse.nAction)
{
case 0://单击
nFlags |= 0x10;
break;
case 1://双击
nFlags |= 0x20;
break;
case 2://按下拖动
nFlags |= 0x40;
break;
case 3://按键松开
nFlags |= 0x80;
break;
default:
break;
}
switch (nFlags)
{
case 0x21://左键双击
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, GetMessageExtraInfo());
case 0x11://左键单击
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, GetMessageExtraInfo());
break;
case 0x41://左键按下
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, GetMessageExtraInfo());
break;
case 0x81://左键松起
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, GetMessageExtraInfo());
break;
//**
case 0x22://右键双击
mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, GetMessageExtraInfo());
case 0x12://右键单击
mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, GetMessageExtraInfo());
break;
case 0x42://右键按下
mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, GetMessageExtraInfo());
break;
case 0x82://右键松起
mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, GetMessageExtraInfo());
break;
//**
case 0x24://中键双击
mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, GetMessageExtraInfo());
case 0x14://中键单击
mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, GetMessageExtraInfo());
mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, GetMessageExtraInfo());
break;
case 0x44://中键按下
mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, GetMessageExtraInfo());
break;
case 0x84://中键松起
mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, GetMessageExtraInfo());
break;
case 0x08://单纯鼠标移动
mouse_event(MOUSEEVENTF_MOVE, mouse.ptXY.x, mouse.ptXY.y, 0, GetMessageExtraInfo());
break;
default:
break;
}
CPacket pack(11, NULL, 0);
CServerSocket::GetInstance()->Send(pack);
}
5.屏幕发送功能
Strategist_SCREEN.h
#pragma once
class CStrategist_SCREEN
{
public:
CStrategist_SCREEN() {}
virtual void DealCommand() = 0;
~CStrategist_SCREEN() {}
};
Screen.h
#pragma once
#include<atlimage.h>//vs2008后有的
#include"Strategist_SCREEN.h"
#include"ServerSocket.h"
class CScreen : public CStrategist_SCREEN
{
public:
CScreen() {
}
~CScreen() {}
public:
void DealCommand() override;
private:
void SendScreen();
private:
CImage screen;//非常适合GlobalDeviceInterface编程
};
Screen.cpp
#include "pch.h"
#include "Screen.h"
void CScreen::DealCommand()
{
SendScreen();
}
void CScreen::SendScreen()
{//Windows GDI(图形设备接口)和 GDI+ 库的一些函数。
HDC hScreen = ::GetDC(NULL);//获取设备上下文
//每个像素占用需要多少个bit通常RGB888用24bit表示,如果ARGB8888则是32bit。RGB565低性能手机用的
int nBitPerPixel = GetDeviceCaps(hScreen, BITSPIXEL);
int nWidth = GetDeviceCaps(hScreen, HORZRES);//获取屏幕水平分辨率我这里是1920
int nHeight = GetDeviceCaps(hScreen, VERTRES);//1080
screenImage.Create(nWidth, nHeight, nBitPerPixel);//screenImage被创建为存储屏幕图像数据的容器。
BitBlt(screenImage.GetDC(), 0, 0, nWidth, nHeight, hScreen, 0, 0, SRCCOPY);//1920*1080,1020不截任务栏
//如上行代码所示,利用位块传输函数讲屏幕图像从上下文复制到容器中
ReleaseDC(NULL, hScreen);//释放上下文
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, 0);//内存分配一个全局句柄
if (hMem == NULL) {
return;
}
IStream* pStream = NULL;
HRESULT ret = CreateStreamOnHGlobal(hMem, TRUE, &pStream);//全局句柄创建一个流对象,用于将图像数据保存在内存中
if (ret == S_OK)
{//存到内存中
screenImage.Save(pStream, Gdiplus::ImageFormatPNG);//容器中的图像保存在内存流中以PNG格式
LARGE_INTEGER bg = { 0 };
pStream->Seek(bg, STREAM_SEEK_SET, NULL);//文件指针移动到流的开头
PBYTE pData = (PBYTE)GlobalLock(hMem);//锁定内存后准备发送
SIZE_T nSize = GlobalSize(hMem);
//
CPacket pack(12, pData, nSize);
CServerSocket::GetInstance()->Send(pack);
GlobalUnlock(hMem);//内存解锁
}
//DWORD tick = GetTickCount64();
//screen.Save(_T("test.png"), Gdiplus::ImageFormatPNG);//png通常比jpeg小些。带宽小些
//TRACE("png:%d\n", GetTickCount64() - tick);
//tick = GetTickCount64();
//screen.Save(_T("test2020.jpg"), Gdiplus::ImageFormatJPEG);//jpeg会快些
//TRACE("jpeg:%d\n", GetTickCount64() - tick);
pStream->Release();//释放流对象
GlobalFree(hMem);//释放内存
screenImage.ReleaseDC();//释放对象的设备上下文
}
内存流:内存流是一种将数据存储在内存中而不是文件中的数据流。在这个特定的情境中,内存流(IStream
接口)的使用是为了将图像数据保存到内存中,然后可以方便地对这块内存中的数据进行操作,例如读取、传输或其他处理。
- 临时存储:暂存内存,相比于磁盘中形成图片文件,然后在去传输效率更快。
- 灵活性:内存流允许在不涉及实际文件的情况下进行数据的读写。
- 方便的接口:
IStream
接口提供了一组用于在流中读写数据的通用方法,这些方法可以用于不同类型的数据源,包括文件、内存、网络等。使用内存流,可以更方便地利用这些通用方法进行数据处理。