Can't type Korean in the text box.
Version/Branch of Dear ImGui:
Version 1.91.0, Branch: docking
Back-ends:
imgui_impl_win32.cpp + imgui_impl_dx11.cpp
Compiler, OS:
Windows 11 + MSVC 2022 + VS 2022 Preview
Full config/build information:
Dear ImGui 1.91.2 WIP (19114)
--------------------------------
sizeof(size_t): 8, sizeof(ImDrawIdx): 2, sizeof(ImDrawVert): 20
define: __cplusplus=199711
define: _WIN32
define: _WIN64
define: _MSC_VER=1942
define: _MSVC_LANG=201402
--------------------------------
io.BackendPlatformName: imgui_impl_win32
io.BackendRendererName: imgui_impl_dx11
io.ConfigFlags: 0x00000003
NavEnableKeyboard
NavEnableGamepad
io.ConfigInputTextCursorBlink
io.ConfigWindowsResizeFromEdges
io.ConfigMemoryCompactTimer = 60.0
io.BackendFlags: 0x0000000E
HasMouseCursors
HasSetMousePos
RendererHasVtxOffset
--------------------------------
io.Fonts: 1 fonts, Flags: 0x00000000, TexSize: 512,64
io.DisplaySize: 1264.00,761.00
io.DisplayFramebufferScale: 1.00,1.00
--------------------------------
style.WindowPadding: 8.00,8.00
style.WindowBorderSize: 1.00
style.FramePadding: 4.00,3.00
style.FrameRounding: 0.00
style.FrameBorderSize: 0.00
style.ItemSpacing: 8.00,4.00
style.ItemInnerSpacing: 4.00,4.00
Details:
My Issue/Question:
I added a Korean font (malgun.ttf) that comes with Windows to use Korean in ImGui.
The result is
- ImGui now outputs Hangul correctly.
- you can't enter Hangul in filters or text boxes.
- if I write Hangul in another window, copy it, and paste it, it looks fine.
I have searched a lot in the last two days to solve this problem, and tried various things, but I couldn't solve the problem.
What I've tried
- Try a different font that supports Korean (google NotoSansKR etc..)
- WM_IME_CHAR support in WndProc function (JX-Master's answer from https://github.com/ocornut/imgui/issues/1807)
- Try adding #pragma execution_character_set(“utf-8”) to my code (https://github.com/ocornut/imgui/blob/master/docs/FONTS.md#loading-font-data-from-memory)
- Change the way I type on my computer (Change IME)
Screenshots/Video:
https://github.com/user-attachments/assets/7d163c96-1fa0-4ed2-98e9-5a9a1a86bcdd
Minimal, Complete and Verifiable Example code:
My code is still in its early stages, and I've changed very little from the examples provided by ImGui.
////////////////////////////////////////////////////////////////////////////// ImGuiManager.cpp ////////////////////////////////////////////////////////////////////////////// #include "ImGuiManager.h"
void ImGuiManager::Init() { // ImGui Init IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // 키보드 입력 활성화
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // 게임패드 입력 활성화
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // 도킹 활성화
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // 다중 뷰포트 활성화
io.ConfigViewportsNoAutoMerge = true;
io.ConfigViewportsNoDefaultParent = true;
io.ConfigDockingTransparentPayload = true;
//Korean font settings
io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\malgun.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesKorean());
//
SetupStyle();
}
void ImGuiManager::SetupImGuiContext(HWND hwnd, ID3D11Device* device, ID3D11DeviceContext* deviceContext) { // Initialize the platform/renderer backend ImGui_ImplWin32_Init(hwnd); ImGui_ImplDX11_Init(device, deviceContext); }
bool ImGuiManager::IsDone() const { return !isWindowOpen; }
void ImGuiManager::Release() { // ImGui Shutdonw and Release Resources ImGui_ImplDX11_Shutdown(); ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); }
void ImGuiManager::Update() { // Start a new frame ImGui_ImplDX11_NewFrame(); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame();
// Set the size of the window
// ImGuiCond_FirstUseEver는 창이 처음 생성될 때만 크기를 설정하도록 하는 옵션
ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
static Searcher log;
// Create an ImGui window
ImGui::Begin("ImGui Window", &isWindowOpen);
{
if (ImGui::SmallButton("[Debug] Add 5 entries"))
{
static int counter = 0;
const char* categories[3] = { "카테", "고리", "에요" };
const char* words[] = { "너구리", "오징어"};
for (int n = 0; n < 5; n++)
{
const char* category = categories[counter % IM_ARRAYSIZE(categories)];
const char* word = words[counter % IM_ARRAYSIZE(words)];
log.AddLog("[%s] word: '%s'\n",
category, word);
counter++;
}
}
}
ImGui::End();
log.Draw(u8"ImGui Window", &isWindowOpen);
}
void ImGuiManager::LateUpdate() { // Use when additional updates are required }
void ImGuiManager::Render() { // ImGui Rendering Handling ImGui::Render(); ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
// Render additional platform windows
ImGuiIO& io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
}
}
void ImGuiManager::ResizeScreen() { // Handle actions required by screen size changes }
void ImGuiManager::SetupStyle() { // Setting up styles ImGui::StyleColorsDark(); ImGuiIO& io = ImGui::GetIO(); ImGuiStyle& style = ImGui::GetStyle();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
style.WindowRounding = 0.0f;
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
}
}
////////////////////////////////////////////////////////////////////////////// ImGuiManager.h ////////////////////////////////////////////////////////////////////////////// #pragma once
#include <imgui.h> #include <imgui_impl_win32.h> #include <imgui_impl_dx11.h> #include <d3d11.h> #include "Types.h"
class ImGuiManager : public Singleton<ImGuiManager> ,public Scene { public: void Init() override; void Release() override; void Update() override; void LateUpdate() override; void Render() override; void ResizeScreen() override;
public: // Additional ImGui initialization functions (can be called directly) void SetupImGuiContext(HWND hwnd, ID3D11Device* device, ID3D11DeviceContext* deviceContext);
private: bool isWindowOpen{ true };
public: bool IsDone() const;
private: void SetupStyle(); };
struct Searcher
{
ImGuiTextBuffer Buf;
ImGuiTextFilter Filter;
ImVector
Searcher()
{
AutoScroll = true;
Clear();
}
void Clear()
{
Buf.clear();
LineOffsets.clear();
LineOffsets.push_back(0);
}
void AddLog(const char* fmt, ...) IM_FMTARGS(2)
{
int old_size = Buf.size();
va_list args;
va_start(args, fmt);
Buf.appendfv(fmt, args);
va_end(args);
for (int new_size = Buf.size(); old_size < new_size; old_size++)
if (Buf[old_size] == '\n')
LineOffsets.push_back(old_size + 1);
}
void Draw(const char* title, bool* p_open = NULL)
{
if (!ImGui::Begin(title, p_open))
{
ImGui::End();
return;
}
// Options menu
if (ImGui::BeginPopup("Options"))
{
ImGui::Checkbox("Auto-scroll", &AutoScroll);
ImGui::EndPopup();
}
// Main window
if (ImGui::Button("Options"))
ImGui::OpenPopup("Options");
ImGui::SameLine();
bool clear = ImGui::Button("Clear");
ImGui::SameLine();
bool copy = ImGui::Button("복사");
ImGui::SameLine();
Filter.Draw("검색어", -100.0f);
//ImGui::InputText 를 사용할 부분
static char inputBuffer[256] = "한글"; // A buffer to store the entered text
ImGui::InputText("아무말이나 입력", inputBuffer, IM_ARRAYSIZE(inputBuffer));
// Output the entered text (for testing)
ImGui::Text("입력된 텍스트: %s", inputBuffer);
ImGui::Separator();
if (ImGui::BeginChild("scrolling", ImVec2(0, 0), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar))
{
if (clear)
Clear();
if (copy)
{
const char* text = "한글 테스트";
ImGui::SetClipboardText(text);
}
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
const char* buf = Buf.begin();
const char* buf_end = Buf.end();
if (Filter.IsActive())
{
for (int line_no = 0; line_no < LineOffsets.Size; line_no++)
{
const char* line_start = buf + LineOffsets[line_no];
const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
if (Filter.PassFilter(line_start, line_end))
ImGui::TextUnformatted(line_start, line_end);
}
}
else
{
ImGuiListClipper clipper;
clipper.Begin(LineOffsets.Size);
while (clipper.Step())
{
for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
{
const char* line_start = buf + LineOffsets[line_no];
const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
ImGui::TextUnformatted(line_start, line_end);
}
}
clipper.End();
}
ImGui::PopStyleVar();
// Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame.
// Using a scrollbar or mouse-wheel will take away from the bottom edge.
if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
ImGui::SetScrollHereY(1.0f);
}
ImGui::EndChild();
ImGui::End();
}
};
- Use Tools->Debug Log->IO to visualize calls to
io.AddInputCharacter()and verify if there are correct. - How do you create your win32 window? Make sure to use
CreateWindowW()and notCreateWindowA(), or configure project Character Set to use Unicode Character set.
I would be interested in your precise feedback, I wonder if this has something to do with #3653.
- In Tools->Debug Log->IO, when I try to type Korean, it is not displayed correctly. (I've attached a video to help you understand.)
https://github.com/user-attachments/assets/99903659-72f8-4e17-b19c-c81f27229321
- The win32 window was created as follows: HWND hwnd = ::CreateWindow(wc.lpszClassName, _T("ImGui Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr);
In WinUser.h, defined as follows: #define CreateWindow CreateWindowW
So I think of CreateWindowW as creating a win32 window.
- Upon checking, in Project Properties -> Configuration Properties/Advanced -> Character Sets: 'Use Unicode character set'
=============Below is my WinMain code.
`// Main code //int main(int, char**) int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, _T("AppClass"), nullptr }; ::RegisterClassEx(&wc); HWND hwnd = ::CreateWindow(wc.lpszClassName, _T("ImGui Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr);
if (!CreateDeviceD3D(hwnd)) { CleanupDeviceD3D(); ::UnregisterClass(wc.lpszClassName, wc.hInstance); return 1; }
::ShowWindow(hwnd, SW_HIDE); ::UpdateWindow(hwnd);
// ImGuiManager 싱글턴 인스턴스 초기화 ImGuiManager::GetInstance()->Init(); ImGuiManager::GetInstance()->SetupImGuiContext(hwnd, g_pd3dDevice, g_pd3dDeviceContext);
bool done = false; while (!done) { MSG msg; while (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); if (msg.message == WM_QUIT) done = true; }
if (done || ImGuiManager::GetInstance()->IsDone())
break;
if (g_ResizeWidth != 0 && g_ResizeHeight != 0)
{
CleanupRenderTarget();
g_pSwapChain->ResizeBuffers(0, g_ResizeWidth, g_ResizeHeight, DXGI_FORMAT_UNKNOWN, 0);
g_ResizeWidth = g_ResizeHeight = 0;
CreateRenderTarget();
}
// ImGuiManager의 Update와 Render 호출
ImGuiManager::GetInstance()->Update();
ImGuiManager::GetInstance()->Render();
const float clear_color[4] = { 0.45f, 0.55f, 0.60f, 1.0f };
g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, nullptr);
g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color);
g_pSwapChain->Present(1, 0);
}
ImGuiManager::GetInstance()->Release(); CleanupDeviceD3D(); ::DestroyWindow(hwnd); ::UnregisterClass(wc.lpszClassName, wc.hInstance);
return 0; }`
(1) Can you compile example_win32_directx11 and test on it? (You don't need to load Korean font, just look at Debug Log->IO if the value are correct)
(2) Does this makes any difference? https://github.com/ocornut/imgui/pull/3653/files
- I compiled and tested example_win32_directx11, and it works fine.
Initially, example_win32_directx11 was also unable to type Korean. I thought it might be a problem with my computer's IME, so I reformatted it. (I was suspicious because I had previously developed a game with Unreal Engine and had tinkered with the IME settings for Korean input issues.) After that, example_win32_directx11 was able to type Korean well.
But in my project, I still can't type Korean. I'm investigating why this is happening with my project. I'll comment back when I figure it out for sure.
- https://github.com/ocornut/imgui/pull/3653/files The second way, it didn't make any difference. Thanks for the different ways to do it.
Except for a few settings, my project is almost identical to example_win32_directx11. However, it’s strange that Korean input doesn't work.
Here are a few other differences:
- I'm using ImGui through vcpkg.
- I changed the entry point from
int main(int, char**)toint APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow). - I changed the encoding of the cpp file to Unicode (UTF-8 without BOM) - code page 65001.
- I enabled some additional options in the ImGui configuration context.
So, I tested it by removing the differences one by one. At some point, I discovered the exact point where Korean input stopped working.
When I set io.ConfigViewportsNoAutoMerge to true in the ImGui configuration context, Korean input stops working. Does this setting affect Korean input?
Please refer to the video below.
https://github.com/user-attachments/assets/ac7ec81f-a503-4d9a-9e9b-f6820652f03a
This will make every imgui window use a platform (Windows) window created by the backend.
Presumably, even with the flag disabled, if you move a window out of the main viewport boundary, then you should have the same problem?
Either way it means looking at the _CreateWindow impl + the associated WndProc handler in second half of imgui_impl_win32 and trying to understand what is wrong and how it would differs how the main window was created.
Presumably, even with the flag disabled, if you move a window out of the main viewport boundary, then you should have the same problem?
Yes, even with the flag disabled, the same problem occurs when I move the window outside the main viewport boundary. I looked into the issue further, but in the end, I wasn't able to solve the problem..
I believe the problem is that the vcpkg version may not compiled not for Unicode but for multi-byte mode and our code in ImGui_ImplWin32_CreateWindow() use the default:
vd->Hwnd = ::CreateWindowEx(
vd->DwExStyle, _T("ImGui Platform"), _T("Untitled"), vd->DwStyle, // Style, class name, window name
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, // Window area
vd->HwndParent, nullptr, ::GetModuleHandle(nullptr), nullptr); // Owner window, Menu, Instance, Param
I have pushed a tentative fix: 3293ef8 This is similar to #5725.
Because you are using backend precompiled by vcpkg I believe you cannot test this now and need to wait for a vcpkg update?
This was part of 1.91.3 but unfortunately vcpkg hasn't updated yet and is still on 1.91.0.. There is an unmerged PR for vcpkg: https://github.com/microsoft/vcpkg/pull/41693
1.91.5 has been merged into the vcpkg baseline. https://github.com/microsoft/vcpkg/pull/42244
@Tadminster Have you been able to confirm that this is fixed?
Closing as assumed fixed.
@Tadminster Have you been able to confirm that this is fixed?
I completely removed ImGui from vcpkg and reinstalled it. After that, I downloaded the latest release with docking support and tested it, and everything works fine now. I really appreciate your continued interest and follow-up support.