/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright 2012-2019 Pierre Ossman for Cendio AB * * This 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 software 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 software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ // -=- Clipboard.cxx #include #include #include #include using namespace rfb; using namespace rfb::win32; static LogWriter vlog("Clipboard"); // // -=- CR/LF handlers // char* unix2dos(const char* text) { int len = strlen(text)+1; char* dos = new char[strlen(text)*2+1]; int i, j=0; for (i=0; i= 1) && (text[i] <= 127)) || ((text[i] >= 160) && (text[i] <= 255))) text[j++] = text[i]; } text[j] = 0; } // // -=- Clipboard object // Clipboard::Clipboard() : MsgWindow(_T("Clipboard")), notifier(0), next_window(0) { next_window = SetClipboardViewer(getHandle()); vlog.debug("registered clipboard handler"); } Clipboard::~Clipboard() { vlog.debug("removing %p from chain (next is %p)", getHandle(), next_window); ChangeClipboardChain(getHandle(), next_window); } LRESULT Clipboard::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CHANGECBCHAIN: vlog.debug("change clipboard chain (%I64x, %I64x)", (long long)wParam, (long long)lParam); if ((HWND) wParam == next_window) next_window = (HWND) lParam; else if (next_window != 0) SendMessage(next_window, msg, wParam, lParam); else vlog.error("bad clipboard chain change!"); break; case WM_DRAWCLIPBOARD: { HWND owner = GetClipboardOwner(); if (owner == getHandle()) { vlog.debug("local clipboard changed by me"); } else { vlog.debug("local clipboard changed by %p", owner); // Open the clipboard if (OpenClipboard(getHandle())) { // Get the clipboard data HGLOBAL cliphandle = GetClipboardData(CF_TEXT); if (cliphandle) { char* clipdata = (char*) GlobalLock(cliphandle); // Notify clients if (notifier) { if (!clipdata) { notifier->notifyClipboardChanged(0); } else { CharArray unix_text(convertLF(clipdata, strlen(clipdata))); removeNonISOLatin1Chars(unix_text.buf); notifier->notifyClipboardChanged(unix_text.buf); } } else { vlog.debug("no clipboard notifier registered"); } // Release the buffer and close the clipboard GlobalUnlock(cliphandle); } CloseClipboard(); } } } if (next_window) SendMessage(next_window, msg, wParam, lParam); return 0; }; return MsgWindow::processMessage(msg, wParam, lParam); }; void Clipboard::setClipText(const char* text) { HANDLE clip_handle = 0; try { // - Firstly, we must open the clipboard if (!OpenClipboard(getHandle())) throw rdr::SystemException("unable to open Win32 clipboard", GetLastError()); // - Pre-process the supplied clipboard text into DOS format CharArray dos_text; dos_text.buf = unix2dos(text); removeNonISOLatin1Chars(dos_text.buf); int dos_text_len = strlen(dos_text.buf); // - Allocate global memory for the data clip_handle = ::GlobalAlloc(GMEM_MOVEABLE, dos_text_len+1); char* data = (char*) GlobalLock(clip_handle); memcpy(data, dos_text.buf, dos_text_len+1); data[dos_text_len] = 0; GlobalUnlock(clip_handle); // - Next, we must clear out any existing data if (!EmptyClipboard()) throw rdr::SystemException("unable to empty Win32 clipboard", GetLastError()); // - Set the new clipboard data if (!SetClipboardData(CF_TEXT, clip_handle)) throw rdr::SystemException("unable to set Win32 clipboard", GetLastError()); clip_handle = 0; vlog.debug("set clipboard"); } catch (rdr::Exception& e) { vlog.debug("%s", e.str()); } // - Close the clipboard if (!CloseClipboard()) vlog.debug("unable to close Win32 clipboard: %lu", GetLastError()); else vlog.debug("closed clipboard"); if (clip_handle) { vlog.debug("freeing clipboard handle"); GlobalFree(clip_handle); } }