"Fossies" - the Fresh Open Source Software archive 
Member "tvnserver-2.0.4/desktop/WindowsMouseGrabber.cpp" of archive tvnserver-2.0.4-src.zip:
// Copyright (C) 2008, 2009, 2010 GlavSoft LLC.
// All rights reserved.
//
//-------------------------------------------------------------------------
// This file is part of the TightVNC software. Please visit our Web site:
//
// http://www.tightvnc.com/
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//-------------------------------------------------------------------------
//
#include "WindowsMouseGrabber.h"
#include "WindowsScreenGrabber.h"
WindowsMouseGrabber::WindowsMouseGrabber(void)
: m_lastHCursor(0)
{
}
WindowsMouseGrabber::~WindowsMouseGrabber(void)
{
}
bool WindowsMouseGrabber::isCursorShapeChanged()
{
HCURSOR hCursor = getHCursor();
if (hCursor == m_lastHCursor) {
return false;
}
m_lastHCursor = hCursor;
return true;
}
bool WindowsMouseGrabber::grab(PixelFormat *pixelFormat)
{
return grabPixels(pixelFormat);
}
bool WindowsMouseGrabber::grabPixels(PixelFormat *pixelFormat)
{
HCURSOR hCursor = getHCursor();
if (hCursor == 0) {
return false;
}
m_lastHCursor = hCursor;
ICONINFO iconInfo;
if (!GetIconInfo(hCursor, &iconInfo)) {
return false;
}
if (iconInfo.hbmMask == NULL) {
return false;
}
bool isColorShape = (iconInfo.hbmColor != NULL);
BITMAP bmMask;
if (!GetObject(iconInfo.hbmMask, sizeof(BITMAP), (LPVOID)&bmMask)) {
DeleteObject(iconInfo.hbmMask);
return false;
}
if (bmMask.bmPlanes != 1 || bmMask.bmBitsPixel != 1) {
DeleteObject(iconInfo.hbmMask);
return false;
}
m_cursorShape.setHotSpot(iconInfo.xHotspot, iconInfo.yHotspot);
int width = bmMask.bmWidth;
int height = isColorShape ? bmMask.bmHeight : bmMask.bmHeight/2;
int widthBytes = bmMask.bmWidthBytes;
const FrameBuffer *pixels= m_cursorShape.getPixels();
m_cursorShape.setProperties(&Dimension(width, height), pixelFormat);
std::vector<char> maskBuff(widthBytes * bmMask.bmHeight);
char *mask = &maskBuff.front();
bool result = GetBitmapBits(iconInfo.hbmMask,
widthBytes * bmMask.bmHeight,
mask) != 0;
DeleteObject(iconInfo.hbmMask);
if (!result) {
return false;
}
HDC screenDC = GetDC(0);
if (screenDC == NULL) {
return false;
}
WindowsScreenGrabber::BMI bmi;
if (!WindowsScreenGrabber::getBMI(&bmi, screenDC)) {
return false;
}
bmi.bmiHeader.biBitCount = pixelFormat->bitsPerPixel;
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biHeight = -height;
bmi.bmiHeader.biCompression = BI_BITFIELDS;
bmi.red = pixelFormat->redMax << pixelFormat->redShift;
bmi.green = pixelFormat->greenMax << pixelFormat->greenShift;
bmi.blue = pixelFormat->blueMax << pixelFormat->blueShift;
HDC destDC = CreateCompatibleDC(NULL);
if (destDC == NULL) {
DeleteDC(screenDC);
return false;
}
void *buffer;
HBITMAP hbmDIB = CreateDIBSection(destDC, (BITMAPINFO *) &bmi, DIB_RGB_COLORS, &buffer, NULL, NULL);
if (hbmDIB == 0) {
DeleteDC(destDC);
DeleteDC(screenDC);
return false;
}
HBITMAP hbmOld = (HBITMAP)SelectObject(destDC, hbmDIB);
result = DrawIconEx(destDC, 0, 0, hCursor, 0, 0, 0, NULL, DI_IMAGE) != 0;
memcpy(pixels->getBuffer(), buffer, pixels->getBufferSize());
if (!isColorShape) {
winMonoShapeToRfb(pixels, mask, mask + widthBytes * height);
} else {
if (pixels->getBitsPerPixel() == 32) {
if (winColorShapeToRfb<UINT32>(pixels, mask)) {
fixAlphaChannel(pixels, mask);
}
} else if (pixels->getBitsPerPixel() == 16) {
winColorShapeToRfb<UINT16>(pixels, mask);
}
}
m_cursorShape.assignMaskFromWindows(mask);
SelectObject(destDC, hbmOld);
DeleteObject(hbmDIB);
DeleteDC(destDC);
DeleteDC(screenDC);
return result;
}
HCURSOR WindowsMouseGrabber::getHCursor()
{
CURSORINFO cursorInfo;
cursorInfo.cbSize = sizeof(CURSORINFO);
if (GetCursorInfo(&cursorInfo) == 0) {
return false;
}
return cursorInfo.hCursor;
}
void WindowsMouseGrabber::inverse(char *bits, int count)
{
for (int i = 0; i < count; i++, bits++) {
*bits = ~*bits;
}
}
void WindowsMouseGrabber::winMonoShapeToRfb(const FrameBuffer *pixels,
char *maskAND, char *maskXOR)
{
char *pixelsBuffer = (char *)pixels->getBuffer();
char *pixel;
int pixelSize = pixels->getBytesPerPixel();
int pixelCount = pixels->getBufferSize() / pixelSize;
int fbWidth = pixels->getDimension().width;
int fbHeight = pixels->getDimension().height;
int widthInBytes = ((fbWidth + 15) / 16) * 2;
for (int iRow = 0; iRow < fbHeight; iRow++) {
for (int iCol = 0; iCol < fbWidth; iCol++) {
pixel = pixelsBuffer + (iRow * fbWidth + iCol) * pixelSize;
char byteAnd = maskAND[iRow * widthInBytes + iCol / 8];
char byteXor = maskXOR[iRow * widthInBytes + iCol / 8];
bool maskANDBit = testBit(byteAnd, iCol % 8);
bool maskXORBit = testBit(byteXor, iCol % 8);
if (!maskANDBit && !maskXORBit) {
memset(pixel, 0, pixelSize);
} else if (!maskANDBit && maskXORBit) {
memset(pixel, 0xff, pixelSize);
} else if (maskANDBit && maskXORBit) {
memset(pixel, 0, pixelSize);
}
}
}
inverse(maskAND, widthInBytes * fbHeight);
for (int i = 0; i < widthInBytes * fbHeight; i++) {
*(maskAND + i) |= *(maskXOR + i);
}
}
template< typename T >
bool WindowsMouseGrabber::winColorShapeToRfb(const FrameBuffer *pixels,
char *maskAND)
{
char *pixelsBuffer = (char *)pixels->getBuffer();
PixelFormat pf = pixels->getPixelFormat();
T *pixel;
int fbWidth = pixels->getDimension().width;
int fbHeight = pixels->getDimension().height;
int widthInBytes = ((fbWidth + 15) / 16) * 2;
bool hasAlphaChannel = false;
UINT32 alphaMask = getAlphaMask(&pf);
for (int iRow = 0; iRow < fbHeight; iRow++) {
for (int iCol = 0; iCol < fbWidth; iCol++) {
pixel = (T *)pixelsBuffer + iRow * fbWidth + iCol;
size_t iMaskAnd = iRow * widthInBytes + iCol / 8;
char byteAnd = maskAND[iMaskAnd];
bool maskANDBit = testBit(byteAnd, iCol % 8);
if (!maskANDBit) {
maskAND[iMaskAnd] = maskAND[iMaskAnd] | 128 >> (iCol % 8);
} else if ((*pixel >> pf.redShift & pf.redMax) == 0 &&
(*pixel >> pf.greenShift & pf.greenMax) == 0 &&
(*pixel >> pf.blueShift & pf.blueMax) == 0) {
maskAND[iMaskAnd] = maskAND[iMaskAnd] & ~(128 >> (iCol % 8));
} else {
maskAND[iMaskAnd] = maskAND[iMaskAnd] | 128 >> (iCol % 8);
*pixel &= ~((T)pf.redMax << pf.redShift);
*pixel &= ~((T)pf.greenMax << pf.greenShift);
*pixel &= ~((T)pf.blueMax << pf.blueShift);
}
hasAlphaChannel = hasAlphaChannel || (*pixel & alphaMask) != 0;
}
}
return hasAlphaChannel;
}
bool WindowsMouseGrabber::testBit(char byte, int index)
{
char dummy = 128 >> index;
return (dummy & byte) != 0;
}
void WindowsMouseGrabber::fixAlphaChannel(const FrameBuffer *pixels,
char *maskAND)
{
PixelFormat pf = pixels->getPixelFormat();
if (pf.bitsPerPixel != 32) {
return;
}
UINT32 alphaMax = getAlphaMask(&pf);
UINT16 alphaShift = 0;
for (alphaShift = 0; alphaShift < 32 && (alphaMax % 2) == 0 ; alphaShift++) {
alphaMax = alphaMax >> 1;
}
if (alphaShift > 24) {
return;
}
UINT32 *pixelBuffer = (UINT32 *)pixels->getBuffer();
int pixelSize = pixels->getBytesPerPixel();
int fbWidth = pixels->getDimension().width;
int fbHeight = pixels->getDimension().height;
int widthInBytes = ((fbWidth + 15) / 16) * 2;
for (int iRow = 0; iRow < fbHeight; iRow++) {
for (int iCol = 0; iCol < fbWidth; iCol++) {
UINT32 *pixel = &pixelBuffer[iRow * fbWidth + iCol];
bool transparent = ((*pixel >> alphaShift) & alphaMax) < 128;
if (transparent) {
char *byteAnd = &maskAND[iRow * widthInBytes + iCol / 8];
unsigned char curBit = 128 >> iCol % 8;
curBit = ~curBit;
*byteAnd = *byteAnd & curBit;
}
}
}
}
UINT32 WindowsMouseGrabber::getAlphaMask(const PixelFormat *pf)
{
if (pf->bitsPerPixel == 32) {
UINT32 alphaMax = pf->redMax << pf->redShift |
pf->greenMax << pf->greenShift |
pf->blueMax << pf->blueShift;
return ~alphaMax;
} else {
return 0;
}
}