Search code examples
c++winapiqt5qthread

Qt: mouse cursor flickering due to fast screen sampling


Hello i use this code to quickly (about 60 times/second) sample the screen and find its average color:

samplerWorker::samplerWorker(int newId)
{
    this->id = newId;
    this->screenWidth = GetSystemMetrics(SM_CXSCREEN);
    this->screenHeight = GetSystemMetrics(SM_CYSCREEN);
    this->hDesktopWnd = GetDesktopWindow();
    this->hDesktopDC = GetDC(this->hDesktopWnd);
    this->hCaptureDC = CreateCompatibleDC(this->hDesktopDC);
}

void samplerWorker::sampleAvgColor(int workerId)
{
    if(workerId != this->id)
    {
        return;
    }
    HBITMAP hCaptureBitmap = CreateCompatibleBitmap(this->hDesktopDC, this->screenWidth, this->screenHeight);
    SelectObject(hCaptureDC, hCaptureBitmap);

    BitBlt(this->hCaptureDC, 0, 0, this->screenWidth, this->screenHeight, this->hDesktopDC, 0,0, SRCCOPY|CAPTUREBLT);

    BITMAPINFO bmi = {0};
    bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
    bmi.bmiHeader.biWidth = this->screenWidth;
    bmi.bmiHeader.biHeight = this->screenHeight;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biCompression = BI_RGB;
    int size = this->screenWidth * this->screenHeight * 4;
    unsigned char *pPixels = new unsigned char[size];

    GetDIBits(this->hCaptureDC, hCaptureBitmap, 0, this->screenHeight, pPixels, &bmi,    DIB_RGB_COLORS);

    unsigned int avgR = 0;
    unsigned int avgG = 0;
    unsigned int avgB = 0;
    size = size /4;
    for (int i = 0; i < size; i++) {
        avgB = avgB + pPixels[4*i + 0];
        avgG = avgG + pPixels[4*i + 1];
        avgR = avgR + pPixels[4*i + 2];
    }

    avgR = avgR / (size);
    avgG = avgG / (size);
    avgB = avgB / (size);

    emit returnAvgColor(avgR,avgG,avgB);

    delete[] pPixels;

    DeleteObject(hCaptureBitmap);
}

samplerWorker is an object that works in a few separate threads, each samplerWorker is in a separate thread, and they are called one after another, so first screenshot is taken by samplerWorker with id == 0, then id == 1, and so on until all of them are called and then it returns back to sampler worker with id == 0. But for some reason, when i screenshot my screen fast enough (more than 10-15 fps) my cursor starts flickering. What might cause this issue?


Solution

  • Refer: Raymond Chen Discusses the Case of the Disappearing Cursor

    These translucent windows, known as layered windows, are not normally included by the BitBlt function when reading pixels from the screen. In order to get them, you have to pass the CAPTUREBLT flag.

    The mouse cursor is just another composition object and therefore would be captured by the CAPTUREBLT flag. To prevent this from happening during a screen capture, the composition engine has to hide the cursor, do the CAPTUREBLT, and then re-show the cursor.

    Related case: Cursor disappears on bitblt