Input Method Editor (IME) support for text buttons
authorSeverin <julian_eisel@web.de>
Sat, 6 Dec 2014 23:58:17 +0000 (00:58 +0100)
committerSeverin <julian_eisel@web.de>
Sat, 6 Dec 2014 23:58:17 +0000 (00:58 +0100)
Original patch by @random (D765) with some minor work done by @campbell
and me.

At this place, I'd like call out a number of people who were involved and
deserve a big "Thank you!":
* At the first place @randon who developed and submitted the patch
* The Blendercn community which helped a lot with testing - espacially
* @yuzukyo, @leon_cheung and @kjym3
* @campbellbarton, @mont29 and @sergey for their help and advises during
* review
* @ton who realized the importance of this early on and asked me for
* reviewing

We are still not finished, as this is only the first part of the
implementaion, but there's more to come!

36 files changed:
CMakeLists.txt
SConstruct
build_files/scons/config/win32-mingw-config.py
build_files/scons/config/win32-vc-config.py
build_files/scons/config/win64-mingw-config.py
build_files/scons/config/win64-vc-config.py
build_files/scons/tools/btools.py
intern/ghost/CMakeLists.txt
intern/ghost/GHOST_C-api.h
intern/ghost/GHOST_IWindow.h
intern/ghost/GHOST_Types.h
intern/ghost/SConscript
intern/ghost/intern/GHOST_C-api.cpp
intern/ghost/intern/GHOST_SystemWin32.cpp
intern/ghost/intern/GHOST_SystemWin32.h
intern/ghost/intern/GHOST_Window.h
intern/ghost/intern/GHOST_WindowWin32.cpp
intern/ghost/intern/GHOST_WindowWin32.h
source/blender/blenloader/intern/readfile.c
source/blender/editors/include/UI_interface.h
source/blender/editors/interface/CMakeLists.txt
source/blender/editors/interface/SConscript
source/blender/editors/interface/interface.c
source/blender/editors/interface/interface_draw.c
source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/interface_intern.h
source/blender/editors/interface/interface_widgets.c
source/blender/makesdna/DNA_windowmanager_types.h
source/blender/windowmanager/CMakeLists.txt
source/blender/windowmanager/SConscript
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/WM_types.h
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_window.c
source/blender/windowmanager/wm_event_types.h
source/blender/windowmanager/wm_window.h

index f2ffffe..4ee277b 100644 (file)
@@ -318,6 +318,9 @@ mark_as_advanced(WITH_LIBMV_SCHUR_SPECIALIZATIONS)
 option(WITH_FREESTYLE     "Enable Freestyle (advanced edges rendering)" ON)
 
 # Misc
+if(WIN32)
+       option(WITH_INPUT_IME "Enable Input Method Editor (IME) for complex Asian character input" ON)
+endif()
 option(WITH_INPUT_NDOF "Enable NDOF input devices (SpaceNavigator and friends)" ${_init_INPUT_NDOF})
 option(WITH_RAYOPTIMIZATION    "Enable use of SIMD (SSE) optimizations for the raytracer" ON)
 option(WITH_OPENNL        "Enable use of Open Numerical Library" ON)
@@ -1151,6 +1154,10 @@ elseif(WIN32)
 
                list(APPEND PLATFORM_LINKLIBS ws2_32 vfw32 winmm kernel32 user32 gdi32 comdlg32 advapi32 shfolder shell32 ole32 oleaut32 uuid psapi)
 
+               if(WITH_INPUT_IME)
+                       list(APPEND PLATFORM_LINKLIBS imm32)
+               endif()
+
                add_definitions(
                        -D_CRT_NONSTDC_NO_DEPRECATE
                        -D_CRT_SECURE_NO_DEPRECATE
@@ -1506,6 +1513,11 @@ elseif(WIN32)
                endif()
                
                list(APPEND PLATFORM_LINKLIBS -lshell32 -lshfolder -lgdi32 -lmsvcrt -lwinmm -lmingw32 -lm -lws2_32 -lz -lstdc++ -lole32 -luuid -lwsock32 -lpsapi)
+
+               if(WITH_INPUT_IME)
+                       list(APPEND PLATFORM_LINKLIBS -limm32)
+               endif()
+
                set(PLATFORM_CFLAGS "-pipe -funsigned-char -fno-strict-aliasing")
 
                if(WITH_MINGW64)
index 4c2097f..4dacf89 100644 (file)
@@ -266,6 +266,7 @@ if 'blenderlite' in B.targets:
     target_env_defs['WITH_BF_BOOLEAN'] = False
     target_env_defs['WITH_BF_REMESH'] = False
     target_env_defs['WITH_BF_PYTHON'] = False
+    target_env_defs['WITH_BF_IME'] = False
     target_env_defs['WITH_BF_3DMOUSE'] = False
     target_env_defs['WITH_BF_LIBMV'] = False
     target_env_defs['WITH_BF_FREESTYLE'] = False
index 85aa72a..0fb84bf 100644 (file)
@@ -170,6 +170,8 @@ BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
 WITH_BF_RAYOPTIMIZATION = True
 BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse']
 
+WITH_BF_IME = True
+
 WITH_BF_OPENMP = True
 
 #CUDA
@@ -198,6 +200,9 @@ CC_WARN = [ '-Wall' ]
 
 LLIBS = ['-lshell32', '-lshfolder', '-lgdi32', '-lmsvcrt', '-lwinmm', '-lmingw32', '-lm', '-lws2_32', '-lz', '-lstdc++','-lole32','-luuid', '-lwsock32', '-lpsapi']
 
+if WITH_BF_IME:
+    LLIBS.append('-limm32')
+
 PLATFORM_LINKFLAGS = ['-Xlinker', '--stack=2097152']
 
 ## DISABLED, causes linking errors!
index 967e963..d447a1e 100644 (file)
@@ -151,6 +151,8 @@ BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include/opencollada'
 BF_OPENCOLLADA_LIB = 'OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser MathMLSolver xml pcre buffer ftoa'
 BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib/opencollada'
 
+WITH_BF_IME = True
+
 WITH_BF_3DMOUSE = True
 
 WITH_BF_OPENMP = True
@@ -237,6 +239,9 @@ CXX_WARN = []
 
 LLIBS = ['ws2_32', 'vfw32', 'winmm', 'kernel32', 'user32', 'gdi32', 'comdlg32', 'advapi32', 'shfolder', 'shell32', 'ole32', 'oleaut32', 'uuid', 'psapi']
 
+if WITH_BF_IME:
+    LLIBS.append('imm32')
+
 PLATFORM_LINKFLAGS = ['/SUBSYSTEM:CONSOLE','/MACHINE:IX86','/STACK:2097152','/INCREMENTAL:NO', '/LARGEADDRESSAWARE', '/NODEFAULTLIB:msvcrt.lib', '/NODEFAULTLIB:msvcmrt.lib', '/NODEFAULTLIB:msvcurt.lib', '/NODEFAULTLIB:msvcrtd.lib']
 
 # # Todo
index 0314ab1..f93be28 100644 (file)
@@ -170,6 +170,8 @@ BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
 WITH_BF_RAYOPTIMIZATION = True
 BF_RAYOPTIMIZATION_SSE_FLAGS = ['-mmmx', '-msse', '-msse2']
 
+WITH_BF_IME = True
+
 WITH_BF_OPENMP = True
 
 #Freestyle
@@ -193,6 +195,9 @@ CC_WARN = [ '-Wall' ]
 
 LLIBS = ['-lshell32', '-lshfolder', '-lgdi32', '-lmsvcrt', '-lwinmm', '-lmingw32', '-lm', '-lws2_32', '-lz', '-lstdc++','-lole32','-luuid', '-lwsock32', '-lpsapi', '-lpthread']
 
+if WITH_BF_IME:
+    LLIBS.append('-limm32')
+
 PLATFORM_LINKFLAGS = ['-Xlinker', '--stack=2097152']
 
 ## DISABLED, causes linking errors!
index 74d8c20..b8e4f3d 100644 (file)
@@ -154,6 +154,8 @@ BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include/opencollada'
 BF_OPENCOLLADA_LIB = 'OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser MathMLSolver xml pcre buffer ftoa'
 BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib/opencollada'
 
+WITH_BF_IME = True
+
 WITH_BF_3DMOUSE = True
 
 WITH_BF_OPENMP = True
@@ -244,6 +246,9 @@ CXX_WARN = []
 
 LLIBS = ['ws2_32', 'vfw32', 'winmm', 'kernel32', 'user32', 'gdi32', 'comdlg32', 'advapi32', 'shfolder', 'shell32', 'ole32', 'oleaut32', 'uuid', 'psapi']
 
+if WITH_BF_IME:
+    LLIBS.append('imm32')
+
 PLATFORM_LINKFLAGS = ['/SUBSYSTEM:CONSOLE','/MACHINE:X64','/STACK:2097152','/OPT:NOREF','/INCREMENTAL:NO', '/NODEFAULTLIB:msvcrt.lib', '/NODEFAULTLIB:msvcmrt.lib', '/NODEFAULTLIB:msvcurt.lib', '/NODEFAULTLIB:msvcrtd.lib']
 
 BF_CYCLES_CUDA_ENV="C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd"
index cf9962d..eb5036f 100644 (file)
@@ -174,6 +174,7 @@ def validate_arguments(args, bc):
             'WITH_BF_CXX_GUARDEDALLOC',
             'WITH_BF_JEMALLOC', 'WITH_BF_STATICJEMALLOC', 'BF_JEMALLOC', 'BF_JEMALLOC_INC', 'BF_JEMALLOC_LIBPATH', 'BF_JEMALLOC_LIB', 'BF_JEMALLOC_LIB_STATIC',
             'BUILDBOT_BRANCH',
+            'WITH_BF_IME',
             'WITH_BF_3DMOUSE', 'WITH_BF_STATIC3DMOUSE', 'BF_3DMOUSE', 'BF_3DMOUSE_INC', 'BF_3DMOUSE_LIB', 'BF_3DMOUSE_LIBPATH', 'BF_3DMOUSE_LIB_STATIC',
             'WITH_BF_CYCLES', 'WITH_BF_CYCLES_CUDA_BINARIES', 'BF_CYCLES_CUDA_NVCC', 'BF_CYCLES_CUDA_NVCC', 'WITH_BF_CYCLES_CUDA_THREADED_COMPILE', 'BF_CYCLES_CUDA_ENV',
             'WITH_BF_OIIO', 'WITH_BF_STATICOIIO', 'BF_OIIO', 'BF_OIIO_INC', 'BF_OIIO_LIB', 'BF_OIIO_LIB_STATIC', 'BF_OIIO_LIBPATH',
@@ -507,6 +508,8 @@ def read_opts(env, cfg, args):
         (BoolVariable('WITH_BF_PLAYER', 'Build blenderplayer if true', False)),
         (BoolVariable('WITH_BF_NOBLENDER', 'Do not build blender if true', False)),
 
+        (BoolVariable('WITH_BF_IME', 'Enable Input Method Editor (IME) for complex Asian character input', False)),
+
         (BoolVariable('WITH_BF_3DMOUSE', 'Build blender with support of 3D mouses', False)),
         (BoolVariable('WITH_BF_STATIC3DMOUSE', 'Staticly link to 3d mouse library', False)),
         ('BF_3DMOUSE', '3d mouse library base path', ''),
index 3ce269c..dc55a81 100644 (file)
@@ -280,6 +280,16 @@ elseif(WIN32)
                )
        endif()
 
+       if(WITH_INPUT_IME)
+               add_definitions(-DWITH_INPUT_IME)
+
+               list(APPEND SRC
+                       intern/GHOST_ImeWin32.cpp
+
+                       intern/GHOST_ImeWin32.h
+               )
+       endif()
+
        if(WITH_INPUT_NDOF)
                list(APPEND SRC
                        intern/GHOST_NDOFManagerWin32.cpp
index 7b47f05..c0f2651 100644 (file)
@@ -897,6 +897,30 @@ extern int GHOST_UseNativePixels(void);
  */
 extern float GHOST_GetNativePixelSize(GHOST_WindowHandle windowhandle);
 
+/**
+ * Enable IME attached to the given window, i.e. allows user-input
+ * events to be dispatched to the IME.
+ * \param windowhandle Window handle of the caller
+ * \param x Requested x-coordinate of the rectangle
+ * \param y Requested y-coordinate of the rectangle
+ * \param w Requested width of the rectangle
+ * \param h Requested height of the rectangle
+ * \param complete Whether or not to complete the ongoing composition
+ * true:  Start a new composition
+ * false: Move the IME windows to the given position without finishing it.
+ */
+extern void GHOST_BeginIME(GHOST_WindowHandle windowhandle,
+                            GHOST_TInt32 x,
+                            GHOST_TInt32 y,
+                            GHOST_TInt32 w,
+                            GHOST_TInt32 h,
+                            int complete);
+/**
+ * Disable the IME attached to the given window, i.e. prohibits any user-input
+ * events from being dispatched to the IME.
+ * \param windowhandle The window handle of the caller
+ */
+extern void GHOST_EndIME(GHOST_WindowHandle windowhandle);
 
 #ifdef __cplusplus
 }
index 71dc193..3f8215d 100644 (file)
@@ -331,6 +331,29 @@ public:
 
        virtual float getNativePixelSize(void) = 0;
 
+#ifdef WITH_INPUT_IME
+       /**
+        * Enable IME attached to the given window, i.e. allows user-input
+        * events to be dispatched to the IME.
+        * \param x Requested x-coordinate of the rectangle
+        * \param y Requested y-coordinate of the rectangle
+        * \param w Requested width of the rectangle
+        * \param h Requested height of the rectangle
+        * \param complete Whether or not to complete the ongoing composition
+        * true:  Start a new composition
+        * false: Move the IME windows to the given position without finishing it.
+        */
+       virtual void beginIME(
+               GHOST_TInt32 x, GHOST_TInt32 y,
+               GHOST_TInt32 w, GHOST_TInt32 h,
+               int completed) = 0;
+
+       /**
+        * Disable the IME attached to the given window, i.e. prohibits any user-input
+        * events from being dispatched to the IME.
+        */
+       virtual void endIME() = 0;
+#endif /* WITH_INPUT_IME */
        
 #ifdef WITH_CXX_GUARDEDALLOC
        MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_IWindow")
index 7333ba0..c4a7490 100644 (file)
@@ -190,6 +190,10 @@ typedef enum {
 
        GHOST_kEventTimer,
 
+       GHOST_kEventImeCompositionStart,
+       GHOST_kEventImeComposition,
+       GHOST_kEventImeCompositionEnd,
+
        GHOST_kNumEventTypes
 } GHOST_TEventType;
 
@@ -436,6 +440,22 @@ typedef struct {
        GHOST_TEventDataPtr data;
 } GHOST_TEventDragnDropData;
 
+/** similar to wmImeData */
+typedef struct {
+       /** size_t */
+       GHOST_TUserDataPtr result_len, composite_len;
+       /** char * utf8 encoding */
+       GHOST_TUserDataPtr result, composite;
+       /** Cursor position in the IME composition. */
+       int cursor_position;
+       /** Represents the position of the beginning of the selection */
+       int target_start;
+       /** Represents the position of the end of the selection */
+       int target_end;
+       /** custom temporal data */
+       GHOST_TUserDataPtr tmp;
+} GHOST_TEventImeData;
+
 typedef struct {
        int count;
        GHOST_TUns8 **strings;
index 5a4572c..a41fadf 100644 (file)
@@ -154,6 +154,13 @@ if env['BF_GHOST_DEBUG']:
 else:
     sources.remove('intern' + os.sep + 'GHOST_EventPrinter.cpp')
 
+if env['WITH_BF_IME']:
+    if window_system in ('win32-vc', 'win32-mingw', 'win64-vc', 'win64-mingw'):
+        defs.append('WITH_INPUT_IME')
+    else:
+        sources.remove('intern' + os.sep + 'GHOST_ImeWin32.h')
+        sources.remove('intern' + os.sep + 'GHOST_ImeWin32.cpp')
+
 if env['WITH_BF_3DMOUSE']:
     defs.append('WITH_INPUT_NDOF')
 
index 5a2e638..0da77ac 100644 (file)
@@ -915,3 +915,21 @@ float GHOST_GetNativePixelSize(GHOST_WindowHandle windowhandle)
        return 1.0f;
 }
 
+#ifdef WITH_INPUT_IME
+
+void GHOST_BeginIME(GHOST_WindowHandle windowhandle,
+                    GHOST_TInt32 x, GHOST_TInt32 y,
+                    GHOST_TInt32 w, GHOST_TInt32 h,
+                    int complete)
+{
+       GHOST_IWindow *window = (GHOST_IWindow *) windowhandle;
+       window->beginIME(x, y, w, h, complete);
+}
+
+void GHOST_EndIME(GHOST_WindowHandle windowhandle)
+{
+       GHOST_IWindow *window = (GHOST_IWindow *) windowhandle;
+       window->endIME();
+}
+
+#endif  /* WITH_INPUT_IME */
index 3b793fd..4247c4f 100644 (file)
@@ -792,6 +792,15 @@ GHOST_Event *GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_
        return new GHOST_Event(system->getMilliSeconds(), type, window);
 }
 
+#ifdef WITH_INPUT_IME
+GHOST_Event *GHOST_SystemWin32::processImeEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TEventImeData *data)
+{
+       GHOST_System *system = (GHOST_System *)getSystem();
+       return new GHOST_EventIME(system->getMilliSeconds(), type, window, data);
+}
+#endif
+
+
 GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(
         GHOST_TEventType eventType,
         GHOST_TDragnDropTypes draggedObjectType,
@@ -904,6 +913,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
 
        LRESULT lResult = 0;
        GHOST_SystemWin32 *system = ((GHOST_SystemWin32 *)getSystem());
+       GHOST_EventManager *eventManager = system->getEventManager();
        GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized");
 
        if (hwnd) {
@@ -912,8 +922,13 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
                        switch (msg) {
                                // we need to check if new key layout has AltGr
                                case WM_INPUTLANGCHANGE:
+                               {
                                        system->handleKeyboardChange();
+#ifdef WITH_INPUT_IME
+                                       window->getImeInput()->SetInputLanguage();
+#endif
                                        break;
+                               }
                                ////////////////////////////////////////////////////////////////////////
                                // Keyboard events, processed
                                ////////////////////////////////////////////////////////////////////////
@@ -949,6 +964,56 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
                                        }
                                        break;
                                }
+#ifdef WITH_INPUT_IME
+                               ////////////////////////////////////////////////////////////////////////
+                               // IME events, processed, read more in GHOST_IME.h
+                               ////////////////////////////////////////////////////////////////////////
+                               case WM_IME_SETCONTEXT:
+                               {
+                                       window->getImeInput()->SetInputLanguage();
+                                       window->getImeInput()->CreateImeWindow(window->getHWND());
+                                       window->getImeInput()->CleanupComposition(window->getHWND());
+                                       window->getImeInput()->CheckFirst(window->getHWND());
+                                       break;
+                               }
+                               case WM_IME_STARTCOMPOSITION:
+                               {
+                                       eventHandled = true;
+                                       /* remove input event before start comp event, avoid redundant input */
+                                       eventManager->removeTypeEvents(GHOST_kEventKeyDown, window);
+                                       window->getImeInput()->CreateImeWindow(window->getHWND());
+                                       window->getImeInput()->ResetComposition(window->getHWND());
+                                       event = processImeEvent(
+                                               GHOST_kEventImeCompositionStart,
+                                               window,
+                                               &window->getImeInput()->eventImeData);
+                                       break;
+                               }
+                               case WM_IME_COMPOSITION:
+                               {
+                                       eventHandled = true;
+                                       window->getImeInput()->UpdateImeWindow(window->getHWND());
+                                       window->getImeInput()->UpdateInfo(window->getHWND());
+                                       event = processImeEvent(
+                                               GHOST_kEventImeComposition,
+                                               window,
+                                               &window->getImeInput()->eventImeData);
+                                       break;
+                               }
+                               case WM_IME_ENDCOMPOSITION:
+                               {
+                                       eventHandled = true;
+                                       /* remove input event after end comp event, avoid redundant input */
+                                       eventManager->removeTypeEvents(GHOST_kEventKeyDown, window);
+                                       window->getImeInput()->ResetComposition(window->getHWND());
+                                       window->getImeInput()->DestroyImeWindow(window->getHWND());
+                                       event = processImeEvent(
+                                               GHOST_kEventImeCompositionEnd,
+                                               window,
+                                               &window->getImeInput()->eventImeData);
+                                       break;
+                               }
+#endif /* WITH_INPUT_IME */
                                ////////////////////////////////////////////////////////////////////////
                                // Keyboard events, ignored
                                ////////////////////////////////////////////////////////////////////////
index 79fed06..cb3b8ee 100644 (file)
@@ -306,6 +306,15 @@ protected:
         */
        static GHOST_Event *processWindowEvent(GHOST_TEventType type, GHOST_IWindow *window);
 
+       /**
+        * Creates a IME event.
+        * \param type          The type of event to create.
+        * \param window                The window receiving the event (the active window).
+        * \param data          IME data.
+        * \return The event created.
+        */
+       static GHOST_Event *processImeEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TEventImeData *data);
+
        /**
         * Handles minimum window size.
         * \param minmax        The MINMAXINFO structure.
index 15b8199..ac31c54 100644 (file)
@@ -295,6 +295,22 @@ public:
                return 1.0f;
        }
 
+#ifdef WITH_INPUT_IME
+       virtual void beginIME(GHOST_TInt32 x,
+                             GHOST_TInt32 y,
+                             GHOST_TInt32 w,
+                             GHOST_TInt32 h,
+                             int completed)
+       {
+               /* do nothing temporarily if not in windows */
+       }
+
+       virtual void endIME()
+       {
+               /* do nothing temporarily if not in windows */
+       }
+#endif /* WITH_INPUT_IME */
+
 protected:
        /**
         * Tries to install a rendering context in this window.
index 64ea719..4e38488 100644 (file)
@@ -1050,3 +1050,16 @@ GHOST_TSuccess GHOST_WindowWin32::endProgressBar()
        return GHOST_kFailure;
 }
 
+
+#ifdef WITH_INPUT_IME
+void GHOST_WindowWin32::beginIME(GHOST_TInt32 x, GHOST_TInt32 y, GHOST_TInt32 w, GHOST_TInt32 h, int completed)
+{
+       this->getImeInput()->BeginIME(this->getHWND(),  GHOST_Rect(x, y - h , x, y), (bool)completed);
+}
+
+
+void GHOST_WindowWin32::endIME()
+{
+       this->getImeInput()->EndIME(this->getHWND());
+}
+#endif /* WITH_INPUT_IME */
index 7b12d8c..c4575d0 100644 (file)
@@ -39,6 +39,9 @@
 
 #include "GHOST_Window.h"
 #include "GHOST_TaskbarWin32.h"
+#ifdef WITH_INPUT_IME
+#  include "GHOST_ImeWin32.h"
+#endif
 
 #include <wintab.h>
 #define PACKETDATA  (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR)
@@ -253,6 +256,17 @@ public:
        /** if the window currently resizing */
        bool m_inLiveResize;
 
+#ifdef WITH_INPUT_IME
+       GHOST_ImeWin32 *getImeInput() {return &m_imeImput;}
+
+       virtual void beginIME(
+               GHOST_TInt32 x, GHOST_TInt32 y,
+               GHOST_TInt32 w, GHOST_TInt32 h,
+               int completed);
+
+       virtual void endIME();
+#endif /* WITH_INPUT_IME */
+
 private:
 
        /**
@@ -339,6 +353,11 @@ private:
 
        /** Hwnd to parent window */
        GHOST_TEmbedderWindowID m_parentWindowHwnd;
+
+#ifdef WITH_INPUT_IME
+       /** Handle input method editors event */
+       GHOST_ImeWin32 m_imeImput;
+#endif
 };
 
 #endif // __GHOST_WINDOWWIN32_H__
index ac903c7..0950eda 100644 (file)
@@ -5677,6 +5677,9 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
                win->eventstate = NULL;
                win->curswin = NULL;
                win->tweak = NULL;
+#ifdef WIN32
+               win->ime_data = NULL;
+#endif
                
                BLI_listbase_clear(&win->queue);
                BLI_listbase_clear(&win->handlers);
index 42f6737..2251f3f 100644 (file)
@@ -313,6 +313,7 @@ void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx,
 void UI_draw_roundbox_gl_mode(int mode, float minx, float miny, float maxx, float maxy, float rad);
 void UI_draw_roundbox_shade_x(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown);
 void UI_draw_roundbox_shade_y(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadeLeft, float shadeRight);
+void UI_draw_text_underline(int pos_x, int pos_y, int len, int height);
 
 /* state for scrolldrawing */
 #define UI_SCROLL_PRESSED       (1 << 0)
index b921d17..972eca7 100644 (file)
@@ -71,6 +71,12 @@ if(WITH_PYTHON)
        add_definitions(-DWITH_PYTHON)
 endif()
 
+if(WIN32)
+       if(WITH_INPUT_IME)
+               add_definitions(-DWITH_INPUT_IME)
+       endif()
+endif()
+
 add_definitions(${GL_DEFINITIONS})
 
 blender_add_lib(bf_editor_interface "${SRC}" "${INC}" "${INC_SYS}")
index 303ab7f..5af8bba 100644 (file)
@@ -48,6 +48,10 @@ incs = [
 
 defs = env['BF_GL_DEFINITIONS']
 
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-vc', 'win64-mingw'):
+    if env['WITH_BF_IME']:
+        defs.append('WITH_INPUT_IME')
+
 if env['WITH_BF_INTERNATIONAL']:
     defs.append('WITH_INTERNATIONAL')
 
index 92017e7..4cbb02c 100644 (file)
@@ -209,6 +209,11 @@ void ui_window_to_region(const ARegion *ar, int *x, int *y)
        *y -= ar->winrct.ymin;
 }
 
+void ui_region_to_window(const ARegion *ar, int *x, int *y)
+{
+       *x += ar->winrct.xmin;
+       *y += ar->winrct.ymin;
+}
 /* ******************* block calc ************************* */
 
 void ui_block_translate(uiBlock *block, int x, int y)
index 4dd952f..bcd9b9a 100644 (file)
@@ -395,6 +395,12 @@ void UI_draw_roundbox(float minx, float miny, float maxx, float maxy, float rad)
        ui_draw_anti_roundbox(GL_POLYGON, minx, miny, maxx, maxy, rad, roundboxtype & UI_RB_ALPHA);
 }
 
+void UI_draw_text_underline(int pos_x, int pos_y, int len, int height)
+{
+       int ofs_y = 4 * U.pixelsize;
+       glRecti(pos_x, pos_y - ofs_y, pos_x + len, pos_y - ofs_y + (height * U.pixelsize));
+}
+
 /* ************** SPECIAL BUTTON DRAWING FUNCTIONS ************* */
 
 void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *rect)
index 3a31280..b39c786 100644 (file)
 #include "WM_api.h"
 #include "WM_types.h"
 
+#ifdef WITH_INPUT_IME
+#  include "wm_window.h"
+#endif
+
 /* place the mouse at the scaled down location when un-grabbing */
 #define USE_CONT_MOUSE_CORRECT
 /* support dragging toggle buttons */
@@ -2425,8 +2429,50 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in
        return changed;
 }
 
+#ifdef WITH_INPUT_IME
+/* enable ime, and set up uibut ime data */
+static void ui_textedit_ime_begin(wmWindow *win, uiBut *UNUSED(but))
+{
+       /* XXX Is this really needed? */
+       int x, y;
+
+       /* enable IME and position to cursor, it's a trick */
+       x = win->eventstate->x;
+       /* flip y and move down a bit, prevent the IME panel cover the edit button */
+       y = win->eventstate->y - 12;
+
+       wm_window_IME_begin(win, x, y, 0, 0, true);
+}
+
+/* disable ime, and clear uibut ime data */
+static void ui_textedit_ime_end(wmWindow *win, uiBut *UNUSED(but))
+{
+       wm_window_IME_end(win);
+}
+
+void ui_but_ime_reposition(uiBut *but, int x, int y, bool complete)
+{
+       BLI_assert(but->active);
+
+       ui_region_to_window(but->active->region, &x, &y);
+       wm_window_IME_begin(but->active->window, x, y - 4, 0, 0, complete);
+}
+
+/* should be ui_but_ime_data_get */
+wmIMEData *ui_but_get_ime_data(uiBut *but)
+{
+       if (but->active && but->active->window) {
+               return but->active->window->ime_data;
+       }
+       else {
+               return NULL;
+       }
+}
+#endif  /* WITH_INPUT_IME */
+
 static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
 {
+       wmWindow *win = CTX_wm_window(C);
        int len;
 
        if (data->str) {
@@ -2482,12 +2528,18 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
        but->flag &= ~UI_BUT_REDALERT;
 
        ui_but_update(but);
-       
-       WM_cursor_modal_set(CTX_wm_window(C), BC_TEXTEDITCURSOR);
+
+       WM_cursor_modal_set(win, BC_TEXTEDITCURSOR);
+
+#ifdef WITH_INPUT_IME
+       ui_textedit_ime_begin(win, but);
+#endif
 }
 
 static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
 {
+       wmWindow *win = CTX_wm_window(C);
+
        if (but) {
                if (ui_but_is_utf8(but)) {
                        int strip = BLI_utf8_invalid_strip(but->editstr, strlen(but->editstr));
@@ -2518,7 +2570,11 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
                but->pos = -1;
        }
        
-       WM_cursor_modal_restore(CTX_wm_window(C));
+       WM_cursor_modal_restore(win);
+
+#ifdef WITH_INPUT_IME
+       ui_textedit_ime_end(win, but);
+#endif
 }
 
 static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonData *data)
@@ -2583,6 +2639,14 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
        int retval = WM_UI_HANDLER_CONTINUE;
        bool changed = false, inbox = false, update = false;
 
+#ifdef WITH_INPUT_IME
+       wmWindow *win = CTX_wm_window(C);
+       wmIMEData *ime_data = win->ime_data;
+       bool is_ime_composing = ime_data && ime_data->is_ime_composing;
+#else
+       bool is_ime_composing = false;
+#endif
+
        switch (event->type) {
                case MOUSEMOVE:
                case MOUSEPAN:
@@ -2603,6 +2667,12 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
                case RIGHTMOUSE:
                case ESCKEY:
                        if (event->val == KM_PRESS) {
+#ifdef WITH_INPUT_IME
+                               /* skips button handling since it is not wanted */
+                               if (is_ime_composing) {
+                                       break;
+                               }
+#endif
                                data->cancel = true;
                                data->escapecancel = true;
                                button_activate_state(C, but, BUTTON_STATE_EXIT);
@@ -2660,7 +2730,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
                }
        }
 
-       if (event->val == KM_PRESS) {
+       if (event->val == KM_PRESS && !is_ime_composing) {
                switch (event->type) {
                        case VKEY:
                        case XKEY:
@@ -2776,7 +2846,15 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
                                break;
                }
 
-               if ((event->ascii || event->utf8_buf[0]) && (retval == WM_UI_HANDLER_CONTINUE)) {
+               if ((event->ascii || event->utf8_buf[0]) &&
+                   (retval == WM_UI_HANDLER_CONTINUE)
+#ifdef WITH_INPUT_IME
+                   &&
+                   !is_ime_composing &&
+                   !WM_event_is_ime_switch(event)
+#endif
+                   )
+               {
                        char ascii = event->ascii;
                        const char *utf8_buf = event->utf8_buf;
 
@@ -2811,6 +2889,25 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
                        update = true;
        }
 
+#ifdef WITH_INPUT_IME
+       if (event->type == WM_IME_COMPOSITE_START || event->type == WM_IME_COMPOSITE_EVENT) {
+               changed = true;
+
+               if (event->type == WM_IME_COMPOSITE_START && but->selend > but->selsta) {
+                       ui_textedit_delete_selection(but, data);
+               }
+               if (event->type == WM_IME_COMPOSITE_EVENT && ime_data->result_len) {
+                       ui_textedit_type_buf(
+                               but, data,
+                               ime_data->str_result,
+                               ime_data->result_len);
+               }
+       }
+       else if (event->type == WM_IME_COMPOSITE_END) {
+               changed = true;
+       }
+#endif
+
        if (changed) {
                /* only update when typing for TAB key */
                if (update && data->interactive) {
index 328822e..2c3a239 100644 (file)
@@ -433,6 +433,7 @@ extern void ui_block_to_window_rctf(const struct ARegion *ar, uiBlock *block, rc
 extern void ui_window_to_block_fl(const struct ARegion *ar, uiBlock *block, float *x, float *y);
 extern void ui_window_to_block(const struct ARegion *ar, uiBlock *block, int *x, int *y);
 extern void ui_window_to_region(const ARegion *ar, int *x, int *y);
+extern void ui_region_to_window(const struct ARegion *ar, int *x, int *y);
 
 extern double ui_but_value_get(uiBut *but);
 extern void ui_but_value_set(uiBut *but, double value);
@@ -627,6 +628,11 @@ void ui_panel_menu(struct bContext *C, ARegion *ar, Panel *pa);
 uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new);
 uiBut *ui_but_find_new(uiBlock *block_old, const uiBut *but_new);
 
+#ifdef WITH_INPUT_IME
+void ui_but_ime_reposition(uiBut *but, int x, int y, bool complete);
+struct wmIMEData *ui_but_get_ime_data(uiBut *but);
+#endif
+
 /* interface_widgets.c */
 void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3);
 void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha);
index c9def07..d6c51b6 100644 (file)
 
 #include "interface_intern.h"
 
+#ifdef WITH_INPUT_IME
+#  include "WM_types.h"
+#endif
+
 /* icons are 80% of height of button (16 pixels inside 20 height) */
 #define ICON_SIZE_FROM_BUTRECT(rect) (0.8f * BLI_rcti_size_y(rect))
 
@@ -1232,6 +1236,50 @@ static void ui_text_clip_right_label(uiFontStyle *fstyle, uiBut *but, const rcti
                BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
 }
 
+#ifdef WITH_INPUT_IME
+static void widget_draw_text_ime_underline(
+        uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, const rcti *rect,
+        const wmIMEData *ime_data, const char *drawstr)
+{
+       int ofs_x, width;
+       int rect_x = BLI_rcti_size_x(rect);
+       int sel_start = ime_data->sel_start, sel_end = ime_data->sel_end;
+
+       if (drawstr[0] != 0) {
+               if (but->pos >= but->ofs) {
+                       ofs_x = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->pos - but->ofs);
+               }
+               else {
+                       ofs_x = 0;
+               }
+
+               width = BLF_width(fstyle->uifont_id, drawstr + but->ofs,
+                                 ime_data->composite_len + but->pos - but->ofs);
+
+               glColor4ubv((unsigned char *)wcol->text);
+               UI_draw_text_underline(rect->xmin + ofs_x, rect->ymin + 6 * U.pixelsize, min_ii(width, rect_x - 2) - ofs_x, 1);
+
+               /* draw the thick line */
+               if (sel_start != -1 && sel_end != -1) {
+                       sel_end -= sel_start;
+                       sel_start += but->pos;
+
+                       if (sel_start >= but->ofs) {
+                               ofs_x = BLF_width(fstyle->uifont_id, drawstr + but->ofs, sel_start - but->ofs);
+                       }
+                       else {
+                               ofs_x = 0;
+                       }
+
+                       width = BLF_width(fstyle->uifont_id, drawstr + but->ofs,
+                                         sel_end + sel_start - but->ofs);
+
+                       UI_draw_text_underline(rect->xmin + ofs_x, rect->ymin + 6 * U.pixelsize, min_ii(width, rect_x - 2) - ofs_x, 2);
+               }
+       }
+}
+#endif  /* WITH_INPUT_IME */
+
 static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
 {
        int drawstr_left_len = UI_MAX_DRAW_STR;
@@ -1239,6 +1287,10 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
        const char *drawstr_right = NULL;
        bool use_right_only = false;
 
+#ifdef WITH_INPUT_IME
+       const wmIMEData *ime_data;
+#endif
+
        UI_fontstyle_set(fstyle);
        
        if (but->editstr || (but->drawflag & UI_BUT_TEXT_LEFT))
@@ -1266,13 +1318,30 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
                        /* max length isn't used in this case,
                         * we rely on string being NULL terminated. */
                        drawstr_left_len = INT_MAX;
-                       drawstr = but->editstr;
+
+#ifdef WITH_INPUT_IME
+                       /* FIXME, IME is modifying 'const char *drawstr! */
+                       ime_data = ui_but_get_ime_data(but);
+
+                       if (ime_data && ime_data->composite_len) {
+                               /* insert composite string into cursor pos */
+                               BLI_snprintf((char *)drawstr, UI_MAX_DRAW_STR, "%s%s%s",
+                                            but->editstr, ime_data->str_composite,
+                                            but->editstr + but->pos);
+                       }
+                       else
+#endif
+                       {
+                               drawstr = but->editstr;
+                       }
                }
        }
 
 
-       /* text button selection and cursor */
+       /* text button selection, cursor, composite underline */
        if (but->editstr && but->pos != -1) {
+               int but_pos_ofs;
+               int tx, ty;
 
                /* text button selection */
                if ((but->selend - but->selsta) > 0) {
@@ -1298,18 +1367,44 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
                }
 
                /* text cursor */
+               but_pos_ofs = but->pos;
+
+#ifdef WITH_INPUT_IME
+               /* if is ime compositing, move the cursor */
+               if (ime_data && ime_data->composite_len && ime_data->cursor_pos != -1) {
+                       but_pos_ofs += ime_data->cursor_pos;
+               }
+#endif
+
                if (but->pos >= but->ofs) {
                        int t;
                        if (drawstr[0] != 0) {
-                               t = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->pos - but->ofs);
+                               t = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but_pos_ofs - but->ofs);
                        }
                        else {
                                t = 0;
                        }
 
                        glColor3f(0.20, 0.6, 0.9);
-                       glRecti(rect->xmin + t, rect->ymin + 2, rect->xmin + t + 2, rect->ymax - 2);
+
+                       tx = rect->xmin + t + 2;
+                       ty = rect->ymin + 2;
+
+                       /* draw cursor */
+                       glRecti(rect->xmin + t, ty, tx, rect->ymax - 2);
                }
+
+#ifdef WITH_INPUT_IME
+               if (ime_data && ime_data->composite_len) {
+                       /* ime cursor following */
+                       if (but->pos >= but->ofs) {
+                               ui_but_ime_reposition(but, tx + 5, ty + 3, false);
+                       }
+
+                       /* composite underline */
+                       widget_draw_text_ime_underline(fstyle, wcol, but, rect, ime_data, drawstr);
+               }
+#endif
        }
        
        if (fstyle->kerning == 1)
index 73a70b4..1a0562a 100644 (file)
@@ -165,6 +165,13 @@ enum {
        WM_INIT_KEYMAP = (1<<1),
 };
 
+/* IME is win32 only! */
+#ifndef WIN32
+#  ifdef __GNUC__
+#    define ime_data ime_data __attribute__ ((deprecated))
+#  endif
+#endif
+
 /* the savable part, rest of data is local in ghostwinlay */
 typedef struct wmWindow {
        struct wmWindow *next, *prev;
@@ -197,6 +204,10 @@ typedef struct wmWindow {
 
        struct wmGesture *tweak;      /* internal for wm_operators.c */
 
+       /* Input Method Editor data - complex character input (esp. for asian character input)
+        * Currently WIN32, runtime-only data */
+       struct wmIMEData *ime_data;
+
        int drawmethod, drawfail;     /* internal for wm_draw.c only */
        void *drawdata;               /* internal for wm_draw.c only */
 
@@ -208,6 +219,10 @@ typedef struct wmWindow {
        ListBase gesture;             /* gesture stuff */
 } wmWindow;
 
+#ifdef ime_data
+#  undef ime_data
+#endif
+
 /* These two Lines with # tell makesdna this struct can be excluded. */
 /* should be something like DNA_EXCLUDE 
  * but the preprocessor first removes all comments, spaces etc */
index 4cbadda..78b5d49 100644 (file)
@@ -130,6 +130,12 @@ if(WITH_BUILDINFO)
        add_definitions(-DWITH_BUILDINFO)
 endif()
 
+if(WIN32)
+       if(WITH_INPUT_IME)
+               add_definitions(-DWITH_INPUT_IME)
+       endif()
+endif()
+
 if(WITH_COMPOSITOR)
        add_definitions(-DWITH_COMPOSITOR)
 endif()
index 3c44ff6..a6f64f7 100644 (file)
@@ -69,6 +69,10 @@ if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', '
 if env['BF_BUILDINFO']:
     defs.append('WITH_BUILDINFO')
 
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-vc', 'win64-mingw'):
+    if env['WITH_BF_IME']:
+        defs.append('WITH_INPUT_IME')
+
 if env['WITH_BF_INTERNATIONAL']:
     defs.append('WITH_INTERNATIONAL')
 
index ced7222..d2abfd4 100644 (file)
@@ -462,6 +462,10 @@ void        WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4
 float       WM_event_tablet_data(const struct wmEvent *event, int *pen_flip, float tilt[2]);
 bool        WM_event_is_tablet(const struct wmEvent *event);
 
+#ifdef WITH_INPUT_IME
+bool        WM_event_is_ime_switch(const struct wmEvent *event);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
index 4b6b5e9..d9924cf 100644 (file)
@@ -570,6 +570,24 @@ typedef struct wmOperatorType {
 
 } wmOperatorType;
 
+#ifdef WITH_INPUT_IME
+/* *********** Input Method Editor (IME) *********** */
+
+/* similar to GHOST_TEventImeData */
+typedef struct wmIMEData {
+       size_t result_len, composite_len;
+
+       char *str_result;           /* utf8 encoding */
+       char *str_composite;        /* utf8 encoding */
+
+       int cursor_pos;             /* cursor position in the IME composition. */
+       int sel_start;              /* beginning of the selection */
+       int sel_end;                /* end of the selection */
+
+       bool is_ime_composing;
+} wmIMEData;
+#endif
+
 /* **************** Paint Cursor ******************* */
 
 typedef void (*wmPaintCursorDraw)(struct bContext *C, int, int, void *customdata);
index cca267a..3de34e7 100644 (file)
@@ -3373,6 +3373,33 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
                        break;
                }
 
+#ifdef WITH_INPUT_IME
+               case GHOST_kEventImeCompositionStart:
+               {
+                       event.val = KM_PRESS;
+                       win->ime_data = customdata;
+                       win->ime_data->is_ime_composing = true;
+                       event.type = WM_IME_COMPOSITE_START;
+                       wm_event_add(win, &event);
+                       break;
+               }
+               case GHOST_kEventImeComposition:
+               {
+                       event.val = KM_PRESS;
+                       event.type = WM_IME_COMPOSITE_EVENT;
+                       wm_event_add(win, &event);
+                       break;
+               }
+               case GHOST_kEventImeCompositionEnd:
+               {
+                       event.val = KM_PRESS;
+                       win->ime_data->is_ime_composing = false;
+                       event.type = WM_IME_COMPOSITE_END;
+                       wm_event_add(win, &event);
+                       break;
+               }
+#endif /* WITH_INPUT_IME */
+
        }
 
 #if 0
@@ -3479,5 +3506,12 @@ bool WM_event_is_tablet(const struct wmEvent *event)
        return (event->tablet_data) ? true : false;
 }
 
+#ifdef WITH_INPUT_IME
+/* most os using ctrl/oskey + space to switch ime, avoid added space */
+bool WM_event_is_ime_switch(const struct wmEvent *event) {
+       return event->val == KM_PRESS && event->type == SPACEKEY &&
+              (event->ctrl || event->oskey || event->shift || event->alt);
+}
+#endif
 
 /** \} */
index 46a20d3..0b33dbb 100644 (file)
@@ -1524,3 +1524,20 @@ bool WM_window_is_fullscreen(wmWindow *win)
        return win->windowstate == GHOST_kWindowStateFullScreen;
 }
 
+
+#ifdef WITH_INPUT_IME
+void wm_window_IME_begin(wmWindow *win, int x, int y, int w, int h, bool complete)
+{
+       BLI_assert(win && (win->ime_data == NULL));
+
+       GHOST_BeginIME(win->ghostwin, x, win->sizey - y, w, h, complete);
+}
+
+void wm_window_IME_end(wmWindow *win)
+{
+       BLI_assert(win && win->ime_data);
+
+       GHOST_EndIME(win->ghostwin);
+       win->ime_data = NULL;
+}
+#endif  /* WITH_INPUT_IME */
index fe6d343..2301405 100644 (file)
@@ -86,6 +86,13 @@ enum {
         * paint and drawing tools however will want to handle these. */
        INBETWEEN_MOUSEMOVE = 0x0011,
 
+/* IME event, GHOST_kEventImeCompositionStart in ghost */
+       WM_IME_COMPOSITE_START = 0x0014,
+/* IME event, GHOST_kEventImeComposition in ghost */
+       WM_IME_COMPOSITE_EVENT      = 0x0015,
+/* IME event, GHOST_kEventImeCompositionEnd in ghost */
+       WM_IME_COMPOSITE_END   = 0x0016,
+
        /* *** Start of keyboard codes. *** */
 
        /* standard keyboard.
index 9c9c79d..833234b 100644 (file)
@@ -69,6 +69,11 @@ wmWindow     *wm_window_copy                 (bContext *C, wmWindow *winorig);
 
 void           wm_window_testbreak             (void);
 
+#ifdef WITH_INPUT_IME
+void           wm_window_IME_begin     (wmWindow *win, int x, int y, int w, int h, bool complete);
+void           wm_window_IME_end       (wmWindow *win);
+#endif
+
 /* *************** window operators ************** */
 int                    wm_window_duplicate_exec(bContext *C, struct wmOperator *op);
 int                    wm_window_fullscreen_toggle_exec(bContext *C, struct wmOperator *op);