diff options
author | Jacek Antonelli | 2008-08-15 23:45:27 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:45:27 -0500 |
commit | a8a62201ba762e98dff92cf49033e577fc34d8d4 (patch) | |
tree | 11f8513c5cdc222f2fac0c93eb724c089803c200 /linden/indra/llwindow/llwindowwin32.cpp | |
parent | Second Life viewer sources 1.18.6.4-RC (diff) | |
download | meta-impy-a8a62201ba762e98dff92cf49033e577fc34d8d4.zip meta-impy-a8a62201ba762e98dff92cf49033e577fc34d8d4.tar.gz meta-impy-a8a62201ba762e98dff92cf49033e577fc34d8d4.tar.bz2 meta-impy-a8a62201ba762e98dff92cf49033e577fc34d8d4.tar.xz |
Second Life viewer sources 1.19.0.0
Diffstat (limited to 'linden/indra/llwindow/llwindowwin32.cpp')
-rw-r--r-- | linden/indra/llwindow/llwindowwin32.cpp | 663 |
1 files changed, 638 insertions, 25 deletions
diff --git a/linden/indra/llwindow/llwindowwin32.cpp b/linden/indra/llwindow/llwindowwin32.cpp index 2fcb36c..171cc09 100644 --- a/linden/indra/llwindow/llwindowwin32.cpp +++ b/linden/indra/llwindow/llwindowwin32.cpp | |||
@@ -12,12 +12,12 @@ | |||
12 | * ("GPL"), unless you have obtained a separate licensing agreement | 12 | * ("GPL"), unless you have obtained a separate licensing agreement |
13 | * ("Other License"), formally executed by you and Linden Lab. Terms of | 13 | * ("Other License"), formally executed by you and Linden Lab. Terms of |
14 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | 14 | * the GPL can be found in doc/GPL-license.txt in this distribution, or |
15 | * online at http://secondlife.com/developers/opensource/gplv2 | 15 | * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 |
16 | * | 16 | * |
17 | * There are special exceptions to the terms and conditions of the GPL as | 17 | * There are special exceptions to the terms and conditions of the GPL as |
18 | * it is applied to this Source Code. View the full text of the exception | 18 | * it is applied to this Source Code. View the full text of the exception |
19 | * in the file doc/FLOSS-exception.txt in this software distribution, or | 19 | * in the file doc/FLOSS-exception.txt in this software distribution, or |
20 | * online at http://secondlife.com/developers/opensource/flossexception | 20 | * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception |
21 | * | 21 | * |
22 | * By copying, modifying or distributing this software, you acknowledge | 22 | * By copying, modifying or distributing this software, you acknowledge |
23 | * that you have read and understood your obligations described above, | 23 | * that you have read and understood your obligations described above, |
@@ -57,6 +57,8 @@ | |||
57 | 57 | ||
58 | #include "indra_constants.h" | 58 | #include "indra_constants.h" |
59 | 59 | ||
60 | #include "llpreeditor.h" | ||
61 | |||
60 | // culled from winuser.h | 62 | // culled from winuser.h |
61 | #ifndef WM_MOUSEWHEEL /* Added to be compatible with later SDK's */ | 63 | #ifndef WM_MOUSEWHEEL /* Added to be compatible with later SDK's */ |
62 | const S32 WM_MOUSEWHEEL = 0x020A; | 64 | const S32 WM_MOUSEWHEEL = 0x020A; |
@@ -82,7 +84,6 @@ LLW32MsgCallback gAsyncMsgCallback = NULL; | |||
82 | void show_window_creation_error(const char* title) | 84 | void show_window_creation_error(const char* title) |
83 | { | 85 | { |
84 | llwarns << title << llendl; | 86 | llwarns << title << llendl; |
85 | shell_open( "help/window_creation_error.html"); | ||
86 | } | 87 | } |
87 | 88 | ||
88 | //static | 89 | //static |
@@ -112,6 +113,7 @@ public: | |||
112 | public: | 113 | public: |
113 | // Wrappers for IMM API. | 114 | // Wrappers for IMM API. |
114 | static BOOL isIME(HKL hkl); | 115 | static BOOL isIME(HKL hkl); |
116 | static HWND getDefaultIMEWnd(HWND hwnd); | ||
115 | static HIMC getContext(HWND hwnd); | 117 | static HIMC getContext(HWND hwnd); |
116 | static BOOL releaseContext(HWND hwnd, HIMC himc); | 118 | static BOOL releaseContext(HWND hwnd, HIMC himc); |
117 | static BOOL getOpenStatus(HIMC himc); | 119 | static BOOL getOpenStatus(HIMC himc); |
@@ -120,6 +122,11 @@ public: | |||
120 | static BOOL setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence); | 122 | static BOOL setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence); |
121 | static BOOL getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); | 123 | static BOOL getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); |
122 | static BOOL setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); | 124 | static BOOL setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); |
125 | static LONG getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length); | ||
126 | static BOOL setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength); | ||
127 | static BOOL setCompositionFont(HIMC himc, LPLOGFONTW logfont); | ||
128 | static BOOL setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form); | ||
129 | static BOOL notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value); | ||
123 | 130 | ||
124 | private: | 131 | private: |
125 | LLWinImm(); | 132 | LLWinImm(); |
@@ -128,6 +135,7 @@ private: | |||
128 | private: | 135 | private: |
129 | // Pointers to IMM API. | 136 | // Pointers to IMM API. |
130 | BOOL (WINAPI *mImmIsIME)(HKL); | 137 | BOOL (WINAPI *mImmIsIME)(HKL); |
138 | HWND (WINAPI *mImmGetDefaultIMEWnd)(HWND); | ||
131 | HIMC (WINAPI *mImmGetContext)(HWND); | 139 | HIMC (WINAPI *mImmGetContext)(HWND); |
132 | BOOL (WINAPI *mImmReleaseContext)(HWND, HIMC); | 140 | BOOL (WINAPI *mImmReleaseContext)(HWND, HIMC); |
133 | BOOL (WINAPI *mImmGetOpenStatus)(HIMC); | 141 | BOOL (WINAPI *mImmGetOpenStatus)(HIMC); |
@@ -136,6 +144,11 @@ private: | |||
136 | BOOL (WINAPI *mImmSetConversionStatus)(HIMC, DWORD, DWORD); | 144 | BOOL (WINAPI *mImmSetConversionStatus)(HIMC, DWORD, DWORD); |
137 | BOOL (WINAPI *mImmGetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM); | 145 | BOOL (WINAPI *mImmGetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM); |
138 | BOOL (WINAPI *mImmSetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM); | 146 | BOOL (WINAPI *mImmSetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM); |
147 | LONG (WINAPI *mImmGetCompositionString)(HIMC, DWORD, LPVOID, DWORD); | ||
148 | BOOL (WINAPI *mImmSetCompositionString)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD); | ||
149 | BOOL (WINAPI *mImmSetCompositionFont)(HIMC, LPLOGFONTW); | ||
150 | BOOL (WINAPI *mImmSetCandidateWindow)(HIMC, LPCANDIDATEFORM); | ||
151 | BOOL (WINAPI *mImmNotifyIME)(HIMC, DWORD, DWORD, DWORD); | ||
139 | 152 | ||
140 | private: | 153 | private: |
141 | HMODULE mHImmDll; | 154 | HMODULE mHImmDll; |
@@ -155,6 +168,7 @@ LLWinImm::LLWinImm() : mHImmDll(NULL) | |||
155 | if (mHImmDll != NULL) | 168 | if (mHImmDll != NULL) |
156 | { | 169 | { |
157 | mImmIsIME = (BOOL (WINAPI *)(HKL)) GetProcAddress(mHImmDll, "ImmIsIME"); | 170 | mImmIsIME = (BOOL (WINAPI *)(HKL)) GetProcAddress(mHImmDll, "ImmIsIME"); |
171 | mImmGetDefaultIMEWnd = (HWND (WINAPI *)(HWND)) GetProcAddress(mHImmDll, "ImmGetDefaultIMEWnd"); | ||
158 | mImmGetContext = (HIMC (WINAPI *)(HWND)) GetProcAddress(mHImmDll, "ImmGetContext"); | 172 | mImmGetContext = (HIMC (WINAPI *)(HWND)) GetProcAddress(mHImmDll, "ImmGetContext"); |
159 | mImmReleaseContext = (BOOL (WINAPI *)(HWND, HIMC)) GetProcAddress(mHImmDll, "ImmReleaseContext"); | 173 | mImmReleaseContext = (BOOL (WINAPI *)(HWND, HIMC)) GetProcAddress(mHImmDll, "ImmReleaseContext"); |
160 | mImmGetOpenStatus = (BOOL (WINAPI *)(HIMC)) GetProcAddress(mHImmDll, "ImmGetOpenStatus"); | 174 | mImmGetOpenStatus = (BOOL (WINAPI *)(HIMC)) GetProcAddress(mHImmDll, "ImmGetOpenStatus"); |
@@ -163,8 +177,14 @@ LLWinImm::LLWinImm() : mHImmDll(NULL) | |||
163 | mImmSetConversionStatus = (BOOL (WINAPI *)(HIMC, DWORD, DWORD)) GetProcAddress(mHImmDll, "ImmSetConversionStatus"); | 177 | mImmSetConversionStatus = (BOOL (WINAPI *)(HIMC, DWORD, DWORD)) GetProcAddress(mHImmDll, "ImmSetConversionStatus"); |
164 | mImmGetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM)) GetProcAddress(mHImmDll, "ImmGetCompositionWindow"); | 178 | mImmGetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM)) GetProcAddress(mHImmDll, "ImmGetCompositionWindow"); |
165 | mImmSetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM)) GetProcAddress(mHImmDll, "ImmSetCompositionWindow"); | 179 | mImmSetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM)) GetProcAddress(mHImmDll, "ImmSetCompositionWindow"); |
180 | mImmGetCompositionString= (LONG (WINAPI *)(HIMC, DWORD, LPVOID, DWORD)) GetProcAddress(mHImmDll, "ImmGetCompositionStringW"); | ||
181 | mImmSetCompositionString= (BOOL (WINAPI *)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD)) GetProcAddress(mHImmDll, "ImmSetCompositionStringW"); | ||
182 | mImmSetCompositionFont = (BOOL (WINAPI *)(HIMC, LPLOGFONTW)) GetProcAddress(mHImmDll, "ImmSetCompositionFontW"); | ||
183 | mImmSetCandidateWindow = (BOOL (WINAPI *)(HIMC, LPCANDIDATEFORM)) GetProcAddress(mHImmDll, "ImmSetCandidateWindow"); | ||
184 | mImmNotifyIME = (BOOL (WINAPI *)(HIMC, DWORD, DWORD, DWORD)) GetProcAddress(mHImmDll, "ImmNotifyIME"); | ||
166 | 185 | ||
167 | if (mImmIsIME == NULL || | 186 | if (mImmIsIME == NULL || |
187 | mImmGetDefaultIMEWnd == NULL || | ||
168 | mImmGetContext == NULL || | 188 | mImmGetContext == NULL || |
169 | mImmReleaseContext == NULL || | 189 | mImmReleaseContext == NULL || |
170 | mImmGetOpenStatus == NULL || | 190 | mImmGetOpenStatus == NULL || |
@@ -172,7 +192,12 @@ LLWinImm::LLWinImm() : mHImmDll(NULL) | |||
172 | mImmGetConversionStatus == NULL || | 192 | mImmGetConversionStatus == NULL || |
173 | mImmSetConversionStatus == NULL || | 193 | mImmSetConversionStatus == NULL || |
174 | mImmGetCompostitionWindow == NULL || | 194 | mImmGetCompostitionWindow == NULL || |
175 | mImmSetCompostitionWindow == NULL) | 195 | mImmSetCompostitionWindow == NULL || |
196 | mImmGetCompositionString == NULL || | ||
197 | mImmSetCompositionString == NULL || | ||
198 | mImmSetCompositionFont == NULL || | ||
199 | mImmSetCandidateWindow == NULL || | ||
200 | mImmNotifyIME == NULL) | ||
176 | { | 201 | { |
177 | // If any of the above API entires are not found, we can't use IMM API. | 202 | // If any of the above API entires are not found, we can't use IMM API. |
178 | // So, turn off the IMM support. We should log some warning message in | 203 | // So, turn off the IMM support. We should log some warning message in |
@@ -186,6 +211,7 @@ LLWinImm::LLWinImm() : mHImmDll(NULL) | |||
186 | 211 | ||
187 | // If we unload the library, make sure all the function pointers are cleared | 212 | // If we unload the library, make sure all the function pointers are cleared |
188 | mImmIsIME = NULL; | 213 | mImmIsIME = NULL; |
214 | mImmGetDefaultIMEWnd = NULL; | ||
189 | mImmGetContext = NULL; | 215 | mImmGetContext = NULL; |
190 | mImmReleaseContext = NULL; | 216 | mImmReleaseContext = NULL; |
191 | mImmGetOpenStatus = NULL; | 217 | mImmGetOpenStatus = NULL; |
@@ -194,6 +220,11 @@ LLWinImm::LLWinImm() : mHImmDll(NULL) | |||
194 | mImmSetConversionStatus = NULL; | 220 | mImmSetConversionStatus = NULL; |
195 | mImmGetCompostitionWindow = NULL; | 221 | mImmGetCompostitionWindow = NULL; |
196 | mImmSetCompostitionWindow = NULL; | 222 | mImmSetCompostitionWindow = NULL; |
223 | mImmGetCompositionString = NULL; | ||
224 | mImmSetCompositionString = NULL; | ||
225 | mImmSetCompositionFont = NULL; | ||
226 | mImmSetCandidateWindow = NULL; | ||
227 | mImmNotifyIME = NULL; | ||
197 | } | 228 | } |
198 | } | 229 | } |
199 | } | 230 | } |
@@ -272,6 +303,50 @@ BOOL LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) | |||
272 | } | 303 | } |
273 | 304 | ||
274 | 305 | ||
306 | // static | ||
307 | LONG LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length) | ||
308 | { | ||
309 | if ( sTheInstance.mImmGetCompositionString ) | ||
310 | return sTheInstance.mImmGetCompositionString(himc, index, data, length); | ||
311 | return FALSE; | ||
312 | } | ||
313 | |||
314 | |||
315 | // static | ||
316 | BOOL LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength) | ||
317 | { | ||
318 | if ( sTheInstance.mImmSetCompositionString ) | ||
319 | return sTheInstance.mImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength); | ||
320 | return FALSE; | ||
321 | } | ||
322 | |||
323 | // static | ||
324 | BOOL LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont) | ||
325 | { | ||
326 | if ( sTheInstance.mImmSetCompositionFont ) | ||
327 | return sTheInstance.mImmSetCompositionFont(himc, pFont); | ||
328 | return FALSE; | ||
329 | } | ||
330 | |||
331 | // static | ||
332 | BOOL LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form) | ||
333 | { | ||
334 | if ( sTheInstance.mImmSetCandidateWindow ) | ||
335 | return sTheInstance.mImmSetCandidateWindow(himc, form); | ||
336 | return FALSE; | ||
337 | } | ||
338 | |||
339 | // static | ||
340 | BOOL LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value) | ||
341 | { | ||
342 | if ( sTheInstance.mImmNotifyIME ) | ||
343 | return sTheInstance.mImmNotifyIME(himc, action, index, value); | ||
344 | return FALSE; | ||
345 | } | ||
346 | |||
347 | |||
348 | |||
349 | |||
275 | // ---------------------------------------------------------------------------------------- | 350 | // ---------------------------------------------------------------------------------------- |
276 | LLWinImm::~LLWinImm() | 351 | LLWinImm::~LLWinImm() |
277 | { | 352 | { |
@@ -304,13 +379,14 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, | |||
304 | mNativeAspectRatio = 0.f; | 379 | mNativeAspectRatio = 0.f; |
305 | mMousePositionModified = FALSE; | 380 | mMousePositionModified = FALSE; |
306 | mInputProcessingPaused = FALSE; | 381 | mInputProcessingPaused = FALSE; |
382 | mPreeditor = NULL; | ||
307 | 383 | ||
308 | // Initialize the keyboard | 384 | // Initialize the keyboard |
309 | gKeyboard = new LLKeyboardWin32(); | 385 | gKeyboard = new LLKeyboardWin32(); |
310 | 386 | ||
311 | // Initialize (boot strap) the Language text input management, | 387 | // Initialize (boot strap) the Language text input management, |
312 | // based on the system's (user's) default settings. | 388 | // based on the system's (user's) default settings. |
313 | allowLanguageTextInput(FALSE); | 389 | allowLanguageTextInput(mPreeditor, FALSE); |
314 | 390 | ||
315 | GLuint pixel_format; | 391 | GLuint pixel_format; |
316 | WNDCLASS wc; | 392 | WNDCLASS wc; |
@@ -938,6 +1014,10 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, | |||
938 | initCursors(); | 1014 | initCursors(); |
939 | setCursor( UI_CURSOR_ARROW ); | 1015 | setCursor( UI_CURSOR_ARROW ); |
940 | 1016 | ||
1017 | // Initialize (boot strap) the Language text input management, | ||
1018 | // based on the system's (or user's) default settings. | ||
1019 | allowLanguageTextInput(NULL, FALSE); | ||
1020 | |||
941 | // Direct Input | 1021 | // Direct Input |
942 | HRESULT hr; | 1022 | HRESULT hr; |
943 | 1023 | ||
@@ -2035,6 +2115,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ | |||
2035 | 2115 | ||
2036 | BOOL minimized = BOOL(HIWORD(w_param)); | 2116 | BOOL minimized = BOOL(HIWORD(w_param)); |
2037 | 2117 | ||
2118 | if (!activating && LLWinImm::isAvailable() && window_imp->mPreeditor) | ||
2119 | { | ||
2120 | window_imp->interruptLanguageTextInput(); | ||
2121 | } | ||
2122 | |||
2038 | // JC - I'm not sure why, but if we don't report that we handled the | 2123 | // JC - I'm not sure why, but if we don't report that we handled the |
2039 | // WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work | 2124 | // WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work |
2040 | // properly when we run fullscreen. | 2125 | // properly when we run fullscreen. |
@@ -2127,6 +2212,47 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ | |||
2127 | // pass on to windows | 2212 | // pass on to windows |
2128 | break; | 2213 | break; |
2129 | 2214 | ||
2215 | case WM_IME_SETCONTEXT: | ||
2216 | if (LLWinImm::isAvailable() && window_imp->mPreeditor) | ||
2217 | { | ||
2218 | l_param &= ~ISC_SHOWUICOMPOSITIONWINDOW; | ||
2219 | // Invoke DefWinProc with the modified LPARAM. | ||
2220 | } | ||
2221 | break; | ||
2222 | |||
2223 | case WM_IME_STARTCOMPOSITION: | ||
2224 | if (LLWinImm::isAvailable() && window_imp->mPreeditor) | ||
2225 | { | ||
2226 | window_imp->handleStartCompositionMessage(); | ||
2227 | return 0; | ||
2228 | } | ||
2229 | break; | ||
2230 | |||
2231 | case WM_IME_ENDCOMPOSITION: | ||
2232 | if (LLWinImm::isAvailable() && window_imp->mPreeditor) | ||
2233 | { | ||
2234 | return 0; | ||
2235 | } | ||
2236 | break; | ||
2237 | |||
2238 | case WM_IME_COMPOSITION: | ||
2239 | if (LLWinImm::isAvailable() && window_imp->mPreeditor) | ||
2240 | { | ||
2241 | window_imp->handleCompositionMessage(l_param); | ||
2242 | return 0; | ||
2243 | } | ||
2244 | break; | ||
2245 | |||
2246 | case WM_IME_REQUEST: | ||
2247 | if (LLWinImm::isAvailable() && window_imp->mPreeditor) | ||
2248 | { | ||
2249 | LRESULT result = 0; | ||
2250 | if (window_imp->handleImeRequests(w_param, l_param, &result)) | ||
2251 | { | ||
2252 | return result; | ||
2253 | } | ||
2254 | } | ||
2255 | break; | ||
2130 | 2256 | ||
2131 | case WM_CHAR: | 2257 | case WM_CHAR: |
2132 | // Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need | 2258 | // Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need |
@@ -2154,6 +2280,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ | |||
2154 | 2280 | ||
2155 | case WM_LBUTTONDOWN: | 2281 | case WM_LBUTTONDOWN: |
2156 | { | 2282 | { |
2283 | if (LLWinImm::isAvailable() && window_imp->mPreeditor) | ||
2284 | { | ||
2285 | window_imp->interruptLanguageTextInput(); | ||
2286 | } | ||
2287 | |||
2157 | // Because we move the cursor position in the app, we need to query | 2288 | // Because we move the cursor position in the app, we need to query |
2158 | // to find out where the cursor at the time the event is handled. | 2289 | // to find out where the cursor at the time the event is handled. |
2159 | // If we don't do this, many clicks could get buffered up, and if the | 2290 | // If we don't do this, many clicks could get buffered up, and if the |
@@ -2236,6 +2367,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ | |||
2236 | case WM_RBUTTONDBLCLK: | 2367 | case WM_RBUTTONDBLCLK: |
2237 | case WM_RBUTTONDOWN: | 2368 | case WM_RBUTTONDOWN: |
2238 | { | 2369 | { |
2370 | if (LLWinImm::isAvailable() && window_imp->mPreeditor) | ||
2371 | { | ||
2372 | window_imp->interruptLanguageTextInput(); | ||
2373 | } | ||
2374 | |||
2239 | // Because we move the cursor position in tllviewerhe app, we need to query | 2375 | // Because we move the cursor position in tllviewerhe app, we need to query |
2240 | // to find out where the cursor at the time the event is handled. | 2376 | // to find out where the cursor at the time the event is handled. |
2241 | // If we don't do this, many clicks could get buffered up, and if the | 2377 | // If we don't do this, many clicks could get buffered up, and if the |
@@ -2287,6 +2423,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ | |||
2287 | case WM_MBUTTONDOWN: | 2423 | case WM_MBUTTONDOWN: |
2288 | // case WM_MBUTTONDBLCLK: | 2424 | // case WM_MBUTTONDBLCLK: |
2289 | { | 2425 | { |
2426 | if (LLWinImm::isAvailable() && window_imp->mPreeditor) | ||
2427 | { | ||
2428 | window_imp->interruptLanguageTextInput(); | ||
2429 | } | ||
2430 | |||
2290 | // Because we move the cursor position in tllviewerhe app, we need to query | 2431 | // Because we move the cursor position in tllviewerhe app, we need to query |
2291 | // to find out where the cursor at the time the event is handled. | 2432 | // to find out where the cursor at the time the event is handled. |
2292 | // If we don't do this, many clicks could get buffered up, and if the | 2433 | // If we don't do this, many clicks could get buffered up, and if the |
@@ -3256,24 +3397,6 @@ void spawn_web_browser(const char* escaped_url ) | |||
3256 | } | 3397 | } |
3257 | } | 3398 | } |
3258 | 3399 | ||
3259 | void shell_open( const char* file_path ) | ||
3260 | { | ||
3261 | llinfos << "Opening " << file_path << llendl; | ||
3262 | |||
3263 | WCHAR wstr[1024]; | ||
3264 | mbstowcs(wstr, file_path, 1024); | ||
3265 | |||
3266 | HWND our_window = NULL; | ||
3267 | int retval = (int) ShellExecute(our_window, L"open", wstr, NULL, NULL, SW_SHOWNORMAL); /* Flawfinder: ignore */ | ||
3268 | if (retval > 32) | ||
3269 | { | ||
3270 | llinfos << "ShellExecute success with " << retval << llendl; | ||
3271 | } | ||
3272 | else | ||
3273 | { | ||
3274 | llinfos << "ShellExecute failure with " << retval << llendl; | ||
3275 | } | ||
3276 | } | ||
3277 | 3400 | ||
3278 | BOOL LLWindowWin32::dialog_color_picker ( F32 *r, F32 *g, F32 *b ) | 3401 | BOOL LLWindowWin32::dialog_color_picker ( F32 *r, F32 *g, F32 *b ) |
3279 | { | 3402 | { |
@@ -3324,15 +3447,37 @@ void LLWindowWin32::focusClient() | |||
3324 | SetFocus ( mWindowHandle ); | 3447 | SetFocus ( mWindowHandle ); |
3325 | } | 3448 | } |
3326 | 3449 | ||
3327 | void LLWindowWin32::allowLanguageTextInput(BOOL b) | 3450 | void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) |
3328 | { | 3451 | { |
3329 | if (b == sLanguageTextInputAllowed || !LLWinImm::isAvailable()) | 3452 | if (b == sLanguageTextInputAllowed || !LLWinImm::isAvailable()) |
3330 | { | 3453 | { |
3331 | return; | 3454 | return; |
3332 | } | 3455 | } |
3456 | |||
3457 | if (preeditor != mPreeditor && !b) | ||
3458 | { | ||
3459 | // This condition may occur with a call to | ||
3460 | // setEnabled(BOOL) from LLTextEditor or LLLineEditor | ||
3461 | // when the control is not focused. | ||
3462 | // We need to silently ignore the case so that | ||
3463 | // the language input status of the focused control | ||
3464 | // is not disturbed. | ||
3465 | return; | ||
3466 | } | ||
3467 | |||
3468 | // Take care of old and new preeditors. | ||
3469 | if (preeditor != mPreeditor || !b) | ||
3470 | { | ||
3471 | if (sLanguageTextInputAllowed) | ||
3472 | { | ||
3473 | interruptLanguageTextInput(); | ||
3474 | } | ||
3475 | mPreeditor = (b ? preeditor : NULL); | ||
3476 | } | ||
3477 | |||
3333 | sLanguageTextInputAllowed = b; | 3478 | sLanguageTextInputAllowed = b; |
3334 | 3479 | ||
3335 | if (b) | 3480 | if ( sLanguageTextInputAllowed ) |
3336 | { | 3481 | { |
3337 | // Allowing: Restore the previous IME status, so that the user has a feeling that the previous | 3482 | // Allowing: Restore the previous IME status, so that the user has a feeling that the previous |
3338 | // text input continues naturally. Be careful, however, the IME status is meaningful only during the user keeps | 3483 | // text input continues naturally. Be careful, however, the IME status is meaningful only during the user keeps |
@@ -3368,7 +3513,24 @@ void LLWindowWin32::allowLanguageTextInput(BOOL b) | |||
3368 | LLWinImm::releaseContext(mWindowHandle, himc); | 3513 | LLWinImm::releaseContext(mWindowHandle, himc); |
3369 | } | 3514 | } |
3370 | } | 3515 | } |
3516 | } | ||
3517 | |||
3518 | void LLWindowWin32::fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, | ||
3519 | CANDIDATEFORM *form) | ||
3520 | { | ||
3521 | LLCoordWindow caret_coord, top_left, bottom_right; | ||
3522 | convertCoords(caret, &caret_coord); | ||
3523 | convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); | ||
3524 | convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); | ||
3371 | 3525 | ||
3526 | memset(form, 0, sizeof(CANDIDATEFORM)); | ||
3527 | form->dwStyle = CFS_EXCLUDE; | ||
3528 | form->ptCurrentPos.x = caret_coord.mX; | ||
3529 | form->ptCurrentPos.y = caret_coord.mY; | ||
3530 | form->rcArea.left = top_left.mX; | ||
3531 | form->rcArea.top = top_left.mY; | ||
3532 | form->rcArea.right = bottom_right.mX; | ||
3533 | form->rcArea.bottom = bottom_right.mY; | ||
3372 | } | 3534 | } |
3373 | 3535 | ||
3374 | 3536 | ||
@@ -3400,4 +3562,455 @@ void LLWindowWin32::setLanguageTextInput( const LLCoordGL & position ) | |||
3400 | } | 3562 | } |
3401 | } | 3563 | } |
3402 | 3564 | ||
3565 | |||
3566 | void LLWindowWin32::fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control, | ||
3567 | IMECHARPOSITION *char_position) | ||
3568 | { | ||
3569 | LLCoordScreen caret_coord, top_left, bottom_right; | ||
3570 | convertCoords(caret, &caret_coord); | ||
3571 | convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); | ||
3572 | convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); | ||
3573 | |||
3574 | char_position->pt.x = caret_coord.mX; | ||
3575 | char_position->pt.y = top_left.mY; // Windows wants the coordinate of upper left corner of a character... | ||
3576 | char_position->cLineHeight = bottom_right.mY - top_left.mY; | ||
3577 | char_position->rcDocument.left = top_left.mX; | ||
3578 | char_position->rcDocument.top = top_left.mY; | ||
3579 | char_position->rcDocument.right = bottom_right.mX; | ||
3580 | char_position->rcDocument.bottom = bottom_right.mY; | ||
3581 | } | ||
3582 | |||
3583 | void LLWindowWin32::fillCompositionLogfont(LOGFONT *logfont) | ||
3584 | { | ||
3585 | // Our font is a list of FreeType recognized font files that may | ||
3586 | // not have a corresponding ones in Windows' fonts. Hence, we | ||
3587 | // can't simply tell Windows which font we are using. We will | ||
3588 | // notify a _standard_ font for a current input locale instead. | ||
3589 | // We use a hard-coded knowledge about the Windows' standard | ||
3590 | // configuration to do so... | ||
3591 | |||
3592 | memset(logfont, 0, sizeof(LOGFONT)); | ||
3593 | |||
3594 | const WORD lang_id = LOWORD(GetKeyboardLayout(0)); | ||
3595 | switch (PRIMARYLANGID(lang_id)) | ||
3596 | { | ||
3597 | case LANG_CHINESE: | ||
3598 | // We need to identify one of two Chinese fonts. | ||
3599 | switch (SUBLANGID(lang_id)) | ||
3600 | { | ||
3601 | case SUBLANG_CHINESE_SIMPLIFIED: | ||
3602 | case SUBLANG_CHINESE_SINGAPORE: | ||
3603 | logfont->lfCharSet = GB2312_CHARSET; | ||
3604 | lstrcpy(logfont->lfFaceName, TEXT("SimHei")); | ||
3605 | break; | ||
3606 | case SUBLANG_CHINESE_TRADITIONAL: | ||
3607 | case SUBLANG_CHINESE_HONGKONG: | ||
3608 | case SUBLANG_CHINESE_MACAU: | ||
3609 | default: | ||
3610 | logfont->lfCharSet = CHINESEBIG5_CHARSET; | ||
3611 | lstrcpy(logfont->lfFaceName, TEXT("MingLiU")); | ||
3612 | break; | ||
3613 | } | ||
3614 | break; | ||
3615 | case LANG_JAPANESE: | ||
3616 | logfont->lfCharSet = SHIFTJIS_CHARSET; | ||
3617 | lstrcpy(logfont->lfFaceName, TEXT("MS Gothic")); | ||
3618 | break; | ||
3619 | case LANG_KOREAN: | ||
3620 | logfont->lfCharSet = HANGUL_CHARSET; | ||
3621 | lstrcpy(logfont->lfFaceName, TEXT("Gulim")); | ||
3622 | break; | ||
3623 | default: | ||
3624 | logfont->lfCharSet = ANSI_CHARSET; | ||
3625 | lstrcpy(logfont->lfFaceName, TEXT("Tahoma")); | ||
3626 | break; | ||
3627 | } | ||
3628 | |||
3629 | logfont->lfHeight = mPreeditor->getPreeditFontSize(); | ||
3630 | logfont->lfWeight = FW_NORMAL; | ||
3631 | } | ||
3632 | |||
3633 | U32 LLWindowWin32::fillReconvertString(const LLWString &text, | ||
3634 | S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string) | ||
3635 | { | ||
3636 | const llutf16string text_utf16 = wstring_to_utf16str(text); | ||
3637 | const DWORD required_size = sizeof(RECONVERTSTRING) + (text_utf16.length() + 1) * sizeof(WCHAR); | ||
3638 | if (reconvert_string && reconvert_string->dwSize >= required_size) | ||
3639 | { | ||
3640 | const DWORD focus_utf16_at = wstring_utf16_length(text, 0, focus); | ||
3641 | const DWORD focus_utf16_length = wstring_utf16_length(text, focus, focus_length); | ||
3642 | |||
3643 | reconvert_string->dwVersion = 0; | ||
3644 | reconvert_string->dwStrLen = text_utf16.length(); | ||
3645 | reconvert_string->dwStrOffset = sizeof(RECONVERTSTRING); | ||
3646 | reconvert_string->dwCompStrLen = focus_utf16_length; | ||
3647 | reconvert_string->dwCompStrOffset = focus_utf16_at * sizeof(WCHAR); | ||
3648 | reconvert_string->dwTargetStrLen = 0; | ||
3649 | reconvert_string->dwTargetStrOffset = focus_utf16_at * sizeof(WCHAR); | ||
3650 | |||
3651 | const LPWSTR text = (LPWSTR)((BYTE *)reconvert_string + sizeof(RECONVERTSTRING)); | ||
3652 | memcpy(text, text_utf16.c_str(), (text_utf16.length() + 1) * sizeof(WCHAR)); | ||
3653 | } | ||
3654 | return required_size; | ||
3655 | } | ||
3656 | |||
3657 | void LLWindowWin32::updateLanguageTextInputArea() | ||
3658 | { | ||
3659 | if (!mPreeditor || !LLWinImm::isAvailable()) | ||
3660 | { | ||
3661 | return; | ||
3662 | } | ||
3663 | |||
3664 | LLCoordGL caret_coord; | ||
3665 | LLRect preedit_bounds; | ||
3666 | if (mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL)) | ||
3667 | { | ||
3668 | mLanguageTextInputPointGL = caret_coord; | ||
3669 | mLanguageTextInputAreaGL = preedit_bounds; | ||
3670 | |||
3671 | CANDIDATEFORM candidate_form; | ||
3672 | fillCandidateForm(caret_coord, preedit_bounds, &candidate_form); | ||
3673 | |||
3674 | HIMC himc = LLWinImm::getContext(mWindowHandle); | ||
3675 | // Win32 document says there may be up to 4 candidate windows. | ||
3676 | // This magic number 4 appears only in the document, and | ||
3677 | // there are no constant/macro for the value... | ||
3678 | for (int i = 3; i >= 0; --i) | ||
3679 | { | ||
3680 | candidate_form.dwIndex = i; | ||
3681 | LLWinImm::setCandidateWindow(himc, &candidate_form); | ||
3682 | } | ||
3683 | LLWinImm::releaseContext(mWindowHandle, himc); | ||
3684 | } | ||
3685 | } | ||
3686 | |||
3687 | void LLWindowWin32::interruptLanguageTextInput() | ||
3688 | { | ||
3689 | if (mPreeditor) | ||
3690 | { | ||
3691 | if (LLWinImm::isAvailable()) | ||
3692 | { | ||
3693 | HIMC himc = LLWinImm::getContext(mWindowHandle); | ||
3694 | LLWinImm::notifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); | ||
3695 | LLWinImm::releaseContext(mWindowHandle, himc); | ||
3696 | } | ||
3697 | mPreeditor->resetPreedit(); | ||
3698 | } | ||
3699 | } | ||
3700 | |||
3701 | void LLWindowWin32::handleStartCompositionMessage() | ||
3702 | { | ||
3703 | // Let IME know the font to use in feedback UI. | ||
3704 | LOGFONT logfont; | ||
3705 | fillCompositionLogfont(&logfont); | ||
3706 | HIMC himc = LLWinImm::getContext(mWindowHandle); | ||
3707 | LLWinImm::setCompositionFont(himc, &logfont); | ||
3708 | LLWinImm::releaseContext(mWindowHandle, himc); | ||
3709 | } | ||
3710 | |||
3711 | // Handle WM_IME_COMPOSITION message. | ||
3712 | |||
3713 | void LLWindowWin32::handleCompositionMessage(const U32 indexes) | ||
3714 | { | ||
3715 | BOOL needs_update = FALSE; | ||
3716 | LLWString result_string; | ||
3717 | LLWString preedit_string; | ||
3718 | S32 preedit_string_utf16_length = 0; | ||
3719 | LLPreeditor::segment_lengths_t preedit_segment_lengths; | ||
3720 | LLPreeditor::standouts_t preedit_standouts; | ||
3721 | |||
3722 | // Step I: Receive details of preedits from IME. | ||
3723 | |||
3724 | HIMC himc = LLWinImm::getContext(mWindowHandle); | ||
3725 | |||
3726 | if (indexes & GCS_RESULTSTR) | ||
3727 | { | ||
3728 | LONG size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, NULL, 0); | ||
3729 | if (size >= 0) | ||
3730 | { | ||
3731 | const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; | ||
3732 | size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, data, size); | ||
3733 | if (size > 0) | ||
3734 | { | ||
3735 | result_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); | ||
3736 | } | ||
3737 | delete[] data; | ||
3738 | needs_update = TRUE; | ||
3739 | } | ||
3740 | } | ||
3741 | |||
3742 | if (indexes & GCS_COMPSTR) | ||
3743 | { | ||
3744 | LONG size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, NULL, 0); | ||
3745 | if (size >= 0) | ||
3746 | { | ||
3747 | const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; | ||
3748 | size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, data, size); | ||
3749 | if (size > 0) | ||
3750 | { | ||
3751 | preedit_string_utf16_length = size / sizeof(WCHAR); | ||
3752 | preedit_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); | ||
3753 | } | ||
3754 | delete[] data; | ||
3755 | needs_update = TRUE; | ||
3756 | } | ||
3757 | } | ||
3758 | |||
3759 | if ((indexes & GCS_COMPCLAUSE) && preedit_string.length() > 0) | ||
3760 | { | ||
3761 | LONG size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, NULL, 0); | ||
3762 | if (size > 0) | ||
3763 | { | ||
3764 | const LPDWORD data = new DWORD[size / sizeof(DWORD)]; | ||
3765 | size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, data, size); | ||
3766 | if (size >= sizeof(DWORD) * 2 | ||
3767 | && data[0] == 0 && data[size / sizeof(DWORD) - 1] == preedit_string_utf16_length) | ||
3768 | { | ||
3769 | preedit_segment_lengths.resize(size / sizeof(DWORD) - 1); | ||
3770 | S32 offset = 0; | ||
3771 | for (U32 i = 0; i < preedit_segment_lengths.size(); i++) | ||
3772 | { | ||
3773 | const S32 length = wstring_wstring_length_from_utf16_length(preedit_string, offset, data[i + 1] - data[i]); | ||
3774 | preedit_segment_lengths[i] = length; | ||
3775 | offset += length; | ||
3776 | } | ||
3777 | } | ||
3778 | delete[] data; | ||
3779 | } | ||
3780 | } | ||
3781 | |||
3782 | if ((indexes & GCS_COMPATTR) && preedit_segment_lengths.size() > 1) | ||
3783 | { | ||
3784 | LONG size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, NULL, 0); | ||
3785 | if (size > 0) | ||
3786 | { | ||
3787 | const LPBYTE data = new BYTE[size / sizeof(BYTE)]; | ||
3788 | size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, data, size); | ||
3789 | if (size == preedit_string_utf16_length) | ||
3790 | { | ||
3791 | preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); | ||
3792 | S32 offset = 0; | ||
3793 | for (U32 i = 0; i < preedit_segment_lengths.size(); i++) | ||
3794 | { | ||
3795 | if (ATTR_TARGET_CONVERTED == data[offset] || ATTR_TARGET_NOTCONVERTED == data[offset]) | ||
3796 | { | ||
3797 | preedit_standouts[i] = TRUE; | ||
3798 | } | ||
3799 | offset += wstring_utf16_length(preedit_string, offset, preedit_segment_lengths[i]); | ||
3800 | } | ||
3801 | } | ||
3802 | delete[] data; | ||
3803 | } | ||
3804 | } | ||
3805 | |||
3806 | S32 caret_position = preedit_string.length(); | ||
3807 | if (indexes & GCS_CURSORPOS) | ||
3808 | { | ||
3809 | const S32 caret_position_utf16 = LLWinImm::getCompositionString(himc, GCS_CURSORPOS, NULL, 0); | ||
3810 | if (caret_position_utf16 >= 0 && caret_position <= preedit_string_utf16_length) | ||
3811 | { | ||
3812 | caret_position = wstring_wstring_length_from_utf16_length(preedit_string, 0, caret_position_utf16); | ||
3813 | } | ||
3814 | } | ||
3815 | |||
3816 | if (indexes == 0) | ||
3817 | { | ||
3818 | // I'm not sure this condition really happens, but | ||
3819 | // Windows SDK document says it is an indication | ||
3820 | // of "reset everything." | ||
3821 | needs_update = TRUE; | ||
3822 | } | ||
3823 | |||
3824 | LLWinImm::releaseContext(mWindowHandle, himc); | ||
3825 | |||
3826 | // Step II: Update the active preeditor. | ||
3827 | |||
3828 | if (needs_update) | ||
3829 | { | ||
3830 | mPreeditor->resetPreedit(); | ||
3831 | |||
3832 | if (result_string.length() > 0) | ||
3833 | { | ||
3834 | for (LLWString::const_iterator i = result_string.begin(); i != result_string.end(); i++) | ||
3835 | { | ||
3836 | mPreeditor->handleUnicodeCharHere(*i, FALSE); | ||
3837 | } | ||
3838 | } | ||
3839 | |||
3840 | if (preedit_string.length() > 0) | ||
3841 | { | ||
3842 | if (preedit_segment_lengths.size() == 0) | ||
3843 | { | ||
3844 | preedit_segment_lengths.assign(1, preedit_string.length()); | ||
3845 | } | ||
3846 | if (preedit_standouts.size() == 0) | ||
3847 | { | ||
3848 | preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); | ||
3849 | } | ||
3850 | mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position); | ||
3851 | } | ||
3852 | |||
3853 | // Some IME doesn't query char position after WM_IME_COMPOSITION, | ||
3854 | // so we need to update them actively. | ||
3855 | updateLanguageTextInputArea(); | ||
3856 | } | ||
3857 | } | ||
3858 | |||
3859 | // Given a text and a focus range, find_context finds and returns a | ||
3860 | // surrounding context of the focused subtext. A variable pointed | ||
3861 | // to by offset receives the offset in llwchars of the beginning of | ||
3862 | // the returned context string in the given wtext. | ||
3863 | |||
3864 | static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_length, S32 *offset) | ||
3865 | { | ||
3866 | static const S32 CONTEXT_EXCESS = 30; // This value is by experiences. | ||
3867 | |||
3868 | const S32 e = llmin((S32) wtext.length(), focus + focus_length + CONTEXT_EXCESS); | ||
3869 | S32 end = focus + focus_length; | ||
3870 | while (end < e && '\n' != wtext[end]) | ||
3871 | { | ||
3872 | end++; | ||
3873 | } | ||
3874 | |||
3875 | const S32 s = llmax(0, focus - CONTEXT_EXCESS); | ||
3876 | S32 start = focus; | ||
3877 | while (start > s && '\n' != wtext[start - 1]) | ||
3878 | { | ||
3879 | --start; | ||
3880 | } | ||
3881 | |||
3882 | *offset = start; | ||
3883 | return wtext.substr(start, end - start); | ||
3884 | } | ||
3885 | |||
3886 | // Handle WM_IME_REQUEST message. | ||
3887 | // If it handled the message, returns TRUE. Otherwise, FALSE. | ||
3888 | // When it handled the message, the value to be returned from | ||
3889 | // the Window Procedure is set to *result. | ||
3890 | |||
3891 | BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result) | ||
3892 | { | ||
3893 | if ( mPreeditor ) | ||
3894 | { | ||
3895 | switch (request) | ||
3896 | { | ||
3897 | case IMR_CANDIDATEWINDOW: // http://msdn2.microsoft.com/en-us/library/ms776080.aspx | ||
3898 | { | ||
3899 | LLCoordGL caret_coord; | ||
3900 | LLRect preedit_bounds; | ||
3901 | mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL); | ||
3902 | |||
3903 | CANDIDATEFORM *const form = (CANDIDATEFORM *)param; | ||
3904 | DWORD const dwIndex = form->dwIndex; | ||
3905 | fillCandidateForm(caret_coord, preedit_bounds, form); | ||
3906 | form->dwIndex = dwIndex; | ||
3907 | |||
3908 | *result = 1; | ||
3909 | return TRUE; | ||
3910 | } | ||
3911 | case IMR_QUERYCHARPOSITION: | ||
3912 | { | ||
3913 | IMECHARPOSITION *const char_position = (IMECHARPOSITION *)param; | ||
3914 | |||
3915 | // char_position->dwCharPos counts in number of | ||
3916 | // WCHARs, i.e., UTF-16 encoding units, so we can't simply pass the | ||
3917 | // number to getPreeditLocation. | ||
3918 | |||
3919 | const LLWString & wtext = mPreeditor->getWText(); | ||
3920 | S32 preedit, preedit_length; | ||
3921 | mPreeditor->getPreeditRange(&preedit, &preedit_length); | ||
3922 | LLCoordGL caret_coord; | ||
3923 | LLRect preedit_bounds, text_control; | ||
3924 | const S32 position = wstring_wstring_length_from_utf16_length(wtext, preedit, char_position->dwCharPos); | ||
3925 | |||
3926 | if (!mPreeditor->getPreeditLocation(position, &caret_coord, &preedit_bounds, &text_control)) | ||
3927 | { | ||
3928 | llwarns << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << llendl; | ||
3929 | return FALSE; | ||
3930 | } | ||
3931 | fillCharPosition(caret_coord, preedit_bounds, text_control, char_position); | ||
3932 | |||
3933 | *result = 1; | ||
3934 | return TRUE; | ||
3935 | } | ||
3936 | case IMR_COMPOSITIONFONT: | ||
3937 | { | ||
3938 | fillCompositionLogfont((LOGFONT *)param); | ||
3939 | |||
3940 | *result = 1; | ||
3941 | return TRUE; | ||
3942 | } | ||
3943 | case IMR_RECONVERTSTRING: | ||
3944 | { | ||
3945 | mPreeditor->resetPreedit(); | ||
3946 | const LLWString & wtext = mPreeditor->getWText(); | ||
3947 | S32 select, select_length; | ||
3948 | mPreeditor->getSelectionRange(&select, &select_length); | ||
3949 | |||
3950 | S32 context_offset; | ||
3951 | const LLWString context = find_context(wtext, select, select_length, &context_offset); | ||
3952 | |||
3953 | RECONVERTSTRING * const reconvert_string = (RECONVERTSTRING *)param; | ||
3954 | const U32 size = fillReconvertString(context, select - context_offset, select_length, reconvert_string); | ||
3955 | if (reconvert_string) | ||
3956 | { | ||
3957 | if (select_length == 0) | ||
3958 | { | ||
3959 | // Let the IME to decide the reconversion range, and | ||
3960 | // adjust the reconvert_string structure accordingly. | ||
3961 | HIMC himc = LLWinImm::getContext(mWindowHandle); | ||
3962 | const BOOL adjusted = LLWinImm::setCompositionString(himc, | ||
3963 | SCS_QUERYRECONVERTSTRING, reconvert_string, size, NULL, 0); | ||
3964 | LLWinImm::releaseContext(mWindowHandle, himc); | ||
3965 | if (adjusted) | ||
3966 | { | ||
3967 | const llutf16string & text_utf16 = wstring_to_utf16str(context); | ||
3968 | const S32 new_preedit_start = reconvert_string->dwCompStrOffset / sizeof(WCHAR); | ||
3969 | const S32 new_preedit_end = new_preedit_start + reconvert_string->dwCompStrLen; | ||
3970 | select = utf16str_wstring_length(text_utf16, new_preedit_start); | ||
3971 | select_length = utf16str_wstring_length(text_utf16, new_preedit_end) - select; | ||
3972 | select += context_offset; | ||
3973 | } | ||
3974 | } | ||
3975 | mPreeditor->markAsPreedit(select, select_length); | ||
3976 | } | ||
3977 | |||
3978 | *result = size; | ||
3979 | return TRUE; | ||
3980 | } | ||
3981 | case IMR_CONFIRMRECONVERTSTRING: | ||
3982 | { | ||
3983 | *result = FALSE; | ||
3984 | return TRUE; | ||
3985 | } | ||
3986 | case IMR_DOCUMENTFEED: | ||
3987 | { | ||
3988 | const LLWString & wtext = mPreeditor->getWText(); | ||
3989 | S32 preedit, preedit_length; | ||
3990 | mPreeditor->getPreeditRange(&preedit, &preedit_length); | ||
3991 | |||
3992 | S32 context_offset; | ||
3993 | LLWString context = find_context(wtext, preedit, preedit_length, &context_offset); | ||
3994 | preedit -= context_offset; | ||
3995 | if (preedit_length) | ||
3996 | { | ||
3997 | // IMR_DOCUMENTFEED may be called when we have an active preedit. | ||
3998 | // We should pass the context string *excluding* the preedit string. | ||
3999 | // Otherwise, some IME are confused. | ||
4000 | context.erase(preedit, preedit_length); | ||
4001 | } | ||
4002 | |||
4003 | RECONVERTSTRING *reconvert_string = (RECONVERTSTRING *)param; | ||
4004 | *result = fillReconvertString(context, preedit, 0, reconvert_string); | ||
4005 | return TRUE; | ||
4006 | } | ||
4007 | default: | ||
4008 | return FALSE; | ||
4009 | } | ||
4010 | } | ||
4011 | |||
4012 | return FALSE; | ||
4013 | } | ||
4014 | |||
4015 | |||
3403 | #endif // LL_WINDOWS | 4016 | #endif // LL_WINDOWS |