1 /* 2 * PROJECT: ReactOS IMM32 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * PURPOSE: Implementing Far-Eastern languages input 5 * COPYRIGHT: Copyright 1998 Patrik Stridvall 6 * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart 7 * Copyright 2017 James Tabor <james.tabor@reactos.org> 8 * Copyright 2018 Amine Khaldi <amine.khaldi@reactos.org> 9 * Copyright 2020 Oleg Dubinskiy <oleg.dubinskij2013@yandex.ua> 10 * Copyright 2020-2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 11 */ 12 13 #include <stdarg.h> 14 #include <stdio.h> 15 16 #define WIN32_NO_STATUS 17 #include <windef.h> 18 #include <winbase.h> 19 #include <wingdi.h> 20 #include <winuser.h> 21 #include <winerror.h> 22 #include <wine/debug.h> 23 #include <imm.h> 24 #include <ddk/imm.h> 25 #include <winnls.h> 26 #include <winreg.h> 27 #include <wine/list.h> 28 #include <stdlib.h> 29 #include <ndk/umtypes.h> 30 #include <ndk/pstypes.h> 31 #include <ndk/rtlfuncs.h> 32 #include "../../../win32ss/include/ntuser.h" 33 #include "../../../win32ss/include/ntwin32.h" 34 #include <undocuser.h> 35 #include <imm32_undoc.h> 36 #include <strsafe.h> 37 38 WINE_DEFAULT_DEBUG_CHANNEL(imm); 39 40 #define IMM_INIT_MAGIC 0x19650412 41 #define IMM_INVALID_CANDFORM ULONG_MAX 42 #define INVALID_HOTKEY_ID 0xFFFFFFFF 43 #define MAX_CANDIDATEFORM 4 44 45 #define LANGID_CHINESE_SIMPLIFIED MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED) 46 #define LANGID_CHINESE_TRADITIONAL MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL) 47 #define LANGID_JAPANESE MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT) 48 49 #define REGKEY_KEYBOARD_LAYOUTS \ 50 L"System\\CurrentControlSet\\Control\\Keyboard Layouts" 51 #define REGKEY_IMM \ 52 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\IMM" 53 54 #define ROUNDUP4(n) (((n) + 3) & ~3) /* DWORD alignment */ 55 56 HMODULE g_hImm32Inst = NULL; 57 RTL_CRITICAL_SECTION g_csImeDpi; 58 PIMEDPI g_pImeDpiList = NULL; 59 PSERVERINFO g_psi = NULL; 60 SHAREDINFO g_SharedInfo = { NULL }; 61 BYTE g_bClientRegd = FALSE; 62 HANDLE g_hImm32Heap = NULL; 63 64 static PWND FASTCALL ValidateHwndNoErr(HWND hwnd) 65 { 66 PCLIENTINFO ClientInfo = GetWin32ClientInfo(); 67 INT index; 68 PUSER_HANDLE_TABLE ht; 69 WORD generation; 70 71 /* See if the window is cached */ 72 if (hwnd == ClientInfo->CallbackWnd.hWnd) 73 return ClientInfo->CallbackWnd.pWnd; 74 75 if (!NtUserValidateHandleSecure(hwnd)) 76 return NULL; 77 78 ht = g_SharedInfo.aheList; /* handle table */ 79 index = (LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1; 80 if (index < 0 || index >= ht->nb_handles || ht->handles[index].type != TYPE_WINDOW) 81 return NULL; 82 83 generation = HIWORD(hwnd); 84 if (generation != ht->handles[index].generation && generation && generation != 0xFFFF) 85 return NULL; 86 87 return (PWND)&ht->handles[index]; 88 } 89 90 static BOOL APIENTRY Imm32InitInstance(HMODULE hMod) 91 { 92 NTSTATUS status; 93 94 if (hMod) 95 g_hImm32Inst = hMod; 96 97 if (g_bClientRegd) 98 return TRUE; 99 100 status = RtlInitializeCriticalSection(&g_csImeDpi); 101 if (NT_ERROR(status)) 102 return FALSE; 103 104 g_bClientRegd = TRUE; 105 return TRUE; 106 } 107 108 LPVOID APIENTRY Imm32HeapAlloc(DWORD dwFlags, DWORD dwBytes) 109 { 110 if (!g_hImm32Heap) 111 { 112 g_hImm32Heap = RtlGetProcessHeap(); 113 if (g_hImm32Heap == NULL) 114 return NULL; 115 } 116 return HeapAlloc(g_hImm32Heap, dwFlags, dwBytes); 117 } 118 119 static LPWSTR APIENTRY Imm32WideFromAnsi(LPCSTR pszA) 120 { 121 INT cch = lstrlenA(pszA); 122 LPWSTR pszW = Imm32HeapAlloc(0, (cch + 1) * sizeof(WCHAR)); 123 if (pszW == NULL) 124 return NULL; 125 cch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszA, cch, pszW, cch + 1); 126 pszW[cch] = 0; 127 return pszW; 128 } 129 130 static LPSTR APIENTRY Imm32AnsiFromWide(LPCWSTR pszW) 131 { 132 INT cchW = lstrlenW(pszW); 133 INT cchA = (cchW + 1) * sizeof(WCHAR); 134 LPSTR pszA = Imm32HeapAlloc(0, cchA); 135 if (!pszA) 136 return NULL; 137 cchA = WideCharToMultiByte(CP_ACP, 0, pszW, cchW, pszA, cchA, NULL, NULL); 138 pszA[cchA] = 0; 139 return pszA; 140 } 141 142 static inline BOOL Imm32IsCrossThreadAccess(HIMC hIMC) 143 { 144 DWORD dwImeThreadId = NtUserQueryInputContext(hIMC, 1); 145 DWORD dwThreadId = GetCurrentThreadId(); 146 return (dwImeThreadId != dwThreadId); 147 } 148 149 static BOOL Imm32IsCrossProcessAccess(HWND hWnd) 150 { 151 return (NtUserQueryWindow(hWnd, QUERY_WINDOW_UNIQUE_PROCESS_ID) != 152 (DWORD_PTR)NtCurrentTeb()->ClientId.UniqueProcess); 153 } 154 155 static VOID APIENTRY Imm32FreeImeDpi(PIMEDPI pImeDpi, BOOL bDestroy) 156 { 157 if (pImeDpi->hInst == NULL) 158 return; 159 if (bDestroy) 160 pImeDpi->ImeDestroy(0); 161 FreeLibrary(pImeDpi->hInst); 162 pImeDpi->hInst = NULL; 163 } 164 165 static BOOL APIENTRY 166 Imm32NotifyAction(HIMC hIMC, HWND hwnd, DWORD dwAction, DWORD_PTR dwIndex, DWORD_PTR dwValue, 167 DWORD_PTR dwCommand, DWORD_PTR dwData) 168 { 169 DWORD dwLayout; 170 HKL hKL; 171 PIMEDPI pImeDpi; 172 173 if (dwAction) 174 { 175 dwLayout = NtUserQueryInputContext(hIMC, 1); 176 if (dwLayout) 177 { 178 /* find keyboard layout and lock it */ 179 hKL = GetKeyboardLayout(dwLayout); 180 pImeDpi = ImmLockImeDpi(hKL); 181 if (pImeDpi) 182 { 183 /* do notify */ 184 pImeDpi->NotifyIME(hIMC, dwAction, dwIndex, dwValue); 185 186 ImmUnlockImeDpi(pImeDpi); /* unlock */ 187 } 188 } 189 } 190 191 if (hwnd && dwCommand) 192 SendMessageW(hwnd, WM_IME_NOTIFY, dwCommand, dwData); 193 194 return TRUE; 195 } 196 197 static PIMEDPI APIENTRY Imm32FindImeDpi(HKL hKL) 198 { 199 PIMEDPI pImeDpi; 200 201 RtlEnterCriticalSection(&g_csImeDpi); 202 for (pImeDpi = g_pImeDpiList; pImeDpi != NULL; pImeDpi = pImeDpi->pNext) 203 { 204 if (pImeDpi->hKL == hKL) 205 break; 206 } 207 RtlLeaveCriticalSection(&g_csImeDpi); 208 209 return pImeDpi; 210 } 211 212 static BOOL Imm32GetSystemLibraryPath(LPWSTR pszPath, DWORD cchPath, LPCWSTR pszFileName) 213 { 214 if (!pszFileName[0] || !GetSystemDirectoryW(pszPath, cchPath)) 215 return FALSE; 216 StringCchCatW(pszPath, cchPath, L"\\"); 217 StringCchCatW(pszPath, cchPath, pszFileName); 218 return TRUE; 219 } 220 221 static BOOL APIENTRY Imm32InquireIme(PIMEDPI pImeDpi) 222 { 223 WCHAR szUIClass[64]; 224 WNDCLASSW wcW; 225 DWORD dwSysInfoFlags = 0; // TODO: ??? 226 LPIMEINFO pImeInfo = &pImeDpi->ImeInfo; 227 228 // TODO: NtUserGetThreadState(16); 229 230 if (!IS_IME_HKL(pImeDpi->hKL)) 231 { 232 if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED) && 233 pImeDpi->CtfImeInquireExW) 234 { 235 // TODO: 236 return FALSE; 237 } 238 } 239 240 if (!pImeDpi->ImeInquire(pImeInfo, szUIClass, dwSysInfoFlags)) 241 return FALSE; 242 243 szUIClass[_countof(szUIClass) - 1] = 0; 244 245 if (pImeInfo->dwPrivateDataSize == 0) 246 pImeInfo->dwPrivateDataSize = 4; 247 248 #define VALID_IME_PROP (IME_PROP_AT_CARET | \ 249 IME_PROP_SPECIAL_UI | \ 250 IME_PROP_CANDLIST_START_FROM_1 | \ 251 IME_PROP_UNICODE | \ 252 IME_PROP_COMPLETE_ON_UNSELECT | \ 253 IME_PROP_END_UNLOAD | \ 254 IME_PROP_KBD_CHAR_FIRST | \ 255 IME_PROP_IGNORE_UPKEYS | \ 256 IME_PROP_NEED_ALTKEY | \ 257 IME_PROP_NO_KEYS_ON_CLOSE | \ 258 IME_PROP_ACCEPT_WIDE_VKEY) 259 #define VALID_CMODE_CAPS (IME_CMODE_ALPHANUMERIC | \ 260 IME_CMODE_NATIVE | \ 261 IME_CMODE_KATAKANA | \ 262 IME_CMODE_LANGUAGE | \ 263 IME_CMODE_FULLSHAPE | \ 264 IME_CMODE_ROMAN | \ 265 IME_CMODE_CHARCODE | \ 266 IME_CMODE_HANJACONVERT | \ 267 IME_CMODE_SOFTKBD | \ 268 IME_CMODE_NOCONVERSION | \ 269 IME_CMODE_EUDC | \ 270 IME_CMODE_SYMBOL | \ 271 IME_CMODE_FIXED) 272 #define VALID_SMODE_CAPS (IME_SMODE_NONE | \ 273 IME_SMODE_PLAURALCLAUSE | \ 274 IME_SMODE_SINGLECONVERT | \ 275 IME_SMODE_AUTOMATIC | \ 276 IME_SMODE_PHRASEPREDICT | \ 277 IME_SMODE_CONVERSATION) 278 #define VALID_UI_CAPS (UI_CAP_2700 | \ 279 UI_CAP_ROT90 | \ 280 UI_CAP_ROTANY | \ 281 UI_CAP_SOFTKBD) 282 #define VALID_SCS_CAPS (SCS_CAP_COMPSTR | \ 283 SCS_CAP_MAKEREAD | \ 284 SCS_CAP_SETRECONVERTSTRING) 285 #define VALID_SELECT_CAPS (SELECT_CAP_CONVERSION | SELECT_CAP_SENTENCE) 286 287 if (pImeInfo->fdwProperty & ~VALID_IME_PROP) 288 return FALSE; 289 if (pImeInfo->fdwConversionCaps & ~VALID_CMODE_CAPS) 290 return FALSE; 291 if (pImeInfo->fdwSentenceCaps & ~VALID_SMODE_CAPS) 292 return FALSE; 293 if (pImeInfo->fdwUICaps & ~VALID_UI_CAPS) 294 return FALSE; 295 if (pImeInfo->fdwSCSCaps & ~VALID_SCS_CAPS) 296 return FALSE; 297 if (pImeInfo->fdwSelectCaps & ~VALID_SELECT_CAPS) 298 return FALSE; 299 300 #undef VALID_IME_PROP 301 #undef VALID_CMODE_CAPS 302 #undef VALID_SMODE_CAPS 303 #undef VALID_UI_CAPS 304 #undef VALID_SCS_CAPS 305 #undef VALID_SELECT_CAPS 306 307 if (pImeInfo->fdwProperty & IME_PROP_UNICODE) 308 { 309 StringCchCopyW(pImeDpi->szUIClass, _countof(pImeDpi->szUIClass), szUIClass); 310 } 311 else 312 { 313 if (pImeDpi->uCodePage != GetACP() && pImeDpi->uCodePage) 314 return FALSE; 315 316 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPSTR)szUIClass, -1, 317 pImeDpi->szUIClass, _countof(pImeDpi->szUIClass)); 318 } 319 320 return GetClassInfoW(pImeDpi->hInst, pImeDpi->szUIClass, &wcW); 321 } 322 323 static BOOL APIENTRY Imm32LoadImeInfo(PIMEINFOEX pImeInfoEx, PIMEDPI pImeDpi) 324 { 325 WCHAR szPath[MAX_PATH]; 326 HINSTANCE hIME; 327 FARPROC fn; 328 329 if (!Imm32GetSystemLibraryPath(szPath, _countof(szPath), pImeInfoEx->wszImeFile)) 330 return FALSE; 331 332 hIME = GetModuleHandleW(szPath); 333 if (hIME == NULL) 334 { 335 hIME = LoadLibraryW(szPath); 336 if (hIME == NULL) 337 { 338 ERR("Imm32LoadImeInfo: LoadLibraryW(%S) failed\n", szPath); 339 return FALSE; 340 } 341 } 342 pImeDpi->hInst = hIME; 343 344 #define DEFINE_IME_ENTRY(type, name, params, extended) \ 345 do { \ 346 fn = GetProcAddress(hIME, #name); \ 347 if (fn) pImeDpi->name = (FN_##name)fn; \ 348 else if (!extended) goto Failed; \ 349 } while (0); 350 #include "../../../win32ss/include/imetable.h" 351 #undef DEFINE_IME_ENTRY 352 353 if (!Imm32InquireIme(pImeDpi)) 354 { 355 ERR("Imm32LoadImeInfo: Imm32InquireIme failed\n"); 356 goto Failed; 357 } 358 359 if (pImeInfoEx->fLoadFlag) 360 return TRUE; 361 362 NtUserSetImeOwnerWindow(pImeInfoEx, TRUE); 363 return TRUE; 364 365 Failed: 366 FreeLibrary(pImeDpi->hInst); 367 pImeDpi->hInst = NULL; 368 return FALSE; 369 } 370 371 #ifdef IMP_SUPPORT /* 3.x support */ 372 static DWORD APIENTRY 373 ImpJTransCompA(LPINPUTCONTEXTDX pIC, LPCOMPOSITIONSTRING pCS, 374 const TRANSMSG *pSrc, LPTRANSMSG pDest) 375 { 376 // FIXME 377 *pDest = *pSrc; 378 return 1; 379 } 380 381 static DWORD APIENTRY 382 ImpJTransCompW(LPINPUTCONTEXTDX pIC, LPCOMPOSITIONSTRING pCS, 383 const TRANSMSG *pSrc, LPTRANSMSG pDest) 384 { 385 // FIXME 386 *pDest = *pSrc; 387 return 1; 388 } 389 390 typedef LRESULT (WINAPI *FN_SendMessage)(HWND, UINT, WPARAM, LPARAM); 391 392 static DWORD APIENTRY 393 ImpJTrans(DWORD dwCount, LPTRANSMSG pTrans, LPINPUTCONTEXTDX pIC, 394 LPCOMPOSITIONSTRING pCS, BOOL bAnsi) 395 { 396 DWORD ret = 0; 397 HWND hWnd, hwndDefIME; 398 LPTRANSMSG pTempList, pEntry, pNext; 399 DWORD dwIndex, iCandForm, dwNumber, cbTempList; 400 HGLOBAL hGlobal; 401 CANDIDATEFORM CandForm; 402 FN_SendMessage pSendMessage; 403 404 hWnd = pIC->hWnd; 405 hwndDefIME = ImmGetDefaultIMEWnd(hWnd); 406 pSendMessage = (IsWindowUnicode(hWnd) ? SendMessageW : SendMessageA); 407 408 // clone the message list 409 cbTempList = (dwCount + 1) * sizeof(TRANSMSG); 410 pTempList = Imm32HeapAlloc(HEAP_ZERO_MEMORY, cbTempList); 411 if (pTempList == NULL) 412 return 0; 413 RtlCopyMemory(pTempList, pTrans, dwCount * sizeof(TRANSMSG)); 414 415 if (pIC->dwUIFlags & 0x2) 416 { 417 // find WM_IME_ENDCOMPOSITION 418 pEntry = pTempList; 419 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pEntry) 420 { 421 if (pEntry->message == WM_IME_ENDCOMPOSITION) 422 break; 423 } 424 425 if (pEntry->message == WM_IME_ENDCOMPOSITION) // if found 426 { 427 // move WM_IME_ENDCOMPOSITION to the end of the list 428 for (pNext = pEntry + 1; pNext->message != 0; ++pEntry, ++pNext) 429 *pEntry = *pNext; 430 431 pEntry->message = WM_IME_ENDCOMPOSITION; 432 pEntry->wParam = 0; 433 pEntry->lParam = 0; 434 } 435 } 436 437 for (pEntry = pTempList; pEntry->message != 0; ++pEntry) 438 { 439 switch (pEntry->message) 440 { 441 case WM_IME_STARTCOMPOSITION: 442 if (!(pIC->dwUIFlags & 0x2)) 443 { 444 // send IR_OPENCONVERT 445 if (pIC->cfCompForm.dwStyle != CFS_DEFAULT) 446 pSendMessage(hWnd, WM_IME_REPORT, IR_OPENCONVERT, 0); 447 448 goto DoDefault; 449 } 450 break; 451 452 case WM_IME_ENDCOMPOSITION: 453 if (pIC->dwUIFlags & 0x2) 454 { 455 // send IR_UNDETERMINE 456 hGlobal = GlobalAlloc(GHND | GMEM_SHARE, sizeof(UNDETERMINESTRUCT)); 457 if (hGlobal) 458 { 459 pSendMessage(hWnd, WM_IME_REPORT, IR_UNDETERMINE, (LPARAM)hGlobal); 460 GlobalFree(hGlobal); 461 } 462 } 463 else 464 { 465 // send IR_CLOSECONVERT 466 if (pIC->cfCompForm.dwStyle != CFS_DEFAULT) 467 pSendMessage(hWnd, WM_IME_REPORT, IR_CLOSECONVERT, 0); 468 469 goto DoDefault; 470 } 471 break; 472 473 case WM_IME_COMPOSITION: 474 if (bAnsi) 475 dwNumber = ImpJTransCompA(pIC, pCS, pEntry, pTrans); 476 else 477 dwNumber = ImpJTransCompW(pIC, pCS, pEntry, pTrans); 478 479 ret += dwNumber; 480 pTrans += dwNumber; 481 482 // send IR_CHANGECONVERT 483 if (!(pIC->dwUIFlags & 0x2)) 484 { 485 if (pIC->cfCompForm.dwStyle != CFS_DEFAULT) 486 pSendMessage(hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0); 487 } 488 break; 489 490 case WM_IME_NOTIFY: 491 if (pEntry->wParam == IMN_OPENCANDIDATE) 492 { 493 if (IsWindow(hWnd) && (pIC->dwUIFlags & 0x2)) 494 { 495 // send IMC_SETCANDIDATEPOS 496 for (iCandForm = 0; iCandForm < MAX_CANDIDATEFORM; ++iCandForm) 497 { 498 if (!(pEntry->lParam & (1 << iCandForm))) 499 continue; 500 501 CandForm.dwIndex = iCandForm; 502 CandForm.dwStyle = CFS_EXCLUDE; 503 CandForm.ptCurrentPos = pIC->cfCompForm.ptCurrentPos; 504 CandForm.rcArea = pIC->cfCompForm.rcArea; 505 pSendMessage(hwndDefIME, WM_IME_CONTROL, IMC_SETCANDIDATEPOS, 506 (LPARAM)&CandForm); 507 } 508 } 509 } 510 511 if (!(pIC->dwUIFlags & 0x2)) 512 goto DoDefault; 513 514 // send a WM_IME_NOTIFY notification to the default ime window 515 pSendMessage(hwndDefIME, pEntry->message, pEntry->wParam, pEntry->lParam); 516 break; 517 518 DoDefault: 519 default: 520 // default processing 521 *pTrans++ = *pEntry; 522 ++ret; 523 break; 524 } 525 } 526 527 HeapFree(g_hImm32Heap, 0, pTempList); 528 return ret; 529 } 530 531 static DWORD APIENTRY 532 ImpKTrans(DWORD dwCount, LPTRANSMSG pEntries, LPINPUTCONTEXTDX pIC, 533 LPCOMPOSITIONSTRING pCS, BOOL bAnsi) 534 { 535 return dwCount; // FIXME 536 } 537 538 static DWORD APIENTRY 539 ImpTrans(DWORD dwCount, LPTRANSMSG pEntries, HIMC hIMC, BOOL bAnsi, WORD wLang) 540 { 541 BOOL ret = FALSE; 542 LPINPUTCONTEXTDX pIC; 543 LPCOMPOSITIONSTRING pCS; 544 545 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 546 if (pIC == NULL) 547 return 0; 548 549 pCS = ImmLockIMCC(pIC->hCompStr); 550 if (pCS) 551 { 552 if (wLang == LANG_JAPANESE) 553 ret = ImpJTrans(dwCount, pEntries, pIC, pCS, bAnsi); 554 else if (wLang == LANG_KOREAN) 555 ret = ImpKTrans(dwCount, pEntries, pIC, pCS, bAnsi); 556 ImmUnlockIMCC(pIC->hCompStr); 557 } 558 559 ImmUnlockIMC(hIMC); 560 return ret; 561 } 562 #endif /* def IMP_SUPPORT */ 563 564 static PIMEDPI APIENTRY Ime32LoadImeDpi(HKL hKL, BOOL bLock) 565 { 566 IMEINFOEX ImeInfoEx; 567 CHARSETINFO ci; 568 PIMEDPI pImeDpiNew, pImeDpiFound; 569 UINT uCodePage; 570 LCID lcid; 571 572 if (!ImmGetImeInfoEx(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL) || 573 ImeInfoEx.fLoadFlag == 1) 574 { 575 return NULL; 576 } 577 578 pImeDpiNew = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(IMEDPI)); 579 if (pImeDpiNew == NULL) 580 return NULL; 581 582 pImeDpiNew->hKL = hKL; 583 584 lcid = LOWORD(hKL); 585 if (TranslateCharsetInfo((LPDWORD)(DWORD_PTR)lcid, &ci, TCI_SRCLOCALE)) 586 uCodePage = ci.ciACP; 587 else 588 uCodePage = CP_ACP; 589 pImeDpiNew->uCodePage = uCodePage; 590 591 if (!Imm32LoadImeInfo(&ImeInfoEx, pImeDpiNew)) 592 { 593 HeapFree(g_hImm32Heap, 0, pImeDpiNew); 594 return FALSE; 595 } 596 597 RtlEnterCriticalSection(&g_csImeDpi); 598 599 pImeDpiFound = Imm32FindImeDpi(hKL); 600 if (pImeDpiFound) 601 { 602 if (!bLock) 603 pImeDpiFound->dwFlags &= ~IMEDPI_FLAG_LOCKED; 604 605 RtlLeaveCriticalSection(&g_csImeDpi); 606 607 Imm32FreeImeDpi(pImeDpiNew, FALSE); 608 HeapFree(g_hImm32Heap, 0, pImeDpiNew); 609 return pImeDpiFound; 610 } 611 else 612 { 613 if (bLock) 614 { 615 pImeDpiNew->dwFlags |= IMEDPI_FLAG_LOCKED; 616 pImeDpiNew->cLockObj = 1; 617 } 618 619 pImeDpiNew->pNext = g_pImeDpiList; 620 g_pImeDpiList = pImeDpiNew; 621 622 RtlLeaveCriticalSection(&g_csImeDpi); 623 return pImeDpiNew; 624 } 625 } 626 627 /*********************************************************************** 628 * ImmLoadIME (IMM32.@) 629 */ 630 BOOL WINAPI ImmLoadIME(HKL hKL) 631 { 632 PW32CLIENTINFO pInfo; 633 PIMEDPI pImeDpi; 634 635 if (!IS_IME_HKL(hKL)) 636 { 637 if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED)) 638 return FALSE; 639 640 pInfo = (PW32CLIENTINFO)(NtCurrentTeb()->Win32ClientInfo); 641 if ((pInfo->W32ClientInfo[0] & 2)) 642 return FALSE; 643 } 644 645 pImeDpi = Imm32FindImeDpi(hKL); 646 if (pImeDpi == NULL) 647 pImeDpi = Ime32LoadImeDpi(hKL, FALSE); 648 return (pImeDpi != NULL); 649 } 650 651 PIMEDPI APIENTRY ImmLockOrLoadImeDpi(HKL hKL) 652 { 653 PW32CLIENTINFO pInfo; 654 PIMEDPI pImeDpi; 655 656 if (!IS_IME_HKL(hKL)) 657 { 658 if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED)) 659 return NULL; 660 661 pInfo = (PW32CLIENTINFO)(NtCurrentTeb()->Win32ClientInfo); 662 if ((pInfo->W32ClientInfo[0] & 2)) 663 return NULL; 664 } 665 666 pImeDpi = ImmLockImeDpi(hKL); 667 if (pImeDpi == NULL) 668 pImeDpi = Ime32LoadImeDpi(hKL, TRUE); 669 return pImeDpi; 670 } 671 672 /*********************************************************************** 673 * ImmLoadLayout (IMM32.@) 674 */ 675 HKL WINAPI ImmLoadLayout(HKL hKL, PIMEINFOEX pImeInfoEx) 676 { 677 DWORD cbData; 678 UNICODE_STRING UnicodeString; 679 HKEY hLayoutKey = NULL, hLayoutsKey = NULL; 680 LONG error; 681 NTSTATUS Status; 682 WCHAR szLayout[MAX_PATH]; 683 684 TRACE("(%p, %p)\n", hKL, pImeInfoEx); 685 686 if (IS_IME_HKL(hKL) || 687 !g_psi || !(g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED) || 688 ((PW32CLIENTINFO)NtCurrentTeb()->Win32ClientInfo)->W32ClientInfo[0] & 2) 689 { 690 UnicodeString.Buffer = szLayout; 691 UnicodeString.MaximumLength = sizeof(szLayout); 692 Status = RtlIntegerToUnicodeString((DWORD_PTR)hKL, 16, &UnicodeString); 693 if (!NT_SUCCESS(Status)) 694 return NULL; 695 696 error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hLayoutsKey); 697 if (error) 698 return NULL; 699 700 error = RegOpenKeyW(hLayoutsKey, szLayout, &hLayoutKey); 701 } 702 else 703 { 704 error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_IMM, &hLayoutKey); 705 } 706 707 if (error) 708 { 709 ERR("RegOpenKeyW error: 0x%08lX\n", error); 710 hKL = NULL; 711 } 712 else 713 { 714 cbData = sizeof(pImeInfoEx->wszImeFile); 715 error = RegQueryValueExW(hLayoutKey, L"Ime File", 0, 0, 716 (LPBYTE)pImeInfoEx->wszImeFile, &cbData); 717 if (error) 718 hKL = NULL; 719 } 720 721 RegCloseKey(hLayoutKey); 722 if (hLayoutsKey) 723 RegCloseKey(hLayoutsKey); 724 return hKL; 725 } 726 727 typedef struct _tagImmHkl{ 728 struct list entry; 729 HKL hkl; 730 HMODULE hIME; 731 IMEINFO imeInfo; 732 WCHAR imeClassName[17]; /* 16 character max */ 733 ULONG uSelected; 734 HWND UIWnd; 735 736 /* Function Pointers */ 737 BOOL (WINAPI *pImeInquire)(IMEINFO *, WCHAR *, const WCHAR *); 738 BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *); 739 BOOL (WINAPI *pImeDestroy)(UINT); 740 LRESULT (WINAPI *pImeEscape)(HIMC, UINT, void *); 741 BOOL (WINAPI *pImeSelect)(HIMC, BOOL); 742 BOOL (WINAPI *pImeSetActiveContext)(HIMC, BOOL); 743 UINT (WINAPI *pImeToAsciiEx)(UINT, UINT, const BYTE *, DWORD *, UINT, HIMC); 744 BOOL (WINAPI *pNotifyIME)(HIMC, DWORD, DWORD, DWORD); 745 BOOL (WINAPI *pImeRegisterWord)(const WCHAR *, DWORD, const WCHAR *); 746 BOOL (WINAPI *pImeUnregisterWord)(const WCHAR *, DWORD, const WCHAR *); 747 UINT (WINAPI *pImeEnumRegisterWord)(REGISTERWORDENUMPROCW, const WCHAR *, DWORD, const WCHAR *, void *); 748 BOOL (WINAPI *pImeSetCompositionString)(HIMC, DWORD, const void *, DWORD, const void *, DWORD); 749 DWORD (WINAPI *pImeConversionList)(HIMC, const WCHAR *, CANDIDATELIST *, DWORD, UINT); 750 BOOL (WINAPI *pImeProcessKey)(HIMC, UINT, LPARAM, const BYTE *); 751 UINT (WINAPI *pImeGetRegisterWordStyle)(UINT, STYLEBUFW *); 752 DWORD (WINAPI *pImeGetImeMenuItems)(HIMC, DWORD, DWORD, IMEMENUITEMINFOW *, IMEMENUITEMINFOW *, DWORD); 753 } ImmHkl; 754 755 typedef struct tagInputContextData 756 { 757 DWORD dwLock; 758 INPUTCONTEXT IMC; 759 DWORD threadID; 760 761 ImmHkl *immKbd; 762 UINT lastVK; 763 BOOL threadDefault; 764 DWORD magic; 765 } InputContextData; 766 767 #define WINE_IMC_VALID_MAGIC 0x56434D49 768 769 typedef struct _tagIMMThreadData { 770 struct list entry; 771 DWORD threadID; 772 HIMC defaultContext; 773 HWND hwndDefault; 774 BOOL disableIME; 775 DWORD windowRefs; 776 } IMMThreadData; 777 778 static struct list ImmHklList = LIST_INIT(ImmHklList); 779 static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList); 780 781 static const WCHAR szwWineIMCProperty[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0}; 782 783 static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0}; 784 static const WCHAR szLayoutTextW[] = {'L','a','y','o','u','t',' ','T','e','x','t',0}; 785 static const WCHAR szImeRegFmt[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s','\\','%','0','8','l','x',0}; 786 787 static const WCHAR szwIME[] = {'I','M','E',0}; 788 static const WCHAR szwDefaultIME[] = {'D','e','f','a','u','l','t',' ','I','M','E',0}; 789 790 static CRITICAL_SECTION threaddata_cs; 791 static CRITICAL_SECTION_DEBUG critsect_debug = 792 { 793 0, 0, &threaddata_cs, 794 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, 795 0, 0, { (DWORD_PTR)(__FILE__ ": threaddata_cs") } 796 }; 797 static CRITICAL_SECTION threaddata_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; 798 799 static inline BOOL is_himc_ime_unicode(const InputContextData *data) 800 { 801 return !!(data->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE); 802 } 803 804 static inline BOOL is_kbd_ime_unicode(const ImmHkl *hkl) 805 { 806 return !!(hkl->imeInfo.fdwProperty & IME_PROP_UNICODE); 807 } 808 809 static InputContextData* get_imc_data(HIMC hIMC); 810 811 static inline WCHAR *strdupAtoW( const char *str ) 812 { 813 WCHAR *ret = NULL; 814 if (str) 815 { 816 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 ); 817 if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) 818 MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len ); 819 } 820 return ret; 821 } 822 823 static inline CHAR *strdupWtoA( const WCHAR *str ) 824 { 825 CHAR *ret = NULL; 826 if (str) 827 { 828 DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL ); 829 if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) 830 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL ); 831 } 832 return ret; 833 } 834 835 static HMODULE load_graphics_driver(void) 836 { 837 static const WCHAR display_device_guid_propW[] = { 838 '_','_','w','i','n','e','_','d','i','s','p','l','a','y','_', 839 'd','e','v','i','c','e','_','g','u','i','d',0 }; 840 static const WCHAR key_pathW[] = { 841 'S','y','s','t','e','m','\\', 842 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', 843 'C','o','n','t','r','o','l','\\', 844 'V','i','d','e','o','\\','{',0}; 845 static const WCHAR displayW[] = {'}','\\','0','0','0','0',0}; 846 static const WCHAR driverW[] = {'G','r','a','p','h','i','c','s','D','r','i','v','e','r',0}; 847 848 HMODULE ret = 0; 849 HKEY hkey; 850 DWORD size; 851 WCHAR path[MAX_PATH]; 852 WCHAR key[ARRAY_SIZE( key_pathW ) + ARRAY_SIZE( displayW ) + 40]; 853 UINT guid_atom = HandleToULong( GetPropW( GetDesktopWindow(), display_device_guid_propW )); 854 855 if (!guid_atom) return 0; 856 memcpy( key, key_pathW, sizeof(key_pathW) ); 857 if (!GlobalGetAtomNameW( guid_atom, key + lstrlenW(key), 40 )) return 0; 858 lstrcatW( key, displayW ); 859 if (RegOpenKeyW( HKEY_LOCAL_MACHINE, key, &hkey )) return 0; 860 size = sizeof(path); 861 if (!RegQueryValueExW( hkey, driverW, NULL, NULL, (BYTE *)path, &size )) ret = LoadLibraryW( path ); 862 RegCloseKey( hkey ); 863 TRACE( "%s %p\n", debugstr_w(path), ret ); 864 return ret; 865 } 866 867 /* ImmHkl loading and freeing */ 868 #define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);} 869 static ImmHkl *IMM_GetImmHkl(HKL hkl) 870 { 871 ImmHkl *ptr; 872 WCHAR filename[MAX_PATH]; 873 874 TRACE("Seeking ime for keyboard %p\n",hkl); 875 876 LIST_FOR_EACH_ENTRY(ptr, &ImmHklList, ImmHkl, entry) 877 { 878 if (ptr->hkl == hkl) 879 return ptr; 880 } 881 /* not found... create it */ 882 883 ptr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ImmHkl)); 884 885 ptr->hkl = hkl; 886 if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename); 887 if (!ptr->hIME) ptr->hIME = load_graphics_driver(); 888 if (ptr->hIME) 889 { 890 LOAD_FUNCPTR(ImeInquire); 891 if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, NULL)) 892 { 893 FreeLibrary(ptr->hIME); 894 ptr->hIME = NULL; 895 } 896 else 897 { 898 LOAD_FUNCPTR(ImeDestroy); 899 LOAD_FUNCPTR(ImeSelect); 900 if (!ptr->pImeSelect || !ptr->pImeDestroy) 901 { 902 FreeLibrary(ptr->hIME); 903 ptr->hIME = NULL; 904 } 905 else 906 { 907 LOAD_FUNCPTR(ImeConfigure); 908 LOAD_FUNCPTR(ImeEscape); 909 LOAD_FUNCPTR(ImeSetActiveContext); 910 LOAD_FUNCPTR(ImeToAsciiEx); 911 LOAD_FUNCPTR(NotifyIME); 912 LOAD_FUNCPTR(ImeRegisterWord); 913 LOAD_FUNCPTR(ImeUnregisterWord); 914 LOAD_FUNCPTR(ImeEnumRegisterWord); 915 LOAD_FUNCPTR(ImeSetCompositionString); 916 LOAD_FUNCPTR(ImeConversionList); 917 LOAD_FUNCPTR(ImeProcessKey); 918 LOAD_FUNCPTR(ImeGetRegisterWordStyle); 919 LOAD_FUNCPTR(ImeGetImeMenuItems); 920 /* make sure our classname is WCHAR */ 921 if (!is_kbd_ime_unicode(ptr)) 922 { 923 WCHAR bufW[17]; 924 MultiByteToWideChar(CP_ACP, 0, (LPSTR)ptr->imeClassName, 925 -1, bufW, 17); 926 lstrcpyW(ptr->imeClassName, bufW); 927 } 928 } 929 } 930 } 931 list_add_head(&ImmHklList,&ptr->entry); 932 933 return ptr; 934 } 935 #undef LOAD_FUNCPTR 936 937 static InputContextData* get_imc_data(HIMC hIMC) 938 { 939 InputContextData *data = (InputContextData *)hIMC; 940 941 if (hIMC == NULL) 942 return NULL; 943 944 if(IsBadReadPtr(data, sizeof(InputContextData)) || data->magic != WINE_IMC_VALID_MAGIC) 945 { 946 SetLastError(ERROR_INVALID_HANDLE); 947 return NULL; 948 } 949 return data; 950 } 951 952 static HIMC get_default_context( HWND hwnd ) 953 { 954 FIXME("Don't use this function\n"); 955 return FALSE; 956 } 957 958 static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC) 959 { 960 InputContextData *data; 961 962 if (hWnd) 963 { 964 DWORD thread = GetWindowThreadProcessId(hWnd, NULL); 965 if (thread != GetCurrentThreadId()) return TRUE; 966 } 967 data = get_imc_data(hIMC); 968 if (data && data->threadID != GetCurrentThreadId()) 969 return TRUE; 970 971 return FALSE; 972 } 973 974 /*********************************************************************** 975 * ImmAssociateContext (IMM32.@) 976 */ 977 HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC) 978 { 979 HIMC old = NULL; 980 InputContextData *data = get_imc_data(hIMC); 981 982 TRACE("(%p, %p):\n", hWnd, hIMC); 983 984 if(hIMC && !data) 985 return NULL; 986 987 /* 988 * If already associated just return 989 */ 990 if (hIMC && data->IMC.hWnd == hWnd) 991 return hIMC; 992 993 if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC)) 994 return NULL; 995 996 if (hWnd) 997 { 998 HIMC defaultContext = get_default_context( hWnd ); 999 old = RemovePropW(hWnd,szwWineIMCProperty); 1000 1001 if (old == NULL) 1002 old = defaultContext; 1003 else if (old == (HIMC)-1) 1004 old = NULL; 1005 1006 if (hIMC != defaultContext) 1007 { 1008 if (hIMC == NULL) /* Meaning disable imm for that window*/ 1009 SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1); 1010 else 1011 SetPropW(hWnd,szwWineIMCProperty,hIMC); 1012 } 1013 1014 if (old) 1015 { 1016 InputContextData *old_data = (InputContextData *)old; 1017 if (old_data->IMC.hWnd == hWnd) 1018 old_data->IMC.hWnd = NULL; 1019 } 1020 } 1021 1022 if (!hIMC) 1023 return old; 1024 1025 if(GetActiveWindow() == data->IMC.hWnd) 1026 { 1027 SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, FALSE, ISC_SHOWUIALL); 1028 data->IMC.hWnd = hWnd; 1029 SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, TRUE, ISC_SHOWUIALL); 1030 } 1031 1032 return old; 1033 } 1034 1035 1036 /* 1037 * Helper function for ImmAssociateContextEx 1038 */ 1039 static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam) 1040 { 1041 HIMC hImc = (HIMC)lParam; 1042 ImmAssociateContext(hwnd,hImc); 1043 return TRUE; 1044 } 1045 1046 /*********************************************************************** 1047 * ImmAssociateContextEx (IMM32.@) 1048 */ 1049 BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags) 1050 { 1051 TRACE("(%p, %p, 0x%x):\n", hWnd, hIMC, dwFlags); 1052 1053 if (!hWnd) 1054 return FALSE; 1055 1056 switch (dwFlags) 1057 { 1058 case 0: 1059 ImmAssociateContext(hWnd,hIMC); 1060 return TRUE; 1061 case IACE_DEFAULT: 1062 { 1063 HIMC defaultContext = get_default_context( hWnd ); 1064 if (!defaultContext) return FALSE; 1065 ImmAssociateContext(hWnd,defaultContext); 1066 return TRUE; 1067 } 1068 case IACE_IGNORENOCONTEXT: 1069 if (GetPropW(hWnd,szwWineIMCProperty)) 1070 ImmAssociateContext(hWnd,hIMC); 1071 return TRUE; 1072 case IACE_CHILDREN: 1073 EnumChildWindows(hWnd,_ImmAssociateContextExEnumProc,(LPARAM)hIMC); 1074 return TRUE; 1075 default: 1076 FIXME("Unknown dwFlags 0x%x\n",dwFlags); 1077 return FALSE; 1078 } 1079 } 1080 1081 /*********************************************************************** 1082 * ImmConfigureIMEA (IMM32.@) 1083 */ 1084 BOOL WINAPI ImmConfigureIMEA( 1085 HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) 1086 { 1087 ImmHkl *immHkl = IMM_GetImmHkl(hKL); 1088 1089 TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData); 1090 1091 if (dwMode == IME_CONFIG_REGISTERWORD && !lpData) 1092 return FALSE; 1093 1094 if (immHkl->hIME && immHkl->pImeConfigure) 1095 { 1096 if (dwMode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode(immHkl)) 1097 return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData); 1098 else 1099 { 1100 REGISTERWORDW rww; 1101 REGISTERWORDA *rwa = lpData; 1102 BOOL rc; 1103 1104 rww.lpReading = strdupAtoW(rwa->lpReading); 1105 rww.lpWord = strdupAtoW(rwa->lpWord); 1106 rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rww); 1107 HeapFree(GetProcessHeap(),0,rww.lpReading); 1108 HeapFree(GetProcessHeap(),0,rww.lpWord); 1109 return rc; 1110 } 1111 } 1112 else 1113 return FALSE; 1114 } 1115 1116 /*********************************************************************** 1117 * ImmConfigureIMEW (IMM32.@) 1118 */ 1119 BOOL WINAPI ImmConfigureIMEW( 1120 HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) 1121 { 1122 ImmHkl *immHkl = IMM_GetImmHkl(hKL); 1123 1124 TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData); 1125 1126 if (dwMode == IME_CONFIG_REGISTERWORD && !lpData) 1127 return FALSE; 1128 1129 if (immHkl->hIME && immHkl->pImeConfigure) 1130 { 1131 if (dwMode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode(immHkl)) 1132 return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData); 1133 else 1134 { 1135 REGISTERWORDW *rww = lpData; 1136 REGISTERWORDA rwa; 1137 BOOL rc; 1138 1139 rwa.lpReading = strdupWtoA(rww->lpReading); 1140 rwa.lpWord = strdupWtoA(rww->lpWord); 1141 rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rwa); 1142 HeapFree(GetProcessHeap(),0,rwa.lpReading); 1143 HeapFree(GetProcessHeap(),0,rwa.lpWord); 1144 return rc; 1145 } 1146 } 1147 else 1148 return FALSE; 1149 } 1150 1151 /*********************************************************************** 1152 * ImmCreateContext (IMM32.@) 1153 */ 1154 HIMC WINAPI ImmCreateContext(void) 1155 { 1156 PCLIENTIMC pClientImc; 1157 HIMC hIMC; 1158 1159 TRACE("()\n"); 1160 1161 if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32)) 1162 return NULL; 1163 1164 pClientImc = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC)); 1165 if (pClientImc == NULL) 1166 return NULL; 1167 1168 hIMC = NtUserCreateInputContext(pClientImc); 1169 if (hIMC == NULL) 1170 { 1171 HeapFree(g_hImm32Heap, 0, pClientImc); 1172 return NULL; 1173 } 1174 1175 RtlInitializeCriticalSection(&pClientImc->cs); 1176 1177 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken. 1178 pClientImc->unknown = NtUserGetThreadState(13); 1179 1180 return hIMC; 1181 } 1182 1183 static VOID APIENTRY Imm32CleanupContextExtra(LPINPUTCONTEXT pIC) 1184 { 1185 FIXME("We have to do something do here"); 1186 } 1187 1188 static PCLIENTIMC APIENTRY Imm32FindClientImc(HIMC hIMC) 1189 { 1190 // FIXME 1191 return NULL; 1192 } 1193 1194 BOOL APIENTRY Imm32CleanupContext(HIMC hIMC, HKL hKL, BOOL bKeep) 1195 { 1196 PIMEDPI pImeDpi; 1197 LPINPUTCONTEXT pIC; 1198 PCLIENTIMC pClientImc; 1199 1200 if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32) || hIMC == NULL) 1201 return FALSE; 1202 1203 FIXME("We have do something to do here\n"); 1204 pClientImc = Imm32FindClientImc(hIMC); 1205 if (!pClientImc) 1206 return FALSE; 1207 1208 if (pClientImc->hImc == NULL) 1209 { 1210 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN1; 1211 ImmUnlockClientImc(pClientImc); 1212 if (!bKeep) 1213 return NtUserDestroyInputContext(hIMC); 1214 return TRUE; 1215 } 1216 1217 pIC = ImmLockIMC(hIMC); 1218 if (pIC == NULL) 1219 { 1220 ImmUnlockClientImc(pClientImc); 1221 return FALSE; 1222 } 1223 1224 FIXME("We have do something to do here\n"); 1225 1226 if (pClientImc->hKL == hKL) 1227 { 1228 pImeDpi = ImmLockImeDpi(hKL); 1229 if (pImeDpi != NULL) 1230 { 1231 if (IS_IME_HKL(hKL)) 1232 { 1233 pImeDpi->ImeSelect(hIMC, FALSE); 1234 } 1235 else if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED)) 1236 { 1237 FIXME("We have do something to do here\n"); 1238 } 1239 ImmUnlockImeDpi(pImeDpi); 1240 } 1241 pClientImc->hKL = NULL; 1242 } 1243 1244 ImmDestroyIMCC(pIC->hPrivate); 1245 ImmDestroyIMCC(pIC->hMsgBuf); 1246 ImmDestroyIMCC(pIC->hGuideLine); 1247 ImmDestroyIMCC(pIC->hCandInfo); 1248 ImmDestroyIMCC(pIC->hCompStr); 1249 1250 Imm32CleanupContextExtra(pIC); 1251 1252 ImmUnlockIMC(hIMC); 1253 1254 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN1; 1255 ImmUnlockClientImc(pClientImc); 1256 1257 if (!bKeep) 1258 return NtUserDestroyInputContext(hIMC); 1259 1260 return TRUE; 1261 } 1262 1263 /*********************************************************************** 1264 * ImmDestroyContext (IMM32.@) 1265 */ 1266 BOOL WINAPI ImmDestroyContext(HIMC hIMC) 1267 { 1268 HKL hKL; 1269 1270 TRACE("(%p)\n", hIMC); 1271 1272 if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32)) 1273 return FALSE; 1274 1275 if (Imm32IsCrossThreadAccess(hIMC)) 1276 return FALSE; 1277 1278 hKL = GetKeyboardLayout(0); 1279 return Imm32CleanupContext(hIMC, hKL, FALSE); 1280 } 1281 1282 /*********************************************************************** 1283 * ImmDisableIME (IMM32.@) 1284 */ 1285 BOOL WINAPI ImmDisableIME(DWORD dwThreadId) 1286 { 1287 return NtUserDisableThreadIme(dwThreadId); 1288 } 1289 1290 /* 1291 * These functions absorb the difference between Ansi and Wide. 1292 */ 1293 typedef struct ENUM_WORD_A2W 1294 { 1295 REGISTERWORDENUMPROCW lpfnEnumProc; 1296 LPVOID lpData; 1297 UINT ret; 1298 } ENUM_WORD_A2W, *LPENUM_WORD_A2W; 1299 1300 typedef struct ENUM_WORD_W2A 1301 { 1302 REGISTERWORDENUMPROCA lpfnEnumProc; 1303 LPVOID lpData; 1304 UINT ret; 1305 } ENUM_WORD_W2A, *LPENUM_WORD_W2A; 1306 1307 static INT CALLBACK 1308 Imm32EnumWordProcA2W(LPCSTR pszReadingA, DWORD dwStyle, LPCSTR pszRegisterA, LPVOID lpData) 1309 { 1310 INT ret = 0; 1311 LPENUM_WORD_A2W lpEnumData = lpData; 1312 LPWSTR pszReadingW = NULL, pszRegisterW = NULL; 1313 1314 if (pszReadingA) 1315 { 1316 pszReadingW = Imm32WideFromAnsi(pszReadingA); 1317 if (pszReadingW == NULL) 1318 goto Quit; 1319 } 1320 1321 if (pszRegisterA) 1322 { 1323 pszRegisterW = Imm32WideFromAnsi(pszRegisterA); 1324 if (pszRegisterW == NULL) 1325 goto Quit; 1326 } 1327 1328 ret = lpEnumData->lpfnEnumProc(pszReadingW, dwStyle, pszRegisterW, lpEnumData->lpData); 1329 lpEnumData->ret = ret; 1330 1331 Quit: 1332 if (pszReadingW) 1333 HeapFree(g_hImm32Heap, 0, pszReadingW); 1334 if (pszRegisterW) 1335 HeapFree(g_hImm32Heap, 0, pszRegisterW); 1336 return ret; 1337 } 1338 1339 static INT CALLBACK 1340 Imm32EnumWordProcW2A(LPCWSTR pszReadingW, DWORD dwStyle, LPCWSTR pszRegisterW, LPVOID lpData) 1341 { 1342 INT ret = 0; 1343 LPENUM_WORD_W2A lpEnumData = lpData; 1344 LPSTR pszReadingA = NULL, pszRegisterA = NULL; 1345 1346 if (pszReadingW) 1347 { 1348 pszReadingA = Imm32AnsiFromWide(pszReadingW); 1349 if (pszReadingW == NULL) 1350 goto Quit; 1351 } 1352 1353 if (pszRegisterW) 1354 { 1355 pszRegisterA = Imm32AnsiFromWide(pszRegisterW); 1356 if (pszRegisterA == NULL) 1357 goto Quit; 1358 } 1359 1360 ret = lpEnumData->lpfnEnumProc(pszReadingA, dwStyle, pszRegisterA, lpEnumData->lpData); 1361 lpEnumData->ret = ret; 1362 1363 Quit: 1364 if (pszReadingA) 1365 HeapFree(g_hImm32Heap, 0, pszReadingA); 1366 if (pszRegisterA) 1367 HeapFree(g_hImm32Heap, 0, pszRegisterA); 1368 return ret; 1369 } 1370 1371 /*********************************************************************** 1372 * ImmEnumRegisterWordA (IMM32.@) 1373 */ 1374 UINT WINAPI ImmEnumRegisterWordA( 1375 HKL hKL, REGISTERWORDENUMPROCA lpfnEnumProc, 1376 LPCSTR lpszReading, DWORD dwStyle, 1377 LPCSTR lpszRegister, LPVOID lpData) 1378 { 1379 UINT ret = 0; 1380 LPWSTR pszReadingW = NULL, pszRegisterW = NULL; 1381 ENUM_WORD_W2A EnumDataW2A; 1382 PIMEDPI pImeDpi; 1383 1384 TRACE("(%p, %p, %s, 0x%lX, %s, %p)", hKL, lpfnEnumProc, debugstr_a(lpszReading), 1385 dwStyle, debugstr_a(lpszRegister), lpData); 1386 1387 pImeDpi = ImmLockOrLoadImeDpi(hKL); 1388 if (!pImeDpi) 1389 return 0; 1390 1391 if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)) 1392 { 1393 ret = pImeDpi->ImeEnumRegisterWord(lpfnEnumProc, lpszReading, dwStyle, 1394 lpszRegister, lpData); 1395 ImmUnlockImeDpi(pImeDpi); 1396 return ret; 1397 } 1398 1399 if (lpszReading) 1400 { 1401 pszReadingW = Imm32WideFromAnsi(lpszReading); 1402 if (pszReadingW == NULL) 1403 goto Quit; 1404 } 1405 1406 if (lpszRegister) 1407 { 1408 pszRegisterW = Imm32WideFromAnsi(lpszRegister); 1409 if (pszRegisterW == NULL) 1410 goto Quit; 1411 } 1412 1413 EnumDataW2A.lpfnEnumProc = lpfnEnumProc; 1414 EnumDataW2A.lpData = lpData; 1415 EnumDataW2A.ret = 0; 1416 pImeDpi->ImeEnumRegisterWord(Imm32EnumWordProcW2A, pszReadingW, dwStyle, 1417 pszRegisterW, &EnumDataW2A); 1418 ret = EnumDataW2A.ret; 1419 1420 Quit: 1421 if (pszReadingW) 1422 HeapFree(g_hImm32Heap, 0, pszReadingW); 1423 if (pszRegisterW) 1424 HeapFree(g_hImm32Heap, 0, pszRegisterW); 1425 ImmUnlockImeDpi(pImeDpi); 1426 return ret; 1427 } 1428 1429 /*********************************************************************** 1430 * ImmEnumRegisterWordW (IMM32.@) 1431 */ 1432 UINT WINAPI ImmEnumRegisterWordW( 1433 HKL hKL, REGISTERWORDENUMPROCW lpfnEnumProc, 1434 LPCWSTR lpszReading, DWORD dwStyle, 1435 LPCWSTR lpszRegister, LPVOID lpData) 1436 { 1437 UINT ret = 0; 1438 LPSTR pszReadingA = NULL, pszRegisterA = NULL; 1439 ENUM_WORD_A2W EnumDataA2W; 1440 PIMEDPI pImeDpi; 1441 1442 TRACE("(%p, %p, %s, 0x%lX, %s, %p)", hKL, lpfnEnumProc, debugstr_w(lpszReading), 1443 dwStyle, debugstr_w(lpszRegister), lpData); 1444 1445 pImeDpi = ImmLockOrLoadImeDpi(hKL); 1446 if (!pImeDpi) 1447 return 0; 1448 1449 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) 1450 { 1451 ret = pImeDpi->ImeEnumRegisterWord(lpfnEnumProc, lpszReading, dwStyle, 1452 lpszRegister, lpData); 1453 ImmUnlockImeDpi(pImeDpi); 1454 return ret; 1455 } 1456 1457 if (lpszReading) 1458 { 1459 pszReadingA = Imm32AnsiFromWide(lpszReading); 1460 if (pszReadingA == NULL) 1461 goto Quit; 1462 } 1463 1464 if (lpszRegister) 1465 { 1466 pszRegisterA = Imm32AnsiFromWide(lpszRegister); 1467 if (pszRegisterA == NULL) 1468 goto Quit; 1469 } 1470 1471 EnumDataA2W.lpfnEnumProc = lpfnEnumProc; 1472 EnumDataA2W.lpData = lpData; 1473 EnumDataA2W.ret = 0; 1474 pImeDpi->ImeEnumRegisterWord(Imm32EnumWordProcA2W, pszReadingA, dwStyle, 1475 pszRegisterA, &EnumDataA2W); 1476 ret = EnumDataA2W.ret; 1477 1478 Quit: 1479 if (pszReadingA) 1480 HeapFree(g_hImm32Heap, 0, pszReadingA); 1481 if (pszRegisterA) 1482 HeapFree(g_hImm32Heap, 0, pszRegisterA); 1483 ImmUnlockImeDpi(pImeDpi); 1484 return ret; 1485 } 1486 1487 static inline BOOL EscapeRequiresWA(UINT uEscape) 1488 { 1489 if (uEscape == IME_ESC_GET_EUDC_DICTIONARY || 1490 uEscape == IME_ESC_SET_EUDC_DICTIONARY || 1491 uEscape == IME_ESC_IME_NAME || 1492 uEscape == IME_ESC_GETHELPFILENAME) 1493 return TRUE; 1494 return FALSE; 1495 } 1496 1497 /*********************************************************************** 1498 * ImmEscapeA (IMM32.@) 1499 */ 1500 LRESULT WINAPI ImmEscapeA( 1501 HKL hKL, HIMC hIMC, 1502 UINT uEscape, LPVOID lpData) 1503 { 1504 ImmHkl *immHkl = IMM_GetImmHkl(hKL); 1505 TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData); 1506 1507 if (immHkl->hIME && immHkl->pImeEscape) 1508 { 1509 if (!EscapeRequiresWA(uEscape) || !is_kbd_ime_unicode(immHkl)) 1510 return immHkl->pImeEscape(hIMC,uEscape,lpData); 1511 else 1512 { 1513 WCHAR buffer[81]; /* largest required buffer should be 80 */ 1514 LRESULT rc; 1515 if (uEscape == IME_ESC_SET_EUDC_DICTIONARY) 1516 { 1517 MultiByteToWideChar(CP_ACP,0,lpData,-1,buffer,81); 1518 rc = immHkl->pImeEscape(hIMC,uEscape,buffer); 1519 } 1520 else 1521 { 1522 rc = immHkl->pImeEscape(hIMC,uEscape,buffer); 1523 WideCharToMultiByte(CP_ACP,0,buffer,-1,lpData,80, NULL, NULL); 1524 } 1525 return rc; 1526 } 1527 } 1528 else 1529 return 0; 1530 } 1531 1532 /*********************************************************************** 1533 * ImmEscapeW (IMM32.@) 1534 */ 1535 LRESULT WINAPI ImmEscapeW( 1536 HKL hKL, HIMC hIMC, 1537 UINT uEscape, LPVOID lpData) 1538 { 1539 ImmHkl *immHkl = IMM_GetImmHkl(hKL); 1540 TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData); 1541 1542 if (immHkl->hIME && immHkl->pImeEscape) 1543 { 1544 if (!EscapeRequiresWA(uEscape) || is_kbd_ime_unicode(immHkl)) 1545 return immHkl->pImeEscape(hIMC,uEscape,lpData); 1546 else 1547 { 1548 CHAR buffer[81]; /* largest required buffer should be 80 */ 1549 LRESULT rc; 1550 if (uEscape == IME_ESC_SET_EUDC_DICTIONARY) 1551 { 1552 WideCharToMultiByte(CP_ACP,0,lpData,-1,buffer,81, NULL, NULL); 1553 rc = immHkl->pImeEscape(hIMC,uEscape,buffer); 1554 } 1555 else 1556 { 1557 rc = immHkl->pImeEscape(hIMC,uEscape,buffer); 1558 MultiByteToWideChar(CP_ACP,0,buffer,-1,lpData,80); 1559 } 1560 return rc; 1561 } 1562 } 1563 else 1564 return 0; 1565 } 1566 1567 static PCLIENTIMC APIENTRY Imm32GetClientImcCache(void) 1568 { 1569 // FIXME: Do something properly here 1570 return NULL; 1571 } 1572 1573 static DWORD APIENTRY Imm32AllocAndBuildHimcList(DWORD dwThreadId, HIMC **pphList) 1574 { 1575 #define INITIAL_COUNT 0x40 1576 #define MAX_RETRY 10 1577 NTSTATUS Status; 1578 DWORD dwCount = INITIAL_COUNT, cRetry = 0; 1579 HIMC *phNewList; 1580 1581 phNewList = Imm32HeapAlloc(0, dwCount * sizeof(HIMC)); 1582 if (phNewList == NULL) 1583 return 0; 1584 1585 Status = NtUserBuildHimcList(dwThreadId, dwCount, phNewList, &dwCount); 1586 while (Status == STATUS_BUFFER_TOO_SMALL) 1587 { 1588 HeapFree(g_hImm32Heap, 0, phNewList); 1589 if (cRetry++ >= MAX_RETRY) 1590 return 0; 1591 1592 phNewList = Imm32HeapAlloc(0, dwCount * sizeof(HIMC)); 1593 if (phNewList == NULL) 1594 return 0; 1595 1596 Status = NtUserBuildHimcList(dwThreadId, dwCount, phNewList, &dwCount); 1597 } 1598 1599 if (NT_ERROR(Status) || !dwCount) 1600 { 1601 HeapFree(g_hImm32Heap, 0, phNewList); 1602 return 0; 1603 } 1604 1605 *pphList = phNewList; 1606 return dwCount; 1607 #undef INITIAL_COUNT 1608 #undef MAX_RETRY 1609 } 1610 1611 static BOOL APIENTRY Imm32ImeNonImeToggle(HIMC hIMC, HKL hKL, HWND hWnd, LANGID LangID) 1612 { 1613 LPINPUTCONTEXT pIC; 1614 BOOL fOpen; 1615 1616 if (hWnd != NULL) 1617 return FALSE; 1618 1619 if (!IS_IME_HKL(hKL) || LOWORD(hKL) != LangID) 1620 { 1621 FIXME("We have to do something here\n"); 1622 return TRUE; 1623 } 1624 1625 pIC = ImmLockIMC(hIMC); 1626 if (pIC == NULL) 1627 return TRUE; 1628 1629 fOpen = pIC->fOpen; 1630 ImmUnlockIMC(hIMC); 1631 1632 if (!fOpen) 1633 { 1634 ImmSetOpenStatus(hIMC, TRUE); 1635 return TRUE; 1636 } 1637 1638 FIXME("We have to do something here\n"); 1639 return TRUE; 1640 } 1641 1642 static BOOL APIENTRY Imm32CShapeToggle(HIMC hIMC, HKL hKL, HWND hWnd) 1643 { 1644 LPINPUTCONTEXT pIC; 1645 BOOL fOpen; 1646 DWORD dwConversion, dwSentence; 1647 1648 if (hWnd == NULL || !IS_IME_HKL(hKL)) 1649 return FALSE; 1650 1651 pIC = ImmLockIMC(hIMC); 1652 if (pIC == NULL) 1653 return TRUE; 1654 1655 fOpen = pIC->fOpen; 1656 if (fOpen) 1657 { 1658 dwConversion = (pIC->fdwConversion ^ IME_CMODE_FULLSHAPE); 1659 dwSentence = pIC->fdwSentence; 1660 } 1661 1662 ImmUnlockIMC(hIMC); 1663 1664 if (fOpen) 1665 ImmSetConversionStatus(hIMC, dwConversion, dwSentence); 1666 else 1667 ImmSetOpenStatus(hIMC, TRUE); 1668 1669 return TRUE; 1670 } 1671 1672 static BOOL APIENTRY Imm32CSymbolToggle(HIMC hIMC, HKL hKL, HWND hWnd) 1673 { 1674 LPINPUTCONTEXT pIC; 1675 BOOL fOpen; 1676 DWORD dwConversion, dwSentence; 1677 1678 if (hWnd == NULL || !IS_IME_HKL(hKL)) 1679 return FALSE; 1680 1681 pIC = ImmLockIMC(hIMC); 1682 if (pIC == NULL) 1683 return TRUE; 1684 1685 fOpen = pIC->fOpen; 1686 if (fOpen) 1687 { 1688 dwConversion = (pIC->fdwConversion ^ IME_CMODE_SYMBOL); 1689 dwSentence = pIC->fdwSentence; 1690 } 1691 1692 ImmUnlockIMC(hIMC); 1693 1694 if (fOpen) 1695 ImmSetConversionStatus(hIMC, dwConversion, dwSentence); 1696 else 1697 ImmSetOpenStatus(hIMC, TRUE); 1698 1699 return TRUE; 1700 } 1701 1702 static BOOL APIENTRY Imm32JCloseOpen(HIMC hIMC, HKL hKL, HWND hWnd) 1703 { 1704 BOOL fOpen; 1705 1706 if (ImmIsIME(hKL) && LOWORD(hKL) == LANGID_JAPANESE) 1707 { 1708 fOpen = ImmGetOpenStatus(hIMC); 1709 ImmSetOpenStatus(hIMC, !fOpen); 1710 return TRUE; 1711 } 1712 1713 FIXME("We have to do something here\n"); 1714 return TRUE; 1715 } 1716 1717 static BOOL APIENTRY Imm32KShapeToggle(HIMC hIMC) 1718 { 1719 LPINPUTCONTEXT pIC; 1720 DWORD dwConversion, dwSentence; 1721 1722 pIC = ImmLockIMC(hIMC); 1723 if (pIC == NULL) 1724 return FALSE; 1725 1726 dwConversion = (pIC->fdwConversion ^ IME_CMODE_FULLSHAPE); 1727 dwSentence = pIC->fdwSentence; 1728 ImmSetConversionStatus(hIMC, dwConversion, dwSentence); 1729 1730 if (pIC->fdwConversion & (IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE)) 1731 ImmSetOpenStatus(hIMC, TRUE); 1732 else 1733 ImmSetOpenStatus(hIMC, FALSE); 1734 1735 ImmUnlockIMC(hIMC); 1736 return TRUE; 1737 } 1738 1739 static BOOL APIENTRY Imm32KHanjaConvert(HIMC hIMC) 1740 { 1741 LPINPUTCONTEXT pIC; 1742 DWORD dwConversion, dwSentence; 1743 1744 pIC = ImmLockIMC(hIMC); 1745 if (!pIC) 1746 return FALSE; 1747 1748 dwConversion = (pIC->fdwConversion ^ IME_CMODE_HANJACONVERT); 1749 dwSentence = pIC->fdwSentence; 1750 ImmUnlockIMC(hIMC); 1751 1752 ImmSetConversionStatus(hIMC, dwConversion, dwSentence); 1753 return TRUE; 1754 } 1755 1756 static BOOL APIENTRY Imm32KEnglish(HIMC hIMC) 1757 { 1758 LPINPUTCONTEXT pIC; 1759 DWORD dwConversion, dwSentence; 1760 BOOL fOpen; 1761 1762 pIC = ImmLockIMC(hIMC); 1763 if (pIC == NULL) 1764 return FALSE; 1765 1766 dwConversion = (pIC->fdwConversion ^ IME_CMODE_NATIVE); 1767 dwSentence = pIC->fdwSentence; 1768 ImmSetConversionStatus(hIMC, dwConversion, dwSentence); 1769 1770 fOpen = ((pIC->fdwConversion & (IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE)) != 0); 1771 ImmSetOpenStatus(hIMC, fOpen); 1772 1773 ImmUnlockIMC(hIMC); 1774 return TRUE; 1775 } 1776 1777 static BOOL APIENTRY Imm32ProcessHotKey(HWND hWnd, HIMC hIMC, HKL hKL, DWORD dwHotKeyID) 1778 { 1779 PIMEDPI pImeDpi; 1780 BOOL ret; 1781 1782 if (hIMC && Imm32IsCrossThreadAccess(hIMC)) 1783 return FALSE; 1784 1785 switch (dwHotKeyID) 1786 { 1787 case IME_CHOTKEY_IME_NONIME_TOGGLE: 1788 return Imm32ImeNonImeToggle(hIMC, hKL, hWnd, LANGID_CHINESE_SIMPLIFIED); 1789 1790 case IME_CHOTKEY_SHAPE_TOGGLE: 1791 return Imm32CShapeToggle(hIMC, hKL, hWnd); 1792 1793 case IME_CHOTKEY_SYMBOL_TOGGLE: 1794 return Imm32CSymbolToggle(hIMC, hKL, hWnd); 1795 1796 case IME_JHOTKEY_CLOSE_OPEN: 1797 return Imm32JCloseOpen(hIMC, hKL, hWnd); 1798 1799 case IME_KHOTKEY_SHAPE_TOGGLE: 1800 return Imm32KShapeToggle(hIMC); 1801 1802 case IME_KHOTKEY_HANJACONVERT: 1803 return Imm32KHanjaConvert(hIMC); 1804 1805 case IME_KHOTKEY_ENGLISH: 1806 return Imm32KEnglish(hIMC); 1807 1808 case IME_THOTKEY_IME_NONIME_TOGGLE: 1809 return Imm32ImeNonImeToggle(hIMC, hKL, hWnd, LANGID_CHINESE_TRADITIONAL); 1810 1811 case IME_THOTKEY_SHAPE_TOGGLE: 1812 return Imm32CShapeToggle(hIMC, hKL, hWnd); 1813 1814 case IME_THOTKEY_SYMBOL_TOGGLE: 1815 return Imm32CSymbolToggle(hIMC, hKL, hWnd); 1816 1817 default: 1818 break; 1819 } 1820 1821 if (dwHotKeyID < IME_HOTKEY_PRIVATE_FIRST || IME_HOTKEY_PRIVATE_LAST < dwHotKeyID) 1822 return FALSE; 1823 1824 pImeDpi = ImmLockImeDpi(hKL); 1825 if (pImeDpi == NULL) 1826 return FALSE; 1827 1828 ret = (BOOL)pImeDpi->ImeEscape(hIMC, IME_ESC_PRIVATE_HOTKEY, &dwHotKeyID); 1829 ImmUnlockImeDpi(pImeDpi); 1830 return ret; 1831 } 1832 1833 /*********************************************************************** 1834 * ImmLockClientImc (IMM32.@) 1835 */ 1836 PCLIENTIMC WINAPI ImmLockClientImc(HIMC hImc) 1837 { 1838 PCLIENTIMC pClientImc; 1839 1840 TRACE("(%p)\n", hImc); 1841 1842 if (hImc == NULL) 1843 return NULL; 1844 1845 pClientImc = Imm32GetClientImcCache(); 1846 if (!pClientImc) 1847 { 1848 pClientImc = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC)); 1849 if (!pClientImc) 1850 return NULL; 1851 1852 RtlInitializeCriticalSection(&pClientImc->cs); 1853 1854 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken. 1855 pClientImc->unknown = NtUserGetThreadState(13); 1856 1857 if (!NtUserUpdateInputContext(hImc, 0, pClientImc)) 1858 { 1859 HeapFree(g_hImm32Heap, 0, pClientImc); 1860 return NULL; 1861 } 1862 1863 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN2; 1864 } 1865 else 1866 { 1867 if (pClientImc->dwFlags & CLIENTIMC_UNKNOWN1) 1868 return NULL; 1869 } 1870 1871 InterlockedIncrement(&pClientImc->cLockObj); 1872 return pClientImc; 1873 } 1874 1875 /*********************************************************************** 1876 * ImmUnlockClientImc (IMM32.@) 1877 */ 1878 VOID WINAPI ImmUnlockClientImc(PCLIENTIMC pClientImc) 1879 { 1880 LONG cLocks; 1881 HIMC hImc; 1882 1883 TRACE("(%p)\n", pClientImc); 1884 1885 cLocks = InterlockedDecrement(&pClientImc->cLockObj); 1886 if (cLocks != 0 || !(pClientImc->dwFlags & CLIENTIMC_UNKNOWN1)) 1887 return; 1888 1889 hImc = pClientImc->hImc; 1890 if (hImc) 1891 LocalFree(hImc); 1892 1893 RtlDeleteCriticalSection(&pClientImc->cs); 1894 HeapFree(g_hImm32Heap, 0, pClientImc); 1895 } 1896 1897 static HIMC APIENTRY Imm32GetContextEx(HWND hWnd, DWORD dwContextFlags) 1898 { 1899 HIMC hIMC; 1900 PCLIENTIMC pClientImc; 1901 PWND pWnd; 1902 1903 if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_IMM32)) 1904 return NULL; 1905 1906 if (!hWnd) 1907 { 1908 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken. 1909 hIMC = (HIMC)NtUserGetThreadState(4); 1910 goto Quit; 1911 } 1912 1913 pWnd = ValidateHwndNoErr(hWnd); 1914 if (!pWnd || Imm32IsCrossProcessAccess(hWnd)) 1915 return NULL; 1916 1917 hIMC = pWnd->hImc; 1918 if (!hIMC && (dwContextFlags & 1)) 1919 hIMC = (HIMC)NtUserQueryWindow(hWnd, QUERY_WINDOW_DEFAULT_ICONTEXT); 1920 1921 Quit: 1922 pClientImc = ImmLockClientImc(hIMC); 1923 if (pClientImc == NULL) 1924 return NULL; 1925 if ((dwContextFlags & 2) && (pClientImc->dwFlags & CLIENTIMC_UNKNOWN3)) 1926 hIMC = NULL; 1927 ImmUnlockClientImc(pClientImc); 1928 return hIMC; 1929 } 1930 1931 static DWORD APIENTRY 1932 CandidateListWideToAnsi(const CANDIDATELIST *pWideCL, LPCANDIDATELIST pAnsiCL, DWORD dwBufLen, 1933 UINT uCodePage) 1934 { 1935 BOOL bUsedDefault; 1936 DWORD dwSize, dwIndex, cbGot, cbLeft; 1937 const BYTE *pbWide; 1938 LPBYTE pbAnsi; 1939 LPDWORD pibOffsets; 1940 1941 /* calculate total ansi size */ 1942 if (pWideCL->dwCount > 0) 1943 { 1944 dwSize = sizeof(CANDIDATELIST) + ((pWideCL->dwCount - 1) * sizeof(DWORD)); 1945 for (dwIndex = 0; dwIndex < pWideCL->dwCount; ++dwIndex) 1946 { 1947 pbWide = (const BYTE *)pWideCL + pWideCL->dwOffset[dwIndex]; 1948 cbGot = WideCharToMultiByte(uCodePage, 0, (LPCWSTR)pbWide, -1, NULL, 0, 1949 NULL, &bUsedDefault); 1950 dwSize += cbGot; 1951 } 1952 } 1953 else 1954 { 1955 dwSize = sizeof(CANDIDATELIST); 1956 } 1957 1958 dwSize = ROUNDUP4(dwSize); 1959 if (dwBufLen == 0) 1960 return dwSize; 1961 if (dwBufLen < dwSize) 1962 return 0; 1963 1964 /* store to ansi */ 1965 pAnsiCL->dwSize = dwBufLen; 1966 pAnsiCL->dwStyle = pWideCL->dwStyle; 1967 pAnsiCL->dwCount = pWideCL->dwCount; 1968 pAnsiCL->dwSelection = pWideCL->dwSelection; 1969 pAnsiCL->dwPageStart = pWideCL->dwPageStart; 1970 pAnsiCL->dwPageSize = pWideCL->dwPageSize; 1971 1972 pibOffsets = pAnsiCL->dwOffset; 1973 if (pWideCL->dwCount > 0) 1974 { 1975 pibOffsets[0] = sizeof(CANDIDATELIST) + ((pWideCL->dwCount - 1) * sizeof(DWORD)); 1976 cbLeft = dwBufLen - pibOffsets[0]; 1977 1978 for (dwIndex = 0; dwIndex < pWideCL->dwCount; ++dwIndex) 1979 { 1980 pbWide = (const BYTE *)pWideCL + pWideCL->dwOffset[dwIndex]; 1981 pbAnsi = (LPBYTE)pAnsiCL + pibOffsets[dwIndex]; 1982 1983 /* convert to ansi */ 1984 cbGot = WideCharToMultiByte(uCodePage, 0, (LPCWSTR)pbWide, -1, 1985 (LPSTR)pbAnsi, cbLeft, NULL, &bUsedDefault); 1986 cbLeft -= cbGot; 1987 1988 if (dwIndex < pWideCL->dwCount - 1) 1989 pibOffsets[dwIndex + 1] = pibOffsets[dwIndex] + cbGot; 1990 } 1991 } 1992 else 1993 { 1994 pibOffsets[0] = sizeof(CANDIDATELIST); 1995 } 1996 1997 return dwBufLen; 1998 } 1999 2000 static DWORD APIENTRY 2001 CandidateListAnsiToWide(const CANDIDATELIST *pAnsiCL, LPCANDIDATELIST pWideCL, DWORD dwBufLen, 2002 UINT uCodePage) 2003 { 2004 DWORD dwSize, dwIndex, cchGot, cbGot, cbLeft; 2005 const BYTE *pbAnsi; 2006 LPBYTE pbWide; 2007 LPDWORD pibOffsets; 2008 2009 /* calculate total wide size */ 2010 if (pAnsiCL->dwCount > 0) 2011 { 2012 dwSize = sizeof(CANDIDATELIST) + ((pAnsiCL->dwCount - 1) * sizeof(DWORD)); 2013 for (dwIndex = 0; dwIndex < pAnsiCL->dwCount; ++dwIndex) 2014 { 2015 pbAnsi = (const BYTE *)pAnsiCL + pAnsiCL->dwOffset[dwIndex]; 2016 cchGot = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, (LPCSTR)pbAnsi, -1, NULL, 0); 2017 dwSize += cchGot * sizeof(WCHAR); 2018 } 2019 } 2020 else 2021 { 2022 dwSize = sizeof(CANDIDATELIST); 2023 } 2024 2025 dwSize = ROUNDUP4(dwSize); 2026 if (dwBufLen == 0) 2027 return dwSize; 2028 if (dwBufLen < dwSize) 2029 return 0; 2030 2031 /* store to wide */ 2032 pWideCL->dwSize = dwBufLen; 2033 pWideCL->dwStyle = pAnsiCL->dwStyle; 2034 pWideCL->dwCount = pAnsiCL->dwCount; 2035 pWideCL->dwSelection = pAnsiCL->dwSelection; 2036 pWideCL->dwPageStart = pAnsiCL->dwPageStart; 2037 pWideCL->dwPageSize = pAnsiCL->dwPageSize; 2038 2039 pibOffsets = pWideCL->dwOffset; 2040 if (pAnsiCL->dwCount > 0) 2041 { 2042 pibOffsets[0] = sizeof(CANDIDATELIST) + ((pWideCL->dwCount - 1) * sizeof(DWORD)); 2043 cbLeft = dwBufLen - pibOffsets[0]; 2044 2045 for (dwIndex = 0; dwIndex < pAnsiCL->dwCount; ++dwIndex) 2046 { 2047 pbAnsi = (const BYTE *)pAnsiCL + pAnsiCL->dwOffset[dwIndex]; 2048 pbWide = (LPBYTE)pWideCL + pibOffsets[dwIndex]; 2049 2050 /* convert to wide */ 2051 cchGot = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, (LPCSTR)pbAnsi, -1, 2052 (LPWSTR)pbWide, cbLeft / sizeof(WCHAR)); 2053 cbGot = cchGot * sizeof(WCHAR); 2054 cbLeft -= cbGot; 2055 2056 if (dwIndex + 1 < pAnsiCL->dwCount) 2057 pibOffsets[dwIndex + 1] = pibOffsets[dwIndex] + cbGot; 2058 } 2059 } 2060 else 2061 { 2062 pibOffsets[0] = sizeof(CANDIDATELIST); 2063 } 2064 2065 return dwBufLen; 2066 } 2067 2068 static DWORD APIENTRY 2069 ImmGetCandidateListAW(HIMC hIMC, DWORD dwIndex, LPCANDIDATELIST lpCandList, DWORD dwBufLen, 2070 BOOL bAnsi) 2071 { 2072 DWORD ret = 0; 2073 LPINPUTCONTEXT pIC; 2074 PCLIENTIMC pClientImc; 2075 LPCANDIDATEINFO pCI; 2076 LPCANDIDATELIST pCL; 2077 DWORD dwSize; 2078 2079 pClientImc = ImmLockClientImc(hIMC); 2080 if (!pClientImc) 2081 return 0; 2082 2083 pIC = ImmLockIMC(hIMC); 2084 if (pIC == NULL) 2085 { 2086 ImmUnlockClientImc(pClientImc); 2087 return 0; 2088 } 2089 2090 pCI = ImmLockIMCC(pIC->hCandInfo); 2091 if (pCI == NULL) 2092 { 2093 ImmUnlockIMC(hIMC); 2094 ImmUnlockClientImc(pClientImc); 2095 return 0; 2096 } 2097 2098 if (pCI->dwSize < sizeof(CANDIDATEINFO) || pCI->dwCount <= dwIndex) 2099 goto Quit; 2100 2101 /* get required size */ 2102 pCL = (LPCANDIDATELIST)((LPBYTE)pCI + pCI->dwOffset[dwIndex]); 2103 if (bAnsi) 2104 { 2105 if (pClientImc->dwFlags & CLIENTIMC_WIDE) 2106 dwSize = CandidateListAnsiToWide(pCL, NULL, 0, CP_ACP); 2107 else 2108 dwSize = pCL->dwSize; 2109 } 2110 else 2111 { 2112 if (pClientImc->dwFlags & CLIENTIMC_WIDE) 2113 dwSize = pCL->dwSize; 2114 else 2115 dwSize = CandidateListWideToAnsi(pCL, NULL, 0, CP_ACP); 2116 } 2117 2118 if (dwBufLen != 0 && dwSize != 0) 2119 { 2120 if (lpCandList == NULL || dwBufLen < dwSize) 2121 goto Quit; 2122 2123 /* store */ 2124 if (bAnsi) 2125 { 2126 if (pClientImc->dwFlags & CLIENTIMC_WIDE) 2127 CandidateListAnsiToWide(pCL, lpCandList, dwSize, CP_ACP); 2128 else 2129 RtlCopyMemory(lpCandList, pCL, dwSize); 2130 } 2131 else 2132 { 2133 if (pClientImc->dwFlags & CLIENTIMC_WIDE) 2134 RtlCopyMemory(lpCandList, pCL, dwSize); 2135 else 2136 CandidateListWideToAnsi(pCL, lpCandList, dwSize, CP_ACP); 2137 } 2138 } 2139 2140 ret = dwSize; 2141 2142 Quit: 2143 ImmUnlockIMCC(pIC->hCandInfo); 2144 ImmUnlockIMC(hIMC); 2145 ImmUnlockClientImc(pClientImc); 2146 return ret; 2147 } 2148 2149 DWORD APIENTRY ImmGetCandidateListCountAW(HIMC hIMC, LPDWORD lpdwListCount, BOOL bAnsi) 2150 { 2151 DWORD ret = 0, cbGot, dwIndex; 2152 PCLIENTIMC pClientImc; 2153 LPINPUTCONTEXT pIC; 2154 const CANDIDATEINFO *pCI; 2155 const BYTE *pb; 2156 const CANDIDATELIST *pCL; 2157 const DWORD *pdwOffsets; 2158 2159 if (lpdwListCount == NULL) 2160 return 0; 2161 2162 *lpdwListCount = 0; 2163 2164 pClientImc = ImmLockClientImc(hIMC); 2165 if (pClientImc == NULL) 2166 return 0; 2167 2168 pIC = ImmLockIMC(hIMC); 2169 if (pIC == NULL) 2170 { 2171 ImmUnlockClientImc(pClientImc); 2172 return 0; 2173 } 2174 2175 pCI = ImmLockIMCC(pIC->hCandInfo); 2176 if (pCI == NULL) 2177 { 2178 ImmUnlockIMC(hIMC); 2179 ImmUnlockClientImc(pClientImc); 2180 return 0; 2181 } 2182 2183 if (pCI->dwSize < sizeof(CANDIDATEINFO)) 2184 goto Quit; 2185 2186 *lpdwListCount = pCI->dwCount; /* the number of candidate lists */ 2187 2188 /* calculate total size of candidate lists */ 2189 if (bAnsi) 2190 { 2191 if (pClientImc->dwFlags & CLIENTIMC_WIDE) 2192 { 2193 ret = ROUNDUP4(pCI->dwPrivateSize); 2194 pdwOffsets = pCI->dwOffset; 2195 for (dwIndex = 0; dwIndex < pCI->dwCount; ++dwIndex) 2196 { 2197 pb = (const BYTE *)pCI + pdwOffsets[dwIndex]; 2198 pCL = (const CANDIDATELIST *)pb; 2199 cbGot = CandidateListWideToAnsi(pCL, NULL, 0, CP_ACP); 2200 ret += cbGot; 2201 } 2202 } 2203 else 2204 { 2205 ret = pCI->dwSize; 2206 } 2207 } 2208 else 2209 { 2210 if (pClientImc->dwFlags & CLIENTIMC_WIDE) 2211 { 2212 ret = pCI->dwSize; 2213 } 2214 else 2215 { 2216 ret = ROUNDUP4(pCI->dwPrivateSize); 2217 pdwOffsets = pCI->dwOffset; 2218 for (dwIndex = 0; dwIndex < pCI->dwCount; ++dwIndex) 2219 { 2220 pb = (const BYTE *)pCI + pdwOffsets[dwIndex]; 2221 pCL = (const CANDIDATELIST *)pb; 2222 cbGot = CandidateListAnsiToWide(pCL, NULL, 0, CP_ACP); 2223 ret += cbGot; 2224 } 2225 } 2226 } 2227 2228 Quit: 2229 ImmUnlockIMCC(pIC->hCandInfo); 2230 ImmUnlockIMC(hIMC); 2231 ImmUnlockClientImc(pClientImc); 2232 return ret; 2233 } 2234 2235 /*********************************************************************** 2236 * ImmGetCandidateListA (IMM32.@) 2237 */ 2238 DWORD WINAPI ImmGetCandidateListA( 2239 HIMC hIMC, DWORD dwIndex, 2240 LPCANDIDATELIST lpCandList, DWORD dwBufLen) 2241 { 2242 return ImmGetCandidateListAW(hIMC, dwIndex, lpCandList, dwBufLen, TRUE); 2243 } 2244 2245 /*********************************************************************** 2246 * ImmGetCandidateListCountA (IMM32.@) 2247 */ 2248 DWORD WINAPI ImmGetCandidateListCountA( 2249 HIMC hIMC, LPDWORD lpdwListCount) 2250 { 2251 return ImmGetCandidateListCountAW(hIMC, lpdwListCount, TRUE); 2252 } 2253 2254 /*********************************************************************** 2255 * ImmGetCandidateListCountW (IMM32.@) 2256 */ 2257 DWORD WINAPI ImmGetCandidateListCountW( 2258 HIMC hIMC, LPDWORD lpdwListCount) 2259 { 2260 return ImmGetCandidateListCountAW(hIMC, lpdwListCount, FALSE); 2261 } 2262 2263 /*********************************************************************** 2264 * ImmGetCandidateListW (IMM32.@) 2265 */ 2266 DWORD WINAPI ImmGetCandidateListW( 2267 HIMC hIMC, DWORD dwIndex, 2268 LPCANDIDATELIST lpCandList, DWORD dwBufLen) 2269 { 2270 return ImmGetCandidateListAW(hIMC, dwIndex, lpCandList, dwBufLen, FALSE); 2271 } 2272 2273 /*********************************************************************** 2274 * ImmGetCandidateWindow (IMM32.@) 2275 */ 2276 BOOL WINAPI ImmGetCandidateWindow( 2277 HIMC hIMC, DWORD dwIndex, LPCANDIDATEFORM lpCandidate) 2278 { 2279 BOOL ret = FALSE; 2280 LPINPUTCONTEXT pIC; 2281 LPCANDIDATEFORM pCF; 2282 2283 TRACE("(%p, %lu, %p)\n", hIMC, dwIndex, lpCandidate); 2284 2285 pIC = ImmLockIMC(hIMC); 2286 if (pIC == NULL) 2287 return FALSE; 2288 2289 pCF = &pIC->cfCandForm[dwIndex]; 2290 if (pCF->dwIndex != IMM_INVALID_CANDFORM) 2291 { 2292 *lpCandidate = *pCF; 2293 ret = TRUE; 2294 } 2295 2296 ImmUnlockIMC(hIMC); 2297 return ret; 2298 } 2299 2300 static VOID APIENTRY LogFontAnsiToWide(const LOGFONTA *plfA, LPLOGFONTW plfW) 2301 { 2302 size_t cch; 2303 RtlCopyMemory(plfW, plfA, offsetof(LOGFONTA, lfFaceName)); 2304 StringCchLengthA(plfA->lfFaceName, _countof(plfA->lfFaceName), &cch); 2305 cch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, plfA->lfFaceName, (INT)cch, 2306 plfW->lfFaceName, _countof(plfW->lfFaceName)); 2307 if (cch > _countof(plfW->lfFaceName) - 1) 2308 cch = _countof(plfW->lfFaceName) - 1; 2309 plfW->lfFaceName[cch] = 0; 2310 } 2311 2312 static VOID APIENTRY LogFontWideToAnsi(const LOGFONTW *plfW, LPLOGFONTA plfA) 2313 { 2314 size_t cch; 2315 RtlCopyMemory(plfA, plfW, offsetof(LOGFONTW, lfFaceName)); 2316 StringCchLengthW(plfW->lfFaceName, _countof(plfW->lfFaceName), &cch); 2317 cch = WideCharToMultiByte(CP_ACP, 0, plfW->lfFaceName, (INT)cch, 2318 plfA->lfFaceName, _countof(plfA->lfFaceName), NULL, NULL); 2319 if (cch > _countof(plfA->lfFaceName) - 1) 2320 cch = _countof(plfA->lfFaceName) - 1; 2321 plfA->lfFaceName[cch] = 0; 2322 } 2323 2324 /*********************************************************************** 2325 * ImmGetCompositionFontA (IMM32.@) 2326 */ 2327 BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) 2328 { 2329 PCLIENTIMC pClientImc; 2330 BOOL ret = FALSE, bWide; 2331 LPINPUTCONTEXT pIC; 2332 2333 TRACE("(%p, %p)\n", hIMC, lplf); 2334 2335 pClientImc = ImmLockClientImc(hIMC); 2336 if (pClientImc == NULL) 2337 return FALSE; 2338 2339 bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE); 2340 ImmUnlockClientImc(pClientImc); 2341 2342 pIC = ImmLockIMC(hIMC); 2343 if (pIC == NULL) 2344 return FALSE; 2345 2346 if (pIC->fdwInit & INIT_LOGFONT) 2347 { 2348 if (bWide) 2349 LogFontWideToAnsi(&pIC->lfFont.W, lplf); 2350 else 2351 *lplf = pIC->lfFont.A; 2352 2353 ret = TRUE; 2354 } 2355 2356 ImmUnlockIMC(hIMC); 2357 return ret; 2358 } 2359 2360 /*********************************************************************** 2361 * ImmGetCompositionFontW (IMM32.@) 2362 */ 2363 BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) 2364 { 2365 PCLIENTIMC pClientImc; 2366 BOOL bWide; 2367 LPINPUTCONTEXT pIC; 2368 BOOL ret = FALSE; 2369 2370 TRACE("(%p, %p)\n", hIMC, lplf); 2371 2372 pClientImc = ImmLockClientImc(hIMC); 2373 if (pClientImc == NULL) 2374 return FALSE; 2375 2376 bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE); 2377 ImmUnlockClientImc(pClientImc); 2378 2379 pIC = ImmLockIMC(hIMC); 2380 if (pIC == NULL) 2381 return FALSE; 2382 2383 if (pIC->fdwInit & INIT_LOGFONT) 2384 { 2385 if (bWide) 2386 *lplf = pIC->lfFont.W; 2387 else 2388 LogFontAnsiToWide(&pIC->lfFont.A, lplf); 2389 2390 ret = TRUE; 2391 } 2392 2393 ImmUnlockIMC(hIMC); 2394 return ret; 2395 } 2396 2397 2398 /* Helpers for the GetCompositionString functions */ 2399 2400 /* Source encoding is defined by context, source length is always given in respective characters. Destination buffer 2401 length is always in bytes. */ 2402 static INT CopyCompStringIMEtoClient(const InputContextData *data, const void *src, INT src_len, void *dst, 2403 INT dst_len, BOOL unicode) 2404 { 2405 int char_size = unicode ? sizeof(WCHAR) : sizeof(char); 2406 INT ret; 2407 2408 if (is_himc_ime_unicode(data) ^ unicode) 2409 { 2410 if (unicode) 2411 ret = MultiByteToWideChar(CP_ACP, 0, src, src_len, dst, dst_len / sizeof(WCHAR)); 2412 else 2413 ret = WideCharToMultiByte(CP_ACP, 0, src, src_len, dst, dst_len, NULL, NULL); 2414 ret *= char_size; 2415 } 2416 else 2417 { 2418 if (dst_len) 2419 { 2420 ret = min(src_len * char_size, dst_len); 2421 memcpy(dst, src, ret); 2422 } 2423 else 2424 ret = src_len * char_size; 2425 } 2426 2427 return ret; 2428 } 2429 2430 /* Composition string encoding is defined by context, returned attributes correspond to string, converted according to 2431 passed mode. String length is in characters, attributes are in byte arrays. */ 2432 static INT CopyCompAttrIMEtoClient(const InputContextData *data, const BYTE *src, INT src_len, const void *comp_string, 2433 INT str_len, BYTE *dst, INT dst_len, BOOL unicode) 2434 { 2435 union 2436 { 2437 const void *str; 2438 const WCHAR *strW; 2439 const char *strA; 2440 } string; 2441 INT rc; 2442 2443 string.str = comp_string; 2444 2445 if (is_himc_ime_unicode(data) && !unicode) 2446 { 2447 rc = WideCharToMultiByte(CP_ACP, 0, string.strW, str_len, NULL, 0, NULL, NULL); 2448 if (dst_len) 2449 { 2450 int i, j = 0, k = 0; 2451 2452 if (rc < dst_len) 2453 dst_len = rc; 2454 for (i = 0; i < str_len; ++i) 2455 { 2456 int len; 2457 2458 len = WideCharToMultiByte(CP_ACP, 0, string.strW + i, 1, NULL, 0, NULL, NULL); 2459 for (; len > 0; --len) 2460 { 2461 dst[j++] = src[k]; 2462 2463 if (j >= dst_len) 2464 goto end; 2465 } 2466 ++k; 2467 } 2468 end: 2469 rc = j; 2470 } 2471 } 2472 else if (!is_himc_ime_unicode(data) && unicode) 2473 { 2474 rc = MultiByteToWideChar(CP_ACP, 0, string.strA, str_len, NULL, 0); 2475 if (dst_len) 2476 { 2477 int i, j = 0; 2478 2479 if (rc < dst_len) 2480 dst_len = rc; 2481 for (i = 0; i < str_len; ++i) 2482 { 2483 if (IsDBCSLeadByte(string.strA[i])) 2484 continue; 2485 2486 dst[j++] = src[i]; 2487 2488 if (j >= dst_len) 2489 break; 2490 } 2491 rc = j; 2492 } 2493 } 2494 else 2495 { 2496 memcpy(dst, src, min(src_len, dst_len)); 2497 rc = src_len; 2498 } 2499 2500 return rc; 2501 } 2502 2503 static INT CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource, 2504 LPBYTE target, INT tlen, BOOL unicode ) 2505 { 2506 INT rc; 2507 2508 if (is_himc_ime_unicode(data) && !unicode) 2509 { 2510 if (tlen) 2511 { 2512 int i; 2513 2514 if (slen < tlen) 2515 tlen = slen; 2516 tlen /= sizeof (DWORD); 2517 for (i = 0; i < tlen; ++i) 2518 { 2519 ((DWORD *)target)[i] = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, 2520 ((DWORD *)source)[i], 2521 NULL, 0, 2522 NULL, NULL); 2523 } 2524 rc = sizeof (DWORD) * i; 2525 } 2526 else 2527 rc = slen; 2528 } 2529 else if (!is_himc_ime_unicode(data) && unicode) 2530 { 2531 if (tlen) 2532 { 2533 int i; 2534 2535 if (slen < tlen) 2536 tlen = slen; 2537 tlen /= sizeof (DWORD); 2538 for (i = 0; i < tlen; ++i) 2539 { 2540 ((DWORD *)target)[i] = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, 2541 ((DWORD *)source)[i], 2542 NULL, 0); 2543 } 2544 rc = sizeof (DWORD) * i; 2545 } 2546 else 2547 rc = slen; 2548 } 2549 else 2550 { 2551 memcpy( target, source, min(slen,tlen)); 2552 rc = slen; 2553 } 2554 2555 return rc; 2556 } 2557 2558 static INT CopyCompOffsetIMEtoClient(InputContextData *data, DWORD offset, LPBYTE ssource, BOOL unicode) 2559 { 2560 int rc; 2561 2562 if (is_himc_ime_unicode(data) && !unicode) 2563 { 2564 rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL); 2565 } 2566 else if (!is_himc_ime_unicode(data) && unicode) 2567 { 2568 rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0); 2569 } 2570 else 2571 rc = offset; 2572 2573 return rc; 2574 } 2575 2576 static LONG ImmGetCompositionStringT( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, 2577 DWORD dwBufLen, BOOL unicode) 2578 { 2579 LONG rc = 0; 2580 InputContextData *data = get_imc_data(hIMC); 2581 LPCOMPOSITIONSTRING compstr; 2582 LPBYTE compdata; 2583 2584 TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen); 2585 2586 if (!data) 2587 return FALSE; 2588 2589 if (!data->IMC.hCompStr) 2590 return FALSE; 2591 2592 compdata = ImmLockIMCC(data->IMC.hCompStr); 2593 compstr = (LPCOMPOSITIONSTRING)compdata; 2594 2595 switch (dwIndex) 2596 { 2597 case GCS_RESULTSTR: 2598 TRACE("GCS_RESULTSTR\n"); 2599 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode); 2600 break; 2601 case GCS_COMPSTR: 2602 TRACE("GCS_COMPSTR\n"); 2603 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode); 2604 break; 2605 case GCS_COMPATTR: 2606 TRACE("GCS_COMPATTR\n"); 2607 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen, 2608 compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, 2609 lpBuf, dwBufLen, unicode); 2610 break; 2611 case GCS_COMPCLAUSE: 2612 TRACE("GCS_COMPCLAUSE\n"); 2613 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen, 2614 compdata + compstr->dwCompStrOffset, 2615 lpBuf, dwBufLen, unicode); 2616 break; 2617 case GCS_RESULTCLAUSE: 2618 TRACE("GCS_RESULTCLAUSE\n"); 2619 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen, 2620 compdata + compstr->dwResultStrOffset, 2621 lpBuf, dwBufLen, unicode); 2622 break; 2623 case GCS_RESULTREADSTR: 2624 TRACE("GCS_RESULTREADSTR\n"); 2625 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode); 2626 break; 2627 case GCS_RESULTREADCLAUSE: 2628 TRACE("GCS_RESULTREADCLAUSE\n"); 2629 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen, 2630 compdata + compstr->dwResultStrOffset, 2631 lpBuf, dwBufLen, unicode); 2632 break; 2633 case GCS_COMPREADSTR: 2634 TRACE("GCS_COMPREADSTR\n"); 2635 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode); 2636 break; 2637 case GCS_COMPREADATTR: 2638 TRACE("GCS_COMPREADATTR\n"); 2639 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen, 2640 compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, 2641 lpBuf, dwBufLen, unicode); 2642 break; 2643 case GCS_COMPREADCLAUSE: 2644 TRACE("GCS_COMPREADCLAUSE\n"); 2645 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen, 2646 compdata + compstr->dwCompStrOffset, 2647 lpBuf, dwBufLen, unicode); 2648 break; 2649 case GCS_CURSORPOS: 2650 TRACE("GCS_CURSORPOS\n"); 2651 rc = CopyCompOffsetIMEtoClient(data, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode); 2652 break; 2653 case GCS_DELTASTART: 2654 TRACE("GCS_DELTASTART\n"); 2655 rc = CopyCompOffsetIMEtoClient(data, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode); 2656 break; 2657 default: 2658 FIXME("Unhandled index 0x%x\n",dwIndex); 2659 break; 2660 } 2661 2662 ImmUnlockIMCC(data->IMC.hCompStr); 2663 2664 return rc; 2665 } 2666 2667 /*********************************************************************** 2668 * ImmGetCompositionStringA (IMM32.@) 2669 */ 2670 LONG WINAPI ImmGetCompositionStringA( 2671 HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen) 2672 { 2673 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, FALSE); 2674 } 2675 2676 2677 /*********************************************************************** 2678 * ImmGetCompositionStringW (IMM32.@) 2679 */ 2680 LONG WINAPI ImmGetCompositionStringW( 2681 HIMC hIMC, DWORD dwIndex, 2682 LPVOID lpBuf, DWORD dwBufLen) 2683 { 2684 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, TRUE); 2685 } 2686 2687 /*********************************************************************** 2688 * ImmGetCompositionWindow (IMM32.@) 2689 */ 2690 BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm) 2691 { 2692 LPINPUTCONTEXT pIC; 2693 BOOL ret = FALSE; 2694 2695 TRACE("(%p, %p)\n", hIMC, lpCompForm); 2696 2697 pIC = ImmLockIMC(hIMC); 2698 if (!pIC) 2699 return FALSE; 2700 2701 if (pIC->fdwInit & INIT_COMPFORM) 2702 { 2703 *lpCompForm = pIC->cfCompForm; 2704 ret = TRUE; 2705 } 2706 2707 ImmUnlockIMC(hIMC); 2708 return ret; 2709 } 2710 2711 /*********************************************************************** 2712 * ImmGetContext (IMM32.@) 2713 */ 2714 HIMC WINAPI ImmGetContext(HWND hWnd) 2715 { 2716 TRACE("(%p)\n", hWnd); 2717 if (hWnd == NULL) 2718 return NULL; 2719 return Imm32GetContextEx(hWnd, 2); 2720 } 2721 2722 /*********************************************************************** 2723 * ImmGetConversionListA (IMM32.@) 2724 */ 2725 DWORD WINAPI ImmGetConversionListA( 2726 HKL hKL, HIMC hIMC, 2727 LPCSTR pSrc, LPCANDIDATELIST lpDst, 2728 DWORD dwBufLen, UINT uFlag) 2729 { 2730 DWORD ret = 0; 2731 UINT cb; 2732 LPWSTR pszSrcW = NULL; 2733 LPCANDIDATELIST pCL = NULL; 2734 PIMEDPI pImeDpi; 2735 2736 TRACE("(%p, %p, %s, %p, %lu, 0x%lX)\n", hKL, hIMC, debugstr_a(pSrc), 2737 lpDst, dwBufLen, uFlag); 2738 2739 pImeDpi = ImmLockOrLoadImeDpi(hKL); 2740 if (pImeDpi == NULL) 2741 return 0; 2742 2743 if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)) 2744 { 2745 ret = pImeDpi->ImeConversionList(hIMC, pSrc, lpDst, dwBufLen, uFlag); 2746 ImmUnlockImeDpi(pImeDpi); 2747 return ret; 2748 } 2749 2750 if (pSrc) 2751 { 2752 pszSrcW = Imm32WideFromAnsi(pSrc); 2753 if (pszSrcW == NULL) 2754 goto Quit; 2755 } 2756 2757 cb = pImeDpi->ImeConversionList(hIMC, pszSrcW, NULL, 0, uFlag); 2758 if (cb == 0) 2759 goto Quit; 2760 2761 pCL = Imm32HeapAlloc(0, cb); 2762 if (pCL == NULL) 2763 goto Quit; 2764 2765 cb = pImeDpi->ImeConversionList(hIMC, pszSrcW, pCL, cb, uFlag); 2766 if (cb == 0) 2767 goto Quit; 2768 2769 ret = CandidateListWideToAnsi(pCL, lpDst, dwBufLen, CP_ACP); 2770 2771 Quit: 2772 if (pszSrcW) 2773 HeapFree(g_hImm32Heap, 0, pszSrcW); 2774 if (pCL) 2775 HeapFree(g_hImm32Heap, 0, pCL); 2776 ImmUnlockImeDpi(pImeDpi); 2777 return ret; 2778 } 2779 2780 /*********************************************************************** 2781 * ImmGetConversionListW (IMM32.@) 2782 */ 2783 DWORD WINAPI ImmGetConversionListW( 2784 HKL hKL, HIMC hIMC, 2785 LPCWSTR pSrc, LPCANDIDATELIST lpDst, 2786 DWORD dwBufLen, UINT uFlag) 2787 { 2788 DWORD ret = 0; 2789 INT cb; 2790 PIMEDPI pImeDpi; 2791 LPCANDIDATELIST pCL = NULL; 2792 LPSTR pszSrcA = NULL; 2793 2794 TRACE("(%p, %p, %s, %p, %lu, 0x%lX)\n", hKL, hIMC, debugstr_w(pSrc), 2795 lpDst, dwBufLen, uFlag); 2796 2797 pImeDpi = ImmLockOrLoadImeDpi(hKL); 2798 if (!pImeDpi) 2799 return 0; 2800 2801 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) 2802 { 2803 ret = pImeDpi->ImeConversionList(hIMC, pSrc, lpDst, dwBufLen, uFlag); 2804 ImmUnlockImeDpi(pImeDpi); 2805 return ret; 2806 } 2807 2808 if (pSrc) 2809 { 2810 pszSrcA = Imm32AnsiFromWide(pSrc); 2811 if (pszSrcA == NULL) 2812 goto Quit; 2813 } 2814 2815 cb = pImeDpi->ImeConversionList(hIMC, pszSrcA, NULL, 0, uFlag); 2816 if (cb == 0) 2817 goto Quit; 2818 2819 pCL = Imm32HeapAlloc(0, cb); 2820 if (!pCL) 2821 goto Quit; 2822 2823 cb = pImeDpi->ImeConversionList(hIMC, pszSrcA, pCL, cb, uFlag); 2824 if (!cb) 2825 goto Quit; 2826 2827 ret = CandidateListAnsiToWide(pCL, lpDst, dwBufLen, CP_ACP); 2828 2829 Quit: 2830 if (pszSrcA) 2831 HeapFree(g_hImm32Heap, 0, pszSrcA); 2832 if (pCL) 2833 HeapFree(g_hImm32Heap, 0, pCL); 2834 ImmUnlockImeDpi(pImeDpi); 2835 return ret; 2836 } 2837 2838 /*********************************************************************** 2839 * ImmGetConversionStatus (IMM32.@) 2840 */ 2841 BOOL WINAPI ImmGetConversionStatus( 2842 HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence) 2843 { 2844 LPINPUTCONTEXT pIC; 2845 2846 TRACE("(%p %p %p)\n", hIMC, lpfdwConversion, lpfdwSentence); 2847 2848 pIC = ImmLockIMC(hIMC); 2849 if (!pIC) 2850 return FALSE; 2851 2852 if (lpfdwConversion) 2853 *lpfdwConversion = pIC->fdwConversion; 2854 if (lpfdwSentence) 2855 *lpfdwSentence = pIC->fdwSentence; 2856 2857 ImmUnlockIMC(hIMC); 2858 return TRUE; 2859 } 2860 2861 /*********************************************************************** 2862 * ImmGetDefaultIMEWnd (IMM32.@) 2863 */ 2864 HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd) 2865 { 2866 if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_IMM32)) 2867 return NULL; 2868 2869 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken. 2870 if (hWnd == NULL) 2871 return (HWND)NtUserGetThreadState(3); 2872 2873 return (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_DEFAULT_IME); 2874 } 2875 2876 /*********************************************************************** 2877 * CtfImmIsCiceroEnabled (IMM32.@) 2878 */ 2879 BOOL WINAPI CtfImmIsCiceroEnabled(VOID) 2880 { 2881 return (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED)); 2882 } 2883 2884 /*********************************************************************** 2885 * ImmGetDescriptionA (IMM32.@) 2886 */ 2887 UINT WINAPI ImmGetDescriptionA( 2888 HKL hKL, LPSTR lpszDescription, UINT uBufLen) 2889 { 2890 IMEINFOEX info; 2891 size_t cch; 2892 2893 TRACE("(%p,%p,%d)\n", hKL, lpszDescription, uBufLen); 2894 2895 if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL)) 2896 return 0; 2897 2898 StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch); 2899 cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeDescription, (INT)cch, 2900 lpszDescription, uBufLen, NULL, NULL); 2901 if (uBufLen) 2902 lpszDescription[cch] = 0; 2903 return (UINT)cch; 2904 } 2905 2906 /*********************************************************************** 2907 * ImmGetDescriptionW (IMM32.@) 2908 */ 2909 UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen) 2910 { 2911 IMEINFOEX info; 2912 size_t cch; 2913 2914 TRACE("(%p, %p, %d)\n", hKL, lpszDescription, uBufLen); 2915 2916 if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL)) 2917 return 0; 2918 2919 if (uBufLen != 0) 2920 StringCchCopyW(lpszDescription, uBufLen, info.wszImeDescription); 2921 2922 StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch); 2923 return (UINT)cch; 2924 } 2925 2926 static DWORD APIENTRY 2927 ImmGetGuideLineAW(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen, BOOL bAnsi) 2928 { 2929 PCLIENTIMC pClientImc; 2930 LPINPUTCONTEXT pIC; 2931 LPGUIDELINE pGuideLine; 2932 DWORD cb, ret = 0; 2933 LPVOID pvStr, pvPrivate; 2934 BOOL bUsedDefault; 2935 2936 pClientImc = ImmLockClientImc(hIMC); 2937 if (!pClientImc) 2938 return 0; 2939 2940 pIC = ImmLockIMC(hIMC); 2941 if (!pIC) 2942 { 2943 ImmUnlockClientImc(pClientImc); 2944 return 0; 2945 } 2946 2947 pGuideLine = ImmLockIMCC(pIC->hGuideLine); 2948 if (!pGuideLine) 2949 { 2950 ImmUnlockIMC(hIMC); 2951 ImmUnlockClientImc(pClientImc); 2952 return 0; 2953 } 2954 2955 if (dwIndex == GGL_LEVEL) 2956 { 2957 ret = pGuideLine->dwLevel; 2958 goto Quit; 2959 } 2960 2961 if (dwIndex == GGL_INDEX) 2962 { 2963 ret = pGuideLine->dwIndex; 2964 goto Quit; 2965 } 2966 2967 if (dwIndex == GGL_STRING) 2968 { 2969 pvStr = (LPBYTE)pGuideLine + pGuideLine->dwStrOffset; 2970 2971 /* get size */ 2972 if (bAnsi) 2973 { 2974 if (pClientImc->dwFlags & CLIENTIMC_WIDE) 2975 { 2976 cb = WideCharToMultiByte(CP_ACP, 0, pvStr, pGuideLine->dwStrLen, 2977 NULL, 0, NULL, &bUsedDefault); 2978 } 2979 else 2980 { 2981 cb = pGuideLine->dwStrLen * sizeof(CHAR); 2982 } 2983 } 2984 else 2985 { 2986 if (pClientImc->dwFlags & CLIENTIMC_WIDE) 2987 { 2988 cb = pGuideLine->dwStrLen * sizeof(WCHAR); 2989 } 2990 else 2991 { 2992 cb = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pvStr, pGuideLine->dwStrLen, 2993 NULL, 0) * sizeof(WCHAR); 2994 } 2995 } 2996 2997 if (dwBufLen == 0 || cb == 0 || lpBuf == NULL || dwBufLen < cb) 2998 { 2999 ret = cb; 3000 goto Quit; 3001 } 3002 3003 /* store to buffer */ 3004 if (bAnsi) 3005 { 3006 if (pClientImc->dwFlags & CLIENTIMC_WIDE) 3007 { 3008 ret = WideCharToMultiByte(CP_ACP, 0, pvStr, pGuideLine->dwStrLen, 3009 lpBuf, dwBufLen, NULL, &bUsedDefault); 3010 goto Quit; 3011 } 3012 } 3013 else 3014 { 3015 if (!(pClientImc->dwFlags & CLIENTIMC_WIDE)) 3016 { 3017 ret = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pvStr, pGuideLine->dwStrLen, 3018 lpBuf, dwBufLen) * sizeof(WCHAR); 3019 goto Quit; 3020 } 3021 } 3022 3023 RtlCopyMemory(lpBuf, pvStr, cb); 3024 ret = cb; 3025 goto Quit; 3026 } 3027 3028 if (dwIndex == GGL_PRIVATE) 3029 { 3030 pvPrivate = (LPBYTE)pGuideLine + pGuideLine->dwPrivateOffset; 3031 3032 /* get size */ 3033 if (bAnsi) 3034 { 3035 if ((pClientImc->dwFlags & CLIENTIMC_WIDE) && 3036 pGuideLine->dwIndex == GL_ID_REVERSECONVERSION) 3037 { 3038 cb = CandidateListWideToAnsi(pvPrivate, NULL, 0, CP_ACP); 3039 } 3040 else 3041 { 3042 cb = pGuideLine->dwPrivateSize; 3043 } 3044 } 3045 else 3046 { 3047 if (!(pClientImc->dwFlags & CLIENTIMC_WIDE) && 3048 pGuideLine->dwIndex == GL_ID_REVERSECONVERSION) 3049 { 3050 cb = CandidateListAnsiToWide(pvPrivate, NULL, 0, CP_ACP); 3051 } 3052 else 3053 { 3054 cb = pGuideLine->dwPrivateSize; 3055 } 3056 } 3057 3058 if (dwBufLen == 0 || cb == 0 || lpBuf == NULL || dwBufLen < cb) 3059 { 3060 ret = cb; 3061 goto Quit; 3062 } 3063 3064 /* store to buffer */ 3065 if (bAnsi) 3066 { 3067 if ((pClientImc->dwFlags & CLIENTIMC_WIDE) && 3068 pGuideLine->dwIndex == GL_ID_REVERSECONVERSION) 3069 { 3070 ret = CandidateListWideToAnsi(pvPrivate, lpBuf, cb, CP_ACP); 3071 goto Quit; 3072 } 3073 } 3074 else 3075 { 3076 if (!(pClientImc->dwFlags & CLIENTIMC_WIDE) && 3077 pGuideLine->dwIndex == GL_ID_REVERSECONVERSION) 3078 { 3079 ret = CandidateListAnsiToWide(pvPrivate, lpBuf, cb, CP_ACP); 3080 goto Quit; 3081 } 3082 } 3083 3084 RtlCopyMemory(lpBuf, pvPrivate, cb); 3085 ret = cb; 3086 goto Quit; 3087 } 3088 3089 Quit: 3090 ImmUnlockIMCC(pIC->hGuideLine); 3091 ImmUnlockIMC(hIMC); 3092 ImmUnlockClientImc(pClientImc); 3093 return ret; 3094 } 3095 3096 /*********************************************************************** 3097 * ImmGetGuideLineA (IMM32.@) 3098 */ 3099 DWORD WINAPI ImmGetGuideLineA( 3100 HIMC hIMC, DWORD dwIndex, LPSTR lpBuf, DWORD dwBufLen) 3101 { 3102 TRACE("(%p, %lu, %p, %lu)\n", hIMC, dwIndex, lpBuf, dwBufLen); 3103 return ImmGetGuideLineAW(hIMC, dwIndex, lpBuf, dwBufLen, TRUE); 3104 } 3105 3106 /*********************************************************************** 3107 * ImmGetGuideLineW (IMM32.@) 3108 */ 3109 DWORD WINAPI ImmGetGuideLineW(HIMC hIMC, DWORD dwIndex, LPWSTR lpBuf, DWORD dwBufLen) 3110 { 3111 TRACE("(%p, %lu, %p, %lu)\n", hIMC, dwIndex, lpBuf, dwBufLen); 3112 return ImmGetGuideLineAW(hIMC, dwIndex, lpBuf, dwBufLen, FALSE); 3113 } 3114 3115 /*********************************************************************** 3116 * ImmGetIMEFileNameA (IMM32.@) 3117 */ 3118 UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen) 3119 { 3120 BOOL bDefUsed; 3121 IMEINFOEX info; 3122 size_t cch; 3123 3124 TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen); 3125 3126 if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL)) 3127 { 3128 if (uBufLen > 0) 3129 lpszFileName[0] = 0; 3130 return 0; 3131 } 3132 3133 StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch); 3134 3135 cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeFile, (INT)cch, 3136 lpszFileName, uBufLen, NULL, &bDefUsed); 3137 if (uBufLen == 0) 3138 return (UINT)cch; 3139 3140 if (cch > uBufLen - 1) 3141 cch = uBufLen - 1; 3142 3143 lpszFileName[cch] = 0; 3144 return (UINT)cch; 3145 } 3146 3147 /*********************************************************************** 3148 * ImmGetIMEFileNameW (IMM32.@) 3149 */ 3150 UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen) 3151 { 3152 IMEINFOEX info; 3153 size_t cch; 3154 3155 TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen); 3156 3157 if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL)) 3158 { 3159 if (uBufLen > 0) 3160 lpszFileName[0] = 0; 3161 return 0; 3162 } 3163 3164 StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch); 3165 if (uBufLen == 0) 3166 return (UINT)cch; 3167 3168 StringCchCopyNW(lpszFileName, uBufLen, info.wszImeFile, cch); 3169 3170 if (cch > uBufLen - 1) 3171 cch = uBufLen - 1; 3172 3173 lpszFileName[cch] = 0; 3174 return (UINT)cch; 3175 } 3176 3177 /*********************************************************************** 3178 * ImmGetOpenStatus (IMM32.@) 3179 */ 3180 BOOL WINAPI ImmGetOpenStatus(HIMC hIMC) 3181 { 3182 BOOL ret; 3183 LPINPUTCONTEXT pIC; 3184 3185 TRACE("(%p)\n", hIMC); 3186 3187 if (!hIMC) 3188 return FALSE; 3189 3190 pIC = ImmLockIMC(hIMC); 3191 if (!pIC) 3192 return FALSE; 3193 3194 ret = pIC->fOpen; 3195 3196 ImmUnlockIMC(hIMC); 3197 return ret; 3198 } 3199 3200 /*********************************************************************** 3201 * ImmGetProperty (IMM32.@) 3202 */ 3203 DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex) 3204 { 3205 IMEINFOEX ImeInfoEx; 3206 LPIMEINFO pImeInfo; 3207 DWORD dwValue; 3208 PIMEDPI pImeDpi = NULL; 3209 3210 TRACE("(%p, %lu)\n", hKL, fdwIndex); 3211 3212 if (!ImmGetImeInfoEx(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL)) 3213 return FALSE; 3214 3215 if (fdwIndex == IGP_GETIMEVERSION) 3216 return ImeInfoEx.dwImeWinVersion; 3217 3218 if (ImeInfoEx.fLoadFlag != 2) 3219 { 3220 pImeDpi = ImmLockOrLoadImeDpi(hKL); 3221 if (pImeDpi == NULL) 3222 return FALSE; 3223 3224 pImeInfo = &pImeDpi->ImeInfo; 3225 } 3226 else 3227 { 3228 pImeInfo = &ImeInfoEx.ImeInfo; 3229 } 3230 3231 switch (fdwIndex) 3232 { 3233 case IGP_PROPERTY: dwValue = pImeInfo->fdwProperty; break; 3234 case IGP_CONVERSION: dwValue = pImeInfo->fdwConversionCaps; break; 3235 case IGP_SENTENCE: dwValue = pImeInfo->fdwSentenceCaps; break; 3236 case IGP_UI: dwValue = pImeInfo->fdwUICaps; break; 3237 case IGP_SETCOMPSTR: dwValue = pImeInfo->fdwSCSCaps; break; 3238 case IGP_SELECT: dwValue = pImeInfo->fdwSelectCaps; break; 3239 default: dwValue = 0; break; 3240 } 3241 3242 if (pImeDpi) 3243 ImmUnlockImeDpi(pImeDpi); 3244 return dwValue; 3245 } 3246 3247 /*********************************************************************** 3248 * ImmGetRegisterWordStyleA (IMM32.@) 3249 */ 3250 UINT WINAPI ImmGetRegisterWordStyleA( 3251 HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf) 3252 { 3253 UINT iItem, ret = 0; 3254 PIMEDPI pImeDpi; 3255 LPSTYLEBUFA pDestA; 3256 LPSTYLEBUFW pSrcW, pNewStylesW = NULL; 3257 size_t cchW; 3258 INT cchA; 3259 3260 TRACE("(%p, %u, %p)\n", hKL, nItem, lpStyleBuf); 3261 3262 pImeDpi = ImmLockOrLoadImeDpi(hKL); 3263 if (!pImeDpi) 3264 return 0; 3265 3266 if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)) 3267 { 3268 ret = pImeDpi->ImeGetRegisterWordStyle(nItem, lpStyleBuf); 3269 goto Quit; 3270 } 3271 3272 if (nItem > 0) 3273 { 3274 pNewStylesW = Imm32HeapAlloc(0, nItem * sizeof(STYLEBUFW)); 3275 if (!pNewStylesW) 3276 goto Quit; 3277 } 3278 3279 ret = pImeDpi->ImeGetRegisterWordStyle(nItem, pNewStylesW); 3280 3281 if (nItem > 0) 3282 { 3283 /* lpStyleBuf <-- pNewStylesW */ 3284 for (iItem = 0; iItem < ret; ++iItem) 3285 { 3286 pSrcW = &pNewStylesW[iItem]; 3287 pDestA = &lpStyleBuf[iItem]; 3288 pDestA->dwStyle = pSrcW->dwStyle; 3289 StringCchLengthW(pSrcW->szDescription, _countof(pSrcW->szDescription), &cchW); 3290 cchA = WideCharToMultiByte(CP_ACP, MB_PRECOMPOSED, 3291 pSrcW->szDescription, (INT)cchW, 3292 pDestA->szDescription, _countof(pDestA->szDescription), 3293 NULL, NULL); 3294 if (cchA > _countof(pDestA->szDescription) - 1) 3295 cchA = _countof(pDestA->szDescription) - 1; 3296 pDestA->szDescription[cchA] = 0; 3297 } 3298 } 3299 3300 Quit: 3301 if (pNewStylesW) 3302 HeapFree(g_hImm32Heap, 0, pNewStylesW); 3303 ImmUnlockImeDpi(pImeDpi); 3304 return ret; 3305 } 3306 3307 /*********************************************************************** 3308 * ImmGetRegisterWordStyleW (IMM32.@) 3309 */ 3310 UINT WINAPI ImmGetRegisterWordStyleW( 3311 HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf) 3312 { 3313 UINT iItem, ret = 0; 3314 PIMEDPI pImeDpi; 3315 LPSTYLEBUFA pSrcA, pNewStylesA = NULL; 3316 LPSTYLEBUFW pDestW; 3317 size_t cchA; 3318 INT cchW; 3319 3320 TRACE("(%p, %u, %p)\n", hKL, nItem, lpStyleBuf); 3321 3322 pImeDpi = ImmLockOrLoadImeDpi(hKL); 3323 if (!pImeDpi) 3324 return 0; 3325 3326 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) 3327 { 3328 ret = pImeDpi->ImeGetRegisterWordStyle(nItem, lpStyleBuf); 3329 goto Quit; 3330 } 3331 3332 if (nItem > 0) 3333 { 3334 pNewStylesA = Imm32HeapAlloc(0, nItem * sizeof(STYLEBUFA)); 3335 if (!pNewStylesA) 3336 goto Quit; 3337 } 3338 3339 ret = pImeDpi->ImeGetRegisterWordStyle(nItem, pNewStylesA); 3340 3341 if (nItem > 0) 3342 { 3343 /* lpStyleBuf <-- pNewStylesA */ 3344 for (iItem = 0; iItem < ret; ++iItem) 3345 { 3346 pSrcA = &pNewStylesA[iItem]; 3347 pDestW = &lpStyleBuf[iItem]; 3348 pDestW->dwStyle = pSrcA->dwStyle; 3349 StringCchLengthA(pSrcA->szDescription, _countof(pSrcA->szDescription), &cchA); 3350 cchW = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, 3351 pSrcA->szDescription, (INT)cchA, 3352 pDestW->szDescription, _countof(pDestW->szDescription)); 3353 if (cchW > _countof(pDestW->szDescription) - 1) 3354 cchW = _countof(pDestW->szDescription) - 1; 3355 pDestW->szDescription[cchW] = 0; 3356 } 3357 } 3358 3359 Quit: 3360 if (pNewStylesA) 3361 HeapFree(g_hImm32Heap, 0, pNewStylesA); 3362 ImmUnlockImeDpi(pImeDpi); 3363 return ret; 3364 } 3365 3366 /*********************************************************************** 3367 * ImmGetStatusWindowPos (IMM32.@) 3368 */ 3369 BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) 3370 { 3371 LPINPUTCONTEXT pIC; 3372 BOOL ret; 3373 3374 TRACE("(%p, %p)\n", hIMC, lpptPos); 3375 3376 pIC = ImmLockIMC(hIMC); 3377 if (pIC == NULL) 3378 return FALSE; 3379 3380 ret = !!(pIC->fdwInit & INIT_STATUSWNDPOS); 3381 if (ret) 3382 *lpptPos = pIC->ptStatusWndPos; 3383 3384 ImmUnlockIMC(hIMC); 3385 return ret; 3386 } 3387 3388 /*********************************************************************** 3389 * ImmGetVirtualKey (IMM32.@) 3390 */ 3391 UINT WINAPI ImmGetVirtualKey(HWND hWnd) 3392 { 3393 HIMC hIMC; 3394 LPINPUTCONTEXTDX pIC; 3395 UINT ret = VK_PROCESSKEY; 3396 3397 TRACE("(%p)\n", hWnd); 3398 3399 hIMC = ImmGetContext(hWnd); 3400 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 3401 if (!pIC) 3402 return ret; 3403 3404 if (pIC->bNeedsTrans) 3405 ret = pIC->nVKey; 3406 3407 ImmUnlockIMC(hIMC); 3408 return ret; 3409 } 3410 3411 /*********************************************************************** 3412 * ImmInstallIMEA (IMM32.@) 3413 */ 3414 HKL WINAPI ImmInstallIMEA( 3415 LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText) 3416 { 3417 HKL hKL = NULL; 3418 LPWSTR pszFileNameW = NULL, pszLayoutTextW = NULL; 3419 3420 TRACE("(%s, %s)\n", debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText)); 3421 3422 pszFileNameW = Imm32WideFromAnsi(lpszIMEFileName); 3423 if (pszFileNameW == NULL) 3424 goto Quit; 3425 3426 pszLayoutTextW = Imm32WideFromAnsi(lpszLayoutText); 3427 if (pszLayoutTextW == NULL) 3428 goto Quit; 3429 3430 hKL = ImmInstallIMEW(pszFileNameW, pszLayoutTextW); 3431 3432 Quit: 3433 if (pszFileNameW) 3434 HeapFree(g_hImm32Heap, 0, pszFileNameW); 3435 if (pszLayoutTextW) 3436 HeapFree(g_hImm32Heap, 0, pszLayoutTextW); 3437 return hKL; 3438 } 3439 3440 /*********************************************************************** 3441 * ImmInstallIMEW (IMM32.@) 3442 */ 3443 HKL WINAPI ImmInstallIMEW( 3444 LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText) 3445 { 3446 INT lcid = GetUserDefaultLCID(); 3447 INT count; 3448 HKL hkl; 3449 DWORD rc; 3450 HKEY hkey; 3451 WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8]; 3452 3453 TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName), 3454 debugstr_w(lpszLayoutText)); 3455 3456 /* Start with 2. e001 will be blank and so default to the wine internal IME */ 3457 count = 2; 3458 3459 while (count < 0xfff) 3460 { 3461 DWORD disposition = 0; 3462 3463 hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count ); 3464 wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl); 3465 3466 rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition); 3467 if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY) 3468 break; 3469 else if (rc == ERROR_SUCCESS) 3470 RegCloseKey(hkey); 3471 3472 count++; 3473 } 3474 3475 if (count == 0xfff) 3476 { 3477 WARN("Unable to find slot to install IME\n"); 3478 return 0; 3479 } 3480 3481 if (rc == ERROR_SUCCESS) 3482 { 3483 rc = RegSetValueExW(hkey, szImeFileW, 0, REG_SZ, (const BYTE*)lpszIMEFileName, 3484 (lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR)); 3485 if (rc == ERROR_SUCCESS) 3486 rc = RegSetValueExW(hkey, szLayoutTextW, 0, REG_SZ, (const BYTE*)lpszLayoutText, 3487 (lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR)); 3488 RegCloseKey(hkey); 3489 return hkl; 3490 } 3491 else 3492 { 3493 WARN("Unable to set IME registry values\n"); 3494 return 0; 3495 } 3496 } 3497 3498 /*********************************************************************** 3499 * ImmIsIME (IMM32.@) 3500 */ 3501 BOOL WINAPI ImmIsIME(HKL hKL) 3502 { 3503 IMEINFOEX info; 3504 TRACE("(%p)\n", hKL); 3505 return !!ImmGetImeInfoEx(&info, ImeInfoExImeWindow, &hKL); 3506 } 3507 3508 static BOOL APIENTRY 3509 ImmIsUIMessageAW(HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam, BOOL bAnsi) 3510 { 3511 switch (msg) 3512 { 3513 case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION: 3514 case WM_IME_COMPOSITION: case WM_IME_SETCONTEXT: case WM_IME_NOTIFY: 3515 case WM_IME_COMPOSITIONFULL: case WM_IME_SELECT: case WM_IME_SYSTEM: 3516 break; 3517 default: 3518 return FALSE; 3519 } 3520 3521 if (!hWndIME) 3522 return TRUE; 3523 3524 if (bAnsi) 3525 SendMessageA(hWndIME, msg, wParam, lParam); 3526 else 3527 SendMessageW(hWndIME, msg, wParam, lParam); 3528 3529 return TRUE; 3530 } 3531 3532 /*********************************************************************** 3533 * ImmIsUIMessageA (IMM32.@) 3534 */ 3535 BOOL WINAPI ImmIsUIMessageA( 3536 HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam) 3537 { 3538 TRACE("(%p, 0x%X, %p, %p)\n", hWndIME, msg, wParam, lParam); 3539 return ImmIsUIMessageAW(hWndIME, msg, wParam, lParam, TRUE); 3540 } 3541 3542 /*********************************************************************** 3543 * ImmIsUIMessageW (IMM32.@) 3544 */ 3545 BOOL WINAPI ImmIsUIMessageW( 3546 HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam) 3547 { 3548 TRACE("(%p, 0x%X, %p, %p)\n", hWndIME, msg, wParam, lParam); 3549 return ImmIsUIMessageAW(hWndIME, msg, wParam, lParam, FALSE); 3550 } 3551 3552 /*********************************************************************** 3553 * ImmNotifyIME (IMM32.@) 3554 */ 3555 BOOL WINAPI ImmNotifyIME( 3556 HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) 3557 { 3558 HKL hKL; 3559 PIMEDPI pImeDpi; 3560 BOOL ret; 3561 3562 TRACE("(%p, %lu, %lu, %lu)\n", hIMC, dwAction, dwIndex, dwValue); 3563 3564 if (hIMC && Imm32IsCrossThreadAccess(hIMC)) 3565 return FALSE; 3566 3567 hKL = GetKeyboardLayout(0); 3568 pImeDpi = ImmLockImeDpi(hKL); 3569 if (pImeDpi == NULL) 3570 return FALSE; 3571 3572 ret = pImeDpi->NotifyIME(hIMC, dwAction, dwIndex, dwValue); 3573 ImmUnlockImeDpi(pImeDpi); 3574 return ret; 3575 } 3576 3577 /*********************************************************************** 3578 * ImmRegisterWordA (IMM32.@) 3579 */ 3580 BOOL WINAPI ImmRegisterWordA( 3581 HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister) 3582 { 3583 BOOL ret = FALSE; 3584 PIMEDPI pImeDpi; 3585 LPWSTR pszReadingW = NULL, pszRegisterW = NULL; 3586 3587 TRACE("(%p, %s, 0x%lX, %s)\n", hKL, debugstr_a(lpszReading), dwStyle, 3588 debugstr_a(lpszRegister)); 3589 3590 pImeDpi = ImmLockOrLoadImeDpi(hKL); 3591 if (!pImeDpi) 3592 return FALSE; 3593 3594 if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)) 3595 { 3596 ret = pImeDpi->ImeRegisterWord(lpszReading, dwStyle, lpszRegister); 3597 ImmUnlockImeDpi(pImeDpi); 3598 return ret; 3599 } 3600 3601 if (lpszReading) 3602 { 3603 pszReadingW = Imm32WideFromAnsi(lpszReading); 3604 if (pszReadingW == NULL) 3605 goto Quit; 3606 } 3607 3608 if (lpszRegister) 3609 { 3610 pszRegisterW = Imm32WideFromAnsi(lpszRegister); 3611 if (pszRegisterW == NULL) 3612 goto Quit; 3613 } 3614 3615 ret = pImeDpi->ImeRegisterWord(pszReadingW, dwStyle, pszRegisterW); 3616 3617 Quit: 3618 if (pszReadingW) 3619 HeapFree(g_hImm32Heap, 0, pszReadingW); 3620 if (pszRegisterW) 3621 HeapFree(g_hImm32Heap, 0, pszRegisterW); 3622 ImmUnlockImeDpi(pImeDpi); 3623 return ret; 3624 } 3625 3626 /*********************************************************************** 3627 * ImmRegisterWordW (IMM32.@) 3628 */ 3629 BOOL WINAPI ImmRegisterWordW( 3630 HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister) 3631 { 3632 BOOL ret = FALSE; 3633 PIMEDPI pImeDpi; 3634 LPSTR pszReadingA = NULL, pszRegisterA = NULL; 3635 3636 TRACE("(%p, %s, 0x%lX, %s)\n", hKL, debugstr_w(lpszReading), dwStyle, 3637 debugstr_w(lpszRegister)); 3638 3639 pImeDpi = ImmLockOrLoadImeDpi(hKL); 3640 if (!pImeDpi) 3641 return FALSE; 3642 3643 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) 3644 { 3645 ret = pImeDpi->ImeRegisterWord(lpszReading, dwStyle, lpszRegister); 3646 ImmUnlockImeDpi(pImeDpi); 3647 return ret; 3648 } 3649 3650 if (lpszReading) 3651 { 3652 pszReadingA = Imm32AnsiFromWide(lpszReading); 3653 if (!pszReadingA) 3654 goto Quit; 3655 } 3656 3657 if (lpszRegister) 3658 { 3659 pszRegisterA = Imm32AnsiFromWide(lpszRegister); 3660 if (!pszRegisterA) 3661 goto Quit; 3662 } 3663 3664 ret = pImeDpi->ImeRegisterWord(pszReadingA, dwStyle, pszRegisterA); 3665 3666 Quit: 3667 if (pszReadingA) 3668 HeapFree(g_hImm32Heap, 0, pszReadingA); 3669 if (pszRegisterA) 3670 HeapFree(g_hImm32Heap, 0, pszRegisterA); 3671 ImmUnlockImeDpi(pImeDpi); 3672 return ret; 3673 } 3674 3675 /*********************************************************************** 3676 * ImmReleaseContext (IMM32.@) 3677 */ 3678 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC) 3679 { 3680 TRACE("(%p, %p)\n", hWnd, hIMC); 3681 UNREFERENCED_PARAMETER(hWnd); 3682 UNREFERENCED_PARAMETER(hIMC); 3683 return TRUE; // Do nothing. This is correct. 3684 } 3685 3686 /*********************************************************************** 3687 * ImmRequestMessageA(IMM32.@) 3688 */ 3689 LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam) 3690 { 3691 InputContextData *data = get_imc_data(hIMC); 3692 3693 TRACE("%p %ld %ld\n", hIMC, wParam, wParam); 3694 3695 if (data) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam); 3696 3697 SetLastError(ERROR_INVALID_HANDLE); 3698 return 0; 3699 } 3700 3701 /*********************************************************************** 3702 * ImmRequestMessageW(IMM32.@) 3703 */ 3704 LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam) 3705 { 3706 InputContextData *data = get_imc_data(hIMC); 3707 3708 TRACE("%p %ld %ld\n", hIMC, wParam, wParam); 3709 3710 if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam); 3711 3712 SetLastError(ERROR_INVALID_HANDLE); 3713 return 0; 3714 } 3715 3716 /*********************************************************************** 3717 * ImmSetCandidateWindow (IMM32.@) 3718 */ 3719 BOOL WINAPI ImmSetCandidateWindow( 3720 HIMC hIMC, LPCANDIDATEFORM lpCandidate) 3721 { 3722 HWND hWnd; 3723 LPINPUTCONTEXT pIC; 3724 3725 TRACE("(%p, %p)\n", hIMC, lpCandidate); 3726 3727 if (lpCandidate->dwIndex >= MAX_CANDIDATEFORM) 3728 return FALSE; 3729 3730 if (Imm32IsCrossThreadAccess(hIMC)) 3731 return FALSE; 3732 3733 pIC = ImmLockIMC(hIMC); 3734 if (pIC == NULL) 3735 return FALSE; 3736 3737 hWnd = pIC->hWnd; 3738 pIC->cfCandForm[lpCandidate->dwIndex] = *lpCandidate; 3739 3740 ImmUnlockIMC(hIMC); 3741 3742 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS, 3743 IMN_SETCANDIDATEPOS, (1 << (BYTE)lpCandidate->dwIndex)); 3744 return TRUE; 3745 } 3746 3747 static VOID APIENTRY WideToAnsiLogFont(const LOGFONTW *plfW, LPLOGFONTA plfA) 3748 { 3749 BOOL bUsedDef; 3750 size_t cchW, cchA = _countof(plfA->lfFaceName); 3751 RtlCopyMemory(plfA, plfW, offsetof(LOGFONTA, lfFaceName)); 3752 StringCchLengthW(plfW->lfFaceName, _countof(plfW->lfFaceName), &cchW); 3753 cchA = WideCharToMultiByte(CP_ACP, 0, plfW->lfFaceName, (INT)cchW, 3754 plfA->lfFaceName, (INT)cchA, NULL, &bUsedDef); 3755 if (cchA > _countof(plfA->lfFaceName) - 1) 3756 cchA = _countof(plfA->lfFaceName) - 1; 3757 plfA->lfFaceName[cchA] = 0; 3758 } 3759 3760 static VOID APIENTRY AnsiToWideLogFont(const LOGFONTA *plfA, LPLOGFONTW plfW) 3761 { 3762 size_t cchA, cchW = _countof(plfW->lfFaceName); 3763 RtlCopyMemory(plfW, plfA, offsetof(LOGFONTW, lfFaceName)); 3764 StringCchLengthA(plfA->lfFaceName, _countof(plfA->lfFaceName), &cchA); 3765 cchW = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, plfA->lfFaceName, (INT)cchA, 3766 plfW->lfFaceName, (INT)cchW); 3767 if (cchW > _countof(plfW->lfFaceName) - 1) 3768 cchW = _countof(plfW->lfFaceName) - 1; 3769 plfW->lfFaceName[cchW] = 0; 3770 } 3771 3772 /*********************************************************************** 3773 * ImmSetCompositionFontA (IMM32.@) 3774 */ 3775 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) 3776 { 3777 LOGFONTW lfW; 3778 PCLIENTIMC pClientImc; 3779 BOOL bWide; 3780 LPINPUTCONTEXTDX pIC; 3781 LCID lcid; 3782 HWND hWnd; 3783 PTEB pTeb; 3784 3785 TRACE("(%p, %p)\n", hIMC, lplf); 3786 3787 if (Imm32IsCrossThreadAccess(hIMC)) 3788 return FALSE; 3789 3790 pClientImc = ImmLockClientImc(hIMC); 3791 if (pClientImc == NULL) 3792 return FALSE; 3793 3794 bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE); 3795 ImmUnlockClientImc(pClientImc); 3796 3797 if (bWide) 3798 { 3799 AnsiToWideLogFont(lplf, &lfW); 3800 return ImmSetCompositionFontW(hIMC, &lfW); 3801 } 3802 3803 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 3804 if (pIC == NULL) 3805 return FALSE; 3806 3807 pTeb = NtCurrentTeb(); 3808 if (pTeb->Win32ClientInfo[2] < 0x400) 3809 { 3810 lcid = GetSystemDefaultLCID(); 3811 if (PRIMARYLANGID(lcid) == LANG_JAPANESE && !(pIC->dwUIFlags & 2) && 3812 pIC->cfCompForm.dwStyle != CFS_DEFAULT) 3813 { 3814 PostMessageA(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0); 3815 } 3816 } 3817 3818 pIC->lfFont.A = *lplf; 3819 pIC->fdwInit |= INIT_LOGFONT; 3820 hWnd = pIC->hWnd; 3821 3822 ImmUnlockIMC(hIMC); 3823 3824 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT, 3825 IMN_SETCOMPOSITIONFONT, 0); 3826 return TRUE; 3827 } 3828 3829 /*********************************************************************** 3830 * ImmSetCompositionFontW (IMM32.@) 3831 */ 3832 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) 3833 { 3834 LOGFONTA lfA; 3835 PCLIENTIMC pClientImc; 3836 BOOL bWide; 3837 HWND hWnd; 3838 LPINPUTCONTEXTDX pIC; 3839 PTEB pTeb; 3840 LCID lcid; 3841 3842 TRACE("(%p, %p)\n", hIMC, lplf); 3843 3844 if (Imm32IsCrossThreadAccess(hIMC)) 3845 return FALSE; 3846 3847 pClientImc = ImmLockClientImc(hIMC); 3848 if (pClientImc == NULL) 3849 return FALSE; 3850 3851 bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE); 3852 ImmUnlockClientImc(pClientImc); 3853 3854 if (!bWide) 3855 { 3856 WideToAnsiLogFont(lplf, &lfA); 3857 return ImmSetCompositionFontA(hIMC, &lfA); 3858 } 3859 3860 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 3861 if (pIC == NULL) 3862 return FALSE; 3863 3864 pTeb = NtCurrentTeb(); 3865 if (pTeb->Win32ClientInfo[2] < 0x400) 3866 { 3867 lcid = GetSystemDefaultLCID(); 3868 if (PRIMARYLANGID(lcid) == LANG_JAPANESE && 3869 !(pIC->dwUIFlags & 2) && 3870 pIC->cfCompForm.dwStyle != CFS_DEFAULT) 3871 { 3872 PostMessageW(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0); 3873 } 3874 } 3875 3876 pIC->lfFont.W = *lplf; 3877 pIC->fdwInit |= INIT_LOGFONT; 3878 hWnd = pIC->hWnd; 3879 3880 ImmUnlockIMC(hIMC); 3881 3882 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT, 3883 IMN_SETCOMPOSITIONFONT, 0); 3884 return TRUE; 3885 } 3886 3887 /*********************************************************************** 3888 * ImmSetCompositionStringA (IMM32.@) 3889 */ 3890 BOOL WINAPI ImmSetCompositionStringA( 3891 HIMC hIMC, DWORD dwIndex, 3892 LPCVOID lpComp, DWORD dwCompLen, 3893 LPCVOID lpRead, DWORD dwReadLen) 3894 { 3895 DWORD comp_len; 3896 DWORD read_len; 3897 WCHAR *CompBuffer = NULL; 3898 WCHAR *ReadBuffer = NULL; 3899 BOOL rc; 3900 InputContextData *data = get_imc_data(hIMC); 3901 3902 TRACE("(%p, %d, %p, %d, %p, %d):\n", 3903 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); 3904 3905 if (!data) 3906 return FALSE; 3907 3908 if (!(dwIndex == SCS_SETSTR || 3909 dwIndex == SCS_CHANGEATTR || 3910 dwIndex == SCS_CHANGECLAUSE || 3911 dwIndex == SCS_SETRECONVERTSTRING || 3912 dwIndex == SCS_QUERYRECONVERTSTRING)) 3913 return FALSE; 3914 3915 if (!is_himc_ime_unicode(data)) 3916 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp, 3917 dwCompLen, lpRead, dwReadLen); 3918 3919 comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0); 3920 if (comp_len) 3921 { 3922 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR)); 3923 MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len); 3924 } 3925 3926 read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0); 3927 if (read_len) 3928 { 3929 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR)); 3930 MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len); 3931 } 3932 3933 rc = ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len, 3934 ReadBuffer, read_len); 3935 3936 HeapFree(GetProcessHeap(), 0, CompBuffer); 3937 HeapFree(GetProcessHeap(), 0, ReadBuffer); 3938 3939 return rc; 3940 } 3941 3942 /*********************************************************************** 3943 * ImmSetCompositionStringW (IMM32.@) 3944 */ 3945 BOOL WINAPI ImmSetCompositionStringW( 3946 HIMC hIMC, DWORD dwIndex, 3947 LPCVOID lpComp, DWORD dwCompLen, 3948 LPCVOID lpRead, DWORD dwReadLen) 3949 { 3950 DWORD comp_len; 3951 DWORD read_len; 3952 CHAR *CompBuffer = NULL; 3953 CHAR *ReadBuffer = NULL; 3954 BOOL rc; 3955 InputContextData *data = get_imc_data(hIMC); 3956 3957 TRACE("(%p, %d, %p, %d, %p, %d):\n", 3958 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); 3959 3960 if (!data) 3961 return FALSE; 3962 3963 if (!(dwIndex == SCS_SETSTR || 3964 dwIndex == SCS_CHANGEATTR || 3965 dwIndex == SCS_CHANGECLAUSE || 3966 dwIndex == SCS_SETRECONVERTSTRING || 3967 dwIndex == SCS_QUERYRECONVERTSTRING)) 3968 return FALSE; 3969 3970 if (is_himc_ime_unicode(data)) 3971 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp, 3972 dwCompLen, lpRead, dwReadLen); 3973 3974 comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL, 3975 NULL); 3976 if (comp_len) 3977 { 3978 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len); 3979 WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len, 3980 NULL, NULL); 3981 } 3982 3983 read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL, 3984 NULL); 3985 if (read_len) 3986 { 3987 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len); 3988 WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len, 3989 NULL, NULL); 3990 } 3991 3992 rc = ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len, 3993 ReadBuffer, read_len); 3994 3995 HeapFree(GetProcessHeap(), 0, CompBuffer); 3996 HeapFree(GetProcessHeap(), 0, ReadBuffer); 3997 3998 return rc; 3999 } 4000 4001 /*********************************************************************** 4002 * ImmSetCompositionWindow (IMM32.@) 4003 */ 4004 BOOL WINAPI ImmSetCompositionWindow( 4005 HIMC hIMC, LPCOMPOSITIONFORM lpCompForm) 4006 { 4007 LPINPUTCONTEXT pIC; 4008 HWND hWnd; 4009 4010 if (Imm32IsCrossThreadAccess(hIMC)) 4011 return FALSE; 4012 4013 pIC = ImmLockIMC(hIMC); 4014 if (pIC == NULL) 4015 return FALSE; 4016 4017 pIC->cfCompForm = *lpCompForm; 4018 pIC->fdwInit |= INIT_COMPFORM; 4019 4020 hWnd = pIC->hWnd; 4021 4022 ImmUnlockIMC(hIMC); 4023 4024 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, 4025 IMC_SETCOMPOSITIONWINDOW, IMN_SETCOMPOSITIONWINDOW, 0); 4026 return TRUE; 4027 } 4028 4029 /*********************************************************************** 4030 * ImmSetConversionStatus (IMM32.@) 4031 */ 4032 BOOL WINAPI ImmSetConversionStatus( 4033 HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence) 4034 { 4035 HKL hKL; 4036 LPINPUTCONTEXT pIC; 4037 DWORD dwOldConversion, dwOldSentence; 4038 BOOL fConversionChange = FALSE, fSentenceChange = FALSE; 4039 HWND hWnd; 4040 4041 TRACE("(%p, 0x%lX, 0x%lX)\n", hIMC, fdwConversion, fdwSentence); 4042 4043 hKL = GetKeyboardLayout(0); 4044 if (!IS_IME_HKL(hKL)) 4045 { 4046 if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED)) 4047 { 4048 FIXME("Cicero\n"); 4049 return FALSE; 4050 } 4051 } 4052 4053 if (Imm32IsCrossThreadAccess(hIMC)) 4054 return FALSE; 4055 4056 pIC = ImmLockIMC(hIMC); 4057 if (pIC == NULL) 4058 return FALSE; 4059 4060 if (pIC->fdwConversion != fdwConversion) 4061 { 4062 dwOldConversion = pIC->fdwConversion; 4063 pIC->fdwConversion = fdwConversion; 4064 fConversionChange = TRUE; 4065 } 4066 4067 if (pIC->fdwSentence != fdwSentence) 4068 { 4069 dwOldSentence = pIC->fdwSentence; 4070 pIC->fdwSentence = fdwSentence; 4071 fSentenceChange = TRUE; 4072 } 4073 4074 hWnd = pIC->hWnd; 4075 ImmUnlockIMC(hIMC); 4076 4077 if (fConversionChange) 4078 { 4079 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldConversion, 4080 IMC_SETCONVERSIONMODE, IMN_SETCONVERSIONMODE, 0); 4081 NtUserNotifyIMEStatus(hWnd, hIMC, fdwConversion); 4082 } 4083 4084 if (fSentenceChange) 4085 { 4086 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldSentence, 4087 IMC_SETSENTENCEMODE, IMN_SETSENTENCEMODE, 0); 4088 } 4089 4090 return TRUE; 4091 } 4092 4093 /*********************************************************************** 4094 * ImmLockImeDpi (IMM32.@) 4095 */ 4096 PIMEDPI WINAPI ImmLockImeDpi(HKL hKL) 4097 { 4098 PIMEDPI pImeDpi = NULL; 4099 4100 TRACE("(%p)\n", hKL); 4101 4102 RtlEnterCriticalSection(&g_csImeDpi); 4103 4104 /* Find by hKL */ 4105 for (pImeDpi = g_pImeDpiList; pImeDpi; pImeDpi = pImeDpi->pNext) 4106 { 4107 if (pImeDpi->hKL == hKL) /* found */ 4108 { 4109 /* lock if possible */ 4110 if (pImeDpi->dwFlags & IMEDPI_FLAG_UNKNOWN) 4111 pImeDpi = NULL; 4112 else 4113 ++(pImeDpi->cLockObj); 4114 break; 4115 } 4116 } 4117 4118 RtlLeaveCriticalSection(&g_csImeDpi); 4119 return pImeDpi; 4120 } 4121 4122 /*********************************************************************** 4123 * ImmUnlockImeDpi (IMM32.@) 4124 */ 4125 VOID WINAPI ImmUnlockImeDpi(PIMEDPI pImeDpi) 4126 { 4127 PIMEDPI *ppEntry; 4128 4129 TRACE("(%p)\n", pImeDpi); 4130 4131 if (pImeDpi == NULL) 4132 return; 4133 4134 RtlEnterCriticalSection(&g_csImeDpi); 4135 4136 /* unlock */ 4137 --(pImeDpi->cLockObj); 4138 if (pImeDpi->cLockObj != 0) 4139 { 4140 RtlLeaveCriticalSection(&g_csImeDpi); 4141 return; 4142 } 4143 4144 if ((pImeDpi->dwFlags & IMEDPI_FLAG_UNKNOWN) == 0) 4145 { 4146 if ((pImeDpi->dwFlags & IMEDPI_FLAG_LOCKED) == 0 || 4147 (pImeDpi->ImeInfo.fdwProperty & IME_PROP_END_UNLOAD) == 0) 4148 { 4149 RtlLeaveCriticalSection(&g_csImeDpi); 4150 return; 4151 } 4152 } 4153 4154 /* Remove from list */ 4155 for (ppEntry = &g_pImeDpiList; *ppEntry; ppEntry = &((*ppEntry)->pNext)) 4156 { 4157 if (*ppEntry == pImeDpi) /* found */ 4158 { 4159 *ppEntry = pImeDpi->pNext; 4160 break; 4161 } 4162 } 4163 4164 Imm32FreeImeDpi(pImeDpi, TRUE); 4165 HeapFree(g_hImm32Heap, 0, pImeDpi); 4166 4167 RtlLeaveCriticalSection(&g_csImeDpi); 4168 } 4169 4170 /*********************************************************************** 4171 * ImmSetOpenStatus (IMM32.@) 4172 */ 4173 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) 4174 { 4175 DWORD dwConversion; 4176 LPINPUTCONTEXT pIC; 4177 HWND hWnd; 4178 BOOL bHasChange = FALSE; 4179 4180 TRACE("(%p, %d)\n", hIMC, fOpen); 4181 4182 if (Imm32IsCrossThreadAccess(hIMC)) 4183 return FALSE; 4184 4185 pIC = ImmLockIMC(hIMC); 4186 if (pIC == NULL) 4187 return FALSE; 4188 4189 if (pIC->fOpen != fOpen) 4190 { 4191 pIC->fOpen = fOpen; 4192 hWnd = pIC->hWnd; 4193 dwConversion = pIC->fdwConversion; 4194 bHasChange = TRUE; 4195 } 4196 4197 ImmUnlockIMC(hIMC); 4198 4199 if (bHasChange) 4200 { 4201 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, 4202 IMC_SETOPENSTATUS, IMN_SETOPENSTATUS, 0); 4203 NtUserNotifyIMEStatus(hWnd, hIMC, dwConversion); 4204 } 4205 4206 return TRUE; 4207 } 4208 4209 /*********************************************************************** 4210 * ImmSetStatusWindowPos (IMM32.@) 4211 */ 4212 BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) 4213 { 4214 LPINPUTCONTEXT pIC; 4215 HWND hWnd; 4216 4217 TRACE("(%p, {%ld, %ld})\n", hIMC, lpptPos->x, lpptPos->y); 4218 4219 if (Imm32IsCrossThreadAccess(hIMC)) 4220 return FALSE; 4221 4222 pIC = ImmLockIMC(hIMC); 4223 if (!pIC) 4224 return FALSE; 4225 4226 hWnd = pIC->hWnd; 4227 pIC->ptStatusWndPos = *lpptPos; 4228 pIC->fdwInit |= INIT_STATUSWNDPOS; 4229 4230 ImmUnlockIMC(hIMC); 4231 4232 Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, 4233 IMC_SETSTATUSWINDOWPOS, IMN_SETSTATUSWINDOWPOS, 0); 4234 return TRUE; 4235 } 4236 4237 /*********************************************************************** 4238 * ImmCreateSoftKeyboard(IMM32.@) 4239 */ 4240 HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y) 4241 { 4242 FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y); 4243 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 4244 return 0; 4245 } 4246 4247 /*********************************************************************** 4248 * ImmDestroySoftKeyboard(IMM32.@) 4249 */ 4250 BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd) 4251 { 4252 TRACE("(%p)\n", hSoftWnd); 4253 return DestroyWindow(hSoftWnd); 4254 } 4255 4256 /*********************************************************************** 4257 * ImmShowSoftKeyboard(IMM32.@) 4258 */ 4259 BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow) 4260 { 4261 TRACE("(%p, %d)\n", hSoftWnd, nCmdShow); 4262 if (hSoftWnd) 4263 return ShowWindow(hSoftWnd, nCmdShow); 4264 return FALSE; 4265 } 4266 4267 /*********************************************************************** 4268 * ImmSimulateHotKey (IMM32.@) 4269 */ 4270 BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID) 4271 { 4272 HIMC hIMC; 4273 DWORD dwThreadId; 4274 HKL hKL; 4275 BOOL ret; 4276 4277 TRACE("(%p, 0x%lX)\n", hWnd, dwHotKeyID); 4278 4279 hIMC = ImmGetContext(hWnd); 4280 dwThreadId = GetWindowThreadProcessId(hWnd, NULL); 4281 hKL = GetKeyboardLayout(dwThreadId); 4282 ret = Imm32ProcessHotKey(hWnd, hIMC, hKL, dwHotKeyID); 4283 ImmReleaseContext(hWnd, hIMC); 4284 return ret; 4285 } 4286 4287 /*********************************************************************** 4288 * ImmUnregisterWordA (IMM32.@) 4289 */ 4290 BOOL WINAPI ImmUnregisterWordA( 4291 HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister) 4292 { 4293 BOOL ret = FALSE; 4294 PIMEDPI pImeDpi; 4295 LPWSTR pszReadingW = NULL, pszUnregisterW = NULL; 4296 4297 TRACE("(%p, %s, 0x%lX, %s)\n", hKL, debugstr_a(lpszReading), dwStyle, 4298 debugstr_a(lpszUnregister)); 4299 4300 pImeDpi = ImmLockOrLoadImeDpi(hKL); 4301 if (pImeDpi == NULL) 4302 return FALSE; 4303 4304 if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)) 4305 { 4306 ret = pImeDpi->ImeUnregisterWord(lpszReading, dwStyle, lpszUnregister); 4307 ImmUnlockImeDpi(pImeDpi); 4308 return ret; 4309 } 4310 4311 if (lpszReading) 4312 { 4313 pszReadingW = Imm32WideFromAnsi(lpszReading); 4314 if (pszReadingW == NULL) 4315 goto Quit; 4316 } 4317 4318 if (lpszUnregister) 4319 { 4320 pszUnregisterW = Imm32WideFromAnsi(lpszUnregister); 4321 if (pszUnregisterW == NULL) 4322 goto Quit; 4323 } 4324 4325 ret = pImeDpi->ImeUnregisterWord(pszReadingW, dwStyle, pszUnregisterW); 4326 4327 Quit: 4328 if (pszReadingW) 4329 HeapFree(g_hImm32Heap, 0, pszReadingW); 4330 if (pszUnregisterW) 4331 HeapFree(g_hImm32Heap, 0, pszUnregisterW); 4332 ImmUnlockImeDpi(pImeDpi); 4333 return ret; 4334 } 4335 4336 /*********************************************************************** 4337 * ImmUnregisterWordW (IMM32.@) 4338 */ 4339 BOOL WINAPI ImmUnregisterWordW( 4340 HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister) 4341 { 4342 BOOL ret = FALSE; 4343 PIMEDPI pImeDpi; 4344 LPSTR pszReadingA = NULL, pszUnregisterA = NULL; 4345 4346 TRACE("(%p, %s, 0x%lX, %s)\n", hKL, debugstr_w(lpszReading), dwStyle, 4347 debugstr_w(lpszUnregister)); 4348 4349 pImeDpi = ImmLockOrLoadImeDpi(hKL); 4350 if (!pImeDpi) 4351 return FALSE; 4352 4353 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) 4354 { 4355 ret = pImeDpi->ImeUnregisterWord(lpszReading, dwStyle, lpszUnregister); 4356 ImmUnlockImeDpi(pImeDpi); 4357 return ret; 4358 } 4359 4360 if (lpszReading) 4361 { 4362 pszReadingA = Imm32AnsiFromWide(lpszReading); 4363 if (!pszReadingA) 4364 goto Quit; 4365 } 4366 4367 if (lpszUnregister) 4368 { 4369 pszUnregisterA = Imm32AnsiFromWide(lpszUnregister); 4370 if (!pszUnregisterA) 4371 goto Quit; 4372 } 4373 4374 ret = pImeDpi->ImeUnregisterWord(pszReadingA, dwStyle, pszUnregisterA); 4375 4376 Quit: 4377 if (pszReadingA) 4378 HeapFree(g_hImm32Heap, 0, pszReadingA); 4379 if (pszUnregisterA) 4380 HeapFree(g_hImm32Heap, 0, pszUnregisterA); 4381 ImmUnlockImeDpi(pImeDpi); 4382 return ret; 4383 } 4384 4385 /*********************************************************************** 4386 * ImmGetImeMenuItemsA (IMM32.@) 4387 */ 4388 DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType, 4389 LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu, 4390 DWORD dwSize) 4391 { 4392 InputContextData *data = get_imc_data(hIMC); 4393 TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType, 4394 lpImeParentMenu, lpImeMenu, dwSize); 4395 4396 if (!data) 4397 { 4398 SetLastError(ERROR_INVALID_HANDLE); 4399 return 0; 4400 } 4401 4402 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems) 4403 { 4404 if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu)) 4405 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType, 4406 (IMEMENUITEMINFOW*)lpImeParentMenu, 4407 (IMEMENUITEMINFOW*)lpImeMenu, dwSize); 4408 else 4409 { 4410 IMEMENUITEMINFOW lpImeParentMenuW; 4411 IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL; 4412 DWORD rc; 4413 4414 if (lpImeParentMenu) 4415 parent = &lpImeParentMenuW; 4416 if (lpImeMenu) 4417 { 4418 int count = dwSize / sizeof(LPIMEMENUITEMINFOA); 4419 dwSize = count * sizeof(IMEMENUITEMINFOW); 4420 lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize); 4421 } 4422 else 4423 lpImeMenuW = NULL; 4424 4425 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType, 4426 parent, lpImeMenuW, dwSize); 4427 4428 if (lpImeParentMenu) 4429 { 4430 memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA)); 4431 lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem; 4432 WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString, 4433 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE, 4434 NULL, NULL); 4435 } 4436 if (lpImeMenu && rc) 4437 { 4438 unsigned int i; 4439 for (i = 0; i < rc; i++) 4440 { 4441 memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA)); 4442 lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem; 4443 WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString, 4444 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE, 4445 NULL, NULL); 4446 } 4447 } 4448 HeapFree(GetProcessHeap(),0,lpImeMenuW); 4449 return rc; 4450 } 4451 } 4452 else 4453 return 0; 4454 } 4455 4456 /*********************************************************************** 4457 * ImmGetImeMenuItemsW (IMM32.@) 4458 */ 4459 DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType, 4460 LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu, 4461 DWORD dwSize) 4462 { 4463 InputContextData *data = get_imc_data(hIMC); 4464 TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType, 4465 lpImeParentMenu, lpImeMenu, dwSize); 4466 4467 if (!data) 4468 { 4469 SetLastError(ERROR_INVALID_HANDLE); 4470 return 0; 4471 } 4472 4473 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems) 4474 { 4475 if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu)) 4476 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType, 4477 lpImeParentMenu, lpImeMenu, dwSize); 4478 else 4479 { 4480 IMEMENUITEMINFOA lpImeParentMenuA; 4481 IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL; 4482 DWORD rc; 4483 4484 if (lpImeParentMenu) 4485 parent = &lpImeParentMenuA; 4486 if (lpImeMenu) 4487 { 4488 int count = dwSize / sizeof(LPIMEMENUITEMINFOW); 4489 dwSize = count * sizeof(IMEMENUITEMINFOA); 4490 lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize); 4491 } 4492 else 4493 lpImeMenuA = NULL; 4494 4495 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType, 4496 (IMEMENUITEMINFOW*)parent, 4497 (IMEMENUITEMINFOW*)lpImeMenuA, dwSize); 4498 4499 if (lpImeParentMenu) 4500 { 4501 memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA)); 4502 lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem; 4503 MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString, 4504 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE); 4505 } 4506 if (lpImeMenu && rc) 4507 { 4508 unsigned int i; 4509 for (i = 0; i < rc; i++) 4510 { 4511 memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA)); 4512 lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem; 4513 MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString, 4514 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE); 4515 } 4516 } 4517 HeapFree(GetProcessHeap(),0,lpImeMenuA); 4518 return rc; 4519 } 4520 } 4521 else 4522 return 0; 4523 } 4524 4525 /*********************************************************************** 4526 * ImmLockIMC(IMM32.@) 4527 */ 4528 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC) 4529 { 4530 InputContextData *data = get_imc_data(hIMC); 4531 4532 if (!data) 4533 return NULL; 4534 data->dwLock++; 4535 return &data->IMC; 4536 } 4537 4538 /*********************************************************************** 4539 * ImmUnlockIMC(IMM32.@) 4540 */ 4541 BOOL WINAPI ImmUnlockIMC(HIMC hIMC) 4542 { 4543 PCLIENTIMC pClientImc; 4544 HIMC hClientImc; 4545 4546 pClientImc = ImmLockClientImc(hIMC); 4547 if (pClientImc == NULL) 4548 return FALSE; 4549 4550 hClientImc = pClientImc->hImc; 4551 if (hClientImc) 4552 LocalUnlock(hClientImc); 4553 4554 InterlockedDecrement(&pClientImc->cLockObj); 4555 ImmUnlockClientImc(pClientImc); 4556 return TRUE; 4557 } 4558 4559 /*********************************************************************** 4560 * ImmGetIMCLockCount(IMM32.@) 4561 */ 4562 DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC) 4563 { 4564 DWORD ret; 4565 HIMC hClientImc; 4566 PCLIENTIMC pClientImc; 4567 4568 pClientImc = ImmLockClientImc(hIMC); 4569 if (pClientImc == NULL) 4570 return 0; 4571 4572 ret = 0; 4573 hClientImc = pClientImc->hImc; 4574 if (hClientImc) 4575 ret = (LocalFlags(hClientImc) & LMEM_LOCKCOUNT); 4576 4577 ImmUnlockClientImc(pClientImc); 4578 return ret; 4579 } 4580 4581 /*********************************************************************** 4582 * ImmCreateIMCC(IMM32.@) 4583 */ 4584 HIMCC WINAPI ImmCreateIMCC(DWORD size) 4585 { 4586 if (size < 4) 4587 size = 4; 4588 return LocalAlloc(LHND, size); 4589 } 4590 4591 /*********************************************************************** 4592 * ImmDestroyIMCC(IMM32.@) 4593 */ 4594 HIMCC WINAPI ImmDestroyIMCC(HIMCC block) 4595 { 4596 if (block) 4597 return LocalFree(block); 4598 return NULL; 4599 } 4600 4601 /*********************************************************************** 4602 * ImmLockIMCC(IMM32.@) 4603 */ 4604 LPVOID WINAPI ImmLockIMCC(HIMCC imcc) 4605 { 4606 if (imcc) 4607 return LocalLock(imcc); 4608 return NULL; 4609 } 4610 4611 /*********************************************************************** 4612 * ImmUnlockIMCC(IMM32.@) 4613 */ 4614 BOOL WINAPI ImmUnlockIMCC(HIMCC imcc) 4615 { 4616 if (imcc) 4617 return LocalUnlock(imcc); 4618 return FALSE; 4619 } 4620 4621 /*********************************************************************** 4622 * ImmGetIMCCLockCount(IMM32.@) 4623 */ 4624 DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc) 4625 { 4626 return LocalFlags(imcc) & LMEM_LOCKCOUNT; 4627 } 4628 4629 /*********************************************************************** 4630 * ImmReSizeIMCC(IMM32.@) 4631 */ 4632 HIMCC WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size) 4633 { 4634 if (!imcc) 4635 return NULL; 4636 return LocalReAlloc(imcc, size, LHND); 4637 } 4638 4639 /*********************************************************************** 4640 * ImmGetIMCCSize(IMM32.@) 4641 */ 4642 DWORD WINAPI ImmGetIMCCSize(HIMCC imcc) 4643 { 4644 if (imcc) 4645 return LocalSize(imcc); 4646 return 0; 4647 } 4648 4649 /*********************************************************************** 4650 * ImmGenerateMessage(IMM32.@) 4651 */ 4652 BOOL WINAPI ImmGenerateMessage(HIMC hIMC) 4653 { 4654 PCLIENTIMC pClientImc; 4655 LPINPUTCONTEXT pIC; 4656 LPTRANSMSG pMsgs, pTrans = NULL, pItem; 4657 HWND hWnd; 4658 DWORD dwIndex, dwCount, cbTrans; 4659 HIMCC hMsgBuf = NULL; 4660 BOOL bAnsi; 4661 4662 TRACE("(%p)\n", hIMC); 4663 4664 if (Imm32IsCrossThreadAccess(hIMC)) 4665 return FALSE; 4666 4667 pClientImc = ImmLockClientImc(hIMC); 4668 if (pClientImc == NULL) 4669 return FALSE; 4670 4671 bAnsi = !(pClientImc->dwFlags & CLIENTIMC_WIDE); 4672 ImmUnlockClientImc(pClientImc); 4673 4674 pIC = ImmLockIMC(hIMC); 4675 if (pIC == NULL) 4676 return FALSE; 4677 4678 dwCount = pIC->dwNumMsgBuf; 4679 if (dwCount == 0) 4680 goto Quit; 4681 4682 hMsgBuf = pIC->hMsgBuf; 4683 pMsgs = ImmLockIMCC(hMsgBuf); 4684 if (pMsgs == NULL) 4685 goto Quit; 4686 4687 cbTrans = dwCount * sizeof(TRANSMSG); 4688 pTrans = Imm32HeapAlloc(0, cbTrans); 4689 if (pTrans == NULL) 4690 goto Quit; 4691 4692 RtlCopyMemory(pTrans, pMsgs, cbTrans); 4693 4694 #ifdef IMP_SUPPORT 4695 if (GetWin32ClientInfo()->dwExpWinVer < _WIN32_WINNT_NT4) /* old version (3.x)? */ 4696 { 4697 LANGID LangID = LANGIDFROMLCID(GetSystemDefaultLCID()); 4698 WORD wLang = PRIMARYLANGID(LangID); 4699 4700 /* translate the messages if Japanese or Korean */ 4701 if (wLang == LANG_JAPANESE || 4702 (wLang == LANG_KOREAN && NtUserGetAppImeLevel(pIC->hWnd) == 3)) 4703 { 4704 dwCount = ImpTrans(dwCount, pTrans, hIMC, bAnsi, wLang); 4705 } 4706 } 4707 #endif 4708 4709 /* send them */ 4710 hWnd = pIC->hWnd; 4711 pItem = pTrans; 4712 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pItem) 4713 { 4714 if (bAnsi) 4715 SendMessageA(hWnd, pItem->message, pItem->wParam, pItem->lParam); 4716 else 4717 SendMessageW(hWnd, pItem->message, pItem->wParam, pItem->lParam); 4718 } 4719 4720 Quit: 4721 if (pTrans) 4722 HeapFree(g_hImm32Heap, 0, pTrans); 4723 if (hMsgBuf) 4724 ImmUnlockIMCC(hMsgBuf); 4725 pIC->dwNumMsgBuf = 0; /* done */ 4726 ImmUnlockIMC(hIMC); 4727 return TRUE; 4728 } 4729 4730 static VOID APIENTRY 4731 Imm32PostMessages(HWND hwnd, HIMC hIMC, DWORD dwCount, LPTRANSMSG lpTransMsg) 4732 { 4733 DWORD dwIndex; 4734 PCLIENTIMC pClientImc; 4735 LPTRANSMSG pNewTransMsg = lpTransMsg, pItem; 4736 BOOL bAnsi; 4737 4738 pClientImc = ImmLockClientImc(hIMC); 4739 if (pClientImc == NULL) 4740 return; 4741 4742 bAnsi = !(pClientImc->dwFlags & CLIENTIMC_WIDE); 4743 ImmUnlockClientImc(pClientImc); 4744 4745 #ifdef IMP_SUPPORT 4746 if (GetWin32ClientInfo()->dwExpWinVer < _WIN32_WINNT_NT4) /* old version (3.x)? */ 4747 { 4748 LANGID LangID = LANGIDFROMLCID(GetSystemDefaultLCID()); 4749 WORD Lang = PRIMARYLANGID(LangID); 4750 4751 /* translate the messages if Japanese or Korean */ 4752 if (Lang == LANG_JAPANESE || 4753 (Lang == LANG_KOREAN && NtUserGetAppImeLevel(hwnd) == 3)) 4754 { 4755 DWORD cbTransMsg = dwCount * sizeof(TRANSMSG); 4756 pNewTransMsg = Imm32HeapAlloc(0, cbTransMsg); 4757 if (pNewTransMsg) 4758 { 4759 RtlCopyMemory(pNewTransMsg, lpTransMsg, cbTransMsg); 4760 dwCount = ImpTrans(dwCount, pNewTransMsg, hIMC, bAnsi, Lang); 4761 } 4762 else 4763 { 4764 pNewTransMsg = lpTransMsg; 4765 } 4766 } 4767 } 4768 #endif 4769 4770 /* post them */ 4771 pItem = pNewTransMsg; 4772 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pItem) 4773 { 4774 if (bAnsi) 4775 PostMessageA(hwnd, pItem->message, pItem->wParam, pItem->lParam); 4776 else 4777 PostMessageW(hwnd, pItem->message, pItem->wParam, pItem->lParam); 4778 } 4779 4780 #ifdef IMP_SUPPORT 4781 if (pNewTransMsg && pNewTransMsg != lpTransMsg) 4782 HeapFree(g_hImm32Heap, 0, pNewTransMsg); 4783 #endif 4784 } 4785 4786 /*********************************************************************** 4787 * ImmTranslateMessage(IMM32.@) 4788 * ( Undocumented, call internally and from user32.dll ) 4789 */ 4790 BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData) 4791 { 4792 #define MSG_COUNT 0x100 4793 BOOL ret = FALSE; 4794 INT kret; 4795 LPINPUTCONTEXTDX pIC; 4796 PIMEDPI pImeDpi = NULL; 4797 LPTRANSMSGLIST pList = NULL; 4798 LPTRANSMSG pTransMsg; 4799 BYTE abKeyState[256]; 4800 HIMC hIMC; 4801 HKL hKL; 4802 UINT vk; 4803 DWORD dwThreadId, dwCount, cbList; 4804 WCHAR wch; 4805 WORD wChar; 4806 4807 TRACE("(%p, 0x%X, %p, %p)\n", hwnd, msg, wParam, lKeyData); 4808 4809 /* filter the message */ 4810 switch (msg) 4811 { 4812 case WM_KEYDOWN: case WM_KEYUP: case WM_SYSKEYDOWN: case WM_SYSKEYUP: 4813 break; 4814 default: 4815 return FALSE; 4816 } 4817 4818 hIMC = ImmGetContext(hwnd); 4819 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 4820 if (pIC == NULL) 4821 { 4822 ImmReleaseContext(hwnd, hIMC); 4823 return FALSE; 4824 } 4825 4826 if (!pIC->bNeedsTrans) /* is translation needed? */ 4827 { 4828 /* directly post them */ 4829 dwCount = pIC->dwNumMsgBuf; 4830 if (dwCount == 0) 4831 goto Quit; 4832 4833 pTransMsg = ImmLockIMCC(pIC->hMsgBuf); 4834 if (pTransMsg) 4835 { 4836 Imm32PostMessages(hwnd, hIMC, dwCount, pTransMsg); 4837 ImmUnlockIMCC(pIC->hMsgBuf); 4838 ret = TRUE; 4839 } 4840 pIC->dwNumMsgBuf = 0; /* done */ 4841 goto Quit; 4842 } 4843 pIC->bNeedsTrans = FALSE; /* clear the flag */ 4844 4845 dwThreadId = GetWindowThreadProcessId(hwnd, NULL); 4846 hKL = GetKeyboardLayout(dwThreadId); 4847 pImeDpi = ImmLockImeDpi(hKL); 4848 if (pImeDpi == NULL) 4849 goto Quit; 4850 4851 if (!GetKeyboardState(abKeyState)) /* get keyboard ON/OFF status */ 4852 goto Quit; 4853 4854 /* convert a virtual key if IME_PROP_KBD_CHAR_FIRST */ 4855 vk = pIC->nVKey; 4856 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST) 4857 { 4858 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) 4859 { 4860 wch = 0; 4861 kret = ToUnicode(vk, HIWORD(lKeyData), abKeyState, &wch, 1, 0); 4862 if (kret == 1) 4863 vk = MAKELONG(LOBYTE(vk), wch); 4864 } 4865 else 4866 { 4867 wChar = 0; 4868 kret = ToAsciiEx(vk, HIWORD(lKeyData), abKeyState, &wChar, 0, hKL); 4869 if (kret > 0) 4870 vk = MAKEWORD(vk, wChar); 4871 } 4872 } 4873 4874 /* allocate a list */ 4875 cbList = offsetof(TRANSMSGLIST, TransMsg) + MSG_COUNT * sizeof(TRANSMSG); 4876 pList = Imm32HeapAlloc(0, cbList); 4877 if (!pList) 4878 goto Quit; 4879 4880 /* use IME conversion engine and convert the list */ 4881 pList->uMsgCount = MSG_COUNT; 4882 kret = pImeDpi->ImeToAsciiEx(vk, HIWORD(lKeyData), abKeyState, pList, 0, hIMC); 4883 if (kret <= 0) 4884 goto Quit; 4885 4886 /* post them */ 4887 if (kret <= MSG_COUNT) 4888 { 4889 Imm32PostMessages(hwnd, hIMC, kret, pList->TransMsg); 4890 ret = TRUE; 4891 } 4892 else 4893 { 4894 pTransMsg = ImmLockIMCC(pIC->hMsgBuf); 4895 if (pTransMsg == NULL) 4896 goto Quit; 4897 Imm32PostMessages(hwnd, hIMC, kret, pTransMsg); 4898 ImmUnlockIMCC(pIC->hMsgBuf); 4899 } 4900 4901 Quit: 4902 if (pList) 4903 HeapFree(g_hImm32Heap, 0, pList); 4904 ImmUnlockImeDpi(pImeDpi); 4905 ImmUnlockIMC(hIMC); 4906 ImmReleaseContext(hwnd, hIMC); 4907 return ret; 4908 #undef MSG_COUNT 4909 } 4910 4911 /*********************************************************************** 4912 * ImmProcessKey(IMM32.@) 4913 * ( Undocumented, called from user32.dll ) 4914 */ 4915 DWORD WINAPI ImmProcessKey(HWND hWnd, HKL hKL, UINT vKey, LPARAM lParam, DWORD dwHotKeyID) 4916 { 4917 DWORD ret = 0; 4918 HIMC hIMC; 4919 PIMEDPI pImeDpi; 4920 LPINPUTCONTEXTDX pIC; 4921 BYTE KeyState[256]; 4922 UINT vk; 4923 BOOL bUseIme = TRUE, bSkipThisKey = FALSE, bLowWordOnly = FALSE; 4924 4925 TRACE("(%p, %p, 0x%X, %p, 0x%lX)\n", hWnd, hKL, vKey, lParam, dwHotKeyID); 4926 4927 hIMC = ImmGetContext(hWnd); 4928 pImeDpi = ImmLockImeDpi(hKL); 4929 if (pImeDpi) 4930 { 4931 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 4932 if (pIC) 4933 { 4934 if (LOBYTE(vKey) == VK_PACKET && 4935 !(pImeDpi->ImeInfo.fdwProperty & IME_PROP_ACCEPT_WIDE_VKEY)) 4936 { 4937 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) 4938 { 4939 bLowWordOnly = TRUE; 4940 } 4941 else 4942 { 4943 bUseIme = FALSE; 4944 if (pIC->fOpen) 4945 bSkipThisKey = TRUE; 4946 } 4947 } 4948 4949 if (bUseIme) 4950 { 4951 if (GetKeyboardState(KeyState)) 4952 { 4953 vk = (bLowWordOnly ? LOWORD(vKey) : vKey); 4954 if (pImeDpi->ImeProcessKey(hIMC, vk, lParam, KeyState)) 4955 { 4956 pIC->bNeedsTrans = TRUE; 4957 pIC->nVKey = vKey; 4958 ret |= IPHK_PROCESSBYIME; 4959 } 4960 } 4961 } 4962 else if (bSkipThisKey) 4963 { 4964 ret |= IPHK_SKIPTHISKEY; 4965 } 4966 4967 ImmUnlockIMC(hIMC); 4968 } 4969 4970 ImmUnlockImeDpi(pImeDpi); 4971 } 4972 4973 if (dwHotKeyID != INVALID_HOTKEY_ID) 4974 { 4975 if (Imm32ProcessHotKey(hWnd, hIMC, hKL, dwHotKeyID)) 4976 { 4977 if (vKey != VK_KANJI || dwHotKeyID != IME_JHOTKEY_CLOSE_OPEN) 4978 ret |= IPHK_HOTKEY; 4979 } 4980 } 4981 4982 if (ret & IPHK_PROCESSBYIME) 4983 { 4984 FIXME("TODO: We have to do something here.\n"); 4985 } 4986 4987 ImmReleaseContext(hWnd, hIMC); 4988 return ret; 4989 } 4990 4991 /*********************************************************************** 4992 * ImmDisableTextFrameService(IMM32.@) 4993 */ 4994 BOOL WINAPI ImmDisableTextFrameService(DWORD dwThreadId) 4995 { 4996 FIXME("Stub\n"); 4997 return FALSE; 4998 } 4999 5000 /*********************************************************************** 5001 * ImmEnumInputContext(IMM32.@) 5002 */ 5003 BOOL WINAPI ImmEnumInputContext(DWORD dwThreadId, IMCENUMPROC lpfn, LPARAM lParam) 5004 { 5005 HIMC *phList; 5006 DWORD dwIndex, dwCount; 5007 BOOL ret = TRUE; 5008 HIMC hIMC; 5009 5010 TRACE("(%lu, %p, %p)\n", dwThreadId, lpfn, lParam); 5011 5012 dwCount = Imm32AllocAndBuildHimcList(dwThreadId, &phList); 5013 if (!dwCount) 5014 return FALSE; 5015 5016 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex) 5017 { 5018 hIMC = phList[dwIndex]; 5019 ret = (*lpfn)(hIMC, lParam); 5020 if (!ret) 5021 break; 5022 } 5023 5024 HeapFree(g_hImm32Heap, 0, phList); 5025 return ret; 5026 } 5027 5028 /*********************************************************************** 5029 * ImmGetHotKey(IMM32.@) 5030 */ 5031 BOOL WINAPI 5032 ImmGetHotKey(IN DWORD dwHotKey, 5033 OUT LPUINT lpuModifiers, 5034 OUT LPUINT lpuVKey, 5035 OUT LPHKL lphKL) 5036 { 5037 TRACE("(0x%lX, %p, %p, %p)\n", dwHotKey, lpuModifiers, lpuVKey, lphKL); 5038 if (lpuModifiers && lpuVKey) 5039 return NtUserGetImeHotKey(dwHotKey, lpuModifiers, lpuVKey, lphKL); 5040 return FALSE; 5041 } 5042 5043 /*********************************************************************** 5044 * ImmDisableLegacyIME(IMM32.@) 5045 */ 5046 BOOL WINAPI ImmDisableLegacyIME(void) 5047 { 5048 FIXME("stub\n"); 5049 return TRUE; 5050 } 5051 5052 /*********************************************************************** 5053 * ImmSetActiveContext(IMM32.@) 5054 */ 5055 BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC hIMC, BOOL fFlag) 5056 { 5057 FIXME("(%p, %p, %d): stub\n", hwnd, hIMC, fFlag); 5058 return FALSE; 5059 } 5060 5061 /*********************************************************************** 5062 * ImmSetActiveContextConsoleIME(IMM32.@) 5063 */ 5064 BOOL WINAPI ImmSetActiveContextConsoleIME(HWND hwnd, BOOL fFlag) 5065 { 5066 HIMC hIMC; 5067 TRACE("(%p, %d)\n", hwnd, fFlag); 5068 5069 hIMC = ImmGetContext(hwnd); 5070 if (hIMC) 5071 return ImmSetActiveContext(hwnd, hIMC, fFlag); 5072 return FALSE; 5073 } 5074 5075 /*********************************************************************** 5076 * ImmRegisterClient(IMM32.@) 5077 * ( Undocumented, called from user32.dll ) 5078 */ 5079 BOOL WINAPI ImmRegisterClient(PSHAREDINFO ptr, HINSTANCE hMod) 5080 { 5081 g_SharedInfo = *ptr; 5082 g_psi = g_SharedInfo.psi; 5083 return Imm32InitInstance(hMod); 5084 } 5085 5086 /*********************************************************************** 5087 * CtfImmIsTextFrameServiceDisabled(IMM32.@) 5088 */ 5089 BOOL WINAPI CtfImmIsTextFrameServiceDisabled(VOID) 5090 { 5091 PTEB pTeb = NtCurrentTeb(); 5092 if (((PW32CLIENTINFO)pTeb->Win32ClientInfo)->CI_flags & CI_TFSDISABLED) 5093 return TRUE; 5094 return FALSE; 5095 } 5096 5097 /*********************************************************************** 5098 * ImmGetImeInfoEx (IMM32.@) 5099 */ 5100 BOOL WINAPI 5101 ImmGetImeInfoEx(PIMEINFOEX pImeInfoEx, 5102 IMEINFOEXCLASS SearchType, 5103 PVOID pvSearchKey) 5104 { 5105 BOOL bDisabled = FALSE; 5106 HKL hKL; 5107 PTEB pTeb; 5108 5109 switch (SearchType) 5110 { 5111 case ImeInfoExKeyboardLayout: 5112 break; 5113 5114 case ImeInfoExImeWindow: 5115 bDisabled = CtfImmIsTextFrameServiceDisabled(); 5116 SearchType = ImeInfoExKeyboardLayout; 5117 break; 5118 5119 case ImeInfoExImeFileName: 5120 StringCchCopyW(pImeInfoEx->wszImeFile, _countof(pImeInfoEx->wszImeFile), 5121 pvSearchKey); 5122 goto Quit; 5123 } 5124 5125 hKL = *(HKL*)pvSearchKey; 5126 pImeInfoEx->hkl = hKL; 5127 5128 if (!IS_IME_HKL(hKL)) 5129 { 5130 if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED)) 5131 { 5132 pTeb = NtCurrentTeb(); 5133 if (((PW32CLIENTINFO)pTeb->Win32ClientInfo)->W32ClientInfo[0] & 2) 5134 return FALSE; 5135 if (!bDisabled) 5136 goto Quit; 5137 } 5138 return FALSE; 5139 } 5140 5141 Quit: 5142 return NtUserGetImeInfoEx(pImeInfoEx, SearchType); 5143 } 5144 5145 /*********************************************************************** 5146 * ImmWINNLSGetIMEHotkey (IMM32.@) 5147 */ 5148 UINT WINAPI ImmWINNLSGetIMEHotkey(HWND hwndIme) 5149 { 5150 TRACE("(%p)\n", hwndIme); 5151 UNREFERENCED_PARAMETER(hwndIme); 5152 return 0; /* This is correct. This function of Windows just returns zero. */ 5153 } 5154 5155 BOOL WINAPI User32InitializeImmEntryTable(DWORD); 5156 5157 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) 5158 { 5159 HKL hKL; 5160 HIMC hIMC; 5161 PTEB pTeb; 5162 5163 TRACE("(%p, 0x%X, %p)\n", hinstDLL, fdwReason, lpReserved); 5164 5165 switch (fdwReason) 5166 { 5167 case DLL_PROCESS_ATTACH: 5168 //Imm32GenerateRandomSeed(hinstDLL, 1, lpReserved); // Non-sense 5169 if (!Imm32InitInstance(hinstDLL)) 5170 { 5171 ERR("Imm32InitInstance failed\n"); 5172 return FALSE; 5173 } 5174 if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC)) 5175 { 5176 ERR("User32InitializeImmEntryTable failed\n"); 5177 return FALSE; 5178 } 5179 break; 5180 5181 case DLL_THREAD_ATTACH: 5182 break; 5183 5184 case DLL_THREAD_DETACH: 5185 if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32)) 5186 return TRUE; 5187 5188 pTeb = NtCurrentTeb(); 5189 if (pTeb->Win32ThreadInfo == NULL) 5190 return TRUE; 5191 5192 hKL = GetKeyboardLayout(0); 5193 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken. 5194 hIMC = (HIMC)NtUserGetThreadState(4); 5195 Imm32CleanupContext(hIMC, hKL, TRUE); 5196 break; 5197 5198 case DLL_PROCESS_DETACH: 5199 RtlDeleteCriticalSection(&g_csImeDpi); 5200 TRACE("imm32.dll is unloaded\n"); 5201 break; 5202 } 5203 5204 return TRUE; 5205 } 5206