怎样得到鼠标光标图相关信息(DirectX 截图取得光标 的方法)
来源:互联网 发布:象棋路边残局知乎 编辑:程序博客网 时间:2024/05/23 15:44
缘由: 由于DirectX 作截图渲染的时候.. 截取整个桌面的图时,它没有得到光标... 对于做桌面的融合等时,在扩展桌面的操作因为看不到
鼠标光标的原因.对操作带来一定的不便.. 所以要想办法把光标也一起截图渲染的时候搞过去...
解决方案: 得到光标的图的相关信息. 在用DirectX 得到截取桌面图后.. 直接改写对应的像素数据.. (一般光标是 32*32,要改写的数据也就是这么多.效率方面一般不受影响的...)
本文示例程序: 可到我的资源下得到: GetCursorIco.rar...
具体步骤:在MFC 中利用对话框,加一个按钮,对应的函数如下即可>>
不足: 本文其实没有达到能截取到动态鼠标光标的目的,虽然这种应用场合比较少.. 我找了很多专业的截图工具,都是没有截取到动态光标,., 也就是比较一个"忙" 的光标,每次截取的时候,都仅截取到,那光标的第一帧图...
这种应用场合:如果要做截图渲染,每秒几十帧,上百帧的.. 那里截得的光标就不会动态了.. 这种没有解决.,如果有谁有更好的方法.可以告知一下.. wen438671344@qq.com
void CGetCursorIconDlg::OnBnClickedButton1(){// TODO: 在此添加控件通知处理程序代码// for (int i = 0; i < 200; i++){// Sleep(2000); DrawCursor(100, 100);}}// 功能:画光标// posX: 光标要画到的x 坐标,posY :光标要画到的y 坐标.// 附注: 整个函数内容啰嗦.. 为了达到把相应的图输出来观察.加入了不少内容...都是学习的原因..// 正式场合使用时,可写得精简.. void CGetCursorIconDlg::DrawCursor(const int posX, const int posY){// 参考 http://bbs.csdn.net/topics/300196964//Sleep(2000);// 停2 秒,方便点击了按钮后,移到别的地方能截到别处的光标.(不延时,一点就取到当时的光标了,不利于观察)CURSORINFO ci;ci.cbSize=sizeof CURSORINFO;if( !(::GetCursorInfo(&ci) )) return;// 判断光标是否为显示状态,若不是,则返回if (ci.flags != CURSOR_SHOWING) return;#if 0// 得到光标图标信息ICONINFO iconif;ZeroMemory(&iconif, sizeof(iconif)); ::GetIconInfo(ci.hCursor,&iconif); // 这样直接得到容易出错,见下面分析#elseHICON hCursorCopy;// 注意啊.如果不用这一句,把原来的的位图信息拷贝出来的话. 如果下面的信息操作的时间长一点的话,但是// 光标在移动的时候已经有变化了.这里光标指向的句柄指向都已经改变了.所以再用 GetBitmapBits 得到的数据时..// 就出错了.. // 所以,要用到光标的位图信息时,最好是先拷贝一次数据出来...// // 2012.12.18 by benbenhCursorCopy = ::CopyIcon(ci.hCursor); // 得到光标图标信息ICONINFO iconif;ZeroMemory(&iconif, sizeof(iconif)); ::GetIconInfo(hCursorCopy, &iconif);#endif//////////////////////////////////////////////////////////////////////////// 把光标图标的 颜色图 保存下来观察下(注意,这里要判断一下句柄是否为空,因为有些黑白图标则没有这个颜色图,比如 I-Beam 光标) CImage image;if (NULL != iconif.hbmColor){ // 注意啊. 对于一些光标为黑白两种颜色的,根本就不需要 颜色位图.所以这时,hbmColor 为空的情况也是有的..所以这里要判断 // 句柄是否为空. image.Attach(iconif.hbmColor); image.Save(_T("..\\cursor\\color.bmp")); image.Detach();}// 保存 掩码图image.Attach(iconif.hbmMask);image.Save(_T("..\\cursor\\mask.bmp"));image.Detach();////////////////////////////////////////////////////////////////////////////// 从磁盘上加载一幅图.看测试的效果,把测试的效果图输出到 文件夹 cursor 目录下HBITMAP hBitmap = LoadBitmap(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDB_BITMAP1));BITMAP bitmap_Src ;GetObject(hBitmap, sizeof(BITMAP), &bitmap_Src);CImage imgSource;imgSource.Attach(hBitmap);BITMAP bitmap_mask;// 得到光标 掩码图相关的信息, 注意 bitmap_mask. bmBits 的结果为NULL,// 可以用 GetBitmapBits 得到数据像素位的信息GetObject(iconif.hbmMask, sizeof(BITMAP), &bitmap_mask); BITMAP bitmap_color;GetObject(iconif.hbmColor, sizeof(BITMAP), &bitmap_color);HDC hDC = NULL ;HBITMAP hOldBitmap = NULL ;if (NULL != iconif.hbmColor){#ifdef NEW_VERSION hDC = ::CreateCompatibleDC( NULL ); if(!hDC) return; hOldBitmap = HBITMAP( ::SelectObject( hDC, iconif.hbmColor ) );#else int cBytes = bitmap_color.bmWidthBytes * (bitmap_color.bmHeight); char *pBitColor = new char[cBytes]; GetBitmapBits(iconif.hbmColor, cBytes, pBitColor);#endif}int maskBytes = bitmap_mask.bmWidthBytes * (bitmap_mask.bmHeight);char *pBitMask = new char[maskBytes];GetBitmapBits(iconif.hbmMask, maskBytes, pBitMask);// 这里应该判断一下能否内存申请成功的.. 这里只是 demo .我没有这样做了.. 注意一下.这在实际应用中需要改成类似于// 以下的..// 其实我觉得这里因为经常调用.. 用类成员变量(或全局变量)<一个保存内存块的指针,另一个保存大小>来保存申请的内存空间..// 没有必要每次进入时申请,离开时释放... 应该这样:申请一块内存后.不释放 .. 到下次用到时..// 判断下次要用到的内存有没有大于当前已经申请的,如果是大于当前已经申请的,才释放当前,另申请一块内存..( benben)// e.g.//if ( (!m_pBufferMask) || (m_MaskBytes < BMask) ) // 指针为空 或 当前已经申请的内存小于现在即将要用到的内存的大小//{// if(m_pBufferMask) delete m_pBufferMask;// m_pBufferMask = new char[BMask]; // if(!m_pBufferMask) break; // 申请内存空间不成功. // m_MaskBytes = BMask; // 保存当前申请的内存空间的大小//}// 解说:对于光标为黑白图的.得到的iconif.hbmMask 的图 就是 32*64(前半部分与 要贴光标的图作"与"运算.// 后半部分,则与图作 "异或" 运算..if (NULL != iconif.hbmColor){ for (int row = 0; row < bitmap_color.bmHeight; ++row) { for (int col = 0; col < bitmap_color.bmWidth; ++col) { COLORREF color = imgSource.GetPixel(col+ posX, row+posY); DWORD red = GetRValue(color); DWORD green = GetGValue(color); DWORD blue = GetBValue(color); // 与光标掩码图 作 "与" 运算DWORD ret = getBitValue(bitmap_mask.bmWidth, bitmap_mask.bmHeight, pBitMask, col, row); // 注意以下三句不要写成 color &= ret; red &= ret; green &= ret; blue &= ret;#ifdef NEW_VERSION // 这个是新的版本.. // 今天和同事讨论到这个彩色图像不一定就是每个像素是 32 来存储.. // 如果是 32位(也就是说用 24 位表示颜色的情况, 没有颜色映射表.所以像我这样做也就足够了..) // 如果这个光标的颜色图可能是其他种类的(比如用 16 位来表示一个像素的时候.要显示到屏幕上)必然会有 // 一个颜色映射表... 一个方案是可以自己考虑来通过 位图信息的相关数据来做.. 另一个方案即是我参考了 // MFC 源码的 CImage 类(找atlimage.h这个头文件) 的成员函数 CImage::GetPixel(int, int) 的做法.. // COLORREF clr = ::GetPixel( hDC, col, row); red |= GetRValue(clr); green |= GetGValue(clr); blue |= GetBValue(clr);#else // 原始版本 // 与光标颜色图 作 "或" 运算(注意以下的顺序)blue |= pBitColor[bitmap_color.bmWidthBytes * row + col * (bitmap_color.bmBitsPixel/8)]; green |= pBitColor[bitmap_color.bmWidthBytes * row + col * (bitmap_color.bmBitsPixel/8) + 1]; red |= pBitColor[bitmap_color.bmWidthBytes * row + col * (bitmap_color.bmBitsPixel/8) + 2];#endif // 把原来像素设置回去 imgSource.SetPixel(col+posX, row+posY, RGB(red, green, blue)); } }}else{ for (int row = 0; row < bitmap_mask.bmHeight/2; ++row) { for (int col = 0; col < bitmap_mask.bmWidth; ++col) { COLORREF color = imgSource.GetPixel(col+posX, row+posY); // 这里取得像素数据 DWORD red = GetRValue(color); DWORD green = GetGValue(color); DWORD blue = GetBValue(color); DWORD ret = getBitValue(bitmap_mask.bmWidth, bitmap_mask.bmHeight, pBitMask, col, row); color &= ret; ret = getBitValue(bitmap_mask.bmWidth, bitmap_mask.bmHeight,\ pBitMask, col, bitmap_mask.bmHeight /2 + row); // 取得后半部分图的对应像素位 color ^= ret; // 把原来像素设置回去 imgSource.SetPixel(col+posX, row+posY, color); } }}imgSource.Save(_T("..\\cursor\\result.bmp"));imgSource.Detach();// 释放资源if(pBitMask) delete pBitMask;#ifdef NEW_VERSIONif(hDC) ::DeleteDC( hDC );if(hOldBitmap) ::SelectObject( hDC, hOldBitmap );#elseif(pBitColor) delete pBitColor;#endif// 检测内存泄漏.._CrtDumpMemoryLeaks();//////////////////////////////////////////////////////////////////////////// ......// 这下面可能做DirectX 相关的渲染操作..// ...}// 功能: 取得单色图对应像素位的信息// 返回值; 如果对应该位为 1 ,则返回0xffffffff; 如果对应位为 0, 则返回 0DWORD CGetCursorIconDlg::getBitValue(int width, int height, void* p, int x, int y){char *pBit = (char*)p;int num = x/8;int bits = x % 8;if(1 == ((pBit[(width/8) * y + num] >> (7 - bits) ) & 1)){ return 0xffffffff; }else{ return 0; // 注意如果是像DirectX 得,有 阿尔法 值的情况,这里可返回 0Xff000000; 这样就不至于影响到 阿尔法的值了...}}
- 怎样得到鼠标光标图相关信息(DirectX 截图取得光标 的方法)
- 用DIRECTX美化自己的鼠标光标
- 得到文件系统的相关信息
- 得到APK 的相关信息
- WPF窗体隐藏鼠标光标的方法
- MFC加载鼠标光标图形的方法
- intra-mart中取得登陆用户相关信息的数据的方法
- android得到手机卡的相关信息
- 得到系统事务的相关信息
- 得到手机sim卡的相关信息
- DirectX截图黑屏的解决办法
- DirectX截图黑屏的解决办法
- DirectX截图黑屏的解决办法
- VC屏幕截图源程序(支持对鼠标光标位置的保存)
- 鼠标光标的位置,
- 取得APP/LIB版本信息的方法
- VC设置鼠标光标方法
- 取得当前屏幕的截图
- 120941138报:凌乱了,java比c++快
- js 去除最后一个,
- 分布式系统原理要点
- 120941138报:IOS项目实战-登录解析(Http请求)
- UVA 494 Kindergarten Counting Game
- 怎样得到鼠标光标图相关信息(DirectX 截图取得光标 的方法)
- AIR文件操作
- Java串口编程
- C#实现文件下载的几种方式
- 120941138报:OpenERP 7.0 即将发布
- C# 文件下载四方法
- 小沈阳恶搞版《大话切糕》
- 120941138报:关于项目经理/IT顾问的两则笑话
- 120941138报:Ubuntu 有了第一个全球 CDN 更新源