Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1455 lines
42 KiB

  1. /**************************************************************************\
  2. * Module Name: context.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Context management routines for imm32 dll
  7. *
  8. * History:
  9. * 03-Jan-1996 wkwok Created
  10. \**************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #define IMCC_ALLOC_TOOLARGE 0x1000
  14. /**************************************************************************\
  15. * ImmCreateContext
  16. *
  17. * Creates and initializes an input context.
  18. *
  19. * 17-Jan-1996 wkwok Created
  20. \**************************************************************************/
  21. HIMC WINAPI ImmCreateContext(void)
  22. {
  23. PCLIENTIMC pClientImc;
  24. HIMC hImc = NULL_HIMC;
  25. if (!IS_IME_ENABLED()) {
  26. return NULL_HIMC;
  27. }
  28. pClientImc = ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
  29. if (pClientImc != NULL) {
  30. hImc = NtUserCreateInputContext((ULONG_PTR)pClientImc);
  31. if (hImc == NULL_HIMC) {
  32. ImmLocalFree(pClientImc);
  33. return NULL_HIMC;
  34. }
  35. InitImcCrit(pClientImc);
  36. pClientImc->dwImeCompatFlags = (DWORD)NtUserGetThreadState(UserThreadStateImeCompatFlags);
  37. }
  38. return hImc;
  39. }
  40. /**************************************************************************\
  41. * ImmDestroyContext
  42. *
  43. * Destroys an input context.
  44. *
  45. * 17-Jan-1996 wkwok Created
  46. \**************************************************************************/
  47. BOOL WINAPI ImmDestroyContext(
  48. HIMC hImc)
  49. {
  50. if (!IS_IME_ENABLED()) {
  51. return FALSE;
  52. }
  53. if (GetInputContextThread(hImc) != GetCurrentThreadId()) {
  54. RIPMSG1(RIP_WARNING,
  55. "ImmDestroyContext: Invalid input context access %lx.", hImc);
  56. return FALSE;
  57. }
  58. return DestroyInputContext(hImc, GetKeyboardLayout(0), FALSE);
  59. }
  60. /**************************************************************************\
  61. * ImmAssociateContext
  62. *
  63. * Associates an input context to the specified window handle.
  64. *
  65. * 17-Jan-1996 wkwok Created
  66. \**************************************************************************/
  67. HIMC WINAPI ImmAssociateContext(
  68. HWND hWnd,
  69. HIMC hImc)
  70. {
  71. PWND pWnd;
  72. HIMC hPrevImc;
  73. AIC_STATUS Status;
  74. // early out
  75. if (!IS_IME_ENABLED()) {
  76. return NULL_HIMC;
  77. }
  78. if ((pWnd = ValidateHwnd(hWnd)) == (PWND)NULL) {
  79. RIPMSG1(RIP_WARNING,
  80. "ImmAssociateContext: invalid window handle %x", hWnd);
  81. return NULL_HIMC;
  82. }
  83. if (hImc != NULL_HIMC &&
  84. GetInputContextThread(hImc) != GetCurrentThreadId()) {
  85. RIPMSG1(RIP_WARNING,
  86. "ImmAssociateContext: Invalid input context access %lx.", hImc);
  87. return NULL_HIMC;
  88. }
  89. /*
  90. * associate to the same input context, do nothing.
  91. */
  92. if (pWnd->hImc == hImc)
  93. return hImc;
  94. hPrevImc = KHIMC_TO_HIMC(pWnd->hImc);
  95. Status = NtUserAssociateInputContext(hWnd, hImc, 0);
  96. switch (Status) {
  97. case AIC_FOCUSCONTEXTCHANGED:
  98. if (IsWndEqual(NtUserQueryWindow(hWnd, WindowFocusWindow), hWnd)) {
  99. ImmSetActiveContext(hWnd, hPrevImc, FALSE);
  100. ImmSetActiveContext(hWnd, hImc, TRUE);
  101. }
  102. // Fall thru.
  103. case AIC_SUCCESS:
  104. return hPrevImc;
  105. default:
  106. return NULL_HIMC;
  107. }
  108. }
  109. BOOL WINAPI ImmAssociateContextEx(
  110. HWND hWnd,
  111. HIMC hImc,
  112. DWORD dwFlag)
  113. {
  114. HWND hWndFocus;
  115. PWND pWndFocus;
  116. HIMC hImcFocusOld;
  117. AIC_STATUS Status;
  118. if (!IS_IME_ENABLED()) {
  119. return FALSE;
  120. }
  121. hWndFocus = NtUserQueryWindow(hWnd, WindowFocusWindow);
  122. if (hImc != NULL_HIMC && !(dwFlag & IACE_DEFAULT) &&
  123. GetInputContextThread(hImc) != GetCurrentThreadId()) {
  124. RIPMSG1(RIP_WARNING,
  125. "ImmAssociateContextEx: Invalid input context access %lx.", hImc);
  126. return FALSE;
  127. }
  128. if ((pWndFocus = ValidateHwnd(hWndFocus)) != (PWND)NULL)
  129. hImcFocusOld = KHIMC_TO_HIMC(pWndFocus->hImc);
  130. else
  131. hImcFocusOld = NULL_HIMC;
  132. Status = NtUserAssociateInputContext(hWnd, hImc, dwFlag);
  133. switch (Status) {
  134. case AIC_FOCUSCONTEXTCHANGED:
  135. if ((pWndFocus = ValidateHwnd(hWndFocus)) != (PWND)NULL) {
  136. hImc = KHIMC_TO_HIMC(pWndFocus->hImc);
  137. if (hImc != hImcFocusOld) {
  138. ImmSetActiveContext(hWndFocus, hImcFocusOld, FALSE);
  139. ImmSetActiveContext(hWndFocus, hImc, TRUE);
  140. };
  141. };
  142. // Fall thru.
  143. case AIC_SUCCESS:
  144. return TRUE;
  145. default:
  146. return FALSE;
  147. }
  148. }
  149. /**************************************************************************\
  150. * ImmGetContext
  151. *
  152. * Retrieves the input context that is associated to the given window.
  153. *
  154. * 17-Jan-1996 wkwok Created
  155. \**************************************************************************/
  156. HIMC WINAPI ImmGetContext(
  157. HWND hWnd)
  158. {
  159. if ( hWnd == NULL ) {
  160. RIPMSG1(RIP_WARNING,
  161. "ImmGetContext: invalid window handle %x", hWnd);
  162. return NULL_HIMC;
  163. }
  164. /*
  165. * for non-NULL hWnd, ImmGetSaveContext will do the
  166. * validation and "same process" checking.
  167. */
  168. return ImmGetSaveContext( hWnd, IGSC_WINNLSCHECK );
  169. }
  170. /**************************************************************************\
  171. * ImmGetSaveContext
  172. *
  173. * Retrieves the input context that is associated to the given window.
  174. *
  175. * 15-Mar-1996 wkwok Created
  176. \**************************************************************************/
  177. HIMC ImmGetSaveContext(
  178. HWND hWnd,
  179. DWORD dwFlag)
  180. {
  181. HIMC hRetImc;
  182. PCLIENTIMC pClientImc;
  183. PWND pwnd;
  184. if (!IS_IME_ENABLED()) {
  185. return NULL_HIMC;
  186. }
  187. if (hWnd == NULL) {
  188. /*
  189. * Retrieves the default input context of current thread.
  190. */
  191. hRetImc = (HIMC)NtUserGetThreadState(UserThreadStateDefaultInputContext);
  192. }
  193. else {
  194. /*
  195. * Retrieves the input context associated to the given window.
  196. */
  197. if ((pwnd = ValidateHwnd(hWnd)) == (PWND)NULL) {
  198. RIPMSG1(RIP_WARNING,
  199. "ImmGetSaveContext: invalid window handle %x", hWnd);
  200. return NULL_HIMC;
  201. }
  202. /*
  203. * Don't allow other process to access input context
  204. */
  205. if (!TestWindowProcess(pwnd)) {
  206. RIPMSG0(RIP_WARNING,
  207. "ImmGetSaveContext: can not get input context of other process");
  208. return NULL_HIMC;
  209. }
  210. hRetImc = KHIMC_TO_HIMC(pwnd->hImc);
  211. if (hRetImc == NULL_HIMC && (dwFlag & IGSC_DEFIMCFALLBACK)) {
  212. /*
  213. * hWnd associated with NULL input context, retrieves the
  214. * default input context of the hWnd's creator thread.
  215. */
  216. hRetImc = (HIMC)NtUserQueryWindow(hWnd, WindowDefaultInputContext);
  217. }
  218. }
  219. pClientImc = ImmLockClientImc(hRetImc);
  220. if (pClientImc == NULL)
  221. return NULL_HIMC;
  222. if ((dwFlag & IGSC_WINNLSCHECK) && TestICF(pClientImc, IMCF_WINNLSDISABLE))
  223. hRetImc = NULL_HIMC;
  224. ImmUnlockClientImc(pClientImc);
  225. return hRetImc;
  226. }
  227. /**************************************************************************\
  228. * ImmReleaseContext
  229. *
  230. * Releases the input context retrieved by ImmGetContext().
  231. *
  232. * 17-Jan-1996 wkwok Created
  233. \**************************************************************************/
  234. BOOL WINAPI ImmReleaseContext(
  235. HWND hWnd,
  236. HIMC hImc)
  237. {
  238. UNREFERENCED_PARAMETER(hWnd);
  239. UNREFERENCED_PARAMETER(hImc);
  240. return TRUE;
  241. }
  242. /**************************************************************************\
  243. * ImmSetActiveContext
  244. *
  245. * 15-Mar-1996 wkwok Created
  246. \**************************************************************************/
  247. BOOL ImmSetActiveContext(
  248. HWND hWnd,
  249. HIMC hImc,
  250. BOOL fActivate)
  251. {
  252. PCLIENTIMC pClientImc;
  253. PINPUTCONTEXT pInputContext;
  254. PIMEDPI pImeDpi;
  255. DWORD dwISC;
  256. HIMC hSaveImc;
  257. HWND hDefImeWnd;
  258. DWORD dwOpenStatus = 0;
  259. DWORD dwConversion = 0;
  260. #ifdef DEBUG
  261. PWND pWnd = ValidateHwnd(hWnd);
  262. if (pWnd != NULL && GETPTI(pWnd) != PtiCurrent()) {
  263. RIPMSG1(RIP_WARNING, "hWnd (=%lx) is not of current thread.", hWnd);
  264. }
  265. #endif
  266. if (!IS_IME_ENABLED()) {
  267. return FALSE;
  268. }
  269. dwISC = ISC_SHOWUIALL;
  270. pClientImc = ImmLockClientImc(hImc);
  271. if (!fActivate) {
  272. if (pClientImc != NULL)
  273. ClrICF(pClientImc, IMCF_ACTIVE);
  274. goto NotifySetActive;
  275. }
  276. if (hImc == NULL_HIMC) {
  277. hSaveImc = ImmGetSaveContext(hWnd, IGSC_DEFIMCFALLBACK);
  278. pInputContext = ImmLockIMC(hSaveImc);
  279. if (pInputContext != NULL) {
  280. pInputContext->hWnd = hWnd;
  281. ImmUnlockIMC(hSaveImc);
  282. }
  283. goto NotifySetActive;
  284. }
  285. /*
  286. * Non-NULL input context, window handle have to be updated.
  287. */
  288. if (pClientImc == NULL)
  289. return FALSE;
  290. pInputContext = ImmLockIMC(hImc);
  291. if (pInputContext == NULL) {
  292. ImmUnlockClientImc(pClientImc);
  293. return FALSE;
  294. }
  295. pInputContext->hWnd = hWnd;
  296. SetICF(pClientImc, IMCF_ACTIVE);
  297. #ifdef LATER
  298. // Do uNumLangVKey checking later
  299. #endif
  300. if (pInputContext->fdw31Compat & F31COMPAT_MCWHIDDEN)
  301. dwISC = ISC_SHOWUIALL - ISC_SHOWUICOMPOSITIONWINDOW;
  302. dwOpenStatus = (DWORD)pInputContext->fOpen;
  303. dwConversion = pInputContext->fdwConversion;
  304. ImmUnlockIMC(hImc);
  305. NotifySetActive:
  306. #ifdef CUAS_ENABLE
  307. {
  308. HKL hKL = GetKeyboardLayout(0);
  309. //
  310. // call msctfime's ImeSetActiveContextAlways() no matter what is the cuurnet
  311. // hkl if we in Cicero Unaware App Support.
  312. //
  313. if (IS_CICERO_ENABLED_AND_NOT16BIT()) {
  314. Internal_CtfImeSetActiveContextAlways(hImc, fActivate, hWnd, hKL);
  315. }
  316. }
  317. #endif // CUAS_ENABLE
  318. #if !defined(CUAS_ENABLE)
  319. pImeDpi = ImmLockImeDpi(GetKeyboardLayout(0));
  320. if (pImeDpi != NULL) {
  321. (*pImeDpi->pfn.ImeSetActiveContext)(hImc, fActivate);
  322. ImmUnlockImeDpi(pImeDpi);
  323. }
  324. #else
  325. //
  326. // msctfime's SetFocus might be change hKL to Cicero.
  327. //
  328. // call IME's ImeSetActiveContext().
  329. //
  330. {
  331. HKL hKL;
  332. pImeDpi = ImmLockImeDpi(hKL=GetKeyboardLayout(0));
  333. if (pImeDpi != NULL) {
  334. if (IS_IME_KBDLAYOUT(hKL)) {
  335. (*pImeDpi->pfn.ImeSetActiveContext)(hImc, fActivate);
  336. }
  337. ImmUnlockImeDpi(pImeDpi);
  338. }
  339. }
  340. #endif
  341. /*
  342. * Notify UI
  343. */
  344. if (IsWindow(hWnd)) {
  345. SendMessage(hWnd, WM_IME_SETCONTEXT, fActivate, dwISC);
  346. /*
  347. * send notify to shell / keyboard driver
  348. */
  349. if ( fActivate )
  350. NtUserNotifyIMEStatus( hWnd, dwOpenStatus, dwConversion );
  351. }
  352. else if (!fActivate) {
  353. /*
  354. * Because hWnd is not there (maybe destroyed), we send
  355. * WM_IME_SETCONTEXT to the default IME window.
  356. */
  357. if ((hDefImeWnd = ImmGetDefaultIMEWnd(NULL)) != NULL) {
  358. SendMessage(hDefImeWnd, WM_IME_SETCONTEXT, fActivate, dwISC);
  359. }
  360. else {
  361. RIPMSG0(RIP_WARNING,
  362. "ImmSetActiveContext: can't send WM_IME_SETCONTEXT(FALSE).");
  363. }
  364. }
  365. #ifdef DEBUG
  366. else {
  367. RIPMSG0(RIP_WARNING,
  368. "ImmSetActiveContext: can't send WM_IME_SETCONTEXT(TRUE).");
  369. }
  370. #endif
  371. #ifdef LATER
  372. // Implements ProcessIMCEvent() later.
  373. #endif
  374. if (pClientImc != NULL)
  375. ImmUnlockClientImc(pClientImc);
  376. return TRUE;
  377. }
  378. /**************************************************************************\
  379. * ModeSaver related routines
  380. *
  381. * Dec-1998 hiroyama Created
  382. \**************************************************************************/
  383. PIMEMODESAVER GetImeModeSaver(
  384. PINPUTCONTEXT pInputContext,
  385. HKL hkl)
  386. {
  387. PIMEMODESAVER pModeSaver;
  388. USHORT langId = PRIMARYLANGID(HKL_TO_LANGID(hkl));
  389. for (pModeSaver = pInputContext->pImeModeSaver; pModeSaver; pModeSaver = pModeSaver->next) {
  390. if (pModeSaver->langId == langId) {
  391. break;
  392. }
  393. }
  394. if (pModeSaver == NULL) {
  395. TAGMSG1(DBGTAG_IMM, "GetImeModeSaver: creating ModeSaver for langId=%04x", langId);
  396. pModeSaver = ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof *pModeSaver);
  397. if (pModeSaver == NULL) {
  398. RIPMSG1(RIP_WARNING, "GetImeModeSaver: failed to create ModeSaver for langId=%04x", langId);
  399. return NULL;
  400. }
  401. pModeSaver->langId = langId;
  402. pModeSaver->next = pInputContext->pImeModeSaver;
  403. pInputContext->pImeModeSaver = pModeSaver;
  404. }
  405. return pModeSaver;
  406. }
  407. VOID DestroyImeModeSaver(
  408. PINPUTCONTEXT pInputContext)
  409. {
  410. PIMEMODESAVER pModeSaver = pInputContext->pImeModeSaver;
  411. //
  412. // Destroy mode savers
  413. //
  414. while (pModeSaver) {
  415. PIMEMODESAVER pNext = pModeSaver->next;
  416. PIMEPRIVATEMODESAVER pPrivateModeSaver = pModeSaver->pImePrivateModeSaver;
  417. //
  418. // Destroy private mode savers
  419. //
  420. while (pPrivateModeSaver) {
  421. PIMEPRIVATEMODESAVER pPrivateNext = pPrivateModeSaver->next;
  422. ImmLocalFree(pPrivateModeSaver);
  423. pPrivateModeSaver = pPrivateNext;
  424. }
  425. ImmLocalFree(pModeSaver);
  426. pModeSaver = pNext;
  427. }
  428. pInputContext->pImeModeSaver = NULL;
  429. }
  430. PIMEPRIVATEMODESAVER GetImePrivateModeSaver(
  431. PIMEMODESAVER pImeModeSaver,
  432. HKL hkl)
  433. {
  434. PIMEPRIVATEMODESAVER pPrivateModeSaver;
  435. for (pPrivateModeSaver = pImeModeSaver->pImePrivateModeSaver; pPrivateModeSaver; pPrivateModeSaver = pPrivateModeSaver->next) {
  436. if (pPrivateModeSaver->hkl == hkl) {
  437. break;
  438. }
  439. }
  440. if (pPrivateModeSaver == NULL) {
  441. TAGMSG1(DBGTAG_IMM, "GetImePrivateModeSaver: creating private mode saver for hkl=%08x", hkl);
  442. pPrivateModeSaver = ImmLocalAlloc(0, sizeof *pPrivateModeSaver);
  443. if (pPrivateModeSaver == NULL) {
  444. RIPMSG1(RIP_WARNING, "GetImePrivateModeSaver: failed to create PrivateModeSaver for hlk=%08x", hkl);
  445. return NULL;
  446. }
  447. pPrivateModeSaver->hkl = hkl;
  448. pPrivateModeSaver->fdwSentence = 0;
  449. pPrivateModeSaver->next = pImeModeSaver->pImePrivateModeSaver;
  450. pImeModeSaver->pImePrivateModeSaver = pPrivateModeSaver;
  451. }
  452. return pPrivateModeSaver;
  453. }
  454. BOOL SavePrivateMode(
  455. PINPUTCONTEXT pInputContext,
  456. PIMEMODESAVER pImeModeSaver,
  457. HKL hkl)
  458. {
  459. PIMEPRIVATEMODESAVER pPrivateModeSaver = GetImePrivateModeSaver(pImeModeSaver, hkl);
  460. if (pPrivateModeSaver == NULL) {
  461. return FALSE;
  462. }
  463. //
  464. // Save private sentence mode
  465. //
  466. pPrivateModeSaver->fdwSentence = pInputContext->fdwSentence & 0xffff0000;
  467. return TRUE;
  468. }
  469. BOOL RestorePrivateMode(
  470. PINPUTCONTEXT pInputContext,
  471. PIMEMODESAVER pImeModeSaver,
  472. HKL hkl)
  473. {
  474. PIMEPRIVATEMODESAVER pPrivateModeSaver = GetImePrivateModeSaver(pImeModeSaver, hkl);
  475. if (pPrivateModeSaver == NULL) {
  476. return FALSE;
  477. }
  478. //
  479. // Restore private sentence mode
  480. //
  481. ImmAssert(LOWORD(pPrivateModeSaver->fdwSentence) == 0);
  482. pInputContext->fdwSentence |= pPrivateModeSaver->fdwSentence;
  483. return TRUE;
  484. }
  485. /**************************************************************************\
  486. * CreateInputContext
  487. *
  488. * 20-Feb-1996 wkwok Created
  489. \**************************************************************************/
  490. BOOL CreateInputContext(
  491. HIMC hImc,
  492. HKL hKL,
  493. BOOL fCanCallImeSelect)
  494. {
  495. PIMEDPI pImeDpi;
  496. PCLIENTIMC pClientImc;
  497. DWORD dwPrivateDataSize;
  498. DWORD fdwInitConvMode = 0; // do it later
  499. BOOL fInitOpen = FALSE; // do it later
  500. PINPUTCONTEXT pInputContext;
  501. PCOMPOSITIONSTRING pCompStr;
  502. PCANDIDATEINFO pCandInfo;
  503. PGUIDELINE pGuideLine;
  504. int i;
  505. pInputContext = ImmLockIMC(hImc);
  506. if (!pInputContext) {
  507. RIPMSG1(RIP_WARNING, "CreateContext: Lock hIMC %x failure", hImc);
  508. goto CrIMCLockErrOut;
  509. }
  510. /*
  511. * Initialize the member of INPUTCONTEXT
  512. */
  513. pInputContext->hCompStr = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
  514. if (!pInputContext->hCompStr) {
  515. RIPMSG0(RIP_WARNING, "CreateContext: Create hCompStr failure");
  516. goto CrIMCUnlockIMC;
  517. }
  518. pCompStr = (PCOMPOSITIONSTRING)ImmLockIMCC(pInputContext->hCompStr);
  519. if (!pCompStr) {
  520. RIPMSG1(RIP_WARNING,
  521. "CreateContext: Lock hCompStr %x failure", pInputContext->hCompStr);
  522. goto CrIMCFreeCompStr;
  523. }
  524. pCompStr->dwSize = sizeof(COMPOSITIONSTRING);
  525. ImmUnlockIMCC(pInputContext->hCompStr);
  526. pInputContext->hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO));
  527. if (!pInputContext->hCandInfo) {
  528. RIPMSG0(RIP_WARNING, "CreateContext: Create hCandInfo failure");
  529. goto CrIMCFreeCompStr;
  530. }
  531. pCandInfo = (PCANDIDATEINFO)ImmLockIMCC(pInputContext->hCandInfo);
  532. if (!pCandInfo) {
  533. RIPMSG1(RIP_WARNING,
  534. "CreateContext: Lock hCandInfo %x failure", pInputContext->hCandInfo);
  535. goto CrIMCFreeCandInfo;
  536. }
  537. pCandInfo->dwSize = sizeof(CANDIDATEINFO);
  538. ImmUnlockIMCC(pInputContext->hCandInfo);
  539. pInputContext->hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE));
  540. if (!pInputContext->hGuideLine) {
  541. RIPMSG0(RIP_WARNING, "CreateContext: Create hGuideLine failure");
  542. goto CrIMCFreeCandInfo;
  543. }
  544. pGuideLine = (PGUIDELINE)ImmLockIMCC(pInputContext->hGuideLine);
  545. if (!pGuideLine) {
  546. RIPMSG1(RIP_WARNING,
  547. "CreateContext: Lock hGuideLine %x failure", pInputContext->hGuideLine);
  548. goto CrIMCFreeGuideLine;
  549. }
  550. pGuideLine->dwSize = sizeof(GUIDELINE);
  551. ImmUnlockIMCC(pInputContext->hGuideLine);
  552. pInputContext->hMsgBuf = ImmCreateIMCC(sizeof(UINT));
  553. if (!pInputContext->hMsgBuf) {
  554. RIPMSG0(RIP_WARNING, "CreateContext: Create hMsgBuf failure");
  555. goto CrIMCFreeGuideLine;
  556. }
  557. pInputContext->dwNumMsgBuf = 0;
  558. pInputContext->fOpen = fInitOpen;
  559. pInputContext->fdwConversion = fdwInitConvMode;
  560. pInputContext->fdwSentence = 0;
  561. for (i = 0; i < 4; i++) {
  562. pInputContext->cfCandForm[i].dwIndex = (DWORD)(-1);
  563. }
  564. pImeDpi = ImmLockImeDpi(hKL);
  565. if (pImeDpi != NULL) {
  566. if ((pClientImc = ImmLockClientImc(hImc)) == NULL) {
  567. RIPMSG0(RIP_WARNING, "CreateContext: ImmLockClientImc() failure");
  568. ImmUnlockImeDpi(pImeDpi);
  569. goto CrIMCFreeMsgBuf;
  570. }
  571. /*
  572. * Unicode based IME expects an Uncode based input context.
  573. */
  574. if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)
  575. SetICF(pClientImc, IMCF_UNICODE);
  576. pClientImc->dwCodePage = IMECodePage(pImeDpi);
  577. ImmUnlockClientImc(pClientImc);
  578. dwPrivateDataSize = pImeDpi->ImeInfo.dwPrivateDataSize;
  579. }
  580. else {
  581. dwPrivateDataSize = sizeof(UINT);
  582. }
  583. pInputContext->hPrivate = ImmCreateIMCC(dwPrivateDataSize);
  584. if (!pInputContext->hPrivate) {
  585. RIPMSG0(RIP_WARNING, "CreateContext: Create hPrivate failure");
  586. ImmUnlockImeDpi(pImeDpi);
  587. goto CrIMCFreeMsgBuf;
  588. }
  589. pInputContext->pImeModeSaver = NULL;
  590. #ifdef CUAS_ENABLE
  591. /*
  592. * Create Cicero Input Context.
  593. */
  594. CtfImmTIMCreateInputContext(hImc);
  595. #endif // CUAS_ENABLE
  596. #if !defined(CUAS_ENABLE)
  597. if (pImeDpi != NULL) {
  598. if (fCanCallImeSelect) {
  599. (*pImeDpi->pfn.ImeSelect)(hImc, TRUE);
  600. }
  601. ImmUnlockImeDpi(pImeDpi);
  602. }
  603. #else
  604. if (pImeDpi != NULL) {
  605. if (fCanCallImeSelect) {
  606. if (IS_IME_KBDLAYOUT(hKL)) {
  607. (*pImeDpi->pfn.ImeSelect)(hImc, TRUE);
  608. }
  609. else if (IS_CICERO_ENABLED_AND_NOT16BIT()) {
  610. (*pImeDpi->pfn.CtfImeSelectEx)(hImc, TRUE, hKL);
  611. }
  612. }
  613. if ((pClientImc = ImmLockClientImc(hImc)) != NULL) {
  614. pClientImc->SelectedHKL = hKL;
  615. ImmUnlockClientImc(pClientImc);
  616. }
  617. ImmUnlockImeDpi(pImeDpi);
  618. }
  619. #endif
  620. ImmUnlockIMC(hImc);
  621. return TRUE;
  622. /*
  623. * context failure case
  624. */
  625. CrIMCFreeMsgBuf:
  626. ImmDestroyIMCC(pInputContext->hMsgBuf);
  627. CrIMCFreeGuideLine:
  628. ImmDestroyIMCC(pInputContext->hGuideLine);
  629. CrIMCFreeCandInfo:
  630. ImmDestroyIMCC(pInputContext->hCandInfo);
  631. CrIMCFreeCompStr:
  632. ImmDestroyIMCC(pInputContext->hCompStr);
  633. CrIMCUnlockIMC:
  634. ImmUnlockIMC(hImc);
  635. CrIMCLockErrOut:
  636. return FALSE;
  637. }
  638. /**************************************************************************\
  639. * DestroyInputContext
  640. *
  641. * 20-Feb-1996 wkwok Created
  642. \**************************************************************************/
  643. BOOL DestroyInputContext(
  644. HIMC hImc,
  645. HKL hKL,
  646. BOOL bTerminate)
  647. {
  648. PINPUTCONTEXT pInputContext;
  649. PIMEDPI pImeDpi;
  650. PIMC pImc;
  651. PCLIENTIMC pClientImc;
  652. if (!IS_IME_ENABLED()) {
  653. return FALSE;
  654. }
  655. if (hImc == NULL_HIMC) {
  656. RIPMSG0(RIP_VERBOSE, "DestroyInputContext: hImc is NULL.");
  657. return FALSE;
  658. }
  659. pImc = HMValidateHandle((HANDLE)hImc, TYPE_INPUTCONTEXT);
  660. /*
  661. * Cannot destroy input context from other thread.
  662. */
  663. if (pImc == NULL || GETPTI(pImc) != PtiCurrent())
  664. return FALSE;
  665. /*
  666. * We are destroying this hImc so we don't bother calling
  667. * ImmLockClientImc() to get the pClientImc. Instead, we
  668. * reference the pImc->dwClientImcData directly and call
  669. * InterlockedIncrement(&pClientImc->cLockObj) right after
  670. * several quick checks.
  671. */
  672. pClientImc = (PCLIENTIMC)pImc->dwClientImcData;
  673. if (pClientImc == NULL) {
  674. /*
  675. * Client side Imc has not been initialzed yet.
  676. * We simply destroy this input context from kernel.
  677. */
  678. if (bTerminate) {
  679. /*
  680. * If called from THREAD_DETACH, we don't
  681. * have to destroy kernel side Input Context.
  682. */
  683. return TRUE;
  684. }
  685. return NtUserDestroyInputContext(hImc);
  686. }
  687. if (TestICF(pClientImc, IMCF_DEFAULTIMC) && !bTerminate) {
  688. /*
  689. * Cannot destroy default input context unless the
  690. * thread is terminating.
  691. */
  692. return FALSE;
  693. }
  694. if (TestICF(pClientImc, IMCF_INDESTROY)) {
  695. /*
  696. * This hImc is being destroyed. Returns as success.
  697. */
  698. return TRUE;
  699. }
  700. /*
  701. * Time to lock up the pClientImc.
  702. */
  703. InterlockedIncrement(&pClientImc->cLockObj);
  704. if (pClientImc->hInputContext != NULL) {
  705. pInputContext = ImmLockIMC(hImc);
  706. if (!pInputContext) {
  707. RIPMSG1(RIP_WARNING, "DestroyContext: Lock hImc %x failure", hImc);
  708. ImmUnlockClientImc(pClientImc);
  709. return FALSE;
  710. }
  711. #ifdef CUAS_ENABLE
  712. /*
  713. * Destroy Cicero Input Context.
  714. */
  715. CtfImmTIMDestroyInputContext(hImc);
  716. #endif // CUAS_ENABLE
  717. #if !defined(CUAS_ENABLE)
  718. pImeDpi = ImmLockImeDpi(hKL);
  719. if (pImeDpi != NULL) {
  720. (*pImeDpi->pfn.ImeSelect)(hImc, FALSE);
  721. ImmUnlockImeDpi(pImeDpi);
  722. }
  723. #else
  724. if (pClientImc->SelectedHKL == hKL) {
  725. pImeDpi = ImmLockImeDpi(hKL);
  726. if (pImeDpi != NULL) {
  727. if (IS_IME_KBDLAYOUT(hKL)) {
  728. (*pImeDpi->pfn.ImeSelect)(hImc, FALSE);
  729. }
  730. else if (IS_CICERO_ENABLED_AND_NOT16BIT()) {
  731. (*pImeDpi->pfn.CtfImeSelectEx)(hImc, FALSE, hKL);
  732. }
  733. ImmUnlockImeDpi(pImeDpi);
  734. }
  735. pClientImc->SelectedHKL = NULL;
  736. }
  737. #endif
  738. ImmDestroyIMCC(pInputContext->hPrivate);
  739. ImmDestroyIMCC(pInputContext->hMsgBuf);
  740. ImmDestroyIMCC(pInputContext->hGuideLine);
  741. ImmDestroyIMCC(pInputContext->hCandInfo);
  742. ImmDestroyIMCC(pInputContext->hCompStr);
  743. /*
  744. * Free all ImeModeSaver.
  745. */
  746. DestroyImeModeSaver(pInputContext);
  747. ImmUnlockIMC(hImc);
  748. }
  749. SetICF(pClientImc, IMCF_INDESTROY);
  750. /*
  751. * ImmUnlockClientImc() will free up the pClientImc
  752. * when InterlockedDecrement(&pClientImc->cLockObj)
  753. * reaches 0.
  754. */
  755. ImmUnlockClientImc(pClientImc);
  756. return (bTerminate) ? TRUE : NtUserDestroyInputContext(hImc);
  757. }
  758. /**************************************************************************\
  759. * SelectInputContext
  760. *
  761. * 20-Feb-1996 wkwok Created
  762. \**************************************************************************/
  763. VOID SelectInputContext(
  764. HKL hSelKL,
  765. HKL hUnSelKL,
  766. HIMC hImc)
  767. {
  768. PIMEDPI pSelImeDpi, pUnSelImeDpi;
  769. PCLIENTIMC pClientImc;
  770. PINPUTCONTEXT pInputContext;
  771. DWORD dwSelPriv = 0, dwUnSelPriv = 0, dwSize;
  772. HIMCC hImcc;
  773. PCOMPOSITIONSTRING pCompStr;
  774. PCANDIDATEINFO pCandInfo;
  775. PGUIDELINE pGuideLine;
  776. BOOLEAN fLogFontInited;
  777. #ifdef CUAS_ENABLE
  778. BOOLEAN fUseImeSaverForSelIme = TRUE;
  779. BOOLEAN fUseImeSaverForUnSelIme = TRUE;
  780. #endif
  781. TAGMSG3(DBGTAG_IMM, "SelectInputContext: called for sel=%08p unsel=%08p hImc=%08p",
  782. hSelKL, hUnSelKL, hImc);
  783. pClientImc = ImmLockClientImc(hImc);
  784. if (pClientImc == NULL) {
  785. RIPMSG0(RIP_VERBOSE, "SelectInputContext: cannot lock client Imc. Bailing out.");
  786. return;
  787. }
  788. pSelImeDpi = ImmLockImeDpi(hSelKL);
  789. if (hSelKL != hUnSelKL) {
  790. /*
  791. * If those new sel and unsel do no match but
  792. * somehow SelectInput is called, that means
  793. * we should initialize the input contex again
  794. * without dumping the old information.
  795. */
  796. pUnSelImeDpi = ImmLockImeDpi(hUnSelKL);
  797. } else {
  798. pUnSelImeDpi = NULL;
  799. }
  800. if (pSelImeDpi != NULL) {
  801. /*
  802. * According to private memory size of the two layout, we decide
  803. * whether we nee to reallocate this memory block
  804. */
  805. dwSelPriv = pSelImeDpi->ImeInfo.dwPrivateDataSize;
  806. /*
  807. * Setup the code page of the newly selected IME.
  808. */
  809. pClientImc->dwCodePage = IMECodePage(pSelImeDpi);
  810. }
  811. else {
  812. pClientImc->dwCodePage = CP_ACP;
  813. }
  814. if (pUnSelImeDpi != NULL)
  815. dwUnSelPriv = pUnSelImeDpi->ImeInfo.dwPrivateDataSize;
  816. dwSelPriv = max(dwSelPriv, sizeof(UINT));
  817. dwUnSelPriv = max(dwUnSelPriv, sizeof(UINT));
  818. /*
  819. * Unselect the input context.
  820. */
  821. #if !defined(CUAS_ENABLE)
  822. if (pUnSelImeDpi != NULL)
  823. (*pUnSelImeDpi->pfn.ImeSelect)(hImc, FALSE);
  824. #else
  825. if (pClientImc->SelectedHKL == hUnSelKL) {
  826. if (pUnSelImeDpi != NULL) {
  827. if (IS_IME_KBDLAYOUT(hUnSelKL)) {
  828. (*pUnSelImeDpi->pfn.ImeSelect)(hImc, FALSE);
  829. }
  830. else if (IS_CICERO_ENABLED_AND_NOT16BIT()) {
  831. (*pUnSelImeDpi->pfn.CtfImeSelectEx)(hImc, FALSE, hUnSelKL);
  832. }
  833. }
  834. pClientImc->SelectedHKL = NULL;
  835. }
  836. //
  837. // don't use a mode saver for non IME or non CUAS.
  838. //
  839. if (CtfImmIsTextFrameServiceDisabled()) {
  840. if (IS_CICERO_ENABLED_AND_NOT16BIT()) {
  841. if (!IS_IME_KBDLAYOUT(hSelKL))
  842. fUseImeSaverForSelIme = FALSE;
  843. if (!IS_IME_KBDLAYOUT(hUnSelKL))
  844. fUseImeSaverForUnSelIme = FALSE;
  845. }
  846. }
  847. #endif
  848. /*
  849. * Reinitialize the client side input context for the selected layout.
  850. */
  851. if ((pInputContext = InternalImmLockIMC(hImc, FALSE)) != NULL) {
  852. DWORD fdwOldConversion = pInputContext->fdwConversion;
  853. DWORD fdwOldSentence = pInputContext->fdwSentence;
  854. BOOL fOldOpen = pInputContext->fOpen;
  855. PIMEMODESAVER pUnSelModeSaver, pSelModeSaver;
  856. const DWORD fdwConvPreserve = IME_CMODE_EUDC;
  857. fLogFontInited = ((pInputContext->fdwInit & INIT_LOGFONT) == INIT_LOGFONT);
  858. if (TestICF(pClientImc, IMCF_UNICODE) && pSelImeDpi != NULL &&
  859. !(pSelImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)) {
  860. /*
  861. * Check if there is any LOGFONT to be converted.
  862. */
  863. if (fLogFontInited) {
  864. LOGFONTA LogFontA;
  865. LFontWtoLFontA(&pInputContext->lfFont.W, &LogFontA);
  866. RtlCopyMemory(&pInputContext->lfFont.A, &LogFontA, sizeof(LOGFONTA));
  867. }
  868. ClrICF(pClientImc, IMCF_UNICODE);
  869. }
  870. else if (!TestICF(pClientImc, IMCF_UNICODE) && pSelImeDpi != NULL &&
  871. (pSelImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)) {
  872. /*
  873. * Check if there is any LOGFONT to be converted.
  874. */
  875. if (fLogFontInited) {
  876. LOGFONTW LogFontW;
  877. LFontAtoLFontW(&pInputContext->lfFont.A, &LogFontW);
  878. RtlCopyMemory(&pInputContext->lfFont.W, &LogFontW, sizeof(LOGFONTW));
  879. }
  880. SetICF(pClientImc, IMCF_UNICODE);
  881. }
  882. /*
  883. * hPrivate
  884. */
  885. if (dwUnSelPriv != dwSelPriv) {
  886. hImcc = ImmReSizeIMCC(pInputContext->hPrivate, dwSelPriv);
  887. if (hImcc) {
  888. pInputContext->hPrivate = hImcc;
  889. }
  890. else {
  891. RIPMSG1(RIP_WARNING,
  892. "SelectContext: resize hPrivate %lX failure",
  893. pInputContext->hPrivate);
  894. ImmDestroyIMCC(pInputContext->hPrivate);
  895. pInputContext->hPrivate = ImmCreateIMCC(dwSelPriv);
  896. }
  897. }
  898. /*
  899. * hMsgBuf
  900. */
  901. dwSize = ImmGetIMCCSize(pInputContext->hMsgBuf);
  902. if (ImmGetIMCCLockCount(pInputContext->hMsgBuf) != 0 ||
  903. dwSize > IMCC_ALLOC_TOOLARGE) {
  904. RIPMSG0(RIP_WARNING, "SelectContext: create new hMsgBuf");
  905. ImmDestroyIMCC(pInputContext->hMsgBuf);
  906. pInputContext->hMsgBuf = ImmCreateIMCC(sizeof(UINT));
  907. pInputContext->dwNumMsgBuf = 0;
  908. }
  909. /*
  910. * hGuideLine
  911. */
  912. dwSize = ImmGetIMCCSize(pInputContext->hGuideLine);
  913. if (ImmGetIMCCLockCount(pInputContext->hGuideLine) != 0 ||
  914. dwSize < sizeof(GUIDELINE) || dwSize > IMCC_ALLOC_TOOLARGE) {
  915. RIPMSG0(RIP_WARNING, "SelectContext: create new hGuideLine");
  916. ImmDestroyIMCC(pInputContext->hGuideLine);
  917. pInputContext->hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE));
  918. pGuideLine = (PGUIDELINE)ImmLockIMCC(pInputContext->hGuideLine);
  919. if (pGuideLine != NULL) {
  920. pGuideLine->dwSize = sizeof(GUIDELINE);
  921. ImmUnlockIMCC(pInputContext->hGuideLine);
  922. }
  923. }
  924. /*
  925. * hCandInfo
  926. */
  927. dwSize = ImmGetIMCCSize(pInputContext->hCandInfo);
  928. if (ImmGetIMCCLockCount(pInputContext->hCandInfo) != 0 ||
  929. dwSize < sizeof(CANDIDATEINFO) || dwSize > IMCC_ALLOC_TOOLARGE) {
  930. RIPMSG0(RIP_WARNING, "SelectContext: create new hCandInfo");
  931. ImmDestroyIMCC(pInputContext->hCandInfo);
  932. pInputContext->hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO));
  933. pCandInfo = (PCANDIDATEINFO)ImmLockIMCC(pInputContext->hCandInfo);
  934. if (pCandInfo != NULL) {
  935. pCandInfo->dwSize = sizeof(CANDIDATEINFO);
  936. ImmUnlockIMCC(pInputContext->hCandInfo);
  937. }
  938. }
  939. /*
  940. * hCompStr
  941. */
  942. dwSize = ImmGetIMCCSize(pInputContext->hCompStr);
  943. if (ImmGetIMCCLockCount(pInputContext->hCompStr) != 0 ||
  944. dwSize < sizeof(COMPOSITIONSTRING) || dwSize > IMCC_ALLOC_TOOLARGE) {
  945. RIPMSG0(RIP_WARNING, "SelectContext: create new hCompStr");
  946. ImmDestroyIMCC(pInputContext->hCompStr);
  947. pInputContext->hCompStr = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
  948. pCompStr = (PCOMPOSITIONSTRING)ImmLockIMCC(pInputContext->hCompStr);
  949. if (pCompStr != NULL) {
  950. pCompStr->dwSize = sizeof(COMPOSITIONSTRING);
  951. ImmUnlockIMCC(pInputContext->hCompStr);
  952. }
  953. }
  954. //
  955. // Save and restore the IME modes when the primary
  956. // language changes.
  957. //
  958. #if !defined(CUAS_ENABLE)
  959. if (pUnSelImeDpi)
  960. #else
  961. if (pUnSelImeDpi && fUseImeSaverForUnSelIme)
  962. #endif
  963. {
  964. //
  965. // If UnSelKL is IME, get ModeSaver per language.
  966. //
  967. pUnSelModeSaver = GetImeModeSaver(pInputContext, hUnSelKL);
  968. TAGMSG1(DBGTAG_IMM, "pUnSelModeSaver=%p", pUnSelModeSaver);
  969. if (pUnSelModeSaver) {
  970. //
  971. // Firstly save the private sentence mode per IME.
  972. //
  973. SavePrivateMode(pInputContext, pUnSelModeSaver, hUnSelKL);
  974. }
  975. }
  976. else {
  977. pUnSelModeSaver = NULL;
  978. }
  979. #if !defined(CUAS_ENABLE)
  980. if (pSelImeDpi)
  981. #else
  982. if (pSelImeDpi && fUseImeSaverForSelIme)
  983. #endif
  984. {
  985. //
  986. // If SelKL is IME, get is ModeSaver per language.
  987. //
  988. pSelModeSaver = GetImeModeSaver(pInputContext, hSelKL);
  989. TAGMSG1(DBGTAG_IMM, "pSelImeDpi. pImeModeSaver=%p", pSelModeSaver);
  990. }
  991. else {
  992. pSelModeSaver = NULL;
  993. }
  994. //
  995. // If the primary language of KL changes, save the current mode
  996. // and restore the previous modes of new language.
  997. //
  998. if (pUnSelModeSaver != pSelModeSaver) {
  999. //
  1000. // If old KL is IME, save the current conversion, sentence and open mode.
  1001. //
  1002. if (pUnSelModeSaver) {
  1003. pUnSelModeSaver->fOpen = (pInputContext->fOpen != FALSE);
  1004. //
  1005. // Don't have to save the preserved bits for conversion mode.
  1006. //
  1007. pUnSelModeSaver->fdwConversion = pInputContext->fdwConversion & ~fdwConvPreserve;
  1008. pUnSelModeSaver->fdwSentence = LOWORD(pInputContext->fdwSentence);
  1009. pUnSelModeSaver->fdwInit = pInputContext->fdwInit;
  1010. }
  1011. //
  1012. // If new KL is IME, restore the previous conversion, sentence and open mode.
  1013. //
  1014. if (pSelModeSaver) {
  1015. if (pInputContext->fdwDirty & IMSS_INIT_OPEN) {
  1016. //
  1017. // HKL change may be kicked from private IME hotkey, and
  1018. // a user wants it opened when switched.
  1019. //
  1020. pInputContext->fOpen = TRUE;
  1021. pInputContext->fdwDirty &= ~IMSS_INIT_OPEN;
  1022. } else {
  1023. pInputContext->fOpen = pSelModeSaver->fOpen;
  1024. }
  1025. //
  1026. // Some bits are preserved across the languages.
  1027. //
  1028. pInputContext->fdwConversion &= fdwConvPreserve;
  1029. ImmAssert((pSelModeSaver->fdwConversion & fdwConvPreserve) == 0);
  1030. pInputContext->fdwConversion |= pSelModeSaver->fdwConversion & ~fdwConvPreserve;
  1031. ImmAssert(HIWORD(pSelModeSaver->fdwSentence) == 0);
  1032. pInputContext->fdwSentence = pSelModeSaver->fdwSentence;
  1033. pInputContext->fdwInit = pSelModeSaver->fdwInit;
  1034. }
  1035. }
  1036. if (pSelModeSaver) {
  1037. //
  1038. // Restore the private sentence mode per IME.
  1039. //
  1040. RestorePrivateMode(pInputContext, pSelModeSaver, hSelKL);
  1041. }
  1042. /*
  1043. * Select the input context.
  1044. */
  1045. #if !defined(CUAS_ENABLE)
  1046. if (pSelImeDpi != NULL)
  1047. (*pSelImeDpi->pfn.ImeSelect)(hImc, TRUE);
  1048. #else
  1049. if (pSelImeDpi != NULL) {
  1050. if (IS_IME_KBDLAYOUT(hSelKL)) {
  1051. (*pSelImeDpi->pfn.ImeSelect)(hImc, TRUE);
  1052. }
  1053. else if (IS_CICERO_ENABLED_AND_NOT16BIT()) {
  1054. (*pSelImeDpi->pfn.CtfImeSelectEx)(hImc, TRUE, hSelKL);
  1055. }
  1056. pClientImc->SelectedHKL = hSelKL;
  1057. }
  1058. #endif
  1059. //
  1060. // Set the dirty bits so that IMM can send notifications later.
  1061. // See SendNotificatonProc.
  1062. //
  1063. pInputContext->fdwDirty = 0;
  1064. if (pInputContext->fOpen != fOldOpen) {
  1065. pInputContext->fdwDirty |= IMSS_UPDATE_OPEN;
  1066. }
  1067. if (pInputContext->fdwConversion != fdwOldConversion) {
  1068. pInputContext->fdwDirty |= IMSS_UPDATE_CONVERSION;
  1069. }
  1070. if (pInputContext->fdwSentence != fdwOldSentence) {
  1071. pInputContext->fdwDirty |= IMSS_UPDATE_SENTENCE;
  1072. }
  1073. TAGMSG4(DBGTAG_IMM, "fOpen:%d fdwConv:%08x fdwSent:%08x dirty:%02x",
  1074. pInputContext->fOpen, pInputContext->fdwConversion, pInputContext->fdwSentence, pInputContext->fdwDirty);
  1075. ImmUnlockIMC(hImc);
  1076. }
  1077. else {
  1078. //
  1079. // To keep the backward compatibility,
  1080. // select the input context here.
  1081. //
  1082. #if !defined(CUAS_ENABLE)
  1083. if (pSelImeDpi != NULL)
  1084. (*pSelImeDpi->pfn.ImeSelect)(hImc, TRUE);
  1085. #else
  1086. if (pSelImeDpi != NULL) {
  1087. if (IS_IME_KBDLAYOUT(hSelKL)) {
  1088. (*pSelImeDpi->pfn.ImeSelect)(hImc, TRUE);
  1089. }
  1090. else if (IS_CICERO_ENABLED_AND_NOT16BIT()) {
  1091. (*pSelImeDpi->pfn.CtfImeSelectEx)(hImc, TRUE, hSelKL);
  1092. }
  1093. pClientImc->SelectedHKL = hSelKL;
  1094. }
  1095. #endif
  1096. }
  1097. ImmUnlockImeDpi(pUnSelImeDpi);
  1098. ImmUnlockImeDpi(pSelImeDpi);
  1099. ImmUnlockClientImc(pClientImc);
  1100. }
  1101. BOOL SendNotificationProc(
  1102. HIMC hImc,
  1103. LPARAM lParam)
  1104. {
  1105. PINPUTCONTEXT pInputContext = ImmLockIMC(hImc);
  1106. UNREFERENCED_PARAMETER(lParam);
  1107. if (pInputContext != NULL) {
  1108. HWND hwnd = pInputContext->hWnd;
  1109. if (IsWindow(hwnd)) {
  1110. TAGMSG2(DBGTAG_IMM, "SendNotificationProc: updating hImc=%08x dirty=%04x",
  1111. hImc, pInputContext->fdwDirty);
  1112. if (pInputContext->fdwDirty & IMSS_UPDATE_OPEN) {
  1113. SendMessageW(hwnd, WM_IME_NOTIFY, IMN_SETOPENSTATUS, 0);
  1114. }
  1115. if (pInputContext->fdwDirty & IMSS_UPDATE_CONVERSION) {
  1116. SendMessageW(hwnd, WM_IME_NOTIFY, IMN_SETCONVERSIONMODE, 0);
  1117. }
  1118. if (pInputContext->fdwDirty & (IMSS_UPDATE_OPEN | IMSS_UPDATE_CONVERSION)) {
  1119. NtUserNotifyIMEStatus(hwnd, pInputContext->fOpen, pInputContext->fdwConversion);
  1120. }
  1121. if (pInputContext->fdwDirty & IMSS_UPDATE_SENTENCE) {
  1122. SendMessageW(hwnd, WM_IME_NOTIFY, IMN_SETSENTENCEMODE, 0);
  1123. }
  1124. }
  1125. pInputContext->fdwDirty = 0;
  1126. }
  1127. return TRUE;
  1128. }
  1129. VOID ImmSendNotification(
  1130. BOOL fForProcess)
  1131. {
  1132. DWORD dwThreadId;
  1133. if (fForProcess) {
  1134. dwThreadId = -1;
  1135. } else {
  1136. dwThreadId = 0;
  1137. }
  1138. ImmEnumInputContext(dwThreadId, (IMCENUMPROC)SendNotificationProc, 0);
  1139. }
  1140. /**************************************************************************\
  1141. * ImmEnumInputContext
  1142. *
  1143. * 20-Feb-1996 wkwok Created
  1144. \**************************************************************************/
  1145. BOOL WINAPI ImmEnumInputContext(
  1146. DWORD idThread,
  1147. IMCENUMPROC lpfn,
  1148. LPARAM lParam)
  1149. {
  1150. UINT i;
  1151. UINT cHimc;
  1152. HIMC *phimcT;
  1153. HIMC *phimcFirst;
  1154. BOOL fSuccess = TRUE;
  1155. /*
  1156. * Get the himc list. It is returned in a block of memory
  1157. * allocated with ImmLocalAlloc.
  1158. */
  1159. if ((cHimc = BuildHimcList(idThread, &phimcFirst)) == 0) {
  1160. return FALSE;
  1161. }
  1162. /*
  1163. * Loop through the input contexts, call the function pointer back for
  1164. * each one. End loop if either FALSE is returned or the end-of-list is
  1165. * reached.
  1166. */
  1167. phimcT = phimcFirst;
  1168. for (i = 0; i < cHimc; i++) {
  1169. if (RevalidateHimc(*phimcT)) {
  1170. if (!(fSuccess = (*lpfn)(*phimcT, lParam)))
  1171. break;
  1172. }
  1173. phimcT++;
  1174. }
  1175. /*
  1176. * Free up buffer and return status - TRUE if entire list was enumerated,
  1177. * FALSE otherwise.
  1178. */
  1179. ImmLocalFree(phimcFirst);
  1180. return fSuccess;
  1181. }
  1182. /**************************************************************************\
  1183. * BuildHimcList
  1184. *
  1185. * 20-Feb-1996 wkwok Created
  1186. \**************************************************************************/
  1187. DWORD BuildHimcList(
  1188. DWORD idThread,
  1189. HIMC **pphimcFirst)
  1190. {
  1191. UINT cHimc;
  1192. HIMC *phimcFirst;
  1193. NTSTATUS Status;
  1194. int cTries;
  1195. /*
  1196. * Allocate a buffer to hold the names.
  1197. */
  1198. cHimc = 64;
  1199. phimcFirst = ImmLocalAlloc(0, cHimc * sizeof(HIMC));
  1200. if (phimcFirst == NULL)
  1201. return 0;
  1202. Status = NtUserBuildHimcList(idThread, cHimc, phimcFirst, &cHimc);
  1203. /*
  1204. * If the buffer wasn't big enough, reallocate
  1205. * the buffer and try again.
  1206. */
  1207. cTries = 0;
  1208. while (Status == STATUS_BUFFER_TOO_SMALL) {
  1209. ImmLocalFree(phimcFirst);
  1210. /*
  1211. * If we can't seem to get it right,
  1212. * call it quits
  1213. */
  1214. if (cTries++ == 10)
  1215. return 0;
  1216. phimcFirst = ImmLocalAlloc(0, cHimc * sizeof(HIMC));
  1217. if (phimcFirst == NULL)
  1218. return 0;
  1219. Status = NtUserBuildHimcList(idThread, cHimc, phimcFirst, &cHimc);
  1220. }
  1221. if (!NT_SUCCESS(Status) || cHimc == 0) {
  1222. ImmLocalFree(phimcFirst);
  1223. return 0;
  1224. }
  1225. *pphimcFirst = phimcFirst;
  1226. return cHimc;
  1227. }