Changeset View
Changeset View
Standalone View
Standalone View
intern/ghost/intern/GHOST_ImeWin32.cpp
| Show All 26 Lines | |||||
| # include "GHOST_ImeWin32.h" | # include "GHOST_ImeWin32.h" | ||||
| # include "GHOST_C-api.h" | # include "GHOST_C-api.h" | ||||
| # include "GHOST_WindowWin32.h" | # include "GHOST_WindowWin32.h" | ||||
| # include "utfconv.h" | # include "utfconv.h" | ||||
| GHOST_ImeWin32::GHOST_ImeWin32() | GHOST_ImeWin32::GHOST_ImeWin32() | ||||
| : is_composing_(false), | : is_composing_(false), | ||||
| ime_status_(false), | |||||
| input_language_id_(LANG_USER_DEFAULT), | input_language_id_(LANG_USER_DEFAULT), | ||||
| resultInfo(), | |||||
| compInfo(), | |||||
| system_caret_(false), | system_caret_(false), | ||||
| caret_rect_(-1, -1, 0, 0), | caret_rect_(-1, -1, 0, 0), | ||||
| is_first(true), | is_first(true), | ||||
| is_enable(true) | is_enable(true) | ||||
| { | { | ||||
| } | } | ||||
| GHOST_ImeWin32::~GHOST_ImeWin32() | GHOST_ImeWin32::~GHOST_ImeWin32() | ||||
| { | { | ||||
| } | } | ||||
| bool GHOST_ImeWin32::SetInputLanguage() | void GHOST_ImeWin32::SetInputLanguage() | ||||
| { | { | ||||
| /** | /** | ||||
| * Retrieve the current keyboard layout from Windows and determine whether | * Retrieve the current input language from the system's keyboard layout. | ||||
| * or not the current input context has IMEs. | * Using GetKeyboardLayoutName instead of GetKeyboardLayout, because | ||||
| * Also save its input language for language-specific operations required | * the language from GetKeyboardLayout is the language under where the | ||||
| * while composing a text. | * keyboard layout is installed. And the language from GetKeyboardLayoutName | ||||
| */ | * indicates the language of the keyboard layout itself. | ||||
| HKL keyboard_layout = ::GetKeyboardLayout(0); | * See crbug.com/344834. | ||||
| input_language_id_ = LOWORD(keyboard_layout); | */ | ||||
| ime_status_ = ::ImmIsIME(keyboard_layout); | WCHAR keyboard_layout[KL_NAMELENGTH]; | ||||
| return ime_status_; | if (::GetKeyboardLayoutNameW(keyboard_layout)) { | ||||
| input_language_id_ = static_cast<LANGID>( | |||||
| wcstol(&keyboard_layout[KL_NAMELENGTH >> 1], nullptr, 16)); | |||||
| } | |||||
| else { | |||||
| input_language_id_ = 0x0409; // Fallback to en-US. | |||||
| } | |||||
| } | } | ||||
| void GHOST_ImeWin32::CreateImeWindow(HWND window_handle) | void GHOST_ImeWin32::CreateImeWindow(HWND window_handle) | ||||
| { | { | ||||
| /** | /** | ||||
| * When a user disables TSF (Text Service Framework) and CUAS (Cicero | * When a user disables TSF (Text Service Framework) and CUAS (Cicero | ||||
| * Unaware Application Support), Chinese IMEs somehow ignore function calls | * Unaware Application Support), Chinese IMEs somehow ignore function calls | ||||
| * to ::ImmSetCandidateWindow(), i.e. they do not move their candidate | * to ::ImmSetCandidateWindow(), i.e. they do not move their candidate | ||||
| Show All 15 Lines | void GHOST_ImeWin32::CreateImeWindow(HWND window_handle) | ||||
| } | } | ||||
| /* Restore the positions of the IME windows. */ | /* Restore the positions of the IME windows. */ | ||||
| UpdateImeWindow(window_handle); | UpdateImeWindow(window_handle); | ||||
| } | } | ||||
| void GHOST_ImeWin32::SetImeWindowStyle( | void GHOST_ImeWin32::SetImeWindowStyle( | ||||
| HWND window_handle, UINT message, WPARAM wparam, LPARAM lparam, BOOL *handled) | HWND window_handle, UINT message, WPARAM wparam, LPARAM lparam, BOOL *handled) | ||||
| { | { | ||||
| if (message = !WM_IME_COMPOSITION || PRIMARYLANGID(input_language_id_) == LANG_CHINESE) { | |||||
| return; | |||||
| } | |||||
| /** | /** | ||||
| * To prevent the IMM (Input Method Manager) from displaying the IME | * To prevent the IMM (Input Method Manager) from displaying the IME | ||||
| * composition window, Update the styles of the IME windows and EXPLICITLY | * composition window, Update the styles of the IME windows and EXPLICITLY | ||||
| * call ::DefWindowProc() here. | * call ::DefWindowProc() here. | ||||
| * NOTE(hbono): We can NEVER let WTL call ::DefWindowProc() when we update | * NOTE(hbono): We can NEVER let WTL call ::DefWindowProc() when we update | ||||
| * the styles of IME windows because the 'lparam' variable is a local one | * the styles of IME windows because the 'lparam' variable is a local one | ||||
| * and all its updates disappear in returning from this function, i.e. WTL | * and all its updates disappear in returning from this function, i.e. WTL | ||||
| * does not call ::DefWindowProc() with our updated 'lparam' value but call | * does not call ::DefWindowProc() with our updated 'lparam' value but call | ||||
| ▲ Show 20 Lines • Show All 131 Lines • ▼ Show 20 Lines | void GHOST_ImeWin32::GetCaret(HIMC imm_context, LPARAM lparam, ImeComposition *composition) | ||||
| * (which can contain one or more Japanese characters). | * (which can contain one or more Japanese characters). | ||||
| */ | */ | ||||
| int target_start = -1; | int target_start = -1; | ||||
| int target_end = -1; | int target_end = -1; | ||||
| switch (PRIMARYLANGID(input_language_id_)) { | switch (PRIMARYLANGID(input_language_id_)) { | ||||
| case LANG_KOREAN: | case LANG_KOREAN: | ||||
| if (lparam & CS_NOMOVECARET) { | if (lparam & CS_NOMOVECARET) { | ||||
| target_start = 0; | target_start = 0; | ||||
| target_end = 1; | target_end = 0; | ||||
| composition->cursor_position = 1; | |||||
| } | } | ||||
| break; | break; | ||||
| case LANG_CHINESE: { | case LANG_CHINESE: { | ||||
| int clause_size = ImmGetCompositionStringW(imm_context, GCS_COMPCLAUSE, NULL, 0); | int clause_size = ImmGetCompositionStringW(imm_context, GCS_COMPCLAUSE, NULL, 0); | ||||
| if (clause_size) { | if (clause_size) { | ||||
| static std::vector<unsigned long> clauses; | static std::vector<unsigned long> clauses; | ||||
| clause_size = clause_size / sizeof(clauses[0]); | clause_size = clause_size / sizeof(clauses[0]); | ||||
| clauses.resize(clause_size); | clauses.resize(clause_size); | ||||
| ▲ Show 20 Lines • Show All 114 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| bool result = false; | bool result = false; | ||||
| HIMC imm_context = ::ImmGetContext(window_handle); | HIMC imm_context = ::ImmGetContext(window_handle); | ||||
| if (imm_context) { | if (imm_context) { | ||||
| /* Copy the composition string to the ImeComposition object. */ | /* Copy the composition string to the ImeComposition object. */ | ||||
| result = GetString(imm_context, lparam, GCS_COMPSTR, composition); | result = GetString(imm_context, lparam, GCS_COMPSTR, composition); | ||||
| /* Retrieve the cursor position in the IME composition. */ | /* Retrieve the cursor position in the IME composition. */ | ||||
| int cursor_position = ::ImmGetCompositionStringW(imm_context, GCS_CURSORPOS, NULL, 0); | if (!(lparam & CS_NOMOVECARET) && (lparam & GCS_CURSORPOS)) { | ||||
| composition->cursor_position = cursor_position; | composition->cursor_position = ::ImmGetCompositionStringW( | ||||
| imm_context, GCS_CURSORPOS, NULL, 0); | |||||
| } | |||||
| composition->target_start = -1; | composition->target_start = -1; | ||||
| composition->target_end = -1; | composition->target_end = -1; | ||||
| /* Retrieve the target selection and Update the ImeComposition object. */ | /* Retrieve the target selection and Update the ImeComposition object. */ | ||||
| GetCaret(imm_context, lparam, composition); | GetCaret(imm_context, lparam, composition); | ||||
| /* Mark that there is an ongoing composition. */ | /* Mark that there is an ongoing composition. */ | ||||
| is_composing_ = true; | is_composing_ = true; | ||||
| Show All 12 Lines | void GHOST_ImeWin32::EndIME(HWND window_handle) | ||||
| * For this case, we have to complete the ongoing composition and | * For this case, we have to complete the ongoing composition and | ||||
| * clean up the resources attached to this object BEFORE DISABLING THE IME. | * clean up the resources attached to this object BEFORE DISABLING THE IME. | ||||
| */ | */ | ||||
| if (!is_enable) | if (!is_enable) | ||||
| return; | return; | ||||
| is_enable = false; | is_enable = false; | ||||
| CleanupComposition(window_handle); | CleanupComposition(window_handle); | ||||
| ::ImmAssociateContextEx(window_handle, NULL, 0); | ::ImmAssociateContextEx(window_handle, NULL, 0); | ||||
| eventImeData.composite_len = 0; | } | ||||
| void GHOST_ImeWin32::CancelIME(HWND window_handle) | |||||
| { | |||||
| if (is_composing_) { | |||||
| HIMC imm_context = ::ImmGetContext(window_handle); | |||||
| if (imm_context) { | |||||
| ::ImmNotifyIME(imm_context, NI_COMPOSITIONSTR, CPS_CANCEL, 0); | |||||
| ::ImmReleaseContext(window_handle, imm_context); | |||||
| } | |||||
| ResetComposition(window_handle); | |||||
| } | |||||
| } | } | ||||
| void GHOST_ImeWin32::BeginIME(HWND window_handle, const GHOST_Rect &caret_rect, bool complete) | void GHOST_ImeWin32::BeginIME(HWND window_handle, const GHOST_Rect &caret_rect, bool complete) | ||||
| { | { | ||||
| if (is_enable && complete) | if (is_enable && complete) | ||||
| return; | return; | ||||
| is_enable = true; | is_enable = true; | ||||
| /** | /** | ||||
| ▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | static size_t updateUtf8Buf(ImeComposition &info) | ||||
| info.utf8_buf.resize(len); | info.utf8_buf.resize(len); | ||||
| conv_utf_16_to_8(info.ime_string.c_str(), &info.utf8_buf[0], len); | conv_utf_16_to_8(info.ime_string.c_str(), &info.utf8_buf[0], len); | ||||
| convert_utf16_to_utf8_len(info.ime_string, info.cursor_position); | convert_utf16_to_utf8_len(info.ime_string, info.cursor_position); | ||||
| convert_utf16_to_utf8_len(info.ime_string, info.target_start); | convert_utf16_to_utf8_len(info.ime_string, info.target_start); | ||||
| convert_utf16_to_utf8_len(info.ime_string, info.target_end); | convert_utf16_to_utf8_len(info.ime_string, info.target_end); | ||||
| return len - 1; | return len - 1; | ||||
| } | } | ||||
| void GHOST_ImeWin32::UpdateInfo(HWND window_handle) | GHOST_TEventImeData *GHOST_ImeWin32::UpdateInfo(HWND window_handle, LPARAM lparam) | ||||
| { | { | ||||
| int res = this->GetResult(window_handle, GCS_RESULTSTR, &resultInfo); | int res = this->GetResult(window_handle, lparam, &resultInfo); | ||||
| int comp = this->GetComposition(window_handle, GCS_COMPSTR | GCS_COMPATTR, &compInfo); | int comp = this->GetComposition(window_handle, lparam, &compInfo); | ||||
| /* convert wchar to utf8 */ | /* convert wchar to utf8 */ | ||||
| if (res) { | if (res) { | ||||
| ResetComposition(window_handle); | |||||
| eventImeData.result_len = (GHOST_TUserDataPtr)updateUtf8Buf(resultInfo); | eventImeData.result_len = (GHOST_TUserDataPtr)updateUtf8Buf(resultInfo); | ||||
| eventImeData.result = &resultInfo.utf8_buf[0]; | eventImeData.result = &resultInfo.utf8_buf[0]; | ||||
| } | } | ||||
| else { | else { | ||||
| eventImeData.result = 0; | eventImeData.result = 0; | ||||
| eventImeData.result_len = 0; | eventImeData.result_len = 0; | ||||
| } | } | ||||
| if (comp) { | if (comp) { | ||||
| eventImeData.composite_len = (GHOST_TUserDataPtr)updateUtf8Buf(compInfo); | eventImeData.composite_len = (GHOST_TUserDataPtr)updateUtf8Buf(compInfo); | ||||
| eventImeData.composite = &compInfo.utf8_buf[0]; | eventImeData.composite = &compInfo.utf8_buf[0]; | ||||
| eventImeData.cursor_position = compInfo.cursor_position; | eventImeData.cursor_position = compInfo.cursor_position; | ||||
| eventImeData.target_start = compInfo.target_start; | eventImeData.target_start = compInfo.target_start; | ||||
| eventImeData.target_end = compInfo.target_end; | eventImeData.target_end = compInfo.target_end; | ||||
| } | } | ||||
| else { | else { | ||||
| eventImeData.composite = 0; | eventImeData.composite = 0; | ||||
| eventImeData.composite_len = 0; | eventImeData.composite_len = 0; | ||||
| eventImeData.cursor_position = -1; | eventImeData.cursor_position = -1; | ||||
| eventImeData.target_start = -1; | eventImeData.target_start = -1; | ||||
| eventImeData.target_end = -1; | eventImeData.target_end = -1; | ||||
| } | } | ||||
| return &eventImeData; | |||||
| } | } | ||||
| #endif // WITH_INPUT_IME | #endif // WITH_INPUT_IME | ||||