diff options
author | Harley Acheson <harley.acheson@gmail.com> | 2021-08-10 18:52:36 +0300 |
---|---|---|
committer | Harley Acheson <harley.acheson@gmail.com> | 2021-08-10 18:54:03 +0300 |
commit | 946da86e026e16cc607797d3ccb94f39269ca4ca (patch) | |
tree | e76b8e2195f0bf65876848e7d0fc78f323eecb22 /intern/ghost | |
parent | 6806459246255440aade69bc0e00a40325dfd95c (diff) |
Win32 IME: Replace Usage of Language IDs
This is a slight refactoring of the Win32 IME code to remove the use of
Language IDs, which is now strongly deprecated. Instead this uses the
new recommended Locale Names, ie ISO-639-1 2-letter abbreviated names
like "en" for English rather than ID 0x09.
See D12143 for more details.
Differential Revision: https://developer.blender.org/D12143
Reviewed by Ray Molenkamp
Diffstat (limited to 'intern/ghost')
-rw-r--r-- | intern/ghost/intern/GHOST_ImeWin32.cpp | 199 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_ImeWin32.h | 35 |
2 files changed, 99 insertions, 135 deletions
diff --git a/intern/ghost/intern/GHOST_ImeWin32.cpp b/intern/ghost/intern/GHOST_ImeWin32.cpp index 343f4d68078..47b5f5688df 100644 --- a/intern/ghost/intern/GHOST_ImeWin32.cpp +++ b/intern/ghost/intern/GHOST_ImeWin32.cpp @@ -30,9 +30,15 @@ # include "GHOST_WindowWin32.h" # include "utfconv.h" +/* ISO_639-1 2-Letter Abbreviations. */ +# define IMELANG_ENGLISH "en" +# define IMELANG_CHINESE "zh" +# define IMELANG_JAPANESE "ja" +# define IMELANG_KOREAN "ko" + GHOST_ImeWin32::GHOST_ImeWin32() : is_composing_(false), - input_language_id_(LANG_USER_DEFAULT), + language_(IMELANG_ENGLISH), conversion_modes_(IME_CMODE_ALPHANUMERIC), sentence_mode_(IME_SMODE_NONE), system_caret_(false), @@ -48,16 +54,21 @@ GHOST_ImeWin32::~GHOST_ImeWin32() void GHOST_ImeWin32::UpdateInputLanguage() { - /** - * Store the current input language. - */ - HKL input_locale = ::GetKeyboardLayout(0); - input_language_id_ = LOWORD(input_locale); + /* Get the current input locale full name. */ + WCHAR locale[LOCALE_NAME_MAX_LENGTH]; + LCIDToLocaleName( + MAKELCID(LOWORD(::GetKeyboardLayout(0)), SORT_DEFAULT), locale, LOCALE_NAME_MAX_LENGTH, 0); + /* Get the 2-letter ISO-63901 abbreviation of the input locale name. */ + WCHAR language_u16[W32_ISO639_LEN]; + GetLocaleInfoEx(locale, LOCALE_SISO639LANGNAME, language_u16, W32_ISO639_LEN); + /* Store this as a UTF-8 string. */ + WideCharToMultiByte( + CP_UTF8, 0, language_u16, W32_ISO639_LEN, language_, W32_ISO639_LEN, NULL, NULL); } -WORD GHOST_ImeWin32::GetInputLanguage() +BOOL GHOST_ImeWin32::IsLanguage(const char name[W32_ISO639_LEN]) { - return input_language_id_; + return (strcmp(name, language_) == 0); } void GHOST_ImeWin32::UpdateConversionStatus(HWND window_handle) @@ -92,21 +103,11 @@ bool GHOST_ImeWin32::IsImeKeyEvent(char ascii) if ((ascii >= 'A' && ascii <= 'Z') || (ascii >= 'a' && ascii <= 'z')) { return true; } - switch (PRIMARYLANGID(GetInputLanguage())) { - /* In Japanese, all symbolic characters are also processed by IME. */ - case LANG_JAPANESE: { - if (ascii >= ' ' && ascii <= '~') { - return true; - } - break; - } - /* In Chinese, some symbolic characters are also processed by IME. */ - case LANG_CHINESE: { - if (ascii && strchr("!\"$'(),.:;<>?[\\]^_`", ascii)) { - return true; - } - break; - } + if (IsLanguage(IMELANG_JAPANESE) && (ascii >= ' ' && ascii <= '~')) { + return true; + } + else if (IsLanguage(IMELANG_CHINESE) && ascii && strchr("!\"$'(),.:;<>?[\\]^_`", ascii)) { + return true; } } return false; @@ -126,13 +127,8 @@ void GHOST_ImeWin32::CreateImeWindow(HWND window_handle) * Since some third-party Japanese IME also uses ::GetCaretPos() to determine * their window position, we also create a caret for Japanese IMEs. */ - if (PRIMARYLANGID(input_language_id_) == LANG_CHINESE || - PRIMARYLANGID(input_language_id_) == LANG_JAPANESE) { - if (!system_caret_) { - if (::CreateCaret(window_handle, NULL, 1, 1)) { - system_caret_ = true; - } - } + if (!system_caret_ && (IsLanguage(IMELANG_CHINESE) || IsLanguage(IMELANG_JAPANESE))) { + system_caret_ = ::CreateCaret(window_handle, NULL, 1, 1); } /* Restore the positions of the IME windows. */ UpdateImeWindow(window_handle); @@ -185,16 +181,9 @@ void GHOST_ImeWin32::MoveImeWindow(HWND window_handle, HIMC imm_context) CANDIDATEFORM candidate_position = {0, CFS_CANDIDATEPOS, {x, y}, {0, 0, 0, 0}}; ::ImmSetCandidateWindow(imm_context, &candidate_position); if (system_caret_) { - switch (PRIMARYLANGID(input_language_id_)) { - case LANG_JAPANESE: - ::SetCaretPos(x, y + caret_rect_.getHeight()); - break; - default: - ::SetCaretPos(x, y); - break; - } + ::SetCaretPos(x, y); } - if (PRIMARYLANGID(input_language_id_) == LANG_KOREAN) { + if (IsLanguage(IMELANG_KOREAN)) { /** * Chinese IMEs and Japanese IMEs require the upper-left corner of * the caret to move the position of their candidate windows. @@ -284,83 +273,79 @@ void GHOST_ImeWin32::GetCaret(HIMC imm_context, LPARAM lparam, ImeComposition *c */ int target_start = -1; int target_end = -1; - switch (PRIMARYLANGID(input_language_id_)) { - case LANG_KOREAN: - if (lparam & CS_NOMOVECARET) { - target_start = 0; - target_end = 1; + if (IsLanguage(IMELANG_KOREAN)) { + if (lparam & CS_NOMOVECARET) { + target_start = 0; + target_end = 1; + } + } + else if (IsLanguage(IMELANG_CHINESE)) { + int clause_size = ImmGetCompositionStringW(imm_context, GCS_COMPCLAUSE, NULL, 0); + if (clause_size) { + static std::vector<unsigned long> clauses; + clause_size = clause_size / sizeof(clauses[0]); + clauses.resize(clause_size); + ImmGetCompositionStringW( + imm_context, GCS_COMPCLAUSE, &clauses[0], sizeof(clauses[0]) * clause_size); + if (composition->cursor_position == composition->ime_string.size()) { + target_start = clauses[clause_size - 2]; + target_end = clauses[clause_size - 1]; } - break; - case LANG_CHINESE: { - int clause_size = ImmGetCompositionStringW(imm_context, GCS_COMPCLAUSE, NULL, 0); - if (clause_size) { - static std::vector<unsigned long> clauses; - clause_size = clause_size / sizeof(clauses[0]); - clauses.resize(clause_size); - ImmGetCompositionStringW( - imm_context, GCS_COMPCLAUSE, &clauses[0], sizeof(clauses[0]) * clause_size); - if (composition->cursor_position == composition->ime_string.size()) { - target_start = clauses[clause_size - 2]; - target_end = clauses[clause_size - 1]; - } - else { - for (int i = 0; i < clause_size - 1; i++) { - if (clauses[i] == composition->cursor_position) { - target_start = clauses[i]; - target_end = clauses[i + 1]; - break; - } + else { + for (int i = 0; i < clause_size - 1; i++) { + if (clauses[i] == composition->cursor_position) { + target_start = clauses[i]; + target_end = clauses[i + 1]; + break; } } } - else { - if (composition->cursor_position != -1) { - target_start = composition->cursor_position; - target_end = composition->ime_string.size(); - } + } + else { + if (composition->cursor_position != -1) { + target_start = composition->cursor_position; + target_end = composition->ime_string.size(); } - break; } - case LANG_JAPANESE: - - /** - * For Japanese IMEs, the robustest way to retrieve the caret - * is scanning the attribute of the latest composition string and - * retrieving the beginning and the end of the target clause, i.e. - * a clause being converted. - */ - if (lparam & GCS_COMPATTR) { - int attribute_size = ::ImmGetCompositionStringW(imm_context, GCS_COMPATTR, NULL, 0); - if (attribute_size > 0) { - char *attribute_data = new char[attribute_size]; - if (attribute_data) { - ::ImmGetCompositionStringW(imm_context, GCS_COMPATTR, attribute_data, attribute_size); - for (target_start = 0; target_start < attribute_size; ++target_start) { - if (IsTargetAttribute(attribute_data[target_start])) - break; - } - for (target_end = target_start; target_end < attribute_size; ++target_end) { - if (!IsTargetAttribute(attribute_data[target_end])) - break; - } - if (target_start == attribute_size) { - /** - * This composition clause does not contain any target clauses, - * i.e. this clauses is an input clause. - * We treat whole this clause as a target clause. - */ - target_end = target_start; - target_start = 0; - } - if (target_start != -1 && target_start < attribute_size && - attribute_data[target_start] == ATTR_TARGET_NOTCONVERTED) { - composition->cursor_position = target_start; - } + } + else if (IsLanguage(IMELANG_JAPANESE)) { + /** + * For Japanese IMEs, the robustest way to retrieve the caret + * is scanning the attribute of the latest composition string and + * retrieving the beginning and the end of the target clause, i.e. + * a clause being converted. + */ + if (lparam & GCS_COMPATTR) { + int attribute_size = ::ImmGetCompositionStringW(imm_context, GCS_COMPATTR, NULL, 0); + if (attribute_size > 0) { + char *attribute_data = new char[attribute_size]; + if (attribute_data) { + ::ImmGetCompositionStringW(imm_context, GCS_COMPATTR, attribute_data, attribute_size); + for (target_start = 0; target_start < attribute_size; ++target_start) { + if (IsTargetAttribute(attribute_data[target_start])) + break; + } + for (target_end = target_start; target_end < attribute_size; ++target_end) { + if (!IsTargetAttribute(attribute_data[target_end])) + break; + } + if (target_start == attribute_size) { + /** + * This composition clause does not contain any target clauses, + * i.e. this clauses is an input clause. + * We treat whole this clause as a target clause. + */ + target_end = target_start; + target_start = 0; + } + if (target_start != -1 && target_start < attribute_size && + attribute_data[target_start] == ATTR_TARGET_NOTCONVERTED) { + composition->cursor_position = target_start; } - delete[] attribute_data; } + delete[] attribute_data; } - break; + } } composition->target_start = target_start; composition->target_end = target_end; diff --git a/intern/ghost/intern/GHOST_ImeWin32.h b/intern/ghost/intern/GHOST_ImeWin32.h index d430a7d745d..ce0e4d64d53 100644 --- a/intern/ghost/intern/GHOST_ImeWin32.h +++ b/intern/ghost/intern/GHOST_ImeWin32.h @@ -36,6 +36,9 @@ # include "GHOST_Rect.h" # include <vector> +/* MSDN LOCALE_SISO639LANGNAME states maximum length of 9, including terminating null. */ +# define W32_ISO639_LEN 9 + class GHOST_EventIME : public GHOST_Event { public: /** @@ -146,13 +149,10 @@ class GHOST_ImeWin32 { return is_composing_; } - /** - * Retrieves the input language from Windows and update it. - */ + /* Retrieve the input language from Windows and store it. */ void UpdateInputLanguage(); - /* Returns the current input language id. */ - WORD GetInputLanguage(); + BOOL IsLanguage(const char name[W32_ISO639_LEN]); /* Saves the current conversion status. */ void UpdateConversionStatus(HWND window_handle); @@ -345,29 +345,8 @@ class GHOST_ImeWin32 { */ bool is_composing_; - /** - * The current input Language ID retrieved from Windows, which consists of: - * * Primary Language ID (bit 0 to bit 9), which shows a natural language - * (English, Korean, Chinese, Japanese, etc.) and; - * * Sub-Language ID (bit 10 to bit 15), which shows a geometrical region - * the language is spoken (For English, United States, United Kingdom, - * Australia, Canada, etc.) - * The following list enumerates some examples for the Language ID: - * * "en-US" (0x0409) - * MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); - * * "ko-KR" (0x0412) - * MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN); - * * "zh-TW" (0x0404) - * MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL); - * * "zh-CN" (0x0804) - * MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED); - * * "ja-JP" (0x0411) - * MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), etc. - * (See `winnt.h` for other available values.) - * This Language ID is used for processing language-specific operations in - * IME functions. - */ - LANGID input_language_id_; + /* Abbreviated ISO 639-1 name of the input language, such as "en" for English. */ + char language_[W32_ISO639_LEN]; /* Current Conversion Mode Values. Retrieved with ImmGetConversionStatus. */ DWORD conversion_modes_; |