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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 891 CtfImeThreadDetach(VOID) 892 { 893 ImeDestroy(0); 894 return S_OK; 895 } 896 897 /// @implemented 898 BOOL AttachIME(VOID) 899 { 900 return RegisterImeClass() && RegisterMSIMEMessage(); 901 } 902 903 /// @implemented 904 VOID DetachIME(VOID) 905 { 906 UnregisterImeClass(); 907 } 908 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 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 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 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