mirror of
https://github.com/Jous99/F4MP.git
synced 2026-01-13 00:40:53 +01:00
254 lines
7.3 KiB
C++
254 lines
7.3 KiB
C++
// Copyright (C) 2022 TiltedPhoques SRL.
|
|
// For licensing information see LICENSE at the root of this distribution.
|
|
// Taken from
|
|
// https://github.com/xposure/ImGuiSharp/blob/58860d38a9ec066f492c983c9c63393d6e00a442/ImGuiSharp.Shared/ImGui.h/Helpers.cpp
|
|
|
|
#include "imgui.h"
|
|
#include <Windows.h>
|
|
#include <imgui/ImGuiClipboard_Win32.h>
|
|
|
|
namespace ImGuiImpl
|
|
{
|
|
namespace
|
|
{
|
|
int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
|
|
{
|
|
unsigned int c = (unsigned int)-1;
|
|
const unsigned char* str = (const unsigned char*)in_text;
|
|
if (!(*str & 0x80))
|
|
{
|
|
c = (unsigned int)(*str++);
|
|
*out_char = c;
|
|
return 1;
|
|
}
|
|
if ((*str & 0xe0) == 0xc0)
|
|
{
|
|
*out_char = 0xFFFD; // will be invalid but not end of string
|
|
if (in_text_end && in_text_end - (const char*)str < 2)
|
|
return 1;
|
|
if (*str < 0xc2)
|
|
return 2;
|
|
c = (unsigned int)((*str++ & 0x1f) << 6);
|
|
if ((*str & 0xc0) != 0x80)
|
|
return 2;
|
|
c += (*str++ & 0x3f);
|
|
*out_char = c;
|
|
return 2;
|
|
}
|
|
if ((*str & 0xf0) == 0xe0)
|
|
{
|
|
*out_char = 0xFFFD; // will be invalid but not end of string
|
|
if (in_text_end && in_text_end - (const char*)str < 3)
|
|
return 1;
|
|
if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf))
|
|
return 3;
|
|
if (*str == 0xed && str[1] > 0x9f)
|
|
return 3; // str[1] < 0x80 is checked below
|
|
c = (unsigned int)((*str++ & 0x0f) << 12);
|
|
if ((*str & 0xc0) != 0x80)
|
|
return 3;
|
|
c += (unsigned int)((*str++ & 0x3f) << 6);
|
|
if ((*str & 0xc0) != 0x80)
|
|
return 3;
|
|
c += (*str++ & 0x3f);
|
|
*out_char = c;
|
|
return 3;
|
|
}
|
|
if ((*str & 0xf8) == 0xf0)
|
|
{
|
|
*out_char = 0xFFFD; // will be invalid but not end of string
|
|
if (in_text_end && in_text_end - (const char*)str < 4)
|
|
return 1;
|
|
if (*str > 0xf4)
|
|
return 4;
|
|
if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf))
|
|
return 4;
|
|
if (*str == 0xf4 && str[1] > 0x8f)
|
|
return 4; // str[1] < 0x80 is checked below
|
|
c = (unsigned int)((*str++ & 0x07) << 18);
|
|
if ((*str & 0xc0) != 0x80)
|
|
return 4;
|
|
c += (unsigned int)((*str++ & 0x3f) << 12);
|
|
if ((*str & 0xc0) != 0x80)
|
|
return 4;
|
|
c += (unsigned int)((*str++ & 0x3f) << 6);
|
|
if ((*str & 0xc0) != 0x80)
|
|
return 4;
|
|
c += (*str++ & 0x3f);
|
|
// utf-8 encodings of values used in surrogate pairs are invalid
|
|
if ((c & 0xFFFFF800) == 0xD800)
|
|
return 4;
|
|
*out_char = c;
|
|
return 4;
|
|
}
|
|
*out_char = 0;
|
|
return 0;
|
|
}
|
|
|
|
int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)
|
|
{
|
|
ImWchar* buf_out = buf;
|
|
ImWchar* buf_end = buf + buf_size;
|
|
while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
|
|
{
|
|
unsigned int c;
|
|
in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
|
|
if (c == 0)
|
|
break;
|
|
if (c < 0x10000) // FIXME: Losing characters that don't fit in 2 bytes
|
|
*buf_out++ = (ImWchar)c;
|
|
}
|
|
*buf_out = 0;
|
|
if (in_text_remaining)
|
|
*in_text_remaining = in_text;
|
|
return (int)(buf_out - buf);
|
|
}
|
|
|
|
int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
|
|
{
|
|
int char_count = 0;
|
|
while ((!in_text_end || in_text < in_text_end) && *in_text)
|
|
{
|
|
unsigned int c;
|
|
in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
|
|
if (c == 0)
|
|
break;
|
|
if (c < 0x10000)
|
|
char_count++;
|
|
}
|
|
return char_count;
|
|
}
|
|
|
|
// Based on stb_to_utf8() from github.com/nothings/stb/
|
|
static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
|
|
{
|
|
if (c < 0x80)
|
|
{
|
|
buf[0] = (char)c;
|
|
return 1;
|
|
}
|
|
if (c < 0x800)
|
|
{
|
|
if (buf_size < 2)
|
|
return 0;
|
|
buf[0] = (char)(0xc0 + (c >> 6));
|
|
buf[1] = (char)(0x80 + (c & 0x3f));
|
|
return 2;
|
|
}
|
|
if (c >= 0xdc00 && c < 0xe000)
|
|
{
|
|
return 0;
|
|
}
|
|
if (c >= 0xd800 && c < 0xdc00)
|
|
{
|
|
if (buf_size < 4)
|
|
return 0;
|
|
buf[0] = (char)(0xf0 + (c >> 18));
|
|
buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
|
|
buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
|
|
buf[3] = (char)(0x80 + ((c)&0x3f));
|
|
return 4;
|
|
}
|
|
// else if (c < 0x10000)
|
|
{
|
|
if (buf_size < 3)
|
|
return 0;
|
|
buf[0] = (char)(0xe0 + (c >> 12));
|
|
buf[1] = (char)(0x80 + ((c >> 6) & 0x3f));
|
|
buf[2] = (char)(0x80 + ((c)&0x3f));
|
|
return 3;
|
|
}
|
|
}
|
|
|
|
static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
|
|
{
|
|
if (c < 0x80)
|
|
return 1;
|
|
if (c < 0x800)
|
|
return 2;
|
|
if (c >= 0xdc00 && c < 0xe000)
|
|
return 0;
|
|
if (c >= 0xd800 && c < 0xdc00)
|
|
return 4;
|
|
return 3;
|
|
}
|
|
|
|
int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
|
|
{
|
|
char* buf_out = buf;
|
|
const char* buf_end = buf + buf_size;
|
|
while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
|
|
{
|
|
unsigned int c = (unsigned int)(*in_text++);
|
|
if (c < 0x80)
|
|
*buf_out++ = (char)c;
|
|
else
|
|
buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end - buf_out - 1), c);
|
|
}
|
|
*buf_out = 0;
|
|
return (int)(buf_out - buf);
|
|
}
|
|
|
|
int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
|
|
{
|
|
int bytes_count = 0;
|
|
while ((!in_text_end || in_text < in_text_end) && *in_text)
|
|
{
|
|
unsigned int c = (unsigned int)(*in_text++);
|
|
if (c < 0x80)
|
|
bytes_count++;
|
|
else
|
|
bytes_count += ImTextCountUtf8BytesFromChar(c);
|
|
}
|
|
return bytes_count;
|
|
}
|
|
|
|
static const char* GetClipboardTextFn_DefaultImpl(void*)
|
|
{
|
|
static char* buf_local = NULL;
|
|
if (buf_local)
|
|
{
|
|
ImGui::MemFree(buf_local);
|
|
buf_local = NULL;
|
|
}
|
|
if (!OpenClipboard(NULL))
|
|
return NULL;
|
|
HANDLE wbuf_handle = GetClipboardData(CF_UNICODETEXT);
|
|
if (wbuf_handle == NULL)
|
|
return NULL;
|
|
if (ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle))
|
|
{
|
|
int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1;
|
|
buf_local = (char*)ImGui::MemAlloc(buf_len * sizeof(char));
|
|
ImTextStrToUtf8(buf_local, buf_len, wbuf_global, NULL);
|
|
}
|
|
GlobalUnlock(wbuf_handle);
|
|
CloseClipboard();
|
|
return buf_local;
|
|
}
|
|
|
|
static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
|
|
{
|
|
if (!OpenClipboard(NULL))
|
|
return;
|
|
|
|
const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1;
|
|
HGLOBAL wbuf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar));
|
|
if (wbuf_handle == NULL)
|
|
return;
|
|
ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle);
|
|
ImTextStrFromUtf8(wbuf_global, wbuf_length, text, NULL, NULL);
|
|
GlobalUnlock(wbuf_handle);
|
|
EmptyClipboard();
|
|
SetClipboardData(CF_UNICODETEXT, wbuf_handle);
|
|
CloseClipboard();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void InstallClipboardHandlers(ImGuiIO& aIO)
|
|
{
|
|
aIO.SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
|
|
aIO.GetClipboardTextFn = GetClipboardTextFn_DefaultImpl;
|
|
}
|
|
} // namespace ImGuiImpl
|