📄 clientconnection.cpp
字号:
case ID_CLOSEDAEMON: if (MessageBox(NULL, _T("Are you sure you want to exit?"), _T("Closing VNCviewer"), MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2) == IDYES) PostQuitMessage(0); return 0; } break; } case WM_DRAWCLIPBOARD: _this->ProcessLocalClipboardChange(); return 0; case WM_CHANGECBCHAIN: { // The clipboard chain is changing HWND hWndRemove = (HWND) wParam; // handle of window being removed HWND hWndNext = (HWND) lParam; // handle of next window in chain // If next window is closing, update our pointer. if (hWndRemove == _this->m_hwndNextViewer) _this->m_hwndNextViewer = hWndNext; // Otherwise, pass the message to the next link. else if (_this->m_hwndNextViewer != NULL) ::SendMessage(_this->m_hwndNextViewer, WM_CHANGECBCHAIN, (WPARAM) hWndRemove, (LPARAM) hWndNext ); return 0; }
#endif
//Added by: Lars Werner (http://lars.werner.no) - These is the custom messages from the TitleBar
case tbWM_CLOSE:
SendMessage(_this->m_hwnd, WM_CLOSE,NULL,NULL);
return 0;
case tbWM_MINIMIZE:
_this->SetDormant(true);
ShowWindow(_this->m_hwnd, SW_MINIMIZE);
return 0;
case tbWM_MAXIMIZE:
_this->SetFullScreenMode(!_this->InFullScreenMode());
return 0;
} } catch (Exception &e) { // Eeek. Something went wrong, so let's clean up and pretend it never happened. _this->KillThread(); DestroyWindow(hwnd); return 0; }; return DefWindowProc(hwnd, iMsg, wParam, lParam); // We know about an unused variable here.#pragma warning(disable : 4101)}#pragma warning(default : 4101)// ProcessPointerEvent handles the delicate case of emulating 3 buttons// on a two button mouse, then passes events off to SubProcessPointerEvent.voidClientConnection::ProcessPointerEvent(int x, int y, DWORD keyflags, UINT msg) { if (m_opts.m_Emul3Buttons) { // XXX To be done: // If this is a left or right press, the user may be // about to press the other button to emulate a middle press. // We need to start a timer, and if it expires without any // further presses, then we send the button press. // If a press of the other button, or any release, comes in // before timer has expired, we cancel timer & take different action. if (m_waitingOnEmulateTimer) { if (msg == WM_LBUTTONUP || msg == WM_RBUTTONUP || abs(x - m_emulateButtonPressedX) > m_opts.m_Emul3Fuzz || abs(y - m_emulateButtonPressedY) > m_opts.m_Emul3Fuzz) { // if button released or we moved too far then cancel. // First let the remote know where the button was down SubProcessPointerEvent( m_emulateButtonPressedX, m_emulateButtonPressedY, m_emulateKeyFlags); // Then tell it where we are now SubProcessPointerEvent(x, y, keyflags); } else if ( (msg == WM_LBUTTONDOWN && (m_emulateKeyFlags & MK_RBUTTON)) || (msg == WM_RBUTTONDOWN && (m_emulateKeyFlags & MK_LBUTTON))) { // Triggered an emulate; remove left and right buttons, put // in middle one. DWORD emulatekeys = keyflags & ~(MK_LBUTTON|MK_RBUTTON); emulatekeys |= MK_MBUTTON; SubProcessPointerEvent(x, y, emulatekeys); m_emulatingMiddleButton = true; } else { // handle movement normally & don't kill timer. // just remove the pressed button from the mask. DWORD keymask = m_emulateKeyFlags & (MK_LBUTTON|MK_RBUTTON); DWORD emulatekeys = keyflags & ~keymask; SubProcessPointerEvent(x, y, emulatekeys); return; } // if we reached here, we don't need the timer anymore. KillTimer(m_hwnd, m_emulate3ButtonsTimer); m_waitingOnEmulateTimer = false; } else if (m_emulatingMiddleButton) { if ((keyflags & MK_LBUTTON) == 0 && (keyflags & MK_RBUTTON) == 0) { // We finish emulation only when both buttons come back up. m_emulatingMiddleButton = false; SubProcessPointerEvent(x, y, keyflags); } else { // keep emulating. DWORD emulatekeys = keyflags & ~(MK_LBUTTON|MK_RBUTTON); emulatekeys |= MK_MBUTTON; SubProcessPointerEvent(x, y, emulatekeys); } } else { // Start considering emulation if we've pressed a button // and the other isn't pressed. if ( (msg == WM_LBUTTONDOWN && !(keyflags & MK_RBUTTON)) || (msg == WM_RBUTTONDOWN && !(keyflags & MK_LBUTTON))) { // Start timer for emulation. m_emulate3ButtonsTimer = SetTimer( m_hwnd, IDT_EMULATE3BUTTONSTIMER, m_opts.m_Emul3Timeout, NULL); if (!m_emulate3ButtonsTimer) { log.Print(0, _T("Failed to create timer for emulating 3 buttons")); PostMessage(m_hwnd, WM_CLOSE, 0, 0); return; } m_waitingOnEmulateTimer = true; // Note that we don't send the event here; we're batching it for // later. m_emulateKeyFlags = keyflags; m_emulateButtonPressedX = x; m_emulateButtonPressedY = y; } else { // just send event noramlly SubProcessPointerEvent(x, y, keyflags); } } } else { SubProcessPointerEvent(x, y, keyflags); }}// SubProcessPointerEvent takes windows positions and flags and converts // them into VNC ones.inline void ClientConnection::SubProcessPointerEvent(int x, int y, DWORD keyflags){ int mask; if (m_opts.m_SwapMouse) { mask = ( ((keyflags & MK_LBUTTON) ? rfbButton1Mask : 0) | ((keyflags & MK_MBUTTON) ? rfbButton3Mask : 0) | ((keyflags & MK_RBUTTON) ? rfbButton2Mask : 0) ); } else { mask = ( ((keyflags & MK_LBUTTON) ? rfbButton1Mask : 0) | ((keyflags & MK_MBUTTON) ? rfbButton2Mask : 0) | ((keyflags & MK_RBUTTON) ? rfbButton3Mask : 0) ); } try { SendPointerEvent((x + m_hScrollPos) * m_opts.m_scale_den / m_opts.m_scale_num, (y + m_vScrollPos) * m_opts.m_scale_den / m_opts.m_scale_num, mask); } catch (Exception &e) { e.Report(); PostMessage(m_hwnd, WM_CLOSE, 0, 0); }}void ClientConnection::ProcessMouseWheel(int delta){ int wheelMask = rfbWheelUpMask; if (delta < 0) { wheelMask = rfbWheelDownMask; delta = -delta; } while (delta > 0) { SendPointerEvent(oldPointerX, oldPointerY, oldButtonMask | wheelMask); SendPointerEvent(oldPointerX, oldPointerY, oldButtonMask & ~wheelMask); delta -= 120; }}//// SendPointerEvent.//inline voidClientConnection::SendPointerEvent(int x, int y, int buttonMask){ rfbPointerEventMsg pe; oldPointerX = x; oldPointerY = y; oldButtonMask = buttonMask; pe.type = rfbPointerEvent; pe.buttonMask = buttonMask; if (x < 0) x = 0; if (y < 0) y = 0; pe.x = Swap16IfLE(x); pe.y = Swap16IfLE(y); WriteExact((char *)&pe, sz_rfbPointerEventMsg);}//// ProcessKeyEvent//// Normally a single Windows key event will map onto a single RFB// key message, but this is not always the case. Much of the stuff// here is to handle AltGr (=Ctrl-Alt) on international keyboards.// Example cases://// We want Ctrl-F to be sent as:// Ctrl-Down, F-Down, F-Up, Ctrl-Up.// because there is no keysym for ctrl-f, and because the ctrl// will already have been sent by the time we get the F.//// On German keyboards, @ is produced using AltGr-Q, which is// Ctrl-Alt-Q. But @ is a valid keysym in its own right, and when// a German user types this combination, he doesn't mean Ctrl-@.// So for this we will send, in total://// Ctrl-Down, Alt-Down, // (when we get the AltGr pressed)//// Alt-Up, Ctrl-Up, @-Down, Ctrl-Down, Alt-Down // (when we discover that this is @ being pressed)//// Alt-Up, Ctrl-Up, @-Up, Ctrl-Down, Alt-Down// (when we discover that this is @ being released)//// Alt-Up, Ctrl-Up// (when the AltGr is released)inline void ClientConnection::ProcessKeyEvent(int virtkey, DWORD keyData){ bool down = ((keyData & 0x80000000l) == 0); // if virtkey found in mapping table, send X equivalent // else // try to convert directly to ascii // if result is in range supported by X keysyms, // raise any modifiers, send it, then restore mods // else // calculate what the ascii would be without mods // send that#ifdef _DEBUG#ifdef UNDER_CE char *keyname="";#else char keyname[32]; if (GetKeyNameText( keyData,keyname, 31)) { log.Print(4, _T("Process key: %s (keyData %04x): "), keyname, keyData); };#endif#endif try { KeyActionSpec kas = m_keymap.PCtoX(virtkey, keyData); if (kas.releaseModifiers & KEYMAP_LCONTROL) { SendKeyEvent(XK_Control_L, false ); log.Print(5, _T("fake L Ctrl raised\n")); } if (kas.releaseModifiers & KEYMAP_LALT) { SendKeyEvent(XK_Alt_L, false ); log.Print(5, _T("fake L Alt raised\n")); } if (kas.releaseModifiers & KEYMAP_RCONTROL) { SendKeyEvent(XK_Control_R, false ); log.Print(5, _T("fake R Ctrl raised\n")); } if (kas.releaseModifiers & KEYMAP_RALT) { SendKeyEvent(XK_Alt_R, false ); log.Print(5, _T("fake R Alt raised\n")); } for (int i = 0; kas.keycodes[i] != XK_VoidSymbol && i < MaxKeysPerKey; i++) { SendKeyEvent(kas.keycodes[i], down ); log.Print(4, _T("Sent keysym %04x (%s)\n"), kas.keycodes[i], down ? _T("press") : _T("release")); } if (kas.releaseModifiers & KEYMAP_RALT) { SendKeyEvent(XK_Alt_R, true ); log.Print(5, _T("fake R Alt pressed\n")); } if (kas.releaseModifiers & KEYMAP_RCONTROL) { SendKeyEvent(XK_Control_R, true ); log.Print(5, _T("fake R Ctrl pressed\n")); } if (kas.releaseModifiers & KEYMAP_LALT) { SendKeyEvent(XK_Alt_L, false ); log.Print(5, _T("fake L Alt pressed\n")); } if (kas.releaseModifiers & KEYMAP_LCONTROL) { SendKeyEvent(XK_Control_L, false ); log.Print(5, _T("fake L Ctrl pressed\n")); } } catch (Exception &e) { e.Report(); PostMessage(m_hwnd, WM_CLOSE, 0, 0); }}//// SendKeyEvent//inline voidClientConnection::SendKeyEvent(CARD32 key, bool down){ rfbKeyEventMsg ke; ke.type = rfbKeyEvent; ke.down = down ? 1 : 0; ke.key = Swap32IfLE(key); WriteExact((char *)&ke, sz_rfbKeyEventMsg); log.Print(6, _T("SendKeyEvent: key = x%04x status = %s\n"), key, down ? _T("down") : _T("up"));}#ifndef UNDER_CE//// SendClientCutText//void ClientConnection::SendClientCutText(char *str, int len){ rfbClientCutTextMsg cct; cct.type = rfbClientCutText; cct.length = Swap32IfLE(len); WriteExact((char *)&cct, sz_rfbClientCutTextMsg); WriteExact(str, len); log.Print(6, _T("Sent %d bytes of clipboard\n"), len);}#endif// Copy any updated areas from the bitmap onto the screen.inline void ClientConnection::DoBlit() { if (m_hBitmap == NULL) return; if (!m_running) return; // No other threads can use bitmap DC omni_mutex_lock l(m_bitmapdcMutex); PAINTSTRUCT ps; HDC hdc = BeginPaint(m_hwnd, &ps); // Select and realize hPalette PaletteSelector p(hdc, m_hPalette); ObjectSelector b(m_hBitmapDC, m_hBitmap); if (m_opts.m_delay) { // Display the area to be updated for debugging purposes COLORREF oldbgcol = SetBkColor(hdc, RGB(0,0,0)); ::ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &ps.rcPaint, NULL, 0, NULL); SetBkColor(hdc,oldbgcol); ::Sleep(m_pApp->m_options.m_delay); } if (m_opts.m_scaling) { int n = m_opts.m_scale_num; int d = m_opts.m_scale_den; // We're about to do some scaling on these values in the StretchBlt // We want to make sure that they divide nicely by n so we round them // down and up appropriately. ps.rcPaint.left = ((ps.rcPaint.left + m_hScrollPos) / n * n) - m_hScrollPos; ps.rcPaint.right = ((ps.rcPaint.right + m_hScrollPos + n - 1) / n * n) - m_hScrollPos; ps.rcPaint.top = ((ps.rcPaint.top + m_vScrollPos) / n * n) - m_vScrollPos; ps.rcPaint.bottom = ((ps.rcPaint.bottom + m_vScrollPos + n - 1) / n * n) - m_vScrollPos; // This is supposed to give better results. I think my driver ignores it? SetStretchBltMode(hdc, HALFTONE); // The docs say that you should call SetBrushOrgEx after SetStretchBltMode, // but not what the arguments should be. SetBrushOrgEx(hdc, 0,0, NULL); if (!StretchBlt( hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right-ps.rcPaint.left, ps.rcPaint.bottom-ps.rcPaint.top, m_hBitmapDC, (ps.rcPaint.left+m_hScrollPos) * d / n, (ps.rcPaint.top+m_vScrollPos) * d / n, (ps.rcPaint.right-ps.rcPaint.left) * d / n, (ps.rcPaint.bottom-ps.rcPaint.top) * d / n, SRCCOPY)) { log.Print(0, _T("Blit error %d\n"), GetLastError()); // throw ErrorException("Error in blit!\n"); }; } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -