diff options
Diffstat (limited to 'src/video/win32_v.cpp')
-rw-r--r-- | src/video/win32_v.cpp | 71 |
1 files changed, 70 insertions, 1 deletions
diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index a6ca85c97..2e7b40902 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -52,6 +52,9 @@ bool _window_maximize; uint _display_hz; uint _fullscreen_bpp; static Dimension _bck_resolution; +#if !defined(WINCE) || _WIN32_WCE >= 0x400 +DWORD _imm_props; +#endif /** Whether the drawing is/may be done in a separate thread. */ static bool _draw_threaded; @@ -501,6 +504,12 @@ static LRESULT HandleCharMsg(uint keycode, WChar charcode) } #if !defined(WINCE) || _WIN32_WCE >= 0x400 +/** Should we draw the composition string ourself, i.e is this a normal IME? */ +static bool DrawIMECompositionString() +{ + return (_imm_props & IME_PROP_AT_CARET) && !(_imm_props & IME_PROP_SPECIAL_UI); +} + /** Set position of the composition window to the caret position. */ static void SetCompositionPos(HWND hwnd) { @@ -571,12 +580,50 @@ static LRESULT HandleIMEComposition(HWND hwnd, WPARAM wParam, LPARAM lParam) str[len / sizeof(TCHAR)] = '\0'; /* Transmit text to windowing system. */ - if (len > 0) HandleTextInput(FS2OTTD(str)); + if (len > 0) { + HandleTextInput(NULL, true); // Clear marked string. + HandleTextInput(FS2OTTD(str)); + } SetCompositionPos(hwnd); /* Don't pass the result string on to the default window proc. */ lParam &= ~(GCS_RESULTSTR | GCS_RESULTCLAUSE | GCS_RESULTREADCLAUSE | GCS_RESULTREADSTR); } + + if ((lParam & GCS_COMPSTR) && DrawIMECompositionString()) { + /* Read composition string from the IME. */ + LONG len = ImmGetCompositionString(hIMC, GCS_COMPSTR, NULL, 0); // Length is always in bytes, even in UNICODE build. + TCHAR *str = (TCHAR *)_alloca(len + sizeof(TCHAR)); + len = ImmGetCompositionString(hIMC, GCS_COMPSTR, str, len); + str[len / sizeof(TCHAR)] = '\0'; + + if (len > 0) { + static char utf8_buf[1024]; + convert_from_fs(str, utf8_buf, lengthof(utf8_buf)); + + /* Convert caret position from bytes in the input string to a position in the UTF-8 encoded string. */ + LONG caret_bytes = ImmGetCompositionString(hIMC, GCS_CURSORPOS, NULL, 0); + const char *caret = utf8_buf; + for (const TCHAR *c = str; *c != '\0' && *caret != '\0' && caret_bytes > 0; c++, caret_bytes--) { + /* Skip DBCS lead bytes or leading surrogates. */ +#ifdef UNICODE + if (Utf16IsLeadSurrogate(*c)) { +#else + if (IsDBCSLeadByte(*c)) { +#endif + c++; + caret_bytes--; + } + Utf8Consume(&caret); + } + + HandleTextInput(utf8_buf, true, caret); + } else { + HandleTextInput(NULL, true); + } + + lParam &= ~(GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE | GCS_CURSORPOS | GCS_DELTASTART); + } } ImmReleaseContext(hwnd, hIMC); @@ -589,10 +636,13 @@ static void CancelIMEComposition(HWND hwnd) HIMC hIMC = ImmGetContext(hwnd); if (hIMC != NULL) ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0); ImmReleaseContext(hwnd, hIMC); + /* Clear any marked string from the current edit box. */ + HandleTextInput(NULL, true); } #else +static bool DrawIMECompositionString() { return false; } static void SetCompositionPos(HWND hwnd) {} static void SetCandidatePos(HWND hwnd) {} static void CancelIMEComposition(HWND hwnd) {} @@ -609,6 +659,9 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP case WM_CREATE: SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, (TIMERPROC)TrackMouseTimerProc); SetCompositionPos(hwnd); +#if !defined(WINCE) || _WIN32_WCE >= 0x400 + _imm_props = ImmGetProperty(GetKeyboardLayout(0), IGP_PROPERTY); +#endif break; case WM_ENTERSIZEMOVE: @@ -735,13 +788,29 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP } #if !defined(WINCE) || _WIN32_WCE >= 0x400 + case WM_INPUTLANGCHANGE: + _imm_props = ImmGetProperty(GetKeyboardLayout(0), IGP_PROPERTY); + break; + + case WM_IME_SETCONTEXT: + /* Don't show the composition window if we draw the string ourself. */ + if (DrawIMECompositionString()) lParam &= ~ISC_SHOWUICOMPOSITIONWINDOW; + break; + case WM_IME_STARTCOMPOSITION: SetCompositionPos(hwnd); + if (DrawIMECompositionString()) return 0; break; case WM_IME_COMPOSITION: return HandleIMEComposition(hwnd, wParam, lParam); + case WM_IME_ENDCOMPOSITION: + /* Clear any pending composition string. */ + HandleTextInput(NULL, true); + if (DrawIMECompositionString()) return 0; + break; + case WM_IME_NOTIFY: if (wParam == IMN_OPENCANDIDATE) SetCandidatePos(hwnd); break; |