1 /* 2 * PROJECT: ReactOS IMM32 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * PURPOSE: Implementing IMM32 keys and messages 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 "precomp.h" 14 15 WINE_DEFAULT_DEBUG_CHANNEL(imm); 16 17 BOOL APIENTRY Imm32ImeNonImeToggle(HIMC hIMC, HKL hKL, HWND hWnd, LANGID LangID) 18 { 19 LPINPUTCONTEXT pIC; 20 BOOL fOpen; 21 22 if (hWnd != NULL) 23 return FALSE; 24 25 if (!IS_IME_HKL(hKL) || LOWORD(hKL) != LangID) 26 { 27 FIXME("We have to do something here\n"); 28 return TRUE; 29 } 30 31 pIC = ImmLockIMC(hIMC); 32 if (pIC == NULL) 33 return TRUE; 34 35 fOpen = pIC->fOpen; 36 ImmUnlockIMC(hIMC); 37 38 if (!fOpen) 39 { 40 ImmSetOpenStatus(hIMC, TRUE); 41 return TRUE; 42 } 43 44 FIXME("We have to do something here\n"); 45 return TRUE; 46 } 47 48 BOOL APIENTRY Imm32CShapeToggle(HIMC hIMC, HKL hKL, HWND hWnd) 49 { 50 LPINPUTCONTEXT pIC; 51 BOOL fOpen; 52 DWORD dwConversion, dwSentence; 53 54 if (hWnd == NULL || !IS_IME_HKL(hKL)) 55 return FALSE; 56 57 pIC = ImmLockIMC(hIMC); 58 if (pIC == NULL) 59 return TRUE; 60 61 fOpen = pIC->fOpen; 62 if (fOpen) 63 { 64 dwConversion = (pIC->fdwConversion ^ IME_CMODE_FULLSHAPE); 65 dwSentence = pIC->fdwSentence; 66 } 67 68 ImmUnlockIMC(hIMC); 69 70 if (fOpen) 71 ImmSetConversionStatus(hIMC, dwConversion, dwSentence); 72 else 73 ImmSetOpenStatus(hIMC, TRUE); 74 75 return TRUE; 76 } 77 78 BOOL APIENTRY Imm32CSymbolToggle(HIMC hIMC, HKL hKL, HWND hWnd) 79 { 80 LPINPUTCONTEXT pIC; 81 BOOL fOpen; 82 DWORD dwConversion, dwSentence; 83 84 if (hWnd == NULL || !IS_IME_HKL(hKL)) 85 return FALSE; 86 87 pIC = ImmLockIMC(hIMC); 88 if (pIC == NULL) 89 return TRUE; 90 91 fOpen = pIC->fOpen; 92 if (fOpen) 93 { 94 dwConversion = (pIC->fdwConversion ^ IME_CMODE_SYMBOL); 95 dwSentence = pIC->fdwSentence; 96 } 97 98 ImmUnlockIMC(hIMC); 99 100 if (fOpen) 101 ImmSetConversionStatus(hIMC, dwConversion, dwSentence); 102 else 103 ImmSetOpenStatus(hIMC, TRUE); 104 105 return TRUE; 106 } 107 108 BOOL APIENTRY Imm32JCloseOpen(HIMC hIMC, HKL hKL, HWND hWnd) 109 { 110 BOOL fOpen; 111 112 if (ImmIsIME(hKL) && LOWORD(hKL) == LANGID_JAPANESE) 113 { 114 fOpen = ImmGetOpenStatus(hIMC); 115 ImmSetOpenStatus(hIMC, !fOpen); 116 return TRUE; 117 } 118 119 FIXME("We have to do something here\n"); 120 return TRUE; 121 } 122 123 BOOL APIENTRY Imm32KShapeToggle(HIMC hIMC) 124 { 125 LPINPUTCONTEXT pIC; 126 DWORD dwConversion, dwSentence; 127 128 pIC = ImmLockIMC(hIMC); 129 if (pIC == NULL) 130 return FALSE; 131 132 dwConversion = (pIC->fdwConversion ^ IME_CMODE_FULLSHAPE); 133 dwSentence = pIC->fdwSentence; 134 ImmSetConversionStatus(hIMC, dwConversion, dwSentence); 135 136 if (pIC->fdwConversion & (IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE)) 137 ImmSetOpenStatus(hIMC, TRUE); 138 else 139 ImmSetOpenStatus(hIMC, FALSE); 140 141 ImmUnlockIMC(hIMC); 142 return TRUE; 143 } 144 145 BOOL APIENTRY Imm32KHanjaConvert(HIMC hIMC) 146 { 147 LPINPUTCONTEXT pIC; 148 DWORD dwConversion, dwSentence; 149 150 pIC = ImmLockIMC(hIMC); 151 if (!pIC) 152 return FALSE; 153 154 dwConversion = (pIC->fdwConversion ^ IME_CMODE_HANJACONVERT); 155 dwSentence = pIC->fdwSentence; 156 ImmUnlockIMC(hIMC); 157 158 ImmSetConversionStatus(hIMC, dwConversion, dwSentence); 159 return TRUE; 160 } 161 162 BOOL APIENTRY Imm32KEnglish(HIMC hIMC) 163 { 164 LPINPUTCONTEXT pIC; 165 DWORD dwConversion, dwSentence; 166 BOOL fOpen; 167 168 pIC = ImmLockIMC(hIMC); 169 if (pIC == NULL) 170 return FALSE; 171 172 dwConversion = (pIC->fdwConversion ^ IME_CMODE_NATIVE); 173 dwSentence = pIC->fdwSentence; 174 ImmSetConversionStatus(hIMC, dwConversion, dwSentence); 175 176 fOpen = ((pIC->fdwConversion & (IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE)) != 0); 177 ImmSetOpenStatus(hIMC, fOpen); 178 179 ImmUnlockIMC(hIMC); 180 return TRUE; 181 } 182 183 BOOL APIENTRY Imm32ProcessHotKey(HWND hWnd, HIMC hIMC, HKL hKL, DWORD dwHotKeyID) 184 { 185 PIMEDPI pImeDpi; 186 BOOL ret; 187 188 if (hIMC && Imm32IsCrossThreadAccess(hIMC)) 189 return FALSE; 190 191 switch (dwHotKeyID) 192 { 193 case IME_CHOTKEY_IME_NONIME_TOGGLE: 194 return Imm32ImeNonImeToggle(hIMC, hKL, hWnd, LANGID_CHINESE_SIMPLIFIED); 195 196 case IME_CHOTKEY_SHAPE_TOGGLE: 197 return Imm32CShapeToggle(hIMC, hKL, hWnd); 198 199 case IME_CHOTKEY_SYMBOL_TOGGLE: 200 return Imm32CSymbolToggle(hIMC, hKL, hWnd); 201 202 case IME_JHOTKEY_CLOSE_OPEN: 203 return Imm32JCloseOpen(hIMC, hKL, hWnd); 204 205 case IME_KHOTKEY_SHAPE_TOGGLE: 206 return Imm32KShapeToggle(hIMC); 207 208 case IME_KHOTKEY_HANJACONVERT: 209 return Imm32KHanjaConvert(hIMC); 210 211 case IME_KHOTKEY_ENGLISH: 212 return Imm32KEnglish(hIMC); 213 214 case IME_THOTKEY_IME_NONIME_TOGGLE: 215 return Imm32ImeNonImeToggle(hIMC, hKL, hWnd, LANGID_CHINESE_TRADITIONAL); 216 217 case IME_THOTKEY_SHAPE_TOGGLE: 218 return Imm32CShapeToggle(hIMC, hKL, hWnd); 219 220 case IME_THOTKEY_SYMBOL_TOGGLE: 221 return Imm32CSymbolToggle(hIMC, hKL, hWnd); 222 223 default: 224 break; 225 } 226 227 if (dwHotKeyID < IME_HOTKEY_PRIVATE_FIRST || IME_HOTKEY_PRIVATE_LAST < dwHotKeyID) 228 return FALSE; 229 230 pImeDpi = ImmLockImeDpi(hKL); 231 if (pImeDpi == NULL) 232 return FALSE; 233 234 ret = (BOOL)pImeDpi->ImeEscape(hIMC, IME_ESC_PRIVATE_HOTKEY, &dwHotKeyID); 235 ImmUnlockImeDpi(pImeDpi); 236 return ret; 237 } 238 239 static BOOL APIENTRY 240 ImmIsUIMessageAW(HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam, BOOL bAnsi) 241 { 242 switch (msg) 243 { 244 case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION: 245 case WM_IME_COMPOSITION: case WM_IME_SETCONTEXT: case WM_IME_NOTIFY: 246 case WM_IME_COMPOSITIONFULL: case WM_IME_SELECT: case WM_IME_SYSTEM: 247 break; 248 default: 249 return FALSE; 250 } 251 252 if (!hWndIME) 253 return TRUE; 254 255 if (bAnsi) 256 SendMessageA(hWndIME, msg, wParam, lParam); 257 else 258 SendMessageW(hWndIME, msg, wParam, lParam); 259 260 return TRUE; 261 } 262 263 /*********************************************************************** 264 * ImmIsUIMessageA (IMM32.@) 265 */ 266 BOOL WINAPI ImmIsUIMessageA(HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam) 267 { 268 TRACE("(%p, 0x%X, %p, %p)\n", hWndIME, msg, wParam, lParam); 269 return ImmIsUIMessageAW(hWndIME, msg, wParam, lParam, TRUE); 270 } 271 272 /*********************************************************************** 273 * ImmIsUIMessageW (IMM32.@) 274 */ 275 BOOL WINAPI ImmIsUIMessageW(HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam) 276 { 277 TRACE("(%p, 0x%X, %p, %p)\n", hWndIME, msg, wParam, lParam); 278 return ImmIsUIMessageAW(hWndIME, msg, wParam, lParam, FALSE); 279 } 280 281 /*********************************************************************** 282 * ImmGetHotKey(IMM32.@) 283 */ 284 BOOL WINAPI 285 ImmGetHotKey(IN DWORD dwHotKey, OUT LPUINT lpuModifiers, OUT LPUINT lpuVKey, 286 OUT LPHKL lphKL) 287 { 288 TRACE("(0x%lX, %p, %p, %p)\n", dwHotKey, lpuModifiers, lpuVKey, lphKL); 289 if (lpuModifiers && lpuVKey) 290 return NtUserGetImeHotKey(dwHotKey, lpuModifiers, lpuVKey, lphKL); 291 return FALSE; 292 } 293 294 /*********************************************************************** 295 * ImmWINNLSGetIMEHotkey (IMM32.@) 296 */ 297 UINT WINAPI ImmWINNLSGetIMEHotkey(HWND hwndIme) 298 { 299 TRACE("(%p)\n", hwndIme); 300 UNREFERENCED_PARAMETER(hwndIme); 301 return 0; /* This is correct. This function of Windows just returns zero. */ 302 } 303 304 /*********************************************************************** 305 * ImmSimulateHotKey (IMM32.@) 306 */ 307 BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID) 308 { 309 HIMC hIMC; 310 DWORD dwThreadId; 311 HKL hKL; 312 BOOL ret; 313 314 TRACE("(%p, 0x%lX)\n", hWnd, dwHotKeyID); 315 316 hIMC = ImmGetContext(hWnd); 317 dwThreadId = GetWindowThreadProcessId(hWnd, NULL); 318 hKL = GetKeyboardLayout(dwThreadId); 319 ret = Imm32ProcessHotKey(hWnd, hIMC, hKL, dwHotKeyID); 320 ImmReleaseContext(hWnd, hIMC); 321 return ret; 322 } 323 324 /*********************************************************************** 325 * ImmGetVirtualKey (IMM32.@) 326 */ 327 UINT WINAPI ImmGetVirtualKey(HWND hWnd) 328 { 329 HIMC hIMC; 330 LPINPUTCONTEXTDX pIC; 331 UINT ret = VK_PROCESSKEY; 332 333 TRACE("(%p)\n", hWnd); 334 335 hIMC = ImmGetContext(hWnd); 336 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 337 if (!pIC) 338 return ret; 339 340 if (pIC->bNeedsTrans) 341 ret = pIC->nVKey; 342 343 ImmUnlockIMC(hIMC); 344 return ret; 345 } 346 347 /*********************************************************************** 348 * ImmProcessKey(IMM32.@) 349 * ( Undocumented, called from user32.dll ) 350 */ 351 DWORD WINAPI 352 ImmProcessKey(HWND hWnd, HKL hKL, UINT vKey, LPARAM lParam, DWORD dwHotKeyID) 353 { 354 DWORD ret = 0; 355 HIMC hIMC; 356 PIMEDPI pImeDpi; 357 LPINPUTCONTEXTDX pIC; 358 BYTE KeyState[256]; 359 UINT vk; 360 BOOL bUseIme = TRUE, bSkipThisKey = FALSE, bLowWordOnly = FALSE; 361 362 TRACE("(%p, %p, 0x%X, %p, 0x%lX)\n", hWnd, hKL, vKey, lParam, dwHotKeyID); 363 364 hIMC = ImmGetContext(hWnd); 365 pImeDpi = ImmLockImeDpi(hKL); 366 if (pImeDpi) 367 { 368 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 369 if (pIC) 370 { 371 if (LOBYTE(vKey) == VK_PACKET && 372 !(pImeDpi->ImeInfo.fdwProperty & IME_PROP_ACCEPT_WIDE_VKEY)) 373 { 374 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) 375 { 376 bLowWordOnly = TRUE; 377 } 378 else 379 { 380 bUseIme = FALSE; 381 if (pIC->fOpen) 382 bSkipThisKey = TRUE; 383 } 384 } 385 386 if (bUseIme) 387 { 388 if (GetKeyboardState(KeyState)) 389 { 390 vk = (bLowWordOnly ? LOWORD(vKey) : vKey); 391 if (pImeDpi->ImeProcessKey(hIMC, vk, lParam, KeyState)) 392 { 393 pIC->bNeedsTrans = TRUE; 394 pIC->nVKey = vKey; 395 ret |= IPHK_PROCESSBYIME; 396 } 397 } 398 } 399 else if (bSkipThisKey) 400 { 401 ret |= IPHK_SKIPTHISKEY; 402 } 403 404 ImmUnlockIMC(hIMC); 405 } 406 407 ImmUnlockImeDpi(pImeDpi); 408 } 409 410 if (dwHotKeyID != INVALID_HOTKEY_ID) 411 { 412 if (Imm32ProcessHotKey(hWnd, hIMC, hKL, dwHotKeyID)) 413 { 414 if (vKey != VK_KANJI || dwHotKeyID != IME_JHOTKEY_CLOSE_OPEN) 415 ret |= IPHK_HOTKEY; 416 } 417 } 418 419 if (ret & IPHK_PROCESSBYIME) 420 { 421 FIXME("TODO: We have to do something here.\n"); 422 } 423 424 ImmReleaseContext(hWnd, hIMC); 425 return ret; 426 } 427 428 /*********************************************************************** 429 * ImmGenerateMessage(IMM32.@) 430 */ 431 BOOL WINAPI ImmGenerateMessage(HIMC hIMC) 432 { 433 PCLIENTIMC pClientImc; 434 LPINPUTCONTEXT pIC; 435 LPTRANSMSG pMsgs, pTrans = NULL, pItem; 436 HWND hWnd; 437 DWORD dwIndex, dwCount, cbTrans; 438 HIMCC hMsgBuf = NULL; 439 BOOL bAnsi; 440 441 TRACE("(%p)\n", hIMC); 442 443 if (Imm32IsCrossThreadAccess(hIMC)) 444 return FALSE; 445 446 pClientImc = ImmLockClientImc(hIMC); 447 if (pClientImc == NULL) 448 return FALSE; 449 450 bAnsi = !(pClientImc->dwFlags & CLIENTIMC_WIDE); 451 ImmUnlockClientImc(pClientImc); 452 453 pIC = ImmLockIMC(hIMC); 454 if (pIC == NULL) 455 return FALSE; 456 457 dwCount = pIC->dwNumMsgBuf; 458 if (dwCount == 0) 459 goto Quit; 460 461 hMsgBuf = pIC->hMsgBuf; 462 pMsgs = ImmLockIMCC(hMsgBuf); 463 if (pMsgs == NULL) 464 goto Quit; 465 466 cbTrans = dwCount * sizeof(TRANSMSG); 467 pTrans = Imm32HeapAlloc(0, cbTrans); 468 if (pTrans == NULL) 469 goto Quit; 470 471 RtlCopyMemory(pTrans, pMsgs, cbTrans); 472 473 #ifdef IMM_NT3_SUPPORT 474 if (GetWin32ClientInfo()->dwExpWinVer < _WIN32_WINNT_NT4) /* old version (3.x)? */ 475 { 476 LANGID LangID = LANGIDFROMLCID(GetSystemDefaultLCID()); 477 WORD wLang = PRIMARYLANGID(LangID); 478 479 /* translate the messages if Japanese or Korean */ 480 if (wLang == LANG_JAPANESE || 481 (wLang == LANG_KOREAN && NtUserGetAppImeLevel(pIC->hWnd) == 3)) 482 { 483 dwCount = ImmNt3Trans(dwCount, pTrans, hIMC, bAnsi, wLang); 484 } 485 } 486 #endif 487 488 /* send them */ 489 hWnd = pIC->hWnd; 490 pItem = pTrans; 491 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pItem) 492 { 493 if (bAnsi) 494 SendMessageA(hWnd, pItem->message, pItem->wParam, pItem->lParam); 495 else 496 SendMessageW(hWnd, pItem->message, pItem->wParam, pItem->lParam); 497 } 498 499 Quit: 500 if (pTrans) 501 HeapFree(g_hImm32Heap, 0, pTrans); 502 if (hMsgBuf) 503 ImmUnlockIMCC(hMsgBuf); 504 pIC->dwNumMsgBuf = 0; /* done */ 505 ImmUnlockIMC(hIMC); 506 return TRUE; 507 } 508 509 VOID APIENTRY 510 Imm32PostMessages(HWND hwnd, HIMC hIMC, DWORD dwCount, LPTRANSMSG lpTransMsg) 511 { 512 DWORD dwIndex; 513 PCLIENTIMC pClientImc; 514 LPTRANSMSG pNewTransMsg = lpTransMsg, pItem; 515 BOOL bAnsi; 516 517 pClientImc = ImmLockClientImc(hIMC); 518 if (pClientImc == NULL) 519 return; 520 521 bAnsi = !(pClientImc->dwFlags & CLIENTIMC_WIDE); 522 ImmUnlockClientImc(pClientImc); 523 524 #ifdef IMM_NT3_SUPPORT 525 if (GetWin32ClientInfo()->dwExpWinVer < _WIN32_WINNT_NT4) /* old version (3.x)? */ 526 { 527 LANGID LangID = LANGIDFROMLCID(GetSystemDefaultLCID()); 528 WORD Lang = PRIMARYLANGID(LangID); 529 530 /* translate the messages if Japanese or Korean */ 531 if (Lang == LANG_JAPANESE || 532 (Lang == LANG_KOREAN && NtUserGetAppImeLevel(hwnd) == 3)) 533 { 534 DWORD cbTransMsg = dwCount * sizeof(TRANSMSG); 535 pNewTransMsg = Imm32HeapAlloc(0, cbTransMsg); 536 if (pNewTransMsg) 537 { 538 RtlCopyMemory(pNewTransMsg, lpTransMsg, cbTransMsg); 539 dwCount = ImmNt3Trans(dwCount, pNewTransMsg, hIMC, bAnsi, Lang); 540 } 541 else 542 { 543 pNewTransMsg = lpTransMsg; 544 } 545 } 546 } 547 #endif 548 549 /* post them */ 550 pItem = pNewTransMsg; 551 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pItem) 552 { 553 if (bAnsi) 554 PostMessageA(hwnd, pItem->message, pItem->wParam, pItem->lParam); 555 else 556 PostMessageW(hwnd, pItem->message, pItem->wParam, pItem->lParam); 557 } 558 559 #ifdef IMM_NT3_SUPPORT 560 if (pNewTransMsg && pNewTransMsg != lpTransMsg) 561 HeapFree(g_hImm32Heap, 0, pNewTransMsg); 562 #endif 563 } 564 565 /*********************************************************************** 566 * ImmTranslateMessage(IMM32.@) 567 * ( Undocumented, call internally and from user32.dll ) 568 */ 569 BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData) 570 { 571 #define MSG_COUNT 0x100 572 BOOL ret = FALSE; 573 INT kret; 574 LPINPUTCONTEXTDX pIC; 575 PIMEDPI pImeDpi = NULL; 576 LPTRANSMSGLIST pList = NULL; 577 LPTRANSMSG pTransMsg; 578 BYTE abKeyState[256]; 579 HIMC hIMC; 580 HKL hKL; 581 UINT vk; 582 DWORD dwThreadId, dwCount, cbList; 583 WCHAR wch; 584 WORD wChar; 585 586 TRACE("(%p, 0x%X, %p, %p)\n", hwnd, msg, wParam, lKeyData); 587 588 /* filter the message */ 589 switch (msg) 590 { 591 case WM_KEYDOWN: case WM_KEYUP: case WM_SYSKEYDOWN: case WM_SYSKEYUP: 592 break; 593 default: 594 return FALSE; 595 } 596 597 hIMC = ImmGetContext(hwnd); 598 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 599 if (pIC == NULL) 600 { 601 ImmReleaseContext(hwnd, hIMC); 602 return FALSE; 603 } 604 605 if (!pIC->bNeedsTrans) /* is translation needed? */ 606 { 607 /* directly post them */ 608 dwCount = pIC->dwNumMsgBuf; 609 if (dwCount == 0) 610 goto Quit; 611 612 pTransMsg = ImmLockIMCC(pIC->hMsgBuf); 613 if (pTransMsg) 614 { 615 Imm32PostMessages(hwnd, hIMC, dwCount, pTransMsg); 616 ImmUnlockIMCC(pIC->hMsgBuf); 617 ret = TRUE; 618 } 619 pIC->dwNumMsgBuf = 0; /* done */ 620 goto Quit; 621 } 622 pIC->bNeedsTrans = FALSE; /* clear the flag */ 623 624 dwThreadId = GetWindowThreadProcessId(hwnd, NULL); 625 hKL = GetKeyboardLayout(dwThreadId); 626 pImeDpi = ImmLockImeDpi(hKL); 627 if (pImeDpi == NULL) 628 goto Quit; 629 630 if (!GetKeyboardState(abKeyState)) /* get keyboard ON/OFF status */ 631 goto Quit; 632 633 /* convert a virtual key if IME_PROP_KBD_CHAR_FIRST */ 634 vk = pIC->nVKey; 635 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST) 636 { 637 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) 638 { 639 wch = 0; 640 kret = ToUnicode(vk, HIWORD(lKeyData), abKeyState, &wch, 1, 0); 641 if (kret == 1) 642 vk = MAKELONG(LOBYTE(vk), wch); 643 } 644 else 645 { 646 wChar = 0; 647 kret = ToAsciiEx(vk, HIWORD(lKeyData), abKeyState, &wChar, 0, hKL); 648 if (kret > 0) 649 vk = MAKEWORD(vk, wChar); 650 } 651 } 652 653 /* allocate a list */ 654 cbList = offsetof(TRANSMSGLIST, TransMsg) + MSG_COUNT * sizeof(TRANSMSG); 655 pList = Imm32HeapAlloc(0, cbList); 656 if (!pList) 657 goto Quit; 658 659 /* use IME conversion engine and convert the list */ 660 pList->uMsgCount = MSG_COUNT; 661 kret = pImeDpi->ImeToAsciiEx(vk, HIWORD(lKeyData), abKeyState, pList, 0, hIMC); 662 if (kret <= 0) 663 goto Quit; 664 665 /* post them */ 666 if (kret <= MSG_COUNT) 667 { 668 Imm32PostMessages(hwnd, hIMC, kret, pList->TransMsg); 669 ret = TRUE; 670 } 671 else 672 { 673 pTransMsg = ImmLockIMCC(pIC->hMsgBuf); 674 if (pTransMsg == NULL) 675 goto Quit; 676 Imm32PostMessages(hwnd, hIMC, kret, pTransMsg); 677 ImmUnlockIMCC(pIC->hMsgBuf); 678 } 679 680 Quit: 681 if (pList) 682 HeapFree(g_hImm32Heap, 0, pList); 683 ImmUnlockImeDpi(pImeDpi); 684 ImmUnlockIMC(hIMC); 685 ImmReleaseContext(hwnd, hIMC); 686 return ret; 687 #undef MSG_COUNT 688 } 689