From e269125c3a13d1c38c23cd1e11d897cefb7649d0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 6 Mar 2015 21:11:14 +0000 Subject: [PATCH] Windows: setup a default handler for ImeSetInputScreenPosFn so IME (Japanese/Chinese) inputs are positioned correctly. User need to set io.ImeWindowHandle --- examples/directx11_example/main.cpp | 2 + examples/directx9_example/main.cpp | 1 + examples/opengl3_example/main.cpp | 14 ++++++- examples/opengl_example/main.cpp | 16 +++++-- imconfig.h | 3 +- imgui.cpp | 65 +++++++++++++++++------------ imgui.h | 5 ++- 7 files changed, 72 insertions(+), 34 deletions(-) diff --git a/examples/directx11_example/main.cpp b/examples/directx11_example/main.cpp index 311a1e192..40400ef38 100644 --- a/examples/directx11_example/main.cpp +++ b/examples/directx11_example/main.cpp @@ -448,7 +448,9 @@ void InitImGui() io.KeyMap[ImGuiKey_X] = 'X'; io.KeyMap[ImGuiKey_Y] = 'Y'; io.KeyMap[ImGuiKey_Z] = 'Z'; + io.RenderDrawListsFn = ImImpl_RenderDrawLists; + io.ImeWindowHandle = hWnd; // Create the vertex buffer { diff --git a/examples/directx9_example/main.cpp b/examples/directx9_example/main.cpp index 7a7f0abd6..2ffa4e682 100644 --- a/examples/directx9_example/main.cpp +++ b/examples/directx9_example/main.cpp @@ -240,6 +240,7 @@ void InitImGui() io.KeyMap[ImGuiKey_Z] = 'Z'; io.RenderDrawListsFn = ImImpl_RenderDrawLists; + io.ImeWindowHandle = hWnd; // Create the vertex buffer if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0) diff --git a/examples/opengl3_example/main.cpp b/examples/opengl3_example/main.cpp index c48b29d06..3b956cb5c 100644 --- a/examples/opengl3_example/main.cpp +++ b/examples/opengl3_example/main.cpp @@ -10,14 +10,21 @@ #include "../../imgui.h" #include -// Gl3w/Glfw +// Gl3W / GLFW #include #include -#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) +#ifdef _MSC_VER +#undef APIENTRY +#define GLFW_EXPOSE_NATIVE_WIN32 +#define GLFW_EXPOSE_NATIVE_WGL +#include +#endif static GLFWwindow* window; static bool mousePressed[2] = { false, false }; +#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) + // Shader variables static int shader_handle, vert_handle, frag_handle; static int texture_location, proj_mtx_location; @@ -279,6 +286,9 @@ void InitImGui() io.RenderDrawListsFn = ImImpl_RenderDrawLists; io.SetClipboardTextFn = ImImpl_SetClipboardTextFn; io.GetClipboardTextFn = ImImpl_GetClipboardTextFn; +#ifdef _MSC_VER + io.ImeWindowHandle = glfwGetWin32Window(window); +#endif LoadFontsTexture(); } diff --git a/examples/opengl_example/main.cpp b/examples/opengl_example/main.cpp index 9df7b20b2..e57618ba3 100644 --- a/examples/opengl_example/main.cpp +++ b/examples/opengl_example/main.cpp @@ -10,13 +10,20 @@ #include "../../imgui.h" #include -// Glfw +// GLFW #include -#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) +#ifdef _MSC_VER +#undef APIENTRY +#define GLFW_EXPOSE_NATIVE_WIN32 +#define GLFW_EXPOSE_NATIVE_WGL +#include +#endif static GLFWwindow* window; static bool mousePressed[2] = { false, false }; +#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) + // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) // If text or lines are blurry when integrating ImGui in your engine: // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) @@ -92,7 +99,7 @@ static void ImImpl_SetClipboardTextFn(const char* text) glfwSetClipboardString(window, text); } -// GLFW callbacks to get events +// GLFW callbacks static void glfw_error_callback(int error, const char* description) { fputs(description, stderr); @@ -190,6 +197,9 @@ void InitImGui() io.RenderDrawListsFn = ImImpl_RenderDrawLists; io.SetClipboardTextFn = ImImpl_SetClipboardTextFn; io.GetClipboardTextFn = ImImpl_GetClipboardTextFn; +#ifdef _MSC_VER + io.ImeWindowHandle = glfwGetWin32Window(window); +#endif LoadFontsTexture(); } diff --git a/imconfig.h b/imconfig.h index 78fc9761d..bcb0972e7 100644 --- a/imconfig.h +++ b/imconfig.h @@ -18,8 +18,9 @@ //#define IMGUI_API __declspec( dllexport ) //#define IMGUI_API __declspec( dllimport ) -//---- Don't implement default clipboard handlers for Windows (so as not to link with OpenClipboard() and others Win32 functions) +//---- Don't implement default handlers for Windows (so as not to link with OpenClipboard() and others Win32 functions) //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS +//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS //---- Include imgui_user.inl at the end of imgui.cpp so you can include code that extends ImGui using its private data/functions. //#define IMGUI_INCLUDE_IMGUI_USER_INL diff --git a/imgui.cpp b/imgui.cpp index 9397e7940..b6f2bbe48 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -207,30 +207,7 @@ io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, io.Fonts->GetGlyphRangesJapanese()); // Load Japanese characters io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() - - If you want to input Japanese/Chinese/Korean in the text input widget: - - - when loading the font, pass a range that contains the characters you need, e.g.: io.Fonts->GetGlyphRangesJapanese() - - to have the Microsoft IME cursor appears at the right location in the screen, setup a handler for the io.ImeSetInputScreenPosFn function: - - #include - #include - static void ImImpl_ImeSetInputScreenPosFn(int x, int y) - { - // Notify OS Input Method Editor of text input position - HWND hwnd = glfwGetWin32Window(window); - if (HIMC himc = ImmGetContext(hwnd)) - { - COMPOSITIONFORM cf; - cf.ptCurrentPos.x = x; - cf.ptCurrentPos.y = y; - cf.dwStyle = CFS_FORCE_POSITION; - ImmSetCompositionWindow(himc, &cf); - } - } - - // Set pointer to handler in ImGuiIO structure - io.ImeSetInputScreenPosFn = ImImpl_ImeSetInputScreenPosFn; + io.ImeWindowHandle = MY_HWND; // To input using Microsoft IME, give ImGui the hwnd of your application - tip: the construct 'IMGUI_ONCE_UPON_A_FRAME { ... }' will run the block of code only once a frame. You can use it to quickly add custom UI in the middle of a deep nested inner loop in your code. - tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug" @@ -459,6 +436,7 @@ static int ImTextCountUtf8BytesFromWchar(const ImWchar* in_text, const static const char* GetClipboardTextFn_DefaultImpl(); static void SetClipboardTextFn_DefaultImpl(const char* text); +static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); //----------------------------------------------------------------------------- // Texture Atlas data @@ -562,7 +540,7 @@ ImGuiIO::ImGuiIO() MemFreeFn = free; GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; - ImeSetInputScreenPosFn = NULL; + ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl; } // Pass in translated ASCII characters for text input. @@ -8117,11 +8095,13 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re #if defined(_MSC_VER) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS) +#ifndef _WINDOWS_ #define WIN32_LEAN_AND_MEAN #include +#endif // Win32 API clipboard implementation -static const char* GetClipboardTextFn_DefaultImpl() +static const char* GetClipboardTextFn_DefaultImpl() { static char* buf_local = NULL; if (buf_local) @@ -8163,7 +8143,7 @@ static void SetClipboardTextFn_DefaultImpl(const char* text) #else // Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers -static const char* GetClipboardTextFn_DefaultImpl() +static const char* GetClipboardTextFn_DefaultImpl() { return GImGui->PrivateClipboard; } @@ -8185,6 +8165,37 @@ static void SetClipboardTextFn_DefaultImpl(const char* text) #endif +#if defined(_MSC_VER) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS) + +#ifndef _WINDOWS_ +#define WIN32_LEAN_AND_MEAN +#include +#endif +#include +#pragma comment(lib, "imm32") + +static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y) +{ + // Notify OS Input Method Editor of text input position + if (HWND hwnd = (HWND)GImGui->IO.ImeWindowHandle) + if (HIMC himc = ImmGetContext(hwnd)) + { + COMPOSITIONFORM cf; + cf.ptCurrentPos.x = x; + cf.ptCurrentPos.y = y; + cf.dwStyle = CFS_FORCE_POSITION; + ImmSetCompositionWindow(himc, &cf); + } +} + +#else + +static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y) +{ +} + +#endif + //----------------------------------------------------------------------------- // HELP //----------------------------------------------------------------------------- diff --git a/imgui.h b/imgui.h index 2041a4836..c8addc70e 100644 --- a/imgui.h +++ b/imgui.h @@ -574,12 +574,15 @@ struct ImGuiIO const char* (*GetClipboardTextFn)(); void (*SetClipboardTextFn)(const char* text); - // Optional: override memory allocations (default to posix malloc/free). MemFreeFn() may be called with a NULL pointer. + // Optional: override memory allocations. MemFreeFn() may be called with a NULL pointer. + // (default to posix malloc/free) void* (*MemAllocFn)(size_t sz); void (*MemFreeFn)(void* ptr); // Optional: notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME in Windows) + // (default to use native imm32 api on Windows) void (*ImeSetInputScreenPosFn)(int x, int y); + void* ImeWindowHandle; // (Windows) Set this to your HWND to get automatic IME cursor positioning. //------------------------------------------------------------------ // Input - Fill before calling NewFrame()