Source code of Windows XP (NT5)
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.

280 lines
9.7 KiB

  1. 1. What is the difference between reading string (CompReadStr) and
  2. composition string (CompStr)?
  3. The reading string only consist with basic symbols for this IME.
  4. For exmaple, the reading string of phonetic IME is bo po mo fo.
  5. The composition string is the string that IME want to show in
  6. the composition window. For example, the composition string of
  7. phonetic IME can be the following for some advance phonetic
  8. IME -
  9. 11111
  10. 012345678901234
  11. �ڭ̳��O�j����
  12. 2. For this advance phonetic IME, what is the clause information?
  13. �ڭ� (offset 0 to 4 in this string), ���O (offset 4 to 8), and
  14. �j���� (offset 8 to 14) are three clauses to this IME. (It may
  15. be different ways deciding a clause to other IME) And the clause
  16. informtion to this IME is DWORD array 0, 4, 8, and 14.
  17. 3. What is the attribute for these three clause?
  18. The attribute for one clause should be the same. For this IME,
  19. �ڭ� (ATTR_CONVERTED - 2), ���O (ATTR_CONVERTED - 2), and �j����
  20. (ATTR_INPUT - 0) can be marked with different attribute as
  21. following.
  22. �ڭ̳��O�j����
  23. 22222222000000
  24. The attribute is BYE array 2,2,2,2,2,2,2,2,0,0,0,0,0,0.
  25. 4. When are the ATTR_TARGET_NOTCONVERTED and ATTR_TARGET_CONVERTED
  26. used?
  27. The _TARGET_ is for the clause which is in the cursor position.
  28. Most likely the Chinese should use ATTR_TARGET_CONVERTED but it is
  29. possible we use ATTR_TARGET_NOTCONVERTED for some prediction
  30. function.
  31. 5. If the IME do not provide the correct information. The
  32. application or DBCS pen window may fail to function.
  33. 6. On developing Win95 IME, we should alway keep in mind the
  34. IME conversion engine must carefully seperate with the
  35. IME UI. Because the advance applications may not use the UI
  36. provided by the IME, they will draw the IME UI by themself.
  37. So it is obvious to an IME designer, we should not put IME UI
  38. window handle into PRIVCONTEXT (data structure in imedefs.h
  39. of the IME sample code).
  40. 7. What is the basic message flow?
  41. 1).
  42. Before application call into GetMessage/PeekMessage, the
  43. system will call into ImeProcessKey asking whether the IME
  44. want to eat this key.
  45. 2).
  46. If the function return TRUE, the system will change the virtual
  47. key to VK_PROCESSKEY, the application will get WM_KEYDOWN with
  48. VK_PROCESSKEY.
  49. 3).
  50. On application calling the TranslateMessage, the system will
  51. pass the original virtual key and other parameters to the
  52. ImeToAsciiEx(,lpdwTransBuf,).
  53. 4).
  54. The IME is responsible to generate WM_IME_STARTCOMPOSITION,
  55. WM_IME_COMPOSITION, WM_IME_ENDCOMPOSITION, WM_IME_NOTIFY/
  56. IMN_OPENCANDIDATE/IMN_CHANGECANIDATE/IMN_CLOSECANDIADTE, ...
  57. into message buffer - lpdwTransBuf.
  58. 5).
  59. The application can get these messages (generated by IME) from
  60. the message loop. If the application do not handle it and
  61. pass it to default window procedure, the system will pass it
  62. to the default IME window. Now the IME window has chance to
  63. handle it.
  64. 8. What is the IME window.
  65. An IME window is a window created base on "IME" class. It is
  66. a system class in user.exe. This window will create an onwee
  67. window base on the UI class of an IME, system use the ImeInquire
  68. to get this UI class name from the IME. This UI class provide
  69. the real UI of the IME. The IME window will pass the UI related
  70. messages to the ownee UI window and the UI window will provide
  71. the UI feedback according to these messages for the end user.
  72. 9. How to switch to an IME or non IME in you application as the
  73. CTRL-SPACE funtion?
  74. // (1) switch to a non IME
  75. hKL = GetKeyboardLayout(0);
  76. if (ImmIsIME(hKL)) {
  77. ImmSimulateHotKey(hAppWnd, IME_THOTKEY_IME_NONIME_TOGGLE);
  78. }
  79. if (ImmIsIME(hKL)) {
  80. // switch fail handling
  81. // P.S. If end user delete all non IMEs and only leave the IMEs
  82. // in the system, above ImmSimulateHotKey will fail
  83. }
  84. // (2) switch to an IME
  85. hKL = GetKeyboardLayout(0);
  86. if (!ImmIsIME(hKL)) {
  87. ImmSimulateHotKey(hAppWnd, IME_THOTKEY_IME_NONIME_TOGGLE);
  88. }
  89. if (!ImmIsIME(hKL)) {
  90. // switch fail handling
  91. // P.S. If end user delete all IMEs in the system, above
  92. // ImmSimulateHotKey will fail
  93. }
  94. 10. How to stick to the previos input IME for one specific field in
  95. your application?
  96. // Whenever focus out call ...
  97. hPrevKL = GetKeyboardLayout(0);
  98. :
  99. :
  100. // Whenever focus in call ...
  101. ActivateKeyboradLayout(hPrevKL, 0);
  102. 11. How to change the direct switch hot key in IME configuration dialog
  103. or control panel?
  104. void ImeConfigureHotKeyPart(uNewModifiers, uNewVKey, hThisIMEKL)
  105. {
  106. DWORD dwHotKeyID;
  107. DWORD dwAvailableHotKeyID = 0;
  108. for (dwHotKeyID = IME_HOTKEY_DSWITCH_FIRST; dwHotKeyID <=
  109. IME_HOTKEY_DSWITCH_LAST; dwHotKeyID++) {
  110. BOOL fRet;
  111. UINT uModifiers;
  112. UINT uVKey;
  113. UINT uTargetKL;
  114. fRet = ImmGetHotKey(dwHotKeyID, &uModifiers, &uVKey,
  115. &hTargetKL);
  116. if (fRet) {
  117. if (hTargetKL == hThisIMEKL) {
  118. // if we want to set the hot key to a new value
  119. ImmSetHotKey(dwHotKeyID, uNewModifiers, uNewVKey,
  120. hThisIMEKL);
  121. return;
  122. }
  123. } else if (dwAvailableHotKeyID) {
  124. // we already find an available ID
  125. } else {
  126. dwAvailableHotKeyID = dwHotKeyID;
  127. }
  128. }
  129. if (!dwAvailableHotKeyID) {
  130. // no available ID case, Oh! Oh!
  131. return;
  132. }
  133. // this IME does not have a direct switch hot key before
  134. ImmSetHotKey(dwHotKeyID, uNewModifiers, uNewVKey, hThisIMEKL);
  135. return;
  136. }
  137. 12. An example of using property
  138. 1) Init code of RichEdit
  139. hRichEditWnd->fdwProperty = ImmGetProperty(GetKeyboardLayout(0),
  140. IGP_PROPERTY);
  141. if (hRichEditWnd->fdwProperty & IME_PROP_SPECIAL_UI) {
  142. // set composition position to init caret position
  143. cpCompForm.dwStyle = CFS_POINT; // or CFS_RECT
  144. cpCompForm.ptCurrentPos = ptAppCaretPosition;
  145. // for CFS_RECT dwStyle you need to set cpCompForm.rcArea
  146. ImmSetCompositionWindow(hIMC, cpCompForm);
  147. } else if (hRichEditWnd->fdwProperty & IME_PROP_AT_CARET) {
  148. // maybe application want to set the init position for
  149. // candiadate window here
  150. } else {
  151. // set composition position to init caret position
  152. cpCompForm.dwStyle = CFS_POINT; // or CFS_RECT
  153. cpCompForm.ptCurrentPos = ptAppCaretPosition;
  154. // for CFS_RECT dwStyle you need to set cpCompForm.rcArea
  155. ImmSetCompositionWindow(hIMC, cpCompForm);
  156. }
  157. 2) On message of keyboard layout change
  158. case WM_INPUTLANGCHQANGE:
  159. hRichEditWnd->fdwProperty = ImmGetProperty(GetKeyboardLayout(0),
  160. IGP_PROPERTY);
  161. hIMC = ImmGetContext(hRichEditWnd);
  162. if (!hIMC) {
  163. return DefWindowProc();
  164. }
  165. if (hRichEditWnd->fdwProperty & IME_PROP_SPECIAL_UI) {
  166. // set composition position to init caret position
  167. cpCompForm.dwStyle = CFS_POINT; // or CFS_RECT
  168. cpCompForm.ptCurrentPos = ptAppCaretPosition;
  169. // for CFS_RECT dwStyle you need to set cpCompForm.rcArea
  170. ImmSetCompositionWindow(hIMC, cpCompForm);
  171. } else if (hRichEditWnd->fdwProperty & IME_PROP_AT_CARET) {
  172. // if you want to set up the candidate window position for
  173. // an at caret IME, you may need to set here
  174. // In the spec, we can set the 4 different candidate window
  175. // positions for 4 level of candidate windows. Anyway the
  176. // application may only care about the 1st level of candidate
  177. // window
  178. for (i = 0; i < 4; i++) {
  179. CANDIDATEFORM cdCandForm;
  180. cdCandForm.dwIndex = 0;
  181. cdCandForm.dwStyle = CFS_CANDIDATEPOS;
  182. cdCandForm.ptCUrrentPos.x = ptAppWantPosition[i].x;
  183. cdCandForm.ptCUrrentPos.y = ptAppWantPosition[i].y;
  184. ImmSetCandidateWindow(hIMC, &cdCandForm);
  185. }
  186. } else {
  187. for (i = 0; i < 4; i++) {
  188. CANDIDATEFORM cdCandForm;
  189. if (!ImmGetCandiadetWindow(hIMC, i, &cdCandForm)) {
  190. contine;
  191. }
  192. if (cdCandForm.dwStyle == CFS_DEFAULT) {
  193. contine;
  194. }
  195. cdCandForm.dwStyle = CFS_DEFAULT;
  196. ImmSetCandidateWindow(hIMC, &cdCandForm);
  197. }
  198. cpCompForm.dwStyle = CFS_POINT; // or CFS_RECT
  199. cpCompForm.ptCurrentPos = ptAppCaretPosition;
  200. // for CFS_RECT dwStyle you also need to set cpCompForm.rcArea field
  201. ImmSetCompositionWindow(hIMC, cpCompForm);
  202. }
  203. return DefWindowProc();
  204. 3) case (all IME related messages handle by RichEdit)
  205. if (hRichEditWnd->fdwProperty & IME_PROP_SPECIAL_UI) {
  206. return DefWindowProc();
  207. } else if (hRichEditWnd->fdwProperty & IME_PROP_AT_CARET) {
  208. } else {
  209. return DefWindowProc();
  210. }
  211. // original IME enable code RichEdit already implement
  212. 4) On caret movement of RichEdit, RichEdit need to set the
  213. COMPOSITIONFORM to this new caret position by ImmSetCompositionWindow
  214. for a near caret IME.
  215. And for an at caret Chinese IME you need to set the CANDIDATEFORM to
  216. the composition cursor position by ImmSetCandidateWindow.
  217. 5) On end user change font, RichEdit need to set the LOGFONT by
  218. ImmSetCompositionFont.
  219. Thank you
  220. J. J. Lee (���a�v)