1 /*
2 * PROJECT: ReactOS msctfime.ime
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Supporting IME interface of Text Input Processors (TIPs)
5 * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6 */
7
8 #include "msctfime.h"
9
10 WINE_DEFAULT_DEBUG_CHANNEL(msctfime);
11
12 HINSTANCE g_hInst = NULL; /* The instance of this module */
13 BOOL g_bWinLogon = FALSE;
14 UINT g_uACP = CP_ACP;
15 DWORD g_dwOSInfo = 0;
16 BOOL gfTFInitLib = FALSE;
17 CRITICAL_SECTION g_csLock;
18 CDispAttrPropCache *g_pPropCache = NULL;
19
20 /// Selects or unselects the input context.
21 /// @implemented
22 static HRESULT
InternalSelectEx(_In_ HIMC hIMC,_In_ BOOL fSelect,_In_ LANGID LangID)23 InternalSelectEx(
24 _In_ HIMC hIMC,
25 _In_ BOOL fSelect,
26 _In_ LANGID LangID)
27 {
28 CicIMCLock imcLock(hIMC);
29 if (FAILED(imcLock.m_hr))
30 return imcLock.m_hr;
31
32 if (PRIMARYLANGID(LangID) == LANG_CHINESE)
33 {
34 imcLock.get().cfCandForm[0].dwStyle = 0;
35 imcLock.get().cfCandForm[0].dwIndex = (DWORD)-1;
36 }
37
38 if (!fSelect)
39 {
40 imcLock.get().fdwInit &= ~INIT_GUIDMAP;
41 return imcLock.m_hr;
42 }
43
44 if (!imcLock.ClearCand())
45 return imcLock.m_hr;
46
47 // Populate conversion mode
48 if (!(imcLock.get().fdwInit & INIT_CONVERSION))
49 {
50 DWORD dwConv = (imcLock.get().fdwConversion & IME_CMODE_SOFTKBD);
51 if (LangID)
52 {
53 if (PRIMARYLANGID(LangID) == LANG_JAPANESE)
54 {
55 dwConv |= IME_CMODE_ROMAN | IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE;
56 }
57 else if (PRIMARYLANGID(LangID) != LANG_KOREAN)
58 {
59 dwConv |= IME_CMODE_NATIVE;
60 }
61 }
62 imcLock.get().fdwConversion |= dwConv;
63 imcLock.get().fdwInit |= INIT_CONVERSION;
64 }
65
66 // Populate sentence mode
67 imcLock.get().fdwSentence |= IME_SMODE_PHRASEPREDICT;
68
69 // Populate LOGFONT
70 if (!(imcLock.get().fdwInit & INIT_LOGFONT))
71 {
72 // Get logical font
73 LOGFONTW lf;
74 HDC hDC = ::GetDC(imcLock.get().hWnd);
75 HGDIOBJ hFont = ::GetCurrentObject(hDC, OBJ_FONT);
76 ::GetObjectW(hFont, sizeof(LOGFONTW), &lf);
77 ::ReleaseDC(imcLock.get().hWnd, hDC);
78
79 imcLock.get().lfFont.W = lf;
80 imcLock.get().fdwInit |= INIT_LOGFONT;
81 }
82 imcLock.get().lfFont.W.lfCharSet = GetCharsetFromLangId(LangID);
83
84 imcLock.InitContext();
85
86 return imcLock.m_hr;
87 }
88
89 /// Retrieves the IME information.
90 /// @implemented
91 HRESULT
Inquire(_Out_ LPIMEINFO lpIMEInfo,_Out_ LPWSTR lpszWndClass,_In_ DWORD dwSystemInfoFlags,_In_ HKL hKL)92 Inquire(
93 _Out_ LPIMEINFO lpIMEInfo,
94 _Out_ LPWSTR lpszWndClass,
95 _In_ DWORD dwSystemInfoFlags,
96 _In_ HKL hKL)
97 {
98 if (!lpIMEInfo)
99 return E_OUTOFMEMORY;
100
101 StringCchCopyW(lpszWndClass, 64, L"MSCTFIME UI");
102 lpIMEInfo->dwPrivateDataSize = 0;
103
104 switch (LOWORD(hKL)) // Language ID
105 {
106 case MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT): // Japanese
107 {
108 lpIMEInfo->fdwProperty = IME_PROP_COMPLETE_ON_UNSELECT | IME_PROP_SPECIAL_UI |
109 IME_PROP_AT_CARET | IME_PROP_NEED_ALTKEY |
110 IME_PROP_KBD_CHAR_FIRST;
111 lpIMEInfo->fdwConversionCaps = IME_CMODE_FULLSHAPE | IME_CMODE_KATAKANA |
112 IME_CMODE_NATIVE;
113 lpIMEInfo->fdwSentenceCaps = IME_SMODE_CONVERSATION | IME_SMODE_PLAURALCLAUSE;
114 lpIMEInfo->fdwSelectCaps = SELECT_CAP_SENTENCE | SELECT_CAP_CONVERSION;
115 lpIMEInfo->fdwSCSCaps = SCS_CAP_SETRECONVERTSTRING | SCS_CAP_MAKEREAD |
116 SCS_CAP_COMPSTR;
117 lpIMEInfo->fdwUICaps = UI_CAP_ROT90;
118 break;
119 }
120 case MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT): // Korean
121 {
122 lpIMEInfo->fdwProperty = IME_PROP_COMPLETE_ON_UNSELECT | IME_PROP_SPECIAL_UI |
123 IME_PROP_AT_CARET | IME_PROP_NEED_ALTKEY |
124 IME_PROP_KBD_CHAR_FIRST;
125 lpIMEInfo->fdwConversionCaps = IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE;
126 lpIMEInfo->fdwSentenceCaps = 0;
127 lpIMEInfo->fdwSCSCaps = SCS_CAP_SETRECONVERTSTRING | SCS_CAP_COMPSTR;
128 lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION;
129 lpIMEInfo->fdwUICaps = UI_CAP_ROT90;
130 break;
131 }
132 case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED): // Simplified Chinese
133 case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL): // Traditional Chinese
134 {
135 lpIMEInfo->fdwProperty = IME_PROP_SPECIAL_UI | IME_PROP_AT_CARET |
136 IME_PROP_NEED_ALTKEY | IME_PROP_KBD_CHAR_FIRST;
137 lpIMEInfo->fdwConversionCaps = IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE;
138 lpIMEInfo->fdwSentenceCaps = SELECT_CAP_CONVERSION;
139 lpIMEInfo->fdwSelectCaps = 0;
140 lpIMEInfo->fdwSCSCaps = SCS_CAP_SETRECONVERTSTRING | SCS_CAP_MAKEREAD |
141 SCS_CAP_COMPSTR;
142 lpIMEInfo->fdwUICaps = UI_CAP_ROT90;
143 break;
144 }
145 default: // Otherwise
146 {
147 lpIMEInfo->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET;
148 lpIMEInfo->fdwConversionCaps = 0;
149 lpIMEInfo->fdwSentenceCaps = 0;
150 lpIMEInfo->fdwSCSCaps = 0;
151 lpIMEInfo->fdwUICaps = 0;
152 lpIMEInfo->fdwSelectCaps = 0;
153 break;
154 }
155 }
156
157 return S_OK;
158 }
159
160 /***********************************************************************
161 * ImeInquire (MSCTFIME.@)
162 *
163 * MSCTFIME's ImeInquire does nothing.
164 *
165 * @implemented
166 * @see CtfImeInquireExW
167 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeInquire.html
168 */
169 EXTERN_C
170 BOOL WINAPI
ImeInquire(_Out_ LPIMEINFO lpIMEInfo,_Out_ LPWSTR lpszWndClass,_In_ DWORD dwSystemInfoFlags)171 ImeInquire(
172 _Out_ LPIMEINFO lpIMEInfo,
173 _Out_ LPWSTR lpszWndClass,
174 _In_ DWORD dwSystemInfoFlags)
175 {
176 TRACE("(%p, %p, 0x%lX)\n", lpIMEInfo, lpszWndClass, dwSystemInfoFlags);
177 return FALSE;
178 }
179
180 /***********************************************************************
181 * ImeConversionList (MSCTFIME.@)
182 *
183 * MSCTFIME's ImeConversionList does nothing.
184 *
185 * @implemented
186 * @see ImmGetConversionListW
187 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeConversionList.html
188 */
189 EXTERN_C DWORD WINAPI
ImeConversionList(_In_ HIMC hIMC,_In_ LPCWSTR lpSrc,_Out_ LPCANDIDATELIST lpDst,_In_ DWORD dwBufLen,_In_ UINT uFlag)190 ImeConversionList(
191 _In_ HIMC hIMC,
192 _In_ LPCWSTR lpSrc,
193 _Out_ LPCANDIDATELIST lpDst,
194 _In_ DWORD dwBufLen,
195 _In_ UINT uFlag)
196 {
197 TRACE("(%p, %s, %p, 0x%lX, %u)\n", hIMC, debugstr_w(lpSrc), lpDst, dwBufLen, uFlag);
198 return 0;
199 }
200
201 /***********************************************************************
202 * ImeRegisterWord (MSCTFIME.@)
203 *
204 * MSCTFIME's ImeRegisterWord does nothing.
205 *
206 * @implemented
207 * @see ImeUnregisterWord
208 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeRegisterWord.html
209 */
210 EXTERN_C BOOL WINAPI
ImeRegisterWord(_In_ LPCWSTR lpszReading,_In_ DWORD dwStyle,_In_ LPCWSTR lpszString)211 ImeRegisterWord(
212 _In_ LPCWSTR lpszReading,
213 _In_ DWORD dwStyle,
214 _In_ LPCWSTR lpszString)
215 {
216 TRACE("(%s, 0x%lX, %s)\n", debugstr_w(lpszReading), dwStyle, debugstr_w(lpszString));
217 return FALSE;
218 }
219
220 /***********************************************************************
221 * ImeUnregisterWord (MSCTFIME.@)
222 *
223 * MSCTFIME's ImeUnregisterWord does nothing.
224 *
225 * @implemented
226 * @see ImeRegisterWord
227 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeUnregisterWord.html
228 */
229 EXTERN_C BOOL WINAPI
ImeUnregisterWord(_In_ LPCWSTR lpszReading,_In_ DWORD dwStyle,_In_ LPCWSTR lpszString)230 ImeUnregisterWord(
231 _In_ LPCWSTR lpszReading,
232 _In_ DWORD dwStyle,
233 _In_ LPCWSTR lpszString)
234 {
235 TRACE("(%s, 0x%lX, %s)\n", debugstr_w(lpszReading), dwStyle, debugstr_w(lpszString));
236 return FALSE;
237 }
238
239 /***********************************************************************
240 * ImeGetRegisterWordStyle (MSCTFIME.@)
241 *
242 * MSCTFIME's ImeGetRegisterWordStyle does nothing.
243 *
244 * @implemented
245 * @see ImeRegisterWord
246 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeGetRegisterWordStyle.html
247 */
248 EXTERN_C UINT WINAPI
ImeGetRegisterWordStyle(_In_ UINT nItem,_Out_ LPSTYLEBUFW lpStyleBuf)249 ImeGetRegisterWordStyle(
250 _In_ UINT nItem,
251 _Out_ LPSTYLEBUFW lpStyleBuf)
252 {
253 TRACE("(%u, %p)\n", nItem, lpStyleBuf);
254 return 0;
255 }
256
257 /***********************************************************************
258 * ImeEnumRegisterWord (MSCTFIME.@)
259 *
260 * MSCTFIME's ImeEnumRegisterWord does nothing.
261 *
262 * @implemented
263 * @see ImeRegisterWord
264 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeEnumRegisterWord.html
265 */
266 EXTERN_C UINT WINAPI
ImeEnumRegisterWord(_In_ REGISTERWORDENUMPROCW lpfnEnumProc,_In_opt_ LPCWSTR lpszReading,_In_ DWORD dwStyle,_In_opt_ LPCWSTR lpszString,_In_opt_ LPVOID lpData)267 ImeEnumRegisterWord(
268 _In_ REGISTERWORDENUMPROCW lpfnEnumProc,
269 _In_opt_ LPCWSTR lpszReading,
270 _In_ DWORD dwStyle,
271 _In_opt_ LPCWSTR lpszString,
272 _In_opt_ LPVOID lpData)
273 {
274 TRACE("(%p, %s, %lu, %s, %p)\n", lpfnEnumProc, debugstr_w(lpszReading),
275 dwStyle, debugstr_w(lpszString), lpData);
276 return 0;
277 }
278
279 /***********************************************************************
280 * ImeConfigure (MSCTFIME.@)
281 *
282 * @implemented
283 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeConfigure.html
284 */
285 EXTERN_C BOOL WINAPI
ImeConfigure(_In_ HKL hKL,_In_ HWND hWnd,_In_ DWORD dwMode,_Inout_opt_ LPVOID lpData)286 ImeConfigure(
287 _In_ HKL hKL,
288 _In_ HWND hWnd,
289 _In_ DWORD dwMode,
290 _Inout_opt_ LPVOID lpData)
291 {
292 TRACE("(%p, %p, %lu, %p)\n", hKL, hWnd, dwMode, lpData);
293
294 TLS *pTLS = TLS::GetTLS();
295 if (!pTLS || !pTLS->m_pBridge || !pTLS->m_pThreadMgr)
296 return FALSE;
297
298 auto pBridge = pTLS->m_pBridge;
299 auto pThreadMgr = pTLS->m_pThreadMgr;
300
301 if (dwMode & 0x1)
302 return (pBridge->ConfigureGeneral(pTLS, pThreadMgr, hKL, hWnd) == S_OK);
303
304 if (dwMode & 0x2)
305 return (pBridge->ConfigureRegisterWord(pTLS, pThreadMgr, hKL, hWnd, lpData) == S_OK);
306
307 return FALSE;
308 }
309
310 /***********************************************************************
311 * ImeDestroy (MSCTFIME.@)
312 *
313 * @implemented
314 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeDestroy.html
315 */
316 EXTERN_C BOOL WINAPI
ImeDestroy(_In_ UINT uReserved)317 ImeDestroy(
318 _In_ UINT uReserved)
319 {
320 TRACE("(%u)\n", uReserved);
321
322 TLS *pTLS = TLS::PeekTLS();
323 if (pTLS)
324 return FALSE;
325
326 if (!pTLS->m_pBridge || !pTLS->m_pThreadMgr)
327 return FALSE;
328
329 if (pTLS->m_dwSystemInfoFlags & IME_SYSINFO_WINLOGON)
330 return TRUE;
331
332 if (pTLS->m_pBridge->DeactivateIMMX(pTLS, pTLS->m_pThreadMgr) != S_OK)
333 return FALSE;
334
335 return pTLS->m_pBridge->UnInitIMMX(pTLS);
336 }
337
338 /***********************************************************************
339 * ImeEscape (MSCTFIME.@)
340 *
341 * MSCTFIME's ImeEscape does nothing.
342 *
343 * @implemented
344 * @see CtfImeEscapeEx
345 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeEscape.html
346 */
347 EXTERN_C LRESULT WINAPI
ImeEscape(_In_ HIMC hIMC,_In_ UINT uEscape,_Inout_opt_ LPVOID lpData)348 ImeEscape(
349 _In_ HIMC hIMC,
350 _In_ UINT uEscape,
351 _Inout_opt_ LPVOID lpData)
352 {
353 TRACE("(%p, %u, %p)\n", hIMC, uEscape, lpData);
354 return 0;
355 }
356
357 /***********************************************************************
358 * ImeProcessKey (MSCTFIME.@)
359 *
360 * @implemented
361 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeProcessKey.html
362 */
363 EXTERN_C BOOL WINAPI
ImeProcessKey(_In_ HIMC hIMC,_In_ UINT uVirtKey,_In_ LPARAM lParam,_In_ CONST LPBYTE lpbKeyState)364 ImeProcessKey(
365 _In_ HIMC hIMC,
366 _In_ UINT uVirtKey,
367 _In_ LPARAM lParam,
368 _In_ CONST LPBYTE lpbKeyState)
369 {
370 TRACE("(%p, %u, %p, lpbKeyState)\n", hIMC, uVirtKey, lParam, lpbKeyState);
371
372 TLS *pTLS = TLS::GetTLS();
373 if (!pTLS)
374 return FALSE;
375
376 auto pBridge = pTLS->m_pBridge;
377 auto pThreadMgr = pTLS->m_pThreadMgr;
378 if (!pBridge || !pThreadMgr)
379 return FALSE;
380
381 if (pTLS->m_dwFlags1 & 0x1)
382 {
383 ITfDocumentMgr *pDocMgr = NULL;
384 pThreadMgr->GetFocus(&pDocMgr);
385 if (pDocMgr && !CicBridge::IsOwnDim(pDocMgr))
386 {
387 pDocMgr->Release();
388 return FALSE;
389 }
390
391 if (pDocMgr)
392 pDocMgr->Release();
393 }
394
395 LANGID LangID = LOWORD(::GetKeyboardLayout(0));
396 if (((pTLS->m_dwFlags2 & 1) && MsimtfIsGuidMapEnable(hIMC, NULL)) ||
397 ((lParam & (KF_ALTDOWN << 16)) &&
398 (LangID == MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT)) &&
399 IsVKDBEKey(uVirtKey)))
400 {
401 return FALSE;
402 }
403
404 INT nUnknown60 = 0;
405 return pBridge->ProcessKey(pTLS, pThreadMgr, hIMC, uVirtKey, lParam, lpbKeyState, &nUnknown60);
406 }
407
408 /***********************************************************************
409 * ImeSelect (MSCTFIME.@)
410 *
411 * MSCTFIME's ImeSelect does nothing.
412 *
413 * @implemented
414 * @see CtfImeSelectEx
415 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeSelect.html
416 */
417 EXTERN_C BOOL WINAPI
ImeSelect(_In_ HIMC hIMC,_In_ BOOL fSelect)418 ImeSelect(
419 _In_ HIMC hIMC,
420 _In_ BOOL fSelect)
421 {
422 TRACE("(%p, %u)\n", hIMC, fSelect);
423 return FALSE;
424 }
425
426 /***********************************************************************
427 * ImeSetActiveContext (MSCTFIME.@)
428 *
429 * MSCTFIME's ImeSetActiveContext does nothing.
430 *
431 * @implemented
432 * @see CtfImeSetActiveContextAlways
433 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeSetActiveContext.html
434 */
435 EXTERN_C BOOL WINAPI
ImeSetActiveContext(_In_ HIMC hIMC,_In_ BOOL fFlag)436 ImeSetActiveContext(
437 _In_ HIMC hIMC,
438 _In_ BOOL fFlag)
439 {
440 TRACE("(%p, %u)\n", hIMC, fFlag);
441 return FALSE;
442 }
443
444 /***********************************************************************
445 * ImeToAsciiEx (MSCTFIME.@)
446 *
447 * @implemented
448 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeToAsciiEx.html
449 */
450 EXTERN_C UINT WINAPI
ImeToAsciiEx(_In_ UINT uVirtKey,_In_ UINT uScanCode,_In_ CONST LPBYTE lpbKeyState,_Out_ LPTRANSMSGLIST lpTransMsgList,_In_ UINT fuState,_In_ HIMC hIMC)451 ImeToAsciiEx(
452 _In_ UINT uVirtKey,
453 _In_ UINT uScanCode,
454 _In_ CONST LPBYTE lpbKeyState,
455 _Out_ LPTRANSMSGLIST lpTransMsgList,
456 _In_ UINT fuState,
457 _In_ HIMC hIMC)
458 {
459 TRACE("(%u, %u, %p, %p, %u, %p)\n", uVirtKey, uScanCode, lpbKeyState, lpTransMsgList,
460 fuState, hIMC);
461
462 TLS *pTLS = TLS::GetTLS();
463 if (!pTLS)
464 return 0;
465
466 auto pBridge = pTLS->m_pBridge;
467 auto pThreadMgr = pTLS->m_pThreadMgr;
468 if (!pBridge || !pThreadMgr)
469 return 0;
470
471 UINT ret = 0;
472 HRESULT hr = pBridge->ToAsciiEx(pTLS, pThreadMgr, uVirtKey, uScanCode, lpbKeyState,
473 lpTransMsgList, fuState, hIMC, &ret);
474 return ((hr == S_OK) ? ret : 0);
475 }
476
477 /***********************************************************************
478 * NotifyIME (MSCTFIME.@)
479 *
480 * @implemented
481 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/NotifyIME.html
482 */
483 EXTERN_C BOOL WINAPI
NotifyIME(_In_ HIMC hIMC,_In_ DWORD dwAction,_In_ DWORD dwIndex,_In_ DWORD_PTR dwValue)484 NotifyIME(
485 _In_ HIMC hIMC,
486 _In_ DWORD dwAction,
487 _In_ DWORD dwIndex,
488 _In_ DWORD_PTR dwValue)
489 {
490 TRACE("(%p, 0x%lX, 0x%lX, %p)\n", hIMC, dwAction, dwIndex, dwValue);
491
492 TLS *pTLS = TLS::GetTLS();
493 if (!pTLS)
494 return FALSE;
495
496 auto pBridge = pTLS->m_pBridge;
497 auto pThreadMgr = pTLS->m_pThreadMgr;
498 if (!pBridge || !pThreadMgr)
499 return FALSE;
500
501 HRESULT hr = pBridge->Notify(pTLS, pThreadMgr, hIMC, dwAction, dwIndex, dwValue);
502 return (hr == S_OK);
503 }
504
505 /***********************************************************************
506 * ImeSetCompositionString (MSCTFIME.@)
507 *
508 * @implemented
509 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImeSetCompositionString.html
510 */
511 EXTERN_C BOOL WINAPI
ImeSetCompositionString(_In_ HIMC hIMC,_In_ DWORD dwIndex,_In_opt_ LPCVOID lpComp,_In_ DWORD dwCompLen,_In_opt_ LPCVOID lpRead,_In_ DWORD dwReadLen)512 ImeSetCompositionString(
513 _In_ HIMC hIMC,
514 _In_ DWORD dwIndex,
515 _In_opt_ LPCVOID lpComp,
516 _In_ DWORD dwCompLen,
517 _In_opt_ LPCVOID lpRead,
518 _In_ DWORD dwReadLen)
519 {
520 TRACE("(%p, 0x%lX, %p, 0x%lX, %p, 0x%lX)\n", hIMC, dwIndex, lpComp, dwCompLen,
521 lpRead, dwReadLen);
522
523 TLS *pTLS = TLS::GetTLS();
524 if (!pTLS)
525 return FALSE;
526
527 auto pBridge = pTLS->m_pBridge;
528 auto pThreadMgr = pTLS->m_pThreadMgr;
529 if (!pBridge || !pThreadMgr)
530 return FALSE;
531
532 return pBridge->SetCompositionString(pTLS, pThreadMgr, hIMC, dwIndex,
533 lpComp, dwCompLen, lpRead, dwReadLen);
534 }
535
536 /***********************************************************************
537 * CtfImeInquireExW (MSCTFIME.@)
538 *
539 * @implemented
540 */
541 EXTERN_C HRESULT WINAPI
CtfImeInquireExW(_Out_ LPIMEINFO lpIMEInfo,_Out_ LPWSTR lpszWndClass,_In_ DWORD dwSystemInfoFlags,_In_ HKL hKL)542 CtfImeInquireExW(
543 _Out_ LPIMEINFO lpIMEInfo,
544 _Out_ LPWSTR lpszWndClass,
545 _In_ DWORD dwSystemInfoFlags,
546 _In_ HKL hKL)
547 {
548 TRACE("(%p, %p, 0x%lX, %p)\n", lpIMEInfo, lpszWndClass, dwSystemInfoFlags, hKL);
549
550 TLS *pTLS = TLS::GetTLS();
551 if (!pTLS)
552 return E_OUTOFMEMORY;
553
554 if (!IsInteractiveUserLogon())
555 {
556 dwSystemInfoFlags |= IME_SYSINFO_WINLOGON;
557 g_bWinLogon = TRUE;
558 }
559
560 pTLS->m_dwSystemInfoFlags = dwSystemInfoFlags;
561
562 return Inquire(lpIMEInfo, lpszWndClass, dwSystemInfoFlags, hKL);
563 }
564
565 /***********************************************************************
566 * CtfImeSelectEx (MSCTFIME.@)
567 *
568 * @implemented
569 */
570 EXTERN_C BOOL WINAPI
CtfImeSelectEx(_In_ HIMC hIMC,_In_ BOOL fSelect,_In_ HKL hKL)571 CtfImeSelectEx(
572 _In_ HIMC hIMC,
573 _In_ BOOL fSelect,
574 _In_ HKL hKL)
575 {
576 TRACE("(%p, %d, %p)\n", hIMC, fSelect, hKL);
577
578 TLS *pTLS = TLS::PeekTLS();
579 if (!pTLS)
580 return E_OUTOFMEMORY;
581
582 InternalSelectEx(hIMC, fSelect, LOWORD(hKL));
583
584 if (!pTLS->m_pBridge || !pTLS->m_pThreadMgr)
585 return E_OUTOFMEMORY;
586
587 return pTLS->m_pBridge->SelectEx(pTLS, pTLS->m_pThreadMgr, hIMC, fSelect, hKL);
588 }
589
590 /***********************************************************************
591 * CtfImeEscapeEx (MSCTFIME.@)
592 *
593 * @implemented
594 */
595 EXTERN_C LRESULT WINAPI
CtfImeEscapeEx(_In_ HIMC hIMC,_In_ UINT uSubFunc,_Inout_opt_ LPVOID lpData,_In_ HKL hKL)596 CtfImeEscapeEx(
597 _In_ HIMC hIMC,
598 _In_ UINT uSubFunc,
599 _Inout_opt_ LPVOID lpData,
600 _In_ HKL hKL)
601 {
602 TRACE("(%p, %u, %p, %p)\n", hIMC, uSubFunc, lpData, hKL);
603
604 if (LOWORD(hKL) != MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT))
605 return 0;
606
607 TLS *pTLS = TLS::GetTLS();
608 if (!pTLS || !pTLS->m_pBridge)
609 return 0;
610
611 return pTLS->m_pBridge->EscapeKorean(pTLS, hIMC, uSubFunc, lpData);
612 }
613
614 /***********************************************************************
615 * CtfImeGetGuidAtom (MSCTFIME.@)
616 *
617 * @implemented
618 */
619 EXTERN_C HRESULT WINAPI
CtfImeGetGuidAtom(_In_ HIMC hIMC,_In_ DWORD dwUnknown,_Out_opt_ LPDWORD pdwGuidAtom)620 CtfImeGetGuidAtom(
621 _In_ HIMC hIMC,
622 _In_ DWORD dwUnknown,
623 _Out_opt_ LPDWORD pdwGuidAtom)
624 {
625 TRACE("(%p, 0x%lX, %p)\n", hIMC, dwUnknown, pdwGuidAtom);
626
627 CicIMCLock imcLock(hIMC);
628 if (FAILED(imcLock.m_hr))
629 return imcLock.m_hr;
630
631 CicIMCCLock<CTFIMECONTEXT> imccLock(imcLock.get().hCtfImeContext);
632 if (FAILED(imccLock.m_hr))
633 return imccLock.m_hr;
634
635 if (!imccLock.get().m_pCicIC)
636 return E_OUTOFMEMORY;
637
638 return imccLock.get().m_pCicIC->GetGuidAtom(imcLock, dwUnknown, pdwGuidAtom);
639 }
640
641 /***********************************************************************
642 * CtfImeIsGuidMapEnable (MSCTFIME.@)
643 *
644 * @implemented
645 */
646 EXTERN_C BOOL WINAPI
CtfImeIsGuidMapEnable(_In_ HIMC hIMC)647 CtfImeIsGuidMapEnable(
648 _In_ HIMC hIMC)
649 {
650 TRACE("(%p)\n", hIMC);
651
652 BOOL ret = FALSE;
653 CicIMCLock imcLock(hIMC);
654 if (SUCCEEDED(imcLock.m_hr))
655 ret = !!(imcLock.get().fdwInit & INIT_GUIDMAP);
656
657 return ret;
658 }
659
660 /***********************************************************************
661 * CtfImeCreateThreadMgr (MSCTFIME.@)
662 *
663 * @implemented
664 */
665 EXTERN_C HRESULT WINAPI
CtfImeCreateThreadMgr(VOID)666 CtfImeCreateThreadMgr(VOID)
667 {
668 TRACE("()\n");
669
670 TLS *pTLS = TLS::GetTLS();
671 if (!pTLS)
672 return E_OUTOFMEMORY;
673
674 if (!pTLS->m_pBridge)
675 {
676 pTLS->m_pBridge = new(cicNoThrow) CicBridge();
677 if (!pTLS->m_pBridge)
678 return E_OUTOFMEMORY;
679 }
680
681 HRESULT hr = S_OK;
682 if (!g_bWinLogon && !(pTLS->m_dwSystemInfoFlags & IME_SYSINFO_WINLOGON))
683 {
684 hr = pTLS->m_pBridge->InitIMMX(pTLS);
685 if (SUCCEEDED(hr))
686 {
687 if (!pTLS->m_pThreadMgr)
688 return E_OUTOFMEMORY;
689
690 hr = pTLS->m_pBridge->ActivateIMMX(pTLS, pTLS->m_pThreadMgr);
691 if (FAILED(hr))
692 pTLS->m_pBridge->UnInitIMMX(pTLS);
693 }
694 }
695
696 return hr;
697 }
698
699 /***********************************************************************
700 * CtfImeDestroyThreadMgr (MSCTFIME.@)
701 *
702 * @implemented
703 */
704 EXTERN_C HRESULT WINAPI
CtfImeDestroyThreadMgr(VOID)705 CtfImeDestroyThreadMgr(VOID)
706 {
707 TRACE("()\n");
708
709 TLS *pTLS = TLS::PeekTLS();
710 if (!pTLS)
711 return E_OUTOFMEMORY;
712
713 if (pTLS->m_pBridge)
714 {
715 pTLS->m_pBridge = new(cicNoThrow) CicBridge();
716 if (!pTLS->m_pBridge)
717 return E_OUTOFMEMORY;
718 }
719
720 if (!pTLS->m_pThreadMgr)
721 return E_OUTOFMEMORY;
722
723 if (pTLS->m_dwSystemInfoFlags & IME_SYSINFO_WINLOGON)
724 return S_OK;
725
726 HRESULT hr = pTLS->m_pBridge->DeactivateIMMX(pTLS, pTLS->m_pThreadMgr);
727 if (hr == S_OK)
728 pTLS->m_pBridge->UnInitIMMX(pTLS);
729
730 return hr;
731 }
732
733 /***********************************************************************
734 * CtfImeCreateInputContext (MSCTFIME.@)
735 *
736 * @implemented
737 */
738 EXTERN_C HRESULT WINAPI
CtfImeCreateInputContext(_In_ HIMC hIMC)739 CtfImeCreateInputContext(
740 _In_ HIMC hIMC)
741 {
742 TRACE("(%p)\n", hIMC);
743
744 TLS *pTLS = TLS::GetTLS();
745 if (!pTLS || !pTLS->m_pBridge)
746 return E_OUTOFMEMORY;
747
748 return pTLS->m_pBridge->CreateInputContext(pTLS, hIMC);
749 }
750
751 /***********************************************************************
752 * CtfImeDestroyInputContext (MSCTFIME.@)
753 *
754 * @implemented
755 */
756 EXTERN_C HRESULT WINAPI
CtfImeDestroyInputContext(_In_ HIMC hIMC)757 CtfImeDestroyInputContext(
758 _In_ HIMC hIMC)
759 {
760 TRACE("(%p)\n", hIMC);
761
762 TLS *pTLS = TLS::PeekTLS();
763 if (!pTLS || !pTLS->m_pBridge)
764 return E_OUTOFMEMORY;
765
766 return pTLS->m_pBridge->DestroyInputContext(pTLS, hIMC);
767 }
768
769 /***********************************************************************
770 * CtfImeSetActiveContextAlways (MSCTFIME.@)
771 *
772 * @implemented
773 */
774 EXTERN_C HRESULT WINAPI
CtfImeSetActiveContextAlways(_In_ HIMC hIMC,_In_ BOOL fActive,_In_ HWND hWnd,_In_ HKL hKL)775 CtfImeSetActiveContextAlways(
776 _In_ HIMC hIMC,
777 _In_ BOOL fActive,
778 _In_ HWND hWnd,
779 _In_ HKL hKL)
780 {
781 TRACE("(%p, %d, %p, %p)\n", hIMC, fActive, hWnd, hKL);
782
783 TLS *pTLS = TLS::GetTLS();
784 if (!pTLS || !pTLS->m_pBridge)
785 return E_OUTOFMEMORY;
786 return pTLS->m_pBridge->SetActiveContextAlways(pTLS, hIMC, fActive, hWnd, hKL);
787 }
788
789 /***********************************************************************
790 * CtfImeProcessCicHotkey (MSCTFIME.@)
791 *
792 * @implemented
793 */
794 EXTERN_C HRESULT WINAPI
CtfImeProcessCicHotkey(_In_ HIMC hIMC,_In_ UINT vKey,_In_ LPARAM lParam)795 CtfImeProcessCicHotkey(
796 _In_ HIMC hIMC,
797 _In_ UINT vKey,
798 _In_ LPARAM lParam)
799 {
800 TRACE("(%p, %u, %p)\n", hIMC, vKey, lParam);
801
802 TLS *pTLS = TLS::GetTLS();
803 if (!pTLS)
804 return S_OK;
805
806 HRESULT hr = S_OK;
807 ITfThreadMgr *pThreadMgr = NULL;
808 ITfThreadMgr_P *pThreadMgr_P = NULL;
809 if ((TF_GetThreadMgr(&pThreadMgr) == S_OK) &&
810 (pThreadMgr->QueryInterface(IID_ITfThreadMgr_P, (void**)&pThreadMgr_P) == S_OK) &&
811 CtfImmIsCiceroStartedInThread())
812 {
813 HRESULT hr2;
814 if (SUCCEEDED(pThreadMgr_P->CallImm32HotkeyHandler(vKey, lParam, &hr2)))
815 hr = hr2;
816 }
817
818 if (pThreadMgr)
819 pThreadMgr->Release();
820 if (pThreadMgr_P)
821 pThreadMgr_P->Release();
822
823 return hr;
824 }
825
826 /***********************************************************************
827 * CtfImeDispatchDefImeMessage (MSCTFIME.@)
828 *
829 * @implemented
830 */
831 EXTERN_C LRESULT WINAPI
CtfImeDispatchDefImeMessage(_In_ HWND hWnd,_In_ UINT uMsg,_In_ WPARAM wParam,_In_ LPARAM lParam)832 CtfImeDispatchDefImeMessage(
833 _In_ HWND hWnd,
834 _In_ UINT uMsg,
835 _In_ WPARAM wParam,
836 _In_ LPARAM lParam)
837 {
838 TRACE("(%p, %u, %p, %p)\n", hWnd, uMsg, wParam, lParam);
839
840 TLS *pTLS = TLS::GetTLS();
841 if (pTLS)
842 {
843 if (uMsg == WM_CREATE)
844 ++pTLS->m_cWnds;
845 else if (uMsg == WM_DESTROY)
846 --pTLS->m_cWnds;
847 }
848
849 if (!IsMsImeMessage(uMsg))
850 return 0;
851
852 HKL hKL = ::GetKeyboardLayout(0);
853 if (IS_IME_HKL(hKL))
854 return 0;
855
856 HWND hImeWnd = (HWND)::SendMessageW(hWnd, WM_IME_NOTIFY, 0x17, 0);
857 if (!IsWindow(hImeWnd))
858 return 0;
859
860 return ::SendMessageW(hImeWnd, uMsg, wParam, lParam);
861 }
862
863 /***********************************************************************
864 * CtfImeIsIME (MSCTFIME.@)
865 *
866 * @implemented
867 */
868 EXTERN_C BOOL WINAPI
CtfImeIsIME(_In_ HKL hKL)869 CtfImeIsIME(
870 _In_ HKL hKL)
871 {
872 TRACE("(%p)\n", hKL);
873
874 if (IS_IME_HKL(hKL))
875 return TRUE;
876
877 TLS *pTLS = TLS::GetTLS();
878 if (!pTLS || !pTLS->m_pProfile)
879 return FALSE;
880
881 // The return value of CicProfile::IsIME is brain-damaged
882 return !pTLS->m_pProfile->IsIME(hKL);
883 }
884
885 /***********************************************************************
886 * CtfImeThreadDetach (MSCTFIME.@)
887 *
888 * @implemented
889 */
890 EXTERN_C HRESULT WINAPI
CtfImeThreadDetach(VOID)891 CtfImeThreadDetach(VOID)
892 {
893 ImeDestroy(0);
894 return S_OK;
895 }
896
897 /// @implemented
AttachIME(VOID)898 BOOL AttachIME(VOID)
899 {
900 return RegisterImeClass() && RegisterMSIMEMessage();
901 }
902
903 /// @implemented
DetachIME(VOID)904 VOID DetachIME(VOID)
905 {
906 UnregisterImeClass();
907 }
908
TFUninitLib(VOID)909 EXTERN_C VOID TFUninitLib(VOID)
910 {
911 if (g_pPropCache)
912 {
913 delete g_pPropCache;
914 g_pPropCache = NULL;
915 }
916 }
917
918 /// @implemented
ProcessAttach(HINSTANCE hinstDLL)919 BOOL ProcessAttach(HINSTANCE hinstDLL)
920 {
921 g_hInst = hinstDLL;
922
923 ::InitializeCriticalSectionAndSpinCount(&g_csLock, 0);
924
925 if (!TLS::Initialize())
926 return FALSE;
927
928 cicGetOSInfo(&g_uACP, &g_dwOSInfo);
929
930 cicInitUIFLib();
931
932 if (!TFInitLib())
933 return FALSE;
934
935 gfTFInitLib = TRUE;
936 return AttachIME();
937 }
938
939 /// @implemented
ProcessDetach(HINSTANCE hinstDLL)940 VOID ProcessDetach(HINSTANCE hinstDLL)
941 {
942 TF_DllDetachInOther();
943
944 if (gfTFInitLib)
945 {
946 DetachIME();
947 TFUninitLib();
948 }
949
950 ::DeleteCriticalSection(&g_csLock);
951 TLS::InternalDestroyTLS();
952 TLS::Uninitialize();
953 cicDoneUIFLib();
954 }
955
956 /// @implemented
957 EXTERN_C BOOL WINAPI
DllMain(_In_ HINSTANCE hinstDLL,_In_ DWORD dwReason,_Inout_opt_ LPVOID lpvReserved)958 DllMain(
959 _In_ HINSTANCE hinstDLL,
960 _In_ DWORD dwReason,
961 _Inout_opt_ LPVOID lpvReserved)
962 {
963 switch (dwReason)
964 {
965 case DLL_PROCESS_ATTACH:
966 {
967 TRACE("(%p, %lu, %p)\n", hinstDLL, dwReason, lpvReserved);
968 if (!ProcessAttach(hinstDLL))
969 {
970 ProcessDetach(hinstDLL);
971 return FALSE;
972 }
973 break;
974 }
975 case DLL_PROCESS_DETACH:
976 {
977 ProcessDetach(hinstDLL);
978 break;
979 }
980 case DLL_THREAD_DETACH:
981 {
982 TF_DllDetachInOther();
983 CtfImeThreadDetach();
984 TLS::InternalDestroyTLS();
985 break;
986 }
987 }
988 return TRUE;
989 }
990