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

输入法编程

开发平台:

Delphi

  1.  {******************************************************}
  2.  {                                                      }
  3.  {    Copyright (c) 1990-1999 Microsoft Corporation     }
  4.  {                                                      }
  5.  {    Module Name:  Compose.c ->>  Compose.pas          }
  6.  {                                                      }
  7.  {    Translator:  Liu_mazi@126.com, 2005-11-19         }
  8.  {                                                      }
  9.  {******************************************************}
  10. unit Compose;
  11. {$I Define.Inc}
  12. interface
  13. uses Windows, ImmDev, ImeDefs;
  14. function GBEngine(lpImcP: PPrivContext): Word;  // Conv GBcode
  15. procedure AddCodeIntoCand(lpCandList: PCandiDateList; wCode: Word); // 添加Candidate
  16. procedure CompEscapeKey(lpIMC: PInputContext; lpCompStr: PCompositionString;
  17.   lpGuideLine: PGuideLine; lpImcP: PPrivContext); // Composition取消处理
  18.   
  19. procedure CompWord(wCharCode: Word; lpIMC: PInputContext;
  20.   lpCompStr: PCompositionString; lpImcP: PPrivContext; lpGuideLine: PGuideLine);
  21. implementation
  22. uses Data, DDIS;
  23.   // 单个字符转数值
  24. function CharToHex(cChar: Char): Word;
  25. begin
  26.   if (cChar >= '0') and (cChar <= '9') then
  27.     Result := Ord(cChar) - Ord('0')
  28.   else
  29.     if (cChar >= 'a') and (cChar <= 'f') then
  30.       Result := Ord(cChar) - Ord('a') + $0A
  31.     else
  32.       Result := 0;
  33. end;
  34.   // GB内码串转内码
  35. function AsciiToGB(lpImcP: PPrivContext): Word;
  36. begin
  37.   Result := (CharToHex(lpImcP.bSeq[2]) shl 4) or CharToHex(lpImcP.bSeq[3]);
  38.   Result := (Result shl 8);
  39.   Result := (CharToHex(lpImcP.bSeq[0]) shl 4) or CharToHex(lpImcP.bSeq[1]) or Result;
  40. end;
  41.   // 区位码串转内码
  42. function AsciiToArea(lpImcP: PPrivContext): Word;
  43. begin
  44.   Result := (CharToHex(lpImcP.bSeq[2]) * 10) + CharToHex(lpImcP.bSeq[3]) + $A0;
  45.   Result := (Result shl 8);
  46.   Result := (CharToHex(lpImcP.bSeq[0]) * 10) + CharToHex(lpImcP.bSeq[1]) + $A0 or Result;
  47. end;
  48.   // Conv GBcode
  49. function GBEngine(lpImcP: PPrivContext): Word;
  50. begin
  51.   if (lpImcP.bSeq[3] <> #0) or (lpImcP.bSeq[2] = '?') then
  52.   begin
  53.     if (lpImcP.bSeq[0] >= '0') and (lpImcP.bSeq[0] <= '9') then //Area mode
  54.     begin
  55.       if (lpImcP.bSeq[2] = '?') then
  56.       begin
  57.         lpImcP.bSeq[2] := '0';
  58.         lpImcP.bSeq[3] := '1';
  59.       end;
  60.       Result := AsciiToArea(lpImcP);
  61.     end else
  62.       if (lpImcP.bSeq[0] >= 'a') and (lpImcP.bSeq[0] <= 'f') then //GB mode
  63.       begin
  64.         if (lpImcP.bSeq[2] = '?') then
  65.         begin
  66.           lpImcP.bSeq[2] := 'a';
  67.           lpImcP.bSeq[3] := '1';
  68.         end;
  69.         Result := AsciiToGB(lpImcP);
  70.       end else
  71.         Result := 0;
  72.   end else
  73.     Result := 0;
  74. end;
  75.   // Conv GBcode for Space
  76. function GBSpcEng(lpImcP: PPrivContext): Word;
  77. begin
  78.   if (lpImcP.bSeq[0] >= '0') and (lpImcP.bSeq[0] <= '9') then //Area mode
  79.   begin
  80.     lpImcP.bSeq[2] := '0';
  81.     lpImcP.bSeq[3] := '1';
  82.     Result := AsciiToArea(lpImcP);
  83.   end else
  84.     if (lpImcP.bSeq[0] >= 'a') and (lpImcP.bSeq[0] <= 'f') then //GB mode
  85.     begin
  86.       lpImcP.bSeq[2] := 'a';
  87.       lpImcP.bSeq[3] := '1';
  88.       Result := AsciiToGB(lpImcP);
  89.     end else
  90.       Result := 0;
  91. end;
  92.   // search MB, and fill lpCompStr & lpCandList
  93. function Engine(lpCompStr: PCompositionString; lpCandList: PCandiDateList;
  94.   lpImcP: PPrivContext; lpIMC: PInputContext; wCharCode: Word): Integer;
  95. var
  96.   J: DWord;
  97.   wCode: Word;
  98.   ResaultStr: array[0..2] of Char;
  99. begin
  100.   if (lpCompStr.dwCursorPos < 4) and (lpImcP.bSeq[2] <> '?') and (wCharCode <> Ord(' ')) then
  101.   begin
  102.     Result := ENGINE_COMP;
  103.     Exit;
  104.   end else
  105.     if (lpCompStr.dwCursorPos = 4) or (lpImcP.bSeq[2] = '?') or
  106.        ((wCharCode = Ord(' ')) and (lpCompStr.dwCursorPos = 2)) then
  107.     begin
  108.       if (lpCompStr = nil) then
  109.       begin
  110.         MessageBeep($FFFFFFFF);
  111.         Result := -1;
  112.         Exit;
  113.       end;
  114.       if (lpImcP = nil) then
  115.       begin
  116.         MessageBeep($FFFFFFFF);
  117.         Result := -1;
  118.         Exit;
  119.       end;
  120.       if (lpImcP.bSeq[2] = '?') then // 查询
  121.       begin
  122.         wCode := GBEngine(lpImcP);
  123.         wCode := HiByte(wCode) or (LoByte(wCode) shl 8);
  124.         for J := 0 to IME_MAXCAND - 1 do
  125.         begin
  126.           AddCodeIntoCand(lpCandList, wCode);
  127.           Inc(wCode);
  128.         end;
  129.         Result := ENGINE_COMP;
  130.         Exit;
  131.       end else
  132.         if (wCharCode = Ord(' ')) then    // 查询
  133.         begin
  134.           wCode := GBSpcEng(lpImcP);
  135.           lpImcP.bSeq[2] := #0;
  136.           lpImcP.bSeq[3] := #0;
  137.           wCode := HiByte(wCode) or (LoByte(wCode) shl 8);
  138.           for J := 0 to IME_MAXCAND - 1 do
  139.           begin
  140.             AddCodeIntoCand(lpCandList, wCode);
  141.             Inc(wCode);
  142.           end;
  143.           Result := ENGINE_COMP;
  144.           Exit
  145.         end else                     // 转换
  146.         begin
  147.           InitCompStr(lpCompStr);
  148.           wCode := GBEngine(lpImcP); // the result string = the selected candidate;
  149.           ResaultStr[0] := Chr(LoByte(wCode));
  150.           ResaultStr[1] := Chr(HiByte(wCode));
  151.           ResaultStr[2] := #0;
  152.           lStrCpy(PChar(DWord(lpCompStr) + lpCompStr.dwResultStrOffset), ResaultStr);
  153.           lpCompStr.dwResultStrLen := lStrLen(ResaultStr); // calculate result string length
  154.           Result := ENGINE_RESAULT;
  155.           Exit;
  156.         end;
  157.     end;
  158.   MessageBeep($FFFFFFFF);
  159.   Result := ENGINE_COMP;
  160. end;
  161.   // Call Engine finalize Chinese word(s) by searching table
  162. function Finalize(lpIMC: PInputContext; lpCompStr: PCompositionString; lpImcP: PPrivContext; wCharCode: Word): uInt;
  163. var
  164.   lpCandInfo: PCandiDateInfo;
  165.   lpCandList: PCandiDateList;
  166. begin
  167.   Result := 0;
  168.   if (lpIMC.hCandInfo = 0) then Exit;
  169.   // get lpCandInfo
  170.   lpCandInfo := ImmLockIMCC(lpIMC.hCandInfo);
  171.   if (lpCandInfo = nil) then Exit;
  172.   // get lpCandList and init dwCount & dwSelection
  173.   lpCandList := PCandiDateList(DWord(lpCandInfo) + lpCandInfo.dwOffset[0]);
  174.   lpCandList.dwCount := 0;
  175.   lpCandList.dwSelection := 0;
  176.   // search the IME tables
  177.   Result := Engine(lpCompStr, lpCandList, lpImcP, lpIMC, wCharCode);
  178.   if (Result = ENGINE_COMP) then
  179.   begin
  180.     lpCandInfo.dwCount := 1;
  181.     if ( (lpCompStr.dwCursorPos < 3) and (wCharCode <> Ord(' ')) ) or
  182.        ( (lpCompStr.dwCursorPos = 3) and (wCharCode <> Ord(' ')) and (wCharCode <> Ord('?')) ) then
  183.     begin
  184.       lpImcP.fdwImeMsg := (lpImcP.fdwImeMsg or MSG_CLOSE_CANDIDATE) and (not MSG_OPEN_CANDIDATE);
  185.       ImmUnlockIMCC(lpIMC.hCandInfo);
  186.       Exit;
  187.     end;
  188.     if (lpCandList.dwCount <> 0) then
  189.     begin // open composition candidate UI window for the string(s)
  190.       if (lpImcP.fdwImeMsg and MSG_ALREADY_OPEN <> 0) and (MSG_ALREADY_OPEN and MSG_CLOSE_CANDIDATE <> 0) then
  191.       begin
  192.         lpImcP.fdwImeMsg := (lpImcP.fdwImeMsg or MSG_CHANGE_CANDIDATE) and (not MSG_CLOSE_CANDIDATE);
  193.       end else
  194.         if ((lpImcP.fdwImeMsg and MSG_ALREADY_OPEN) <> 0) then
  195.           lpImcP.fdwImeMsg := (lpImcP.fdwImeMsg or MSG_CHANGE_CANDIDATE)
  196.         else
  197.           lpImcP.fdwImeMsg := (lpImcP.fdwImeMsg or MSG_OPEN_CANDIDATE) and (not MSG_CLOSE_CANDIDATE);
  198.     end;
  199.     if ((lpImcP.fdwImeMsg and MSG_ALREADY_START) <> 0) then lpImcP.fdwImeMsg := lpImcP.fdwImeMsg or MSG_COMPOSITION;
  200.   end else
  201.     if (Result = ENGINE_ASCII) then
  202.     begin
  203.       // **
  204.     end else
  205.       if (Result = ENGINE_RESAULT) then
  206.       begin
  207.         // Set lpImep!   and tell application, there is a reslut string
  208.         lpImcP.fdwImeMsg := lpImcP.fdwImeMsg or MSG_COMPOSITION;
  209.         lpImcP.dwCompChar := 0;
  210.         lpImcP.fdwGcsFlag := lpImcP.fdwGcsFlag or GCS_COMPREAD or
  211.           GCS_COMP or GCS_CURSORPOS or GCS_DELTASTART or GCS_RESULTREAD or GCS_RESULT;
  212.         if ((lpImcP.fdwImeMsg and MSG_ALREADY_OPEN) <> 0) then
  213.           lpImcP.fdwImeMsg := (lpImcP.fdwImeMsg or MSG_CLOSE_CANDIDATE) and (not MSG_OPEN_CANDIDATE);
  214.         // clear candidate now
  215.         lpCandList.dwCount := 0;
  216.         // set iImeState with CST_INIT
  217.         lpImcP.iImeState := CST_INIT;
  218.         PDWord(@lpImcP.bSeq)^ := 0;
  219.       end;
  220.   ImmUnlockIMCC(lpIMC.hCandInfo);
  221. end;
  222.   // 添加Candidate
  223. procedure AddCodeIntoCand(lpCandList: PCandiDateList; wCode: Word);
  224. var
  225.   wInCode: Word;
  226. begin
  227.   if (lpCandList.dwCount >= IME_MAXCAND) then Exit;
  228.   wInCode := HiByte(wCode) or (LoByte(wCode) shl 8);
  229.   // add GB string into candidate list
  230.   PUnaWord(DWord(lpCandList) + lpCandList.dwOffset[lpCandList.dwCount])^ := wInCode;
  231.   // null terminator
  232.   PChar(DWord(lpCandList) + lpCandList.dwOffset[lpCandList.dwCount] + SizeOf(Word))^ := #0;
  233.   lpCandList.dwOffset[lpCandList.dwCount + 1] := lpCandList.dwOffset[lpCandList.dwCount] + SizeOf(Word) + SizeOf(Char);
  234.   Inc(lpCandList.dwCount);
  235. end;
  236.   // Composition取消处理
  237. procedure CompEscapeKey(lpIMC: PInputContext; lpCompStr: PCompositionString; lpGuideLine: PGuideLine; lpImcP: PPrivContext);
  238. begin
  239.   if (lpGuideLine = nil) then
  240.   begin
  241.     MessageBeep($FFFFFFFF);
  242.   end else
  243.     if (lpGuideLine.dwLevel <> GL_LEVEL_NOGUIDELINE) then
  244.     begin
  245.       lpGuideLine.dwLevel := GL_LEVEL_NOGUIDELINE;
  246.       lpGuideLine.dwIndex := GL_ID_UNKNOWN;
  247.       lpGuideLine.dwStrLen := 0;
  248.       lpImcP.fdwImeMsg := lpImcP.fdwImeMsg or MSG_GUIDELINE;
  249.     end;
  250.   if (lpImcP.iImeState <> CST_CHOOSE) then
  251.     if ((lpImcP.fdwImeMsg and MSG_ALREADY_START) <> 0) then
  252.       lpImcP.fdwImeMsg := (lpImcP.fdwImeMsg or MSG_END_COMPOSITION) and (not MSG_START_COMPOSITION);
  253.   lpImcP.iImeState := CST_INIT;
  254.   PDWord(@lpImcP.bSeq)^ := 0;
  255.   if (lpCompStr <> nil) then
  256.   begin
  257.     InitCompStr(lpCompStr);
  258.     lpImcP.fdwImeMsg := lpImcP.fdwImeMsg or MSG_COMPOSITION;
  259.     lpImcP.dwCompChar := VK_ESCAPE;
  260.     lpImcP.fdwGcsFlag := lpImcP.fdwGcsFlag or GCS_COMPREAD or GCS_COMP or GCS_CURSORPOS or GCS_DELTASTART;
  261.   end;
  262. end;
  263.   // Composition回退处理
  264. procedure CompBackSpaceKey(lpIMC: PInputContext; lpCompStr: PCompositionString; lpImcP: PPrivContext);
  265. begin
  266.   if (lpCompStr.dwCursorPos < SizeOf(Byte)) then lpCompStr.dwCursorPos := SizeOf(Byte);
  267.   lpImcP.bSeq[3] := #0;
  268.   // go back a compsoition char
  269.   Dec(lpCompStr.dwCursorPos, SizeOf(Byte));
  270.   // clean the sequence code
  271.   lpImcP.bSeq[lpCompStr.dwCursorPos] := #0;
  272.   lpImcP.fdwImeMsg := lpImcP.fdwImeMsg or MSG_COMPOSITION;
  273.   lpImcP.dwCompChar := $08;
  274.   lpImcP.fdwGcsFlag := lpImcP.fdwGcsFlag or GCS_COMPREAD or GCS_COMP or GCS_CURSORPOS or GCS_DELTASTART;
  275.   if (lpCompStr.dwCursorPos = 0) then
  276.   begin
  277.     if ((lpImcP.fdwImeMsg and MSG_ALREADY_OPEN) <> 0) then
  278.     begin
  279.       ClearCand(lpIMC);
  280.       lpImcP.fdwImeMsg := (lpImcP.fdwImeMsg or MSG_CLOSE_CANDIDATE) and (not MSG_OPEN_CANDIDATE);
  281.     end;
  282.     if (lpImcP.iImeState <> CST_INIT) then
  283.     begin
  284.       lpImcP.iImeState := CST_INIT;
  285.       lpCompStr.dwCompReadStrLen := lpCompStr.dwCursorPos;
  286.       lpCompStr.dwCompStrLen := lpCompStr.dwCursorPos;
  287.       lpCompStr.dwDeltaStart := lpCompStr.dwCursorPos;
  288.       Finalize(lpIMC, lpCompStr, lpImcP, $08);
  289.       Exit;
  290.     end;
  291.     if ((lpImcP.fdwImeMsg and MSG_ALREADY_START) <> 0) then
  292.     begin
  293.       InitCompStr(lpCompStr);
  294.       lpImcP.fdwImeMsg := (lpImcP.fdwImeMsg or MSG_END_COMPOSITION) and (not MSG_START_COMPOSITION);
  295.       Exit;
  296.     end;
  297.   end;
  298.   // reading string is composition string for some simple IMEs
  299.   // delta start is the same as cursor position for backspace
  300.   lpCompStr.dwCompReadStrLen := lpCompStr.dwCursorPos;
  301.   lpCompStr.dwCompStrLen := lpCompStr.dwCursorPos;
  302.   lpCompStr.dwDeltaStart := lpCompStr.dwCursorPos;
  303.   Finalize(lpIMC, lpCompStr, lpImcP, $08);
  304. end;
  305.   // 添加Composition, **
  306. procedure CompStrInfo(lpCompStr: PCompositionString; lpImcP: PPrivContext; lpGuideLine: PGuideLine; wCharCode: Word);
  307. var
  308.   dwCursorPos: DWord;
  309. begin
  310.   dwCursorPos := lpCompStr.dwCursorPos;
  311.   // dwCrusorPos limit
  312.   if (dwCursorPos >= sImeL.nMaxKey) then
  313.   begin
  314.     // exceed the max input key limitation
  315.     lpGuideLine.dwLevel := GL_LEVEL_ERROR;
  316.     lpGuideLine.dwIndex := GL_ID_TOOMANYSTROKE;
  317.     lpImcP.fdwImeMsg := lpImcP.fdwImeMsg or MSG_GUIDELINE;
  318.     Exit;
  319.   end;
  320.   // set MSG_START_COMPOSITION
  321.   if ((lpImcP.fdwImeMsg and MSG_ALREADY_START) = 0) then
  322.     lpImcP.fdwImeMsg := (lpImcP.fdwImeMsg or MSG_START_COMPOSITION) and (not MSG_END_COMPOSITION);
  323.   // clean the 4 bytes in one time
  324.   if (lpImcP.iImeState = CST_INIT) then PDWord(@lpImcP.bSeq)^ := 0;
  325.   // **
  326.   lpImcP.bSeq[dwCursorPos] := Chr(Byte(wCharCode));
  327.   // composition/reading string - UsedCode(Full Shape)
  328.   lpImcP.dwCompChar := wCharCode;
  329.   // set reading string for lpCompStr
  330.   PUnaWord(DWord(lpCompStr) + lpCompStr.dwCompReadStrOffset + dwCursorPos)^ := Byte(lpImcP.dwCompChar);
  331.   PUnaWord(DWord(lpCompStr) + lpCompStr.dwCompReadAttrOffset + dwCursorPos)^ := (ATTR_TARGET_CONVERTED shl 8) or ATTR_TARGET_CONVERTED;
  332.   // set reading string lenght for lpCompStr
  333.   if (lpCompStr.dwCompReadStrLen <= dwCursorPos) then Inc(lpCompStr.dwCompReadStrLen, SizeOf(Byte));
  334.   // composition string is reading string for some simple IMEs
  335.   lpCompStr.dwCompStrLen := lpCompStr.dwCompReadStrLen;
  336.   // composition/reading attribute length is equal to reading string length
  337.   lpCompStr.dwCompReadAttrLen := lpCompStr.dwCompReadStrLen;
  338.   lpCompStr.dwCompAttrLen := lpCompStr.dwCompStrLen;
  339.   // delta start from previous cursor position
  340.   lpCompStr.dwDeltaStart := lpCompStr.dwCursorPos;
  341.   // set new cursor with next to the composition string
  342.   lpCompStr.dwCursorPos := lpCompStr.dwCompStrLen;
  343.   // set lpImcp->iImeState
  344.   lpImcP.iImeState := CST_INPUT;
  345.   // tell app, there is a composition char generated
  346.   lpImcP.fdwImeMsg := lpImcP.fdwImeMsg or MSG_COMPOSITION;
  347.   // set lpImeP->fdwGcsFlag
  348.   lpImcP.fdwGcsFlag := lpImcP.fdwGcsFlag or GCS_COMPREAD or GCS_COMP or GCS_CURSORPOS or GCS_DELTASTART;
  349. end;
  350.   // compose the Chinese word(s) according to input key
  351. procedure CompWord(wCharCode: Word; lpIMC: PInputContext;
  352.   lpCompStr: PCompositionString; lpImcP: PPrivContext; lpGuideLine: PGuideLine);
  353. begin
  354.   if (lpCompStr = nil) then begin MessageBeep($FFFFFFFF); Exit; end;
  355.   // not good to use VK as char, but..., ??
  356.   if (wCharCode = VK_ESCAPE) then  // 取消
  357.   begin
  358.     CompEscapeKey(lpIMC, lpCompStr, lpGuideLine, lpImcP);
  359.     Exit;
  360.   end;
  361.   if (lpGuideLine = nil) then
  362.   begin
  363.   end else
  364.     if (lpGuideLine.dwLevel = GL_LEVEL_NOGUIDELINE) then
  365.     begin
  366.       lpGuideLine.dwStrLen := 0;
  367.     end else
  368.     begin
  369.       // previous input error cause us trancate some chars
  370.       if (lpGuideLine.dwLevel = GL_LEVEL_ERROR) then
  371.       begin
  372.         lpImcP.bSeq[lpCompStr.dwCursorPos div 2] := #0;
  373.         lpCompStr.dwCompReadStrLen := lpCompStr.dwCursorPos; // **
  374.         lpCompStr.dwCompStrLen := lpCompStr.dwCursorPos;
  375.         lpCompStr.dwCompReadAttrLen := lpCompStr.dwCompReadStrLen;
  376.         lpCompStr.dwCompAttrLen := lpCompStr.dwCompStrLen;
  377.       end;
  378.       lpGuideLine.dwLevel := GL_LEVEL_NOGUIDELINE;
  379.       lpGuideLine.dwIndex := GL_ID_UNKNOWN;
  380.       lpGuideLine.dwStrLen := 0;
  381.       lpImcP.fdwImeMsg := lpImcP.fdwImeMsg or MSG_GUIDELINE;
  382.     end;
  383.   if (wCharCode = $08) then // 回格
  384.   begin
  385.     CompBackSpaceKey(lpIMC, lpCompStr, lpImcP);
  386.     Exit;
  387.   end;
  388.   if (wCharCode <> Ord(' ')) then
  389.     CompStrInfo(lpCompStr, lpImcP, lpGuideLine, wCharCode); // build up composition string info
  390.   Finalize(lpIMC, lpCompStr, lpImcP, wCharCode); // compsition
  391. end;
  392. end.