Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarley Acheson <harley.acheson@gmail.com>2021-08-10 18:52:36 +0300
committerHarley Acheson <harley.acheson@gmail.com>2021-08-10 18:54:03 +0300
commit946da86e026e16cc607797d3ccb94f39269ca4ca (patch)
treee76b8e2195f0bf65876848e7d0fc78f323eecb22
parent6806459246255440aade69bc0e00a40325dfd95c (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
-rw-r--r--intern/ghost/intern/GHOST_ImeWin32.cpp199
-rw-r--r--intern/ghost/intern/GHOST_ImeWin32.h35
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_;