如何在windows截屏的时候带上鼠标光标

2018-06-23  本文已影响0人  叶迎宪

https://www.codeproject.com/Articles/5051/Various-methods-for-capturing-the-screen 文章中提到,使用GDI或者DirectX方法截屏的时候,是不会有鼠标在截图之中的。要将鼠标补上,必须自己动手画。可以参考ffmpeg当中的gdigrab.c实现 https://github.com/FFmpeg/FFmpeg/blob/master/libavdevice/gdigrab.c

实现要点:

  1. 调用CreateDIBSection创建一个bitmap,用于将截屏图像放上去并且在上面使用GDI进行绘制
  2. 使用GetCursorInfo获得当前鼠标的信息,调用DrawIcon将鼠标光标画上去
HDC dcTemp;  // 用于绘制鼠标的DC
HBITMAP hBmp;  // 存放截图和用于绘制的bitmap
void *gdiBuffer;  // 存放截图和绘制结果的缓存区

bool InitGDI()
{
    HDC dcDesktop = ::GetDC(NULL);
    dcTemp = ::CreateCompatibleDC(dcDesktop);

    int screenWidth = GetSystemMetrics(SM_CXSCREEN);
    int screenHeight = GetSystemMetrics(SM_CYSCREEN);

    //prepare the bitmap attributes
    BITMAPINFO bmInfo;
    memset(&bmInfo.bmiHeader, 0, sizeof(BITMAPINFOHEADER));
    bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmInfo.bmiHeader.biWidth = screenWidth;
    bmInfo.bmiHeader.biHeight = -screenHeight;
    bmInfo.bmiHeader.biPlanes = 1;
    bmInfo.bmiHeader.biBitCount = 32;
    bmInfo.bmiHeader.biCompression = BI_RGB;

    gdiBuffer = NULL;
    hBmp = CreateDIBSection(dcTemp, &bmInfo, DIB_RGB_COLORS,
        &gdiBuffer, NULL, 0);

    SelectObject(dcTemp, hBmp);

    if (dcDesktop)
        ReleaseDC(NULL, dcDesktop);

    return true;
}

void DeinitGDI()
{
    if (dcTemp)
        DeleteDC(dcTemp);
    if (hBmp)
        DeleteObject(hBmp);
}

void PaintMousePointer()
{
    CURSORINFO ci = { 0 };

    ci.cbSize = sizeof(ci);

    if (GetCursorInfo(&ci)) {
        HCURSOR icon = CopyCursor(ci.hCursor);
        ICONINFO info;
        POINT pos;

        info.hbmMask = NULL;
        info.hbmColor = NULL;

        if (ci.flags != CURSOR_SHOWING)
            return;

        if (!icon) {
            /* Use the standard arrow cursor as a fallback.
            * You'll probably only hit this in Wine, which can't fetch
            * the current system cursor. */
            icon = CopyCursor(LoadCursor(NULL, IDC_ARROW));
        }

        if (!GetIconInfo(icon, &info)) {
            goto icon_error;
        }

        pos.x = ci.ptScreenPos.x - info.xHotspot;
        pos.y = ci.ptScreenPos.y - info.yHotspot;

        if (!DrawIcon(dcTemp, pos.x, pos.y, icon))
        {
        }

    icon_error:
        if (info.hbmMask)
            DeleteObject(info.hbmMask);
        if (info.hbmColor)
            DeleteObject(info.hbmColor);
        if (icon)
            DestroyCursor(icon);
    }
    else {       
    }
}

HRESULT capture(IDirect3DDevice9* d3ddev9)
{
    // ...省略截屏部分
    if (lr.pBits)
    {
        uint8_t *dst_data[4] = { 0 };
        int dst_linesize[4];
        uint8_t *src_data[4] = { 0 };
        int src_linesize[4];
        struct SwsContext *sws_ctx = NULL;
        AVFrame *frame = NULL;
        int ret;

        // 将截屏数据放入bitmap中
        memcpy(gdiBuffer, lr.pBits, screenWidth * screenHeight * 4);

        // 把鼠标画上去
        PaintMousePointer();

        // ...省略了中间部分
        // 将bitmap的BGRA格式转换成YUV420P
        src_data[0] = (uint8_t*)gdiBuffer;
        src_linesize[0] = screenWidth * 4;

        sws_scale(sws_ctx, src_data,
            src_linesize, 0, screenHeight, dst_data, dst_linesize);

        // ...省略了后面
}

上一篇下一篇

猜你喜欢

热点阅读