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.

1641 lines
46 KiB

  1. /**************************************************************************\
  2. * Module Name: imectl.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * IME Window Handling Routines
  7. *
  8. * History:
  9. * 20-Dec-1995 wkwok
  10. \**************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include <intlshar.h>
  14. #define LATE_CREATEUI 1
  15. CONST WCHAR szIndicDLL[] = L"indicdll.dll";
  16. FARPROC gpfnGetIMEMenuItemData = NULL;
  17. BOOL IMEIndicatorGetMenuIDData(PUINT puMenuID, PDWORD pdwData);
  18. /*
  19. * Local Routines.
  20. */
  21. LONG ImeWndCreateHandler(PIMEUI, LPCREATESTRUCT);
  22. void ImeWndDestroyHandler(PIMEUI);
  23. LRESULT ImeSystemHandler(PIMEUI, UINT, WPARAM, LPARAM);
  24. LONG ImeSelectHandler(PIMEUI, UINT, WPARAM, LPARAM);
  25. LRESULT ImeControlHandler(PIMEUI, UINT, WPARAM, LPARAM, BOOL);
  26. LRESULT ImeSetContextHandler(PIMEUI, UINT, WPARAM, LPARAM);
  27. LRESULT ImeNotifyHandler(PIMEUI, UINT, WPARAM, LPARAM);
  28. HWND CreateIMEUI(PIMEUI, HKL);
  29. VOID DestroyIMEUI(PIMEUI);
  30. LRESULT SendMessageToUI(PIMEUI, UINT, WPARAM, LPARAM, BOOL);
  31. VOID SendOpenStatusNotify(PIMEUI, HWND, BOOL);
  32. VOID ImeSetImc(PIMEUI, HIMC);
  33. VOID FocusSetIMCContext(HWND, BOOL);
  34. BOOL ImeBroadCastMsg(PIMEUI, UINT, WPARAM, LPARAM);
  35. VOID ImeMarkUsedContext(HWND, HIMC);
  36. BOOL ImeIsUsableContext(HWND, HIMC);
  37. BOOL GetIMEShowStatus(void);
  38. /*
  39. * Common macros for IME UI, HKL and IMC handlings
  40. */
  41. #define GETHKL(pimeui) (KHKL_TO_HKL(pimeui->hKL))
  42. #define SETHKL(pimeui, hkl) (pimeui->hKL=(hkl))
  43. #define GETIMC(pimeui) (KHIMC_TO_HIMC(pimeui->hIMC))
  44. #define SETIMC(pimeui, himc) (ImeSetImc(pimeui, KHIMC_TO_HIMC(himc)))
  45. #define GETUI(pimeui) (KHWND_TO_HWND(pimeui->hwndUI))
  46. #define SETUI(pimeui, hwndui) (pimeui->hwndUI=(hwndui))
  47. LOOKASIDE ImeUILookaside;
  48. /***************************************************************************\
  49. * NtUserBroadcastImeShowStatusChange(), NtUserCheckImeShowStatusInThread()
  50. *
  51. * Stub for kernel mode routines
  52. *
  53. \***************************************************************************/
  54. _inline void NtUserBroadcastImeShowStatusChange(HWND hwndDefIme, BOOL fShow)
  55. {
  56. NtUserCallHwndParamLock(hwndDefIme, fShow, SFI_XXXBROADCASTIMESHOWSTATUSCHANGE);
  57. }
  58. _inline void NtUserCheckImeShowStatusInThread(HWND hwndDefIme)
  59. {
  60. NtUserCallHwndLock(hwndDefIme, SFI_XXXCHECKIMESHOWSTATUSINTHREAD);
  61. }
  62. /***************************************************************************\
  63. * ImeWndProc
  64. *
  65. * WndProc for IME class
  66. *
  67. * History:
  68. \***************************************************************************/
  69. LRESULT APIENTRY ImeWndProcWorker(
  70. PWND pwnd,
  71. UINT message,
  72. WPARAM wParam,
  73. LPARAM lParam,
  74. DWORD fAnsi)
  75. {
  76. HWND hwnd = HWq(pwnd);
  77. PIMEUI pimeui;
  78. static BOOL fInit = TRUE;
  79. CheckLock(pwnd);
  80. VALIDATECLASSANDSIZE(pwnd, FNID_IME);
  81. INITCONTROLLOOKASIDE(&ImeUILookaside, IMEUI, spwnd, 8);
  82. #ifdef CUAS_ENABLE
  83. if (IS_CICERO_ENABLED()) {
  84. LRESULT lRet;
  85. lRet = fpCtfImmDispatchDefImeMessage(hwnd, message, wParam, lParam);
  86. if (lRet)
  87. return lRet;
  88. }
  89. #endif
  90. /*
  91. * If the control is not interested in this message,
  92. * pass it to DefWindowProc.
  93. */
  94. if (!FWINDOWMSG(message, FNID_IME))
  95. return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
  96. /*
  97. * Get the pimeui for the given window now since we will use it a lot in
  98. * various handlers. This was stored using SetWindowLong(hwnd,0,pimeui) when
  99. * we initially created the IME control.
  100. */
  101. pimeui = ((PIMEWND)pwnd)->pimeui;
  102. if (pimeui == NULL) {
  103. /*
  104. * Further processing not needed
  105. */
  106. RIPMSG0(RIP_WARNING, "ImeWndProcWorker: pimeui == NULL\n");
  107. return 0L;
  108. }
  109. /*
  110. * This is necessary to avoid recursion call from IME UI.
  111. */
  112. UserAssert(pimeui->nCntInIMEProc >= 0);
  113. if (pimeui->nCntInIMEProc > 0) {
  114. TAGMSG5(DBGTAG_IMM, "ImeWndProcWorker: Recursive for pwnd=%08p, msg=%08x, wp=%08x, lp=%08x, fAnsi=%d\n",
  115. pwnd, message, wParam, lParam, fAnsi);
  116. switch (message) {
  117. case WM_IME_SYSTEM:
  118. switch (wParam) {
  119. case IMS_ISACTIVATED:
  120. case IMS_SETOPENSTATUS:
  121. // case IMS_SETCONVERSIONSTATUS:
  122. case IMS_SETSOFTKBDONOFF:
  123. /*
  124. * Because these will not be pass to UI.
  125. * We can do it.
  126. */
  127. break;
  128. default:
  129. return 0L;
  130. }
  131. break;
  132. case WM_IME_STARTCOMPOSITION:
  133. case WM_IME_ENDCOMPOSITION:
  134. case WM_IME_COMPOSITION:
  135. case WM_IME_SETCONTEXT:
  136. #if !defined(CUAS_ENABLE)
  137. case WM_IME_NOTIFY:
  138. #endif
  139. case WM_IME_CONTROL:
  140. case WM_IME_COMPOSITIONFULL:
  141. case WM_IME_SELECT:
  142. case WM_IME_CHAR:
  143. case WM_IME_REQUEST:
  144. return 0L;
  145. #ifdef CUAS_ENABLE
  146. case WM_IME_NOTIFY:
  147. if (wParam >= IMN_PRIVATE &&
  148. ! IS_IME_KBDLAYOUT(GETHKL(pimeui)) && IS_CICERO_ENABLED()) {
  149. //
  150. // CUAS: IMN_PRIVATE always call UI window.
  151. //
  152. break;
  153. }
  154. return 0L;
  155. #endif
  156. default:
  157. return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
  158. }
  159. }
  160. if (TestWF(pwnd, WFINDESTROY) || TestWF(pwnd, WFDESTROYED)) {
  161. switch (message) {
  162. case WM_DESTROY:
  163. case WM_NCDESTROY:
  164. case WM_FINALDESTROY:
  165. break;
  166. default:
  167. RIPMSG1(RIP_WARNING, "ImeWndProcWorker: message %x is sent to destroyed window.", message);
  168. return 0L;
  169. }
  170. }
  171. switch (message) {
  172. case WM_ERASEBKGND:
  173. return (LONG)TRUE;
  174. case WM_PAINT:
  175. break;
  176. case WM_CREATE:
  177. return ImeWndCreateHandler(pimeui, (LPCREATESTRUCT)lParam);
  178. case WM_DESTROY:
  179. /*
  180. * We are destroying the IME window, destroy
  181. * any UI window that it owns.
  182. */
  183. ImeWndDestroyHandler(pimeui);
  184. break;
  185. case WM_NCDESTROY:
  186. case WM_FINALDESTROY:
  187. if (pimeui) {
  188. Unlock(&pimeui->spwnd);
  189. FreeLookasideEntry(&ImeUILookaside, pimeui);
  190. }
  191. NtUserSetWindowFNID(hwnd, FNID_CLEANEDUP_BIT);
  192. goto CallDWP;
  193. case WM_IME_SYSTEM:
  194. UserAssert(pimeui->spwnd == pwnd);
  195. return ImeSystemHandler(pimeui, message, wParam, lParam);
  196. case WM_IME_SELECT:
  197. return ImeSelectHandler(pimeui, message, wParam, lParam);
  198. case WM_IME_CONTROL:
  199. return ImeControlHandler(pimeui, message, wParam, lParam, fAnsi);
  200. case WM_IME_SETCONTEXT:
  201. return ImeSetContextHandler(pimeui, message, wParam, lParam);
  202. case WM_IME_NOTIFY:
  203. return ImeNotifyHandler(pimeui, message, wParam, lParam);
  204. case WM_IME_REQUEST:
  205. return 0;
  206. case WM_IME_COMPOSITION:
  207. case WM_IME_ENDCOMPOSITION:
  208. case WM_IME_STARTCOMPOSITION:
  209. return SendMessageToUI(pimeui, message, wParam, lParam, fAnsi);
  210. default:
  211. CallDWP:
  212. return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
  213. }
  214. return 0L;
  215. }
  216. LRESULT WINAPI ImeWndProcA(
  217. HWND hwnd,
  218. UINT message,
  219. WPARAM wParam,
  220. LPARAM lParam)
  221. {
  222. PWND pwnd;
  223. if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
  224. return (0L);
  225. }
  226. return ImeWndProcWorker(pwnd, message, wParam, lParam, TRUE);
  227. }
  228. LRESULT WINAPI ImeWndProcW(
  229. HWND hwnd,
  230. UINT message,
  231. WPARAM wParam,
  232. LPARAM lParam)
  233. {
  234. PWND pwnd;
  235. if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
  236. return (0L);
  237. }
  238. return ImeWndProcWorker(pwnd, message, wParam, lParam, FALSE);
  239. }
  240. LONG ImeWndCreateHandler(
  241. PIMEUI pimeui,
  242. LPCREATESTRUCT lpcs)
  243. {
  244. PWND pwndParent;
  245. HIMC hImc;
  246. PWND pwndIme = pimeui->spwnd;
  247. #if _DBG
  248. static DWORD dwFirstWinlogonThreadId;
  249. #endif
  250. #if _DBG
  251. /*
  252. * For Winlogon, only the first thread can have IME processing.
  253. */
  254. if (gfLogonProcess) {
  255. UserAssert(dwFirstWinLogonThreadId == 0);
  256. dwFirstWinlogonThreadId = GetCurrentThreadId();
  257. }
  258. #endif
  259. if (!TestWF(pwndIme, WFPOPUP) || !TestWF(pwndIme, WFDISABLED)) {
  260. RIPMSG0(RIP_WARNING, "IME window should have WS_POPUP and WS_DISABLE!!");
  261. return -1L;
  262. }
  263. /*
  264. * Check with parent window, if exists, try to get IMC.
  265. * If this is top level window, wait for first WM_IME_SETCONTEXT.
  266. */
  267. if ((pwndParent = ValidateHwndNoRip(lpcs->hwndParent)) != NULL) {
  268. hImc = KHIMC_TO_HIMC(pwndParent->hImc);
  269. if (hImc != NULL_HIMC && ImeIsUsableContext(HWq(pwndIme), hImc)) {
  270. /*
  271. * Store it for later use.
  272. */
  273. SETIMC(pimeui, hImc);
  274. }
  275. else {
  276. SETIMC(pimeui, NULL_HIMC);
  277. }
  278. }
  279. else {
  280. SETIMC(pimeui, NULL_HIMC);
  281. }
  282. /*
  283. * Initialize status window show state
  284. * The status window is not open yet.
  285. */
  286. pimeui->fShowStatus = 0;
  287. pimeui->nCntInIMEProc = 0;
  288. pimeui->fActivate = 0;
  289. pimeui->fDestroy = 0;
  290. pimeui->hwndIMC = NULL;
  291. pimeui->hKL = THREAD_HKL();
  292. pimeui->fCtrlShowStatus = TRUE;
  293. #if !defined(CUAS_ENABLE) // move to LoadThreadLayout
  294. /*
  295. * Load up the IME DLL of current keyboard layout.
  296. */
  297. fpImmLoadIME(GETHKL(pimeui));
  298. #ifdef LATE_CREATEUI
  299. SETUI(pimeui, NULL);
  300. #else
  301. SETUI(pimeui, CreateIMEUI(pimeui, pimeui->hKL));
  302. #endif
  303. #else
  304. // Cicero
  305. pimeui->dwPrevToolbarStatus = 0;
  306. #endif // CUAS_ENABLE // move to LoadThreadLayout
  307. return 0L;
  308. }
  309. void ImeWndDestroyHandler(
  310. PIMEUI pimeui)
  311. {
  312. DestroyIMEUI(pimeui);
  313. }
  314. #ifdef CUAS_ENABLE
  315. VOID
  316. CtfLoadThreadLayout(
  317. PIMEUI pimeui)
  318. {
  319. #if 1
  320. /*
  321. * Cicero Unaware Support. Activate Thread Input Manager.
  322. */
  323. fpCtfImmTIMActivate(pimeui->hKL);
  324. /*
  325. * Load up the IME DLL of current keyboard layout.
  326. */
  327. pimeui->hKL = THREAD_HKL(); // Reload thread hKL if TIM activated, hKL changed.
  328. fpImmLoadIME(GETHKL(pimeui));
  329. #ifdef LATE_CREATEUI
  330. SETUI(pimeui, NULL);
  331. #else
  332. SETUI(pimeui, CreateIMEUI(pimeui, pimeui->hKL));
  333. #endif
  334. #else
  335. UNREFERENCED_PARAMETER(pimeui);
  336. #endif
  337. }
  338. #endif // CUAS_ENABLE
  339. /***************************************************************************\
  340. * GetSystemModulePath
  341. *
  342. \***************************************************************************/
  343. #define SYSTEM_DIR 0
  344. #define WINDOWS_DIR 1
  345. UINT GetSystemModulePath(DWORD dir, LPWSTR psz, DWORD cch, CONST WCHAR* pszModuleName)
  346. {
  347. UINT uRet;
  348. if (! psz || ! pszModuleName || cch == 0) {
  349. return 0;
  350. }
  351. if (! pszModuleName[0]) {
  352. return 0;
  353. }
  354. if (dir == SYSTEM_DIR) {
  355. uRet = GetSystemDirectory(psz, cch);
  356. }
  357. else {
  358. uRet = GetSystemWindowsDirectory(psz, cch);
  359. }
  360. if (uRet >= cch) {
  361. uRet = 0;
  362. psz[0] = L'\0';
  363. }
  364. else if (uRet) {
  365. UINT uLen;
  366. if (psz[uRet - 1] != L'\\') {
  367. psz[uRet] = L'\\';
  368. uRet++;
  369. }
  370. if (uRet >= cch) {
  371. uRet = 0;
  372. psz[0] = L'\0';
  373. }
  374. else {
  375. uLen = wcslen(pszModuleName);
  376. if (cch - uRet > uLen) {
  377. wcsncpy(&psz[uRet],
  378. pszModuleName,
  379. cch - uRet);
  380. uRet += uLen;
  381. }
  382. else {
  383. uRet = 0;
  384. psz[0] = L'\0';
  385. }
  386. }
  387. }
  388. return uRet;
  389. }
  390. /***************************************************************************\
  391. * ImeRunHelp
  392. *
  393. * Display Help file (HLP and CHM).
  394. *
  395. * History:
  396. * 27-Oct-98 Hiroyama
  397. \***************************************************************************/
  398. void ImeRunHelp(LPWSTR wszHelpFile)
  399. {
  400. static const WCHAR wszHelpFileExt[] = L".HLP";
  401. UINT cchLen = wcslen(wszHelpFile);
  402. if (cchLen > 4 && _wcsicmp(wszHelpFile + cchLen - 4, wszHelpFileExt) == 0) {
  403. #ifdef FYI
  404. WinHelpW(NULL, wszHelpFile, HELP_CONTENTS, 0);
  405. #else
  406. WinHelpW(NULL, wszHelpFile, HELP_FINDER, 0);
  407. #endif
  408. } else {
  409. //
  410. // If it's not HLP file, try to run hh.exe, HTML based
  411. // help tool. It should be in %windir%\hh.exe.
  412. //
  413. static const WCHAR wszHH[] = L"hh.exe ";
  414. WCHAR wszCmdLine[MAX_PATH * 2];
  415. DWORD idProcess;
  416. STARTUPINFO StartupInfo;
  417. PROCESS_INFORMATION ProcessInformation;
  418. UINT i;
  419. WCHAR wszAppName[MAX_PATH + 1];
  420. if (! (i=GetSystemModulePath(WINDOWS_DIR, wszAppName, ARRAYSIZE(wszAppName), wszHH)))
  421. {
  422. return;
  423. }
  424. if (i + cchLen >= ARRAYSIZE(wszCmdLine))
  425. {
  426. return;
  427. }
  428. wcsncpy(wszCmdLine,
  429. wszAppName,
  430. ARRAYSIZE(wszCmdLine));
  431. wcsncpy(&wszCmdLine[i],
  432. wszHelpFile,
  433. ARRAYSIZE(wszCmdLine) - i);
  434. /*
  435. * Launch HTML Help.
  436. */
  437. RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
  438. StartupInfo.cb = sizeof(StartupInfo);
  439. StartupInfo.wShowWindow = SW_SHOW;
  440. StartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_FORCEONFEEDBACK;
  441. TAGMSG2(DBGTAG_IMM, "Invoking help with '%S %S'", wszAppName, wszHelpFile);
  442. idProcess = (DWORD)CreateProcessW(wszAppName, wszCmdLine,
  443. NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &StartupInfo,
  444. &ProcessInformation);
  445. if (idProcess) {
  446. WaitForInputIdle(ProcessInformation.hProcess, 10000);
  447. NtClose(ProcessInformation.hProcess);
  448. NtClose(ProcessInformation.hThread);
  449. }
  450. }
  451. }
  452. LRESULT ImeSystemHandler(
  453. PIMEUI pimeui,
  454. UINT message,
  455. WPARAM wParam,
  456. LPARAM lParam)
  457. {
  458. PINPUTCONTEXT pInputContext;
  459. HIMC hImc = GETIMC(pimeui);
  460. LRESULT dwRet = 0L;
  461. UNREFERENCED_PARAMETER(message);
  462. switch (wParam) {
  463. case IMS_SETOPENCLOSE:
  464. if (hImc != NULL_HIMC)
  465. fpImmSetOpenStatus(hImc, (BOOL)lParam);
  466. break;
  467. case IMS_WINDOWPOS:
  468. if (hImc != NULL_HIMC) {
  469. BOOL f31Hidden = FALSE;
  470. if ((pInputContext = fpImmLockIMC(hImc)) != NULL) {
  471. f31Hidden = (pInputContext->fdw31Compat & F31COMPAT_MCWHIDDEN);
  472. fpImmUnlockIMC(hImc);
  473. }
  474. if (IsWindow(KHWND_TO_HWND(pimeui->hwndIMC))) {
  475. int i;
  476. if (!f31Hidden) {
  477. COMPOSITIONFORM cof;
  478. if (fpImmGetCompositionWindow(hImc, &cof) && cof.dwStyle != CFS_DEFAULT) {
  479. fpImmSetCompositionWindow(hImc, &cof);
  480. }
  481. }
  482. for (i = 0; i < 4 ; i++) {
  483. CANDIDATEFORM caf;
  484. if (fpImmGetCandidateWindow(hImc, (DWORD)i, &caf) && caf.dwStyle != CFS_DEFAULT) {
  485. fpImmSetCandidateWindow(hImc, &caf);
  486. }
  487. }
  488. }
  489. }
  490. break;
  491. case IMS_ACTIVATECONTEXT:
  492. FocusSetIMCContext((HWND)(lParam), TRUE);
  493. break;
  494. case IMS_DEACTIVATECONTEXT:
  495. FocusSetIMCContext((HWND)(lParam), FALSE);
  496. break;
  497. #ifdef CUAS_ENABLE
  498. case IMS_LOADTHREADLAYOUT:
  499. CtfLoadThreadLayout(pimeui);
  500. break;
  501. #endif // CUAS_ENABLE
  502. case IMS_UNLOADTHREADLAYOUT:
  503. return (LONG)(fpImmFreeLayout((DWORD)lParam));
  504. case IMS_ACTIVATETHREADLAYOUT:
  505. return (LONG)(fpImmActivateLayout((HKL)lParam));
  506. case IMS_SETCANDIDATEPOS:
  507. if ( (pInputContext = fpImmLockIMC( hImc )) != NULL ) {
  508. LPCANDIDATEFORM lpcaf;
  509. DWORD dwIndex = (DWORD)lParam;
  510. lpcaf = &(pInputContext->cfCandForm[dwIndex]);
  511. fpImmSetCandidateWindow( hImc, lpcaf );
  512. fpImmUnlockIMC( hImc );
  513. }
  514. break;
  515. case IMS_SETCOMPOSITIONWINDOW:
  516. if ( (pInputContext = fpImmLockIMC( hImc )) != NULL ) {
  517. LPCOMPOSITIONFORM lpcof;
  518. lpcof = &(pInputContext->cfCompForm);
  519. pInputContext->fdw31Compat |= F31COMPAT_CALLFROMWINNLS;
  520. fpImmSetCompositionWindow( hImc, lpcof);
  521. fpImmUnlockIMC( hImc );
  522. }
  523. break;
  524. case IMS_SETCOMPOSITIONFONT:
  525. if ( (pInputContext = fpImmLockIMC( hImc )) != NULL ) {
  526. LPLOGFONT lplf;
  527. lplf = &(pInputContext->lfFont.W);
  528. fpImmSetCompositionFont( hImc, lplf );
  529. fpImmUnlockIMC( hImc );
  530. }
  531. break;
  532. case IMS_CONFIGUREIME:
  533. fpImmConfigureIMEW( (HKL)lParam, KHWND_TO_HWND(pimeui->hwndIMC), IME_CONFIG_GENERAL, NULL);
  534. break;
  535. case IMS_CHANGE_SHOWSTAT:
  536. // Private message from internat.exe
  537. // Before it reaches here, the registry is already updated.
  538. if (GetIMEShowStatus() == !lParam) {
  539. #if 1
  540. NtUserBroadcastImeShowStatusChange(HW(pimeui->spwnd), !!lParam);
  541. #else
  542. SystemParametersInfo(SPI_SETSHOWIMEUI, lParam, NULL, FALSE);
  543. #endif
  544. }
  545. break;
  546. case IMS_GETCONVERSIONMODE:
  547. {
  548. DWORD dwConv = 0;
  549. DWORD dwTemp;
  550. fpImmGetConversionStatus(hImc, &dwConv, &dwTemp);
  551. return (dwConv);
  552. break;
  553. }
  554. case IMS_SETSOFTKBDONOFF:
  555. fpImmEnumInputContext(0, SyncSoftKbdState, lParam);
  556. break;
  557. case IMS_GETIMEMENU:
  558. // new in NT50
  559. // IMS_GETIEMMENU is used to handle Inter Process GetMenu.
  560. // NOTE: This operation is only intended to internat.exe
  561. return fpImmPutImeMenuItemsIntoMappedFile((HIMC)lParam);
  562. case IMS_IMEHELP:
  563. dwRet = IME_ESC_GETHELPFILENAME;
  564. dwRet = fpImmEscapeW(GETHKL(pimeui), GETIMC(pimeui), IME_ESC_QUERY_SUPPORT, (LPVOID)&dwRet);
  565. if (lParam) {
  566. // try to run WinHelp
  567. WCHAR wszHelpFile[MAX_PATH];
  568. if (dwRet) {
  569. if (fpImmEscapeW(GETHKL(pimeui), GETIMC(pimeui), IME_ESC_GETHELPFILENAME,
  570. (LPVOID)wszHelpFile)) {
  571. ImeRunHelp(wszHelpFile);
  572. }
  573. }
  574. }
  575. return dwRet;
  576. case IMS_GETCONTEXT:
  577. dwRet = (ULONG_PTR)fpImmGetContext((HWND)lParam);
  578. return dwRet;
  579. case IMS_ENDIMEMENU:
  580. // New in NT5.0: Special support for Internat.exe
  581. if (IsWindow((HWND)lParam)) {
  582. HIMC hImc;
  583. UINT uID;
  584. DWORD dwData;
  585. hImc = fpImmGetContext((HWND)lParam);
  586. if (hImc != NULL) {
  587. //
  588. // Call Indicator to get IME menu data.
  589. //
  590. if (IMEIndicatorGetMenuIDData(&uID, &dwData)) {
  591. fpImmNotifyIME(hImc, NI_IMEMENUSELECTED, uID, dwData);
  592. }
  593. fpImmReleaseContext((HWND)lParam, hImc);
  594. }
  595. }
  596. break;
  597. case IMS_SENDNOTIFICATION:
  598. case IMS_FINALIZE_COMPSTR:
  599. dwRet = fpImmSystemHandler(hImc, wParam, lParam);
  600. break;
  601. #ifdef CUAS_ENABLE
  602. case IMS_SETLANGBAND:
  603. case IMS_RESETLANGBAND:
  604. dwRet = fpImmSystemHandler(hImc, wParam, lParam);
  605. break;
  606. #endif // CUAS_ENABLE
  607. default:
  608. break;
  609. }
  610. return dwRet;
  611. }
  612. LONG ImeSelectHandler(
  613. PIMEUI pimeui,
  614. UINT message,
  615. WPARAM wParam,
  616. LPARAM lParam)
  617. {
  618. HWND hwndUI;
  619. /*
  620. * Deliver this message to other IME windows in this thread.
  621. */
  622. if (pimeui->fDefault)
  623. ImeBroadCastMsg(pimeui, message, wParam, lParam);
  624. /*
  625. * We must re-create UI window of newly selected IME.
  626. */
  627. if ((BOOL)wParam == TRUE) {
  628. UserAssert(!IsWindow(GETUI(pimeui)));
  629. SETHKL(pimeui, (HKL)lParam);
  630. #ifdef LATE_CREATEUI
  631. if (!pimeui->fActivate)
  632. return 0L;
  633. #endif
  634. hwndUI = CreateIMEUI(pimeui, (HKL)lParam);
  635. SETUI(pimeui, hwndUI);
  636. if (hwndUI != NULL) {
  637. SetWindowLongPtr(hwndUI, IMMGWLP_IMC, (LONG_PTR)GETIMC(pimeui));
  638. SendMessageToUI(pimeui, message, wParam, lParam, FALSE);
  639. }
  640. if (GetIMEShowStatus() && pimeui->fCtrlShowStatus) {
  641. if (!pimeui->fShowStatus && pimeui->fActivate &&
  642. IsWindow(KHWND_TO_HWND(pimeui->hwndIMC))) {
  643. /*
  644. * This must be sent to an application as an app may want
  645. * to hook this message to do its own UI.
  646. */
  647. SendOpenStatusNotify(pimeui, KHWND_TO_HWND(pimeui->hwndIMC), TRUE);
  648. }
  649. }
  650. }
  651. else {
  652. if (pimeui->fShowStatus && pimeui->fActivate &&
  653. IsWindow(KHWND_TO_HWND(pimeui->hwndIMC))) {
  654. /*
  655. * This must be sent to an application as an app may want
  656. * to hook this message to do its own UI.
  657. */
  658. SendOpenStatusNotify(pimeui, KHWND_TO_HWND(pimeui->hwndIMC), FALSE);
  659. }
  660. SendMessageToUI(pimeui, message, wParam, lParam, FALSE);
  661. DestroyIMEUI(pimeui);
  662. SETHKL(pimeui, (HKL)NULL);
  663. }
  664. return 0L;
  665. }
  666. LRESULT ImeControlHandler(
  667. PIMEUI pimeui,
  668. UINT message,
  669. WPARAM wParam,
  670. LPARAM lParam,
  671. BOOL fAnsi)
  672. {
  673. HIMC hImc;
  674. DWORD dwConversion, dwSentence;
  675. #ifdef CUAS_ENABLE
  676. if (IS_CICERO_ENABLED()) {
  677. if (wParam == IMC_OPENSTATUSWINDOW) {
  678. fpCtfImmRestoreToolbarWnd(pimeui->dwPrevToolbarStatus);
  679. pimeui->dwPrevToolbarStatus = 0;
  680. }
  681. else if (wParam == IMC_CLOSESTATUSWINDOW) {
  682. pimeui->dwPrevToolbarStatus = fpCtfImmHideToolbarWnd();
  683. }
  684. }
  685. #endif // CUAS_ENABLE
  686. /*
  687. * Do nothing with NULL hImc.
  688. */
  689. if ((hImc = GETIMC(pimeui)) == NULL_HIMC)
  690. return 0L;
  691. switch (wParam) {
  692. case IMC_OPENSTATUSWINDOW:
  693. if (GetIMEShowStatus() && !pimeui->fShowStatus) {
  694. pimeui->fShowStatus = TRUE;
  695. SendMessageToUI(pimeui, WM_IME_NOTIFY,
  696. IMN_OPENSTATUSWINDOW, 0L, FALSE);
  697. }
  698. pimeui->fCtrlShowStatus = TRUE;
  699. break;
  700. case IMC_CLOSESTATUSWINDOW:
  701. if (GetIMEShowStatus() && pimeui->fShowStatus) {
  702. pimeui->fShowStatus = FALSE;
  703. SendMessageToUI(pimeui, WM_IME_NOTIFY,
  704. IMN_CLOSESTATUSWINDOW, 0L, FALSE);
  705. }
  706. pimeui->fCtrlShowStatus = FALSE;
  707. break;
  708. /*
  709. * ------------------------------------------------
  710. * IMC_SETCOMPOSITIONFONT,
  711. * IMC_SETCONVERSIONMODE,
  712. * IMC_SETOPENSTATUS
  713. * ------------------------------------------------
  714. * Don't pass these WM_IME_CONTROLs to UI window.
  715. * Call Imm in order to process these requests instead.
  716. * It makes message flows simpler.
  717. */
  718. case IMC_SETCOMPOSITIONFONT:
  719. if (fAnsi) {
  720. if (!fpImmSetCompositionFontA(hImc, (LPLOGFONTA)lParam))
  721. return 1L;
  722. }
  723. else {
  724. if (!fpImmSetCompositionFontW(hImc, (LPLOGFONTW)lParam))
  725. return 1L;
  726. }
  727. break;
  728. case IMC_SETCONVERSIONMODE:
  729. if (!fpImmGetConversionStatus(hImc, &dwConversion, &dwSentence) ||
  730. !fpImmSetConversionStatus(hImc, (DWORD)lParam, dwSentence))
  731. return 1L;
  732. break;
  733. case IMC_SETSENTENCEMODE:
  734. if (!fpImmGetConversionStatus(hImc, &dwConversion, &dwSentence) ||
  735. !fpImmSetConversionStatus(hImc, dwConversion, (DWORD)lParam))
  736. return 1L;
  737. break;
  738. case IMC_SETOPENSTATUS:
  739. if (!fpImmSetOpenStatus(hImc, (BOOL)lParam))
  740. return 1L;
  741. break;
  742. case IMC_GETCONVERSIONMODE:
  743. if (!fpImmGetConversionStatus(hImc,&dwConversion, &dwSentence))
  744. return 1L;
  745. return (LONG)dwConversion;
  746. case IMC_GETSENTENCEMODE:
  747. if (!fpImmGetConversionStatus(hImc,&dwConversion, &dwSentence))
  748. return 1L;
  749. return (LONG)dwSentence;
  750. case IMC_GETOPENSTATUS:
  751. return (LONG)fpImmGetOpenStatus(hImc);
  752. case IMC_GETCOMPOSITIONFONT:
  753. if (fAnsi) {
  754. if (!fpImmGetCompositionFontA(hImc, (LPLOGFONTA)lParam))
  755. return 1L;
  756. }
  757. else {
  758. if (!fpImmGetCompositionFontW(hImc, (LPLOGFONTW)lParam))
  759. return 1L;
  760. }
  761. break;
  762. case IMC_SETCOMPOSITIONWINDOW:
  763. if (!fpImmSetCompositionWindow(hImc, (LPCOMPOSITIONFORM)lParam))
  764. return 1L;
  765. break;
  766. case IMC_SETSTATUSWINDOWPOS:
  767. {
  768. POINT ppt;
  769. ppt.x = (LONG)((LPPOINTS)&lParam)->x;
  770. ppt.y = (LONG)((LPPOINTS)&lParam)->y;
  771. if (!fpImmSetStatusWindowPos(hImc, &ppt))
  772. return 1L;
  773. }
  774. break;
  775. case IMC_SETCANDIDATEPOS:
  776. if (!fpImmSetCandidateWindow(hImc, (LPCANDIDATEFORM)lParam))
  777. return 1;
  778. break;
  779. /*
  780. * Followings are the messsages to be sent to UI.
  781. */
  782. case IMC_GETCANDIDATEPOS:
  783. case IMC_GETSTATUSWINDOWPOS:
  784. case IMC_GETCOMPOSITIONWINDOW:
  785. case IMC_GETSOFTKBDPOS:
  786. case IMC_SETSOFTKBDPOS:
  787. return SendMessageToUI(pimeui, message, wParam, lParam, fAnsi);
  788. default:
  789. break;
  790. }
  791. return 0L;
  792. }
  793. LRESULT ImeSetContextHandler(
  794. PIMEUI pimeui,
  795. UINT message,
  796. WPARAM wParam,
  797. LPARAM lParam)
  798. {
  799. HWND hwndPrevIMC, hwndFocus; // focus window in the thread
  800. HIMC hFocusImc; // focus window's IMC
  801. LRESULT lRet;
  802. pimeui->fActivate = (BOOL)wParam ? 1 : 0;
  803. hwndPrevIMC = KHWND_TO_HWND(pimeui->hwndIMC);
  804. if (wParam) {
  805. /*
  806. * if it's being activated
  807. */
  808. #ifdef LATE_CREATEUI
  809. if (!GETUI(pimeui))
  810. SETUI(pimeui, CreateIMEUI(pimeui, GETHKL(pimeui)));
  811. #endif
  812. /*
  813. * Check if this process a console IME ?
  814. */
  815. if (gfConIme == UNKNOWN_CONIME) {
  816. gfConIme = (DWORD)NtUserGetThreadState(UserThreadStateIsConImeThread);
  817. if (gfConIme) {
  818. RIPMSG0(RIP_VERBOSE, "ImmSetContextHandler: This thread is console IME.\n");
  819. UserAssert(pimeui);
  820. // Console IME will never show the IME status window.
  821. pimeui->fCtrlShowStatus = FALSE;
  822. }
  823. }
  824. if (gfConIme) {
  825. /*
  826. * Special handling for Console IME is needed
  827. */
  828. PWND pwndOwner;
  829. UserAssert(pimeui->spwnd);
  830. pwndOwner = REBASEPWND(pimeui->spwnd, spwndOwner);
  831. if (pwndOwner != NULL) {
  832. /*
  833. * Set current associated hIMC in IMEUI.
  834. */
  835. SETIMC(pimeui, pwndOwner->hImc);
  836. /*
  837. * Store it to the window memory.
  838. */
  839. if (GETUI(pimeui) != NULL)
  840. SetWindowLongPtr(GETUI(pimeui), IMMGWLP_IMC, (LONG_PTR)pwndOwner->hImc);
  841. }
  842. hwndFocus = NtUserQueryWindow(HW(pimeui->spwnd), WindowFocusWindow);
  843. hFocusImc = KHIMC_TO_HIMC(pwndOwner->hImc);
  844. RIPMSG2(RIP_VERBOSE, "CONSOLE IME: hwndFocus = %x, hFocusImc = %x", hwndFocus, hFocusImc);
  845. return SendMessageToUI(pimeui, message, wParam, lParam, FALSE);
  846. }
  847. else {
  848. hwndFocus = NtUserQueryWindow(HW(pimeui->spwnd), WindowFocusWindow);
  849. hFocusImc = fpImmGetContext(hwndFocus);
  850. }
  851. /*
  852. * Cannot share input context with other IME window.
  853. */
  854. if (hFocusImc != NULL_HIMC &&
  855. !ImeIsUsableContext(HW(pimeui->spwnd), hFocusImc)) {
  856. SETIMC(pimeui, NULL_HIMC);
  857. return 0L;
  858. }
  859. SETIMC(pimeui, hFocusImc);
  860. /*
  861. * Store it to the window memory.
  862. */
  863. if (GETUI(pimeui) != NULL)
  864. SetWindowLongPtr(GETUI(pimeui), IMMGWLP_IMC, (LONG_PTR)hFocusImc);
  865. /*
  866. * When we're receiving context,
  867. * it is necessary to set the owner to this window.
  868. * This is for:
  869. * Give the UI moving information.
  870. * Give the UI automatic Z-ordering.
  871. * Hide the UI when the owner is minimized.
  872. */
  873. if (hFocusImc != NULL_HIMC) {
  874. PINPUTCONTEXT pInputContext;
  875. /*
  876. * Get the window who's given the context.
  877. */
  878. if ((pInputContext = fpImmLockIMC(hFocusImc)) != NULL) {
  879. //UserAssert(hwndFocus == pInputContext->hWnd);
  880. if (hwndFocus != pInputContext->hWnd) {
  881. fpImmUnlockIMC(hFocusImc);
  882. /*
  883. * Pq->spwndFocus has been changed so far...
  884. * All we can do is just to bail out.
  885. */
  886. return 0L;
  887. }
  888. }
  889. else
  890. return 0L; // the context was broken
  891. if ((pInputContext->fdw31Compat & F31COMPAT_ECSETCFS) &&
  892. hwndPrevIMC != hwndFocus) {
  893. COMPOSITIONFORM cf;
  894. /*
  895. * Set CFS_DEFAULT....
  896. */
  897. RtlZeroMemory(&cf, sizeof(cf));
  898. fpImmSetCompositionWindow(hFocusImc, &cf);
  899. pInputContext->fdw31Compat &= ~F31COMPAT_ECSETCFS;
  900. }
  901. fpImmUnlockIMC(hFocusImc);
  902. if (NtUserSetImeOwnerWindow(HW(pimeui->spwnd), hwndFocus))
  903. pimeui->hwndIMC = hwndFocus;
  904. }
  905. else {
  906. /*
  907. * NULL IMC is getting activated
  908. */
  909. pimeui->hwndIMC = hwndFocus;
  910. NtUserSetImeOwnerWindow(HW(pimeui->spwnd), NULL);
  911. }
  912. }
  913. lRet = SendMessageToUI(pimeui, message, wParam, lParam, FALSE);
  914. if (pimeui->spwnd == NULL) {
  915. // Unusual case in stress..
  916. // IME window has been destroyed during the callback
  917. RIPMSG0(RIP_WARNING, "ImmSetContextHandler: pimeui->spwnd is NULL after SendMessageToUI.");
  918. return 0L;
  919. }
  920. if (pimeui->fCtrlShowStatus && GetIMEShowStatus()) {
  921. PWND pwndFocus, pwndIMC, pwndPrevIMC;
  922. HWND hwndActive;
  923. hwndFocus = NtUserQueryWindow(HWq(pimeui->spwnd), WindowFocusWindow);
  924. pwndFocus = ValidateHwndNoRip(hwndFocus);
  925. if ((BOOL)wParam == TRUE) {
  926. HWND hwndIme;
  927. /*
  928. * BOGUS BOGUS
  929. * The following if statement is still insufficient
  930. * it needs to think what WM_IME_SETCONTEXT:TRUE should do
  931. * in the case of WINNLSEnableIME(true) - ref.win95c B#8548.
  932. */
  933. UserAssert(pimeui->spwnd);
  934. if (pwndFocus != NULL && GETPTI(pimeui->spwnd) == GETPTI(pwndFocus)) {
  935. if (!pimeui->fShowStatus) {
  936. /*
  937. * We have never sent IMN_OPENSTATUSWINDOW yet....
  938. */
  939. if (ValidateHwndNoRip(KHWND_TO_HWND(pimeui->hwndIMC))) {
  940. SendOpenStatusNotify(pimeui, KHWND_TO_HWND(pimeui->hwndIMC), TRUE);
  941. }
  942. }
  943. else if ((pwndIMC = ValidateHwndNoRip(KHWND_TO_HWND(pimeui->hwndIMC))) != NULL &&
  944. (pwndPrevIMC = ValidateHwndNoRip(hwndPrevIMC)) != NULL &&
  945. GetTopLevelWindow(pwndIMC) != GetTopLevelWindow(pwndPrevIMC)) {
  946. /*
  947. * Because the top level window of IME Wnd was changed.
  948. */
  949. SendOpenStatusNotify(pimeui, hwndPrevIMC, FALSE);
  950. SendOpenStatusNotify(pimeui, KHWND_TO_HWND(pimeui->hwndIMC), TRUE);
  951. }
  952. }
  953. /*
  954. * There may have other IME windows that have fShowStatus.
  955. * We need to check the fShowStatus in the window list.
  956. */
  957. hwndIme = HW(pimeui->spwnd);
  958. if (hwndIme) {
  959. NtUserCheckImeShowStatusInThread(hwndIme);
  960. }
  961. }
  962. else {
  963. /*
  964. * When focus was removed from this thread, we close the
  965. * status window.
  966. * Because focus was already removed from whndPrevIMC,
  967. * hwndPrevIMC may be destroyed but we need to close the
  968. * status window.
  969. */
  970. hwndActive = NtUserQueryWindow(HW(pimeui->spwnd), WindowActiveWindow);
  971. UserAssert(pimeui->spwnd);
  972. if (pwndFocus == NULL || GETPTI(pimeui->spwnd) != GETPTI(pwndFocus) ||
  973. hwndActive == NULL) {
  974. if (IsWindow(hwndPrevIMC)) {
  975. RIPMSG1(RIP_VERBOSE, "ImeSetContextHandler: notifying OpenStatus (FALSE) to hwnd=%p", hwndPrevIMC);
  976. SendOpenStatusNotify(pimeui, hwndPrevIMC, FALSE);
  977. }
  978. else {
  979. RIPMSG1(RIP_VERBOSE, "ImeSetContextHandler: sending IMN_CLOSESTATUSWINDOW to UIwnd=%p", pimeui->hwndUI);
  980. pimeui->fShowStatus = FALSE;
  981. SendMessageToUI(pimeui, WM_IME_NOTIFY, IMN_CLOSESTATUSWINDOW, 0L, FALSE);
  982. }
  983. }
  984. }
  985. }
  986. return lRet;
  987. }
  988. LRESULT ImeNotifyHandler(
  989. PIMEUI pimeui,
  990. UINT message,
  991. WPARAM wParam,
  992. LPARAM lParam)
  993. {
  994. HWND hwndUI;
  995. LRESULT lRet = 0L;
  996. HIMC hImc;
  997. PINPUTCONTEXT pInputContext;
  998. switch (wParam) {
  999. case IMN_PRIVATE:
  1000. hwndUI = GETUI(pimeui);
  1001. if (IsWindow(hwndUI))
  1002. lRet = SendMessage(hwndUI, message, wParam, lParam);
  1003. break;
  1004. case IMN_SETCONVERSIONMODE:
  1005. case IMN_SETOPENSTATUS:
  1006. //
  1007. // notify shell and keyboard the conversion mode change
  1008. //
  1009. // if this message is sent from ImmSetOpenStatus or
  1010. // ImmSetConversionStatus, we have already notified
  1011. // kernel the change. This is a little bit redundant.
  1012. //
  1013. // if application has eaten the message, we won't be here.
  1014. // We need to think about the possibility later.
  1015. //
  1016. hImc = GETIMC(pimeui);
  1017. if ((pInputContext = fpImmLockIMC(hImc)) != NULL) {
  1018. if ( IsWindow(KHWND_TO_HWND(pimeui->hwndIMC)) ) {
  1019. NtUserNotifyIMEStatus( KHWND_TO_HWND(pimeui->hwndIMC),
  1020. (DWORD)pInputContext->fOpen,
  1021. pInputContext->fdwConversion );
  1022. }
  1023. else if (gfConIme == TRUE) {
  1024. /*
  1025. * Special handling for Console IME is needed
  1026. */
  1027. if (pimeui->spwnd) { // If IME window is still there.
  1028. PWND pwndOwner = REBASEPWND(pimeui->spwnd, spwndOwner);
  1029. if (pwndOwner != NULL) {
  1030. NtUserNotifyIMEStatus(HWq(pwndOwner),
  1031. (DWORD)pInputContext->fOpen,
  1032. pInputContext->fdwConversion);
  1033. }
  1034. }
  1035. }
  1036. fpImmUnlockIMC(hImc);
  1037. }
  1038. /*** FALL THROUGH ***/
  1039. default:
  1040. TAGMSG4(DBGTAG_IMM, "ImeNotifyHandler: sending to pimeui->ui=%p, msg=%x, wParam=%x, lParam=%x\n", GETUI(pimeui), message, wParam, lParam);
  1041. lRet = SendMessageToUI(pimeui, message, wParam, lParam, FALSE);
  1042. }
  1043. return lRet;
  1044. }
  1045. HWND CreateIMEUI(
  1046. PIMEUI pimeui,
  1047. HKL hKL)
  1048. {
  1049. PWND pwndIme = pimeui->spwnd;
  1050. HWND hwndUI;
  1051. IMEINFOEX iiex;
  1052. PIMEDPI pimedpi;
  1053. WNDCLASS wndcls;
  1054. if (!fpImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayout, &hKL))
  1055. return (HWND)NULL;
  1056. if ((pimedpi = fpImmLockImeDpi(hKL)) == NULL) {
  1057. RIPMSG1(RIP_WARNING, "CreateIMEUI: ImmLockImeDpi(%lx) failed.", hKL);
  1058. return (HWND)NULL;
  1059. }
  1060. if (!GetClassInfoW(pimedpi->hInst, iiex.wszUIClass, &wndcls)) {
  1061. RIPMSG1(RIP_WARNING, "CreateIMEUI: GetClassInfoW(%ws) failed\n", iiex.wszUIClass);
  1062. fpImmUnlockImeDpi(pimedpi);
  1063. return (HWND)NULL;
  1064. }
  1065. // HACK HACK HACK
  1066. if ((wndcls.style & CS_IME) == 0) {
  1067. RIPMSG1(RIP_ERROR, "CreateIMEUI: the Window Class (%S) does not have CS_IME flag on !!!\n",
  1068. wndcls.lpszClassName);
  1069. }
  1070. if (iiex.ImeInfo.fdwProperty & IME_PROP_UNICODE) {
  1071. /*
  1072. * For Unicode IME, we create an Unicode IME UI window.
  1073. */
  1074. hwndUI = CreateWindowExW(0L,
  1075. iiex.wszUIClass,
  1076. iiex.wszUIClass,
  1077. WS_POPUP|WS_DISABLED,
  1078. 0, 0, 0, 0,
  1079. HWq(pwndIme), 0, wndcls.hInstance, NULL);
  1080. }
  1081. else {
  1082. /*
  1083. * For ANSI IME, we create an ANSI IME UI window.
  1084. */
  1085. LPSTR pszClass;
  1086. int i;
  1087. i = WCSToMB(iiex.wszUIClass, -1, &pszClass, -1, TRUE);
  1088. if (i == 0) {
  1089. RIPMSG1(RIP_WARNING, "CreateIMEUI: failed in W->A conversion (%S)", iiex.wszUIClass);
  1090. fpImmUnlockImeDpi(pimedpi);
  1091. return (HWND)NULL;
  1092. }
  1093. pszClass[i] = '\0';
  1094. hwndUI = CreateWindowExA(0L,
  1095. pszClass,
  1096. pszClass,
  1097. WS_POPUP|WS_DISABLED,
  1098. 0, 0, 0, 0,
  1099. HWq(pwndIme), 0, wndcls.hInstance, NULL);
  1100. UserLocalFree(pszClass);
  1101. }
  1102. if (hwndUI)
  1103. NtUserSetWindowLongPtr(hwndUI, IMMGWLP_IMC, (LONG_PTR)GETIMC(pimeui), FALSE);
  1104. fpImmUnlockImeDpi(pimedpi);
  1105. return hwndUI;
  1106. }
  1107. VOID DestroyIMEUI(
  1108. PIMEUI pimeui)
  1109. {
  1110. // This has currently nothing to do except for destroying the UI.
  1111. // Review: Need to notify the UI with WM_IME_SETCONTEXT ?
  1112. // Review: This doesn't support Multiple IME install yet.
  1113. HWND hwndUI = GETUI(pimeui);
  1114. if (IsWindow(hwndUI)) {
  1115. pimeui->fDestroy = TRUE;
  1116. /*
  1117. * We need this verify because the owner might have already
  1118. * killed it during its termination.
  1119. */
  1120. NtUserDestroyWindow(hwndUI);
  1121. }
  1122. pimeui->fDestroy = FALSE;
  1123. /*
  1124. * Reinitialize show status of the IME status window so that
  1125. * notification message will be sent when needed.
  1126. */
  1127. pimeui->fShowStatus = FALSE;
  1128. SETUI(pimeui, NULL);
  1129. return;
  1130. }
  1131. /***************************************************************************\
  1132. * SendMessageToUI
  1133. *
  1134. * History:
  1135. * 09-Apr-1996 wkwok Created
  1136. \***************************************************************************/
  1137. LRESULT SendMessageToUI(
  1138. PIMEUI pimeui,
  1139. UINT message,
  1140. WPARAM wParam,
  1141. LPARAM lParam,
  1142. BOOL fAnsi)
  1143. {
  1144. PWND pwndUI;
  1145. LRESULT lRet;
  1146. TAGMSG1(DBGTAG_IMM, "Sending to UI msg[%04X]\n", message);
  1147. pwndUI = ValidateHwndNoRip(GETUI(pimeui));
  1148. if (pwndUI == NULL || pimeui->spwnd == NULL)
  1149. return 0L;
  1150. if (TestWF(pimeui->spwnd, WFINDESTROY) || TestWF(pimeui->spwnd, WFDESTROYED) ||
  1151. TestWF(pwndUI, WFINDESTROY) || TestWF(pwndUI, WFDESTROYED)) {
  1152. return 0L;
  1153. }
  1154. InterlockedIncrement(&pimeui->nCntInIMEProc); // Mark to avoid recursion.
  1155. lRet = SendMessageWorker(pwndUI, message, wParam, lParam, fAnsi);
  1156. InterlockedDecrement(&pimeui->nCntInIMEProc); // Mark to avoid recursion.
  1157. return lRet;
  1158. }
  1159. /***************************************************************************\
  1160. * SendOpenStatusNotify
  1161. *
  1162. * History:
  1163. * 09-Apr-1996 wkwok Created
  1164. \***************************************************************************/
  1165. VOID SendOpenStatusNotify(
  1166. PIMEUI pimeui,
  1167. HWND hwndApp,
  1168. BOOL fOpen)
  1169. {
  1170. WPARAM wParam = fOpen ? IMN_OPENSTATUSWINDOW : IMN_CLOSESTATUSWINDOW;
  1171. pimeui->fShowStatus = fOpen;
  1172. if (Is400Compat(GetClientInfo()->dwExpWinVer)) {
  1173. TAGMSG2(DBGTAG_IMM, "SendOpenStatusNotify: sending to hwnd=%lx, wParam=%d\n", hwndApp, wParam);
  1174. SendMessage(hwndApp, WM_IME_NOTIFY, wParam, 0L);
  1175. }
  1176. else {
  1177. TAGMSG2(DBGTAG_IMM, "SendOpenStatusNotify:sending to imeui->UI=%p, wParam=%d\n", GETUI(pimeui), wParam);
  1178. SendMessageToUI(pimeui, WM_IME_NOTIFY, wParam, 0L, FALSE);
  1179. }
  1180. return;
  1181. }
  1182. VOID ImeSetImc(
  1183. PIMEUI pimeui,
  1184. HIMC hImc)
  1185. {
  1186. HWND hImeWnd = HW(pimeui->spwnd);
  1187. HIMC hOldImc = GETIMC(pimeui);
  1188. /*
  1189. * return if nothing to change.
  1190. */
  1191. if (hImc == hOldImc)
  1192. return;
  1193. /*
  1194. * Unmark the old input context.
  1195. */
  1196. if (hOldImc != NULL_HIMC)
  1197. ImeMarkUsedContext(NULL, hOldImc);
  1198. /*
  1199. * Update the in use input context for this IME window.
  1200. */
  1201. pimeui->hIMC = hImc;
  1202. /*
  1203. * Mark the new input context.
  1204. */
  1205. if (hImc != NULL_HIMC)
  1206. ImeMarkUsedContext(hImeWnd, hImc);
  1207. }
  1208. /***************************************************************************\
  1209. * FocusSetIMCContext()
  1210. *
  1211. * History:
  1212. * 21-Mar-1996 wkwok Created
  1213. \***************************************************************************/
  1214. VOID FocusSetIMCContext(
  1215. HWND hWnd,
  1216. BOOL fActivate)
  1217. {
  1218. HIMC hImc;
  1219. if (IsWindow(hWnd)) {
  1220. hImc = fpImmGetContext(hWnd);
  1221. fpImmSetActiveContext(hWnd, hImc, fActivate);
  1222. fpImmReleaseContext(hWnd, hImc);
  1223. }
  1224. else {
  1225. fpImmSetActiveContext(NULL, NULL_HIMC, fActivate);
  1226. }
  1227. return;
  1228. }
  1229. BOOL ImeBroadCastMsg(
  1230. PIMEUI pimeui,
  1231. UINT message,
  1232. WPARAM wParam,
  1233. LPARAM lParam)
  1234. {
  1235. UNREFERENCED_PARAMETER(pimeui);
  1236. UNREFERENCED_PARAMETER(message);
  1237. UNREFERENCED_PARAMETER(wParam);
  1238. UNREFERENCED_PARAMETER(lParam);
  1239. return TRUE;
  1240. }
  1241. /***************************************************************************\
  1242. * ImeMarkUsedContext()
  1243. *
  1244. * Some IME windows can not share the same input context. This function
  1245. * marks the specified hImc to be in used by the specified IME window.
  1246. *
  1247. * History:
  1248. * 12-Mar-1996 wkwok Created
  1249. \***************************************************************************/
  1250. VOID ImeMarkUsedContext(
  1251. HWND hImeWnd,
  1252. HIMC hImc)
  1253. {
  1254. PIMC pImc;
  1255. pImc = HMValidateHandle((HANDLE)hImc, TYPE_INPUTCONTEXT);
  1256. if (pImc == NULL) {
  1257. RIPMSG1(RIP_WARNING, "ImeMarkUsedContext: Invalid hImc (=%lx).", hImc);
  1258. return;
  1259. }
  1260. UserAssert( ValidateHwndNoRip(pImc->hImeWnd) == NULL || hImeWnd == NULL );
  1261. /*
  1262. * Nothing to change?
  1263. */
  1264. if (pImc->hImeWnd == hImeWnd)
  1265. return;
  1266. NtUserUpdateInputContext(hImc, UpdateInUseImeWindow, (ULONG_PTR)hImeWnd);
  1267. return;
  1268. }
  1269. /***************************************************************************\
  1270. * ImeIsUsableContext()
  1271. *
  1272. * Some IME windows can not share the same input context. This function
  1273. * checks whether the specified hImc can be used (means 'Set activated')
  1274. * by the specified IME window.
  1275. *
  1276. * Return: TRUE - OK to use the hImc by hImeWnd.
  1277. * FALSE - otherwise.
  1278. *
  1279. * History:
  1280. * 12-Mar-1996 wkwok Created
  1281. \***************************************************************************/
  1282. BOOL ImeIsUsableContext(
  1283. HWND hImeWnd,
  1284. HIMC hImc)
  1285. {
  1286. PIMC pImc;
  1287. UserAssert(hImeWnd != NULL);
  1288. pImc = HMValidateHandle((HANDLE)hImc, TYPE_INPUTCONTEXT);
  1289. if (pImc == NULL) {
  1290. RIPMSG1(RIP_WARNING, "ImeIsUsableContext: Invalid hImc (=%lx).", hImc);
  1291. return FALSE;
  1292. }
  1293. if ( pImc->hImeWnd == NULL ||
  1294. pImc->hImeWnd == hImeWnd ||
  1295. ValidateHwndNoRip(pImc->hImeWnd) == NULL )
  1296. {
  1297. return TRUE;
  1298. }
  1299. return FALSE;
  1300. }
  1301. /***************************************************************************\
  1302. * GetIMEShowStatus()
  1303. *
  1304. * Get the global IME show status from kernel.
  1305. *
  1306. * History:
  1307. * 19-Sep-1996 takaok Ported from internat.exe.
  1308. \***************************************************************************/
  1309. BOOL GetIMEShowStatus(void)
  1310. {
  1311. return (BOOL)NtUserCallNoParam(SFI__GETIMESHOWSTATUS);
  1312. }
  1313. /***************************************************************************\
  1314. * IMEIndicatorGetMenuIDData
  1315. *
  1316. * History:
  1317. * 3-Nov-97 Hiroyama
  1318. \***************************************************************************/
  1319. BOOL IMEIndicatorGetMenuIDData(PUINT puMenuID, PDWORD pdwData)
  1320. {
  1321. HANDLE hinstIndic;
  1322. WCHAR szModule[MAX_PATH + 1];
  1323. if (! GetSystemModulePath(SYSTEM_DIR, szModule, ARRAYSIZE(szModule), szIndicDLL)) {
  1324. gpfnGetIMEMenuItemData = NULL;
  1325. return FALSE;
  1326. }
  1327. hinstIndic = GetModuleHandle(szModule);
  1328. if (hinstIndic == NULL) {
  1329. gpfnGetIMEMenuItemData = NULL;
  1330. return FALSE;
  1331. }
  1332. if (!gpfnGetIMEMenuItemData) {
  1333. gpfnGetIMEMenuItemData = GetProcAddress(hinstIndic, (LPSTR)ORD_GETIMEMENUITEMDATA);
  1334. }
  1335. if (!gpfnGetIMEMenuItemData)
  1336. return FALSE;
  1337. (*(FPGETIMEMENUITEMDATA)gpfnGetIMEMenuItemData)(puMenuID, pdwData);
  1338. return TRUE;
  1339. }
  1340. BOOL SyncSoftKbdState(
  1341. HIMC hImc,
  1342. LPARAM lParam)
  1343. {
  1344. DWORD fdwConversion, fdwSentence, fdwNewConversion;
  1345. fpImmGetConversionStatus(hImc, &fdwConversion, &fdwSentence);
  1346. if (lParam) {
  1347. fdwNewConversion = fdwConversion | IME_CMODE_SOFTKBD;
  1348. } else {
  1349. fdwNewConversion = fdwConversion & ~IME_CMODE_SOFTKBD;
  1350. }
  1351. if (fdwNewConversion != fdwConversion) {
  1352. fpImmSetConversionStatus(hImc, fdwNewConversion, fdwSentence);
  1353. }
  1354. return TRUE;
  1355. }