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

输入法编程

开发平台:

Delphi

  1.  {******************************************************}
  2.  {                                                      }
  3.  {    Copyright (c) 1990-1999 Microsoft Corporation     }
  4.  {                                                      }
  5.  {    Module Name:  DDIS.c ->>  DDIS.pas                }
  6.  {                                                      }
  7.  {    Translator:  Liu_mazi@126.com, 2005-11-15         }
  8.  {                                                      }
  9.  {******************************************************}
  10. unit DDIS;
  11. {$I Define.Inc}
  12. interface
  13. uses Windows, ImmDev;
  14. var hCrtDlg: hWnd = 0;
  15. function OpenReg_PathSetup(_phKey: PHKey): DWord; // 打开注册表
  16. function OpenReg_User(_hKey: HKey; lpszSubKey: PChar; phkResult: PHKey): DWord; // 打开注册表
  17. function ClearCand(lpIMC: PInputContext): Bool; // 清除Candidate, **
  18. procedure InitCompStr(lpCompStr: PCompositionString); // 初始化编码串
  19.   // Ime回调 ..
  20. function ImeConfigure(_hKL: hKL; hAppWnd: hWnd; dwMode: DWord; lpData: Pointer): Bool; stdcall;
  21. function ImeConversionList(_hIMC: hIMC; lpszSrc: PChar; lpCandList: PCandiDateList; uBufLen, uFlag: uInt): DWord; stdcall;
  22. function ImeDestroy(uReserved: uInt): Bool; stdcall;
  23. function ImeEscape(_hIMC: hIMC; uSubFunc: uInt; lpData: PChar): LResult; stdcall;
  24. function ImeInquire(lpImeInfo: PImeInfo; lpszWndCls: PChar; lpszOptions: DWord): Bool; stdcall;
  25. function ImeSelect(_hIMC: hIMC; fSelect: Bool): Bool; stdcall;
  26. function ImeSetActiveContext(_hIMC: hIMC; fOn: Bool): Bool; stdcall;
  27. implementation
  28. uses Messages, ImeDefs, Data, ToAscii, Ui, Compose, LogText;
  29.   // Ime回调, initialized data structure of IME
  30. function ImeInquire(lpImeInfo: PImeInfo; lpszWndCls: PChar; lpszOptions: DWord): Bool; stdcall;
  31. begin
  32.   Result := False;
  33.   if (lpImeInfo = nil) then Exit;
  34.   lpImeInfo.dwPrivateDataSize := SizeOf(TPrivContext);
  35.   lpImeInfo.fdwProperty := IME_PROP_KBD_CHAR_FIRST or IME_PROP_CANDLIST_START_FROM_1 or IME_PROP_IGNORE_UPKEYS;
  36.   lpImeInfo.fdwConversionCaps := IME_CMODE_NATIVE or IME_CMODE_FULLSHAPE or IME_CMODE_CHARCODE or IME_CMODE_SOFTKBD or IME_CMODE_NOCONVERSION;
  37.   lpImeInfo.fdwSentenceCaps := 0;
  38.   // IME will have different distance base multiple of 900 escapement
  39.   lpImeInfo.fdwUICaps := UI_CAP_ROT90 or UI_CAP_SOFTKBD;
  40.   // composition string is the reading string for simple IME
  41.   lpImeInfo.fdwSCSCaps := SCS_CAP_COMPSTR or SCS_CAP_MAKEREAD;
  42.   // IME want to decide conversion mode on ImeSelect
  43.   lpImeInfo.fdwSelectCaps := 0;
  44.   lStrCpy(lpszWndCls, szUIClassName);
  45.   Result := True;
  46. end;
  47.   // Ime配置对话框回调
  48. function ImeSetDlgProc(hDlg: hWnd; uMessage: uInt; wParam: WParam; lParam: LParam): Bool; stdcall;
  49. const {$J+}
  50.   TempParam: DWord = $FFFFFFFF; {$J-}
  51. var
  52.   rc: TRect;
  53.   DlgWidth, DlgHeight: Integer;
  54.   hKeyCurrVersion, hKeyGB: hKey;
  55.   retCode: DWord;
  56. begin
  57.   Result := False;
  58.   case (uMessage) of
  59.     WM_INITDIALOG:
  60.     begin
  61.       hCrtDlg := hDlg;
  62.       // reset position
  63.       GetWindowRect(hDlg, rc);
  64.       DlgWidth :=  rc.Right - rc.Left;
  65.       DlgHeight :=  rc.Bottom - rc.Top;
  66.       SetWindowPos(hDlg, HWND_TOP, (sImeG.rcWorkArea.Right - DlgWidth) div 2,
  67.         (sImeG.rcWorkArea.Bottom - DlgHeight) div 2, 0, 0, SWP_NOSIZE);
  68.       TempParam := sImeG.IC_Trace;
  69.       CheckDlgButton(hDlg, IDC_TRACE, sImeG.IC_Trace);
  70.       // don't want to set focus to special control
  71.       Result := True;
  72.     end;
  73.     WM_COMMAND:
  74.       case (wParam) of
  75.         IDOK:
  76.         begin
  77.           sImeG.IC_Trace := TempParam;
  78.           
  79.           retCode := OpenReg_PathSetup(@hKeyCurrVersion);
  80.           if (retCode <> ERROR_SUCCESS) then RegCreateKey(HKEY_CURRENT_USER, REGSTR_PATH_SETUP, hKeyCurrVersion);
  81.           retCode := RegCreateKeyEx(hKeyCurrVersion, szImeRegName, 0, nil,
  82.             REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, nil, hKeyGB, nil);
  83.           if (retCode <> ERROR_SUCCESS) then RegCreateKey(HKEY_CURRENT_USER, REGSTR_PATH_SETUP, hKeyCurrVersion);
  84.           RegSetValueEx(hKeyGB, szTrace, 0, REG_DWORD, @sImeG.IC_Trace, SizeOf(DWord));
  85.           
  86.           RegCloseKey(hKeyGB);
  87.           RegCloseKey(hKeyCurrVersion);
  88.           EndDialog(hDlg, 0);
  89.           Result := True;
  90.         end;
  91.         IDCANCEL:
  92.         begin
  93.           EndDialog(hDlg, 0);
  94.           Result := True;
  95.         end;
  96.         IDC_TRACE: // Set Current InputMode Param(temp)
  97.         begin
  98.           if (TempParam = $FFFFFFFF) then TempParam := sImeG.IC_Trace; // 初始化, ++
  99.           TempParam := (TempParam xor $00000001) and $00000001;
  100.           Result := True;
  101.         end;
  102.       end;
  103.     WM_PAINT:
  104.     begin
  105.       GetClientRect(hDlg, rc);
  106.       DrawConvexRect(GetDC(hDlg), rc.Left + 7, rc.Top + 7, rc.Right - 7 - 1, rc.Bottom - 40 - 1);
  107.       DrawConvexRectP(GetDC(hDlg), rc.Left + 7, rc.Top + 7, rc.Right - 7, rc.Bottom - 40);
  108.     end;
  109.     WM_CLOSE:
  110.     begin
  111.       EndDialog(hDlg, 0);
  112.       Result := True;
  113.     end;
  114.   end;
  115. end;
  116.   // Ime回调, configurate the IME setting
  117. function ImeConfigure(_hKL: hKL; hAppWnd: hWnd; dwMode: DWord; lpData: Pointer): Bool; stdcall;
  118. begin
  119.   case (dwMode) of
  120.     IME_CONFIG_GENERAL:
  121.     begin
  122.       DialogBox(HInstance, 'ImeSet', hAppWnd, @ImeSetDlgProc);
  123.       Result := True;
  124.     end;
  125.     else
  126.       Result := False;
  127.   end;
  128. end;
  129.   // GCL_CONVERSION处理
  130. function Conversion(lpszReading: PChar; lpCandList: PCandiDateList; uBufLen: uInt): DWord;
  131. var
  132.   MAX_COMP, J, uMaxCand, iRet: uInt;
  133.   wCode: Word;
  134.   lpImcP: PPrivContext;
  135.   hImcP: hGlobal;
  136.   dwSize: DWord;
  137. begin
  138.   Result := 0;
  139.   if (lStrLen(lpszReading) <> 4) then Exit;
  140.   hImcP := GlobalAlloc(GMEM_MOVEABLE, SizeOf(TPrivContext));
  141.   if(hImcP = 0) then Exit;
  142.   lpImcP := GlobalLock(hImcP);
  143.   if (lpImcP = nil) then
  144.   begin
  145.     GlobalFree(hImcP);
  146.     Exit;
  147.   end;
  148.   lStrCpy(lpImcP.bSeq, lpszReading);
  149.   if (lpImcP.bSeq[3] = '?') then MAX_COMP := 94 else MAX_COMP := 1;
  150.   dwSize := SizeOf(TCandiDateList) + SizeOf(DWord) * MAX_COMP + (SizeOf(Word) + SizeOf(Char)) * MAX_COMP;
  151.   if (uBufLen = 0) then
  152.   begin
  153.     Result := dwSize;
  154.     Exit;
  155.   end;
  156.   uMaxCand := uBufLen - SizeOf(TCandidateList);
  157.   uMaxCand := uMaxCand div (SizeOf(DWord) + SizeOf(Word) + SizeOf(Char));
  158.   if (uMaxCand = 0) then Exit;  // can not even put one string
  159.   lpCandList.dwSize := dwSize;
  160.   lpCandList.dwStyle := IME_CAND_READ;    // candidate having same reading
  161.   lpCandList.dwCount := 0;
  162.   lpCandList.dwSelection := 0;
  163.   lpCandList.dwPageSize := CANDPERPAGE;
  164.   lpCandList.dwOffset[0] := SizeOf(TCandiDateList) + SizeOf(DWord) * (uMaxCand - 1);
  165.   lpImcP.bSeq[0] := #0;
  166.   lpImcP.bSeq[1] := #0;
  167.   lpImcP.bSeq[2] := #0;
  168.   lpImcP.bSeq[3] := #0;
  169.   for J := 0 to 3 do
  170.   begin
  171.     iRet := GBProcessKey(PByte(DWord(lpszReading) + J)^, lpImcP);
  172.     if (iRet = CST_INPUT) then lpImcP.bSeq[J] := PChar(DWord(lpszReading) + J)^ else Exit; //return 0;
  173.   end;
  174.   wCode := GBEngine(lpImcP);
  175.   wCode := HiByte(wCode) or (LoByte(wCode) shl 8);
  176.   for J := 0 to MAX_COMP - 1 do
  177.   begin
  178.     AddCodeIntoCand(lpCandList, wCode);
  179.     Inc(wCode);
  180.   end;
  181.   GlobalUnlock(hImcP);
  182.   GlobalFree(hImcP);
  183.   Result := dwSize;
  184. end;
  185.   // 汉字内码转区位码串, **
  186.   // function DBCSToGBCode(wCode: Word; AbSeq: array[0..4] of Char): Bool;
  187. function DBCSToGBCode(wCode: Word; AbSeq: PChar): Bool;
  188. var
  189.   AreaCode: Word;
  190. begin
  191.   Result := False;
  192.   //check valid GB range code first
  193.   if (LoByte(wCode) < $A1) or (LoByte(wCode) > $FE) or (HiByte(wCode) < $A1) or (HiByte(wCode) > $FE) then Exit;
  194.   AbSeq[1] := Chr(((wCode - $A0) and $FF) mod 10);
  195.   AbSeq[0] := Chr(((wCode - $A0) and $FF) div 10);
  196.   AreaCode := wCode shr 8; // **
  197.   AbSeq[3] := Chr(((AreaCode - $A0) and 256) mod 10);
  198.   AbSeq[2] := Chr(((AreaCode - $A0) and 256) div 10);
  199.   AbSeq[4] := #0;
  200.   Result := True;
  201. end;
  202.   // 区位码串转GB码串, **
  203.   // function AreaToGB(AbSeq: array[0..4] of Char; GbSeq: array[0..4] of Char): Bool;
  204. function AreaToGB(AbSeq, GbSeq: PChar): Bool;
  205. var
  206.   MbSeq: array[0..2] of Char; // Temp string
  207.   vList: DWord;
  208. begin
  209.   // Area turn
  210.   vList := Ord(AbSeq[0]) * 10 + Ord(AbSeq[1]) + $A0;
  211.   wvsprintf(MbSeq, '%lx', @vList);
  212.   GbSeq[0] := MbSeq[0];
  213.   GbSeq[1] := MbSeq[1];
  214.   // position turn
  215.   vList := Ord(AbSeq[2]) * 10 + Ord(AbSeq[3]) + $A0;
  216.   wvsprintf(MbSeq, '%lx', @vList);
  217.   GbSeq[2] := MbSeq[0];
  218.   GbSeq[3] := MbSeq[1];
  219.   GbSeq[4] := #0;
  220.   Result := True;
  221. end;
  222.   // GCL_REVERSECONVERSION处理
  223. function ReverseConversion(wCode: Word; lpCandList: PCandiDateList; uBufLen: uInt): DWord;
  224. const
  225.   Max_Comp: uInt = 2; // **
  226.   nMaxKey: uInt = 4;
  227. var
  228.   AbSeq, GbSeq: array [0..4] of Char;
  229.   uMaxCand: uInt;
  230.   dwSize: DWord;  // similar to ClearCand
  231.   lpdwOffset: PDWord;
  232. begin
  233.   Result := 0;
  234.   dwSize := SizeOf(TCandidateList) + SizeOf(DWord) * Max_Comp + (SizeOf(Char) * nMaxKey + SizeOf(Char));
  235.   if (uBufLen = 0) then
  236.   begin
  237.     Result := dwSize;
  238.     Exit;
  239.   end;
  240.   uMaxCand := uBufLen - SizeOf(TCandidateList);
  241.   uMaxCand := uMaxCand div (SizeOf(DWord) + SizeOf(Char) * nMaxKey + SizeOf(Char));
  242.   if (uMaxCand = 0) then Exit;// can not put one string
  243.   lpCandList.dwSize := SizeOf(TCandidateList) + SizeOf(DWord) * uMaxCand + (SizeOf(Char) * nMaxKey + SizeOf(Char));
  244.   lpCandList.dwStyle := IME_CAND_READ;
  245.   lpCandList.dwCount := 0;
  246.   lpCandList.dwSelection := 0;
  247.   lpCandList.dwOffset[0] := SizeOf(TCandidateList) + SizeOf(DWord);
  248.   if (DBCSToGBCode(wCode, AbSeq) = False) then Exit;
  249.   AreaToGB(AbSeq, GbSeq);
  250.   Inc(AbSeq[1], Ord('0'));
  251.   Inc(AbSeq[0], Ord('0'));
  252.   Inc(AbSeq[3], Ord('0'));
  253.   Inc(AbSeq[2], Ord('0'));
  254.   lStrCpy(PChar(DWord(lpCandList) + lpCandList.dwOffset[0]), AbSeq);
  255.   lpdwOffset := @lpCandList.dwOffset[0];
  256.   Inc(lpdwOffset);
  257.   lpdwOffset^ := lpCandList.dwOffset[0] + 4 * SizeOf(Char) + SizeOf(Char);
  258.   lStrCpy(PChar(DWord(lpCandList) + lpdwOffset^), GbSeq);
  259.   lpCandList.dwCount := 2; // string count ++
  260.   Result := dwSize;
  261. end;
  262.   // Ime回调
  263. function ImeConversionList(_hIMC: hIMC; lpszSrc: PChar; lpCandList: PCandiDateList; uBufLen, uFlag: uInt): DWord; stdcall;
  264. var
  265.   wCode: Word;
  266.   lpIMC: PInputContext;
  267.   lpImcP: PPrivContext;
  268. begin
  269.   Result := 0;
  270.   if (uBufLen = 0) then
  271.   begin
  272.   end else
  273.     if (lpszSrc = nil) or
  274.        (lpszSrc^ = #0) or
  275.        (lpCandList = nil) or
  276.        (uBufLen <= SizeOf(TCandidateList))
  277.     then Exit;
  278.   case (uFlag) of
  279.     GCL_CONVERSION:
  280.     begin
  281.       lpIMC := ImmLockIMC(_hIMC);
  282.       if (lpIMC = nil) then Exit;
  283.       lpImcP := ImmLockIMCC(lpIMC.hPrivate);
  284.       if (lpImcP = nil) then
  285.       begin
  286.         ImmUnlockIMC(_hIMC);
  287.         Exit;
  288.       end;
  289.       Result := Conversion(lpszSrc, lpCandList, uBufLen);
  290.     end;
  291.     GCL_REVERSECONVERSION:
  292.     begin
  293.       if (uBufLen = 0) then
  294.       begin
  295.         Result := 1;
  296.         Exit;
  297.       end;
  298.       // only support one DBCS char reverse conversion
  299.       if PChar(DWord(lpszSrc) + SizeOf(Word))^ <> #0 then Exit;
  300.       wCode := PWord(lpszSrc)^;
  301.       // swap lead byte & second byte, UNICODE don't need it
  302.       // wCode = HIBYTE(wCode) | (LOBYTE(wCode) << 8);  For Big5
  303.       Result := ReverseConversion(wCode, lpCandList, uBufLen);
  304.     end;
  305.   end;
  306. end;
  307.   // Ime回调, this dll is unloaded
  308. function ImeDestroy(uReserved: uInt): Bool; stdcall;
  309. begin
  310.   Result := (uReserved = 0);
  311. end;
  312.   // **
  313. const
  314.   IME_INPUTKEYTOSEQUENCE = $22;
  315.   // Ime回调, escape function of IMEs
  316. function ImeEscape(_hIMC: hIMC; uSubFunc: uInt; lpData: PChar): LResult; stdcall;
  317. var
  318.   szIMEGUDHlpName: array[0..MAXSTRLEN] of Char;
  319. begin
  320.   case (uSubFunc) of
  321.     IME_ESC_QUERY_SUPPORT:
  322.     begin
  323.       if (lpData = nil) then
  324.       begin
  325.         Result := 0;
  326.         Exit;
  327.       end;
  328.       case PUInt(lpData)^ of // **
  329.         IME_ESC_QUERY_SUPPORT,
  330.         IME_ESC_MAX_KEY,
  331.         IME_ESC_IME_NAME,
  332.         IME_ESC_GETHELPFILENAME:
  333.           Result := 0;
  334.         IME_ESC_SEQUENCE_TO_INTERNAL,
  335.         IME_ESC_GET_EUDC_DICTIONARY,
  336.         IME_ESC_SET_EUDC_DICTIONARY,
  337.         IME_INPUTKEYTOSEQUENCE:      // will not supported in next version
  338.           Result := 0;      // will not supported in GB IME
  339.         else
  340.           Result := 0;
  341.       end;
  342.     end;
  343.     IME_ESC_SEQUENCE_TO_INTERNAL,
  344.     IME_ESC_GET_EUDC_DICTIONARY,
  345.     IME_ESC_SET_EUDC_DICTIONARY,
  346.     IME_INPUTKEYTOSEQUENCE:
  347.       Result := 0;
  348.     IME_ESC_MAX_KEY:
  349.       Result := 4;
  350.     IME_ESC_IME_NAME:
  351.     begin
  352.       Result := 0;
  353.       if (lpData = nil) then Exit;
  354.       lStrCpy(lpData, szImeName);
  355.       Result := 1;
  356.     end;
  357.     IME_ESC_GETHELPFILENAME:
  358.     begin
  359.       Result := 0;
  360.       if (lpData = nil) then Exit;
  361.       szIMEGUDHlpName[0] := #0;
  362.       GetWindowsDirectory(szIMEGUDHlpName, MAXSTRLEN);
  363.       lStrCat(szIMEGUDHlpName, 'HELPWINGB.CHM');
  364.       lStrCpy(lpData, szIMEGUDHlpName);
  365.       Result := 1;
  366.     end;
  367.     else
  368.       Result := 1;
  369.   end;
  370. end;
  371.   // init setting for composing string
  372. procedure InitCompStr(lpCompStr: PCompositionString);
  373. begin
  374.   if (lpCompStr = nil) then Exit;
  375.   lpCompStr.dwCompReadAttrLen := 0;
  376.   lpCompStr.dwCompReadClauseLen := 0;
  377.   lpCompStr.dwCompReadStrLen := 0;
  378.   lpCompStr.dwCompAttrLen := 0;
  379.   lpCompStr.dwCompClauseLen := 0;
  380.   lpCompStr.dwCompStrLen := 0;
  381.   lpCompStr.dwCursorPos := 0;
  382.   lpCompStr.dwDeltaStart := 0;
  383.   lpCompStr.dwResultReadClauseLen := 0;
  384.   lpCompStr.dwResultReadStrLen := 0;
  385.   lpCompStr.dwResultClauseLen := 0;
  386.   lpCompStr.dwResultStrLen := 0;
  387. end;
  388.   // 清除编码串, **
  389. function ClearCompStr(lpIMC: PInputContext): Bool;
  390. var
  391.   hMem: hIMCC;
  392.   lpCompStr: PCompositionString;
  393.   dwSize: DWord;
  394. begin
  395.   Result := False;
  396.   if (lpIMC = nil) then Exit;
  397.   dwSize :=
  398.     SizeOf(TCompositionString) +
  399.     sImeL.nMaxKey * SizeOf(Byte) + SizeOf(Byte) +
  400.     SizeOf(DWord) + SizeOf(DWord) +
  401.     sImeL.nMaxKey * SizeOf(Word) + SizeOf(Word) +
  402.     SizeOf(DWord) + SizeOf(DWord) +
  403.     sImeL.nMaxKey * SizeOf(Word) + SizeOf(Word) +
  404.     SizeOf(DWord) + SizeOf(DWord) +
  405.     MAXSTRLEN * SizeOf(Word) + SizeOf(Word);
  406.   if (lpIMC.hCompStr = 0) then
  407.   begin
  408.     lpIMC.hCompStr := ImmCreateIMCC(dwSize); // it maybe free by other IME, init it
  409.   end else
  410.   begin
  411.     hMem := ImmReSizeIMCC(lpIMC.hCompStr, dwSize);
  412.     if (hMem <> 0) then
  413.     begin
  414.       lpIMC.hCompStr := hMem;
  415.     end else
  416.     begin
  417.       ImmDestroyIMCC(lpIMC.hCompStr);
  418.       lpIMC.hCompStr := ImmCreateIMCC(dwSize);
  419.       Exit;
  420.     end;
  421.   end;
  422.   if (lpIMC.hCompStr = 0) then Exit; // return (FALSE)
  423.   lpCompStr := ImmLockIMCC(lpIMC.hCompStr);
  424.   if (lpCompStr = nil) then
  425.   begin
  426.     ImmDestroyIMCC(lpIMC.hCompStr);
  427.     lpIMC.hCompStr := ImmCreateIMCC(dwSize);
  428.     Exit;
  429.   end;
  430.   lpCompStr.dwSize := dwSize;
  431.   // 1. composition (reading) string - simple IME
  432.   // 2. result reading string
  433.   // 3. result string
  434.   lpCompStr.dwCompReadAttrLen := 0;
  435.   lpCompStr.dwCompReadAttrOffset := SizeOf(TCompositionString);
  436.   lpCompStr.dwCompReadClauseLen := 0;
  437.   lpCompStr.dwCompReadClauseOffset := lpCompStr.dwCompReadAttrOffset + sImeL.nMaxKey * SizeOf(Char) + SizeOf(Char);
  438.   lpCompStr.dwCompReadStrLen := 0;
  439.   lpCompStr.dwCompReadStrOffset := lpCompStr.dwCompReadClauseOffset + Sizeof(DWord) + Sizeof(DWord);
  440.   // composition string is the same with composition reading string for simple IMEs
  441.   lpCompStr.dwCompAttrLen := 0;
  442.   lpCompStr.dwCompAttrOffset := lpCompStr.dwCompReadAttrOffset;
  443.   lpCompStr.dwCompClauseLen := 0;
  444.   lpCompStr.dwCompClauseOffset := lpCompStr.dwCompReadClauseOffset;
  445.   lpCompStr.dwCompStrLen := 0;
  446.   lpCompStr.dwCompStrOffset := lpCompStr.dwCompReadStrOffset;
  447.   lpCompStr.dwCursorPos := 0;
  448.   lpCompStr.dwDeltaStart := 0;
  449.   lpCompStr.dwResultReadClauseLen := 0;
  450.   lpCompStr.dwResultReadClauseOffset := lpCompStr.dwCompStrOffset + sImeL.nMaxKey * SizeOf(Word) + SizeOf(Word);
  451.   lpCompStr.dwResultReadStrLen := 0;
  452.   lpCompStr.dwResultReadStrOffset := lpCompStr.dwResultReadClauseOffset + SizeOf(DWord) + SizeOf(DWord);
  453.   lpCompStr.dwResultClauseLen := 0;
  454.   lpCompStr.dwResultClauseOffset := lpCompStr.dwResultReadStrOffset + sImeL.nMaxKey * SizeOf(Word) + SizeOf(Word);
  455.   lpCompStr.dwResultStrOffset := 0;
  456.   lpCompStr.dwResultStrOffset := lpCompStr.dwResultClauseOffset + SizeOf(DWord) + SizeOf(DWord);
  457.   GlobalUnlock(lpIMC.hCompStr);
  458.   Result := True;
  459. end;
  460.   // 清除Candidate, **
  461. function ClearCand(lpIMC: PInputContext): Bool;
  462. var
  463.   hMem: hIMCC;
  464.   lpCandInfo: PCandiDateInfo;
  465.   lpCandList: PCandiDateList;
  466.   dwSize: DWord;
  467. begin
  468.   dwSize := SizeOf(TCandidateInfo) + SizeOf(TCandidateList) +
  469.     SizeOf(DWord) * (MAXCAND + 1) + (SizeOf(Word) + SizeOf(Word)) * (MAXCAND + 1);
  470.   Result := False;
  471.   if (lpIMC = nil) then Exit;
  472.   if (lpIMC.hCandInfo = 0) then
  473.   begin
  474.     lpIMC.hCandInfo := ImmCreateIMCC(dwSize); // it maybe free by other IME, init it
  475.   end else
  476.   begin
  477.     hMem := ImmReSizeIMCC(lpIMC.hCandInfo, dwSize);
  478.     if (hMem <> 0) then
  479.     begin
  480.       lpIMC.hCandInfo := hMem;
  481.     end else
  482.     begin
  483.       ImmDestroyIMCC(lpIMC.hCandInfo);
  484.       lpIMC.hCandInfo := ImmCreateIMCC(dwSize);
  485.       Exit; // return (FALSE)
  486.     end;
  487.   end;
  488.   if (lpIMC.hCandInfo = 0) then Exit; // return (FALSE)
  489.   lpCandInfo := ImmLockIMCC(lpIMC.hCandInfo);
  490.   if (lpCandInfo = nil) then
  491.   begin
  492.     ImmDestroyIMCC(lpIMC.hCandInfo);
  493.     lpIMC.hCandInfo := ImmCreateIMCC(dwSize);
  494.     Exit; // return (FALSE)
  495.   end;
  496.   // ordering of strings are buffer size
  497.   lpCandInfo.dwSize := dwSize;
  498.   lpCandInfo.dwCount := 0;
  499.   lpCandInfo.dwOffset[0] := SizeOf(TCandidateInfo);
  500.   lpCandList := PCandidateList(DWord(lpCandInfo) + lpCandInfo.dwOffset[0]);
  501.   // whole candidate info size - header
  502.   lpCandList.dwSize := lpCandInfo.dwSize - SizeOf(TCandidateInfo);
  503.   lpCandList.dwStyle := IME_CAND_READ;
  504.   lpCandList.dwCount := 0;
  505.   lpCandList.dwSelection := 0;
  506.   lpCandList.dwPageSize := CANDPERPAGE;
  507.   lpCandList.dwOffset[0] := SizeOf(TCandidateList) + SizeOf(DWord) * (MAXCAND);
  508.   ImmUnlockIMCC(lpIMC.hCandInfo);
  509.   Result := True;
  510. end;
  511.   // 清除GuideLine, **
  512. function ClearGuideLine(lpIMC: PInputContext): Bool;
  513. var
  514.   hMem: hIMCC;
  515.   lpGuideLine: PGuideLine;
  516.   dwSize: DWord;
  517. begin
  518.   dwSize := SizeOf(TGuideLine) + sImeG.cbStatusErr;
  519.   Result := False;
  520.   if (lpIMC.hGuideLine = 0) then
  521.   begin
  522.     lpIMC.hGuideLine := ImmCreateIMCC(dwSize); // it maybe free by IME
  523.   end else
  524.   begin
  525.     hMem := ImmReSizeIMCC(lpIMC.hGuideLine, dwSize);
  526.     if (hMem <> 0) then
  527.     begin
  528.       lpIMC.hGuideLine := hMem;
  529.     end else
  530.     begin
  531.       ImmDestroyIMCC(lpIMC.hGuideLine);
  532.       lpIMC.hGuideLine := ImmCreateIMCC(dwSize);
  533.     end;
  534.   end;
  535.   lpGuideLine := ImmLockIMCC(lpIMC.hGuideLine);
  536.   if (lpGuideLine = nil) then Exit; // return (FALSE)
  537.   lpGuideLine.dwSize := dwSize;
  538.   lpGuideLine.dwLevel := GL_LEVEL_NOGUIDELINE;
  539.   lpGuideLine.dwIndex := GL_ID_UNKNOWN;
  540.   lpGuideLine.dwStrLen := 0;
  541.   lpGuideLine.dwStrOffset := SizeOf(TGuideLine);
  542.   CopyMemory(Pointer(DWord(lpGuideLine) + lpGuideLine.dwStrOffset), @sImeG.szStatusErr, sImeG.cbStatusErr);
  543.   ImmUnlockIMCC(lpIMC.hGuideLine);
  544.   Result := True;
  545. end;
  546.   // **
  547. procedure InitContext(lpIMC: PInputContext);
  548. var
  549.   ptWnd: TPoint;
  550. begin
  551.   if (lpIMC.fdwInit and INIT_STATUSWNDPOS) <> 0 then
  552.   begin
  553.   end else
  554.     if (IsWindow(lpIMC.hWnd) = False) then
  555.     begin
  556.     end else
  557.     begin
  558.       ptWnd.x := 0;
  559.       ptWnd.y := 0;
  560.       ClientToScreen(lpIMC.hWnd, ptWnd);
  561.       if (ptWnd.x < sImeG.rcWorkArea.Left) then
  562.       begin
  563.         lpIMC.ptStatusWndPos.x := sImeG.rcWorkArea.Left;
  564.       end else
  565.         if (ptWnd.x + sImeG.xStatusWi > sImeG.rcWorkArea.Right) then
  566.         begin
  567.           lpIMC.ptStatusWndPos.x := sImeG.rcWorkArea.Right - sImeG.xStatusWi;
  568.         end else
  569.         begin
  570.           lpIMC.ptStatusWndPos.x := ptWnd.x;
  571.         end;
  572.       lpIMC.ptStatusWndPos.y := sImeG.rcWorkArea.Bottom - sImeG.yStatusHi;
  573.       lpIMC.fdwInit := lpIMC.fdwInit or INIT_STATUSWNDPOS;
  574.     end;
  575.   if (lpIMC.fdwInit and INIT_COMPFORM) <> 0 then
  576.   begin
  577.   end else
  578.     if (IsWindow(lpIMC.hWnd) = False) then
  579.     begin
  580.     end else
  581.     begin
  582.       ptWnd := sImeL.ptDefComp;
  583.       ScreenToClient(lpIMC.hWnd, ptWnd);
  584.       lpIMC.cfCompForm.dwStyle := CFS_DEFAULT;
  585.       lpIMC.cfCompForm.ptCurrentPos := ptWnd;
  586.       lpIMC.fdwInit := lpIMC.fdwInit or INIT_COMPFORM;
  587.     end;
  588. end;
  589.   // **
  590. function Select(_hIMC: hIMC; lpIMC: PInputContext; fSelect: Bool): Bool;
  591. var
  592.   lpImcP: PPrivContext;
  593. //  J: uInt;
  594.   _hDC: hDC;
  595.   hSysFont: hGdiObj;
  596.   fdwConversion: DWord;
  597. begin
  598.   Result := False;
  599.   if (fSelect) then
  600.   begin
  601.     if (ClearCompStr(lpIMC) = False) then Exit; // return FALSE
  602.     if (ClearCand(lpIMC) = False) then Exit; // return FALSE
  603.     ClearGuideLine(lpIMC);
  604.   end;
  605.   if (lpIMC.cfCandForm[0].dwIndex <> 0) then lpIMC.cfCandForm[0].dwStyle := CFS_DEFAULT;
  606.   // We add this hack for switching from other IMEs, this IME has a bug.
  607.   // Before this bug fixed in this IME, it depends on this hack.
  608.   if (lpIMC.cfCandForm[0].dwStyle = CFS_DEFAULT) then lpIMC.cfCandForm[0].dwIndex := $FFFFFFFF; 
  609.   if (lpIMC.hPrivate = 0) then Exit; // return FALSE
  610.   lpImcP := ImmLockIMCC(lpIMC.hPrivate);
  611.   if (lpImcP = nil) then Exit; // return FALSE
  612.   if (fSelect) then
  613.   begin
  614.     //
  615.     // init fields of hPrivate
  616.     //
  617.     lpImcP.iImeState  := CST_INIT;
  618.     lpImcP.fdwImeMsg  := 0;
  619.     lpImcP.dwCompChar := 0;
  620.     lpImcP.fdwGcsFlag := 0;
  621.     lpImcP.uSYHFlg    := 0;
  622.     lpImcP.uDYHFlg    := 0;
  623.     lpImcP.uDSMHCount := 0;
  624.     lpImcP.uDSMHFlg   := 0;
  625.     //lpImcP->fdwSentence = (DWORD)NULL;
  626.     //
  627.     // reset SK State
  628.     //
  629.     PDWord(@lpImcP.bSeq)^ := 0;
  630.     lpIMC.fOpen := True;
  631.     if (lpIMC.fdwInit and INIT_CONVERSION) = 0 then
  632.     begin
  633.       lpIMC.fdwConversion := (lpIMC.fdwConversion and IME_CMODE_SOFTKBD) or IME_CMODE_NATIVE;
  634.       lpIMC.fdwInit := lpIMC.fdwInit or INIT_CONVERSION;
  635.     end;
  636.     if (lpIMC.fdwInit and INIT_SENTENCE) <> 0 then
  637.     begin
  638.     end else
  639.       if (sImeL.fModeConfig and MODE_CONFIG_PREDICT) <> 0 then
  640.       begin
  641.         lpIMC.fdwSentence := IME_SMODE_PHRASEPREDICT;
  642.         lpIMC.fdwInit := lpIMC.fdwInit or INIT_SENTENCE;
  643.       end;
  644.     if (lpIMC.fdwInit and INIT_LOGFONT) = 0 then
  645.     begin
  646.       //hSysFont = GetStockObject(SYSTEM_FONT);
  647.       _hDC := GetDC(0);
  648.       hSysFont := GetCurrentObject(_hDC, OBJ_FONT);
  649.       GetObject(hSysFont, SizeOf(TLogFont), @lpIMC.lfFont.A);
  650.       ReleaseDC(0, _hDC);
  651.       lpIMC.fdwInit := lpIMC.fdwInit or INIT_LOGFONT;
  652.     end;
  653.     InitContext(lpIMC);
  654.     //
  655.     // Set Caps status
  656.     //
  657.     if (GetKeyState(VK_CAPITAL) and $01) <> 0 then
  658.     begin
  659.       //
  660.       // Change to alphanumeric mode.
  661.       //
  662.       fdwConversion := lpIMC.fdwConversion and not(IME_CMODE_NATIVE or IME_CMODE_CHARCODE or IME_CMODE_EUDC);
  663.     end else
  664.     begin
  665.       //
  666.       // Change to native mode
  667.       //
  668.       fdwConversion := (lpIMC.fdwConversion or IME_CMODE_NATIVE) and not(IME_CMODE_CHARCODE or IME_CMODE_EUDC );
  669.     end;
  670.     ImmSetConversionStatus(_hIMC, fdwConversion, lpIMC.fdwSentence);
  671.   end else
  672.   begin
  673.     if (sImeL.hSKMenu <> 0) then
  674.     begin
  675.       DestroyMenu(sImeL.hSKMenu);
  676.       sImeL.hSKMenu := 0;
  677.     end;
  678.     if (sImeL.hPropMenu <> 0) then
  679.     begin
  680.       DestroyMenu(sImeL.hPropMenu);
  681.       sImeL.hPropMenu := 0;
  682.     end;
  683.     if IsWindow(hCrtDlg) then
  684.     begin
  685.       SendMessage(hCrtDlg, WM_CLOSE, 0, 0);
  686.       hCrtDlg := 0;
  687.     end;
  688.   end;
  689.   ImmUnlockIMCC(lpIMC.hPrivate);
  690.   Result := True;
  691. end;
  692.   // Ime回调, 初始化
  693. function ImeSelect(_hIMC: hIMC; fSelect: Bool): Bool; stdcall;
  694. var
  695.   lpIMC: PInputContext;
  696. begin
  697.   Result := False;
  698.   if (_hIMC = 0) then Exit;
  699.   lpIMC := ImmLockIMC(_hIMC);
  700.   if (lpIMC = nil) then Exit;
  701.   Result := Select(_hIMC, lpIMC, fSelect);
  702.   ImmUnlockIMC(_hIMC);
  703. end;
  704.   // Ime回调, 激活输入法
  705. function ImeSetActiveContext(_hIMC: hIMC; fOn: Bool): Bool; stdcall;
  706. var
  707.   lpIMC: PInputContext;
  708. begin
  709.   Result := False;
  710.   if (fOn = False) then
  711.   begin
  712.   end else
  713.     if (_hIMC = 0) then
  714.     begin
  715.     end else
  716.     begin
  717.       lpIMC := ImmLockIMC(_hIMC);
  718.       if (lpIMC = nil) then Exit;
  719.       InitContext(lpIMC);
  720.       ImmUnlockIMC(_hIMC);
  721.     end;
  722.   Result := True;
  723. end;
  724.   // 打开注册表, HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersion
  725. function OpenReg_PathSetup(_phKey: PHKey): DWord;
  726. begin
  727.   Result := RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_SETUP, 0,
  728.     KEY_ENUMERATE_SUB_KEYS or KEY_EXECUTE or KEY_QUERY_VALUE, _phKey^);
  729. end;
  730.   // 打开注册表, _hKeylpszSubKey
  731. function OpenReg_User(_hKey: HKey; lpszSubKey: PChar; phkResult: PHKey): DWord;
  732. begin
  733. {$IfDef Debug}
  734.   ImeLog('OpenReg_User, ' + lpszSubKey);
  735. {$EndIf}
  736.   Result := RegOpenKeyEx(_hKey, lpszSubKey, 0, KEY_ALL_ACCESS, phkResult^);
  737. end;
  738.   // 显示信息
  739. procedure InfoMessage(_hWnd: hWnd; wMsgID: Word);
  740. var
  741.   szStr: array[0..256] of Char;
  742. begin
  743.   LoadString(0, wMsgID, szStr, SizeOf(szStr) - 1);
  744.   MessageBox(_hWnd, szStr, szWarnTitle, MB_ICONINFORMATION or MB_OK);
  745. end;
  746.   // 显示错误
  747. procedure FatalMessage(_hWnd: hWnd; wMsgID: Word);
  748. var
  749.   szStr: array[0..256] of Char;
  750. begin
  751.   LoadString(0, wMsgID, szStr, SizeOf(szStr) - 1);
  752.   MessageBox(_hWnd, szStr, szErrorTitle, MB_ICONSTOP or MB_OK);
  753. end;
  754. end.