unicode clipboard changes for win32 plus some bug fixes.
This commit is contained in:
parent
b1163aa593
commit
8ada1e8a72
|
@ -160,8 +160,8 @@ CUnicode::UTF8ToUTF16(const CString& src, bool* errors)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
c -= 0x00010000;
|
c -= 0x00010000;
|
||||||
UInt16 utf16h = static_cast<UInt16>(c >> 10) + 0xd800;
|
UInt16 utf16h = static_cast<UInt16>((c >> 10) + 0xd800);
|
||||||
UInt16 utf16l = (static_cast<UInt16>(c) & 0x03ff) + 0xdc00;
|
UInt16 utf16l = static_cast<UInt16>((c & 0x03ff) + 0xdc00);
|
||||||
dst.append(reinterpret_cast<const char*>(&utf16h), 2);
|
dst.append(reinterpret_cast<const char*>(&utf16h), 2);
|
||||||
dst.append(reinterpret_cast<const char*>(&utf16l), 2);
|
dst.append(reinterpret_cast<const char*>(&utf16l), 2);
|
||||||
}
|
}
|
||||||
|
@ -206,14 +206,16 @@ CUnicode::UTF8ToText(const CString& src, bool* errors)
|
||||||
resetError(errors);
|
resetError(errors);
|
||||||
|
|
||||||
// convert to wide char
|
// convert to wide char
|
||||||
wchar_t* tmp = UTF8ToWideChar(src, errors);
|
UInt32 size;
|
||||||
|
wchar_t* tmp = UTF8ToWideChar(src, size, errors);
|
||||||
|
|
||||||
// get length of multibyte string
|
// get length of multibyte string
|
||||||
size_t len = 0;
|
|
||||||
char mbc[MB_LEN_MAX];
|
char mbc[MB_LEN_MAX];
|
||||||
mbstate_t state;
|
mbstate_t state;
|
||||||
memset(&state, 0, sizeof(state));
|
memset(&state, 0, sizeof(state));
|
||||||
for (const wchar_t* scan = tmp; *scan != 0; ++scan) {
|
size_t len = 0;
|
||||||
|
UInt32 n = size;
|
||||||
|
for (const wchar_t* scan = tmp; n > 0; ++scan, --n) {
|
||||||
size_t mblen = wcrtomb(mbc, *scan, &state);
|
size_t mblen = wcrtomb(mbc, *scan, &state);
|
||||||
if (mblen == -1) {
|
if (mblen == -1) {
|
||||||
// unconvertable character
|
// unconvertable character
|
||||||
|
@ -237,7 +239,8 @@ CUnicode::UTF8ToText(const CString& src, bool* errors)
|
||||||
|
|
||||||
// convert to multibyte
|
// convert to multibyte
|
||||||
char* dst = mbs;
|
char* dst = mbs;
|
||||||
for (const wchar_t* scan = tmp; *scan != 0; ++scan) {
|
n = size;
|
||||||
|
for (const wchar_t* scan = tmp; n > 0; ++scan, --n) {
|
||||||
size_t mblen = wcrtomb(dst, *scan, &state);
|
size_t mblen = wcrtomb(dst, *scan, &state);
|
||||||
if (mblen == -1) {
|
if (mblen == -1) {
|
||||||
// unconvertable character
|
// unconvertable character
|
||||||
|
@ -312,7 +315,7 @@ CUnicode::textToUTF8(const CString& src, bool* errors)
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
mbstate_t state;
|
mbstate_t state;
|
||||||
memset(&state, 0, sizeof(state));
|
memset(&state, 0, sizeof(state));
|
||||||
for (const char* scan = src.c_str(); n > 0 && *scan != 0; ) {
|
for (const char* scan = src.c_str(); n > 0; ) {
|
||||||
size_t mblen = mbrtowc(NULL, scan, n, &state);
|
size_t mblen = mbrtowc(NULL, scan, n, &state);
|
||||||
switch (mblen) {
|
switch (mblen) {
|
||||||
case (size_t)-2:
|
case (size_t)-2:
|
||||||
|
@ -331,6 +334,12 @@ CUnicode::textToUTF8(const CString& src, bool* errors)
|
||||||
n -= 1;
|
n -= 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
len += 1;
|
||||||
|
scan += 1;
|
||||||
|
n -= 1;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// normal character
|
// normal character
|
||||||
len += 1;
|
len += 1;
|
||||||
|
@ -342,12 +351,12 @@ CUnicode::textToUTF8(const CString& src, bool* errors)
|
||||||
memset(&state, 0, sizeof(state));
|
memset(&state, 0, sizeof(state));
|
||||||
|
|
||||||
// allocate wide character string
|
// allocate wide character string
|
||||||
wchar_t* wcs = new wchar_t[len + 1];
|
wchar_t* wcs = new wchar_t[len];
|
||||||
|
|
||||||
// convert multibyte to wide char
|
// convert multibyte to wide char
|
||||||
n = src.size();
|
n = src.size();
|
||||||
wchar_t* dst = wcs;
|
wchar_t* dst = wcs;
|
||||||
for (const char* scan = src.c_str(); n > 0 && *scan != 0; ++dst) {
|
for (const char* scan = src.c_str(); n > 0; ++dst) {
|
||||||
size_t mblen = mbrtowc(dst, scan, n, &state);
|
size_t mblen = mbrtowc(dst, scan, n, &state);
|
||||||
switch (mblen) {
|
switch (mblen) {
|
||||||
case (size_t)-2:
|
case (size_t)-2:
|
||||||
|
@ -359,9 +368,15 @@ CUnicode::textToUTF8(const CString& src, bool* errors)
|
||||||
case (size_t)-1:
|
case (size_t)-1:
|
||||||
// invalid character. count one unknown character and
|
// invalid character. count one unknown character and
|
||||||
// start at the next byte.
|
// start at the next byte.
|
||||||
|
*dst = (wchar_t)0xfffd;
|
||||||
|
scan += 1;
|
||||||
|
n -= 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
*dst = (wchar_t)0x0000;
|
||||||
scan += 1;
|
scan += 1;
|
||||||
n -= 1;
|
n -= 1;
|
||||||
*dst = (wchar_t)0xfffd;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -371,10 +386,9 @@ CUnicode::textToUTF8(const CString& src, bool* errors)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*dst = L'\0';
|
|
||||||
|
|
||||||
// convert to UTF8
|
// convert to UTF8
|
||||||
CString utf8 = wideCharToUTF8(wcs, errors);
|
CString utf8 = wideCharToUTF8(wcs, len, errors);
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
delete[] wcs;
|
delete[] wcs;
|
||||||
|
@ -383,17 +397,17 @@ CUnicode::textToUTF8(const CString& src, bool* errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
wchar_t*
|
wchar_t*
|
||||||
CUnicode::UTF8ToWideChar(const CString& src, bool* errors)
|
CUnicode::UTF8ToWideChar(const CString& src, UInt32& size, bool* errors)
|
||||||
{
|
{
|
||||||
// convert to platform's wide character encoding.
|
// convert to platform's wide character encoding.
|
||||||
// note -- this must include a wide nul character (independent of
|
// note -- this must include a wide nul character (independent of
|
||||||
// the CString's nul character).
|
// the CString's nul character).
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
CString tmp = UTF8ToUCS16(src);
|
CString tmp = UTF8ToUTF16(src, errors);
|
||||||
UInt32 size = tmp.size() >> 1;
|
size = tmp.size() >> 1;
|
||||||
#elif UNIX_LIKE
|
#elif UNIX_LIKE
|
||||||
CString tmp = UTF8ToUCS4(src);
|
CString tmp = UTF8ToUCS4(src, errors);
|
||||||
UInt32 size = tmp.size() >> 2;
|
size = tmp.size() >> 2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// copy to a wchar_t array
|
// copy to a wchar_t array
|
||||||
|
@ -403,17 +417,15 @@ CUnicode::UTF8ToWideChar(const CString& src, bool* errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
CString
|
CString
|
||||||
CUnicode::wideCharToUTF8(const wchar_t* src, bool* errors)
|
CUnicode::wideCharToUTF8(const wchar_t* src, UInt32 size, bool* errors)
|
||||||
{
|
{
|
||||||
// convert from platform's wide character encoding.
|
// convert from platform's wide character encoding.
|
||||||
// note -- this must include a wide nul character (independent of
|
// note -- this must include a wide nul character (independent of
|
||||||
// the CString's nul character).
|
// the CString's nul character).
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
return doUCS16ToUTF8(reinterpret_cast<const UInt8*>(src),
|
return doUTF16ToUTF8(reinterpret_cast<const UInt8*>(src), size, errors);
|
||||||
wcslen(src), errors);
|
|
||||||
#elif UNIX_LIKE
|
#elif UNIX_LIKE
|
||||||
return doUCS4ToUTF8(reinterpret_cast<const UInt8*>(src),
|
return doUCS4ToUTF8(reinterpret_cast<const UInt8*>(src), size, errors);
|
||||||
wcslen(src), errors);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,12 +558,10 @@ CUnicode::fromUTF8(const UInt8*& data, UInt32& n)
|
||||||
size = 1;
|
size = 1;
|
||||||
}
|
}
|
||||||
else if (data[0] < 0xc0) {
|
else if (data[0] < 0xc0) {
|
||||||
// 10xxxxxx -- in the middle of a multibyte character. skip
|
// 10xxxxxx -- in the middle of a multibyte character. counts
|
||||||
// until we find a start byte and return error.
|
// as one invalid character.
|
||||||
do {
|
--n;
|
||||||
--n;
|
++data;
|
||||||
++data;
|
|
||||||
} while (n > 0 && (data[0] & 0xc0) == 0x80);
|
|
||||||
return s_invalid;
|
return s_invalid;
|
||||||
}
|
}
|
||||||
else if (data[0] < 0xe0) {
|
else if (data[0] < 0xe0) {
|
||||||
|
@ -632,6 +642,7 @@ CUnicode::fromUTF8(const UInt8*& data, UInt32& n)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(0 && "invalid size");
|
assert(0 && "invalid size");
|
||||||
|
return s_invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that all bytes after the first have the pattern 10xxxxxx.
|
// check that all bytes after the first have the pattern 10xxxxxx.
|
||||||
|
@ -724,38 +735,38 @@ CUnicode::toUTF8(CString& dst, UInt32 c, bool* errors)
|
||||||
dst.append(reinterpret_cast<char*>(data), 1);
|
dst.append(reinterpret_cast<char*>(data), 1);
|
||||||
}
|
}
|
||||||
else if (c < 0x00000800) {
|
else if (c < 0x00000800) {
|
||||||
data[0] = static_cast<UInt8>((c >> 6) & 0x0000001f) + 0xc0;
|
data[0] = static_cast<UInt8>(((c >> 6) & 0x0000001f) + 0xc0);
|
||||||
data[1] = static_cast<UInt8>(c & 0x0000003f) + 0x80;
|
data[1] = static_cast<UInt8>((c & 0x0000003f) + 0x80);
|
||||||
dst.append(reinterpret_cast<char*>(data), 2);
|
dst.append(reinterpret_cast<char*>(data), 2);
|
||||||
}
|
}
|
||||||
else if (c < 0x00010000) {
|
else if (c < 0x00010000) {
|
||||||
data[0] = static_cast<UInt8>((c >> 12) & 0x0000000f) + 0xe0;
|
data[0] = static_cast<UInt8>(((c >> 12) & 0x0000000f) + 0xe0);
|
||||||
data[1] = static_cast<UInt8>((c >> 6) & 0x0000003f) + 0x80;
|
data[1] = static_cast<UInt8>(((c >> 6) & 0x0000003f) + 0x80);
|
||||||
data[2] = static_cast<UInt8>(c & 0x0000003f) + 0x80;
|
data[2] = static_cast<UInt8>((c & 0x0000003f) + 0x80);
|
||||||
dst.append(reinterpret_cast<char*>(data), 3);
|
dst.append(reinterpret_cast<char*>(data), 3);
|
||||||
}
|
}
|
||||||
else if (c < 0x00200000) {
|
else if (c < 0x00200000) {
|
||||||
data[0] = static_cast<UInt8>((c >> 18) & 0x00000007) + 0xf0;
|
data[0] = static_cast<UInt8>(((c >> 18) & 0x00000007) + 0xf0);
|
||||||
data[1] = static_cast<UInt8>((c >> 12) & 0x0000003f) + 0x80;
|
data[1] = static_cast<UInt8>(((c >> 12) & 0x0000003f) + 0x80);
|
||||||
data[2] = static_cast<UInt8>((c >> 6) & 0x0000003f) + 0x80;
|
data[2] = static_cast<UInt8>(((c >> 6) & 0x0000003f) + 0x80);
|
||||||
data[3] = static_cast<UInt8>(c & 0x0000003f) + 0x80;
|
data[3] = static_cast<UInt8>((c & 0x0000003f) + 0x80);
|
||||||
dst.append(reinterpret_cast<char*>(data), 4);
|
dst.append(reinterpret_cast<char*>(data), 4);
|
||||||
}
|
}
|
||||||
else if (c < 0x04000000) {
|
else if (c < 0x04000000) {
|
||||||
data[0] = static_cast<UInt8>((c >> 24) & 0x00000003) + 0xf8;
|
data[0] = static_cast<UInt8>(((c >> 24) & 0x00000003) + 0xf8);
|
||||||
data[1] = static_cast<UInt8>((c >> 18) & 0x0000003f) + 0x80;
|
data[1] = static_cast<UInt8>(((c >> 18) & 0x0000003f) + 0x80);
|
||||||
data[2] = static_cast<UInt8>((c >> 12) & 0x0000003f) + 0x80;
|
data[2] = static_cast<UInt8>(((c >> 12) & 0x0000003f) + 0x80);
|
||||||
data[3] = static_cast<UInt8>((c >> 6) & 0x0000003f) + 0x80;
|
data[3] = static_cast<UInt8>(((c >> 6) & 0x0000003f) + 0x80);
|
||||||
data[4] = static_cast<UInt8>(c & 0x0000003f) + 0x80;
|
data[4] = static_cast<UInt8>((c & 0x0000003f) + 0x80);
|
||||||
dst.append(reinterpret_cast<char*>(data), 5);
|
dst.append(reinterpret_cast<char*>(data), 5);
|
||||||
}
|
}
|
||||||
else if (c < 0x80000000) {
|
else if (c < 0x80000000) {
|
||||||
data[0] = static_cast<UInt8>((c >> 30) & 0x00000001) + 0xfc;
|
data[0] = static_cast<UInt8>(((c >> 30) & 0x00000001) + 0xfc);
|
||||||
data[1] = static_cast<UInt8>((c >> 24) & 0x0000003f) + 0x80;
|
data[1] = static_cast<UInt8>(((c >> 24) & 0x0000003f) + 0x80);
|
||||||
data[2] = static_cast<UInt8>((c >> 18) & 0x0000003f) + 0x80;
|
data[2] = static_cast<UInt8>(((c >> 18) & 0x0000003f) + 0x80);
|
||||||
data[3] = static_cast<UInt8>((c >> 12) & 0x0000003f) + 0x80;
|
data[3] = static_cast<UInt8>(((c >> 12) & 0x0000003f) + 0x80);
|
||||||
data[4] = static_cast<UInt8>((c >> 6) & 0x0000003f) + 0x80;
|
data[4] = static_cast<UInt8>(((c >> 6) & 0x0000003f) + 0x80);
|
||||||
data[5] = static_cast<UInt8>(c & 0x0000003f) + 0x80;
|
data[5] = static_cast<UInt8>((c & 0x0000003f) + 0x80);
|
||||||
dst.append(reinterpret_cast<char*>(data), 6);
|
dst.append(reinterpret_cast<char*>(data), 6);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -15,7 +15,9 @@ public:
|
||||||
// not NULL then it gets true if any characters could not be
|
// not NULL then it gets true if any characters could not be
|
||||||
// encoded in the target encoding and false otherwise. note
|
// encoded in the target encoding and false otherwise. note
|
||||||
// that decoding errors do not set errors to error. UTF8ToText()
|
// that decoding errors do not set errors to error. UTF8ToText()
|
||||||
// converts to the current locale's (multibyte) encoding.
|
// converts to the current locale's (multibyte) encoding. all of
|
||||||
|
// these methods include the nul terminator in the returned
|
||||||
|
// string (independent of the CString's own nul terminator).
|
||||||
static CString UTF8ToUCS2(const CString&, bool* errors = NULL);
|
static CString UTF8ToUCS2(const CString&, bool* errors = NULL);
|
||||||
static CString UTF8ToUCS4(const CString&, bool* errors = NULL);
|
static CString UTF8ToUCS4(const CString&, bool* errors = NULL);
|
||||||
static CString UTF8ToUTF16(const CString&, bool* errors = NULL);
|
static CString UTF8ToUTF16(const CString&, bool* errors = NULL);
|
||||||
|
@ -25,7 +27,9 @@ public:
|
||||||
// convert from some encoding to UTF-8. if errors is not NULL
|
// convert from some encoding to UTF-8. if errors is not NULL
|
||||||
// then it gets true if any characters could not be decoded and
|
// then it gets true if any characters could not be decoded and
|
||||||
// false otherwise. textToUTF8() converts from the current
|
// false otherwise. textToUTF8() converts from the current
|
||||||
// locale's (multibyte) encoding.
|
// locale's (multibyte) encoding. all of these methods strip
|
||||||
|
// a terminating nul so the returned UTF-8 string uses the
|
||||||
|
// CString's own nul terminator for termination.
|
||||||
static CString UCS2ToUTF8(const CString&, bool* errors = NULL);
|
static CString UCS2ToUTF8(const CString&, bool* errors = NULL);
|
||||||
static CString UCS4ToUTF8(const CString&, bool* errors = NULL);
|
static CString UCS4ToUTF8(const CString&, bool* errors = NULL);
|
||||||
static CString UTF16ToUTF8(const CString&, bool* errors = NULL);
|
static CString UTF16ToUTF8(const CString&, bool* errors = NULL);
|
||||||
|
@ -36,11 +40,13 @@ private:
|
||||||
// convert UTF8 to nul terminated wchar_t string (using whatever
|
// convert UTF8 to nul terminated wchar_t string (using whatever
|
||||||
// encoding is native to the platform). caller must delete[]
|
// encoding is native to the platform). caller must delete[]
|
||||||
// the returned string.
|
// the returned string.
|
||||||
static wchar_t* UTF8ToWideChar(const CString&, bool* errors);
|
static wchar_t* UTF8ToWideChar(const CString&,
|
||||||
|
UInt32& size, bool* errors);
|
||||||
|
|
||||||
// convert nul terminated wchar_t string (in platform's native
|
// convert nul terminated wchar_t string (in platform's native
|
||||||
// encoding) to UTF8.
|
// encoding) to UTF8.
|
||||||
static CString wideCharToUTF8(const wchar_t*, bool* errors);
|
static CString wideCharToUTF8(const wchar_t*,
|
||||||
|
UInt32 size, bool* errors);
|
||||||
|
|
||||||
// internal conversion to UTF8
|
// internal conversion to UTF8
|
||||||
static CString doUCS2ToUTF8(const UInt8* src, UInt32 n, bool* errors);
|
static CString doUCS2ToUTF8(const UInt8* src, UInt32 n, bool* errors);
|
||||||
|
|
|
@ -103,6 +103,10 @@ SOURCE=.\CString.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CUnicode.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\XBase.cpp
|
SOURCE=.\XBase.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# End Group
|
# End Group
|
||||||
|
@ -135,6 +139,10 @@ SOURCE=.\CString.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CUnicode.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\IInterface.h
|
SOURCE=.\IInterface.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#include "CMSWindowsClipboard.h"
|
#include "CMSWindowsClipboard.h"
|
||||||
|
#include "CMSWindowsClipboardTextConverter.h"
|
||||||
|
#include "CMSWindowsClipboardUTF16Converter.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -9,12 +11,14 @@ CMSWindowsClipboard::CMSWindowsClipboard(HWND window) :
|
||||||
m_window(window),
|
m_window(window),
|
||||||
m_time(0)
|
m_time(0)
|
||||||
{
|
{
|
||||||
// do nothing
|
// add converters, most desired first
|
||||||
|
m_converters.push_back(new CMSWindowsClipboardUTF16Converter);
|
||||||
|
m_converters.push_back(new CMSWindowsClipboardTextConverter);
|
||||||
}
|
}
|
||||||
|
|
||||||
CMSWindowsClipboard::~CMSWindowsClipboard()
|
CMSWindowsClipboard::~CMSWindowsClipboard()
|
||||||
{
|
{
|
||||||
// do nothing
|
clearConverters();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -35,22 +39,23 @@ CMSWindowsClipboard::add(EFormat format, const CString& data)
|
||||||
{
|
{
|
||||||
log((CLOG_DEBUG "add %d bytes to clipboard format: %d", data.size(), format));
|
log((CLOG_DEBUG "add %d bytes to clipboard format: %d", data.size(), format));
|
||||||
|
|
||||||
// convert data to win32 required form
|
// convert data to win32 form
|
||||||
const UINT win32Format = convertFormatToWin32(format);
|
for (ConverterList::const_iterator index = m_converters.begin();
|
||||||
HANDLE win32Data;
|
index != m_converters.end(); ++index) {
|
||||||
switch (win32Format) {
|
IMSWindowsClipboardConverter* converter = *index;
|
||||||
case CF_TEXT:
|
|
||||||
win32Data = convertTextToWin32(data);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
// skip converters for other formats
|
||||||
win32Data = NULL;
|
if (converter->getFormat() == format) {
|
||||||
break;
|
HANDLE win32Data = converter->fromIClipboard(data);
|
||||||
}
|
if (win32Data != NULL) {
|
||||||
|
UINT win32Format = converter->getWin32Format();
|
||||||
// put the data on the clipboard
|
if (SetClipboardData(win32Format, win32Data) == NULL) {
|
||||||
if (win32Data != NULL) {
|
// free converted data if we couldn't put it on
|
||||||
SetClipboardData(win32Format, win32Data);
|
// the clipboard
|
||||||
|
GlobalFree(win32Data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,124 +90,58 @@ CMSWindowsClipboard::getTime() const
|
||||||
bool
|
bool
|
||||||
CMSWindowsClipboard::has(EFormat format) const
|
CMSWindowsClipboard::has(EFormat format) const
|
||||||
{
|
{
|
||||||
const UINT win32Format = convertFormatToWin32(format);
|
for (ConverterList::const_iterator index = m_converters.begin();
|
||||||
return (win32Format != 0 && IsClipboardFormatAvailable(win32Format) != 0);
|
index != m_converters.end(); ++index) {
|
||||||
|
IMSWindowsClipboardConverter* converter = *index;
|
||||||
|
if (converter->getFormat() == format) {
|
||||||
|
if (IsClipboardFormatAvailable(converter->getWin32Format())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CString
|
CString
|
||||||
CMSWindowsClipboard::get(EFormat format) const
|
CMSWindowsClipboard::get(EFormat format) const
|
||||||
{
|
{
|
||||||
// get the win32 format. return empty data if unknown format.
|
// find the converter for the first clipboard format we can handle
|
||||||
const UINT win32Format = convertFormatToWin32(format);
|
IMSWindowsClipboardConverter* converter = NULL;
|
||||||
if (win32Format == 0) {
|
UINT win32Format = EnumClipboardFormats(0);
|
||||||
|
while (win32Format != 0) {
|
||||||
|
for (ConverterList::const_iterator index = m_converters.begin();
|
||||||
|
index != m_converters.end(); ++index) {
|
||||||
|
converter = *index;
|
||||||
|
if (converter->getWin32Format() == win32Format &&
|
||||||
|
converter->getFormat() == format) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
converter = NULL;
|
||||||
|
}
|
||||||
|
win32Format = EnumClipboardFormats(win32Format);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no converter then we don't recognize any formats
|
||||||
|
if (converter == NULL) {
|
||||||
return CString();
|
return CString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// get a handle to the clipboard data and convert it
|
// get a handle to the clipboard data
|
||||||
HANDLE win32Data = GetClipboardData(win32Format);
|
HANDLE win32Data = GetClipboardData(converter->getWin32Format());
|
||||||
CString data;
|
if (win32Data == NULL) {
|
||||||
if (win32Data != NULL) {
|
|
||||||
// convert the data
|
|
||||||
switch (win32Format) {
|
|
||||||
case CF_TEXT:
|
|
||||||
data = convertTextFromWin32(win32Data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT
|
|
||||||
CMSWindowsClipboard::convertFormatToWin32(EFormat format) const
|
|
||||||
{
|
|
||||||
switch (format) {
|
|
||||||
case kText:
|
|
||||||
return CF_TEXT;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HANDLE
|
|
||||||
CMSWindowsClipboard::convertTextToWin32(const CString& data) const
|
|
||||||
{
|
|
||||||
// compute size of converted text
|
|
||||||
UInt32 dstSize = 1;
|
|
||||||
const UInt32 srcSize = data.size();
|
|
||||||
const char* src = data.c_str();
|
|
||||||
for (UInt32 index = 0; index < srcSize; ++index) {
|
|
||||||
if (src[index] == '\n') {
|
|
||||||
// add \r
|
|
||||||
++dstSize;
|
|
||||||
}
|
|
||||||
++dstSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// allocate
|
|
||||||
HGLOBAL gData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, dstSize);
|
|
||||||
if (gData != NULL) {
|
|
||||||
// get a pointer to the allocated memory
|
|
||||||
char* dst = (char*)GlobalLock(gData);
|
|
||||||
if (dst != NULL) {
|
|
||||||
// convert text. we change LF to CRLF.
|
|
||||||
dstSize = 0;
|
|
||||||
for (UInt32 index = 0; index < srcSize; ++index) {
|
|
||||||
if (src[index] == '\n') {
|
|
||||||
// add \r
|
|
||||||
dst[dstSize++] = '\r';
|
|
||||||
}
|
|
||||||
dst[dstSize++] = src[index];
|
|
||||||
}
|
|
||||||
dst[dstSize] = '\0';
|
|
||||||
|
|
||||||
// done converting
|
|
||||||
GlobalUnlock(gData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return gData;
|
|
||||||
}
|
|
||||||
|
|
||||||
CString
|
|
||||||
CMSWindowsClipboard::convertTextFromWin32(HANDLE handle) const
|
|
||||||
{
|
|
||||||
// get source data and it's size
|
|
||||||
const char* src = (const char*)GlobalLock(handle);
|
|
||||||
UInt32 srcSize = (SInt32)GlobalSize(handle);
|
|
||||||
if (src == NULL || srcSize <= 1) {
|
|
||||||
return CString();
|
return CString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore trailing NUL
|
// convert
|
||||||
--srcSize;
|
return converter->toIClipboard(win32Data);
|
||||||
|
}
|
||||||
// compute size of converted text
|
|
||||||
UInt32 dstSize = 0;
|
void
|
||||||
UInt32 index;
|
CMSWindowsClipboard::clearConverters()
|
||||||
for (index = 0; index < srcSize; ++index) {
|
{
|
||||||
if (src[index] == '\r') {
|
for (ConverterList::iterator index = m_converters.begin();
|
||||||
// skip \r
|
index != m_converters.end(); ++index) {
|
||||||
if (index + 1 < srcSize && src[index + 1] == '\n') {
|
delete *index;
|
||||||
++index;
|
}
|
||||||
}
|
m_converters.clear();
|
||||||
}
|
|
||||||
++dstSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// allocate
|
|
||||||
CString data;
|
|
||||||
data.reserve(dstSize);
|
|
||||||
|
|
||||||
// convert text. we change CRLF to LF.
|
|
||||||
for (index = 0; index < srcSize; ++index) {
|
|
||||||
if (src[index] == '\r') {
|
|
||||||
// skip \r
|
|
||||||
if (index + 1 < srcSize && src[index + 1] == '\n') {
|
|
||||||
++index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data += src[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,12 @@
|
||||||
#define CMSWINDOWSCLIPBOARD_H
|
#define CMSWINDOWSCLIPBOARD_H
|
||||||
|
|
||||||
#include "IClipboard.h"
|
#include "IClipboard.h"
|
||||||
|
#include "stdvector.h"
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
class IMSWindowsClipboardConverter;
|
||||||
|
|
||||||
class CMSWindowsClipboard : public IClipboard {
|
class CMSWindowsClipboard : public IClipboard {
|
||||||
public:
|
public:
|
||||||
CMSWindowsClipboard(HWND window);
|
CMSWindowsClipboard(HWND window);
|
||||||
|
@ -20,13 +23,41 @@ public:
|
||||||
virtual CString get(EFormat) const;
|
virtual CString get(EFormat) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void clearConverters();
|
||||||
|
|
||||||
UINT convertFormatToWin32(EFormat) const;
|
UINT convertFormatToWin32(EFormat) const;
|
||||||
HANDLE convertTextToWin32(const CString& data) const;
|
HANDLE convertTextToWin32(const CString& data) const;
|
||||||
CString convertTextFromWin32(HANDLE) const;
|
CString convertTextFromWin32(HANDLE) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
typedef std::vector<IMSWindowsClipboardConverter*> ConverterList;
|
||||||
|
|
||||||
HWND m_window;
|
HWND m_window;
|
||||||
mutable Time m_time;
|
mutable Time m_time;
|
||||||
|
ConverterList m_converters;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IMSWindowsClipboardConverter : public IInterface {
|
||||||
|
public:
|
||||||
|
// accessors
|
||||||
|
|
||||||
|
// return the clipboard format this object converts from/to
|
||||||
|
virtual IClipboard::EFormat
|
||||||
|
getFormat() const = 0;
|
||||||
|
|
||||||
|
// return the atom representing the win32 clipboard format that
|
||||||
|
// this object converts from/to
|
||||||
|
virtual UINT getWin32Format() const = 0;
|
||||||
|
|
||||||
|
// convert from the IClipboard format to the win32 clipboard format.
|
||||||
|
// the input data must be in the IClipboard format returned by
|
||||||
|
// getFormat(). the return data will be in the win32 clipboard
|
||||||
|
// format returned by getWin32Format(), allocated by GlobalAlloc().
|
||||||
|
virtual HANDLE fromIClipboard(const CString&) const = 0;
|
||||||
|
|
||||||
|
// convert from the win32 clipboard format to the IClipboard format
|
||||||
|
// (i.e., the reverse of fromIClipboard()).
|
||||||
|
virtual CString toIClipboard(HANDLE data) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
#include "CMSWindowsClipboardAnyTextConverter.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CMSWindowsClipboardAnyTextConverter
|
||||||
|
//
|
||||||
|
|
||||||
|
CMSWindowsClipboardAnyTextConverter::CMSWindowsClipboardAnyTextConverter()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CMSWindowsClipboardAnyTextConverter::~CMSWindowsClipboardAnyTextConverter()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
IClipboard::EFormat
|
||||||
|
CMSWindowsClipboardAnyTextConverter::getFormat() const
|
||||||
|
{
|
||||||
|
return IClipboard::kText;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE
|
||||||
|
CMSWindowsClipboardAnyTextConverter::fromIClipboard(const CString& data) const
|
||||||
|
{
|
||||||
|
// convert linefeeds and then convert to desired encoding
|
||||||
|
CString text = doFromIClipboard(convertLinefeedToWin32(data));
|
||||||
|
UInt32 size = text.size();
|
||||||
|
|
||||||
|
// copy to memory handle
|
||||||
|
HGLOBAL gData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
|
||||||
|
if (gData != NULL) {
|
||||||
|
// get a pointer to the allocated memory
|
||||||
|
char* dst = (char*)GlobalLock(gData);
|
||||||
|
if (dst != NULL) {
|
||||||
|
memcpy(dst, text.data(), size);
|
||||||
|
GlobalUnlock(gData);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GlobalFree(gData);
|
||||||
|
gData = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return gData;
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CMSWindowsClipboardAnyTextConverter::toIClipboard(HANDLE data) const
|
||||||
|
{
|
||||||
|
// get datator
|
||||||
|
const char* src = (const char*)GlobalLock(data);
|
||||||
|
UInt32 srcSize = (UInt32)GlobalSize(data);
|
||||||
|
if (src == NULL || srcSize <= 1) {
|
||||||
|
return CString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert text
|
||||||
|
CString text = doToIClipboard(CString(src, srcSize));
|
||||||
|
|
||||||
|
// release handle
|
||||||
|
GlobalUnlock(data);
|
||||||
|
|
||||||
|
// convert newlines
|
||||||
|
return convertLinefeedToUnix(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CMSWindowsClipboardAnyTextConverter::convertLinefeedToWin32(
|
||||||
|
const CString& src) const
|
||||||
|
{
|
||||||
|
// note -- we assume src is a valid UTF-8 string
|
||||||
|
|
||||||
|
// count newlines in string
|
||||||
|
UInt32 numNewlines = 0;
|
||||||
|
UInt32 n = src.size();
|
||||||
|
for (const char* scan = src.c_str(); n > 0; ++scan, --n) {
|
||||||
|
if (*scan == '\n') {
|
||||||
|
++numNewlines;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (numNewlines == 0) {
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate new string
|
||||||
|
CString dst;
|
||||||
|
dst.reserve(src.size() + numNewlines);
|
||||||
|
|
||||||
|
// copy string, converting newlines
|
||||||
|
n = src.size();
|
||||||
|
for (const char* scan = src.c_str(); n > 0; ++scan, --n) {
|
||||||
|
if (scan[0] == '\n') {
|
||||||
|
dst += '\r';
|
||||||
|
}
|
||||||
|
dst += scan[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CMSWindowsClipboardAnyTextConverter::convertLinefeedToUnix(
|
||||||
|
const CString& src) const
|
||||||
|
{
|
||||||
|
// count newlines in string
|
||||||
|
UInt32 numNewlines = 0;
|
||||||
|
UInt32 n = src.size();
|
||||||
|
for (const char* scan = src.c_str(); n > 0; ++scan, --n) {
|
||||||
|
if (scan[0] == '\r' && scan[1] == '\n') {
|
||||||
|
++numNewlines;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (numNewlines == 0) {
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate new string
|
||||||
|
CString dst;
|
||||||
|
dst.reserve(src.size());
|
||||||
|
|
||||||
|
// copy string, converting newlines
|
||||||
|
n = src.size();
|
||||||
|
for (const char* scan = src.c_str(); n > 0; ++scan, --n) {
|
||||||
|
if (scan[0] != '\r' || scan[1] != '\n') {
|
||||||
|
dst += scan[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef CMSWINDOWSCLIPBOARDANYTEXTCONVERTER_H
|
||||||
|
#define CMSWINDOWSCLIPBOARDANYTEXTCONVERTER_H
|
||||||
|
|
||||||
|
#include "CMSWindowsClipboard.h"
|
||||||
|
|
||||||
|
class CMSWindowsClipboardAnyTextConverter :
|
||||||
|
public IMSWindowsClipboardConverter {
|
||||||
|
public:
|
||||||
|
CMSWindowsClipboardAnyTextConverter();
|
||||||
|
virtual ~CMSWindowsClipboardAnyTextConverter();
|
||||||
|
|
||||||
|
// IMSWindowsClipboardConverter overrides
|
||||||
|
virtual IClipboard::EFormat
|
||||||
|
getFormat() const;
|
||||||
|
virtual UINT getWin32Format() const = 0;
|
||||||
|
virtual HANDLE fromIClipboard(const CString&) const;
|
||||||
|
virtual CString toIClipboard(HANDLE) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// do UTF-8 conversion only. memory handle allocation and
|
||||||
|
// linefeed conversion is done by this class. doFromIClipboard()
|
||||||
|
// must include the nul terminator in the returned string (not
|
||||||
|
// including the CString's nul terminator).
|
||||||
|
virtual CString doFromIClipboard(const CString&) const = 0;
|
||||||
|
virtual CString doToIClipboard(const CString&) const = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
CString convertLinefeedToWin32(const CString&) const;
|
||||||
|
CString convertLinefeedToUnix(const CString&) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,34 @@
|
||||||
|
#include "CMSWindowsClipboardTextConverter.h"
|
||||||
|
#include "CUnicode.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CMSWindowsClipboardTextConverter
|
||||||
|
//
|
||||||
|
|
||||||
|
CMSWindowsClipboardTextConverter::CMSWindowsClipboardTextConverter()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CMSWindowsClipboardTextConverter::~CMSWindowsClipboardTextConverter()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT
|
||||||
|
CMSWindowsClipboardTextConverter::getWin32Format() const
|
||||||
|
{
|
||||||
|
return CF_TEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CMSWindowsClipboardTextConverter::doFromIClipboard(const CString& data) const
|
||||||
|
{
|
||||||
|
return CUnicode::UTF8ToText(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CMSWindowsClipboardTextConverter::doToIClipboard(const CString& data) const
|
||||||
|
{
|
||||||
|
return CUnicode::textToUTF8(data);
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef CMSWINDOWSCLIPBOARDTEXTCONVERTER_H
|
||||||
|
#define CMSWINDOWSCLIPBOARDTEXTCONVERTER_H
|
||||||
|
|
||||||
|
#include "CMSWindowsClipboardAnyTextConverter.h"
|
||||||
|
|
||||||
|
class CMSWindowsClipboardTextConverter :
|
||||||
|
public CMSWindowsClipboardAnyTextConverter {
|
||||||
|
public:
|
||||||
|
CMSWindowsClipboardTextConverter();
|
||||||
|
virtual ~CMSWindowsClipboardTextConverter();
|
||||||
|
|
||||||
|
// IMSWindowsClipboardConverter overrides
|
||||||
|
virtual UINT getWin32Format() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// CMSWindowsClipboardAnyTextConverter overrides
|
||||||
|
virtual CString doFromIClipboard(const CString&) const;
|
||||||
|
virtual CString doToIClipboard(const CString&) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,34 @@
|
||||||
|
#include "CMSWindowsClipboardUTF16Converter.h"
|
||||||
|
#include "CUnicode.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CMSWindowsClipboardUTF16Converter
|
||||||
|
//
|
||||||
|
|
||||||
|
CMSWindowsClipboardUTF16Converter::CMSWindowsClipboardUTF16Converter()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CMSWindowsClipboardUTF16Converter::~CMSWindowsClipboardUTF16Converter()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT
|
||||||
|
CMSWindowsClipboardUTF16Converter::getWin32Format() const
|
||||||
|
{
|
||||||
|
return CF_UNICODETEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CMSWindowsClipboardUTF16Converter::doFromIClipboard(const CString& data) const
|
||||||
|
{
|
||||||
|
return CUnicode::UTF8ToUTF16(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CMSWindowsClipboardUTF16Converter::doToIClipboard(const CString& data) const
|
||||||
|
{
|
||||||
|
return CUnicode::UTF16ToUTF8(data);
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef CMSWINDOWSCLIPBOARDUTF16CONVERTER_H
|
||||||
|
#define CMSWINDOWSCLIPBOARDUTF16CONVERTER_H
|
||||||
|
|
||||||
|
#include "CMSWindowsClipboardAnyTextConverter.h"
|
||||||
|
|
||||||
|
class CMSWindowsClipboardUTF16Converter :
|
||||||
|
public CMSWindowsClipboardAnyTextConverter {
|
||||||
|
public:
|
||||||
|
CMSWindowsClipboardUTF16Converter();
|
||||||
|
virtual ~CMSWindowsClipboardUTF16Converter();
|
||||||
|
|
||||||
|
// IMSWindowsClipboardConverter overrides
|
||||||
|
virtual UINT getWin32Format() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// CMSWindowsClipboardAnyTextConverter overrides
|
||||||
|
virtual CString doFromIClipboard(const CString&) const;
|
||||||
|
virtual CString doToIClipboard(const CString&) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -91,6 +91,18 @@ SOURCE=.\CMSWindowsClipboard.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CMSWindowsClipboardAnyTextConverter.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CMSWindowsClipboardTextConverter.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CMSWindowsClipboardUTF16Converter.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\CMSWindowsScreen.cpp
|
SOURCE=.\CMSWindowsScreen.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
@ -111,6 +123,18 @@ SOURCE=.\CMSWindowsClipboard.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CMSWindowsClipboardAnyTextConverter.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CMSWindowsClipboardTextConverter.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CMSWindowsClipboardUTF16Converter.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\CMSWindowsScreen.h
|
SOURCE=.\CMSWindowsScreen.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
Loading…
Reference in New Issue