ImGuiManager: Plumb through clipboard access

This commit is contained in:
Stenzek 2024-11-20 12:43:20 +10:00
parent b726fa8918
commit b59f9a1270
No known key found for this signature in database
4 changed files with 81 additions and 15 deletions

View File

@ -1909,6 +1909,18 @@ void Host::OpenURL(std::string_view url)
QtHost::RunOnUIThread([url = QtUtils::StringViewToQString(url)]() { QtUtils::OpenURL(g_main_window, QUrl(url)); }); QtHost::RunOnUIThread([url = QtUtils::StringViewToQString(url)]() { QtUtils::OpenURL(g_main_window, QUrl(url)); });
} }
std::string Host::GetClipboardText()
{
// Hope this doesn't deadlock...
std::string ret;
QtHost::RunOnUIThread([&ret]() {
QClipboard* clipboard = QGuiApplication::clipboard();
if (clipboard)
ret = clipboard->text().toStdString();
}, true);
return ret;
}
bool Host::CopyTextToClipboard(std::string_view text) bool Host::CopyTextToClipboard(std::string_view text)
{ {
QtHost::RunOnUIThread([text = QtUtils::StringViewToQString(text)]() { QtHost::RunOnUIThread([text = QtUtils::StringViewToQString(text)]() {

View File

@ -380,6 +380,11 @@ void Host::OpenURL(std::string_view url)
// //
} }
std::string Host::GetClipboardText()
{
return std::string();
}
bool Host::CopyTextToClipboard(std::string_view text) bool Host::CopyTextToClipboard(std::string_view text)
{ {
return false; return false;

View File

@ -50,7 +50,10 @@ std::string GetHTTPUserAgent();
/// Opens a URL, using the default application. /// Opens a URL, using the default application.
void OpenURL(std::string_view url); void OpenURL(std::string_view url);
/// Copies the provided text to the host's clipboard, if present. /// Returns the current contents of the clipboard as UTF-8 text, if any.
std::string GetClipboardText();
/// Copies the provided UTF-8 text to the host's clipboard, if present.
bool CopyTextToClipboard(std::string_view text); bool CopyTextToClipboard(std::string_view text);
/// Returns a localized version of the specified string within the specified context. /// Returns a localized version of the specified string within the specified context.

View File

@ -75,6 +75,10 @@ static bool AddImGuiFonts(bool fullscreen_fonts);
static ImFont* AddTextFont(float size, bool full_glyph_range); static ImFont* AddTextFont(float size, bool full_glyph_range);
static ImFont* AddFixedFont(float size); static ImFont* AddFixedFont(float size);
static bool AddIconFonts(float size); static bool AddIconFonts(float size);
static void SetCommonIOOptions(ImGuiIO& io);
static void SetImKeyState(ImGuiIO& io, u32 key, bool pressed);
static const char* GetClipboardTextImpl(void* userdata);
static void SetClipboardTextImpl(void* userdata, const char* text);
static void AddOSDMessage(std::string key, std::string message, float duration, bool is_warning); static void AddOSDMessage(std::string key, std::string message, float duration, bool is_warning);
static void RemoveKeyedOSDMessage(std::string key, bool is_warning); static void RemoveKeyedOSDMessage(std::string key, bool is_warning);
static void ClearOSDMessages(bool clear_warnings); static void ClearOSDMessages(bool clear_warnings);
@ -246,9 +250,6 @@ bool ImGuiManager::Initialize(float global_scale, float screen_margin, Error* er
ImGuiIO& io = s_imgui_context->IO; ImGuiIO& io = s_imgui_context->IO;
io.IniFilename = nullptr; io.IniFilename = nullptr;
io.BackendFlags |= ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_RendererHasVtxOffset; io.BackendFlags |= ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_RendererHasVtxOffset;
io.BackendUsingLegacyKeyArrays = 0;
io.BackendUsingLegacyNavInputArray = 0;
io.KeyRepeatDelay = 0.5f;
#ifndef __ANDROID__ #ifndef __ANDROID__
// Android has no keyboard, nor are we using ImGui for any actual user-interactable windows. // Android has no keyboard, nor are we using ImGui for any actual user-interactable windows.
io.ConfigFlags |= io.ConfigFlags |=
@ -256,6 +257,7 @@ bool ImGuiManager::Initialize(float global_scale, float screen_margin, Error* er
#else #else
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_NavEnableGamepad; io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_NavEnableGamepad;
#endif #endif
SetCommonIOOptions(io);
s_window_width = s_window_width =
g_gpu_device->HasMainSwapChain() ? static_cast<float>(g_gpu_device->GetMainSwapChain()->GetWidth()) : 0.0f; g_gpu_device->HasMainSwapChain() ? static_cast<float>(g_gpu_device->GetMainSwapChain()->GetWidth()) : 0.0f;
@ -456,11 +458,11 @@ void ImGuiManager::SetKeyMap()
{ImGuiKey_Space, "Space", nullptr}, {ImGuiKey_Space, "Space", nullptr},
{ImGuiKey_Enter, "Return", nullptr}, {ImGuiKey_Enter, "Return", nullptr},
{ImGuiKey_Escape, "Escape", nullptr}, {ImGuiKey_Escape, "Escape", nullptr},
{ImGuiKey_LeftCtrl, "LeftCtrl", "Ctrl"}, {ImGuiKey_LeftCtrl, "LeftControl", "Control"},
{ImGuiKey_LeftShift, "LeftShift", "Shift"}, {ImGuiKey_LeftShift, "LeftShift", "Shift"},
{ImGuiKey_LeftAlt, "LeftAlt", "Alt"}, {ImGuiKey_LeftAlt, "LeftAlt", "Alt"},
{ImGuiKey_LeftSuper, "LeftSuper", "Super"}, {ImGuiKey_LeftSuper, "LeftSuper", "Super"},
{ImGuiKey_RightCtrl, "RightCtrl", nullptr}, {ImGuiKey_RightCtrl, "RightControl", nullptr},
{ImGuiKey_RightShift, "RightShift", nullptr}, {ImGuiKey_RightShift, "RightShift", nullptr},
{ImGuiKey_RightAlt, "RightAlt", nullptr}, {ImGuiKey_RightAlt, "RightAlt", nullptr},
{ImGuiKey_RightSuper, "RightSuper", nullptr}, {ImGuiKey_RightSuper, "RightSuper", nullptr},
@ -1091,6 +1093,15 @@ void ImGuiManager::UpdateMousePosition(float x, float y)
std::atomic_thread_fence(std::memory_order_release); std::atomic_thread_fence(std::memory_order_release);
} }
void ImGuiManager::SetCommonIOOptions(ImGuiIO& io)
{
io.BackendUsingLegacyKeyArrays = 0;
io.BackendUsingLegacyNavInputArray = 0;
io.KeyRepeatDelay = 0.5f;
io.GetClipboardTextFn = GetClipboardTextImpl;
io.SetClipboardTextFn = SetClipboardTextImpl;
}
bool ImGuiManager::ProcessPointerButtonEvent(InputBindingKey key, float value) bool ImGuiManager::ProcessPointerButtonEvent(InputBindingKey key, float value)
{ {
if (!s_imgui_context || key.data >= std::size(ImGui::GetIO().MouseDown)) if (!s_imgui_context || key.data >= std::size(ImGui::GetIO().MouseDown))
@ -1116,16 +1127,33 @@ bool ImGuiManager::ProcessPointerAxisEvent(InputBindingKey key, float value)
bool ImGuiManager::ProcessHostKeyEvent(InputBindingKey key, float value) bool ImGuiManager::ProcessHostKeyEvent(InputBindingKey key, float value)
{ {
decltype(s_imgui_key_map)::iterator iter; if (!s_imgui_context)
if (!s_imgui_context || (iter = s_imgui_key_map.find(key.data)) == s_imgui_key_map.end())
return false; return false;
// still update state anyway // still update state anyway
s_imgui_context->IO.AddKeyEvent(iter->second, value != 0.0); SetImKeyState(s_imgui_context->IO, key.data, (value != 0.0f));
return s_imgui_wants_keyboard.load(std::memory_order_acquire); return s_imgui_wants_keyboard.load(std::memory_order_acquire);
} }
void ImGuiManager::SetImKeyState(ImGuiIO& io, u32 key, bool pressed)
{
const auto iter = s_imgui_key_map.find(key);
if (iter == s_imgui_key_map.end())
return;
const ImGuiKey imkey = iter->second;
s_imgui_context->IO.AddKeyEvent(imkey, pressed);
// modifier keys need to be handled separately
if ((imkey >= ImGuiKey_LeftCtrl && imkey <= ImGuiKey_LeftSuper) ||
(imkey >= ImGuiKey_RightCtrl && imkey <= ImGuiKey_RightSuper))
{
const u32 idx = imkey - ((imkey >= ImGuiKey_RightCtrl) ? ImGuiKey_RightCtrl : ImGuiKey_LeftCtrl);
s_imgui_context->IO.AddKeyEvent(static_cast<ImGuiKey>(static_cast<u32>(ImGuiMod_Ctrl) << idx), pressed);
}
}
bool ImGuiManager::ProcessGenericInputEvent(GenericInputBinding key, float value) bool ImGuiManager::ProcessGenericInputEvent(GenericInputBinding key, float value)
{ {
static constexpr ImGuiKey key_map[] = { static constexpr ImGuiKey key_map[] = {
@ -1167,6 +1195,28 @@ bool ImGuiManager::ProcessGenericInputEvent(GenericInputBinding key, float value
return s_imgui_wants_keyboard.load(std::memory_order_acquire); return s_imgui_wants_keyboard.load(std::memory_order_acquire);
} }
const char* ImGuiManager::GetClipboardTextImpl(void* userdata)
{
const std::string text = Host::GetClipboardText();
if (text.empty() || text.length() >= std::numeric_limits<int>::max())
return nullptr;
const size_t length = text.length();
GImGui->ClipboardHandlerData.resize(static_cast<int>(length + 1));
std::memcpy(GImGui->ClipboardHandlerData.Data, text.data(), length);
GImGui->ClipboardHandlerData.Data[length] = 0;
return GImGui->ClipboardHandlerData.Data;
}
void ImGuiManager::SetClipboardTextImpl(void* userdata, const char* text)
{
const size_t length = std::strlen(text);
if (length == 0)
return;
Host::CopyTextToClipboard(std::string_view(text, length));
}
void ImGuiManager::CreateSoftwareCursorTextures() void ImGuiManager::CreateSoftwareCursorTextures()
{ {
for (u32 i = 0; i < static_cast<u32>(s_software_cursors.size()); i++) for (u32 i = 0; i < static_cast<u32>(s_software_cursors.size()); i++)
@ -1341,10 +1391,8 @@ bool ImGuiManager::CreateAuxiliaryRenderWindow(AuxiliaryRenderWindowState* state
ImVec2(static_cast<float>(state->swap_chain->GetWidth()), static_cast<float>(state->swap_chain->GetHeight())); ImVec2(static_cast<float>(state->swap_chain->GetWidth()), static_cast<float>(state->swap_chain->GetHeight()));
state->imgui_context->IO.IniFilename = nullptr; state->imgui_context->IO.IniFilename = nullptr;
state->imgui_context->IO.BackendFlags |= ImGuiBackendFlags_HasGamepad; state->imgui_context->IO.BackendFlags |= ImGuiBackendFlags_HasGamepad;
state->imgui_context->IO.BackendUsingLegacyKeyArrays = 0;
state->imgui_context->IO.BackendUsingLegacyNavInputArray = 0;
state->imgui_context->IO.KeyRepeatDelay = 0.5f;
state->imgui_context->IO.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange; state->imgui_context->IO.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange;
SetCommonIOOptions(state->imgui_context->IO);
SetStyle(state->imgui_context->Style, state->swap_chain->GetScale()); SetStyle(state->imgui_context->Style, state->swap_chain->GetScale());
state->imgui_context->Style.WindowBorderSize = 0.0f; state->imgui_context->Style.WindowBorderSize = 0.0f;
@ -1472,9 +1520,7 @@ void ImGuiManager::ProcessAuxiliaryRenderWindowInputEvent(Host::AuxiliaryRenderW
case Host::AuxiliaryRenderWindowEvent::KeyPressed: case Host::AuxiliaryRenderWindowEvent::KeyPressed:
case Host::AuxiliaryRenderWindowEvent::KeyReleased: case Host::AuxiliaryRenderWindowEvent::KeyReleased:
{ {
const auto iter = s_imgui_key_map.find(param1.uint_param); SetImKeyState(io, param1.uint_param, (event == Host::AuxiliaryRenderWindowEvent::KeyPressed));
if (iter != s_imgui_key_map.end())
io.AddKeyEvent(iter->second, (event == Host::AuxiliaryRenderWindowEvent::KeyPressed));
} }
break; break;