1 /** 2 * OS clipboard interaction. 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <vladimir@thecybershadow.net> 12 */ 13 14 module ae.sys.clipboard; 15 16 version (Windows) 17 { 18 import win32.winbase; 19 import win32.windef; 20 import win32.winnls; 21 import win32.winuser; 22 import ae.sys.windows.exception; 23 import std.utf; 24 import std.conv; 25 26 void setClipboardText(string s) 27 { 28 auto ws = s.toUTF16(); 29 30 char[] as; 31 int readLen; 32 as.length = WideCharToMultiByte(0, 0, ws.ptr, ws.length.to!DWORD, null, 0, null, null); 33 34 if (as.length) 35 { 36 readLen = WideCharToMultiByte(0, 0, ws.ptr, ws.length.to!DWORD, as.ptr, to!int(as.length), null, null); 37 wenforce(readLen == as.length, "WideCharToMultiByte"); 38 } 39 40 as ~= 0; 41 ws ~= 0; 42 43 setClipboard([ 44 ClipboardFormat(CF_TEXT, as), 45 ClipboardFormat(CF_UNICODETEXT, ws), 46 ]); 47 } 48 49 string getClipboardText() 50 { 51 static immutable DWORD[] textFormat = [CF_UNICODETEXT]; 52 auto format = getClipboard(textFormat)[0]; 53 wchar[] ws = (cast(wchar[])format.data)[0..$-1]; 54 return ws.toUTF8(); 55 } 56 57 // Windows-specific 58 59 /// One format entry in the Windows clipboard. 60 struct ClipboardFormat 61 { 62 DWORD format; 63 const (void)[] data; 64 65 string getName() 66 { 67 wchar[256] sbuf; 68 wchar[] buf = sbuf[]; 69 int ret; 70 do 71 { 72 ret = wenforce(GetClipboardFormatNameW(format, buf.ptr, buf.length.to!DWORD), "GetClipboardFormatNameW"); 73 } while (ret == buf.length ? (buf.length *=2, true) : false); 74 return buf[0..ret].toUTF8(); 75 } 76 } 77 78 /// Get clipboard data for the specified (default: all) formats. 79 ClipboardFormat[] getClipboard(in DWORD[] desiredFormatsP = null) 80 { 81 const(DWORD)[] desiredFormats = desiredFormatsP; 82 83 wenforce(OpenClipboard(null), "OpenClipboard"); 84 scope(exit) wenforce(CloseClipboard(), "CloseClipboard"); 85 86 if (desiredFormats is null) 87 { 88 auto allFormats = new DWORD[CountClipboardFormats()]; 89 DWORD previous = 0; 90 foreach (ref f; allFormats) 91 f = previous = EnumClipboardFormats(previous); 92 desiredFormats = allFormats; 93 } 94 95 auto result = new ClipboardFormat[desiredFormats.length]; 96 foreach (n, ref r; result) 97 { 98 r.format = desiredFormats[n]; 99 auto hBuf = wenforce(GetClipboardData(r.format), "GetClipboardData"); 100 auto size = GlobalSize(hBuf); 101 LPVOID buf = wenforce(GlobalLock(hBuf), "GlobalLock"); 102 r.data = buf[0..size].dup; 103 wenforce(GlobalUnlock(hBuf) || GetLastError()==NO_ERROR, "GlobalUnlock"); 104 } 105 106 return result; 107 } 108 109 void setClipboard(in ClipboardFormat[] formats) 110 { 111 wenforce(OpenClipboard(null), "OpenClipboard"); 112 scope(exit) wenforce(CloseClipboard(), "CloseClipboard"); 113 EmptyClipboard(); 114 foreach (ref format; formats) 115 { 116 HGLOBAL hBuf = wenforce(GlobalAlloc(GMEM_MOVEABLE, format.data.length.to!DWORD), "GlobalAlloc"); 117 scope(failure) wenforce(!GlobalFree(hBuf), "GlobalFree"); 118 LPVOID buf = wenforce(GlobalLock(hBuf), "GlobalLock"); 119 buf[0..format.data.length] = format.data[]; 120 wenforce(GlobalUnlock(hBuf) || GetLastError()==NO_ERROR, "GlobalUnlock"); 121 wenforce(SetClipboardData(format.format, hBuf), "SetClipboardData"); 122 } 123 } 124 }