16 # define IMELANG_ENGLISH "en"
17 # define IMELANG_CHINESE "zh"
18 # define IMELANG_JAPANESE "ja"
19 # define IMELANG_KOREAN "ko"
21 GHOST_ImeWin32::GHOST_ImeWin32()
22 : is_composing_(false),
23 language_(IMELANG_ENGLISH),
24 conversion_modes_(IME_CMODE_ALPHANUMERIC),
25 sentence_mode_(IME_SMODE_NONE),
27 caret_rect_(-1, -1, 0, 0),
33 GHOST_ImeWin32::~GHOST_ImeWin32()
37 void GHOST_ImeWin32::UpdateInputLanguage()
40 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
42 MAKELCID(LOWORD(::GetKeyboardLayout(0)), SORT_DEFAULT), locale, LOCALE_NAME_MAX_LENGTH, 0);
44 WCHAR language_u16[W32_ISO639_LEN];
45 GetLocaleInfoEx(locale, LOCALE_SISO639LANGNAME, language_u16, W32_ISO639_LEN);
48 CP_UTF8, 0, language_u16, W32_ISO639_LEN, language_, W32_ISO639_LEN,
NULL,
NULL);
51 BOOL GHOST_ImeWin32::IsLanguage(
const char name[W32_ISO639_LEN])
53 return (strcmp(name, language_) == 0);
56 void GHOST_ImeWin32::UpdateConversionStatus(HWND window_handle)
58 HIMC imm_context = ::ImmGetContext(window_handle);
60 if (::ImmGetOpenStatus(imm_context)) {
61 ::ImmGetConversionStatus(imm_context, &conversion_modes_, &sentence_mode_);
64 conversion_modes_ = IME_CMODE_ALPHANUMERIC;
65 sentence_mode_ = IME_SMODE_NONE;
67 ::ImmReleaseContext(window_handle, imm_context);
70 conversion_modes_ = IME_CMODE_ALPHANUMERIC;
71 sentence_mode_ = IME_SMODE_NONE;
75 bool GHOST_ImeWin32::IsEnglishMode()
77 return (conversion_modes_ & IME_CMODE_NOCONVERSION) ||
78 !(conversion_modes_ & (IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE));
81 bool GHOST_ImeWin32::IsImeKeyEvent(
char ascii,
GHOST_TKey key)
83 if (!(IsEnglishMode())) {
85 if ((ascii >=
'A' && ascii <=
'Z') || (ascii >=
'a' && ascii <=
'z')) {
88 if (IsLanguage(IMELANG_JAPANESE) && (ascii >=
' ' && ascii <=
'~')) {
91 if (IsLanguage(IMELANG_CHINESE)) {
95 if (conversion_modes_ & IME_CMODE_FULLSHAPE && (ascii >=
'0' && ascii <=
'9')) {
104 void GHOST_ImeWin32::CreateImeWindow(HWND window_handle)
118 if (!system_caret_ && (IsLanguage(IMELANG_CHINESE) || IsLanguage(IMELANG_JAPANESE))) {
119 system_caret_ = ::CreateCaret(window_handle,
NULL, 1, 1);
122 UpdateImeWindow(window_handle);
125 void GHOST_ImeWin32::SetImeWindowStyle(
126 HWND window_handle,
UINT message, WPARAM wparam, LPARAM lparam, BOOL *handled)
139 lparam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
140 ::DefWindowProc(window_handle, message, wparam, lparam);
143 void GHOST_ImeWin32::DestroyImeWindow(HWND window_handle)
148 system_caret_ =
false;
152 void GHOST_ImeWin32::MoveImeWindow(HWND window_handle, HIMC imm_context)
154 int x = caret_rect_.m_l;
155 int y = caret_rect_.m_t;
156 const int kCaretMargin = 1;
169 CANDIDATEFORM candidate_position = {0, CFS_CANDIDATEPOS, {
x,
y}, {0, 0, 0, 0}};
170 ::ImmSetCandidateWindow(imm_context, &candidate_position);
174 if (IsLanguage(IMELANG_KOREAN)) {
189 CANDIDATEFORM exclude_rectangle = {
190 0, CFS_EXCLUDE, {
x,
y}, {
x,
y,
x + caret_rect_.getWidth(),
y + caret_rect_.getHeight()}};
191 ::ImmSetCandidateWindow(imm_context, &exclude_rectangle);
194 void GHOST_ImeWin32::UpdateImeWindow(HWND window_handle)
197 if (caret_rect_.m_l >= 0 && caret_rect_.m_t >= 0) {
198 HIMC imm_context = ::ImmGetContext(window_handle);
200 MoveImeWindow(window_handle, imm_context);
201 ::ImmReleaseContext(window_handle, imm_context);
206 void GHOST_ImeWin32::CleanupComposition(HWND window_handle)
214 HIMC imm_context = ::ImmGetContext(window_handle);
216 ::ImmNotifyIME(imm_context, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
217 ::ImmReleaseContext(window_handle, imm_context);
219 ResetComposition(window_handle);
223 void GHOST_ImeWin32::CheckFirst(HWND window_handle)
226 this->EndIME(window_handle);
231 void GHOST_ImeWin32::ResetComposition(HWND window_handle)
234 is_composing_ =
false;
237 void GHOST_ImeWin32::CompleteComposition(HWND window_handle, HIMC imm_context)
245 ::ImmNotifyIME(imm_context, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
246 ResetComposition(window_handle);
250 void GHOST_ImeWin32::GetCaret(HIMC imm_context, LPARAM lparam, ImeComposition *composition)
262 int target_start = -1;
264 if (IsLanguage(IMELANG_KOREAN)) {
265 if (lparam & CS_NOMOVECARET) {
270 else if (IsLanguage(IMELANG_CHINESE)) {
271 int clause_size = ImmGetCompositionStringW(imm_context, GCS_COMPCLAUSE,
NULL, 0);
273 static std::vector<unsigned long> clauses;
274 clause_size = clause_size /
sizeof(clauses[0]);
275 clauses.resize(clause_size);
276 ImmGetCompositionStringW(
277 imm_context, GCS_COMPCLAUSE, &clauses[0],
sizeof(clauses[0]) * clause_size);
278 if (composition->cursor_position == composition->ime_string.size()) {
279 target_start = clauses[clause_size - 2];
280 target_end = clauses[clause_size - 1];
283 for (
int i = 0; i < clause_size - 1; i++) {
284 if (clauses[i] == composition->cursor_position) {
285 target_start = clauses[i];
286 target_end = clauses[i + 1];
293 if (composition->cursor_position != -1) {
294 target_start = composition->cursor_position;
295 target_end = composition->ime_string.size();
299 else if (IsLanguage(IMELANG_JAPANESE)) {
306 if (lparam & GCS_COMPATTR) {
307 int attribute_size = ::ImmGetCompositionStringW(imm_context, GCS_COMPATTR,
NULL, 0);
308 if (attribute_size > 0) {
309 char *attribute_data =
new char[attribute_size];
310 if (attribute_data) {
311 ::ImmGetCompositionStringW(imm_context, GCS_COMPATTR, attribute_data, attribute_size);
312 for (target_start = 0; target_start < attribute_size; ++target_start) {
313 if (IsTargetAttribute(attribute_data[target_start]))
316 for (target_end = target_start; target_end < attribute_size; ++target_end) {
317 if (!IsTargetAttribute(attribute_data[target_end]))
320 if (target_start == attribute_size) {
326 target_end = target_start;
329 if (target_start != -1 && target_start < attribute_size &&
330 attribute_data[target_start] == ATTR_TARGET_NOTCONVERTED) {
331 composition->cursor_position = target_start;
334 delete[] attribute_data;
338 composition->target_start = target_start;
339 composition->target_end = target_end;
342 bool GHOST_ImeWin32::GetString(HIMC imm_context,
345 ImeComposition *composition)
349 int string_size = ::ImmGetCompositionStringW(imm_context,
type,
NULL, 0);
350 if (string_size > 0) {
351 int string_length = string_size /
sizeof(wchar_t);
352 wchar_t *string_data =
new wchar_t[string_length + 1];
353 string_data[string_length] =
'\0';
356 ::ImmGetCompositionStringW(imm_context,
type, string_data, string_size);
357 composition->string_type =
type;
358 composition->ime_string = string_data;
361 delete[] string_data;
367 bool GHOST_ImeWin32::GetResult(HWND window_handle, LPARAM lparam, ImeComposition *composition)
370 HIMC imm_context = ::ImmGetContext(window_handle);
373 result = GetString(imm_context, lparam, GCS_RESULTSTR, composition);
378 composition->cursor_position = -1;
379 composition->target_start = -1;
380 composition->target_end = -1;
381 ::ImmReleaseContext(window_handle, imm_context);
386 bool GHOST_ImeWin32::GetComposition(HWND window_handle, LPARAM lparam, ImeComposition *composition)
389 HIMC imm_context = ::ImmGetContext(window_handle);
392 result = GetString(imm_context, lparam, GCS_COMPSTR, composition);
395 int cursor_position = ::ImmGetCompositionStringW(imm_context, GCS_CURSORPOS,
NULL, 0);
396 composition->cursor_position = cursor_position;
397 composition->target_start = -1;
398 composition->target_end = -1;
401 GetCaret(imm_context, lparam, composition);
404 is_composing_ =
true;
406 ::ImmReleaseContext(window_handle, imm_context);
411 void GHOST_ImeWin32::EndIME(HWND window_handle)
423 CleanupComposition(window_handle);
424 ::ImmAssociateContextEx(window_handle,
NULL, 0);
425 eventImeData.composite_len = 0;
428 void GHOST_ImeWin32::BeginIME(HWND window_handle,
const GHOST_Rect &caret_rect,
bool complete)
430 if (is_enable && complete)
439 ::ImmAssociateContextEx(window_handle,
NULL, IACE_DEFAULT);
441 HIMC imm_context = ::ImmGetContext(window_handle);
452 CompleteComposition(window_handle, imm_context);
459 if (caret_rect.
m_l >= 0 && caret_rect.
m_t >= 0) {
460 caret_rect_ = caret_rect;
461 MoveImeWindow(window_handle, imm_context);
463 ::ImmReleaseContext(window_handle, imm_context);
467 static void convert_utf16_to_utf8_len(std::wstring s,
int &
len)
469 if (
len >= 0 &&
len <= s.size())
475 static size_t updateUtf8Buf(ImeComposition &info)
478 info.utf8_buf.resize(
len);
480 convert_utf16_to_utf8_len(info.ime_string, info.cursor_position);
481 convert_utf16_to_utf8_len(info.ime_string, info.target_start);
482 convert_utf16_to_utf8_len(info.ime_string, info.target_end);
486 void GHOST_ImeWin32::UpdateInfo(HWND window_handle)
488 int res = this->GetResult(window_handle, GCS_RESULTSTR, &resultInfo);
489 int comp = this->GetComposition(window_handle, GCS_COMPSTR | GCS_COMPATTR, &compInfo);
493 eventImeData.result = &resultInfo.utf8_buf[0];
496 eventImeData.result = 0;
497 eventImeData.result_len = 0;
501 eventImeData.composite = &compInfo.utf8_buf[0];
502 eventImeData.cursor_position = compInfo.cursor_position;
503 eventImeData.target_start = compInfo.target_start;
504 eventImeData.target_end = compInfo.target_end;
507 eventImeData.composite = 0;
508 eventImeData.composite_len = 0;
509 eventImeData.cursor_position = -1;
510 eventImeData.target_start = -1;
511 eventImeData.target_end = -1;
GHOST C-API function and type declarations.
void * GHOST_TUserDataPtr
typedef UINT(API *GHOST_WIN32_GetDpiForWindow)(HWND)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
size_t count_utf_8_from_16(const wchar_t *string16)
int conv_utf_16_to_8(const wchar_t *in16, char *out8, size_t size8)