diff options
author | Severin <julian_eisel@web.de> | 2014-12-07 02:58:17 +0300 |
---|---|---|
committer | Severin <julian_eisel@web.de> | 2014-12-07 02:58:17 +0300 |
commit | e81d077c852f43b635f10972479e36909a66d60c (patch) | |
tree | 35eabcec49938e0d66c083354fa6c0c600372a12 /intern | |
parent | 06515475b9c87c553d75481abfa600a0f7a5faf8 (diff) |
Input Method Editor (IME) support for text buttons
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!
Diffstat (limited to 'intern')
-rw-r--r-- | intern/ghost/CMakeLists.txt | 10 | ||||
-rw-r--r-- | intern/ghost/GHOST_C-api.h | 24 | ||||
-rw-r--r-- | intern/ghost/GHOST_IWindow.h | 23 | ||||
-rw-r--r-- | intern/ghost/GHOST_Types.h | 20 | ||||
-rw-r--r-- | intern/ghost/SConscript | 7 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_C-api.cpp | 18 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWin32.cpp | 65 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWin32.h | 9 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_Window.h | 16 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_WindowWin32.cpp | 13 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_WindowWin32.h | 19 |
11 files changed, 224 insertions, 0 deletions
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index 3ce269c2b4f..dc55a81b0d8 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -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 diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 7b47f0526a2..c0f2651dd8b 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -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 } diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index 71dc193a81b..3f8215dc7c2 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -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") diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 7333ba025a5..c4a7490c71c 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -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; diff --git a/intern/ghost/SConscript b/intern/ghost/SConscript index 5a4572c164d..a41fadf9ac7 100644 --- a/intern/ghost/SConscript +++ b/intern/ghost/SConscript @@ -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') diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index 5a2e638f01a..0da77ac5e20 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -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 */ diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 3b793fda968..4247c4f31ce 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -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 //////////////////////////////////////////////////////////////////////// diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index 79fed06c6a5..cb3b8ee3cfc 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -307,6 +307,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. */ diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index 15b81998aab..ac31c54666b 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -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. diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 64ea7192616..4e384881f2c 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -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 */ diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index 7b12d8c583e..c4575d0f9b0 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -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__ |