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