【问题标题】:Include mouse cursor in screen capture在屏幕截图中包含鼠标光标
【发布时间】:2023-03-08 23:10:02
【问题描述】:

我使用 CreateDC / BitBlt / GetDIBits 等捕捉屏幕,但没有捕捉到光标。是否有一些简单的论点或包含它的东西?

【问题讨论】:

  • 一句话,没有。光标是由操作系统绘制的,因此,它实际上并不是由选择到 HDC 中的 HBITMAP 保存的图像的一部分。绘制到屏幕时,它绘制在此图像的(副本)之上。处理此问题的方法是在执行捕获时获取鼠标位置。然后在该位置绘制光标图像的副本。请注意,当您按下 PrtSc 按钮时,也不会捕获光标。 InstantDemo 软件(一个屏幕录制应用程序)采用了我提到的方法来显示鼠标光标。
  • 如何获取光标的图像?
  • 通过谷歌搜索“指针光标”,然后下载您喜欢的。只有 500 万次点击 - 我想你会找到你喜欢的。
  • 但我需要光标与屏幕上的相同,因为它将在具有自定义光标的软件中捕获。
  • 你应该这么说很有趣,我在发布回复后不久就考虑了这种可能性。在这种情况下,您可以使用 GetCursor 函数获取光标,但我认为这在另一个进程或线程中不起作用。在这种情况下,我怀疑您应该使用 GetCursorInfo。 msdn.microsoft.com/en-us/library/windows/desktop/… 似乎是一个不错的起点。值得一提的是,它们与 HICON 非常相似,尽管有额外的变量来定义热点的位置。 (即“正常”光标的左上角,十字准线的中间中心)

标签: c++ c screenshot screen-capture


【解决方案1】:
#include <Windows.h>
#include <stdio.h>
#include <assert.h>

void scrshot() {
    HWND hwnd = GetDesktopWindow();
    HDC hdc = GetWindowDC(hwnd);
    HDC hdcMem = CreateCompatibleDC(hdc);
    int cx = GetDeviceCaps(hdc, HORZRES);
    int cy = GetDeviceCaps(hdc, VERTRES);
    HBITMAP hbitmap(NULL);
    hbitmap = CreateCompatibleBitmap(hdc, cx, cy);
    SelectObject(hdcMem, hbitmap);
    BitBlt(hdcMem, 0, 0, cx, cy, hdc, 0, 0, SRCCOPY);
    CURSORINFO cursor = { sizeof(cursor) };
    GetCursorInfo(&cursor);
    if (cursor.flags == CURSOR_SHOWING) {
        RECT rect;
        GetWindowRect(hwnd, &rect);
        ICONINFO info = { sizeof(info) };
        GetIconInfo(cursor.hCursor, &info);
        const int x = cursor.ptScreenPos.x - rect.left - rect.left - info.xHotspot;
        const int y = cursor.ptScreenPos.y - rect.top - rect.top - info.yHotspot;
        BITMAP bmpCursor = { 0 };
        GetObject(info.hbmColor, sizeof(bmpCursor), &bmpCursor);
        DrawIconEx(hdcMem, x, y, cursor.hCursor, bmpCursor.bmWidth, bmpCursor.bmHeight,
            0, NULL, DI_NORMAL);
    }
}

int main(){
    scrshot();
    return 0;
}

【讨论】:

    【解决方案2】:

    在 cmets 中发生的进一步讨论之后,我有机会进一步调查这个问题。结果,我想出了下面的代码,它将抓取当前光标的 HBITMAP 并将其绘制到屏幕上。

    由于光标实际上是一个HICON,它带有一个掩码。最初,我只是做了一个简单的 BitBlt - 但是,我得到了一个 32x32 黑色方块,光标在左上角 1/4 左右。

    然后我使用 MaskBlt 进行了调查。根据应用程序启动时光标所在的位置,我得到等待光标、NS 调整大小光标或标准指针。我想您可以启动一个计时器并添加一个 WM_TIMER 处理程序以每秒触发几次,以便实时更新光标,因为它在系统中的其他窗口中使用。做这样的事情似乎只是出于好奇,所以我没有打扰。

    编辑:我实际上确实在 WM_INITDIALOG 中启动了一个计时器并在 WM_TIMER 中处理它。您现在可以看到图像每秒更新 10 次。出于某种原因,I 型光标似乎根本没有显示——我猜这是需要进一步调查的案例。

    这是完整列表(resource.rc 和 resource.h 除外 - 只需创建一个对话框应用程序并确保在 Main 中调用 DialogBox 时使用了对话框的资源 ID)

    #include <windows.h>
    #include <commctrl.h>
    #include <stdio.h>
    #include "resource.h"
    
    HINSTANCE hInst;
    
    HBITMAP getCursorHBITMAP(HBITMAP *maskBmp)
    {
        CURSORINFO pci;
        ICONINFO iconinfo;
        HBITMAP result;
    
        pci.cbSize = sizeof(pci);
        GetCursorInfo(&pci);
    
        if (GetIconInfo(pci.hCursor,&iconinfo))
        {
            result = iconinfo.hbmColor;
            if (maskBmp)
                *maskBmp = iconinfo.hbmMask;
        }
        else
            result = NULL;
    
        return result;
    }
    
    BOOL CALLBACK DlgMain(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        switch(uMsg)
        {
            case WM_INITDIALOG:
            {
                SetTimer(hwndDlg, 1, 100, NULL);
            }
            return TRUE;
    
            case WM_TIMER:
            {
                InvalidateRect(hwndDlg, NULL, true);
            }
            return 0;
    
            case WM_ERASEBKGND:
            {
                HDC hdc = (HDC)wParam;
                RECT mRect;
                GetClientRect(hwndDlg, &mRect);
                FillRect(hdc, &mRect, (HBRUSH)GetStockObject(GRAY_BRUSH));
            }
            return 1;
    
            case WM_PAINT:
            {
                HBITMAP oldBm, cursorBmp, maskBmp;
    
                cursorBmp = getCursorHBITMAP(&maskBmp);
                if (cursorBmp)
                {
                    HDC hdc;
                    PAINTSTRUCT ps;
                    HDC memDC;
                    BITMAP bm;
    
                    hdc = BeginPaint(hwndDlg, &ps);
                    memDC = CreateCompatibleDC(hdc);
                    oldBm = (HBITMAP) SelectObject(memDC, cursorBmp);
    
                    GetObject(cursorBmp, sizeof(bm), &bm);
        //            printf("Cursor size: %d x %d\n", bm.bmWidth, bm.bmHeight);
    
        //            BitBlt(hdc, 10,10, 32,32, memDC, 0,0, SRCCOPY);
                    MaskBlt(hdc, 10,10, bm.bmWidth, bm.bmHeight, memDC, 0,0, maskBmp, 0,0, MAKEROP4(SRCPAINT,SRCCOPY) );
    
    
                    SelectObject(memDC, oldBm);
                    DeleteDC(memDC);
                    EndPaint(hwndDlg, &ps);
                }
            }
            return 0;
    
            case WM_CLOSE:
            {
                EndDialog(hwndDlg, 0);
            }
            return TRUE;
    
            case WM_COMMAND:
            {
                switch(LOWORD(wParam))
                {
                }
            }
            return TRUE;
        }
        return FALSE;
    }
    
    
    int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
    {
        hInst=hInstance;
        InitCommonControls();
        return DialogBox(hInst, MAKEINTRESOURCE(DLG_MAIN), NULL, (DLGPROC)DlgMain);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-10
      • 2014-03-25
      • 2020-06-24
      相关资源
      最近更新 更多