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.

1102 lines
34 KiB

  1. /*++
  2. Copyright (c) 1990-1999 Microsoft Corporation, All Rights Reserved
  3. Module Name:
  4. INIT.c
  5. Abstract:
  6. IME sample source code. This is pure UNICODE implementation of IME.
  7. ++*/
  8. #include <windows.h>
  9. #include <commdlg.h>
  10. #include <winerror.h>
  11. #include <immdev.h>
  12. #include "imeattr.h"
  13. #include "imerc.h"
  14. #include "imedefs.h"
  15. #if defined(MINIIME) || defined(UNIIME)
  16. #include "uniime.h"
  17. #endif
  18. #if !defined(MINIIME)
  19. /**********************************************************************/
  20. /* InitImeGlobalData() */
  21. /**********************************************************************/
  22. void PASCAL InitImeGlobalData(void)
  23. {
  24. #if !defined(ROMANIME)
  25. TCHAR szChiChar[4];
  26. HDC hDC;
  27. HGDIOBJ hOldFont;
  28. LOGFONT lfFont;
  29. SIZE lTextSize;
  30. int xHalfWi[2];
  31. #endif
  32. HGLOBAL hResData;
  33. int i;
  34. #if !defined(ROMANIME)
  35. DWORD dwSize;
  36. HKEY hKeyNearCaret;
  37. LONG lRet;
  38. #endif
  39. {
  40. RECT rcWorkArea;
  41. // get work area
  42. SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0);
  43. if (rcWorkArea.right < 2 * UI_MARGIN) {
  44. } else if (rcWorkArea.bottom < 2 * UI_MARGIN) {
  45. } else {
  46. sImeG.rcWorkArea = rcWorkArea;
  47. }
  48. }
  49. if (sImeG.wFullSpace) {
  50. // the global data already init
  51. return;
  52. }
  53. sImeG.uAnsiCodePage = NATIVE_ANSI_CP;
  54. #if !defined(ROMANIME)
  55. // get the Chinese char
  56. LoadString(hInst, IDS_CHICHAR, szChiChar, sizeof(szChiChar)/sizeof(TCHAR));
  57. // get size of Chinese char
  58. hDC = GetDC(NULL);
  59. hOldFont = GetCurrentObject(hDC, OBJ_FONT);
  60. GetObject(hOldFont, sizeof(LOGFONT), &lfFont);
  61. if (lfFont.lfCharSet != NATIVE_CHARSET) {
  62. // Chicago Simplified Chinese
  63. sImeG.fDiffSysCharSet = TRUE;
  64. lfFont.lfCharSet = NATIVE_CHARSET;
  65. lfFont.lfFaceName[0] = TEXT('\0');
  66. } else {
  67. sImeG.fDiffSysCharSet = FALSE;
  68. }
  69. lfFont.lfWeight = FW_DONTCARE;
  70. SelectObject(hDC, CreateFontIndirect(&lfFont));
  71. GetTextExtentPoint(hDC, szChiChar, lstrlen(szChiChar), &lTextSize);
  72. if (sImeG.rcWorkArea.right < 2 * UI_MARGIN) {
  73. sImeG.rcWorkArea.left = 0;
  74. sImeG.rcWorkArea.right = GetDeviceCaps(hDC, HORZRES);
  75. }
  76. if (sImeG.rcWorkArea.bottom < 2 * UI_MARGIN) {
  77. sImeG.rcWorkArea.top = 0;
  78. sImeG.rcWorkArea.bottom = GetDeviceCaps(hDC, VERTRES);
  79. }
  80. DeleteObject(SelectObject(hDC, hOldFont));
  81. ReleaseDC(NULL, hDC);
  82. // get text metrics to decide the width & height of composition window
  83. // these IMEs always use system font to show
  84. sImeG.xChiCharWi = lTextSize.cx;
  85. sImeG.yChiCharHi = lTextSize.cy;
  86. // if unfortunate the xChiCharWi is odd number, xHalfWi[0] != xHalfWi[1]
  87. xHalfWi[0] = sImeG.xChiCharWi / 2;
  88. xHalfWi[1] = sImeG.xChiCharWi - xHalfWi[0];
  89. for (i = 0; i < sizeof(iDx) / sizeof(int); i++) {
  90. #ifdef UNICODE
  91. iDx[i] = sImeG.xChiCharWi;
  92. #else
  93. iDx[i] = xHalfWi[i % 2];
  94. #endif
  95. }
  96. #endif
  97. // load full ABC chars
  98. hResData = LoadResource(hInst, FindResource(hInst,
  99. MAKEINTRESOURCE(IDRC_FULLABC), RT_RCDATA));
  100. *(LPFULLABC)sImeG.wFullABC = *(LPFULLABC)LockResource(hResData);
  101. UnlockResource(hResData);
  102. FreeResource(hResData);
  103. // full shape space
  104. sImeG.wFullSpace = sImeG.wFullABC[0];
  105. #ifndef UNICODE
  106. // reverse internal code to internal code, NT don't need it
  107. for (i = 0; i < NFULLABC; i++) {
  108. sImeG.wFullABC[i] = (sImeG.wFullABC[i] << 8) |
  109. (sImeG.wFullABC[i] >> 8);
  110. }
  111. #endif
  112. #if !defined(ROMANIME) && !defined(WINAR30)
  113. // load symbol chars
  114. hResData = LoadResource(hInst, FindResource(hInst,
  115. MAKEINTRESOURCE(IDRC_SYMBOL), RT_RCDATA));
  116. *(LPSYMBOL)sImeG.wSymbol = *(LPSYMBOL)LockResource(hResData);
  117. UnlockResource(hResData);
  118. FreeResource(hResData);
  119. #ifndef UNICODE
  120. // reverse internal code to internal code, UNICODE don't need it
  121. for (i = 0; i < NSYMBOL; i++) {
  122. sImeG.wSymbol[i] = (sImeG.wSymbol[i] << 8) |
  123. (sImeG.wSymbol[i] >> 8);
  124. }
  125. #endif
  126. #endif
  127. #ifdef HANDLE_PRIVATE_HOTKEY
  128. // get IME hot key
  129. for (i = 0; i < NUM_OF_IME_HOTKEYS; i++) {
  130. ImmGetHotKey(IME_ITHOTKEY_RESEND_RESULTSTR + i, &sImeG.uModifiers[i],
  131. &sImeG.uVKey[i], NULL);
  132. }
  133. #endif
  134. #if defined(UNIIME)
  135. // phrase table files
  136. hResData = LoadResource(hInst, FindResource(hInst,
  137. MAKEINTRESOURCE(IDRC_PHRASETABLES), RT_RCDATA));
  138. *(LPPHRASETABLES)sImeG.szTblFile[0] =
  139. *(LPPHRASETABLES)LockResource(hResData);
  140. UnlockResource(hResData);
  141. FreeResource(hResData);
  142. #endif
  143. #if !defined(ROMANIME)
  144. // get the UI offset for near caret operation
  145. RegCreateKey(HKEY_CURRENT_USER, szRegNearCaret, &hKeyNearCaret);
  146. #if defined(UNIIME) && defined(UNICODE)
  147. // if the user has its own phrase table file, we will overwrite it
  148. {
  149. TCHAR szPhraseDictionary[MAX_PATH];
  150. TCHAR szPhrasePointer[MAX_PATH];
  151. dwSize = sizeof(szPhraseDictionary);
  152. lRet = RegQueryValueEx(hKeyNearCaret, szPhraseDic, NULL, NULL,
  153. (LPBYTE)szPhraseDictionary, &dwSize);
  154. if (lRet != ERROR_SUCCESS) {
  155. goto PharseOvr;
  156. }
  157. if (dwSize >= sizeof(szPhraseDictionary)) {
  158. goto PharseOvr;
  159. } else {
  160. szPhraseDictionary[dwSize / sizeof(TCHAR)] = TEXT('\0');
  161. }
  162. dwSize = sizeof(szPhrasePointer);
  163. lRet = RegQueryValueEx(hKeyNearCaret, szPhrasePtr, NULL, NULL,
  164. (LPBYTE)szPhrasePointer, &dwSize);
  165. if (lRet != ERROR_SUCCESS) {
  166. goto PharseOvr;
  167. }
  168. if (dwSize >= sizeof(szPhrasePointer)) {
  169. goto PharseOvr;
  170. } else {
  171. szPhrasePointer[dwSize / sizeof(TCHAR)] = TEXT('\0');
  172. }
  173. dwSize = dwSize / sizeof(TCHAR) - 1;
  174. for (; dwSize > 0; dwSize--) {
  175. if (szPhrasePointer[dwSize] == TEXT('\\')) {
  176. CopyMemory(sImeG.szPhrasePath, szPhrasePointer,
  177. (dwSize + 1) * sizeof(TCHAR));
  178. sImeG.uPathLen = dwSize + 1;
  179. // phrase pointer file name
  180. CopyMemory(sImeG.szTblFile[0], &szPhrasePointer[dwSize + 1],
  181. sizeof(sImeG.szTblFile[0]));
  182. // phrase file name
  183. CopyMemory(sImeG.szTblFile[1], &szPhraseDictionary[dwSize + 1],
  184. sizeof(sImeG.szTblFile[1]));
  185. break;
  186. }
  187. }
  188. PharseOvr: ; // NULL statement for goto
  189. }
  190. #endif
  191. dwSize = sizeof(dwSize);
  192. lRet = RegQueryValueEx(hKeyNearCaret, szPara, NULL, NULL,
  193. (LPBYTE)&sImeG.iPara, &dwSize);
  194. if (lRet != ERROR_SUCCESS) {
  195. sImeG.iPara = 0;
  196. RegSetValueEx(hKeyNearCaret, szPara, 0, REG_DWORD,
  197. (LPBYTE)&sImeG.iPara, sizeof(int));
  198. }
  199. dwSize = sizeof(dwSize);
  200. lRet = RegQueryValueEx(hKeyNearCaret, szPerp, NULL, NULL,
  201. (LPBYTE)&sImeG.iPerp, &dwSize);
  202. if (lRet != ERROR_SUCCESS) {
  203. sImeG.iPerp = sImeG.yChiCharHi;
  204. RegSetValueEx(hKeyNearCaret, szPerp, 0, REG_DWORD,
  205. (LPBYTE)&sImeG.iPerp, sizeof(int));
  206. }
  207. dwSize = sizeof(dwSize);
  208. lRet = RegQueryValueEx(hKeyNearCaret, szParaTol, NULL, NULL,
  209. (LPBYTE)&sImeG.iParaTol, &dwSize);
  210. if (lRet != ERROR_SUCCESS) {
  211. sImeG.iParaTol = sImeG.xChiCharWi * 4;
  212. RegSetValueEx(hKeyNearCaret, szParaTol, 0, REG_DWORD,
  213. (LPBYTE)&sImeG.iParaTol, sizeof(int));
  214. }
  215. dwSize = sizeof(dwSize);
  216. lRet = RegQueryValueEx(hKeyNearCaret, szPerpTol, NULL, NULL,
  217. (LPBYTE)&sImeG.iPerpTol, &dwSize);
  218. if (lRet != ERROR_SUCCESS) {
  219. sImeG.iPerpTol = sImeG.yChiCharHi;
  220. RegSetValueEx(hKeyNearCaret, szPerpTol, 0, REG_DWORD,
  221. (LPBYTE)&sImeG.iPerpTol, sizeof(int));
  222. }
  223. RegCloseKey(hKeyNearCaret);
  224. #endif
  225. return;
  226. }
  227. /**********************************************************************/
  228. /* GetUserSetting() */
  229. /**********************************************************************/
  230. DWORD PASCAL GetUserSetting(
  231. #if defined(UNIIME)
  232. LPIMEL lpImeL,
  233. #endif
  234. LPCTSTR lpszValueName,
  235. LPVOID lpbData,
  236. DWORD dwDataSize)
  237. {
  238. HKEY hKeyAppUser, hKeyIMEUser;
  239. RegCreateKey(HKEY_CURRENT_USER, szRegAppUser, &hKeyAppUser);
  240. RegCreateKey(hKeyAppUser, lpImeL->szUIClassName, &hKeyIMEUser);
  241. RegCloseKey(hKeyAppUser);
  242. RegQueryValueEx(hKeyIMEUser, lpszValueName, NULL, NULL,
  243. lpbData, &dwDataSize);
  244. RegCloseKey(hKeyIMEUser);
  245. return (dwDataSize);
  246. }
  247. /**********************************************************************/
  248. /* SetUserSetting() */
  249. /**********************************************************************/
  250. void PASCAL SetUserSetting(
  251. #if defined(UNIIME)
  252. LPIMEL lpImeL,
  253. #endif
  254. LPCTSTR lpszValueName,
  255. DWORD dwType,
  256. LPBYTE lpbData,
  257. DWORD dwDataSize)
  258. {
  259. HKEY hKeyAppUser, hKeyIMEUser;
  260. RegCreateKey(HKEY_CURRENT_USER, szRegAppUser, &hKeyAppUser);
  261. RegCreateKey(hKeyAppUser, lpImeL->szUIClassName, &hKeyIMEUser);
  262. RegCloseKey(hKeyAppUser);
  263. RegSetValueEx(hKeyIMEUser, lpszValueName, 0, dwType, lpbData,
  264. dwDataSize);
  265. RegCloseKey(hKeyIMEUser);
  266. return;
  267. }
  268. void RemoveRearSpaces( LPTSTR lpStr )
  269. {
  270. INT iLen;
  271. if (lpStr == NULL ) return;
  272. iLen = lstrlen(lpStr);
  273. if ( iLen == 0 ) return;
  274. iLen = iLen - 1;
  275. while ( iLen >= 0 ) {
  276. if ( lpStr[iLen] == TEXT(' ') ) {
  277. lpStr[iLen] = TEXT('\0');
  278. iLen --;
  279. }
  280. else
  281. break;
  282. }
  283. return;
  284. }
  285. /**********************************************************************/
  286. /* InitImeLocalData() */
  287. /**********************************************************************/
  288. BOOL PASCAL InitImeLocalData(
  289. LPINSTDATAL lpInstL,
  290. LPIMEL lpImeL)
  291. {
  292. #if !defined(ROMANIME)
  293. HGLOBAL hResData;
  294. UINT i;
  295. WORD nSeqCode;
  296. #if defined(PHON)
  297. UINT nReadLayout;
  298. #endif
  299. #endif
  300. // the local data already init
  301. if (lpImeL->szIMEName[0]) {
  302. return (TRUE);
  303. }
  304. // we will use the same string length for W version so / sizeof(WORD)
  305. // get the IME name
  306. LoadString(lpInstL->hInst, IDS_IMENAME, lpImeL->szIMEName,
  307. sizeof(lpImeL->szIMEName) / sizeof(WCHAR));
  308. // get the UI class name
  309. LoadString(lpInstL->hInst, IDS_IMEUICLASS, lpImeL->szUIClassName,
  310. sizeof(lpImeL->szUIClassName) / sizeof(WCHAR));
  311. RemoveRearSpaces(lpImeL->szUIClassName);
  312. #if !defined(ROMANIME)
  313. // get the composition class name
  314. LoadString(lpInstL->hInst, IDS_IMECOMPCLASS, lpImeL->szCompClassName,
  315. sizeof(lpImeL->szCompClassName) / sizeof(WCHAR));
  316. RemoveRearSpaces(lpImeL->szCompClassName);
  317. // get the candidate class name
  318. LoadString(lpInstL->hInst, IDS_IMECANDCLASS, lpImeL->szCandClassName,
  319. sizeof(lpImeL->szCandClassName) / sizeof(WCHAR));
  320. RemoveRearSpaces(lpImeL->szCandClassName);
  321. #endif
  322. // get the status class name
  323. LoadString(lpInstL->hInst, IDS_IMESTATUSCLASS, lpImeL->szStatusClassName,
  324. sizeof(lpImeL->szStatusClassName) / sizeof(WCHAR));
  325. RemoveRearSpaces(lpImeL->szStatusClassName);
  326. // get the off caret class name
  327. LoadString(lpInstL->hInst, IDS_IMEOFFCARETCLASS,
  328. lpImeL->szOffCaretClassName,
  329. sizeof(lpImeL->szOffCaretClassName) / sizeof(WCHAR));
  330. RemoveRearSpaces(lpImeL->szOffCaretClassName);
  331. LoadString(lpInstL->hInst, IDS_IMECMENUCLASS, lpImeL->szCMenuClassName,
  332. sizeof(lpImeL->szCMenuClassName) / sizeof(WCHAR));
  333. RemoveRearSpaces(lpImeL->szCMenuClassName);
  334. #if defined(ROMANIME)
  335. lpImeL->nMaxKey = 1;
  336. #else
  337. // table not loaded
  338. // lpInstL->fdwTblLoad = TBL_NOTLOADED;
  339. // reference count is 0
  340. // lpInstL->cRefCount = 0;
  341. // tables are NULL
  342. // lpInstL->hMapTbl[] = (HANDLE)NULL;
  343. // user dictionary is NULL
  344. // lpInstL->hUsrDicMem = (HANLE)NULL;
  345. // load valid char in choose/input state
  346. hResData = LoadResource(lpInstL->hInst, FindResource(lpInstL->hInst,
  347. MAKEINTRESOURCE(IDRC_VALIDCHAR), RT_RCDATA));
  348. *(LPVALIDCHAR)&lpImeL->dwVersion = *(LPVALIDCHAR)LockResource(hResData);
  349. UnlockResource(hResData);
  350. FreeResource(hResData);
  351. #if !defined(WINIME) && !defined(UNICDIME)
  352. // IME table files
  353. hResData = LoadResource(lpInstL->hInst, FindResource(lpInstL->hInst,
  354. MAKEINTRESOURCE(IDRC_TABLEFILES), RT_RCDATA));
  355. *(LPTABLEFILES)lpImeL->szTblFile[0] =
  356. *(LPTABLEFILES)LockResource(hResData);
  357. UnlockResource(hResData);
  358. FreeResource(hResData);
  359. #ifndef UNICODE
  360. #if defined(DAYI) || defined(WINAR30)
  361. for (i = 0; i < sizeof(lpImeL->wSymbol) / sizeof(WORD); i++) {
  362. lpImeL->wSymbol[i] = (lpImeL->wSymbol[i] << 8) |
  363. (lpImeL->wSymbol[i] >> 8);
  364. }
  365. #endif
  366. #endif
  367. // file name of user dictionary
  368. lpImeL->szUsrDic[0] = TEXT('\0'); // default value
  369. i = GetUserSetting(
  370. #if defined(UNIIME)
  371. lpImeL,
  372. #endif
  373. szRegUserDic, lpImeL->szUsrDic, sizeof(lpImeL->szUsrDic));
  374. if (i >= sizeof(lpImeL->szUsrDic)) {
  375. lpImeL->szUsrDic[sizeof(lpImeL->szUsrDic) / sizeof(TCHAR) - 1] = '\0';
  376. } else {
  377. lpImeL->szUsrDic[i / sizeof(TCHAR)] = '\0';
  378. }
  379. lpImeL->szUsrDicMap[0] = '\0';
  380. if (lpImeL->szUsrDic[0]) {
  381. TCHAR szTempDir[MAX_PATH];
  382. TCHAR szTempFile[MAX_PATH];
  383. GetTempPath(sizeof(szTempDir) / sizeof(TCHAR), szTempDir);
  384. // we do not want to create a real file so we GetTickCount
  385. i = (UINT)GetTickCount();
  386. if (!i) {
  387. i++;
  388. }
  389. GetTempFileName(szTempDir, lpImeL->szUIClassName, i, szTempFile);
  390. GetFileTitle(szTempFile, lpImeL->szUsrDicMap,
  391. sizeof(lpImeL->szUsrDicMap) / sizeof(TCHAR));
  392. }
  393. #endif
  394. nSeqCode = 0x0001;
  395. for (i = 1; i < sizeof(DWORD) * 8; i++) {
  396. nSeqCode <<= 1;
  397. if (nSeqCode > lpImeL->nSeqCode) {
  398. lpImeL->nSeqBits = (WORD)i;
  399. break;
  400. }
  401. }
  402. // calculate sequence code mask for one stoke (reading char)
  403. if (!lpImeL->dwSeqMask) { // check again, it is still possible
  404. // that multiple thread reach here
  405. for (i = 0; i < lpImeL->nSeqBits; i++) {
  406. lpImeL->dwSeqMask <<= 1;
  407. lpImeL->dwSeqMask |= 0x0001;
  408. }
  409. }
  410. // data bytes for one finalized char
  411. lpImeL->nSeqBytes = (lpImeL->nSeqBits * lpImeL->nMaxKey + 7) / 8;
  412. // valid bits mask for all strokes
  413. if (!lpImeL->dwPatternMask) { // check again, it is still possible
  414. // that multiple thread reach here
  415. for (i =0; i < lpImeL->nMaxKey; i++) {
  416. lpImeL->dwPatternMask <<= lpImeL->nSeqBits;
  417. lpImeL->dwPatternMask |= lpImeL->dwSeqMask;
  418. }
  419. }
  420. lpImeL->hRevKL = NULL;
  421. GetUserSetting(
  422. #if defined(UNIIME)
  423. lpImeL,
  424. #endif
  425. szRegRevKL, &lpImeL->hRevKL, sizeof(lpImeL->hRevKL));
  426. // mark this event for later check reverse length
  427. if (lpImeL->hRevKL) {
  428. lpImeL->fdwErrMsg |= NO_REV_LENGTH;
  429. }
  430. // we assume the max key is the same as this IME, check later
  431. lpImeL->nRevMaxKey = lpImeL->nMaxKey;
  432. #if defined(PHON)
  433. // keyboard arrangement, ACER ETen IBM ... for bo po mo fo
  434. nReadLayout = READ_LAYOUT_DEFAULT; // default value
  435. // can not use lpImeL->nReadLayout, its size is WORD only
  436. GetUserSetting(
  437. #if defined(UNIIME)
  438. lpImeL,
  439. #endif
  440. szRegReadLayout, &nReadLayout, sizeof(nReadLayout));
  441. lpImeL->nReadLayout = (WORD)nReadLayout;
  442. if (lpImeL->nReadLayout >= READ_LAYOUTS) {
  443. lpImeL->nReadLayout = READ_LAYOUT_DEFAULT;
  444. }
  445. #endif
  446. #endif
  447. #if defined(WINAR30)
  448. lpImeL->fdwModeConfig = MODE_CONFIG_QUICK_KEY|MODE_CONFIG_PREDICT;
  449. #elif defined(ROMANIME)
  450. lpImeL->fdwModeConfig = 0;
  451. #else
  452. lpImeL->fdwModeConfig = MODE_CONFIG_PREDICT;
  453. #endif
  454. GetUserSetting(
  455. #if defined(UNIIME)
  456. lpImeL,
  457. #endif
  458. szRegModeConfig, &lpImeL->fdwModeConfig, sizeof(lpImeL->fdwModeConfig));
  459. return (TRUE);
  460. }
  461. /**********************************************************************/
  462. /* InitImeUIData() */
  463. /**********************************************************************/
  464. void PASCAL InitImeUIData( // initialize each UI component coordination
  465. LPIMEL lpImeL)
  466. {
  467. int cxBorder, cyBorder, cxEdge, cyEdge, cxMinWindowWidth;
  468. cxEdge = GetSystemMetrics(SM_CXEDGE);
  469. cyEdge = GetSystemMetrics(SM_CYEDGE);
  470. // border + raising edge
  471. cxBorder = GetSystemMetrics(SM_CXBORDER);
  472. cyBorder = GetSystemMetrics(SM_CYBORDER);
  473. lpImeL->cxStatusBorder = cxBorder + cxEdge;
  474. lpImeL->cyStatusBorder = cyBorder + cyEdge;
  475. // the width/high and status position relative to status window
  476. lpImeL->rcStatusText.left = 0;
  477. lpImeL->rcStatusText.top = 0;
  478. lpImeL->rcStatusText.bottom = lpImeL->rcStatusText.top + STATUS_DIM_Y;
  479. // conversion mode status
  480. lpImeL->rcInputText.left = lpImeL->rcStatusText.left;
  481. lpImeL->rcInputText.top = lpImeL->rcStatusText.top;
  482. lpImeL->rcInputText.right = lpImeL->rcInputText.left + STATUS_DIM_X;
  483. lpImeL->rcInputText.bottom = lpImeL->rcStatusText.bottom;
  484. // full/half shape status
  485. lpImeL->rcShapeText.left = lpImeL->rcInputText.right;
  486. lpImeL->rcShapeText.top = lpImeL->rcStatusText.top;
  487. lpImeL->rcShapeText.right = lpImeL->rcShapeText.left + STATUS_DIM_X;
  488. lpImeL->rcShapeText.bottom = lpImeL->rcStatusText.bottom;
  489. lpImeL->rcStatusText.right = lpImeL->rcShapeText.right;
  490. lpImeL->xStatusWi = (lpImeL->rcStatusText.right -
  491. lpImeL->rcStatusText.left) + lpImeL->cxStatusBorder * 2;
  492. lpImeL->yStatusHi = (lpImeL->rcStatusText.bottom -
  493. lpImeL->rcStatusText.top) + lpImeL->cyStatusBorder * 2;
  494. #if !defined(ROMANIME)
  495. if (lpImeL->fdwModeConfig & MODE_CONFIG_OFF_CARET_UI) {
  496. lpImeL->cxCompBorder = cxBorder + cxEdge;
  497. lpImeL->cyCompBorder = cyBorder + cyEdge;
  498. } else {
  499. lpImeL->cxCompBorder = cxBorder;
  500. lpImeL->cyCompBorder = cyBorder;
  501. }
  502. lpImeL->rcCompText.top = lpImeL->cyCompBorder;
  503. lpImeL->rcCompText.bottom = lpImeL->rcCompText.top +
  504. sImeG.yChiCharHi;
  505. // two borders, outsize & candidate inside border
  506. if (lpImeL->fdwModeConfig & MODE_CONFIG_OFF_CARET_UI) {
  507. lpImeL->cxCandBorder = cxBorder + cxEdge;
  508. lpImeL->cyCandBorder = cyBorder + cyEdge;
  509. } else {
  510. lpImeL->cxCandBorder = cxBorder;
  511. lpImeL->cyCandBorder = cyBorder;
  512. }
  513. lpImeL->cxCandMargin = cxBorder + cxEdge;
  514. lpImeL->cyCandMargin = cyBorder + cyEdge;
  515. // the width/high and text position relative to candidate window
  516. if (lpImeL->fdwModeConfig & MODE_CONFIG_OFF_CARET_UI) {
  517. lpImeL->rcCandText.top = lpImeL->cyCandBorder;
  518. #if defined(WINAR30)
  519. lpImeL->rcCompText.left = lpImeL->rcStatusText.right +
  520. lpImeL->cxCompBorder * 2;
  521. lpImeL->rcCompText.right = lpImeL->rcCompText.left +
  522. sImeG.xChiCharWi * lpImeL->nRevMaxKey;
  523. lpImeL->rcCandText.left = lpImeL->rcCompText.right +
  524. lpImeL->cxCompBorder * 2 + lpImeL->cxCandBorder;
  525. lpImeL->rcCandText.right = lpImeL->rcCandText.left +
  526. sImeG.xChiCharWi * CANDPERPAGE * 3 / 2;
  527. #else
  528. lpImeL->rcCandText.left = lpImeL->rcCompText.left =
  529. lpImeL->rcStatusText.right + lpImeL->cxCompBorder +
  530. lpImeL->cxCandBorder;
  531. lpImeL->rcCandText.right = lpImeL->rcCompText.right =
  532. lpImeL->rcCompText.left + sImeG.xChiCharWi * CANDPERPAGE * 3 / 2;
  533. #endif
  534. lpImeL->rcCandText.bottom = lpImeL->rcCandText.top + sImeG.yChiCharHi;
  535. lpImeL->rcCandPrompt.left = lpImeL->rcCandText.right +
  536. lpImeL->cxCandMargin + lpImeL->cxCandBorder;
  537. lpImeL->rcCandPrompt.top = lpImeL->rcStatusText.top +
  538. (STATUS_DIM_Y - CAND_PROMPT_DIM_Y) / 2;
  539. lpImeL->rcCandPrompt.right = lpImeL->rcCandPrompt.left +
  540. CAND_PROMPT_DIM_X;
  541. lpImeL->rcCandPrompt.bottom = lpImeL->rcCandPrompt.top +
  542. CAND_PROMPT_DIM_Y;
  543. lpImeL->rcCandPageText.left = lpImeL->rcCandPrompt.right +
  544. lpImeL->cxCandMargin + lpImeL->cxCandBorder;
  545. lpImeL->rcCandPageText.top = lpImeL->rcStatusText.top +
  546. (STATUS_DIM_Y - PAGE_DIM_Y) / 2;
  547. lpImeL->rcCandPageText.bottom = lpImeL->rcCandPageText.top +
  548. PAGE_DIM_Y;
  549. lpImeL->rcCandPageUp.left = lpImeL->rcCandPageText.left;
  550. lpImeL->rcCandPageUp.top = lpImeL->rcCandPageText.top;
  551. lpImeL->rcCandPageUp.right = lpImeL->rcCandPageUp.left + PAGE_DIM_X;
  552. lpImeL->rcCandPageUp.bottom = lpImeL->rcCandPageText.bottom;
  553. lpImeL->rcCandHome.left = lpImeL->rcCandPageUp.right;
  554. lpImeL->rcCandHome.top = lpImeL->rcCandPageUp.top;
  555. lpImeL->rcCandHome.right = lpImeL->rcCandHome.left + PAGE_DIM_X;
  556. lpImeL->rcCandHome.bottom = lpImeL->rcCandPageUp.bottom;
  557. lpImeL->rcCandPageDn.left = lpImeL->rcCandHome.right;
  558. lpImeL->rcCandPageDn.top = lpImeL->rcCandHome.top;
  559. lpImeL->rcCandPageDn.right = lpImeL->rcCandPageDn.left + PAGE_DIM_X;
  560. lpImeL->rcCandPageDn.bottom = lpImeL->rcCandHome.bottom;
  561. lpImeL->rcCandPageText.right = lpImeL->rcCandPageDn.right;
  562. lpImeL->xCompWi = lpImeL->rcCandPageDn.right +
  563. lpImeL->cxCandMargin + lpImeL->cxCandBorder;
  564. lpImeL->xCandWi = lpImeL->xCompWi;
  565. lpImeL->xStatusWi = lpImeL->xCompWi;
  566. } else {
  567. lpImeL->rcCompText.left = lpImeL->cxCompBorder;
  568. lpImeL->rcCompText.right = lpImeL->rcCompText.left +
  569. sImeG.xChiCharWi * lpImeL->nRevMaxKey;
  570. lpImeL->rcCandPrompt.left = lpImeL->cxCandMargin;
  571. lpImeL->rcCandPrompt.top = lpImeL->cyCandBorder;
  572. lpImeL->rcCandPrompt.right = lpImeL->rcCandPrompt.left +
  573. CAND_PROMPT_DIM_X;
  574. lpImeL->rcCandPrompt.bottom = lpImeL->rcCandPrompt.top +
  575. CAND_PROMPT_DIM_Y;
  576. lpImeL->rcCandPageText.top = lpImeL->rcCandPrompt.top;
  577. lpImeL->rcCandPageText.bottom = lpImeL->rcCandPageText.top +
  578. PAGE_DIM_Y;
  579. lpImeL->rcCandPageUp.top = lpImeL->rcCandPageText.top;
  580. lpImeL->rcCandPageUp.bottom = lpImeL->rcCandPageText.bottom;
  581. lpImeL->rcCandHome.top = lpImeL->rcCandPageUp.top;
  582. lpImeL->rcCandHome.bottom = lpImeL->rcCandPageUp.bottom;
  583. lpImeL->rcCandPageDn.top = lpImeL->rcCandHome.top;
  584. lpImeL->rcCandPageDn.bottom = lpImeL->rcCandHome.bottom;
  585. lpImeL->rcCandText.left = lpImeL->cxCandMargin;
  586. lpImeL->rcCandText.top = lpImeL->rcCandPageText.bottom +
  587. lpImeL->cyCandBorder + lpImeL->cyCandMargin;
  588. //Window width should be at least 8 characters AND greater than total
  589. //width of the bitmaps.
  590. cxMinWindowWidth= CAND_PROMPT_DIM_X + 2 * PAGE_DIM_X +
  591. lpImeL->cxCandMargin + lpImeL->cxCandBorder;
  592. lpImeL->rcCandText.right = lpImeL->rcCandText.left +
  593. sImeG.xChiCharWi * 8 > cxMinWindowWidth ?
  594. sImeG.xChiCharWi * 8 : cxMinWindowWidth;
  595. lpImeL->rcCandText.bottom = lpImeL->rcCandText.top +
  596. sImeG.yChiCharHi * CANDPERPAGE;
  597. lpImeL->rcCandPageText.right = lpImeL->rcCandText.right;
  598. lpImeL->rcCandPageDn.right = lpImeL->rcCandPageText.right;
  599. lpImeL->rcCandPageDn.left = lpImeL->rcCandPageDn.right - PAGE_DIM_X;
  600. lpImeL->rcCandPageUp.right = lpImeL->rcCandPageDn.left;
  601. lpImeL->rcCandPageUp.left = lpImeL->rcCandPageUp.right - PAGE_DIM_X;
  602. lpImeL->rcCandPageText.left = lpImeL->rcCandPageUp.left;
  603. lpImeL->xCompWi = (lpImeL->rcCompText.right -
  604. lpImeL->rcCompText.left) + lpImeL->cxCompBorder * 2 * 2;
  605. lpImeL->xCandWi = (lpImeL->rcCandText.right -
  606. lpImeL->rcCandText.left) + lpImeL->cxCandBorder * 2 +
  607. lpImeL->cxCandMargin * 2;
  608. }
  609. lpImeL->yCompHi = (lpImeL->rcCompText.bottom - lpImeL->rcCompText.top) +
  610. lpImeL->cyCompBorder * 2 * 2;
  611. lpImeL->yCandHi = lpImeL->rcCandText.bottom + lpImeL->cyCandBorder * 2 +
  612. lpImeL->cyCandMargin;
  613. #endif
  614. #if !defined(ROMANIME)
  615. if (lpImeL->fdwModeConfig & MODE_CONFIG_OFF_CARET_UI) {
  616. // the font in composition window is higher than status bitmap
  617. if (lpImeL->yStatusHi < lpImeL->yCompHi) {
  618. int cyDelta;
  619. cyDelta = (lpImeL->yCompHi - lpImeL->yStatusHi) / 2;
  620. lpImeL->yStatusHi = lpImeL->yCompHi;
  621. lpImeL->rcShapeText.top = lpImeL->rcInputText.top =
  622. lpImeL->rcStatusText.top += cyDelta;
  623. lpImeL->rcShapeText.bottom = lpImeL->rcInputText.bottom =
  624. lpImeL->rcStatusText.bottom += cyDelta;
  625. lpImeL->rcCandPageUp.top = lpImeL->rcCandHome.top =
  626. lpImeL->rcCandPageDn.top += cyDelta;
  627. lpImeL->rcCandPageUp.bottom = lpImeL->rcCandHome.bottom =
  628. lpImeL->rcCandPageDn.bottom += cyDelta;
  629. }
  630. // the font in composition window is smaller than status bitmap
  631. if (lpImeL->yCompHi < lpImeL->yStatusHi) {
  632. int cyDelta;
  633. cyDelta = (lpImeL->yStatusHi - lpImeL->yCompHi) / 2;
  634. lpImeL->yCandHi = lpImeL->yCompHi = lpImeL->yStatusHi;
  635. lpImeL->rcCandText.top = lpImeL->rcCompText.top += cyDelta;
  636. lpImeL->rcCandText.bottom = lpImeL->rcCompText.bottom += cyDelta;
  637. }
  638. }
  639. #endif
  640. return;
  641. }
  642. #if !defined(ROMANIME)
  643. /**********************************************************************/
  644. /* SetCompLocalData() */
  645. /**********************************************************************/
  646. void PASCAL SetCompLocalData(
  647. LPIMEL lpImeL)
  648. {
  649. if (lpImeL->fdwModeConfig & MODE_CONFIG_OFF_CARET_UI) {
  650. #if defined(WINAR30)
  651. InitImeUIData(lpImeL);
  652. #endif
  653. return;
  654. }
  655. // text position relative to the composition window
  656. lpImeL->rcCompText.right = lpImeL->rcCompText.left +
  657. sImeG.xChiCharWi * lpImeL->nRevMaxKey;
  658. // set the width & height for composition window
  659. lpImeL->xCompWi = lpImeL->rcCompText.right + lpImeL->cxCompBorder * 3;
  660. return;
  661. }
  662. #endif
  663. /**********************************************************************/
  664. /* RegisterImeClass() */
  665. /**********************************************************************/
  666. void PASCAL RegisterImeClass(
  667. #if defined(UNIIME)
  668. LPINSTDATAL lpInstL,
  669. LPIMEL lpImeL,
  670. #endif
  671. WNDPROC lpfnUIWndProc,
  672. #if !defined(ROMANIME)
  673. WNDPROC lpfnCompWndProc,
  674. WNDPROC lpfnCandWndProc,
  675. #endif
  676. WNDPROC lpfnStatusWndProc,
  677. WNDPROC lpfnOffCaretWndProc,
  678. WNDPROC lpfnContextMenuWndProc)
  679. {
  680. WNDCLASSEX wcWndCls;
  681. // IME UI class
  682. wcWndCls.cbSize = sizeof(WNDCLASSEX);
  683. wcWndCls.cbClsExtra = 0;
  684. wcWndCls.cbWndExtra = WND_EXTRA_SIZE;
  685. wcWndCls.hIcon = LoadIcon(lpInstL->hInst,
  686. MAKEINTRESOURCE(IDIC_IME_ICON));
  687. wcWndCls.hInstance = lpInstL->hInst;
  688. wcWndCls.hCursor = LoadCursor(NULL, IDC_ARROW);
  689. wcWndCls.hbrBackground = GetStockObject(NULL_BRUSH);
  690. wcWndCls.lpszMenuName = (LPTSTR)NULL;
  691. wcWndCls.hIconSm = LoadImage(lpInstL->hInst,
  692. MAKEINTRESOURCE(IDIC_IME_ICON), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
  693. // IME UI class
  694. if (!GetClassInfoEx(lpInstL->hInst, lpImeL->szUIClassName, &wcWndCls)) {
  695. wcWndCls.style = CS_IME;
  696. wcWndCls.lpfnWndProc = lpfnUIWndProc;
  697. wcWndCls.lpszClassName = lpImeL->szUIClassName;
  698. RegisterClassEx(&wcWndCls);
  699. }
  700. wcWndCls.style = CS_IME|CS_HREDRAW|CS_VREDRAW;
  701. wcWndCls.hbrBackground = GetStockObject(LTGRAY_BRUSH);
  702. #if !defined(ROMANIME)
  703. // IME composition class
  704. if (!GetClassInfoEx(lpInstL->hInst, lpImeL->szCompClassName, &wcWndCls)) {
  705. wcWndCls.lpfnWndProc = lpfnCompWndProc;
  706. wcWndCls.lpszClassName = lpImeL->szCompClassName;
  707. RegisterClassEx(&wcWndCls);
  708. }
  709. // IME candidate class
  710. if (!GetClassInfoEx(lpInstL->hInst, lpImeL->szCandClassName, &wcWndCls)) {
  711. wcWndCls.lpfnWndProc = lpfnCandWndProc;
  712. wcWndCls.lpszClassName = lpImeL->szCandClassName;
  713. RegisterClassEx(&wcWndCls);
  714. }
  715. #endif
  716. // IME status class
  717. if (!GetClassInfoEx(lpInstL->hInst, lpImeL->szStatusClassName, &wcWndCls)) {
  718. wcWndCls.lpfnWndProc = lpfnStatusWndProc;
  719. wcWndCls.lpszClassName = lpImeL->szStatusClassName;
  720. RegisterClassEx(&wcWndCls);
  721. }
  722. // IME off caret class
  723. if (!GetClassInfoEx(lpInstL->hInst, lpImeL->szOffCaretClassName, &wcWndCls)) {
  724. wcWndCls.lpfnWndProc = lpfnOffCaretWndProc;
  725. wcWndCls.lpszClassName = lpImeL->szOffCaretClassName;
  726. RegisterClassEx(&wcWndCls);
  727. }
  728. // IME context menu class
  729. if (!GetClassInfoEx(lpInstL->hInst, lpImeL->szCMenuClassName, &wcWndCls)) {
  730. wcWndCls.style = 0;
  731. wcWndCls.hbrBackground = GetStockObject(NULL_BRUSH);
  732. wcWndCls.lpfnWndProc = lpfnContextMenuWndProc;
  733. wcWndCls.lpszClassName = lpImeL->szCMenuClassName;
  734. RegisterClassEx(&wcWndCls);
  735. }
  736. return;
  737. }
  738. /**********************************************************************/
  739. /* AttachIME() / UniAttachMiniIME() */
  740. /**********************************************************************/
  741. #if defined(UNIIME)
  742. void WINAPI UniAttachMiniIME(
  743. #else
  744. void PASCAL AttachIME(
  745. #endif
  746. #if defined(UNIIME)
  747. LPINSTDATAL lpInstL,
  748. LPIMEL lpImeL,
  749. #endif
  750. WNDPROC lpfnUIWndProc,
  751. #if !defined(ROMANIME)
  752. WNDPROC lpfnCompWndProc,
  753. WNDPROC lpfnCandWndProc,
  754. #endif
  755. WNDPROC lpfnStatusWndProc,
  756. WNDPROC lpfnOffCaretWndProc,
  757. WNDPROC lpfnContextMenuWndProc)
  758. {
  759. #if !defined(UNIIME)
  760. InitImeGlobalData();
  761. #endif
  762. InitImeLocalData(lpInstL, lpImeL);
  763. if (!lpImeL->rcStatusText.bottom) {
  764. InitImeUIData(lpImeL);
  765. }
  766. RegisterImeClass(
  767. #if defined(UNIIME)
  768. lpInstL, lpImeL,
  769. #endif
  770. lpfnUIWndProc,
  771. #if !defined(ROMANIME)
  772. lpfnCompWndProc, lpfnCandWndProc,
  773. #endif
  774. lpfnStatusWndProc, lpfnOffCaretWndProc,
  775. lpfnContextMenuWndProc);
  776. return;
  777. }
  778. /**********************************************************************/
  779. /* DetachIME() / UniDetachMiniIME() */
  780. /**********************************************************************/
  781. #if defined(UNIIME)
  782. void WINAPI UniDetachMiniIME(
  783. #else
  784. void PASCAL DetachIME(
  785. #endif
  786. LPINSTDATAL lpInstL,
  787. LPIMEL lpImeL)
  788. {
  789. WNDCLASSEX wcWndCls;
  790. if (GetClassInfoEx(lpInstL->hInst, lpImeL->szCMenuClassName, &wcWndCls)) {
  791. UnregisterClass(lpImeL->szCMenuClassName, lpInstL->hInst);
  792. }
  793. if (GetClassInfoEx(lpInstL->hInst, lpImeL->szOffCaretClassName, &wcWndCls)) {
  794. UnregisterClass(lpImeL->szOffCaretClassName, lpInstL->hInst);
  795. }
  796. if (GetClassInfoEx(lpInstL->hInst, lpImeL->szStatusClassName, &wcWndCls)) {
  797. UnregisterClass(lpImeL->szStatusClassName, lpInstL->hInst);
  798. }
  799. #if !defined(ROMANIME)
  800. if (GetClassInfoEx(lpInstL->hInst, lpImeL->szCandClassName, &wcWndCls)) {
  801. UnregisterClass(lpImeL->szCandClassName, lpInstL->hInst);
  802. }
  803. if (GetClassInfoEx(lpInstL->hInst, lpImeL->szCompClassName, &wcWndCls)) {
  804. UnregisterClass(lpImeL->szCompClassName, lpInstL->hInst);
  805. }
  806. #endif
  807. if (!GetClassInfoEx(lpInstL->hInst, lpImeL->szUIClassName, &wcWndCls)) {
  808. } else if (!UnregisterClass(lpImeL->szUIClassName, lpInstL->hInst)) {
  809. } else {
  810. DestroyIcon(wcWndCls.hIcon);
  811. DestroyIcon(wcWndCls.hIconSm);
  812. }
  813. #if !defined(ROMANIME)
  814. FreeTable(lpInstL);
  815. #endif
  816. }
  817. #endif // !defined(MINIIME)
  818. /**********************************************************************/
  819. /* ImeDllInit() / UniImeDllInit() */
  820. /* Return Value: */
  821. /* TRUE - successful */
  822. /* FALSE - failure */
  823. /**********************************************************************/
  824. #if defined(UNIIME)
  825. BOOL CALLBACK UniImeDllInit(
  826. #else
  827. BOOL CALLBACK ImeDllInit(
  828. #endif
  829. HINSTANCE hInstance, // instance handle of this library
  830. DWORD fdwReason, // reason called
  831. LPVOID lpvReserve) // reserve pointer
  832. {
  833. switch (fdwReason) {
  834. case DLL_PROCESS_ATTACH:
  835. hInst = hInstance;
  836. #if !defined(UNIIME)
  837. if (lpInstL) {
  838. // the local instance data already init
  839. return (TRUE);
  840. }
  841. lpInstL = &sInstL;
  842. lpInstL->hInst = hInstance;
  843. lpInstL->lpImeL = lpImeL = &sImeL;
  844. #endif
  845. #if defined(MINIIME)
  846. UniAttachMiniIME(lpInstL, lpImeL, UIWndProc, CompWndProc,
  847. CandWndProc, StatusWndProc, OffCaretWndProc,
  848. ContextMenuWndProc);
  849. #elif defined(UNIIME)
  850. InitImeGlobalData();
  851. {
  852. LoadPhraseTable(sImeG.uPathLen, sImeG.szPhrasePath);
  853. }
  854. #else
  855. AttachIME(UIWndProc,
  856. #if !defined(ROMANIME)
  857. CompWndProc, CandWndProc,
  858. #endif
  859. StatusWndProc, OffCaretWndProc, ContextMenuWndProc);
  860. #endif
  861. break;
  862. case DLL_PROCESS_DETACH:
  863. #if defined(MINIIME)
  864. UniDetachMiniIME(lpInstL, lpImeL);
  865. #elif defined(UNIIME)
  866. {
  867. int i;
  868. for (i = 0; i < MAX_PHRASE_TABLES; i++) {
  869. if (sInstG.hMapTbl[i]) {
  870. CloseHandle(sInstG.hMapTbl[i]);
  871. sInstG.hMapTbl[i] = (HANDLE)NULL;
  872. }
  873. }
  874. }
  875. #else
  876. DetachIME(lpInstL, lpImeL);
  877. #endif
  878. break;
  879. default:
  880. break;
  881. }
  882. return (TRUE);
  883. }