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 std.utf; 19 import std.conv; 20 21 import ae.sys.windows.exception; 22 23 import ae.sys.windows.imports; 24 mixin(importWin32!q{winbase}); 25 mixin(importWin32!q{windef}); 26 mixin(importWin32!q{winnls}); 27 mixin(importWin32!q{winuser}); 28 29 void setClipboardText(string s) 30 { 31 auto ws = s.toUTF16(); 32 33 char[] as; 34 int readLen; 35 as.length = WideCharToMultiByte(0, 0, ws.ptr, ws.length.to!DWORD, null, 0, null, null); 36 37 if (as.length) 38 { 39 readLen = WideCharToMultiByte(0, 0, ws.ptr, ws.length.to!DWORD, as.ptr, to!int(as.length), null, null); 40 wenforce(readLen == as.length, "WideCharToMultiByte"); 41 } 42 43 as ~= 0; 44 ws ~= 0; 45 46 setClipboard([ 47 ClipboardFormat(CF_TEXT, as), 48 ClipboardFormat(CF_UNICODETEXT, ws), 49 ]); 50 } 51 52 string getClipboardText() 53 { 54 static immutable DWORD[] textFormat = [CF_UNICODETEXT]; 55 auto format = getClipboard(textFormat)[0]; 56 wchar[] ws = (cast(wchar[])format.data)[0..$-1]; 57 return ws.toUTF8(); 58 } 59 60 // Windows-specific 61 62 /// One format entry in the Windows clipboard. 63 struct ClipboardFormat 64 { 65 DWORD format; 66 const (void)[] data; 67 68 string getName() 69 { 70 wchar[256] sbuf; 71 wchar[] buf = sbuf[]; 72 int ret; 73 do 74 { 75 ret = wenforce(GetClipboardFormatNameW(format, buf.ptr, buf.length.to!DWORD), "GetClipboardFormatNameW"); 76 } while (ret == buf.length ? (buf.length *=2, true) : false); 77 return buf[0..ret].toUTF8(); 78 } 79 } 80 81 /// Get clipboard data for the specified (default: all) formats. 82 ClipboardFormat[] getClipboard(in DWORD[] desiredFormatsP = null) 83 { 84 const(DWORD)[] desiredFormats = desiredFormatsP; 85 86 wenforce(OpenClipboard(null), "OpenClipboard"); 87 scope(exit) wenforce(CloseClipboard(), "CloseClipboard"); 88 89 if (desiredFormats is null) 90 { 91 auto allFormats = new DWORD[CountClipboardFormats()]; 92 DWORD previous = 0; 93 foreach (ref f; allFormats) 94 f = previous = EnumClipboardFormats(previous); 95 desiredFormats = allFormats; 96 } 97 98 auto result = new ClipboardFormat[desiredFormats.length]; 99 foreach (n, ref r; result) 100 { 101 r.format = desiredFormats[n]; 102 auto hBuf = wenforce(GetClipboardData(r.format), "GetClipboardData"); 103 auto size = GlobalSize(hBuf); 104 LPVOID buf = wenforce(GlobalLock(hBuf), "GlobalLock"); 105 r.data = buf[0..size].dup; 106 wenforce(GlobalUnlock(hBuf) || GetLastError()==NO_ERROR, "GlobalUnlock"); 107 } 108 109 return result; 110 } 111 112 void setClipboard(in ClipboardFormat[] formats) 113 { 114 wenforce(OpenClipboard(null), "OpenClipboard"); 115 scope(exit) wenforce(CloseClipboard(), "CloseClipboard"); 116 EmptyClipboard(); 117 foreach (ref format; formats) 118 { 119 HGLOBAL hBuf = wenforce(GlobalAlloc(GMEM_MOVEABLE, format.data.length.to!DWORD), "GlobalAlloc"); 120 scope(failure) wenforce(!GlobalFree(hBuf), "GlobalFree"); 121 LPVOID buf = wenforce(GlobalLock(hBuf), "GlobalLock"); 122 buf[0..format.data.length] = format.data[]; 123 wenforce(GlobalUnlock(hBuf) || GetLastError()==NO_ERROR, "GlobalUnlock"); 124 wenforce(SetClipboardData(format.format, hBuf), "SetClipboardData"); 125 } 126 } 127 } 128 else 129 version (Posix) 130 { 131 import std.process; 132 import std.exception; 133 134 import ae.utils.path; 135 136 void setClipboardText(string s) 137 { 138 string[] cmdLine; 139 if (haveExecutable("xclip")) 140 cmdLine = ["xclip", "-in", "-selection", "clipboard"]; 141 else 142 if (haveExecutable("xsel")) 143 cmdLine = ["xsel", "--input", "--clipboard"]; 144 else 145 if (haveExecutable("pbcopy")) 146 cmdLine = ["pbcopy"]; 147 else 148 throw new Exception("No clipboard management programs detected"); 149 auto p = pipe(); 150 auto pid = spawnProcess(cmdLine, p.readEnd); 151 p.writeEnd.rawWrite(s); 152 p.writeEnd.close(); 153 enforce(pid.wait() == 0, cmdLine[0] ~ " failed"); 154 } 155 156 string getClipboardText() 157 { 158 string[] cmdLine; 159 if (haveExecutable("xclip")) 160 cmdLine = ["xclip", "-out", "-selection", "clipboard"]; 161 else 162 if (haveExecutable("xsel")) 163 cmdLine = ["xsel", "--output", "--clipboard"]; 164 else 165 if (haveExecutable("pbpaste")) 166 cmdLine = ["pbpaste"]; 167 else 168 throw new Exception("No clipboard management programs detected"); 169 auto result = execute(cmdLine); 170 enforce(result.status == 0, cmdLine[0] ~ " failed"); 171 return result.output; 172 } 173 }