I have made continuous attempts and discovered some patterns in color conversion. The official documentation of QCursor mentions Qt::color0 and Qt::color1, which indeed follow certain rules. However, I found that the results I obtained are the opposite of the bit values.
As mentioned in my comments, I am currently inverting the bit values of the Windows original AND mask and XOR mask to match Qt::color0 and Qt::color1 as mentioned in the QCursor documentation.
/**
* type: MONOCHAROME has (AND bitmap) and (XOR bitmap).
* 1 bit = 1 pixed
*
* Windows:
* AND bitmap XOR bitmap Display
* 0 0 Black
* 0 1 White
* 1 0 Screen
* 1 1 Reverse screen
*
* QCursor:
* The cursor bitmap (B) and mask (M) bits are combined like this:
* B=1 and M=1 gives black.
* B=0 and M=1 gives white.
* B=0 and M=0 gives transparent.
* B=1 and M=0 gives an XOR'd result under Windows, undefined results on all other platforms.
* Use the global Qt color Qt::color0 to draw 0-pixels and Qt::color1 to draw 1-pixels in the bitmaps.
*
* Actual results:
* 0 0 Black
* 1 0 White
* 1 1 transparent screen
* 0 1 Reverse screen
*/
int size = pCursorData->width * pCursorData->height / 2 / 8;
if(pCursorData->dataLen / 2 != size)
{
qWarning() << "[CMouseModule::SetServerCursor] set Cursor Data dataLen failed.";
return;
}
QImage image(pCursorData->width, pCursorData->height / 2, QImage::Format_Mono);
QImage maskImage(pCursorData->width, pCursorData->height / 2, QImage::Format_Mono);
if(image.sizeInBytes() != size)
{
qWarning() << "[CMouseModule::SetServerCursor] bitmap size not eq Cursor Data image size.";
return;
}
uchar* imageBits = image.bits();
uchar* maskImageBits = maskImage.bits();
int pitch = pCursorData->dataLen / pCursorData->height;
bool andPixel;
bool xorPixel;
// // `height` is 2 bitmap;
for(int y=0; y < pCursorData->height / 2; y++)
{
for(int x=0; x < pCursorData->width; x++)
{
quint8 bitMask = 0x80 >> (x % 8);
quint8 uint8_x = x / 8; // width is bit size
andPixel = pCursorData->pixelData[y * pitch + uint8_x] & bitMask;
xorPixel = pCursorData->pixelData[(y + pCursorData->height / 2) * pitch + uint8_x] & bitMask;
if(!andPixel && !xorPixel)
{
imageBits[y * pitch + uint8_x] &= ~bitMask; // 0
maskImageBits[y * pitch + uint8_x] &= ~bitMask; // 0
} else if(!andPixel && xorPixel)
{
imageBits[y * pitch + uint8_x] |= bitMask; // 1
maskImageBits[y * pitch + uint8_x] &= ~bitMask; // 0
} else if(andPixel && !xorPixel)
{
imageBits[y * pitch + uint8_x] |= bitMask; // 1
maskImageBits[y * pitch + uint8_x] |= bitMask; // 1
} else if(andPixel && xorPixel)
{
imageBits[y * pitch + uint8_x] &= ~bitMask; // 0
maskImageBits[y * pitch + uint8_x] |= bitMask; // 1
}
}
}
QBitmap bitmap;
QBitmap maskBitmap;
bitmap = QBitmap::fromImage(image);
maskBitmap = QBitmap::fromImage(maskImage);
QCursor cursor(bitmap, maskBitmap, pCursorData->xHotspot, pCursorData->yHotspot);
renderWidget->setCursor(cursor);