/* * Retrieve string pasted depending on OS mechanisms. * Copyright (C) 2001-2010 Wormux Team * Copyright (C) 2010-2012 The Mana Developers * * This file is part of The Mana Client. * * 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 * 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, see . */ /* * IMPORTANT! * * This code was taken from Wormux svn trunk at Feb 25 2010. Please don't * make any unnecessary modifications, and try to sync up modifications * when possible. */ #ifdef _MSC_VER # include "msvc/config.h" #elif defined(HAVE_CONFIG_H) # include "config.h" #endif #include #include "copynpaste.h" #ifdef _WIN32 bool RetrieveBuffer(std::string& text, std::string::size_type& pos) { bool ret = false; if (!OpenClipboard(NULL)) return false; HANDLE h = GetClipboardData(CF_UNICODETEXT); if (h) { LPCWSTR data = (LPCWSTR)GlobalLock(h); if (data) { int len = WideCharToMultiByte(CP_UTF8, 0, data, -1, NULL, 0, NULL, NULL); if (len > 0) { // Convert from UTF-16 to UTF-8 void *temp = malloc(len); if (WideCharToMultiByte(CP_UTF8, 0, data, -1, (LPSTR)temp, len, NULL, NULL)) { text.insert(pos, (char*)temp); pos += len-1; } free(temp); ret = true; } } GlobalUnlock(h); } else { h = GetClipboardData(CF_TEXT); if (h) { const char *data = (char*)GlobalLock(h); if (data) { text.insert(pos, data); pos += strlen(data); ret = true; } GlobalUnlock(h); } } CloseClipboard(); return ret; } #elif defined(__APPLE__) #ifdef Status #undef Status #endif #include // Sorry for the very long code, all nicer OS X APIs are coded in Objective C and not C! // Also it does very thorough error handling bool GetDataFromPasteboard( PasteboardRef inPasteboard, char* flavorText /* out */, const int bufSize ) { OSStatus err = noErr; PasteboardSyncFlags syncFlags; ItemCount itemCount; syncFlags = PasteboardSynchronize( inPasteboard ); //require_action( syncFlags & kPasteboardModified, PasteboardOutOfSync, // err = badPasteboardSyncErr ); err = PasteboardGetItemCount( inPasteboard, &itemCount ); require_noerr( err, CantGetPasteboardItemCount ); for (UInt32 itemIndex = 1; itemIndex <= itemCount; itemIndex++) { PasteboardItemID itemID; CFArrayRef flavorTypeArray; CFIndex flavorCount; err = PasteboardGetItemIdentifier( inPasteboard, itemIndex, &itemID ); require_noerr( err, CantGetPasteboardItemIdentifier ); err = PasteboardCopyItemFlavors( inPasteboard, itemID, &flavorTypeArray ); require_noerr( err, CantCopyPasteboardItemFlavors ); flavorCount = CFArrayGetCount( flavorTypeArray ); for (CFIndex flavorIndex = 0; flavorIndex < flavorCount; flavorIndex++) { CFStringRef flavorType; CFDataRef flavorData; CFIndex flavorDataSize; flavorType = (CFStringRef)CFArrayGetValueAtIndex(flavorTypeArray, flavorIndex); // we're only interested by text... if (UTTypeConformsTo(flavorType, CFSTR("public.utf8-plain-text"))) { err = PasteboardCopyItemFlavorData( inPasteboard, itemID, flavorType, &flavorData ); require_noerr( err, CantCopyFlavorData ); flavorDataSize = CFDataGetLength( flavorData ); flavorDataSize = (flavorDataSize<254) ? flavorDataSize : 254; if (flavorDataSize+2 > bufSize) { fprintf(stderr, "Cannot copy clipboard, contents is too big!\n"); return false; } for (short dataIndex = 0; dataIndex <= flavorDataSize; dataIndex++) { char byte = *(CFDataGetBytePtr( flavorData ) + dataIndex); flavorText[dataIndex] = byte; } flavorText[flavorDataSize] = '\0'; flavorText[flavorDataSize+1] = '\n'; CFRelease (flavorData); return true; } continue; CantCopyFlavorData: fprintf(stderr, "Cannot copy clipboard, CantCopyFlavorData!\n"); } CFRelease (flavorTypeArray); continue; CantCopyPasteboardItemFlavors: fprintf(stderr, "Cannot copy clipboard, CantCopyPasteboardItemFlavors!\n"); continue; CantGetPasteboardItemIdentifier: fprintf(stderr, "Cannot copy clipboard, CantGetPasteboardItemIdentifier!\n"); continue; } fprintf(stderr, "Cannot copy clipboard, found no acceptable flavour!\n"); return false; CantGetPasteboardItemCount: fprintf(stderr, "Cannot copy clipboard, CantGetPasteboardItemCount!\n"); return false; //PasteboardOutOfSync: fprintf(stderr, "Cannot copy clipboard, PasteboardOutOfSync!\n"); return false; } bool getClipBoard(char* text /* out */, const int bufSize ) { OSStatus err = noErr; PasteboardRef theClipboard; err = PasteboardCreate( kPasteboardClipboard, &theClipboard ); require_noerr( err, PasteboardCreateFailed ); if (!GetDataFromPasteboard(theClipboard, text, bufSize)) { fprintf(stderr, "Cannot copy clipboard, GetDataFromPasteboardFailed!\n"); return false; } CFRelease(theClipboard); return true; // ---- error handling PasteboardCreateFailed: fprintf(stderr, "Cannot copy clipboard, PasteboardCreateFailed!\n"); CFRelease(theClipboard); return false; } bool RetrieveBuffer(std::string& text, std::string::size_type& pos) { const int bufSize = 512; char buffer[bufSize]; if (getClipBoard(buffer, bufSize)) { text = buffer; pos += strlen(buffer); return true; } else { return false; } } #elif USE_X11 static char* getSelection(Display *dpy, Window us, Atom selection) { int max_events = 50; Window owner = XGetSelectionOwner (dpy, selection); int ret; //printf("XConvertSelection on %s\n", XGetAtomName(dpy, selection)); if (owner == None) { //printf("No owner\n"); return NULL; } XConvertSelection(dpy, selection, XA_STRING, XA_PRIMARY, us, CurrentTime); XFlush(dpy); while (max_events--) { XEvent e; XNextEvent(dpy, &e); if(e.type == SelectionNotify) { //printf("Received %s\n", XGetAtomName(dpy, e.xselection.selection)); if(e.xselection.property == None) { //printf("Couldn't convert\n"); return NULL; } long unsigned len, left, dummy; int format; Atom type; unsigned char *data = NULL; XGetWindowProperty(dpy, us, e.xselection.property, 0, 0, False, AnyPropertyType, &type, &format, &len, &left, &data); if (left < 1) return NULL; ret = XGetWindowProperty(dpy, us, e.xselection.property, 0, left, False, AnyPropertyType, &type, &format, &len, &dummy, &data); if (ret != Success) { //printf("Failed to get property: %p on %lu\n", data, len); return NULL; } //printf(">>> Got %s: len=%lu left=%lu (event %i)\n", data, len, left, 50-max_events); return (char*)data; } } return NULL; } bool RetrieveBuffer(std::string& text, std::string::size_type& pos) { SDL_SysWMinfo info; //printf("Retrieving buffer...\n"); SDL_VERSION(&info.version); if ( SDL_GetWMInfo(&info) ) { Display *dpy = info.info.x11.display; Window us = info.info.x11.window; char *data = NULL; if (!data) { data = getSelection(dpy, us, XA_PRIMARY); } if (!data) { data = getSelection(dpy, us, XA_SECONDARY); } if (!data) { Atom XA_CLIPBOARD = XInternAtom(dpy, "CLIPBOARD", 0); data = getSelection(dpy, us, XA_CLIPBOARD); } if (data) { // check cursor position if (pos > text.size()) { pos = text.size(); } text.insert(pos, data); pos += strlen(data); XFree(data); return true; } } return false; } #else bool RetrieveBuffer(std::string&, std::string::size_type&) { return false; } #endif