📄 vncdesktop.cpp
字号:
// Save the bounding rectangle
m_cursorpos.left = CursorPos.x;
m_cursorpos.top = CursorPos.y;
m_cursorpos.right = CursorPos.x + GetSystemMetrics(SM_CXCURSOR);
m_cursorpos.bottom = CursorPos.y + GetSystemMetrics(SM_CYCURSOR);
}
// Add the mouse pointer to the buffer
void vncDesktop::CaptureMouse(BYTE *scrBuff, UINT scrBuffSize)
{
// Protect the memory bitmap
omni_mutex_lock l(m_bitbltlock);
CaptureMouseRect();
// Select the memory bitmap into the memory DC
HBITMAP oldbitmap;
if ((oldbitmap = (HBITMAP) SelectObject(m_hmemdc, m_membitmap)) == NULL)
return;
// Draw the cursor
DrawIconEx(
m_hmemdc, // handle to device context
m_cursorpos.left - m_bmrect.left,
m_cursorpos.top - m_bmrect.top,
m_hcursor, // handle to icon to draw
0,0, // width of the icon
0, // index of frame in animated cursor
NULL, // handle to background brush
DI_NORMAL // icon-drawing flags
);
// Select the old bitmap back into the memory DC
SelectObject(m_hmemdc, oldbitmap);
// Clip the bounding rect to the screen
RECT screen = m_server->GetSharedRect();
// Copy the mouse cursor into the screen buffer, if any of it is visible
if (IntersectRect(&m_cursorpos, &m_cursorpos, &screen))
CopyToBuffer(m_cursorpos, scrBuff);
}
// Obtain cursor image data in server's local format.
// The length of databuf[] should be at least (width * height * 4).
BOOL
vncDesktop::GetRichCursorData(BYTE *databuf, HCURSOR hcursor, int width, int height)
{
// Protect the memory bitmap (is it really necessary here?)
omni_mutex_lock l(m_bitbltlock);
// Create bitmap, select it into memory DC
HBITMAP membitmap = CreateCompatibleBitmap(m_hrootdc, width, height);
if (membitmap == NULL) {
return FALSE;
}
HBITMAP oldbitmap = (HBITMAP) SelectObject(m_hmemdc, membitmap);
if (oldbitmap == NULL) {
DeleteObject(membitmap);
return FALSE;
}
// Draw the cursor
DrawIconEx(m_hmemdc, 0, 0, hcursor, 0, 0, 0, NULL, DI_IMAGE);
SelectObject(m_hmemdc, oldbitmap);
// Prepare BITMAPINFO structure (copy most m_bminfo fields)
BITMAPINFO *bmi = (BITMAPINFO *)calloc(1, sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD));
memcpy(bmi, &m_bminfo.bmi, sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD));
bmi->bmiHeader.biWidth = width;
bmi->bmiHeader.biHeight = -height;
// Clear data buffer and extract RGB data
memset(databuf, 0x00, width * height * 4);
int lines = GetDIBits(m_hmemdc, membitmap, 0, height, databuf, bmi, DIB_RGB_COLORS);
// Cleanup
free(bmi);
DeleteObject(membitmap);
return (lines != 0);
}
// Return the current mouse pointer position
RECT
vncDesktop::MouseRect()
{
return m_cursorpos;
}
void vncDesktop::SetCursor(HCURSOR cursor)
{
if (cursor == NULL)
m_hcursor = m_hdefcursor;
else
m_hcursor = cursor;
}
//
// DEBUG: Some visualization for LF->CRLF conversion code.
//
/*
static void ShowClipText(char *caption, char *text)
{
int len = strlen(text);
char *out_text = new char[len * 4 + 8];
int pos = 0;
out_text[pos++] = '"';
for (int i = 0; i < len; i++) {
if (text[i] == '\r') {
strcpy(&out_text[pos], "\\r");
pos += 2;
} else if (text[i] == '\n') {
strcpy(&out_text[pos], "\\n");
pos += 2;
} else if (text[i] < ' ') {
strcpy(&out_text[pos], "\\?");
pos += 2;
} else {
out_text[pos++] = text[i];
}
}
out_text[pos++] = '"';
out_text[pos++] = '\0';
MessageBox(NULL, out_text, caption, MB_OK);
delete[] out_text;
}
*/
//
// Convert text from Unix (LF only) format to CR+LF.
// NOTE: The size of dst[] buffer must be at least (strlen(src) * 2 + 1).
//
void
vncDesktop::ConvertClipText(char *dst, const char *src)
{
const char *ptr0 = src;
const char *ptr1;
int dst_pos = 0;
while ((ptr1 = strchr(ptr0, '\n')) != NULL) {
// Copy the string before the LF
if (ptr1 != ptr0) {
memcpy(&dst[dst_pos], ptr0, ptr1 - ptr0);
dst_pos += ptr1 - ptr0;
}
// Don't insert CR if there is one already
if (ptr1 == ptr0 || *(ptr1 - 1) != '\r') {
dst[dst_pos++] = '\r';
}
// Append LF
dst[dst_pos++] = '\n';
// Next position in the source text
ptr0 = ptr1 + 1;
}
// Copy the last string with no LF, but with '\0'
memcpy(&dst[dst_pos], ptr0, &src[strlen(src)] - ptr0 + 1);
}
//
// Manipulation of the clipboard
//
void
vncDesktop::SetClipText(LPSTR text)
{
// Open the system clipboard
if (OpenClipboard(m_hwnd))
{
// Empty it
if (EmptyClipboard())
{
HANDLE hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
strlen(text) * 2 + 1);
if (hMem != NULL)
{
LPSTR pMem = (char*)GlobalLock(hMem);
// Get the data (with line endings converted to CR+LF)
ConvertClipText(pMem, text);
// Tell the clipboard
GlobalUnlock(hMem);
SetClipboardData(CF_TEXT, hMem);
}
}
}
// Now close it
CloseClipboard();
}
// INTERNAL METHODS
inline void
vncDesktop::MaskToMaxAndShift(DWORD mask, CARD16 &max, CARD8 &shift)
{
for (shift = 0; (mask & 1) == 0; shift++)
mask >>= 1;
max = (CARD16) mask;
}
// Copy data from the memory bitmap into a buffer
void vncDesktop::CopyToBuffer(RECT rect, BYTE *destbuff)
{
// Are we being asked to blit from the DIBsection to itself?
if (destbuff == m_DIBbits)
{
// Yes. Ignore the request!
return;
}
// Protect the memory bitmap
omni_mutex_lock l(m_bitbltlock);
const int crect_re_vd_left = rect.left - m_bmrect.left;
const int crect_re_vd_top = rect.top - m_bmrect.top;
_ASSERTE(crect_re_vd_left >= 0);
_ASSERTE(crect_re_vd_top >= 0);
// Calculate the scanline-ordered y position to copy from
// NB: m_membitmap is bottom2top
const int y_inv_re_vd = m_bmrect.bottom - m_bmrect.top - rect.bottom;
_ASSERTE(y_inv_re_vd >= 0);
// Calculate where in the output buffer to put the data
BYTE * destbuffpos = destbuff + (m_bytesPerRow * crect_re_vd_top);
// Set the number of bytes for GetDIBits to actually write
// NOTE : GetDIBits pads the destination buffer if biSizeImage < no. of bytes required
m_bminfo.bmi.bmiHeader.biSizeImage = (rect.bottom-rect.top) * m_bytesPerRow;
// Get the actual bits from the bitmap into the bit buffer
// If fast (DIBsection) blits are disabled then use the old GetDIBits technique
if (m_DIBbits == NULL)
{
if (GetDIBits(
m_hmemdc,
m_membitmap,
y_inv_re_vd,
rect.bottom - rect.top,
destbuffpos,
&m_bminfo.bmi,
DIB_RGB_COLORS) == 0)
{
#ifdef _MSC_VER
_RPT1(_CRT_WARN, "vncDesktop : [1] GetDIBits failed! %d\n", GetLastError());
_RPT3(_CRT_WARN, "vncDesktop : thread = %d, DC = %d, bitmap = %d\n", omni_thread::self(), m_hmemdc, m_membitmap);
_RPT2(_CRT_WARN, "vncDesktop : y = %d, height = %d\n", y_inv_re_vd, (rect.bottom-rect.top));
#endif
}
}
else
{
// Fast blits are enabled. [I have a sneaking suspicion this will never get used, unless
// something weird goes wrong in the code. It's here to keep the function general, though!]
const int bytesPerPixel = m_scrinfo.format.bitsPerPixel / 8;
BYTE *srcbuffpos = (BYTE*)m_DIBbits;
srcbuffpos += (m_bytesPerRow * crect_re_vd_top) + (bytesPerPixel * crect_re_vd_left);
destbuffpos += bytesPerPixel * crect_re_vd_left;
const int widthBytes = (rect.right - rect.left) * bytesPerPixel;
for (int y = rect.top; y < rect.bottom; y++)
{
memcpy(destbuffpos, srcbuffpos, widthBytes);
srcbuffpos += m_bytesPerRow;
destbuffpos += m_bytesPerRow;
}
}
}
void vncDesktop::CopyToBuffer(RECT rect, BYTE *destbuff, const BYTE *srcbuffpos)
{
const int crect_re_vd_left = rect.left - m_bmrect.left;
const int crect_re_vd_top = rect.top - m_bmrect.top;
_ASSERTE(crect_re_vd_left >= 0);
_ASSERTE(crect_re_vd_top >= 0);
const int bytesPerPixel = m_scrinfo.format.bitsPerPixel / 8;
const int bmoffset = (m_bytesPerRow * crect_re_vd_top) + (bytesPerPixel * crect_re_vd_left);
BYTE *destbuffpos = destbuff + bmoffset;
srcbuffpos += bmoffset;
const int widthBytes = (rect.right - rect.left) * bytesPerPixel;
for (int y = rect.top; y < rect.bottom; y++)
{
memcpy(destbuffpos, srcbuffpos, widthBytes);
srcbuffpos += m_bytesPerRow;
destbuffpos += m_bytesPerRow;
}
}
// Callback routine used internally to catch window movement...
BOOL CALLBACK
EnumWindowsFnCopyRect(HWND hwnd, LPARAM arg)
{
//For excluding the popup windows
if ((GetWindowLong( hwnd, GWL_STYLE) & WS_POPUP) ==0)
{
HANDLE prop = GetProp(hwnd, (LPCTSTR) MAKELONG(VNC_WINDOWPOS_ATOM, 0));
if (prop != NULL) {
if (IsWindowVisible(hwnd)) {
RECT dest;
POINT source;
// Get the window rectangle
if (GetWindowRect(hwnd, &dest)) {
// Old position
source.x = (SHORT) LOWORD(prop);
source.y = (SHORT) HIWORD(prop);
// Got the destination position. Now send to clients!
if ((source.x != dest.left) || (source.y != dest.top)) {
// Update the property entry
SHORT x = (SHORT) dest.left;
SHORT y = (SHORT) dest.top;
SetProp(hwnd,
(LPCTSTR) MAKELONG(VNC_WINDOWPOS_ATOM, 0),
(HANDLE) MAKELONG(x, y));
// Store of the copyrect
((vncDesktop*)arg)->CopyRect(dest, source);
}
} else {
RemoveProp(hwnd, (LPCTSTR) MAKELONG(VNC_WINDOWPOS_ATOM, 0));
}
} else {
RemoveProp(hwnd, (LPCTSTR) MAKELONG(VNC_WINDOWPOS_ATOM, 0));
}
} else {
// If the window has become visible then save its position!
if (IsWindowVisible(hwnd)) {
RECT dest;
if (GetWindowRect(hwnd, &dest)) {
SHORT x = (SHORT) dest.left;
SHORT y = (SHORT) dest.top;
SetProp(hwnd,
(LPCTSTR) MAKELONG(VNC_WINDOWPOS_ATOM, 0),
(HANDLE) MAKELONG(x, y));
}
}
}
}
return TRUE;
}
void
vncDesktop::SetLocalInputDisableHook(BOOL enable)
{
SetKeyboardFilterHook(enable);
SetMouseFilterHook(enable);
}
void
vncDesktop::SetLocalInputPriorityHook(BOOL enable)
{
if (vncService::IsWin95()) {
SetKeyboardPriorityHook(m_hwnd,enable,RFB_LOCAL_KEYBOARD);
SetMousePriorityHook(m_hwnd,enable,RFB_LOCAL_MOUSE);
} else {
SetKeyboardPriorityLLHook(m_hwnd,enable,RFB_LOCAL_KEYBOARD);
SetMousePriorityLLHook(m_hwnd,enable,RFB_LOCAL_MOUSE);
}
if (!enable)
// FIXME: incremental semantics broken here;
// that's why we're compelled to consume extra unlocks
m_server->BlockRemoteInput(false);
}
// Routine to find out which windows have moved
void
vncDesktop::CalcCopyRects()
{
// Enumerate all the desktop windows for movement
EnumWindows((WNDENUMPROC)EnumWindowsFnCopyRect, (LPARAM) this);
}
// Window procedure for the Desktop window
LRESULT CALLBACK
DesktopWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
vncDesktop *_this = (vncDesktop*)GetWindowLong(hwnd, GWL_USERDATA);
switch (iMsg)
{
// GENERAL
case WM_DISPLAYCHANGE:
// The display resolution is changing
// We must kick off any clients since their screen size will be wrong
_this->m_displaychanged = TRUE;
return 0;
case WM_SYSCOLORCHANGE:
case WM_PALETTECHANGED:
// The palette colours have changed, so tell the server
// Get the system palette
if (!_this->SetPalette())
PostQuitMessage(0);
// Update any palette-based clients, too
_this->m_server->UpdatePalette();
return 0;
case WM_TIMER:
switch (wParam) {
case vncDesktop::TIMER_POLL:
_this->SetPollingFlag(true);
break;
case vncDesktop::TIMER_BLANK_SCREEN:
if (_this->m_server->GetBlankScreen())
_this->BlankScreen(TRUE);
break;
case vncDesktop::TIMER_RESTORE_SCREEN:
_this->BlankScreen(FALSE);
break;
}
return 0;
// CLIPBOARD MESSAGES
case WM_CHANGECBCHAIN:
// The clipboard chain has changed - check our nextviewer handle
if ((HWND)wParam == _this->m_hnextviewer)
_this->m_hnextviewer = (HWND)lParam;
else
if (_this->m_hnextviewer != NULL)
SendMessage(_this->m_hnextviewer,
WM_CHANGECBCHAIN,
wParam, lParam);
return 0;
case WM_DRAWCLIPBOARD:
// The clipboard contents have changed
if((GetClipboardOwner() != _this->Window()) &&
_this->m_initialClipBoardSeen &&
_this->m_clipboard_active)
{
LPSTR cliptext = NULL;
// Open the clipboard
if (OpenClipboard(_this->Window()))
{
// Get the clipboard data
HGLOBAL cliphandle = GetClipboardData(CF_TEXT);
if (cliphandle != NULL)
{
LPSTR clipdata = (LPSTR) GlobalLock(cliphandle);
// Copy it into a new buffer
if (clipdata == NULL)
cliptext = NULL;
else
cliptext = strdup(clipdata);
// Release the buffer and close the clipboard
GlobalUnlock(cliphandle);
}
CloseClipboard();
}
if (cliptext != NULL)
{
int cliplen = strlen(cliptext);
LPSTR unixtext = (char *)malloc(cliplen+1);
// Replace CR-LF with LF - never send CR-LF on the wire,
// since Unix won't like it
int unixpos=0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -