Notify.pas
上传用户:wen198501
上传日期:2013-04-01
资源大小:335k
文件大小:22k
源码类别:

输入法编程

开发平台:

Delphi

  1.  {******************************************************}
  2.  {                                                      }
  3.  {    Copyright (c) 1990-1999 Microsoft Corporation     }
  4.  {                                                      }
  5.  {    Module Name:  Notify.c ->>  Notify.pas            }
  6.  {                                                      }
  7.  {    Translator:  Liu_mazi@126.com, 2005-11-16         }
  8.  {                                                      }
  9.  {******************************************************}
  10. unit Notify;
  11. {$I Define.Inc}
  12. interface
  13. uses Windows, ImmDev, ImeDefs;
  14. procedure CompCancel(_hIMC: hIMC; lpIMC: PInputContext);
  15. procedure GenerateMessage(_hIMC: hIMC; lpIMC: PInputContext; lpImcP: PPrivContext);
  16. function NotifyIME(_hIMC: hIMC; dwAction: DWord; dwIndex: DWord; dwValue: DWord): Bool; stdcall;
  17. function ImeSetCompositionString(_hIMC: hIMC; dwIndex: DWord; lpComp: Pointer; dwCompLen: DWord; lpRead: Pointer; dwReadLen: DWord): Bool; stdcall;
  18. implementation
  19. uses DDIS, ToAscii, Chcand, Compose, LogText;
  20.   // 消息发送, **
  21. procedure GenerateMessage(_hIMC: hIMC; lpIMC: PInputContext; lpImcP: PPrivContext);
  22. begin
  23.   if (_hIMC = 0) or (lpIMC = nil) or (lpImcP = nil) then Exit;
  24.   if (lpImcP.fdwImeMsg and MSG_IN_IMETOASCIIEX) <> 0 then Exit;
  25.   Inc(lpIMC.dwNumMsgBuf, TranslateImeMessage(nil, lpIMC, lpImcP));
  26.   lpImcP.fdwImeMsg := lpImcP.fdwImeMsg and (MSG_ALREADY_OPEN or MSG_ALREADY_START);
  27.   lpImcP.fdwGcsFlag := 0;
  28.   ImmGenerateMessage(_hIMC);
  29. end;
  30.   // 消息发送
  31. procedure GenerateImeMessage(_hIMC: hIMC; lpIMC: PInputContext; fdwImeMsg: DWord);
  32. var
  33.   lpImcP: PPrivContext;
  34. begin
  35.   lpImcP := ImmLockIMCC(lpIMC.hPrivate);
  36.   if (lpImcP = nil) then Exit;
  37.   lpImcP.fdwImeMsg := lpImcP.fdwImeMsg or fdwImeMsg;
  38.   if (fdwImeMsg and MSG_CLOSE_CANDIDATE) <> 0 then
  39.   begin
  40.     lpImcP.fdwImeMsg := lpImcP.fdwImeMsg and not (MSG_OPEN_CANDIDATE or MSG_CHANGE_CANDIDATE);
  41.   end else
  42.     if fdwImeMsg and (MSG_OPEN_CANDIDATE or MSG_CHANGE_CANDIDATE) <> 0 then
  43.     begin
  44.       lpImcP.fdwImeMsg := lpImcP.fdwImeMsg and (not MSG_CLOSE_CANDIDATE);
  45.     end;
  46.   if (fdwImeMsg and MSG_END_COMPOSITION) <> 0 then
  47.   begin
  48.     lpImcP.fdwImeMsg := lpImcP.fdwImeMsg and (not MSG_START_COMPOSITION);
  49.   end else
  50.     if (fdwImeMsg and MSG_START_COMPOSITION) <> 0 then
  51.     begin
  52.       lpImcP.fdwImeMsg := lpImcP.fdwImeMsg and (not MSG_END_COMPOSITION);
  53.     end;
  54.   GenerateMessage(_hIMC, lpIMC, lpImcP);
  55.   ImmUnlockIMCC(lpIMC.hPrivate);
  56. end;
  57.   // 取消Composition
  58. procedure CompCancel(_hIMC: hIMC; lpIMC: PInputContext);
  59. var
  60.   lpImcP: PPrivContext;
  61.   lpCompStr: PCompositionString;
  62.   lpGuideLine: PGuideLine;
  63. begin
  64.   if (lpIMC.hPrivate = 0) then Exit;
  65.   lpImcP := ImmLockIMCC(lpIMC.hPrivate);
  66.   if (lpImcP = nil) then Exit;
  67.   lpImcP.fdwGcsFlag := 0;
  68.   if (lpImcP.fdwImeMsg and MSG_ALREADY_OPEN) <> 0 then
  69.   begin
  70.     CandEscapeKey(lpIMC, lpImcP);
  71.   end else
  72.     if (lpImcP.fdwImeMsg and MSG_ALREADY_START) <> 0 then
  73.     begin
  74.       lpCompStr := ImmLockIMCC(lpIMC.hCompStr);
  75.       if (lpCompStr = nil) then
  76.       begin
  77.         ImmUnlockIMCC(lpIMC.hCompStr);
  78.         ImmUnlockIMCC(lpIMC.hPrivate);
  79.         Exit;
  80.       end;
  81.       lpGuideLine := ImmLockIMCC(lpIMC.hGuideLine);
  82.       if (lpGuideLine = nil) then
  83.       begin
  84.         ImmUnlockIMCC(lpIMC.hCompStr); // **
  85.         ImmUnlockIMCC(lpIMC.hGuideLine);
  86.         ImmUnlockIMCC(lpIMC.hPrivate);
  87.         Exit;
  88.       end;
  89.       CompEscapeKey(lpIMC, lpCompStr, lpGuideLine, lpImcP);
  90.       if (lpGuideLine <> nil) then ImmUnlockIMCC(lpIMC.hGuideLine);
  91.       if (lpCompStr <> nil) then ImmUnlockIMCC(lpIMC.hCompStr);
  92.     end else
  93.     begin
  94.       ImmUnlockIMCC(lpIMC.hPrivate);
  95.       Exit;
  96.     end;
  97.   GenerateMessage(_hIMC, lpIMC, lpImcP);
  98.   ImmUnlockIMCC(lpIMC.hPrivate);
  99. end;
  100.   // 设置字符串, **
  101. function SetString(_hIMC: hIMC; lpIMC: PInputContext; lpCompStr: PCompositionString;
  102.   lpImcP: PPrivContext; lpszRead: PChar; dwReadLen: DWord): Bool;
  103. label
  104.   Finalize;
  105. var
  106.   lpCandList: PCandidateList;
  107.   lpCandInfo: PCandidateInfo;
  108.   lpGuideLine: PGuideLine;
  109.   iRet, ii, Max_Comp, i: uInt;
  110.   wCode: Word;
  111. begin
  112.   Result := False;
  113.   lStrCpy(lpImcP.bSeq, lpszRead);
  114.   if (lpImcP.bSeq[3] = '?') then Max_Comp := 94 else Max_Comp := 1;
  115.   if (dwReadLen > 4) then Exit; // return (FALSE);
  116.   lpCandInfo := ImmLockIMCC(lpIMC.hCandInfo);
  117.   if (lpCandInfo = nil) then
  118.   begin
  119.     Result := Bool(-1);
  120.     Exit;
  121.   end;
  122.   // get lpCandList and init dwCount & dwSelection
  123.   lpCandList := PCandidateList(DWord(lpCandInfo) + lpCandInfo.dwOffset[0]);
  124.   InitCompStr(lpCompStr);
  125.   ClearCand(lpIMC);
  126.   lpGuideLine := ImmLockIMCC(lpIMC.hGuideLine);
  127.   if (lpGuideLine <> nil) then ImmUnlockIMCC(lpIMC.hGuideLine); // ??
  128.   CopyMemory(Pointer(DWord(lpCompStr) + lpCompStr.dwCompReadStrOffset), lpszRead, dwReadLen + SizeOf(Char));
  129.   CopyMemory(Pointer(DWord(lpCompStr) + lpCompStr.dwCompStrOffset), lpszRead, dwReadLen + SizeOf(Char));
  130.   lpCompStr.dwCompReadAttrLen := dwReadLen;
  131.   lpCompStr.dwCompAttrLen := lpCompStr.dwCompReadAttrLen;
  132.   for I := 0 to dwReadLen - 1 do // The IME has converted these chars
  133.     PByte(DWord(lpCompStr) + lpCompStr.dwCompReadAttrOffset + I)^ := ATTR_TARGET_CONVERTED;
  134.   lpCompStr.dwCompReadStrLen := dwReadLen;
  135.   lpCompStr.dwCompStrLen := lpCompStr.dwCompReadStrLen;
  136.   // dlta start from 0;
  137.   lpCompStr.dwDeltaStart := 0;
  138.   // cursor is next to composition string
  139.   lpCompStr.dwCursorPos := lpCompStr.dwCompStrLen;
  140.   lpCompStr.dwResultReadClauseLen := 0;
  141.   lpCompStr.dwResultReadStrLen := 0;
  142.   lpCompStr.dwResultClauseLen := 0;
  143.   lpCompStr.dwResultStrLen := 0;
  144.   // set private input context
  145.   lpImcP.iImeState := CST_INPUT;
  146.   if (lpImcP.fdwImeMsg and MSG_ALREADY_OPEN) <> 0 then
  147.     lpImcP.fdwImeMsg := (lpImcP.fdwImeMsg or MSG_CLOSE_CANDIDATE) and (not MSG_OPEN_CANDIDATE);
  148.   if (lpImcP.fdwImeMsg and MSG_ALREADY_START) = 0 then
  149.     lpImcP.fdwImeMsg := (lpImcP.fdwImeMsg or MSG_START_COMPOSITION) and (not MSG_END_COMPOSITION);
  150.   lpImcP.fdwImeMsg := lpImcP.fdwImeMsg or MSG_COMPOSITION;
  151.   lpImcP.fdwGcsFlag := GCS_COMPREAD or GCS_COMP or GCS_DELTASTART or GCS_CURSORPOS;
  152.   lpImcP.fdwImeMsg := lpImcP.fdwImeMsg or MSG_GUIDELINE;
  153.   lpCandList.dwCount := 0;
  154.   if (dwReadLen < 4) then goto Finalize;
  155.   lpImcP.bSeq[0] := #0;
  156.   lpImcP.bSeq[1] := #0;
  157.   lpImcP.bSeq[2] := #0;
  158.   lpImcP.bSeq[3] := #0;
  159.   for ii := 0 to 3 do
  160.   begin
  161.     iRet := GBProcessKey(PByte(DWord(@lpszRead) + ii)^, lpImcP);
  162.     if (iRet = CST_INPUT) then lpImcP.bSeq[ii] := PChar(DWord(@lpszRead) + ii)^ else goto Finalize;
  163.   end;
  164.   wCode := GBEngine(lpImcP);
  165.   wCode := HiByte(wCode) or (LoByte(wCode) shl 8);
  166.   for i := 0 to Max_Comp - 1 do
  167.   begin
  168.     AddCodeIntoCand(lpCandList, wCode);
  169.     Inc(wCode);
  170.   end;
  171.   if (lpCandList.dwCount = 1) then
  172.   begin
  173.     lStrCpy(PChar(DWord(lpCompStr) + lpCompStr.dwResultStrOffset), PChar(DWord(lpCandList) + lpCandList.dwOffset[0]));
  174.     // calculate result string length
  175.     lpCompStr.dwResultStrLen := lStrLen(PChar(DWord(lpCandList) + lpCandList.dwOffset[0]));
  176.     lpImcP.fdwImeMsg := lpImcP.fdwImeMsg or MSG_COMPOSITION;
  177.     lpImcP.dwCompChar := 0;
  178.     lpImcP.fdwGcsFlag := lpImcP.fdwGcsFlag or GCS_CURSORPOS or GCS_RESULTREAD or GCS_RESULT;
  179.     if ((lpImcP.fdwImeMsg and MSG_ALREADY_OPEN) <> 0) then
  180.       lpImcP.fdwImeMsg := (lpImcP.fdwImeMsg or MSG_CLOSE_CANDIDATE) and (not MSG_OPEN_CANDIDATE)
  181.     else
  182.       lpImcP.fdwImeMsg := lpImcP.fdwImeMsg and (not (MSG_CLOSE_CANDIDATE or MSG_OPEN_CANDIDATE));
  183.     lpImcP.iImeState := CST_INIT;
  184.     PDWord(@lpImcP.bSeq)^ := 0;
  185.     lpCandList.dwCount := 0;
  186.   end else
  187.     if (lpCandList.dwCount > 1) then
  188.       lpImcP.fdwImeMsg := (lpImcP.fdwImeMsg or MSG_OPEN_CANDIDATE) and (not MSG_CLOSE_CANDIDATE)
  189.     else
  190.       if(lpCandList.dwCount = 0) then
  191.         lpImcP.fdwImeMsg := (lpImcP.fdwImeMsg or MSG_CLOSE_CANDIDATE) and (not MSG_OPEN_CANDIDATE);
  192. Finalize:
  193.   GenerateMessage(_hIMC, lpIMC, lpImcP);
  194.   Result := True;
  195. end;
  196.   // Ime回调, **
  197. function ImeSetCompositionString(_hIMC: hIMC; dwIndex: DWord; lpComp: Pointer;
  198.   dwCompLen: DWord; lpRead: Pointer; dwReadLen: DWord): Bool; stdcall;
  199. var
  200.   lpIMC: PInputContext;
  201.   lpCompStr: PCompositionString;
  202.   lpImcP: PPrivContext;
  203. //  fRet: Bool;
  204. begin
  205.   Result := False;
  206.   if (_hIMC = 0) then Exit; // return (FALSE);
  207.   // composition string must  == reading string reading is more important
  208.   if (dwReadLen = 0) then dwReadLen := dwCompLen;
  209.   // composition string must  == reading string, reading is more important
  210.   if (lpRead = nil) then lpRead := lpComp;
  211.   if (dwReadLen = 0) then
  212.   begin
  213.     lpIMC := ImmLockIMC(_hIMC);
  214.     if (lpIMC = nil) then Exit; // return (FALSE);
  215.     CompCancel(_hIMC, lpIMC);
  216.     ImmUnlockIMC(_hIMC);
  217.     Result := True;
  218.     Exit; // return (TRUE);
  219.   end else
  220.     if (lpRead = nil) then
  221.     begin
  222.       Exit; // return (FALSE);
  223.     end else
  224.       if (dwCompLen = 0) then
  225.       begin
  226.       end else
  227.         if (lpComp = nil) then
  228.         begin
  229.         end else
  230.           if (dwReadLen <> dwCompLen) then
  231.           begin
  232.             Exit; // return (FALSE);
  233.           end else
  234.             if (lpRead = lpComp) then
  235.             begin
  236.             end else
  237.               if (lStrCmp(lpRead, lpComp) = 0) then
  238.               begin
  239.                 // composition string must  == reading string
  240.               end else
  241.               begin
  242.                 // composition string != reading string
  243.                 Exit; // return (FALSE);
  244.               end;
  245.   if (dwIndex <> SCS_SETSTR) then Exit; // return (FALSE);
  246.   lpIMC := ImmLockIMC(_hIMC);
  247.   if (lpIMC = nil) then Exit; //  return (FALSE);
  248.   if (lpIMC.hCompStr = 0) then
  249.   begin
  250.     ImmUnlockIMC(_hIMC);
  251.     Exit; // return (FALSE);
  252.   end;
  253.   lpCompStr := ImmLockIMCC(lpIMC.hCompStr);
  254.   if (lpCompStr = nil) then
  255.   begin
  256.     ImmUnlockIMC(_hIMC);
  257.     Exit; // return (FALSE);
  258.   end;
  259.   lpImcP := ImmLockIMCC(lpIMC.hPrivate);
  260.   if (lpCompStr = nil) then
  261.   begin
  262.     ImmUnlockIMCC(lpIMC.hCompStr);
  263.     ImmUnlockIMC(_hIMC);
  264.     Exit; // return (FALSE);
  265.   end;
  266.   Result := SetString(_hIMC, lpIMC, lpCompStr, lpImcP, lpRead, dwReadLen);
  267.   ImmUnlockIMCC(lpIMC.hPrivate);
  268.   ImmUnlockIMCC(lpIMC.hCompStr);
  269.   ImmUnlockIMC(_hIMC);
  270. end;
  271.   // app tell IME that one candidate string is selected (by mouse or non keyboard actionfor example sound)
  272. procedure NotifySelectCand(_hIMC: hIMC; lpIMC: PInputContext; lpCandInfo: PCandiDateInfo; dwIndex, dwValue: DWord);
  273. var
  274.   lpCandList: PCandiDateList;
  275.   lpCompStr: PCompositionString;
  276.   lpImcP: PPrivContext;
  277. begin
  278.   if (lpCandInfo = nil) then Exit;
  279.   if (dwIndex >= lpCandInfo.dwCount) then
  280.   begin
  281.     Exit;  // wanted candidate list is not created yet!
  282.   end else
  283.     if (dwIndex = 0) then
  284.     begin
  285.       if (lpIMC.fdwConversion and IME_CMODE_CHARCODE) <> 0 then
  286.       begin
  287.         Exit;  // not implemented yet
  288.       end;
  289.     end;
  290.   lpCandList := PCandiDateList(DWord(lpCandInfo) + lpCandInfo.dwOffset[0]);
  291.   // the selected value even more than the number of total candidate strings, it is imposible. should be error of app
  292.   if (dwValue >= lpCandList.dwCount) then Exit;
  293.   // app select this candidate string
  294.   lpCandList.dwSelection := dwValue;
  295.   lpCompStr := ImmLockIMCC(lpIMC.hCompStr);
  296.   if (lpCompStr = nil) then Exit;
  297.   lpImcP := ImmLockIMCC(lpIMC.hPrivate);
  298.   if (lpCompStr = nil) then
  299.   begin
  300.     ImmUnlockIMCC(lpIMC.hCompStr);
  301.     Exit;
  302.   end;
  303.   // translate into message buffer
  304.   SelectOneCand(lpIMC, lpCompStr, lpImcP, lpCandList);
  305.   // let app generate those messages in its message loop
  306.   GenerateMessage(_hIMC, lpIMC, lpImcP);
  307.   ImmUnlockIMCC(lpIMC.hPrivate);
  308.   ImmUnlockIMCC(lpIMC.hCompStr);
  309. end;
  310.   // Ime回调, **
  311. function NotifyIME(_hIMC: hIMC; dwAction: DWord; dwIndex: DWord; dwValue: DWord): Bool; stdcall;
  312. label
  313.   NotifyIMEUnlock;
  314. var
  315.   lpIMC: PInputContext;
  316.   fdwImeMsg: DWord;
  317.   lpCandInfo: PCandidateInfo;
  318.   lpCandList: PCandidateList;
  319.   lpImcP: PPrivContext;
  320.   lpCompStr: PCompositionString;
  321.   lpGuideLine: PGuideLine;
  322. begin
  323.   Result := False;
  324.   if (_hIMC = 0) then Exit;
  325.   case (dwAction) of
  326.     NI_OPENCANDIDATE,
  327.     NI_CLOSECANDIDATE:
  328.       Exit;               // not supported
  329.     NI_SELECTCANDIDATESTR,
  330.     NI_SETCANDIDATE_PAGESTART,
  331.     NI_SETCANDIDATE_PAGESIZE:
  332.       ;                   // need to handle it
  333.     NI_CHANGECANDIDATELIST:
  334.       ;
  335.     NI_CONTEXTUPDATED:
  336.       case (dwValue) of
  337.         IMC_SETCONVERSIONMODE,
  338.         IMC_SETOPENSTATUS:
  339.           ;                 // need to handle it
  340.         IMC_SETCANDIDATEPOS,
  341.         IMC_SETCOMPOSITIONFONT,
  342.         IMC_SETCOMPOSITIONWINDOW:
  343.         begin
  344.           Result := True;
  345.           Exit;             // not important to the IME
  346.         end;
  347.         else Exit;          // not supported
  348.       end;
  349.     NI_COMPOSITIONSTR:
  350.       case (dwIndex) of
  351.         CPS_COMPLETE:
  352.           ;                 // need to handle it
  353.         CPS_CONVERT,        // all composition string can not be convert
  354.         CPS_REVERT:         // any more, it maybe work for some intelligent phonetic IMEs
  355.           Exit;
  356.         CPS_CANCEL:
  357.           ;                 // need to handle it
  358.         else Exit;          // not supported
  359.       end;                // need to handle it
  360.     else Exit;            // not supported
  361.   end; // case (dwAction) of ..
  362.   lpIMC := ImmLockIMC(_hIMC);
  363.   if (lpIMC = nil) then Exit;
  364.   Result := True; // **
  365.   case (dwAction) of
  366.     NI_CONTEXTUPDATED:
  367.     begin
  368.       case (dwValue) of
  369.         IMC_SETCONVERSIONMODE:
  370.         begin
  371.           if ((lpIMC.fdwConversion or dwIndex) and IME_CMODE_CHARCODE) <> 0 then
  372.           begin
  373.             // reject CHARCODE
  374.             lpIMC.fdwConversion := lpIMC.fdwConversion and (not IME_CMODE_CHARCODE);
  375.             MessageBeep($FFFFFFFF);
  376.             goto NotifyIMEUnlock; // Break
  377.           end;
  378.           fdwImeMsg := 0;
  379.           if ((lpIMC.fdwConversion or dwIndex) and IME_CMODE_NOCONVERSION) <> 0 then
  380.           begin
  381.             lpIMC.fdwConversion := lpIMC.fdwConversion or IME_CMODE_NATIVE;
  382.             lpIMC.fdwConversion := lpIMC.fdwConversion and not(IME_CMODE_CHARCODE or IME_CMODE_EUDC or IME_CMODE_SYMBOL);
  383.           end;
  384.           if ((lpIMC.fdwConversion or dwIndex) and IME_CMODE_EUDC) <> 0 then
  385.           begin
  386.             lpIMC.fdwConversion := lpIMC.fdwConversion or IME_CMODE_NATIVE;
  387.             lpIMC.fdwConversion := lpIMC.fdwConversion and not(IME_CMODE_CHARCODE or IME_CMODE_NOCONVERSION or IME_CMODE_SYMBOL);
  388.           end;
  389.           if ((lpIMC.fdwConversion or dwIndex) and IME_CMODE_SOFTKBD) <> 0 then
  390.           begin
  391.             fdwImeMsg := MSG_IMN_UPDATE_SOFTKBD;
  392.           end;
  393.           if (lpIMC.fdwConversion or dwIndex) = IME_CMODE_NATIVE then
  394.           begin
  395.             lpIMC.fdwConversion := lpIMC.fdwConversion and not(IME_CMODE_CHARCODE or IME_CMODE_NOCONVERSION  or IME_CMODE_EUDC);
  396.             fdwImeMsg := fdwImeMsg or MSG_IMN_UPDATE_SOFTKBD;
  397.           end;
  398.           if (fdwImeMsg <> 0) then GenerateImeMessage(_hIMC, lpIMC, fdwImeMsg);
  399.           if ((lpIMC.fdwConversion or dwIndex) and not(IME_CMODE_FULLSHAPE or IME_CMODE_SOFTKBD)) <> 0 then
  400.           begin
  401.           end else
  402.           begin
  403.             goto NotifyIMEUnlock;
  404.           end;
  405.           CompCancel(_hIMC, lpIMC);
  406.         end;
  407.         IMC_SETOPENSTATUS:
  408.         begin
  409.           if (lpIMC.fdwConversion and IME_CMODE_SOFTKBD) <> 0 then
  410.           begin
  411.             GenerateImeMessage(_hIMC, lpIMC, MSG_IMN_UPDATE_SOFTKBD);
  412.           end;
  413.           CompCancel(_hIMC, lpIMC);
  414.         end;
  415.       end;
  416.     end;
  417.     NI_SELECTCANDIDATESTR:
  418.     begin
  419.       if (lpIMC.fOpen = False) then
  420.       begin
  421.         Result := False;
  422.       end else
  423.         if (lpIMC.fdwConversion and IME_CMODE_NOCONVERSION) <> 0 then
  424.         begin
  425.           Result := False;
  426.         end else
  427.           if (lpIMC.fdwConversion and IME_CMODE_EUDC) <> 0 then
  428.           begin
  429.             Result := False;
  430.           end else
  431.             if (lpIMC.hCandInfo = 0) then
  432.             begin
  433.               Result := False;
  434.             end else
  435.             begin
  436.               lpCandInfo := ImmLockIMCC(lpIMC.hCandInfo);
  437.               if(lpCandInfo = nil) then
  438.               begin
  439.                 Result := False;
  440.               end else
  441.               begin
  442.                 NotifySelectCand(_hIMC, lpIMC, lpCandInfo, dwIndex, dwValue);
  443.                 ImmUnlockIMCC(lpIMC.hCandInfo);
  444.               end;
  445.             end;
  446.     end;
  447.     NI_CHANGECANDIDATELIST:
  448.     begin
  449.       fdwImeMsg := 0;
  450.       fdwImeMsg := fdwImeMsg or MSG_CHANGE_CANDIDATE;
  451.       GenerateImeMessage(_hIMC, lpIMC, fdwImeMsg);
  452.     end;
  453.     NI_SETCANDIDATE_PAGESTART,
  454.     NI_SETCANDIDATE_PAGESIZE:
  455.     begin
  456.       if (dwIndex <> 0) then
  457.       begin
  458.         Result := False;
  459.       end else
  460.         if (lpIMC.fOpen = False) then
  461.         begin
  462.           Result := False;
  463.         end else
  464.           if (lpIMC.fdwConversion and IME_CMODE_NOCONVERSION) <> 0 then
  465.           begin
  466.             Result := False;
  467.           end else
  468.             if (lpIMC.fdwConversion and (IME_CMODE_EUDC or IME_CMODE_SYMBOL)) <> 0 then
  469.             begin
  470.               Result := False;
  471.             end else
  472.               if (lpIMC.hCandInfo = 0) then
  473.               begin
  474.                 Result := False;
  475.               end else
  476.               begin
  477.                 lpCandInfo := ImmLockIMCC(lpIMC.hCandInfo);
  478.                 if (lpCandInfo = nil) then
  479.                 begin
  480.                   Result := False;
  481.                 end else
  482.                 begin
  483.                   lpCandList := PCandidateList(DWord(lpCandInfo) + lpCandInfo.dwOffset[0]);
  484.                   if (dwAction = NI_SETCANDIDATE_PAGESTART) then
  485.                   begin
  486.                     if (dwValue < lpCandList.dwCount) then
  487.                     begin
  488.                       lpCandList.dwPageStart := dwValue;
  489.                       lpCandList.dwSelection := dwValue;
  490.                     end;
  491.                   end else
  492.                     if (lpCandList.dwCount <> 0) then lpCandList.dwPageSize := dwValue;
  493.                   ImmUnlockIMCC(lpIMC.hCandInfo);
  494.                 end;
  495.               end;
  496.     end;
  497.     NI_COMPOSITIONSTR:
  498.     begin
  499.       case (dwIndex) of
  500.         CPS_CANCEL:
  501.           CompCancel(_hIMC, lpIMC);
  502.         CPS_COMPLETE:
  503.         begin
  504.           lpImcP := ImmLockIMCC(lpIMC.hPrivate);
  505.           if (lpImcP = nil) then goto NotifyIMEUnlock;
  506.           if (lpImcP.iImeState = CST_INIT) then
  507.           begin
  508.             CompCancel(_hIMC, lpIMC); // can not do any thing
  509.           end else
  510.             if (lpImcP.iImeState = CST_CHOOSE) then
  511.             begin
  512.               lpCompStr := ImmLockIMCC(lpIMC.hCompStr);
  513.               if (lpCompStr = nil) then goto NotifyIMEUnlock;
  514.               lpCandInfo := ImmLockIMCC(lpIMC.hCandInfo);
  515.               if (lpCandInfo <> nil) then
  516.               begin
  517.                 lpCandList := PCandidateList(DWord(lpCandInfo) + lpCandInfo.dwOffset[0]);
  518.                 SelectOneCand(lpIMC, lpCompStr, lpImcP, lpCandList);
  519.                 ImmUnlockIMCC(lpIMC.hCandInfo);
  520.                 GenerateMessage(_hIMC, lpIMC, lpImcP);
  521.               end;
  522.               if (lpCompStr <> nil) then ImmUnlockIMCC(lpIMC.hCompStr);
  523.             end else
  524.               if (lpIMC.fdwConversion and (IME_CMODE_NATIVE or IME_CMODE_EUDC or IME_CMODE_SYMBOL) <> IME_CMODE_NATIVE) then
  525.               begin
  526.                 CompCancel(_hIMC, lpIMC);
  527.               end else
  528.                 if (lpImcP.iImeState = CST_INPUT) then
  529.                 begin
  530.                   lpCompStr := ImmLockIMCC(lpIMC.hCompStr);
  531.                   if (lpCompStr = nil) then goto NotifyIMEUnlock;
  532.                   lpGuideLine := ImmLockIMCC(lpIMC.hGuideLine);
  533.                   if (lpGuideLine = nil) then
  534.                   begin
  535.                     ImmUnlockIMCC(lpIMC.hCompStr);
  536.                     goto NotifyIMEUnlock;
  537.                   end;
  538.                   CompWord(Ord(' '), lpIMC, lpCompStr, lpImcP, lpGuideLine);
  539.                   if (lpImcP.iImeState = CST_INPUT) then
  540.                   begin
  541.                     CompCancel(_hIMC, lpIMC);
  542.                   end else
  543.                     if (lpImcP.iImeState <> CST_CHOOSE) then
  544.                     begin
  545.                     end else
  546.                     begin
  547.                       lpCandInfo := ImmLockIMCC(lpIMC.hCandInfo);
  548.                       if (lpCandInfo <> nil) then
  549.                       begin
  550.                         lpCandList := PCandidateList(DWord(lpCandInfo) + lpCandInfo.dwOffset[0]);
  551.                         SelectOneCand(lpIMC, lpCompStr, lpImcP, lpCandList);
  552.                         ImmUnlockIMCC(lpIMC.hCandInfo);
  553.                       end else
  554.                       begin
  555.                       end;
  556.                     end;
  557.                   if (lpCompStr <> nil) then ImmUnlockIMCC(lpIMC.hCompStr);
  558.                   if (lpGuideLine <> nil) then ImmUnlockIMCC(lpIMC.hGuideLine);
  559.                   // don't phrase predition under this case
  560.                   if (lpImcP.fdwImeMsg and MSG_ALREADY_OPEN) <> 0 then
  561.                     lpImcP.fdwImeMsg := (lpImcP.fdwImeMsg or MSG_CLOSE_CANDIDATE) and not(MSG_OPEN_CANDIDATE or MSG_CHANGE_CANDIDATE)
  562.                   else
  563.                     lpImcP.fdwImeMsg := lpImcP.fdwImeMsg and not(MSG_CLOSE_CANDIDATE or MSG_OPEN_CANDIDATE);
  564.                   GenerateMessage(_hIMC, lpIMC, lpImcP);
  565.                 end else
  566.                 begin
  567.                   CompCancel(_hIMC, lpIMC);
  568.                 end;
  569.           ImmUnlockIMCC(lpIMC.hPrivate);
  570.         end;
  571.       end;
  572.     end;
  573.   end;
  574. NotifyIMEUnlock:
  575.   ImmUnlockIMC(_hIMC);
  576. end;
  577. end.