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.

1286 lines
38 KiB

  1. /**************************************************************************\
  2. * Module Name: immime.c (corresponds to Win95 ime.c)
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * IME DLL related functinality
  7. *
  8. * History:
  9. * 03-Jan-1996 wkwok Created
  10. \**************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. typedef struct tagSELECTCONTEXT_ENUM {
  14. HKL hSelKL;
  15. HKL hUnSelKL;
  16. } SCE, *PSCE;
  17. BOOL NotifyIMEProc(
  18. HIMC hImc,
  19. LPARAM lParam)
  20. {
  21. UserAssert(lParam == CPS_COMPLETE || lParam == CPS_CANCEL);
  22. ImmNotifyIME(hImc, NI_COMPOSITIONSTR, (DWORD)lParam, 0);
  23. return TRUE;
  24. }
  25. BOOL SelectContextProc(
  26. HIMC hImc,
  27. PSCE psce)
  28. {
  29. SelectInputContext(psce->hSelKL, psce->hUnSelKL, hImc);
  30. return TRUE;
  31. }
  32. BOOL InquireIme(
  33. PIMEDPI pImeDpi)
  34. {
  35. WNDCLASS wc;
  36. BYTE ClassName[IM_UI_CLASS_SIZE * sizeof(WCHAR)];
  37. DWORD dwSystemInfoFlags;
  38. PIMEINFO pImeInfo = &pImeDpi->ImeInfo;
  39. /*
  40. * Check if this process requires the security.
  41. * Adding to the pid check, the current desktop check is required,
  42. * for there are applications run on the secure desktop.
  43. */
  44. dwSystemInfoFlags = (NtUserGetThreadState(UserThreadStateNeedsSecurity) ? IME_SYSINFO_WINLOGON : 0);
  45. if (GetClientInfo()->dwTIFlags & TIF_16BIT)
  46. dwSystemInfoFlags |= IME_SYSINFO_WOW16;
  47. #if !defined(CUAS_ENABLE)
  48. (*pImeDpi->pfn.ImeInquire.w)(pImeInfo, (PVOID)ClassName, dwSystemInfoFlags);
  49. #else
  50. if (! IS_IME_KBDLAYOUT(pImeDpi->hKL) && IS_CICERO_ENABLED_AND_NOT16BIT()) {
  51. if ((*pImeDpi->pfn.CtfImeInquireExW)(pImeInfo, (PVOID)ClassName, dwSystemInfoFlags, pImeDpi->hKL) == S_OK)
  52. {
  53. }
  54. else
  55. {
  56. RIPMSG0(RIP_WARNING, "InquireIme: pImeDpi->pfn.ImeInquireExW failed");
  57. return FALSE;
  58. }
  59. }
  60. else {
  61. (*pImeDpi->pfn.ImeInquire.w)(pImeInfo, (PVOID)ClassName, dwSystemInfoFlags);
  62. }
  63. #endif
  64. /*
  65. * parameter checking for each fields.
  66. */
  67. if (pImeInfo->dwPrivateDataSize == 0)
  68. pImeInfo->dwPrivateDataSize = sizeof(UINT);
  69. if (pImeInfo->fdwProperty & ~(IME_PROP_ALL)) {
  70. RIPMSG0(RIP_WARNING, "wrong property");
  71. return FALSE;
  72. }
  73. if (pImeInfo->fdwConversionCaps & ~(IME_CMODE_ALL)) {
  74. RIPMSG0(RIP_WARNING, "wrong conversion capabilities");
  75. return FALSE;
  76. }
  77. if (pImeInfo->fdwSentenceCaps & ~(IME_SMODE_ALL)) {
  78. RIPMSG0(RIP_WARNING, "wrong sentence capabilities");
  79. return FALSE;
  80. }
  81. if (pImeInfo->fdwUICaps & ~(UI_CAP_ALL)) {
  82. RIPMSG0(RIP_WARNING, "wrong UI capabilities");
  83. return FALSE;
  84. }
  85. if (pImeInfo->fdwSCSCaps & ~(SCS_CAP_ALL)) {
  86. RIPMSG0(RIP_WARNING, "wrong set comp string capabilities");
  87. return FALSE;
  88. }
  89. if (pImeInfo->fdwSelectCaps & ~(SELECT_CAP_ALL)) {
  90. RIPMSG0(RIP_WARNING, "wrong select capabilities");
  91. return FALSE;
  92. }
  93. if (!(pImeInfo->fdwProperty & IME_PROP_UNICODE)) {
  94. /*
  95. * This is ANSI IME. Ensure that it is usable under current system
  96. * codepage.
  97. */
  98. if (pImeDpi->dwCodePage != GetACP() && pImeDpi->dwCodePage != CP_ACP) {
  99. // Note: in the future, if possible, these reference to dwCodepage
  100. // should be IMECodePage()...
  101. RIPMSG1(RIP_WARNING, "incompatible codepage(%d) for ANSI IME", pImeDpi->dwCodePage);
  102. return FALSE;
  103. }
  104. /*
  105. * ANSI -> Unicode Class name.
  106. */
  107. MultiByteToWideChar(IMECodePage(pImeDpi),
  108. (DWORD)MB_PRECOMPOSED,
  109. (LPSTR)ClassName, // src
  110. (INT)-1,
  111. pImeDpi->wszUIClass, // dest
  112. IM_UI_CLASS_SIZE);
  113. } else {
  114. RtlCopyMemory(pImeDpi->wszUIClass, ClassName, sizeof(ClassName));
  115. }
  116. pImeDpi->wszUIClass[IM_UI_CLASS_SIZE-1] = L'\0';
  117. if (!GetClassInfoW((HINSTANCE)pImeDpi->hInst, pImeDpi->wszUIClass, &wc)) {
  118. RIPMSG1(RIP_WARNING, "UI class (%ws) not found in this IME", pImeDpi->wszUIClass);
  119. return FALSE;
  120. } else if (wc.cbWndExtra < sizeof(DWORD) * 2) {
  121. RIPMSG0(RIP_WARNING, "UI class cbWndExtra problem");
  122. return FALSE;
  123. }
  124. return TRUE;
  125. }
  126. BOOL CheckAndApplyAppCompat(LPWSTR wszImeFile)
  127. {
  128. DWORD dwReason;
  129. HMODULE hAppHelp;
  130. typedef BOOL (*PFNApphelpCheckIME)(
  131. IN LPCWSTR pwszPath // Unicode path to the executable (DOS_PATH)
  132. );
  133. PFNApphelpCheckIME pfnAppHelpCheckIME;
  134. BOOL bRunIME = TRUE;
  135. //
  136. // tentative prototype (find out a semi-public header to include! [and a lib too])
  137. //
  138. BOOL
  139. WINAPI
  140. BaseCheckAppcompatCache(
  141. LPCWSTR pwszPath,
  142. HANDLE hFile,
  143. PVOID pEnvironment,
  144. DWORD* dwReason
  145. );
  146. //
  147. // Assuming most of IMEs are just fine, not needing
  148. // Shim's help, let's check the good guy cache first
  149. // so that the overhead should be minimum. This API
  150. // is meant to be really light weight.
  151. //
  152. if (BaseCheckAppcompatCache(wszImeFile, INVALID_HANDLE_VALUE, NULL, &dwReason)) {
  153. // This IME is in the good guy cache. Just bail out quietly.
  154. return bRunIME;
  155. }
  156. // What's a good use of dwReason?
  157. RIPMSG1(RIP_VERBOSE, "Shim'ing this IME='%ls'", wszImeFile);
  158. //
  159. // Call the real Shim helper for this IME.
  160. //
  161. hAppHelp = GetModuleHandleW(L"apphelp.dll");
  162. if (hAppHelp == NULL) {
  163. hAppHelp = LoadLibraryW(L"apphelp.dll");
  164. if (hAppHelp == NULL) {
  165. // Failed to load apphelp.dll.
  166. // We have no other choice than bailing out.
  167. RIPMSG0(RIP_WARNING, "CheckAndApplyAppCompat: failed to load apphelp.dll");
  168. return bRunIME;
  169. }
  170. }
  171. UserAssert(hAppHelp);
  172. pfnAppHelpCheckIME = (PFNApphelpCheckIME)GetProcAddress(hAppHelp, "ApphelpCheckIME");
  173. if (pfnAppHelpCheckIME == NULL) {
  174. RIPMSG0(RIP_WARNING, "CheckAndApplyAppCompat: failed to getproc ApphelpCheckIME");
  175. return bRunIME;
  176. }
  177. //
  178. // return result has no meaning for this ca
  179. //
  180. bRunIME = pfnAppHelpCheckIME(wszImeFile);
  181. return bRunIME;
  182. }
  183. BOOL LoadIME(
  184. PIMEINFOEX piiex,
  185. PIMEDPI pImeDpi)
  186. {
  187. WCHAR wszImeFile[MAX_PATH];
  188. BOOL fSuccess;
  189. GetSystemPathName(wszImeFile, piiex->wszImeFile, MAX_PATH);
  190. if (!CheckAndApplyAppCompat(wszImeFile)) {
  191. RIPMSG1(RIP_WARNING, "LoadIME: IME (%ws) blocked by appcompat", wszImeFile);
  192. goto LoadIME_ErrOut;
  193. }
  194. pImeDpi->hInst = LoadLibraryW(wszImeFile);
  195. if (!pImeDpi->hInst) {
  196. RIPMSG1(RIP_WARNING, "LoadIME: LoadLibraryW(%ws) failed", wszImeFile);
  197. goto LoadIME_ErrOut;
  198. }
  199. #define GET_IMEPROCT(x) \
  200. if (!(pImeDpi->pfn.##x.t = (PVOID) GetProcAddress(pImeDpi->hInst, #x))) { \
  201. RIPMSG1(RIP_WARNING, "LoadIME: " #x " not supported in %ws", wszImeFile); \
  202. goto LoadIME_ErrOut; }
  203. #define GET_IMEPROC(x) \
  204. if (!(pImeDpi->pfn.##x = (PVOID) GetProcAddress(pImeDpi->hInst, #x))) { \
  205. RIPMSG1(RIP_WARNING, "LoadIME: " #x " not supported in %ws", wszImeFile); \
  206. goto LoadIME_ErrOut; }
  207. GET_IMEPROCT(ImeInquire);
  208. GET_IMEPROCT(ImeConversionList);
  209. GET_IMEPROCT(ImeRegisterWord);
  210. GET_IMEPROCT(ImeUnregisterWord);
  211. GET_IMEPROCT(ImeGetRegisterWordStyle);
  212. GET_IMEPROCT(ImeEnumRegisterWord);
  213. GET_IMEPROC (ImeConfigure);
  214. GET_IMEPROC (ImeDestroy);
  215. GET_IMEPROC (ImeEscape);
  216. GET_IMEPROC (ImeProcessKey);
  217. GET_IMEPROC (ImeSelect);
  218. GET_IMEPROC (ImeSetActiveContext);
  219. GET_IMEPROC (ImeToAsciiEx);
  220. GET_IMEPROC (NotifyIME);
  221. GET_IMEPROC (ImeSetCompositionString);
  222. // 4.0 IMEs don't have this entry. could be NULL.
  223. pImeDpi->pfn.ImeGetImeMenuItems = (PVOID)GetProcAddress(pImeDpi->hInst, "ImeGetImeMenuItems");
  224. #ifdef CUAS_ENABLE
  225. //
  226. // Cicero IME
  227. //
  228. if (! IS_IME_KBDLAYOUT(pImeDpi->hKL) && IS_CICERO_ENABLED_AND_NOT16BIT()) {
  229. GET_IMEPROC (CtfImeInquireExW);
  230. GET_IMEPROC (CtfImeSelectEx);
  231. GET_IMEPROC (CtfImeEscapeEx);
  232. GET_IMEPROC (CtfImeGetGuidAtom);
  233. GET_IMEPROC (CtfImeIsGuidMapEnable);
  234. }
  235. #endif // CUAS_ENABLE
  236. #undef GET_IMEPROCT
  237. #undef GET_IMEPROC
  238. if (!InquireIme(pImeDpi)) {
  239. RIPMSG0(RIP_WARNING, "LoadIME: InquireIme failed");
  240. LoadIME_ErrOut:
  241. FreeLibrary(pImeDpi->hInst);
  242. pImeDpi->hInst = NULL;
  243. fSuccess = FALSE;
  244. }
  245. else {
  246. fSuccess = TRUE;
  247. }
  248. /*
  249. * Update kernel side IMEINFOEX for this keyboard layout if
  250. * this is its first loading.
  251. */
  252. if (piiex->fLoadFlag == IMEF_NONLOAD) {
  253. if (fSuccess) {
  254. RtlCopyMemory((PBYTE)&piiex->ImeInfo,
  255. (PBYTE)&pImeDpi->ImeInfo, sizeof(IMEINFO));
  256. RtlCopyMemory((PBYTE)piiex->wszUIClass,
  257. (PBYTE)pImeDpi->wszUIClass, sizeof(pImeDpi->wszUIClass));
  258. piiex->fLoadFlag = IMEF_LOADED;
  259. }
  260. else {
  261. piiex->fLoadFlag = IMEF_LOADERROR;
  262. RIPMSG1(RIP_WARNING, "LoadIME: hKL=%lx piiex->fLoadFlag = IMEF_LOADERROR", piiex->hkl);
  263. }
  264. NtUserSetImeInfoEx(piiex);
  265. }
  266. return fSuccess;
  267. }
  268. VOID UnloadIME(
  269. PIMEDPI pImeDpi,
  270. BOOL fTerminateIme)
  271. {
  272. if (pImeDpi->hInst == NULL) {
  273. RIPMSG0(RIP_WARNING, "UnloadIME: No IME's hInst.");
  274. return;
  275. }
  276. if (fTerminateIme) {
  277. /*
  278. * Destroy IME first.
  279. */
  280. (*pImeDpi->pfn.ImeDestroy)(0);
  281. }
  282. FreeLibrary(pImeDpi->hInst);
  283. pImeDpi->hInst = NULL;
  284. return;
  285. }
  286. PIMEDPI LoadImeDpi(
  287. HKL hKL,
  288. BOOL fLock)
  289. {
  290. PIMEDPI pImeDpi, pImeDpiT;
  291. IMEINFOEX iiex;
  292. /*
  293. * Query the IME information.
  294. */
  295. if (!ImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayout, &hKL)) {
  296. RIPMSG1(RIP_WARNING, "LoadImeDpi: ImmGetImeInfoEx(%lx) failed", hKL);
  297. return NULL;
  298. }
  299. /*
  300. * Win95 behaviour: If there was an IME load error for this layout,
  301. * further attempt to load the same IME layout will be rejected.
  302. */
  303. if (iiex.fLoadFlag == IMEF_LOADERROR)
  304. {
  305. RIPMSG1(RIP_WARNING, "LoadImeDpi: hKL=%lx iiex.fLoadFlag = IMEF_LOADERROR", iiex.hkl);
  306. return NULL;
  307. }
  308. /*
  309. * Allocate a new IMEDPI for this layout.
  310. */
  311. pImeDpi = (PIMEDPI)ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof(IMEDPI));
  312. if (pImeDpi == NULL)
  313. return NULL;
  314. pImeDpi->hKL = hKL;
  315. // get code page of IME
  316. {
  317. CHARSETINFO cs;
  318. if (TranslateCharsetInfo((DWORD*)LOWORD(HandleToUlong(hKL)), &cs, TCI_SRCLOCALE)) {
  319. pImeDpi->dwCodePage = cs.ciACP;
  320. }
  321. else {
  322. pImeDpi->dwCodePage = CP_ACP;
  323. }
  324. }
  325. /*
  326. * Load up IME DLL.
  327. */
  328. if (!LoadIME(&iiex, pImeDpi)) {
  329. ImmLocalFree(pImeDpi);
  330. return NULL;
  331. }
  332. /*
  333. * Link in the newly allocated entry.
  334. */
  335. RtlEnterCriticalSection(&gcsImeDpi);
  336. pImeDpiT = ImmGetImeDpi(hKL);
  337. if (pImeDpiT == NULL) {
  338. if (fLock) {
  339. /*
  340. * Newly loaded with lock, will unload upon unlock.
  341. */
  342. pImeDpi->cLock = 1;
  343. pImeDpi->dwFlag |= IMEDPI_UNLOCKUNLOAD;
  344. }
  345. /*
  346. * Update the global list for this new pImeDpi entry.
  347. */
  348. pImeDpi->pNext = gpImeDpi;
  349. gpImeDpi = pImeDpi;
  350. RtlLeaveCriticalSection(&gcsImeDpi);
  351. }
  352. else {
  353. if (!fLock) {
  354. pImeDpiT->dwFlag &= ~IMEDPI_UNLOCKUNLOAD;
  355. }
  356. /*
  357. * The same IME has been loaded, discard this extra entry.
  358. */
  359. RtlLeaveCriticalSection(&gcsImeDpi);
  360. UnloadIME(pImeDpi, FALSE);
  361. ImmLocalFree(pImeDpi);
  362. pImeDpi = pImeDpiT;
  363. }
  364. return pImeDpi;
  365. }
  366. PIMEDPI FindOrLoadImeDpi(
  367. HKL hKL)
  368. {
  369. PIMEDPI pImeDpi;
  370. /*
  371. * Non IME based keyboard layout doesn't have IMEDPI.
  372. */
  373. #if !defined(CUAS_ENABLE)
  374. if (!IS_IME_KBDLAYOUT(hKL))
  375. return (PIMEDPI)NULL;
  376. #else
  377. if (! IS_IME_KBDLAYOUT(hKL) && ! IS_CICERO_ENABLED_AND_NOT16BIT())
  378. return (PIMEDPI)NULL;
  379. #endif
  380. pImeDpi = ImmLockImeDpi(hKL);
  381. if (pImeDpi == NULL)
  382. pImeDpi = LoadImeDpi(hKL, TRUE);
  383. return pImeDpi;
  384. }
  385. BOOL WINAPI ImmLoadIME(
  386. HKL hKL)
  387. {
  388. PIMEDPI pImeDpi;
  389. /*
  390. * Non IME based keyboard layout doesn't have IMEDPI.
  391. */
  392. #if !defined(CUAS_ENABLE)
  393. if (!IS_IME_KBDLAYOUT(hKL))
  394. return FALSE;
  395. #else
  396. if (! IS_IME_KBDLAYOUT(hKL) && ! IS_CICERO_ENABLED_AND_NOT16BIT())
  397. return FALSE;
  398. #endif
  399. pImeDpi = ImmGetImeDpi(hKL);
  400. if (pImeDpi == NULL)
  401. pImeDpi = LoadImeDpi(hKL, FALSE);
  402. return (pImeDpi != NULL);
  403. }
  404. BOOL WINAPI ImmUnloadIME(
  405. HKL hKL)
  406. {
  407. PIMEDPI pImeDpi, pImeDpiT;
  408. RtlEnterCriticalSection(&gcsImeDpi);
  409. pImeDpi = gpImeDpi;
  410. while (pImeDpi != NULL && pImeDpi->hKL != hKL)
  411. pImeDpi = pImeDpi->pNext;
  412. if (pImeDpi == NULL) {
  413. RtlLeaveCriticalSection(&gcsImeDpi);
  414. return TRUE;
  415. }
  416. else if (pImeDpi->cLock != 0) {
  417. pImeDpi->dwFlag |= IMEDPI_UNLOADED;
  418. RtlLeaveCriticalSection(&gcsImeDpi);
  419. return FALSE;
  420. }
  421. /*
  422. * Unlink it.
  423. */
  424. if (gpImeDpi == pImeDpi) {
  425. gpImeDpi = pImeDpi->pNext;
  426. }
  427. else {
  428. pImeDpiT = gpImeDpi;
  429. while (pImeDpiT != NULL && pImeDpiT->pNext != pImeDpi)
  430. pImeDpiT = pImeDpiT->pNext;
  431. if (pImeDpiT != NULL)
  432. pImeDpiT->pNext = pImeDpi->pNext;
  433. }
  434. /*
  435. * Unload the IME DLL.
  436. */
  437. UnloadIME(pImeDpi, TRUE);
  438. ImmLocalFree(pImeDpi);
  439. RtlLeaveCriticalSection(&gcsImeDpi);
  440. return TRUE;
  441. }
  442. BOOL WINAPI ImmFreeLayout(
  443. DWORD dwFlag)
  444. {
  445. PIMEDPI pImeDpi;
  446. HKL *phklRoot, hklCurrent;
  447. WCHAR pwszNonImeKLID[KL_NAMELENGTH];
  448. UINT nLayouts, uNonImeKLID = 0, i;
  449. hklCurrent = GetKeyboardLayout(0);
  450. switch (dwFlag) {
  451. case IFL_DEACTIVATEIME:
  452. /*
  453. * Do nothing if no IME to be deactivated.
  454. */
  455. if (!IS_IME_KBDLAYOUT(hklCurrent))
  456. return TRUE;
  457. /*
  458. * Deactivate IME based layout by activating a non-IME based
  459. * keyboard layout.
  460. */
  461. uNonImeKLID = (UINT)LANGIDFROMLCID(GetSystemDefaultLCID());
  462. nLayouts = GetKeyboardLayoutList(0, NULL);
  463. if (nLayouts != 0) {
  464. phklRoot = ImmLocalAlloc(0, nLayouts * sizeof(HKL));
  465. if (phklRoot == NULL)
  466. return FALSE;
  467. nLayouts = GetKeyboardLayoutList(nLayouts, phklRoot);
  468. for (i = 0; i < nLayouts && IS_IME_KBDLAYOUT(phklRoot[i]); i++) ;
  469. if (i < nLayouts)
  470. uNonImeKLID = HandleToUlong(phklRoot[i]) & 0xffff;
  471. ImmLocalFree(phklRoot);
  472. }
  473. wsprintf(pwszNonImeKLID, L"%08x", uNonImeKLID);
  474. if (LoadKeyboardLayoutW(pwszNonImeKLID, KLF_ACTIVATE) == NULL) {
  475. RIPMSG1(RIP_WARNING, "ImmFreeLayout: LoadKeyboardLayoutW(%S, KLF_ACTIVATE) failed. Trying 00000409", pwszNonImeKLID);
  476. // Somehow it failed (probably a bad setup), let's try
  477. // 409 KL, which should be installed on all localized NTs.
  478. if (LoadKeyboardLayoutW(L"00000409", KLF_ACTIVATE | KLF_FAILSAFE) == NULL) {
  479. RIPMSG0(RIP_WARNING, "LoadKeyboardLayoutW(00000409) failed either. will try NULL.");
  480. }
  481. }
  482. break;
  483. case IFL_UNLOADIME:
  484. RtlEnterCriticalSection(&gcsImeDpi);
  485. UnloadImeDpiLoop:
  486. for (pImeDpi = gpImeDpi; pImeDpi != NULL; pImeDpi = pImeDpi->pNext) {
  487. if (ImmUnloadIME(pImeDpi->hKL))
  488. goto UnloadImeDpiLoop; // Rescan as list was updated.
  489. }
  490. RtlLeaveCriticalSection(&gcsImeDpi);
  491. break;
  492. default:
  493. {
  494. HKL hklFlag = (HKL)LongToHandle( dwFlag );
  495. if (IS_IME_KBDLAYOUT(hklFlag) && hklFlag != hklCurrent) {
  496. ImmUnloadIME(hklFlag);
  497. }
  498. }
  499. break;
  500. }
  501. return TRUE;
  502. }
  503. BOOL WINAPI ImmActivateLayout(
  504. HKL hSelKL)
  505. {
  506. HKL hUnSelKL;
  507. HWND hWndDefaultIme;
  508. SCE sce;
  509. DWORD dwCPS;
  510. PIMEDPI pImeDpi;
  511. BOOLEAN fOptimizeActivation = TRUE;
  512. hUnSelKL = GetKeyboardLayout(0);
  513. {
  514. PCLIENTINFO pClientInfo = GetClientInfo();
  515. if (pClientInfo->CI_flags & CI_INPUTCONTEXT_REINIT) {
  516. fOptimizeActivation = FALSE;
  517. }
  518. }
  519. /*
  520. * if already current active, do nothing
  521. */
  522. if (hUnSelKL == hSelKL && fOptimizeActivation)
  523. return TRUE;
  524. ImmLoadIME(hSelKL);
  525. if (hUnSelKL != hSelKL) {
  526. pImeDpi = ImmLockImeDpi(hUnSelKL);
  527. if (pImeDpi != NULL) {
  528. /*
  529. * Send out CPS_CANCEL or CPS_COMPLETE to every input
  530. * context assoicated to window(s) created by this thread.
  531. * Starting from SUR, we only assoicate input context to window created
  532. * by the same thread.
  533. */
  534. dwCPS = (pImeDpi->ImeInfo.fdwProperty & IME_PROP_COMPLETE_ON_UNSELECT) ? CPS_COMPLETE : CPS_CANCEL;
  535. ImmUnlockImeDpi(pImeDpi);
  536. ImmEnumInputContext(0, NotifyIMEProc, dwCPS);
  537. }
  538. hWndDefaultIme = ImmGetDefaultIMEWnd(NULL);
  539. if (IsWindow(hWndDefaultIme))
  540. SendMessage(hWndDefaultIme, WM_IME_SELECT, FALSE, (LPARAM)hUnSelKL);
  541. /*
  542. * This is the time to update the kernel side layout handles.
  543. * We must do this before sending WM_IME_SELECT.
  544. */
  545. NtUserSetThreadLayoutHandles(hSelKL, hUnSelKL);
  546. }
  547. /*
  548. * Unselect and select input context(s).
  549. */
  550. sce.hSelKL = hSelKL;
  551. sce.hUnSelKL = hUnSelKL;
  552. ImmEnumInputContext(0, (IMCENUMPROC)SelectContextProc, (LPARAM)&sce);
  553. /*
  554. * inform UI select after all hIMC select
  555. */
  556. if (IsWindow(hWndDefaultIme))
  557. SendMessage(hWndDefaultIme, WM_IME_SELECT, TRUE, (LPARAM)hSelKL);
  558. return (TRUE);
  559. }
  560. /***************************************************************************\
  561. * ImmConfigureIMEA
  562. *
  563. * Brings up the configuration dialogbox of the IME with the specified hKL.
  564. *
  565. * History:
  566. * 29-Feb-1995 wkwok Created
  567. \***************************************************************************/
  568. BOOL WINAPI ImmConfigureIMEA(
  569. HKL hKL,
  570. HWND hWnd,
  571. DWORD dwMode,
  572. LPVOID lpData)
  573. {
  574. PWND pWnd;
  575. PIMEDPI pImeDpi;
  576. BOOL fRet = FALSE;
  577. if ((pWnd = ValidateHwnd(hWnd)) == (PWND)NULL) {
  578. RIPMSG1(RIP_WARNING,
  579. "ImmConfigureIMEA: invalid window handle %x", hWnd);
  580. return FALSE;
  581. }
  582. if (!TestWindowProcess(pWnd)) {
  583. RIPMSG1(RIP_WARNING,
  584. "ImmConfigureIMEA: hWnd=%lx belongs to different process!", hWnd);
  585. return FALSE;
  586. }
  587. pImeDpi = FindOrLoadImeDpi(hKL);
  588. if (pImeDpi == NULL) {
  589. RIPMSG0(RIP_WARNING, "ImmConfigureIMEA: no pImeDpi entry.");
  590. return FALSE;
  591. }
  592. if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) || lpData == NULL) {
  593. /*
  594. * Doesn't need A/W conversion. Calls directly to IME to
  595. * bring up the configuration dialogbox.
  596. */
  597. // This message handles by Console IME.
  598. SendMessage(hWnd, WM_IME_SYSTEM, IMS_OPENPROPERTYWINDOW, 0L);
  599. fRet = (*pImeDpi->pfn.ImeConfigure)(hKL, hWnd, dwMode, lpData);
  600. // This message handles by Console IME.
  601. SendMessage(hWnd, WM_IME_SYSTEM, IMS_CLOSEPROPERTYWINDOW, 0L);
  602. ImmUnlockImeDpi(pImeDpi);
  603. return fRet;
  604. }
  605. /*
  606. * ANSI caller, Unicode IME. Needs A/W conversion on lpData when
  607. * dwMode == IME_CONFIG_REGISTERWORD. In this case, lpData points
  608. * to a structure of REGISTERWORDA.
  609. */
  610. switch (dwMode) {
  611. case IME_CONFIG_REGISTERWORD:
  612. {
  613. LPREGISTERWORDA lpRegisterWordA;
  614. REGISTERWORDW RegisterWordW;
  615. LPVOID lpBuffer;
  616. ULONG cbBuffer;
  617. INT i;
  618. lpRegisterWordA = (LPREGISTERWORDA)lpData;
  619. cbBuffer = 0;
  620. lpBuffer = NULL;
  621. if (lpRegisterWordA->lpReading != NULL)
  622. cbBuffer += strlen(lpRegisterWordA->lpReading) + 1;
  623. if (lpRegisterWordA->lpWord != NULL)
  624. cbBuffer += strlen(lpRegisterWordA->lpWord) + 1;
  625. if (cbBuffer != 0) {
  626. cbBuffer *= sizeof(WCHAR);
  627. if ((lpBuffer = ImmLocalAlloc(0, cbBuffer)) == NULL) {
  628. RIPMSG0(RIP_WARNING, "ImmConfigureIMEA: memory failure.");
  629. break;
  630. }
  631. }
  632. if (lpRegisterWordA->lpReading != NULL) {
  633. RegisterWordW.lpReading = lpBuffer;
  634. i = MultiByteToWideChar(IMECodePage(pImeDpi),
  635. (DWORD)MB_PRECOMPOSED,
  636. (LPSTR)lpRegisterWordA->lpReading,
  637. (INT)strlen(lpRegisterWordA->lpReading),
  638. (LPWSTR)RegisterWordW.lpReading,
  639. (INT)(cbBuffer/sizeof(WCHAR)));
  640. RegisterWordW.lpReading[i] = L'\0';
  641. cbBuffer -= (i * sizeof(WCHAR));
  642. }
  643. else {
  644. RegisterWordW.lpReading = NULL;
  645. }
  646. if (lpRegisterWordA->lpWord != NULL) {
  647. if (RegisterWordW.lpReading != NULL)
  648. RegisterWordW.lpWord = &RegisterWordW.lpReading[i+1];
  649. else
  650. RegisterWordW.lpWord = lpBuffer;
  651. i = MultiByteToWideChar(IMECodePage(pImeDpi),
  652. (DWORD)MB_PRECOMPOSED,
  653. (LPSTR)lpRegisterWordA->lpWord,
  654. (INT)strlen(lpRegisterWordA->lpWord),
  655. (LPWSTR)RegisterWordW.lpWord,
  656. (INT)(cbBuffer/sizeof(WCHAR)));
  657. RegisterWordW.lpWord[i] = L'\0';
  658. }
  659. else
  660. RegisterWordW.lpWord = NULL;
  661. fRet = ImmConfigureIMEW(hKL, hWnd, dwMode, &RegisterWordW);
  662. if (lpBuffer != NULL)
  663. ImmLocalFree(lpBuffer);
  664. break;
  665. }
  666. default:
  667. fRet = ImmConfigureIMEW(hKL, hWnd, dwMode, lpData);
  668. break;
  669. }
  670. ImmUnlockImeDpi(pImeDpi);
  671. return fRet;
  672. }
  673. /***************************************************************************\
  674. * ImmConfigureIMEW
  675. *
  676. * Brings up the configuration dialogbox of the IME with the specified hKL.
  677. *
  678. * History:
  679. * 29-Feb-1995 wkwok Created
  680. \***************************************************************************/
  681. BOOL WINAPI ImmConfigureIMEW(
  682. HKL hKL,
  683. HWND hWnd,
  684. DWORD dwMode,
  685. LPVOID lpData)
  686. {
  687. PWND pWnd;
  688. PIMEDPI pImeDpi;
  689. BOOL fRet = FALSE;
  690. if ((pWnd = ValidateHwnd(hWnd)) == (PWND)NULL) {
  691. RIPMSG1(RIP_WARNING,
  692. "ImmConfigureIMEA: invalid window handle %x", hWnd);
  693. return FALSE;
  694. }
  695. if (!TestWindowProcess(pWnd)) {
  696. RIPMSG1(RIP_WARNING,
  697. "ImmConfigureIMEA: hWnd=%lx belongs to different process!", hWnd);
  698. return FALSE;
  699. }
  700. pImeDpi = FindOrLoadImeDpi(hKL);
  701. if (pImeDpi == NULL) {
  702. RIPMSG0(RIP_WARNING, "ImmConfigureIMEA: no pImeDpi entry.");
  703. return FALSE;
  704. }
  705. if ((pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) || lpData == NULL) {
  706. /*
  707. * Doesn't need A/W conversion. Calls directly to IME to
  708. * bring up the configuration dialogbox.
  709. */
  710. // This message handles by Console IME.
  711. SendMessage(hWnd, WM_IME_SYSTEM, IMS_OPENPROPERTYWINDOW, 0L);
  712. fRet = (*pImeDpi->pfn.ImeConfigure)(hKL, hWnd, dwMode, lpData);
  713. // This message handles by Console IME.
  714. SendMessage(hWnd, WM_IME_SYSTEM, IMS_CLOSEPROPERTYWINDOW, 0L);
  715. ImmUnlockImeDpi(pImeDpi);
  716. return fRet;
  717. }
  718. /*
  719. * Unicode caller, ANSI IME. Needs A/W conversion on lpData when
  720. * dwMode == IME_CONFIG_REGISTERWORD. In this case, lpData points
  721. * to a structure of REGISTERWORDW.
  722. */
  723. switch (dwMode) {
  724. case IME_CONFIG_REGISTERWORD:
  725. {
  726. LPREGISTERWORDW lpRegisterWordW;
  727. REGISTERWORDA RegisterWordA;
  728. LPVOID lpBuffer;
  729. ULONG cbBuffer;
  730. BOOL bUDC;
  731. INT i;
  732. lpRegisterWordW = (LPREGISTERWORDW)lpData;
  733. cbBuffer = 0;
  734. lpBuffer = NULL;
  735. if (lpRegisterWordW->lpReading != NULL)
  736. cbBuffer += wcslen(lpRegisterWordW->lpReading) + 1;
  737. if (lpRegisterWordW->lpWord != NULL)
  738. cbBuffer += wcslen(lpRegisterWordW->lpWord) + 1;
  739. if (cbBuffer != 0) {
  740. cbBuffer *= sizeof(WCHAR);
  741. if ((lpBuffer = ImmLocalAlloc(0, cbBuffer)) == NULL) {
  742. RIPMSG0(RIP_WARNING, "ImmConfigureIMEW: memory failure.");
  743. break;
  744. }
  745. }
  746. if (lpRegisterWordW->lpReading != NULL) {
  747. RegisterWordA.lpReading = lpBuffer;
  748. i = WideCharToMultiByte(IMECodePage(pImeDpi),
  749. (DWORD)0,
  750. (LPWSTR)lpRegisterWordW->lpReading,
  751. (INT)wcslen(lpRegisterWordW->lpReading),
  752. (LPSTR)RegisterWordA.lpReading,
  753. (INT)cbBuffer,
  754. (LPSTR)NULL,
  755. (LPBOOL)&bUDC);
  756. RegisterWordA.lpReading[i] = '\0';
  757. cbBuffer -= (i * sizeof(CHAR));
  758. }
  759. else {
  760. RegisterWordA.lpReading = NULL;
  761. }
  762. if (lpRegisterWordW->lpWord != NULL) {
  763. if (RegisterWordA.lpReading != NULL)
  764. RegisterWordA.lpWord = &RegisterWordA.lpReading[i+1];
  765. else
  766. RegisterWordA.lpWord = lpBuffer;
  767. i = WideCharToMultiByte(IMECodePage(pImeDpi),
  768. (DWORD)0,
  769. (LPWSTR)lpRegisterWordW->lpWord,
  770. (INT)wcslen(lpRegisterWordW->lpWord),
  771. (LPSTR)RegisterWordA.lpWord,
  772. (INT)cbBuffer,
  773. (LPSTR)NULL,
  774. (LPBOOL)&bUDC);
  775. RegisterWordA.lpWord[i] = '\0';
  776. }
  777. else
  778. RegisterWordA.lpWord = NULL;
  779. fRet = ImmConfigureIMEA(hKL, hWnd, dwMode, &RegisterWordA);
  780. if (lpBuffer != NULL)
  781. ImmLocalFree(lpBuffer);
  782. break;
  783. }
  784. default:
  785. fRet = ImmConfigureIMEA(hKL, hWnd, dwMode, lpData);
  786. break;
  787. }
  788. ImmUnlockImeDpi(pImeDpi);
  789. return fRet;
  790. }
  791. #define IME_T_EUDC_DIC_SIZE 80 // the Traditional Chinese EUDC dictionary
  792. /***************************************************************************\
  793. * ImmEscapeA
  794. *
  795. * This API allows an application to access capabilities of a particular
  796. * IME with specified hKL not directly available thru. other IMM APIs.
  797. * This is necessary mainly for country specific functions or private
  798. * functions in IME.
  799. *
  800. * History:
  801. * 29-Feb-1995 wkwok Created
  802. \***************************************************************************/
  803. LRESULT WINAPI ImmEscapeA(
  804. HKL hKL,
  805. HIMC hImc,
  806. UINT uSubFunc,
  807. LPVOID lpData)
  808. {
  809. PIMEDPI pImeDpi;
  810. LRESULT lRet = 0;
  811. pImeDpi = FindOrLoadImeDpi(hKL);
  812. if (pImeDpi == NULL) {
  813. RIPMSG0(RIP_WARNING, "ImmEscapeA: no pImeDpi entry.");
  814. return lRet;
  815. }
  816. if ((pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) == 0 || lpData == NULL) {
  817. /*
  818. * Doesn't need A/W conversion. Calls directly to IME to
  819. * bring up the configuration dialogbox.
  820. */
  821. #if !defined(CUAS_ENABLE)
  822. lRet = (*pImeDpi->pfn.ImeEscape)(hImc, uSubFunc, lpData);
  823. #else
  824. if (IS_IME_KBDLAYOUT(hKL)) {
  825. lRet = (*pImeDpi->pfn.ImeEscape)(hImc, uSubFunc, lpData);
  826. }
  827. else if (IS_CICERO_ENABLED_AND_NOT16BIT()) {
  828. lRet = (*pImeDpi->pfn.CtfImeEscapeEx)(hImc, uSubFunc, lpData, hKL);
  829. }
  830. #endif
  831. ImmUnlockImeDpi(pImeDpi);
  832. return lRet;
  833. }
  834. /*
  835. * ANSI caller, Unicode IME. Needs A/W conversion depending on
  836. * uSubFunc.
  837. */
  838. switch (uSubFunc) {
  839. case IME_ESC_GET_EUDC_DICTIONARY:
  840. case IME_ESC_IME_NAME:
  841. case IME_ESC_GETHELPFILENAME:
  842. {
  843. WCHAR wszData[IME_T_EUDC_DIC_SIZE];
  844. BOOL bUDC;
  845. INT i;
  846. lRet = ImmEscapeW(hKL, hImc, uSubFunc, (LPVOID)wszData);
  847. if (lRet != 0) {
  848. try {
  849. i = WideCharToMultiByte(IMECodePage(pImeDpi),
  850. (DWORD)0,
  851. (LPWSTR)wszData, // src
  852. (INT)wcslen(wszData),
  853. (LPSTR)lpData, // dest
  854. (INT)IME_T_EUDC_DIC_SIZE,
  855. (LPSTR)NULL,
  856. (LPBOOL)&bUDC);
  857. ((LPSTR)lpData)[i] = '\0';
  858. }
  859. except (EXCEPTION_EXECUTE_HANDLER) {
  860. lRet = 0;
  861. }
  862. }
  863. break;
  864. }
  865. case IME_ESC_SET_EUDC_DICTIONARY:
  866. case IME_ESC_HANJA_MODE:
  867. {
  868. WCHAR wszData[IME_T_EUDC_DIC_SIZE];
  869. INT i;
  870. i = MultiByteToWideChar(IMECodePage(pImeDpi),
  871. (DWORD)MB_PRECOMPOSED,
  872. (LPSTR)lpData, // src
  873. (INT)strlen(lpData),
  874. (LPWSTR)wszData, // dest
  875. (INT)sizeof(wszData)/sizeof(WCHAR));
  876. wszData[i] = L'\0';
  877. lRet = ImmEscapeW(hKL, hImc, uSubFunc, (LPVOID)wszData);
  878. break;
  879. }
  880. case IME_ESC_SEQUENCE_TO_INTERNAL:
  881. {
  882. CHAR szData[4];
  883. WCHAR wszData[4];
  884. INT i = 0;
  885. lRet = ImmEscapeW(hKL, hImc, uSubFunc, lpData);
  886. if (HIWORD(lRet))
  887. wszData[i++] = HIWORD(lRet);
  888. if (LOWORD(lRet))
  889. wszData[i++] = LOWORD(lRet);
  890. i = WideCharToMultiByte(IMECodePage(pImeDpi),
  891. (DWORD)0,
  892. (LPWSTR)wszData, // src
  893. (INT)i,
  894. (LPSTR)szData, // dest
  895. (INT)sizeof(szData),
  896. (LPSTR)NULL,
  897. (LPBOOL)NULL);
  898. switch (i) {
  899. case 1:
  900. lRet = MAKELONG(MAKEWORD(szData[0], 0), 0);
  901. break;
  902. case 2:
  903. lRet = MAKELONG(MAKEWORD(szData[1], szData[0]), 0);
  904. break;
  905. case 3:
  906. lRet = MAKELONG(MAKEWORD(szData[2], szData[1]), MAKEWORD(szData[0], 0));
  907. break;
  908. case 4:
  909. lRet = MAKELONG(MAKEWORD(szData[3], szData[2]), MAKEWORD(szData[1], szData[0]));
  910. break;
  911. default:
  912. lRet = 0;
  913. break;
  914. }
  915. break;
  916. }
  917. default:
  918. lRet = ImmEscapeW(hKL, hImc, uSubFunc, lpData);
  919. break;
  920. }
  921. ImmUnlockImeDpi(pImeDpi);
  922. return lRet;
  923. }
  924. /***************************************************************************\
  925. * ImmEscapeW
  926. *
  927. * This API allows an application to access capabilities of a particular
  928. * IME with specified hKL not directly available thru. other IMM APIs.
  929. * This is necessary mainly for country specific functions or private
  930. * functions in IME.
  931. *
  932. * History:
  933. * 29-Feb-1995 wkwok Created
  934. \***************************************************************************/
  935. LRESULT WINAPI ImmEscapeW(
  936. HKL hKL,
  937. HIMC hImc,
  938. UINT uSubFunc,
  939. LPVOID lpData)
  940. {
  941. PIMEDPI pImeDpi;
  942. LRESULT lRet = 0;
  943. pImeDpi = FindOrLoadImeDpi(hKL);
  944. if (pImeDpi == NULL) {
  945. RIPMSG0(RIP_WARNING, "ImmEscapeW: no pImeDpi entry.");
  946. return lRet;
  947. }
  948. if ((pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) || lpData == NULL) {
  949. /*
  950. * Doesn't need W/A conversion. Calls directly to IME to
  951. * bring up the configuration dialogbox.
  952. */
  953. #if !defined(CUAS_ENABLE)
  954. lRet = (*pImeDpi->pfn.ImeEscape)(hImc, uSubFunc, lpData);
  955. #else
  956. if (IS_IME_KBDLAYOUT(hKL)) {
  957. lRet = (*pImeDpi->pfn.ImeEscape)(hImc, uSubFunc, lpData);
  958. }
  959. else if (IS_CICERO_ENABLED_AND_NOT16BIT()) {
  960. lRet = (*pImeDpi->pfn.CtfImeEscapeEx)(hImc, uSubFunc, lpData, hKL);
  961. }
  962. #endif
  963. ImmUnlockImeDpi(pImeDpi);
  964. return lRet;
  965. }
  966. /*
  967. * Unicode caller, ANSI IME. Needs W/A conversion depending on
  968. * uSubFunc.
  969. */
  970. switch (uSubFunc) {
  971. case IME_ESC_GET_EUDC_DICTIONARY:
  972. case IME_ESC_IME_NAME:
  973. case IME_ESC_GETHELPFILENAME:
  974. {
  975. CHAR szData[IME_T_EUDC_DIC_SIZE];
  976. INT i;
  977. lRet = ImmEscapeA(hKL, hImc, uSubFunc, (LPVOID)szData);
  978. if (lRet != 0) {
  979. try {
  980. i = MultiByteToWideChar(IMECodePage(pImeDpi),
  981. (DWORD)MB_PRECOMPOSED,
  982. (LPSTR)szData, // src
  983. (INT)strlen(szData),
  984. (LPWSTR)lpData, // dest
  985. (INT)IME_T_EUDC_DIC_SIZE);
  986. ((LPWSTR)lpData)[i] = L'\0';
  987. }
  988. except (EXCEPTION_EXECUTE_HANDLER) {
  989. lRet = 0;
  990. }
  991. }
  992. break;
  993. }
  994. case IME_ESC_SET_EUDC_DICTIONARY:
  995. case IME_ESC_HANJA_MODE:
  996. {
  997. CHAR szData[IME_T_EUDC_DIC_SIZE];
  998. BOOL bUDC;
  999. INT i;
  1000. i = WideCharToMultiByte(IMECodePage(pImeDpi),
  1001. (DWORD)0,
  1002. (LPWSTR)lpData, // src
  1003. (INT)wcslen(lpData),
  1004. (LPSTR)szData, // dest
  1005. (INT)sizeof(szData),
  1006. (LPSTR)NULL,
  1007. (LPBOOL)&bUDC);
  1008. szData[i] = '\0';
  1009. lRet = ImmEscapeA(hKL, hImc, uSubFunc, (LPVOID)szData);
  1010. break;
  1011. }
  1012. case IME_ESC_SEQUENCE_TO_INTERNAL:
  1013. {
  1014. CHAR szData[4];
  1015. WCHAR wszData[4];
  1016. INT i = 0;
  1017. lRet = ImmEscapeA(hKL, hImc, uSubFunc, lpData);
  1018. if (HIBYTE(LOWORD(lRet)))
  1019. szData[i++] = HIBYTE(LOWORD(lRet));
  1020. if (LOBYTE(LOWORD(lRet)))
  1021. szData[i++] = LOBYTE(LOWORD(lRet));
  1022. i = MultiByteToWideChar(IMECodePage(pImeDpi),
  1023. (DWORD)MB_PRECOMPOSED,
  1024. (LPSTR)szData, // src
  1025. i,
  1026. (LPWSTR)wszData, // dest
  1027. (INT)sizeof(wszData)/sizeof(WCHAR));
  1028. switch (i) {
  1029. case 1:
  1030. lRet = MAKELONG(wszData[0], 0);
  1031. break;
  1032. case 2:
  1033. lRet = MAKELONG(wszData[1], wszData[0]);
  1034. break;
  1035. default:
  1036. lRet = 0;
  1037. break;
  1038. }
  1039. break;
  1040. }
  1041. default:
  1042. lRet = ImmEscapeA(hKL, hImc, uSubFunc, lpData);
  1043. break;
  1044. }
  1045. ImmUnlockImeDpi(pImeDpi);
  1046. return lRet;
  1047. }
  1048. BOOL WINAPI ImmNotifyIME(
  1049. HIMC hImc,
  1050. DWORD dwAction,
  1051. DWORD dwIndex,
  1052. DWORD dwValue)
  1053. {
  1054. PIMEDPI pImeDpi;
  1055. BOOL bRet;
  1056. if (hImc != NULL_HIMC &&
  1057. GetInputContextThread(hImc) != GetCurrentThreadId()) {
  1058. RIPMSG1(RIP_WARNING,
  1059. "ImmNotifyIME: Invalid input context access %lx.", hImc);
  1060. return FALSE;
  1061. }
  1062. pImeDpi = ImmLockImeDpi(GetKeyboardLayout(0));
  1063. if (pImeDpi == NULL)
  1064. return FALSE;
  1065. bRet = (*pImeDpi->pfn.NotifyIME)(hImc, dwAction, dwIndex, dwValue);
  1066. ImmUnlockImeDpi(pImeDpi);
  1067. return bRet;
  1068. }