1 |
|
|
/* |
2 |
|
|
* The ManaPlus Client |
3 |
|
|
* Copyright (C) 2001-2010 Wormux Team |
4 |
|
|
* Copyright (C) 2011-2019 The ManaPlus Developers |
5 |
|
|
* Copyright (C) 2019-2021 Andrei Karas |
6 |
|
|
* |
7 |
|
|
* This file is part of The ManaPlus Client. |
8 |
|
|
* |
9 |
|
|
* This program is free software; you can redistribute it and/or modify |
10 |
|
|
* it under the terms of the GNU General Public License as published by |
11 |
|
|
* the Free Software Foundation; either version 2 of the License, or |
12 |
|
|
* any later version. |
13 |
|
|
* |
14 |
|
|
* This program is distributed in the hope that it will be useful, |
15 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 |
|
|
* GNU General Public License for more details. |
18 |
|
|
* |
19 |
|
|
* You should have received a copy of the GNU General Public License |
20 |
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
21 |
|
|
*/ |
22 |
|
|
|
23 |
|
|
/* |
24 |
|
|
* IMPORTANT! |
25 |
|
|
* |
26 |
|
|
* This code was taken from Wormux svn trunk at Feb 25 2010. Please don't |
27 |
|
|
* make any unnecessary modifications, and try to sync up modifications |
28 |
|
|
* when possible. |
29 |
|
|
*/ |
30 |
|
|
|
31 |
|
|
#ifdef _MSC_VER |
32 |
|
|
# include "msvc/config.h" |
33 |
|
|
#elif defined(HAVE_CONFIG_H) |
34 |
|
|
#include "config.h" |
35 |
|
|
#endif // _MSC_VER |
36 |
|
|
|
37 |
|
|
#include "utils/copynpaste.h" |
38 |
|
|
|
39 |
|
|
#include "debug.h" |
40 |
|
|
|
41 |
|
|
#ifdef USE_SDL2 |
42 |
|
|
PRAGMA48(GCC diagnostic push) |
43 |
|
|
PRAGMA48(GCC diagnostic ignored "-Wshadow") |
44 |
|
|
#include <SDL_clipboard.h> |
45 |
|
|
PRAGMA48(GCC diagnostic pop) |
46 |
|
|
|
47 |
|
|
#else // USE_SDL2 |
48 |
|
|
|
49 |
|
|
#if defined(__APPLE__) |
50 |
|
|
#ifdef Status |
51 |
|
|
#undef Status |
52 |
|
|
#endif // Status |
53 |
|
|
#include <Carbon/Carbon.h> |
54 |
|
|
#elif defined USE_X11 |
55 |
|
|
#include "render/graphics.h" |
56 |
|
|
|
57 |
|
|
#include "utils/sdlhelper.h" |
58 |
|
|
|
59 |
|
|
PRAGMA48(GCC diagnostic push) |
60 |
|
|
PRAGMA48(GCC diagnostic ignored "-Wshadow") |
61 |
|
|
#include <SDL_syswm.h> |
62 |
|
|
PRAGMA48(GCC diagnostic pop) |
63 |
|
|
#include <unistd.h> |
64 |
|
|
#elif defined __native_client__ |
65 |
|
|
#include "utils/naclmessages.h" |
66 |
|
|
#elif defined WIN32 |
67 |
|
|
#include "utils/cast.h" |
68 |
|
|
PRAGMA48(GCC diagnostic push) |
69 |
|
|
PRAGMA48(GCC diagnostic ignored "-Wshadow") |
70 |
|
|
#include <SDL_syswm.h> |
71 |
|
|
PRAGMA48(GCC diagnostic pop) |
72 |
|
|
#endif // defined(__APPLE__) |
73 |
|
|
|
74 |
|
|
#endif // USE_SDL2 |
75 |
|
|
|
76 |
|
|
#ifdef USE_SDL2 |
77 |
|
|
bool retrieveBuffer(std::string& text, size_t& pos) |
78 |
|
|
{ |
79 |
|
|
char *buf = SDL_GetClipboardText(); |
80 |
|
|
if (buf) |
81 |
|
|
{ |
82 |
|
|
text.insert(pos, buf); |
83 |
|
|
pos += strlen(buf); |
84 |
|
|
SDL_free(buf); |
85 |
|
|
return true; |
86 |
|
|
} |
87 |
|
|
return false; |
88 |
|
|
} |
89 |
|
|
|
90 |
|
|
bool sendBuffer(const std::string &restrict text) |
91 |
|
|
{ |
92 |
|
|
return !SDL_SetClipboardText(text.c_str()); |
93 |
|
|
} |
94 |
|
|
|
95 |
|
|
#else // USE_SDL2 |
96 |
|
|
|
97 |
|
|
#ifdef WIN32 |
98 |
|
|
bool retrieveBuffer(std::string& text, size_t& pos) |
99 |
|
|
{ |
100 |
|
|
bool ret = false; |
101 |
|
|
|
102 |
|
|
if (!OpenClipboard(nullptr)) |
103 |
|
|
return false; |
104 |
|
|
|
105 |
|
|
HANDLE h = GetClipboardData(CF_UNICODETEXT); |
106 |
|
|
if (h) |
107 |
|
|
{ |
108 |
|
|
LPCWSTR data = static_cast<LPCWSTR>(GlobalLock(h)); |
109 |
|
|
|
110 |
|
|
if (data) |
111 |
|
|
{ |
112 |
|
|
const size_t len = WideCharToMultiByte(CP_UTF8, 0, data, -1, |
113 |
|
|
nullptr, 0, nullptr, nullptr); |
114 |
|
|
if (len > 0) |
115 |
|
|
{ |
116 |
|
|
// Convert from UTF-16 to UTF-8 |
117 |
|
|
void *temp = calloc(len, 1); |
118 |
|
|
if (WideCharToMultiByte(CP_UTF8, 0, data, -1, |
119 |
|
|
static_cast<LPSTR>(temp), len, nullptr, nullptr)) |
120 |
|
|
{ |
121 |
|
|
text.insert(pos, static_cast<char*>(temp)); |
122 |
|
|
pos += len - 1; |
123 |
|
|
} |
124 |
|
|
free(temp); |
125 |
|
|
ret = true; |
126 |
|
|
} |
127 |
|
|
} |
128 |
|
|
GlobalUnlock(h); |
129 |
|
|
} |
130 |
|
|
else |
131 |
|
|
{ |
132 |
|
|
h = GetClipboardData(CF_TEXT); |
133 |
|
|
|
134 |
|
|
if (h) |
135 |
|
|
{ |
136 |
|
|
const char *const data = static_cast<char*>(GlobalLock(h)); |
137 |
|
|
if (data) |
138 |
|
|
{ |
139 |
|
|
text.insert(pos, data); |
140 |
|
|
pos += strlen(data); |
141 |
|
|
ret = true; |
142 |
|
|
} |
143 |
|
|
GlobalUnlock(h); |
144 |
|
|
} |
145 |
|
|
} |
146 |
|
|
|
147 |
|
|
CloseClipboard(); |
148 |
|
|
return ret; |
149 |
|
|
} |
150 |
|
|
|
151 |
|
|
bool sendBuffer(const std::string &restrict text) |
152 |
|
|
{ |
153 |
|
|
const int wCharsLen = MultiByteToWideChar(CP_UTF8, |
154 |
|
|
0, text.c_str(), -1, nullptr, 0); |
155 |
|
|
if (!wCharsLen) |
156 |
|
|
return false; |
157 |
|
|
|
158 |
|
|
HANDLE h = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, |
159 |
|
|
CAST_SIZE(wCharsLen) * sizeof(WCHAR)); |
160 |
|
|
WCHAR *const out = static_cast<WCHAR*>(GlobalLock(h)); |
161 |
|
|
|
162 |
|
|
MultiByteToWideChar(CP_UTF8, 0, text.c_str(), -1, out, wCharsLen); |
163 |
|
|
|
164 |
|
|
if (!OpenClipboard(nullptr)) |
165 |
|
|
{ |
166 |
|
|
GlobalUnlock(h); |
167 |
|
|
GlobalFree(h); |
168 |
|
|
return false; |
169 |
|
|
} |
170 |
|
|
GlobalUnlock(h); |
171 |
|
|
EmptyClipboard(); |
172 |
|
|
if (!SetClipboardData(CF_UNICODETEXT, out)) |
173 |
|
|
{ |
174 |
|
|
GlobalFree(h); |
175 |
|
|
CloseClipboard(); |
176 |
|
|
return false; |
177 |
|
|
} |
178 |
|
|
GlobalFree(h); |
179 |
|
|
CloseClipboard(); |
180 |
|
|
|
181 |
|
|
return true; |
182 |
|
|
} |
183 |
|
|
|
184 |
|
|
#elif defined(__APPLE__) |
185 |
|
|
|
186 |
|
|
// Sorry for the very long code, all nicer OS X APIs are coded in |
187 |
|
|
// Objective C and not C! |
188 |
|
|
// Also it does very thorough error handling |
189 |
|
|
bool getDataFromPasteboard(PasteboardRef inPasteboard, |
190 |
|
|
char* flavorText /* out */, |
191 |
|
|
const int bufSize) |
192 |
|
|
{ |
193 |
|
|
ItemCount itemCount; |
194 |
|
|
PasteboardSyncFlags syncFlags = PasteboardSynchronize(inPasteboard); |
195 |
|
|
OSStatus err = PasteboardGetItemCount(inPasteboard, &itemCount); |
196 |
|
|
require_noerr(err, CantGetPasteboardItemCount); |
197 |
|
|
|
198 |
|
|
for (UInt32 itemIndex = 1; itemIndex <= itemCount; itemIndex ++) |
199 |
|
|
{ |
200 |
|
|
PasteboardItemID itemID; |
201 |
|
|
CFArrayRef flavorTypeArray; |
202 |
|
|
CFIndex flavorCount; |
203 |
|
|
|
204 |
|
|
err = PasteboardGetItemIdentifier(inPasteboard, itemIndex, &itemID); |
205 |
|
|
require_noerr(err, CantGetPasteboardItemIdentifier); |
206 |
|
|
|
207 |
|
|
err = PasteboardCopyItemFlavors(inPasteboard, |
208 |
|
|
itemID, &flavorTypeArray); |
209 |
|
|
require_noerr(err, CantCopyPasteboardItemFlavors); |
210 |
|
|
|
211 |
|
|
flavorCount = CFArrayGetCount(flavorTypeArray); |
212 |
|
|
|
213 |
|
|
for (CFIndex flavorIndex = 0; flavorIndex < flavorCount; |
214 |
|
|
flavorIndex ++) |
215 |
|
|
{ |
216 |
|
|
CFStringRef flavorType = (CFStringRef)CFArrayGetValueAtIndex( |
217 |
|
|
flavorTypeArray, flavorIndex); |
218 |
|
|
|
219 |
|
|
// we're only interested by text... |
220 |
|
|
if (UTTypeConformsTo(flavorType, CFSTR("public.utf8-plain-text"))) |
221 |
|
|
{ |
222 |
|
|
CFDataRef flavorData; |
223 |
|
|
err = PasteboardCopyItemFlavorData(inPasteboard, itemID, |
224 |
|
|
flavorType, &flavorData); |
225 |
|
|
require_noerr(err, CantCopyFlavorData); |
226 |
|
|
CFIndex flavorDataSize = CFDataGetLength(flavorData); |
227 |
|
|
flavorDataSize = (flavorDataSize<254) ? flavorDataSize : 254; |
228 |
|
|
|
229 |
|
|
if (flavorDataSize + 2 > bufSize) |
230 |
|
|
{ |
231 |
|
|
fprintf(stderr, |
232 |
|
|
"Cannot copy clipboard, contents is too big!\n"); |
233 |
|
|
return false; |
234 |
|
|
} |
235 |
|
|
|
236 |
|
|
for (short dataIndex = 0; dataIndex <= flavorDataSize; |
237 |
|
|
dataIndex ++) |
238 |
|
|
{ |
239 |
|
|
signed char byte = *(CFDataGetBytePtr( |
240 |
|
|
flavorData) + dataIndex); |
241 |
|
|
flavorText[dataIndex] = byte; |
242 |
|
|
} |
243 |
|
|
|
244 |
|
|
flavorText[flavorDataSize] = '\0'; |
245 |
|
|
flavorText[flavorDataSize + 1] = '\n'; |
246 |
|
|
|
247 |
|
|
CFRelease(flavorData); |
248 |
|
|
return true; |
249 |
|
|
} |
250 |
|
|
|
251 |
|
|
continue; |
252 |
|
|
CantCopyFlavorData: |
253 |
|
|
fprintf(stderr, "Cannot copy clipboard, CantCopyFlavorData!\n"); |
254 |
|
|
} |
255 |
|
|
|
256 |
|
|
CFRelease(flavorTypeArray); |
257 |
|
|
continue; |
258 |
|
|
|
259 |
|
|
CantCopyPasteboardItemFlavors: |
260 |
|
|
fprintf(stderr, |
261 |
|
|
"Cannot copy clipboard, CantCopyPasteboardItemFlavors!\n"); |
262 |
|
|
continue; |
263 |
|
|
CantGetPasteboardItemIdentifier: |
264 |
|
|
fprintf(stderr, |
265 |
|
|
"Cannot copy clipboard, CantGetPasteboardItemIdentifier!\n"); |
266 |
|
|
continue; |
267 |
|
|
} |
268 |
|
|
fprintf(stderr, |
269 |
|
|
"Cannot copy clipboard, found no acceptable flavour!\n"); |
270 |
|
|
return false; |
271 |
|
|
|
272 |
|
|
CantGetPasteboardItemCount: |
273 |
|
|
fprintf(stderr, "Cannot copy clipboard, CantGetPasteboardItemCount!\n"); |
274 |
|
|
return false; |
275 |
|
|
} |
276 |
|
|
|
277 |
|
|
bool getClipBoard(char* text /* out */, const int bufSize) |
278 |
|
|
{ |
279 |
|
|
PasteboardRef theClipboard; |
280 |
|
|
OSStatus err = PasteboardCreate(kPasteboardClipboard, &theClipboard); |
281 |
|
|
require_noerr(err, PasteboardCreateFailed); |
282 |
|
|
|
283 |
|
|
if (!getDataFromPasteboard(theClipboard, text, bufSize)) |
284 |
|
|
{ |
285 |
|
|
fprintf(stderr, |
286 |
|
|
"Cannot copy clipboard, getDataFromPasteboardFailed!\n"); |
287 |
|
|
return false; |
288 |
|
|
} |
289 |
|
|
|
290 |
|
|
CFRelease(theClipboard); |
291 |
|
|
|
292 |
|
|
return true; |
293 |
|
|
|
294 |
|
|
// ---- error handling |
295 |
|
|
PasteboardCreateFailed: |
296 |
|
|
fprintf(stderr, "Cannot copy clipboard, PasteboardCreateFailed!\n"); |
297 |
|
|
CFRelease(theClipboard); |
298 |
|
|
return false; |
299 |
|
|
} |
300 |
|
|
|
301 |
|
|
bool retrieveBuffer(std::string& text, size_t& pos) |
302 |
|
|
{ |
303 |
|
|
const int bufSize = 512; |
304 |
|
|
char buffer[bufSize + 1]; |
305 |
|
|
|
306 |
|
|
if (getClipBoard(buffer, bufSize)) |
307 |
|
|
{ |
308 |
|
|
text = buffer; |
309 |
|
|
pos += strlen(buffer); |
310 |
|
|
return true; |
311 |
|
|
} |
312 |
|
|
else |
313 |
|
|
{ |
314 |
|
|
return false; |
315 |
|
|
} |
316 |
|
|
} |
317 |
|
|
|
318 |
|
|
bool sendBuffer(const std::string &restrict text) |
319 |
|
|
{ |
320 |
|
|
return false; |
321 |
|
|
} |
322 |
|
|
|
323 |
|
|
#elif defined USE_X11 |
324 |
|
|
|
325 |
|
|
static char* getSelection2(Display *const dpy, Window us, Atom selection, |
326 |
|
|
Atom request_target) |
327 |
|
|
{ |
328 |
|
|
int max_events = 50; |
329 |
|
|
Window owner = XGetSelectionOwner(dpy, selection); |
330 |
|
|
|
331 |
|
|
if (owner == None) |
332 |
|
|
return nullptr; |
333 |
|
|
|
334 |
|
|
XConvertSelection(dpy, selection, request_target, |
335 |
|
|
XA_PRIMARY, us, CurrentTime); |
336 |
|
|
XFlush(dpy); |
337 |
|
|
|
338 |
|
|
while (max_events --) |
339 |
|
|
{ |
340 |
|
|
XEvent e; |
341 |
|
|
|
342 |
|
|
XNextEvent(dpy, &e); |
343 |
|
|
if (e.type == SelectionNotify) |
344 |
|
|
{ |
345 |
|
|
if (e.xselection.property == None) |
346 |
|
|
return nullptr; |
347 |
|
|
|
348 |
|
|
long unsigned len, left, dummy; |
349 |
|
|
int format; |
350 |
|
|
Atom type; |
351 |
|
|
unsigned char *data = nullptr; |
352 |
|
|
|
353 |
|
|
int ret = XGetWindowProperty(dpy, us, e.xselection.property, 0, 0, |
354 |
|
|
False, AnyPropertyType, &type, &format, &len, &left, &data); |
355 |
|
|
if (left < 1) |
356 |
|
|
{ |
357 |
|
|
if (ret == Success) |
358 |
|
|
XFree(data); |
359 |
|
|
return nullptr; |
360 |
|
|
} |
361 |
|
|
|
362 |
|
|
ret = XGetWindowProperty(dpy, us, e.xselection.property, 0, |
363 |
|
|
left, False, AnyPropertyType, &type, &format, &len, |
364 |
|
|
&dummy, &data); |
365 |
|
|
|
366 |
|
|
if (ret != Success) |
367 |
|
|
return nullptr; |
368 |
|
|
|
369 |
|
|
return reinterpret_cast<char*>(data); |
370 |
|
|
} |
371 |
|
|
} |
372 |
|
|
return nullptr; |
373 |
|
|
} |
374 |
|
|
|
375 |
|
|
static Atom requestAtom; |
376 |
|
|
|
377 |
|
|
static char* getSelection(Display *const dpy, Window us, Atom selection) |
378 |
|
|
{ |
379 |
|
|
char *data = nullptr; |
380 |
|
|
if (requestAtom != None) |
381 |
|
|
data = getSelection2(dpy, us, selection, requestAtom); |
382 |
|
|
if (!data) |
383 |
|
|
data = getSelection2(dpy, us, selection, XA_STRING); |
384 |
|
|
return data; |
385 |
|
|
} |
386 |
|
|
|
387 |
|
|
bool retrieveBuffer(std::string& text, size_t& pos) |
388 |
|
|
{ |
389 |
|
|
SDL_SysWMinfo info; |
390 |
|
|
|
391 |
|
|
SDL_VERSION(&info.version) |
392 |
|
|
if (SDL::getWindowWMInfo(mainGraphics->getWindow(), &info)) |
393 |
|
|
{ |
394 |
|
|
Display *const dpy = info.info.x11.display; |
395 |
|
|
Window us = info.info.x11.window; |
396 |
|
|
|
397 |
|
|
requestAtom = XInternAtom(dpy, "UTF8_STRING", true); |
398 |
|
|
char *data = getSelection(dpy, us, XA_PRIMARY); |
399 |
|
|
if (!data) |
400 |
|
|
data = getSelection(dpy, us, XA_SECONDARY); |
401 |
|
|
if (!data) |
402 |
|
|
{ |
403 |
|
|
Atom XA_CLIPBOARD = XInternAtom(dpy, "CLIPBOARD", 0); |
404 |
|
|
if (XA_CLIPBOARD != None) |
405 |
|
|
data = getSelection(dpy, us, XA_CLIPBOARD); |
406 |
|
|
} |
407 |
|
|
|
408 |
|
|
if (data) |
409 |
|
|
{ |
410 |
|
|
// check cursor position |
411 |
|
|
const size_t sz = text.size(); |
412 |
|
|
if (pos > sz) |
413 |
|
|
pos = sz; |
414 |
|
|
|
415 |
|
|
text.insert(pos, data); |
416 |
|
|
pos += strlen(data); |
417 |
|
|
XFree(data); |
418 |
|
|
|
419 |
|
|
return true; |
420 |
|
|
} |
421 |
|
|
} |
422 |
|
|
return false; |
423 |
|
|
} |
424 |
|
|
|
425 |
|
|
static bool runxsel(const std::string &text, const char *p1, |
426 |
|
|
const char *p2 = nullptr); |
427 |
|
|
|
428 |
|
|
bool sendBuffer(const std::string &restrict text) |
429 |
|
|
{ |
430 |
|
|
runxsel(text, "-i"); |
431 |
|
|
runxsel(text, "-b", "-i"); |
432 |
|
|
return true; |
433 |
|
|
} |
434 |
|
|
|
435 |
|
|
static bool runxsel(const std::string &text, const char *p1, const char *p2) |
436 |
|
|
{ |
437 |
|
|
pid_t pid; |
438 |
|
|
int fd[2]; |
439 |
|
|
|
440 |
|
|
if (pipe(fd)) |
441 |
|
|
return false; |
442 |
|
|
|
443 |
|
|
if ((pid = fork()) == -1) |
444 |
|
|
{ // fork error |
445 |
|
|
return false; |
446 |
|
|
} |
447 |
|
|
else if (!pid) |
448 |
|
|
{ // child |
449 |
|
|
close(fd[1]); |
450 |
|
|
|
451 |
|
|
if (fd[0] != STDIN_FILENO) |
452 |
|
|
{ |
453 |
|
|
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) |
454 |
|
|
{ |
455 |
|
|
close(fd[0]); |
456 |
|
|
_exit(1); |
457 |
|
|
} |
458 |
|
|
close(fd[0]); |
459 |
|
|
} |
460 |
|
|
|
461 |
|
|
const char *const xselPath = |
462 |
|
|
#if defined __OpenBSD__ || defined __FreeBSD__ || defined __DragonFly__ |
463 |
|
|
"/usr/local/bin/xsel"; |
464 |
|
|
#else // defined __OpenBSD__ || defined __FreeBSD__ || defined __DragonFly__ |
465 |
|
|
"/usr/bin/xsel"; |
466 |
|
|
#endif // defined __OpenBSD__ || defined __FreeBSD__ || defined __DragonFly__ |
467 |
|
|
|
468 |
|
|
if (p2) |
469 |
|
|
{ |
470 |
|
|
execl(xselPath, "xsel", p1, p2, |
471 |
|
|
static_cast<char *>(nullptr)); |
472 |
|
|
} |
473 |
|
|
else |
474 |
|
|
{ |
475 |
|
|
execl(xselPath, "xsel", p1, |
476 |
|
|
static_cast<char *>(nullptr)); |
477 |
|
|
} |
478 |
|
|
|
479 |
|
|
_exit(1); |
480 |
|
|
} |
481 |
|
|
|
482 |
|
|
// parent |
483 |
|
|
close(fd[0]); |
484 |
|
|
const size_t len = text.length(); |
485 |
|
|
if (write(fd[1], text.c_str(), len) != static_cast<ssize_t>(len)) |
486 |
|
|
{ |
487 |
|
|
close(fd[1]); |
488 |
|
|
return false; |
489 |
|
|
} |
490 |
|
|
close(fd[1]); |
491 |
|
|
return true; |
492 |
|
|
} |
493 |
|
|
|
494 |
|
|
#elif defined __native_client__ |
495 |
|
|
|
496 |
|
|
bool retrieveBuffer(std::string& text, size_t& pos) |
497 |
|
|
{ |
498 |
|
|
NaclMessageHandle *handle = naclRegisterMessageHandler("clipboard-paste"); |
499 |
|
|
naclPostMessage("clipboard-paste", ""); |
500 |
|
|
std::string response = naclWaitForMessage(handle); |
501 |
|
|
text.insert(pos, response); |
502 |
|
|
pos += response.size(); |
503 |
|
|
return true; |
504 |
|
|
} |
505 |
|
|
|
506 |
|
|
bool sendBuffer(const std::string &restrict text) |
507 |
|
|
{ |
508 |
|
|
naclPostMessage("clipboard-copy", text); |
509 |
|
|
return true; |
510 |
|
|
} |
511 |
|
|
#else // WIN32 |
512 |
|
|
|
513 |
|
|
bool retrieveBuffer(std::string &text A_UNUSED, size_t &pos A_UNUSED) |
514 |
|
|
{ |
515 |
|
|
return false; |
516 |
|
|
} |
517 |
|
|
|
518 |
|
|
bool sendBuffer(const std::string &restrict text A_UNUSED) |
519 |
|
|
{ |
520 |
|
|
return false; |
521 |
|
|
} |
522 |
|
|
#endif // WIN32 |
523 |
|
|
#endif // USE_SDL2 |