如何使用X11从所有显示屏获取屏幕截图?

时间:2015-06-18 06:01:49

标签: c screenshot x11

我正在编写截图事件,并为Mac找到了这个优秀主题:How can I get screenshot from all displays on MAC?

我想知道是否有人拥有x11库的等价物?获取所有显示器然后将它们全部截图?

我找到了这个主题:https://stackoverflow.com/a/5293559/1828637

但是从那里链接的代码对于像我这样的新手来说并不容易。

RootWindow(3)将所有监视器的区域合并在一起吗?然后我可以通过并获取监视器尺寸然后XGetImage返回RootWindow上的那些部分?

我遇到过这个主题:How do take a screenshot correctly with xlib?但我不确定它是否支持多显示器。我在ctypes中这样做,所以我不能轻易地测试该代码,而无需先完成编写它的艰苦任务。所以我想知道这是否正确或如何修改它来处理多个星期一?

修改

那里的海报分享了他的代码,在这里可以看到:https://github.com/Lalaland/ScreenCap/blob/master/src/screenCapturerImpl.cpp#L96但它很复杂而且我不理解它。它使用XFixesGetCursorImage这样的功能,我无法在文档中找到它,而且我也看不到多监视器如何在那里工作。该主题的作者警告他不记得代码,它可能不适用于现代Linux。

1 个答案:

答案 0 :(得分:1)

这不是一个完美的答案,但是可以修改以下代码以获得所需最终结果的快速版本: https://github.com/Clodo76/vr-desktop-mirror/blob/master/DesktopCapture/main.cpp

DesktopCapturePlugin_Initialize方法将所有显示转换为对象:

UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API DesktopCapturePlugin_Initialize()
{   
    DesksClean();

    g_needReinit = 0;


    IDXGIFactory1* factory;
    CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&factory));

    IDXGIAdapter1* adapter;
    for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
    {
        IDXGIOutput* output;
        for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); j++)
        {
            DXGI_OUTPUT_DESC outputDesc;
            output->GetDesc(&outputDesc);

            MONITORINFOEX monitorInfo;
            monitorInfo.cbSize = sizeof(MONITORINFOEX);
            GetMonitorInfo(outputDesc.Monitor, &monitorInfo);

            // Maybe in future add a function to identify the primary monitor.
            //if (monitorInfo.dwFlags == MONITORINFOF_PRIMARY)
            {
                int iDesk = DeskAdd();

                g_desks[iDesk].g_width = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;                  
                g_desks[iDesk].g_height = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;

                auto device = g_unity->Get<IUnityGraphicsD3D11>()->GetDevice();
                IDXGIOutput1* output1;
                output1 = reinterpret_cast<IDXGIOutput1*>(output);
                output1->DuplicateOutput(device, &g_desks[iDesk].g_deskDupl);
            }

            output->Release();
        }
        adapter->Release();
    }

    factory->Release();
}

然后,OnRenderEvent方法将显示画面中的帧复制到纹理中(在这种情况下,由单位提供):

void UNITY_INTERFACE_API OnRenderEvent(int eventId)
{
    for (int iDesk = 0; iDesk < g_nDesks; iDesk++)
    {
        if (g_desks[iDesk].g_deskDupl == nullptr || g_desks[iDesk].g_texture == nullptr)
        {
            g_needReinit++;
            return;
        }

        IDXGIResource* resource = nullptr;

        const UINT timeout = 0; // ms
        HRESULT resultAcquire = g_desks[iDesk].g_deskDupl->AcquireNextFrame(timeout, &g_desks[iDesk].g_frameInfo, &resource);
        if (resultAcquire != S_OK)
        {
            g_needReinit++;
            return;
        }

        g_desks[iDesk].g_isPointerVisible = (g_desks[iDesk].g_frameInfo.PointerPosition.Visible == TRUE);
        g_desks[iDesk].g_pointerX = g_desks[iDesk].g_frameInfo.PointerPosition.Position.x;
        g_desks[iDesk].g_pointerY = g_desks[iDesk].g_frameInfo.PointerPosition.Position.y;

        ID3D11Texture2D* texture;
        HRESULT resultQuery = resource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&texture));
        resource->Release();

        if (resultQuery != S_OK)
        {
            g_needReinit++;
            return;
        }

        ID3D11DeviceContext* context;
        auto device = g_unity->Get<IUnityGraphicsD3D11>()->GetDevice();
        device->GetImmediateContext(&context);
        context->CopyResource(g_desks[iDesk].g_texture, texture);

        g_desks[iDesk].g_deskDupl->ReleaseFrame();
    }

    g_needReinit = 0;
}