C# - 捕获鼠标光标图像 [英] C# - Capturing the Mouse cursor image

查看:148
本文介绍了C# - 捕获鼠标光标图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景


  • 我写一个屏幕捕获应用程序

  • 我的code基于从该项目中得出:<一href=\"http://www.$c$cproject.com/KB/cs/DesktopCaptureWithMouse.aspx?display=Print\">http://www.$c$cproject.com/KB/cs/DesktopCaptureWithMouse.aspx?display=Print

  • 请注意,code捕获鼠标光标也(这是可取的我)

我的问题


  • code工作正常时,鼠标光标是正常的指针或手形图标 - 鼠标正确呈现的截图

  • 然而,当鼠标光标变为插入点(以下简称工字钢光标) - 用于在记事本中输入例如 - 那么code不工作 - 结果是我得到一个模糊图像光标 - 喜欢它非常透明(灰色)版本,而不是空白和放大器;白人们所期望的。

我的问题


  • 如何捕获鼠标光标图像时,图像是这些工字钢型图像之一

  • 注:如果您单击原始文章的人提供了一个建议 - 它不起作用

这是从原来的文章。

 静态位图CaptureCursor(REF INT X,裁判int y)对
    {
        BMP位图;
        IntPtr的HICON;
        Win32Stuff.CURSORINFO CI =新Win32Stuff.CURSORINFO();
        Win32Stuff.ICONINFO ICINFO;
        ci.cbSize = Marshal.SizeOf(CI);
        如果(Win32Stuff.GetCursorInfo(出CI))
        {
            如果(ci.flags == Win32Stuff.CURSOR_SHOWING)
            {
                HICON = Win32Stuff.CopyIcon(ci.hCursor);
                如果(Win32Stuff.GetIconInfo(HICON,出ICINFO))
                {
                    X = ci.ptScreenPos.x - ((int)的icInfo.xHotspot);
                    Y = ci.ptScreenPos.y - ((INT)icInfo.yHotspot);                    图标IC = Icon.FromHandle(HICON);
                    BMP = ic.ToBitmap();
                    返回BMP;
                }
            }
        }        返回null;
    }


解决方案

虽然我不能确切地解释为什么会这样,我想我可以显示如何绕过它。

该ICONINFO结构包含两个成员,hbmMask和hbmColor,包含面罩和彩色位图,分别为光标(请参阅MSDN页的作的官方文档ICONINFO )。

当你调用的GetIconInfo()默认光标时,ICONINFO结构包含有效的掩码和彩色位图,如下图所示(注:红色边框已添加到清楚地显示图像边界):

默认光标掩码位图

默认光标颜色位图

当Windows绘制缺省光标时,掩码位图,首先用一个与光栅操作施加,则彩色位图被施加的XOR光栅操作。这导致不透明的光标和一个透明背景

当你调用的GetIconInfo()为I型光标,虽然,ICONINFO结构只包含一个有效的掩码位图,并没有彩色位图,如下图所示(注:再次,红色边框已添加到清楚地显示图像边界):

I型光标掩码位图

根据本ICONINFO文档中,工字梁光标然后单色光标。掩码位图的上半部分是与掩模和掩模位图的下半部分是异或位图。当Windows绘制I型光标,此位图的上半部分在与和光栅操作桌面首先绘制。位图的下半部然后通过与异或光栅操作顶端绘制。屏幕上,光标将显示为它后面的内容的逆

其中为您链接的原创文章评论提到了这一点。在桌面上,由于施加在桌面内容的光栅操作时,光标将显示正确的。然而,当图像被绘制在没有背景,如在贴出code时,光栅操作Windows执行导致褪色的形象。

话虽这么说,这个更新的CaptureCursor()方法将处理彩色和单色光标,提供一个纯黑色光标图像当光标是单色的。

 静态位图CaptureCursor(REF INT X,裁判int y)对
{
  关于cursorinfo Win32Stuff.CURSORINFO =新Win32Stuff.CURSORINFO();
  cursorInfo.cbSize = Marshal.SizeOf(cursorinfo段);
  如果(!Win32Stuff.GetCursorInfo(关于cursorinfo出))
    返回null;  如果(cursorInfo.flags!= Win32Stuff.CURSOR_SHOWING)
    返回null;  IntPtr的HICON = Win32Stuff.CopyIcon(cursorInfo.hCursor);
  如果(HICON == IntPtr.Zero)
    返回null;  Win32Stuff.ICONINFO ICONINFO;
  如果(!Win32Stuff.GetIconInfo(HICON,出ICONINFO))
    返回null;  X = cursorInfo.ptScreenPos.x - ((int)的iconInfo.xHotspot);
  Y = cursorInfo.ptScreenPos.y - ((INT)iconInfo.yHotspot);  使用(位图maskBitmap = Bitmap.FromHbitmap(iconInfo.hbmMask))
  {
    //这是一个单色的光标?
    如果(maskBitmap.Height == maskBitmap.Width * 2)
    {
      位图resultBitmap =新位图(maskBitmap.Width,maskBitmap.Width);      图形desktopGraphics = Graphics.FromHwnd(Win32Stuff.GetDesktopWindow());
      IntPtr的desktopHdc = desktopGraphics.GetHdc();      IntPtr的maskHdc = Win32Stuff.CreateCompatibleDC(desktopHdc);
      IntPtr的oldPtr = Win32Stuff.SelectObject(maskHdc,maskBitmap.GetHbitmap());      使用(图形resultGraphics = Graphics.FromImage(resultBitmap))
      {
        IntPtr的resultHdc = resultGraphics.GetHdc();        //这两个操作将导致一个黑色的鼠标在白色背景。
        //后来在code,以MakeTransparent()的调用将摆脱白色背景。
        Win32Stuff.BitBlt(resultHdc,0,0,32,32,maskHdc,0,32,Win32Stuff.TernaryRasterOperations.SRCCOPY);
        Win32Stuff.BitBlt(resultHdc,0,0,32,32,maskHdc,0,0,Win32Stuff.TernaryRasterOperations.SRCINVERT);        resultGraphics.ReleaseHdc(resultHdc);
      }      IntPtr的NEWPTR = Win32Stuff.SelectObject(maskHdc,oldPtr);
      Win32Stuff.DeleteObject(NEWPTR);
      Win32Stuff.DeleteDC(maskHdc);
      desktopGraphics.ReleaseHdc(desktopHdc);      //取下白色背景从BitBlt的调用,
      //导致黑色光标放在一个透明背景。
      resultBitmap.MakeTransparent(Color.White);
      返回resultBitmap;
    }
  }  图标图标= Icon.FromHandle(HICON);
  返回icon.ToBitmap();
}

有一些问题与code可能会或可能不会成为一个问题。


  1. 对于单色光标的检查只是测试是否高度是宽度的两倍。虽然这似乎是合乎逻辑的ICONINFO文档并不要求只单色游标由该定义。

  2. 有可能是一个更好的方式来呈现的BitBlt()光标 - 的BitBlt() - MakeTransparent()方法调用的组合我用

BACKGROUND

MY PROBLEM

  • Code works fine when the mouse cursor is the normal pointer or hand icon - the mouse is rendered correctly on the screenshot
  • However, when the mouse cursor is changed to the insertion point (the "I-beam" cursor) - for example typing in NOTEPAD - then code doesn't work - the result is that I get a faint image of the cursor - like a very translucent (gray) version of it instead of the blank & white one would expect.

MY QUESTION

  • How can I capture the mouse cursor image when the image is one of these "I-beam"-type images
  • NOTE: If you click on the original article someone offers a suggestion - it doesn't work

SOURCE

This is from the original article.

    static Bitmap CaptureCursor(ref int x, ref int y)
    {
        Bitmap bmp;
        IntPtr hicon;
        Win32Stuff.CURSORINFO ci = new Win32Stuff.CURSORINFO();
        Win32Stuff.ICONINFO icInfo;
        ci.cbSize = Marshal.SizeOf(ci);
        if (Win32Stuff.GetCursorInfo(out ci))
        {
            if (ci.flags == Win32Stuff.CURSOR_SHOWING)
            {
                hicon = Win32Stuff.CopyIcon(ci.hCursor);
                if (Win32Stuff.GetIconInfo(hicon, out icInfo))
                {
                    x = ci.ptScreenPos.x - ((int)icInfo.xHotspot);
                    y = ci.ptScreenPos.y - ((int)icInfo.yHotspot);

                    Icon ic = Icon.FromHandle(hicon);
                    bmp = ic.ToBitmap(); 
                    return bmp;
                }
            }
        }

        return null;
    }

解决方案

While I can't explain exactly why this happens, I think I can show how to get around it.

The ICONINFO struct contains two members, hbmMask and hbmColor, that contain the mask and color bitmaps, respectively, for the cursor (see the MSDN page for ICONINFO for the official documentation).

When you call GetIconInfo() for the default cursor, the ICONINFO struct contains both valid mask and color bitmaps, as shown below (Note: the red border has been added to clearly show the image boundaries):

Default Cursor Mask Bitmap

Default Cursor Color Bitmap

When Windows draws the default cursor, the mask bitmap is first applied with an AND raster operation, then the color bitmap is applied with an XOR raster operation. This results in an opaque cursor and a transparent background.

When you call GetIconInfo() for the I-Beam cursor, though, the ICONINFO struct only contains a valid mask bitmap, and no color bitmap, as shown below (Note: again, the red border has been added to clearly show the image boundaries):

I-Beam Cursor Mask Bitmap

According to the ICONINFO documentation, the I-Beam cursor is then a monochrome cursor. The top half of the mask bitmap is the AND mask, and the bottom half of the mask bitmap is the XOR bitmap. When Windows draws the I-Beam cursor, the top half of this bitmap is first drawn over the desktop with an AND raster operation. The bottom half of the bitmap is then drawn over top with an XOR raster operation. Onscreen, The cursor will appear as the inverse of the content behind it.

One of the comments for the original article that you linked mentions this. On the desktop, since the raster operations are applied over the desktop content, the cursor will appear correct. However, when the image is drawn over no background, as in your posted code, the raster operations that Windows performs result in a faded image.

That being said, this updated CaptureCursor() method will handle both color and monochrome cursors, supplying a plain black cursor image when the cursor is monochrome.

static Bitmap CaptureCursor(ref int x, ref int y)
{
  Win32Stuff.CURSORINFO cursorInfo = new Win32Stuff.CURSORINFO();
  cursorInfo.cbSize = Marshal.SizeOf(cursorInfo);
  if (!Win32Stuff.GetCursorInfo(out cursorInfo))
    return null;

  if (cursorInfo.flags != Win32Stuff.CURSOR_SHOWING)
    return null;

  IntPtr hicon = Win32Stuff.CopyIcon(cursorInfo.hCursor);
  if (hicon == IntPtr.Zero)
    return null;

  Win32Stuff.ICONINFO iconInfo;
  if (!Win32Stuff.GetIconInfo(hicon, out iconInfo))
    return null;

  x = cursorInfo.ptScreenPos.x - ((int)iconInfo.xHotspot);
  y = cursorInfo.ptScreenPos.y - ((int)iconInfo.yHotspot);

  using (Bitmap maskBitmap = Bitmap.FromHbitmap(iconInfo.hbmMask))
  {
    // Is this a monochrome cursor?
    if (maskBitmap.Height == maskBitmap.Width * 2)
    {
      Bitmap resultBitmap = new Bitmap(maskBitmap.Width, maskBitmap.Width);

      Graphics desktopGraphics = Graphics.FromHwnd(Win32Stuff.GetDesktopWindow());
      IntPtr desktopHdc = desktopGraphics.GetHdc();

      IntPtr maskHdc = Win32Stuff.CreateCompatibleDC(desktopHdc);
      IntPtr oldPtr = Win32Stuff.SelectObject(maskHdc, maskBitmap.GetHbitmap());

      using (Graphics resultGraphics = Graphics.FromImage(resultBitmap))
      {
        IntPtr resultHdc = resultGraphics.GetHdc();

        // These two operation will result in a black cursor over a white background.
        // Later in the code, a call to MakeTransparent() will get rid of the white background.
        Win32Stuff.BitBlt(resultHdc, 0, 0, 32, 32, maskHdc, 0, 32, Win32Stuff.TernaryRasterOperations.SRCCOPY);
        Win32Stuff.BitBlt(resultHdc, 0, 0, 32, 32, maskHdc, 0, 0, Win32Stuff.TernaryRasterOperations.SRCINVERT);

        resultGraphics.ReleaseHdc(resultHdc);
      }

      IntPtr newPtr = Win32Stuff.SelectObject(maskHdc, oldPtr);
      Win32Stuff.DeleteObject(newPtr);
      Win32Stuff.DeleteDC(maskHdc);
      desktopGraphics.ReleaseHdc(desktopHdc);

      // Remove the white background from the BitBlt calls,
      // resulting in a black cursor over a transparent background.
      resultBitmap.MakeTransparent(Color.White);
      return resultBitmap;
    }
  }

  Icon icon = Icon.FromHandle(hicon);
  return icon.ToBitmap();
}

There are some issues with the code that may or may not be a problem.

  1. The check for a monochrome cursor simply tests whether the height is twice the width. While this seems logical, the ICONINFO documentation does not mandate that only a monochrome cursor is defined by this.
  2. There is probably a better way to render the cursor that the BitBlt() - BitBlt() - MakeTransparent() combination of method calls I used.

这篇关于C# - 捕获鼠标光标图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆