Compui.pas
资源名称:Wingb_Mz.rar [点击查看]
上传用户:wen198501
上传日期:2013-04-01
资源大小:335k
文件大小:25k
源码类别:
输入法编程
开发平台:
Delphi
- {******************************************************}
- { }
- { Copyright (c) 1990-1999 Microsoft Corporation }
- { }
- { Module Name: Compui.c ->> Compui.pas }
- { }
- { Translator: Liu_mazi@126.com, 2005-11-17 }
- { }
- {******************************************************}
- unit Compui;
- {$I Define.Inc}
- interface
- uses Windows;
- function GetCompWnd(hUIWnd: hWnd): hWnd; // 返回Composition窗口句柄
- function CompWndProc(hCompWnd: hWnd; uMsg: uInt; wParam: WParam; lParam: LParam): LResult; stdcall; // Composition窗口回调
- procedure ShowComp(hUIWnd: hWnd; nShowCompCmd: Integer); // 显示隐藏Composition窗口
- procedure StartComp(hUIWnd: hWnd); // 打开Composition窗口
- procedure EndComp(hUIWnd: hWnd); // 隐藏Composition窗口
- procedure MoveDefaultCompPosition(hUIWnd: hWnd); // the default comp position need to near the caret
- implementation
- uses Messages, ImmDev, ImeDefs, Data, Ui, Uisubs, Statusui, Candui, LogText;
- // 返回Composition窗口句柄
- function GetCompWnd(hUIWnd: hWnd): hWnd;
- var
- hUIPrivate: HGlobal;
- lpUIPrivate: PUIPriv;
- begin
- Result := 0;
- hUIPrivate := GetWindowLong(hUIWnd, IMMGWLP_PRIVATE);
- if (hUIPrivate = 0) then Exit; // can not darw candidate window
- lpUIPrivate := GlobalLock(hUIPrivate);
- if (lpUIPrivate = nil) then Exit; // can not draw candidate window
- Result := lpUIPrivate.hCompWnd;
- GlobalUnlock(hUIPrivate);
- end;
- // fit in lazy operation or not
- function FitInLazyOperation(lpptOrg, lpptNearCaret: PPoint; lprcInputRect: PRect; uEsc: uInt): Bool;
- var
- ptDelta, ptTol: TPoint;
- rcUIRect, rcInterRect: TRect;
- begin
- Result := False;
- ptDelta.x := lpptOrg.x - lpptNearCaret.x;
- if (ptDelta.x < 0) then ptDelta.x := - ptDelta.x;
- ptTol.x := sImeG.iParaTol * ncUIEsc[uEsc].iParaFacX + sImeG.iPerpTol * ncUIEsc[uEsc].iPerpFacX;
- if (ptTol.x < 0) then ptTol.x := - ptTol.x;
- if (ptDelta.x > ptTol.x) then Exit;
- ptDelta.y := lpptOrg.y - lpptNearCaret.y;
- if (ptDelta.y < 0) then ptDelta.y := - ptDelta.y;
- ptTol.y := sImeG.iParaTol * ncUIEsc[uEsc].iParaFacY + sImeG.iPerpTol * ncUIEsc[uEsc].iPerpFacY;
- if (ptTol.y < 0) then ptTol.y := - ptTol.y;
- if (ptDelta.y > ptTol.y) then Exit;
- // build up the UI rectangle (composition window)
- rcUIRect.Left := lpptOrg.x;
- rcUIRect.Top := lpptOrg.y;
- rcUIRect.Right := rcUIRect.Left + sImeL.xCompWi;
- rcUIRect.Bottom := rcUIRect.Top + sImeL.yCompHi;
- if IntersectRect(rcInterRect, rcUIRect, lprcInputRect^) then Exit;
- Result := True;
- end;
- // decide a near caret position according to the caret position
- procedure GetNearCaretPosition(lpptFont: PPoint; uEsc, uRot: uInt; lpptCaret, lpptNearCaret: PPoint; fFlags: DWord);
- var
- lFontSize, xWidthUI, yHeightUI, xBorder, yBorder: Integer;
- begin
- if ((uEsc + uRot) and $0001) <> 0 then lFontSize := lpptFont.x else lFontSize := lpptFont.y;
- xWidthUI := sImeL.xCompWi;
- yHeightUI := sImeL.yCompHi;
- xBorder := sImeL.cxCompBorder;
- yBorder := sImeL.cyCompBorder;
- if (fFlags and NEAR_CARET_FIRST_TIME) <> 0 then
- begin
- lpptNearCaret.x := lpptCaret.x +
- lFontSize * ncUIEsc[uEsc].iLogFontFacX +
- sImeG.iPara * ncUIEsc[uEsc].iParaFacX +
- sImeG.iPerp * ncUIEsc[uEsc].iPerpFacX;
- if (ptInputEsc[uEsc].x >= 0) then
- Inc(lpptNearCaret.x, xBorder * 2)
- else
- Dec(lpptNearCaret.x, xWidthUI - xBorder * 2);
- lpptNearCaret.y := lpptCaret.y +
- lFontSize * ncUIEsc[uEsc].iLogFontFacY +
- sImeG.iPara * ncUIEsc[uEsc].iParaFacY +
- sImeG.iPerp * ncUIEsc[uEsc].iPerpFacY;
- if (ptInputEsc[uEsc].y >= 0) then
- Inc(lpptNearCaret.y, yBorder * 2)
- else
- Dec(lpptNearCaret.y, yHeightUI - yBorder * 2);
- end else
- begin
- lpptNearCaret.x := lpptCaret.x +
- lFontSize * ncAltUIEsc[uEsc].iLogFontFacX +
- sImeG.iPara * ncAltUIEsc[uEsc].iParaFacX +
- sImeG.iPerp * ncAltUIEsc[uEsc].iPerpFacX;
- if (ptAltInputEsc[uEsc].x >= 0) then
- Inc(lpptNearCaret.x, xBorder * 2)
- else
- Dec(lpptNearCaret.x, xWidthUI - xBorder * 2);
- lpptNearCaret.y := lpptCaret.y +
- lFontSize * ncAltUIEsc[uEsc].iLogFontFacY +
- sImeG.iPara * ncAltUIEsc[uEsc].iParaFacY +
- sImeG.iPerp * ncAltUIEsc[uEsc].iPerpFacY;
- if (ptAltInputEsc[uEsc].y >= 0) then
- Inc(lpptNearCaret.y, yBorder * 2)
- else
- Dec(lpptNearCaret.y, yHeightUI - yBorder * 2);
- end;
- if (lpptNearCaret.x < sImeG.rcWorkArea.Left) then
- begin
- lpptNearCaret.x := sImeG.rcWorkArea.Left;
- end else
- if (lpptNearCaret.x + xWidthUI > sImeG.rcWorkArea.Right) then
- begin
- lpptNearCaret.x := sImeG.rcWorkArea.Right - xWidthUI;
- end;
- if (lpptNearCaret.y < sImeG.rcWorkArea.Top) then
- begin
- lpptNearCaret.y := sImeG.rcWorkArea.Top
- end else
- if (lpptNearCaret.y + yHeightUI > sImeG.rcWorkArea.Bottom) then
- begin
- lpptNearCaret.y := sImeG.rcWorkArea.Bottom - yHeightUI;
- end;
- end;
- // IME adjust position according to composition form
- function AdjustCompPosition(lpIMC: PInputContext; lpptOrg: PPoint; lpptNew: PPoint): Bool;
- var
- ptNearCaret, ptOldNearCaret, ptFont: TPoint;
- uEsc, uRot, uTmp: uInt;
- rcUIRect, rcInputRect, rcInterRect: TRect;
- begin
- Result := False;
- if (lpIMC = nil) then Exit;
- // we need to adjust according to font attribute
- if (lpIMC.lfFont.A.lfWidth > 0) then
- ptFont.x := lpIMC.lfFont.A.lfWidth * 2
- else
- if (lpIMC.lfFont.A.lfWidth < 0) then
- ptFont.x := - lpIMC.lfFont.A.lfWidth * 2
- else
- if (lpIMC.lfFont.A.lfHeight > 0) then
- ptFont.x := lpIMC.lfFont.A.lfHeight
- else
- if (lpIMC.lfFont.A.lfHeight < 0) then
- ptFont.x := - lpIMC.lfFont.A.lfHeight
- else
- ptFont.x := sImeL.yCompHi;
- if (lpIMC.lfFont.A.lfHeight > 0) then
- ptFont.y := lpIMC.lfFont.A.lfHeight
- else
- if (lpIMC.lfFont.A.lfHeight < 0) then
- ptFont.y := -lpIMC.lfFont.A.lfHeight
- else
- ptFont.y := ptFont.x;
- // if the input char is too big, we don't need to consider so much
- if (ptFont.x > sImeL.yCompHi * 8) then ptFont.x := sImeL.yCompHi * 8;
- if (ptFont.y > sImeL.yCompHi * 8) then ptFont.y := sImeL.yCompHi * 8;
- if (ptFont.x < sImeG.xChiCharWi) then ptFont.x := sImeG.xChiCharWi;
- if (ptFont.y < sImeG.yChiCharHi) then ptFont.y := sImeG.yChiCharHi;
- // -450 to 450 index 0
- // 450 to 1350 index 1
- // 1350 to 2250 index 2
- // 2250 to 3150 index 3
- uEsc := (lpIMC.lfFont.A.lfEscapement + 450) div 900 mod 4;
- uRot := (lpIMC.lfFont.A.lfOrientation + 450) div 900 mod 4;
- // decide the input rectangle
- rcInputRect.Left := lpptNew.x;
- rcInputRect.Top := lpptNew.y;
- // build up an input rectangle from escapemment
- rcInputRect.Right := rcInputRect.Left + ptFont.x * ptInputEsc[uEsc].x;
- rcInputRect.Bottom := rcInputRect.Top + ptFont.y * ptInputEsc[uEsc].y;
- // be a normal rectangle, not a negative rectangle
- if (rcInputRect.Left > rcInputRect.Right) then
- begin
- uTmp := rcInputRect.Left;
- rcInputRect.Left := rcInputRect.Right;
- rcInputRect.Right := uTmp;
- end;
- if (rcInputRect.Top > rcInputRect.Bottom) then
- begin
- uTmp := rcInputRect.Top;
- rcInputRect.Top := rcInputRect.Bottom;
- rcInputRect.Bottom := uTmp;
- end;
- GetNearCaretPosition(@ptFont, uEsc, uRot, lpptNew, @ptNearCaret, NEAR_CARET_FIRST_TIME);
- // 1st, use the adjust point build up the new suggest UI rectangle (composition window)
- rcUIRect.Left := ptNearCaret.x;
- rcUIRect.Top := ptNearCaret.y;
- rcUIRect.Right := rcUIRect.Left + sImeL.xCompWi;
- rcUIRect.Bottom := rcUIRect.Top + sImeL.yCompHi;
- ptOldNearCaret := ptNearCaret;
- // OK, no intersect between the near caret position and input char
- if IntersectRect(rcInterRect, rcUIRect, rcInputRect) then
- begin
- end else
- if FitInLazyOperation(lpptOrg, @ptNearCaret, @rcInputRect, uEsc) then
- begin
- Result := False; // happy ending!!!, don't change position
- Exit;
- end else
- begin
- lpptOrg^ := ptNearCaret;
- Result := True; // happy ending!!
- Exit;
- end;
- // unhappy case
- GetNearCaretPosition(@ptFont, uEsc, uRot, lpptNew, @ptNearCaret, 0);
- // build up the new suggest UI rectangle (composition window)
- rcUIRect.Left := ptNearCaret.x;
- rcUIRect.Top := ptNearCaret.y;
- rcUIRect.Right := rcUIRect.Left + sImeL.xCompWi;
- rcUIRect.Bottom := rcUIRect.Top + sImeL.yCompHi;
- // OK, no intersect between the adjust position and input char
- if IntersectRect(rcInterRect, rcUIRect, rcInputRect) then
- begin
- end else
- if FitInLazyOperation(lpptOrg, @ptNearCaret, @rcInputRect, uEsc) then
- begin
- Result := False;
- Exit;
- end else
- begin
- lpptOrg^ := ptNearCaret;
- Result := True;
- Exit;
- end;
- lpptOrg^ := ptOldNearCaret;
- Result := True;
- end;
- // 设置Composition窗口位置
- procedure SetCompPosition(hCompWnd: hWnd; _hIMC: hIMC; lpIMC: PInputContext);
- var
- ptWnd, ptSTWPos, ptNew: TPoint;
- hCandWnd: hWnd;
- fChange: Bool; // = FALSE
- Comp_CandWndLen: Integer;
- begin
- fChange := False;
- // Composition窗口当前位置
- ptWnd.x := 0;
- ptWnd.y := 0;
- ClientToScreen(hCompWnd, ptWnd);
- Dec(ptWnd.x, sImeL.cxCompBorder);
- Dec(ptWnd.y, sImeL.cyCompBorder);
- // 光标跟随 = False
- if (sImeG.IC_Trace = 0) then
- begin
- ImmGetStatusWindowPos(_hIMC, @ptSTWPos);
- // reset status window for LINE_UI(FIX_UI)
- if (uStartComp <> 0) then
- begin
- Comp_CandWndLen := 0;
- Inc(Comp_CandWndLen, sImeL.xCompWi + UI_MARGIN);
- if (uOpenCand <> 0) then Inc(Comp_CandWndLen, sImeG.xCandWi + UI_MARGIN);
- if (ptSTWPos.x + sImeG.xStatusWi + Comp_CandWndLen > sImeG.rcWorkArea.Right) then
- ptSTWPos.x := sImeG.rcWorkArea.Right - sImeG.xStatusWi - Comp_CandWndLen;
- SetWindowPos(GetStatusWnd(GetWindow(hCompWnd, GW_OWNER)), 0, ptSTWPos.x,
- ptSTWPos.y, 0, 0, SWP_NOACTIVATE or SWP_NOCOPYBITS or SWP_NOSIZE or SWP_NOZORDER);
- ImmSetStatusWindowPos(_hIMC, PPoint(@ptSTWPos));
- end;
- ptWnd.x := ptSTWPos.x + sImeG.xStatusWi + UI_MARGIN;
- ptWnd.y := ptSTWPos.y;
- lpIMC.cfCompForm.ptCurrentPos := ptWnd;
- ScreenToClient(lpIMC.hWnd, lpIMC.cfCompForm.ptCurrentPos);
- fChange := True;
- end else
- if ((lpIMC.cfCompForm.dwStyle and CFS_FORCE_POSITION) <> 0) then
- begin
- ptNew.x := lpIMC.cfCompForm.ptCurrentPos.x;
- ptNew.y := lpIMC.cfCompForm.ptCurrentPos.y;
- ClientToScreen(lpIMC.hWnd, ptNew);
- if (ptWnd.x <> ptNew.x) then
- begin
- ptWnd.x := ptNew.x;
- fChange := True;
- end;
- if (ptWnd.y <> ptNew.y) then
- begin
- ptWnd.y := ptNew.y;
- fChange := True;
- end;
- if (fChange) then
- begin
- Dec(ptWnd.x, sImeL.cxCompBorder);
- Dec(ptWnd.y, sImeL.cyCompBorder);
- end;
- end else
- if (lpIMC.cfCompForm.dwStyle <> CFS_DEFAULT) then
- begin
- ptNew.x := lpIMC.cfCompForm.ptCurrentPos.x;
- ptNew.y := lpIMC.cfCompForm.ptCurrentPos.y;
- ClientToScreen(lpIMC.hWnd, ptNew);
- fChange := AdjustCompPosition(lpIMC, @ptWnd, @ptNew);
- end else
- begin
- ImmGetStatusWindowPos(_hIMC, @ptSTWPos);
- ptNew.x := ptSTWPos.x + sImeG.xStatusWi + UI_MARGIN;
- if (ptNew.x + sImeL.xCompWi + UI_MARGIN + sImeG.xCandWi >= sImeG.rcWorkArea.Right) then
- begin
- ptNew.x := ptSTWPos.x - sImeL.xCompWi - UI_MARGIN;
- end;
- ptNew.y := ptSTWPos.y;
- if (ptWnd.x <> ptNew.x) then
- begin
- ptWnd.x := ptNew.x;
- fChange := True;
- end;
- if (ptWnd.y <> ptNew.y) then
- begin
- ptWnd.y := ptNew.y;
- fChange := True;
- end;
- if (fChange) then
- begin
- lpIMC.cfCompForm.ptCurrentPos := ptNew;
- ScreenToClient(lpIMC.hWnd, lpIMC.cfCompForm.ptCurrentPos);
- end;
- end;
- if (fChange = False) then Exit; // 没有变化
- SetWindowPos(hCompWnd, 0, ptWnd.x, ptWnd.y, 0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER);
- // 调整Candidate窗口位置 ..
- hCandWnd := GetCandWnd(GetWindow(hCompWnd, GW_OWNER));
- if IsWindow(hCandWnd) then Exit;
- CalcCandPos(_hIMC, GetWindow(hCompWnd, GW_OWNER), @ptWnd);
- ScreenToClient(lpIMC.hWnd, ptWnd);
- lpIMC.cfCandForm[0].dwStyle := CFS_CANDIDATEPOS;
- lpIMC.cfCandForm[0].ptCurrentPos := ptWnd;
- if (IsWindowVisible(hCandWnd) = False) then Exit;
- PostMessage(hCandWnd, WM_IME_NOTIFY, IMN_SETCANDIDATEPOS, 1);
- end;
- // IMN_SETCOMPOSITIONWINDOW处理
- procedure SetCompWindow(hCompWnd: hWnd);
- var
- _hIMC: hIMC;
- lpIMC: PInputContext;
- hUIWnd: hWnd;
- begin
- hUIWnd := GetWindow(hCompWnd, GW_OWNER);
- if (IsWindow(hUIWnd) = False) then Exit;
- _hIMC := GetWindowLong(hUIWnd, IMMGWLP_IMC);
- if (_hIMC = 0) then Exit;
- lpIMC := ImmLockIMC(_hIMC);
- if (lpIMC = nil) then Exit;
- SetCompPosition(hCompWnd, _hIMC, lpIMC);
- ImmUnlockIMC(_hIMC);
- end;
- // the default comp position need to near the caret
- procedure MoveDefaultCompPosition(hUIWnd: hWnd);
- var
- _hIMC: hIMC;
- lpIMC: PInputContext;
- hCompWnd: hWnd;
- begin
- hCompWnd := GetCompWnd(hUIWnd);
- if (IsWindow(hCompWnd) = False) then Exit;
- _hIMC := GetWindowLong(hUIWnd, IMMGWLP_IMC);
- if (_hIMC = 0) then Exit;
- lpIMC := ImmLockIMC(_hIMC);
- if (lpIMC = nil) then Exit;
- if ((lpIMC.cfCompForm.dwStyle and CFS_FORCE_POSITION) = 0) then
- begin
- SetCompPosition(hCompWnd, _hIMC, lpIMC);
- end;
- ImmUnlockIMC(_hIMC);
- end;
- // 显示隐藏Composition窗口
- procedure ShowComp(hUIWnd: hWnd; nShowCompCmd: Integer);
- var
- hUIPrivate: HGlobal;
- lpUIPrivate: PUIPriv;
- begin
- hUIPrivate := GetWindowLong(hUIWnd, IMMGWLP_PRIVATE);
- if (hUIPrivate = 0) then Exit;
- lpUIPrivate := GlobalLock(hUIPrivate);
- if (lpUIPrivate = nil) then Exit;
- if (lpUIPrivate.nShowCompCmd = nShowCompCmd) then Exit; // **
- if (nShowCompCmd = SW_HIDE) then
- lpUIPrivate.fdwSetContext := lpUIPrivate.fdwSetContext and (not ISC_HIDE_COMP_WINDOW);
- if IsWindow(lpUIPrivate.hCompWnd) then
- begin
- if (nShowCompCmd = SW_HIDE) then uStartComp := 0 else uStartComp := 1;
- ShowWindow(lpUIPrivate.hCompWnd, nShowCompCmd);
- lpUIPrivate.nShowCompCmd := nShowCompCmd;
- end;
- GlobalUnlock(hUIPrivate);
- end;
- // "打开"Composition窗口
- procedure StartComp(hUIWnd: hWnd);
- var
- _hIMC: hIMC;
- hUIPrivate: HGlobal;
- lpIMC: PInputContext;
- lpUIPrivate: PUIPriv;
- begin
- _hIMC := GetWindowLong(hUIWnd, IMMGWLP_IMC);
- if (_hIMC = 0) then Exit;
- hUIPrivate := GetWindowLong(hUIWnd, IMMGWLP_PRIVATE);
- if (hUIPrivate = 0) then Exit;
- lpIMC := ImmLockIMC(_hIMC);
- if (lpIMC = nil) then Exit;
- lpUIPrivate := GlobalLock(hUIPrivate);
- if (lpUIPrivate = nil) then // can not draw composition window
- begin
- ImmUnlockIMC(_hIMC);
- Exit;
- end;
- lpUIPrivate.fdwSetContext := lpUIPrivate.fdwSetContext or ISC_SHOWUICOMPOSITIONWINDOW;
- if (IsWindow(lpUIPrivate.hCompWnd) = False) then // 窗口不存在则建立
- begin
- lpUIPrivate.hCompWnd := CreateWindowEx(WS_EX_WINDOWEDGE or WS_EX_DLGMODALFRAME, szCompClassName,
- nil, WS_POPUP or WS_DISABLED, 0, 0, sImeL.xCompWi, sImeL.yCompHi, hUIWnd, 0, HInstance, nil);
- SetWindowLong(lpUIPrivate.hCompWnd, UI_MOVE_OFFSET, WINDOW_NOT_DRAG);
- SetWindowLong(lpUIPrivate.hCompWnd, UI_MOVE_XY, sImeL.nMaxKey);
- end;
- uStartComp := 1;
- // try to set the position of composition UI window near the caret
- SetCompPosition(lpUIPrivate.hCompWnd, _hIMC, lpIMC);
- ImmUnlockIMC(_hIMC);
- ShowComp(hUIWnd, SW_SHOWNOACTIVATE);
- GlobalUnlock(hUIPrivate);
- end;
- // "关闭"Composition窗口
- procedure EndComp(hUIWnd: hWnd);
- begin
- ShowComp(hUIWnd, SW_HIDE);
- end;
- // WM_DESTROY消息处理
- procedure DestroyCompWindow(hCompWnd: hWnd);
- var
- hUIPrivate: HGlobal;
- lpUIPrivate: PUIPriv;
- begin
- if (GetWindowLong(hCompWnd, UI_MOVE_OFFSET) <> WINDOW_NOT_DRAG) then // undo the drag border
- DrawDragBorder(hCompWnd, GetWindowLong(hCompWnd, UI_MOVE_XY), GetWindowLong(hCompWnd, UI_MOVE_OFFSET));
- hUIPrivate := GetWindowLong(GetWindow(hCompWnd, GW_OWNER), IMMGWLP_PRIVATE);
- if (hUIPrivate = 0) then Exit;
- lpUIPrivate := GlobalLock(hUIPrivate);
- if (lpUIPrivate = nil) then Exit;
- lpUIPrivate.nShowCompCmd := SW_HIDE;
- lpUIPrivate.hCompWnd := 0;
- GlobalUnlock(hUIPrivate);
- end;
- // WM_SETCURSOR消息处理
- procedure CompSetCursor(hCompWnd: hWnd; lParam: LParam);
- var
- ptCursor: TPoint;
- rcWnd: TRect;
- begin
- SetCursor(LoadCursor(0, IDC_SIZEALL));
- if (GetWindowLong(hCompWnd, UI_MOVE_OFFSET) <> WINDOW_NOT_DRAG) then Exit;
- if (HiWord(lParam) <> WM_LBUTTONDOWN) then Exit;
- // start dragging ..
- SystemParametersInfo(SPI_GETWORKAREA, 0, @sImeG.rcWorkArea, 0);
- SetCapture(hCompWnd);
- GetCursorPos(ptCursor);
- SetWindowLong(hCompWnd, UI_MOVE_XY, MakeLong(ptCursor.x, ptCursor.y));
- GetWindowRect(hCompWnd, rcWnd);
- SetWindowLong(hCompWnd, UI_MOVE_OFFSET, MakeLong(ptCursor.x - rcWnd.Left, ptCursor.y - rcWnd.Top));
- DrawDragBorder(hCompWnd, MakeLong(ptCursor.x, ptCursor.y), GetWindowLong(hCompWnd, UI_MOVE_OFFSET));
- end;
- // WM_LBUTTONUP消息处理
- function CompButtonUp(hCompWnd: hWnd): Bool;
- var
- lTmpCursor, lTmpOffset: DWord;
- pt: TPoint;
- hUIWnd: hWnd;
- _hIMC: hIMC;
- lpIMC: PInputContext;
- begin
- Result := False;
- if (GetWindowLong(hCompWnd, UI_MOVE_OFFSET) = WINDOW_NOT_DRAG) then Exit; // 非拖拽状态
- lTmpCursor := GetWindowLong(hCompWnd, UI_MOVE_XY);
- lTmpOffset := GetWindowLong(hCompWnd, UI_MOVE_OFFSET);
- // calculate the org by the offset
- pt.x := PSmallPoint(@lTmpCursor).x - PSmallPoint(@lTmpOffset).x;
- pt.y := PSmallPoint(@lTmpCursor).y - PSmallPoint(@lTmpOffset).y;
- DrawDragBorder(hCompWnd, lTmpCursor, lTmpOffset);
- SetWindowLong(hCompWnd, UI_MOVE_OFFSET, WINDOW_NOT_DRAG);
- SetWindowLong(hCompWnd, UI_MOVE_XY, sImeL.nMaxKey);
- ReleaseCapture();
- hUIWnd := GetWindow(hCompWnd, GW_OWNER);
- if (IsWindow(hUIWnd) = False) then Exit;
- _hIMC := GetWindowLong(hUIWnd, IMMGWLP_IMC);
- if (_hIMC = 0) then Exit;
- lpIMC := ImmLockIMC(_hIMC);
- if (lpIMC = nil) then Exit;
- if (pt.x < sImeG.rcWorkArea.Left) then
- begin
- pt.x := sImeG.rcWorkArea.Left;
- end else
- if (pt.x + sImeL.xCompWi > sImeG.rcWorkArea.Right) then
- begin
- pt.x := sImeG.rcWorkArea.Right - sImeL.xCompWi;
- end;
- if (pt.y < sImeG.rcWorkArea.Top) then
- begin
- pt.y := sImeG.rcWorkArea.Top;
- end else
- if (pt.y + sImeL.yCompHi > sImeG.rcWorkArea.Bottom) then
- begin
- pt.y := sImeG.rcWorkArea.Bottom - sImeL.yCompHi;
- end;
- lpIMC.cfCompForm.dwStyle := CFS_FORCE_POSITION;
- lpIMC.cfCompForm.ptCurrentPos.x := pt.x + sImeL.cxCompBorder;
- lpIMC.cfCompForm.ptCurrentPos.y := pt.y + sImeL.cyCompBorder;
- ScreenToClient(lpIMC.hWnd, lpIMC.cfCompForm.ptCurrentPos);
- ImmUnlockIMC(_hIMC);
- // set composition window to the new poosition
- PostMessage(hCompWnd, WM_IME_NOTIFY, IMN_SETCOMPOSITIONWINDOW, 0);
- Result := True;
- end;
- // 绘制Composition窗口
- procedure PaintCompWindow(hUIWnd: hWnd; hCompWnd: hWnd; _hDC: hDC);
- var
- _hIMC: hIMC;
- lpIMC: PInputContext;
- hOldFont: HGdiObj;
- lpCompStr: PCompositionString;
- lpGuideLine: PGuideLine;
- fShowString: DWord;
- lfFont: TLogFont;
- rcWnd: TRect;
- begin
- _hIMC := GetWindowLong(hUIWnd, IMMGWLP_IMC);
- if (_hIMC = 0) then Exit;
- lpIMC := ImmLockIMC(_hIMC);
- if (lpIMC = nil) then Exit;
- if (sImeG.fDiffSysCharSet) then
- begin
- hOldFont := GetCurrentObject(_hDC, OBJ_FONT);
- ZeroMemory(@lfFont, SizeOf(lfFont));
- lfFont.lfHeight := - MulDiv(12, GetDeviceCaps(_hDC, LOGPIXELSY), 72);
- lfFont.lfCharSet := NATIVE_CHARSET;
- lStrCpy(lfFont.lfFaceName, '宋体');
- SelectObject(_hDC, CreateFontIndirect(lfFont));
- end else
- hOldFont := 0;
- lpCompStr := ImmLockIMCC(lpIMC.hCompStr);
- if (lpCompStr = nil) then Exit;
- lpGuideLine := ImmLockIMCC(lpIMC.hGuideLine);
- if (lpGuideLine = nil) then Exit;
- // 凹陷边框
- GetClientRect(hCompWnd, rcWnd);
- DrawConcaveRect(_hDC, rcWnd.Left, rcWnd.Top, rcWnd.Right - 1, rcWnd.Bottom - 1);
- SetBkColor(_hDC, RGB($C0, $C0, $C0));
- fShowString := 0;
- if (lpGuideLine = nil) then
- begin
- end else
- if (lpGuideLine.dwLevel = GL_LEVEL_NOGUIDELINE) then
- begin
- end else
- if (lpGuideLine.dwStrLen = 0) then
- begin
- if (lpGuideLine.dwLevel = GL_LEVEL_ERROR) then
- begin
- fShowString := fShowString or IME_STR_ERROR;
- end;
- end else
- begin
- // if there is information string, we will show the information string
- if (lpGuideLine.dwLevel = GL_LEVEL_ERROR) then
- begin
- SetTextColor(_hDC, RGB($FF, 0, 0)); // red text for error
- SetBkColor(_hDC, RGB($80, $80, $80)); // light gray background for error
- end;
- ExtTextOut(_hDC, sImeL.rcCompText.Left, sImeL.rcCompText.Top, ETO_OPAQUE, @sImeL.rcCompText,
- PChar(DWord(lpGuideLine) + lpGuideLine.dwStrOffset), lpGuideLine.dwStrLen, nil);
- fShowString := fShowString or IME_STR_SHOWED; // 已显示
- end;
- if (fShowString and IME_STR_SHOWED) <> 0 then
- begin
- // already show it, don't need to show
- end else
- if (lpCompStr.dwCompStrLen > 0) then
- begin
- ExtTextOut(_hDC, sImeL.rcCompText.Left, sImeL.rcCompText.Top, ETO_OPAQUE, @sImeL.rcCompText, nil, 0, nil);
- DrawText(_hDC, PChar(DWord(lpCompStr) + lpCompStr.dwCompStrOffset),
- lpCompStr.dwCompStrLen, sImeL.rcCompText, DT_LEFT or DT_VCENTER or DT_SINGLELINE);
- if (fShowString and IME_STR_ERROR) <> 0 then
- begin
- // red text for error
- SetTextColor(_hDC, RGB($FF, 0, 0));
- // light gray background for error
- SetBkColor(_hDC, RGB($80, $80, $80));
- ExtTextOut(_hDC, sImeL.rcCompText.Left + Integer(lpCompStr.dwCursorPos) * sImeG.xChiCharWi div 2,
- sImeL.rcCompText.Top, ETO_CLIPPED, @sImeL.rcCompText,
- PChar(DWord(lpCompStr) + lpCompStr.dwCompStrOffset + lpCompStr.dwCursorPos),
- lpCompStr.dwCompStrLen - lpCompStr.dwCursorPos, nil);
- end else
- if (lpCompStr.dwCursorPos < lpCompStr.dwCompStrLen) then
- begin
- // light gray background for cursor start
- SetBkColor(_hDC, RGB($80, $80, $80));
- ExtTextOut(_hDC, sImeL.rcCompText.Left + Integer(lpCompStr.dwCursorPos) * sImeG.xChiCharWi div 2,
- sImeL.rcCompText.Top, ETO_CLIPPED, @sImeL.rcCompText,
- PChar(DWord(lpCompStr) + lpCompStr.dwCompStrOffset + lpCompStr.dwCursorPos),
- lpCompStr.dwCompStrLen - lpCompStr.dwCursorPos, nil);
- end else
- begin
- end;
- end else
- begin
- ExtTextOut(_hDC, sImeL.rcCompText.Left, sImeL.rcCompText.Top, ETO_OPAQUE, @sImeL.rcCompText, nil, 0, nil);
- end;
- if (sImeG.fDiffSysCharSet) then DeleteObject(SelectObject(_hDC, hOldFont));
- ImmUnlockIMCC(lpIMC.hGuideLine);
- ImmUnlockIMCC(lpIMC.hCompStr);
- ImmUnlockIMC(_hIMC);
- end;
- // Composition窗口回调
- function CompWndProc(hCompWnd: hWnd; uMsg: uInt; wParam: WParam; lParam: LParam): LResult; stdcall;
- var
- ptCursor: TPoint;
- _hDC: hDC;
- ps: TPaintStruct;
- begin
- Result := 0;
- case (uMsg) of
- WM_DESTROY:
- DestroyCompWindow(hCompWnd);
- WM_SETCURSOR:
- CompSetCursor(hCompWnd, lParam);
- WM_MOUSEMOVE:
- if (GetWindowLong(hCompWnd, UI_MOVE_OFFSET) <> WINDOW_NOT_DRAG) then // 拖拽中
- begin
- DrawDragBorder(hCompWnd, GetWindowLong(hCompWnd, UI_MOVE_XY), GetWindowLong(hCompWnd, UI_MOVE_OFFSET));
- GetCursorPos(ptCursor);
- SetWindowLong(hCompWnd, UI_MOVE_XY, MakeLong(ptCursor.x, ptCursor.y));
- DrawDragBorder(hCompWnd, MakeLong(ptCursor.x, ptCursor.y), GetWindowLong(hCompWnd, UI_MOVE_OFFSET));
- end else
- Result := DefWindowProc(hCompWnd, uMsg, wParam, lParam);
- WM_LBUTTONUP:
- if (CompButtonUp(hCompWnd) = False) then Result := DefWindowProc(hCompWnd, uMsg, wParam, lParam);
- WM_IME_NOTIFY:
- if (wParam = IMN_SETCOMPOSITIONWINDOW) then SetCompWindow(hCompWnd);
- WM_PAINT:
- begin
- _hDC := BeginPaint(hCompWnd, ps);
- PaintCompWindow(GetWindow(hCompWnd, GW_OWNER), hCompWnd, _hDC);
- EndPaint(hCompWnd, ps);
- end;
- WM_MOUSEACTIVATE:
- Result := MA_NOACTIVATE;
- else
- Result := DefWindowProc(hCompWnd, uMsg, wParam, lParam);
- end;
- end;
- end.