Commit 91632d71 authored by nanahira's avatar nanahira

Merge branch 'patch-clipboard' of github.com:mercury233/irrlicht into develop

parents a7be8a33 2e30bc5d
......@@ -26,11 +26,11 @@ public:
}
//! Copies text to the clipboard
virtual void copyToClipboard(const c16* text) const = 0;
virtual void copyToClipboard(const c8* text) const = 0;
//! Get text from the clipboard
/** \return Returns 0 if no string is in there. */
virtual const c16* getTextFromClipboard() const = 0;
virtual const c8* getTextFromClipboard() const = 0;
//! Get the processor speed in megahertz
/** \param MHz The integer variable to store the speed in.
......
......@@ -12,6 +12,11 @@
#include <string.h>
#include <stdlib.h>
#ifdef _IRR_WINDOWS_API_
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
namespace irr
{
namespace core
......@@ -1360,14 +1365,66 @@ typedef string<c8> stringc;
//! Typedef for wide character strings
typedef string<wchar_t> stringw;
//! wrap of mbstowcs
//! Converts UTF-8/multibyte string to wide character string
/** On Windows: Converts from UTF-8 (encoding-agnostic, does not depend on locale).
On other platforms: Uses current locale settings (UTF-8 is recommended).
\return Pointer to newly allocated wide character string; caller must delete[].
*/
static inline wchar_t* toWideChar(const char* p)
{
if (!p)
{
wchar_t* ws = new wchar_t[1];
ws[0] = 0;
return ws;
}
#ifdef _IRR_WINDOWS_API_
int len = MultiByteToWideChar(CP_UTF8, 0, p, -1, NULL, 0);
if (len <= 0) len = 1;
wchar_t* ws = new wchar_t[len];
if (MultiByteToWideChar(CP_UTF8, 0, p, -1, ws, len) == 0)
ws[0] = 0;
return ws;
#else
size_t lenOld = strlen(p);
wchar_t* ws = new wchar_t[lenOld + 1];
size_t lenNew = mbstowcs(ws, p, lenOld);
size_t lenNew = mbstowcs(ws, p, lenOld + 1);
if (lenNew == (size_t)-1) lenNew = 0;
ws[lenNew] = 0;
return ws;
#endif
}
//! Converts wide character string to UTF-8/multibyte string
/** On Windows: Converts to UTF-8 (encoding-agnostic, does not depend on locale).
On other platforms: Uses current locale settings (UTF-8 is recommended).
\return Pointer to newly allocated multibyte string; caller must delete[].
*/
static inline char* toMultiByte(const wchar_t* p)
{
if (!p)
{
char* cs = new char[1];
cs[0] = 0;
return cs;
}
#ifdef _IRR_WINDOWS_API_
int len = WideCharToMultiByte(CP_UTF8, 0, p, -1, NULL, 0, NULL, NULL);
if (len <= 0) len = 1;
char* cs = new char[len];
if (WideCharToMultiByte(CP_UTF8, 0, p, -1, cs, len, NULL, NULL) == 0)
cs[0] = 0;
return cs;
#else
size_t lenOld = wcslen(p);
// Allocate worst-case buffer (MB_CUR_MAX bytes per wchar_t)
size_t bufSize = lenOld * MB_CUR_MAX + 1;
char* cs = new char[bufSize];
size_t lenNew = wcstombs(cs, p, bufSize - 1);
if (lenNew == (size_t)-1) lenNew = 0;
cs[lenNew] = 0;
return cs;
#endif
}
} // end namespace core
......
......@@ -48,9 +48,6 @@ typedef __int16 s16;
typedef signed short s16;
#endif
//! 16 bit character variable.
/** This is a typedef for wchar_t, it ensures portability of the engine. */
typedef wchar_t c16;
//! 32 bit unsigned variable.
......
......@@ -287,9 +287,10 @@ bool CGUIEditBox::processKey(const SEvent& event)
const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
core::stringw s;
s = Text.subString(realmbgn, realmend - realmbgn).c_str();
Operator->copyToClipboard(s.c_str());
core::stringw s = Text.subString(realmbgn, realmend - realmbgn);
c8* mb = core::toMultiByte(s.c_str());
Operator->copyToClipboard(mb);
delete[] mb;
}
break;
case KEY_KEY_X:
......@@ -300,9 +301,10 @@ bool CGUIEditBox::processKey(const SEvent& event)
const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
// copy
core::stringw sc;
sc = Text.subString(realmbgn, realmend - realmbgn).c_str();
Operator->copyToClipboard(sc.c_str());
core::stringw sc = Text.subString(realmbgn, realmend - realmbgn);
c8* mb = core::toMultiByte(sc.c_str());
Operator->copyToClipboard(mb);
delete[] mb;
if (isEnabled())
{
......@@ -330,10 +332,12 @@ bool CGUIEditBox::processKey(const SEvent& event)
const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
// add new character
const c16* p = Operator->getTextFromClipboard();
const c8* p = Operator->getTextFromClipboard();
if (p)
{
irr::core::stringw widep(p);
wchar_t* ws = core::toWideChar(p);
irr::core::stringw widep(ws);
delete[] ws;
if (MarkBegin == MarkEnd)
{
......
......@@ -1114,7 +1114,7 @@ bool CIrrDeviceLinux::run()
XChangeProperty (display,
req->requestor,
req->property,
req->target == X_ATOM_TEXT ? XA_STRING : req->target,
req->target == XA_STRING ? XA_STRING : X_ATOM_UTF8_STRING,
8, // format
PropModeReplace,
(unsigned char*) Clipboard.c_str(),
......@@ -1123,10 +1123,12 @@ bool CIrrDeviceLinux::run()
}
else if ( req->target == X_ATOM_TARGETS )
{
long data[2];
data[0] = X_ATOM_TEXT;
data[1] = XA_STRING;
// Most preferred format first
Atom data[4];
data[0] = X_ATOM_UTF8_STRING;
data[1] = X_ATOM_TEXT;
data[2] = XA_STRING;
data[3] = X_ATOM_TARGETS;
XChangeProperty (display,
req->requestor,
......@@ -1134,8 +1136,8 @@ bool CIrrDeviceLinux::run()
XA_ATOM,
32, // format
PropModeReplace,
(unsigned char *) &X_ATOM_UTF8_STRING,
1);
(unsigned char *)data,
4);
respond.xselection.property = req->property;
}
else
......@@ -1882,11 +1884,35 @@ const c8* CIrrDeviceLinux::getTextFromClipboard() const
Clipboard = "";
if (ownerWindow != None )
{
XConvertSelection (display, X_ATOM_CLIPBOARD, X_ATOM_UTF8_STRING, X_ATOM_XSEL_DATA, window, CurrentTime);
// First try UTF-8, then fall back to XA_STRING (ISO Latin-1)
Atom fmtsToTry[2] = { X_ATOM_UTF8_STRING, XA_STRING };
for (int fmtIdx = 0; fmtIdx < 2 && Clipboard.empty(); ++fmtIdx)
{
XConvertSelection (display, X_ATOM_CLIPBOARD, fmtsToTry[fmtIdx], X_ATOM_XSEL_DATA, window, CurrentTime);
XSync (display, 0);
XEvent event;
do nanosleep ((const struct timespec[]){{0, 1L}}, NULL);
while (!XCheckTypedEvent (display, SelectionNotify, &event));
struct timespec deadline;
clock_gettime(CLOCK_MONOTONIC, &deadline);
deadline.tv_sec += 1;
bool gotSelectionNotify = false;
do
{
struct timespec sleepTs = {0, 1000000L};
nanosleep (&sleepTs, NULL);
gotSelectionNotify = XCheckTypedEvent (display, SelectionNotify, &event) != 0;
if (!gotSelectionNotify)
{
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
if (now.tv_sec > deadline.tv_sec || (now.tv_sec == deadline.tv_sec && now.tv_nsec >= deadline.tv_nsec))
break;
}
}
while (!gotSelectionNotify);
if (!gotSelectionNotify)
continue;
if ( (event.xselection.selection == X_ATOM_CLIPBOARD) && event.xselection.property )
{
Atom type;
......@@ -1906,14 +1932,17 @@ const c8* CIrrDeviceLinux::getTextFromClipboard() const
&dummy, // remaining bytes for partial reads
&data); // data
if ( result == Success
&& data
&& (type == X_ATOM_UTF8_STRING || type == XA_STRING) ) // not implemented: INCR (partial reads)
{
Clipboard = strndup((char*)data, size);
XFree (data);
Clipboard = core::stringc((const c8*)data, size);
}
if (data)
XFree (data);
XDeleteProperty (event.xselection.display, event.xselection.requestor, event.xselection.property);
}
}
}
return Clipboard.c_str();
......
......@@ -9,7 +9,6 @@
#include <windows.h>
#endif
#else
#include <locale.h>
#include <string.h>
#include <unistd.h>
#ifndef _IRR_SOLARIS_PLATFORM_
......@@ -55,30 +54,51 @@ const core::stringc& COSOperator::getOperatingSystemVersion() const
//! copies text to the clipboard
void COSOperator::copyToClipboard(const c16* text) const
//! text must be encoded in the system multibyte format (UTF-8 on Linux/macOS)
void COSOperator::copyToClipboard(const c8* text) const
{
size_t len = wcslen(text);
if (len==0)
if (!text || text[0] == '\0')
return;
// Windows version
#if defined(_IRR_XBOX_PLATFORM_)
#elif defined(_IRR_WINDOWS_API_)
if (!OpenClipboard(NULL) || text == 0)
// Convert UTF-8 to UTF-16 for the Windows clipboard
int wlen = MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0);
if (wlen == 0)
return;
if (!OpenClipboard(NULL))
return;
EmptyClipboard();
HGLOBAL clipbuffer;
wchar_t * buffer;
HGLOBAL clipbuffer = GlobalAlloc(GMEM_MOVEABLE, sizeof(wchar_t) * wlen);
if (!clipbuffer)
{
CloseClipboard();
return;
}
clipbuffer = GlobalAlloc(GMEM_DDESHARE, sizeof(wchar_t) * (len + 1));
buffer = (wchar_t*)GlobalLock(clipbuffer);
wchar_t* buffer = (wchar_t*)GlobalLock(clipbuffer);
if (!buffer)
{
GlobalFree(clipbuffer);
CloseClipboard();
return;
}
wcscpy(buffer, text);
if (MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, wlen) == 0)
{
GlobalUnlock(clipbuffer);
GlobalFree(clipbuffer);
CloseClipboard();
return;
}
GlobalUnlock(clipbuffer);
SetClipboardData(CF_UNICODETEXT, clipbuffer);
if (!SetClipboardData(CF_UNICODETEXT, clipbuffer))
GlobalFree(clipbuffer);
CloseClipboard();
// MacOSX version
......@@ -88,18 +108,7 @@ void COSOperator::copyToClipboard(const c16* text) const
#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_)
if ( IrrDeviceLinux )
{
size_t wlen = sizeof(wchar_t) * (len + 1);
char ctext[wlen];
char* oldLocale = setlocale(LC_CTYPE, NULL);
setlocale(LC_CTYPE, "");
size_t lenNew = wcstombs(ctext, text, wlen);
ctext[lenNew] = 0;
setlocale(LC_CTYPE, oldLocale);
IrrDeviceLinux->copyToClipboard(ctext);
}
IrrDeviceLinux->copyToClipboard(text);
#else
#endif
......@@ -108,7 +117,8 @@ void COSOperator::copyToClipboard(const c16* text) const
//! gets text from the clipboard
//! \return Returns 0 if no string is in there.
const c16* COSOperator::getTextFromClipboard() const
//! Result is encoded in the system multibyte format (UTF-8 on Linux/macOS)
const c8* COSOperator::getTextFromClipboard() const
{
#if defined(_IRR_XBOX_PLATFORM_)
return 0;
......@@ -116,29 +126,35 @@ const c16* COSOperator::getTextFromClipboard() const
if (!OpenClipboard(NULL))
return 0;
wchar_t * buffer = 0;
HANDLE hData = GetClipboardData( CF_UNICODETEXT );
buffer = (wchar_t*)GlobalLock( hData );
GlobalUnlock( hData );
ClipboardBuffer = "";
HANDLE hData = GetClipboardData(CF_UNICODETEXT);
if (hData)
{
wchar_t* wbuffer = (wchar_t*)GlobalLock(hData);
if (wbuffer)
{
// Convert UTF-16 clipboard data to UTF-8 and store in member buffer
// so the returned pointer remains valid after CloseClipboard()
int len = WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, NULL, 0, NULL, NULL);
if (len > 0)
{
c8* tmp = new c8[len];
WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, tmp, len, NULL, NULL);
ClipboardBuffer = tmp;
delete[] tmp;
}
GlobalUnlock(hData);
}
}
CloseClipboard();
return buffer;
return ClipboardBuffer.c_str();
#elif defined(_IRR_COMPILE_WITH_OSX_DEVICE_)
return (OSXCopyFromClipboard());
#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_)
if ( IrrDeviceLinux )
{
const c8 * p = IrrDeviceLinux->getTextFromClipboard();
char* oldLocale = setlocale(LC_CTYPE, NULL);
setlocale(LC_CTYPE, "");
wchar_t* ws = core::toWideChar(p);
setlocale(LC_CTYPE, oldLocale);
return ws;
}
return IrrDeviceLinux->getTextFromClipboard();
return 0;
#else
......
......@@ -27,11 +27,11 @@ public:
virtual const core::stringc& getOperatingSystemVersion() const;
//! copies text to the clipboard
virtual void copyToClipboard(const c16* text) const;
virtual void copyToClipboard(const c8* text) const;
//! gets text from the clipboard
//! \return Returns 0 if no string is in there.
virtual const c16* getTextFromClipboard() const;
virtual const c8* getTextFromClipboard() const;
//! gets the processor speed in megahertz
//! \param Mhz:
......@@ -47,6 +47,9 @@ public:
private:
core::stringc OperatingSystem;
#ifdef _IRR_WINDOWS_API_
mutable core::stringc ClipboardBuffer;
#endif
#if defined(_IRR_COMPILE_WITH_X11_DEVICE_)
CIrrDeviceLinux * IrrDeviceLinux;
......
......@@ -7,8 +7,8 @@
extern "C" {
#endif
void OSXCopyToClipboard(const wchar_t *text);
wchar_t* OSXCopyFromClipboard();
void OSXCopyToClipboard(const char *text);
const char* OSXCopyFromClipboard();
#ifdef __cplusplus
}
......
......@@ -7,31 +7,32 @@
#include "OSXClipboard.h"
#import <Cocoa/Cocoa.h>
void OSXCopyToClipboard(const wchar_t *text)
void OSXCopyToClipboard(const char *text)
{
NSString *str;
NSPasteboard *board;
if ((text != NULL) && (wcslen(text) > 0))
if (text != NULL && strlen(text) > 0)
{
NSString* str = [NSString stringWithUTF8String:text];
if (str)
{
str = [[NSString alloc] initWithBytes:text length:wcslen(text)*sizeof(*text) encoding:NSUTF32LittleEndianStringEncoding];
board = [NSPasteboard generalPasteboard];
[board declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:NSApp];
[board setString:str forType:NSStringPboardType];
NSPasteboard* board = [NSPasteboard generalPasteboard];
[board declareTypes:@[NSPasteboardTypeString] owner:NSApp];
[board setString:str forType:NSPasteboardTypeString];
}
}
}
wchar_t* OSXCopyFromClipboard()
const char* OSXCopyFromClipboard()
{
NSString* str;
NSPasteboard* board;
wchar_t* result;
result = NULL;
board = [NSPasteboard generalPasteboard];
str = [board stringForType:NSStringPboardType];
if (str != nil)
result = (wchar_t*)[str cStringUsingEncoding:NSUTF32LittleEndianStringEncoding];
return (result);
static irr::core::stringc buffer;
NSPasteboard* board = [NSPasteboard generalPasteboard];
NSString* str = [board stringForType:NSPasteboardTypeString];
if (str == nil)
{
buffer = "";
return buffer.c_str();
}
const char* utf8 = [str UTF8String];
buffer = utf8 ? utf8 : "";
return buffer.c_str();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment