mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-07 16:58:48 +02:00
1300 lines
38 KiB
PHP
1300 lines
38 KiB
PHP
{%MainUnit CustomDrawnInt.pas}
|
|
{
|
|
*****************************************************************************
|
|
This file is part of the Lazarus Component Library (LCL)
|
|
|
|
See the file COPYING.modifiedLGPL.txt, included in this distribution,
|
|
for details about the license.
|
|
*****************************************************************************
|
|
}
|
|
type
|
|
TWinControlAccess = class(TWinControl);
|
|
|
|
{*************************************************************}
|
|
{ callback routines }
|
|
{*************************************************************}
|
|
|
|
function WndClassName(Wnd: HWND): WideString; inline;
|
|
var
|
|
winClassName: array[0..19] of WideChar;
|
|
begin
|
|
GetClassName(Wnd, @winClassName, 20);
|
|
Result := winClassName;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: CallDefaultWindowProc
|
|
Params: Window - The window that receives a message
|
|
Msg - The message received
|
|
WParam - Word parameter
|
|
LParam - Long-integer parameter
|
|
Returns: 0 if Msg is handled; non-zero long-integer result otherwise
|
|
|
|
Passes message on to 'default' handler. This can be a control specific window
|
|
procedure or the default window procedure.
|
|
------------------------------------------------------------------------------}
|
|
function CallDefaultWindowProc(Window: HWnd; Msg: UInt; WParam: Windows.WParam;
|
|
LParam: Windows.LParam): LResult;
|
|
var
|
|
PrevWndProc: Windows.WNDPROC;
|
|
setComboWindow: boolean;
|
|
WindowInfo: TWindowInfo;
|
|
begin
|
|
{$ifdef MSG_DEBUG}
|
|
DebugLn('Trace:CallDefaultWindowProc - Start');
|
|
{$endif}
|
|
|
|
WindowInfo := GetWindowInfo(Window);
|
|
PrevWndProc := WindowInfo.DefWndProc;
|
|
|
|
if (PrevWndProc = nil) or (PrevWndProc = @WindowProc) // <- prevent recursion
|
|
then
|
|
begin
|
|
{$ifdef MSG_DEBUG}
|
|
DebugLn('Trace:CallDefaultWindowProc - A');
|
|
{$endif}
|
|
Result := Windows.DefWindowProcW(Window, Msg, WParam, LParam)
|
|
end
|
|
else begin
|
|
{$ifdef MSG_DEBUG}
|
|
DebugLn('Trace:CallDefaultWindowProc - B ' + IntToHex(PtrInt(PrevWndProc), 8));
|
|
{$endif}
|
|
Result := Windows.CallWindowProc(PrevWndProc, Window, Msg, WParam, LParam);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
DisabledForms: TList = nil;
|
|
|
|
function CheckMouseMovement: boolean;
|
|
// returns true if mouse did not move between lmousebutton down
|
|
var
|
|
lCursorPos: TPoint;
|
|
moveX, moveY: integer;
|
|
begin
|
|
Result := true;
|
|
{ GetCursorPos(lCursorPos);
|
|
moveX := lCursorPos.X - MouseDownPos.X;
|
|
moveY := lCursorPos.Y - MouseDownPos.Y;
|
|
Result := (-3 <= moveX) and (moveX <= 3) and (-3 <= moveY) and (moveY <= 3);}
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: WindowProc
|
|
Params: Window - The window that receives a message
|
|
Msg - The message received
|
|
WParam - Word parameter
|
|
LParam - Long-integer parameter
|
|
Returns: 0 if Msg is handled; non-zero long-integer result otherwise
|
|
|
|
Handles the messages sent to the specified window, in parameter Window, by
|
|
Windows or other applications
|
|
------------------------------------------------------------------------------}
|
|
function WindowProc(Window: HWnd; Msg: UInt; WParam: Windows.WParam;
|
|
LParam: Windows.LParam): LResult; {$if defined(win32) or defined(win64)}stdcall{$else}cdecl{$endif};
|
|
Var
|
|
LMessage: TLMessage;
|
|
PLMsg: PLMessage;
|
|
R: TRect;
|
|
P: TPoint;
|
|
NewLeft, NewTop, NewWidth, NewHeight: integer;
|
|
lWinControl, ChildWinControl: TWinControl;
|
|
TargetObject: TObject;
|
|
WinProcess: Boolean;
|
|
NotifyUserInput: Boolean;
|
|
WindowPlacement: TWINDOWPLACEMENT;
|
|
OverlayWindow: HWND;
|
|
TargetWindow: HWND;
|
|
WindowInfo: TWindowInfo;
|
|
Flags: dword;
|
|
WindowColor: Integer;
|
|
|
|
LMScroll: TLMScroll; // used by WM_HSCROLL
|
|
LMKey: TLMKey; // used by WM_KEYDOWN WM_KEYUP
|
|
LMChar: TLMChar; // used by WM_CHAR
|
|
LMMouse: TLMMouse; // used by WM_LBUTTONDBLCLK
|
|
LMContextMenu: TLMContextMenu;
|
|
LMMouseMove: TLMMouseMove; // used by WM_MOUSEMOVE
|
|
LMMouseEvent: TLMMouseEvent; // used by WM_MOUSEWHEEL
|
|
LMMove: TLMMove; // used by WM_MOVE
|
|
LMNotify: TLMNotify; // used by WM_NOTIFY
|
|
DrawListItemStruct: TDrawListItemStruct; //used by WM_DRAWITEM
|
|
CancelEndSession : Boolean;//use by WM_QUERYENDSESSION
|
|
|
|
OrgCharCode: word; // used in WM_CHAR handling
|
|
|
|
// Message information
|
|
XPos, YPos: Integer;
|
|
WParamShiftState: TShiftState;
|
|
MouseButton: TMouseButton;
|
|
UTF8Char: TUTF8Char;
|
|
|
|
NMHdr: PNMHdr absolute LParam; // used by WM_NOTIFY
|
|
TmpSize: TSize; // used by WM_MEASUREITEM
|
|
{$ifdef wince}
|
|
Info: SHRGINFO; // used by SHRecognizeGesture in WM_LBUTTONDOWN
|
|
{$endif}
|
|
|
|
// CustomDrawn specific
|
|
lEventReceiver: TWinControl;
|
|
lEventX: Integer = -1;
|
|
lEventY: Integer = -1;
|
|
|
|
function GetIsNativeControl(AWindow: HWND): Boolean;
|
|
begin
|
|
Result := False;//WndClassName(AWindow) <> ClsName;
|
|
end;
|
|
|
|
{ Differences with LCL-Win32:
|
|
|
|
* Here there are zero native controls
|
|
* Here nothing needs parent paint
|
|
* The double buffering from LCL-Win32 is not used, instead we have a different
|
|
architecture where double buffering is always on, it is impossible to turn it
|
|
off because all drawings are done to the temporary image first
|
|
}
|
|
procedure SendPaintMessage(ControlDC: HDC);
|
|
var
|
|
DC: HDC;
|
|
lBitmap, lMask: HBITMAP;
|
|
PaintRegion: HRGN;
|
|
PS : TPaintStruct;
|
|
PaintMsg: TLMPaint;
|
|
WindowOrg: Windows.POINT;
|
|
WindowWidth, WindowHeight: Integer;
|
|
DCIndex: integer;
|
|
parLeft, parTop: integer;
|
|
needParentPaint: boolean;
|
|
BufferWasSaved: Boolean;
|
|
lRawImage: TRawImage;
|
|
begin
|
|
if lWinControl = nil then exit;
|
|
|
|
{$IFDEF VerboseCDMessages}
|
|
DebugLn(Format('[SendPaintMessage]: Control:%s:%s', [lWinControl.Name, lWinControl.ClassName]));
|
|
{$ENDIF}
|
|
|
|
// create a paint message
|
|
needParentPaint := False;
|
|
|
|
LCLIntf.GetWindowSize(HWND(WindowInfo), WindowWidth, WindowHeight);
|
|
|
|
// Start the double buffering by checking if we need to increase the buffer
|
|
if (WindowInfo.BitmapWidth < WindowWidth) or (WindowInfo.BitmapHeight < WindowHeight) then
|
|
begin
|
|
// first release old objects
|
|
if WindowInfo.BitmapDC <> 0 then
|
|
begin
|
|
Windows.SelectObject(WindowInfo.BitmapDC, WindowInfo.DCBitmapOld);
|
|
Windows.DeleteObject(WindowInfo.BitmapDC);
|
|
end;
|
|
if WindowInfo.Bitmap <> 0 then Windows.DeleteObject(WindowInfo.Bitmap);
|
|
|
|
// And now create the new ones
|
|
DC := Windows.GetDC(0);
|
|
WindowInfo.BitmapDC := Windows.CreateCompatibleDC(0);
|
|
WindowInfo.BitmapWidth := WindowWidth;
|
|
WindowInfo.BitmapHeight := WindowHeight;
|
|
WindowInfo.Bitmap := Windows.CreateCompatibleBitmap(DC, WindowWidth, WindowHeight);
|
|
WindowInfo.DCBitmapOld := Windows.SelectObject(WindowInfo.BitmapDC, WindowInfo.Bitmap);
|
|
Windows.ReleaseDC(0, DC);
|
|
|
|
// Reset the image and canvas
|
|
WindowInfo.Canvas.Free;
|
|
WindowInfo.Canvas := nil;
|
|
WindowInfo.Image.Free;
|
|
WindowInfo.Image := nil;
|
|
end;
|
|
|
|
// Prepare the non-native Canvas if necessary
|
|
if (WindowInfo.Image = nil) then
|
|
begin
|
|
WinProc_RawImage_FromBitmap(lRawImage, WindowInfo.Bitmap, 0);
|
|
WindowInfo.Image := TLazIntfImage.Create(WindowWidth, WindowHeight);
|
|
WindowInfo.Image.SetRawImage(lRawImage);
|
|
end;
|
|
if (WindowInfo.Canvas = nil) then WindowInfo.Canvas := TLazCanvas.Create(WindowInfo.Image);
|
|
|
|
{$ifdef VerboseCDMessages}
|
|
DebugLn(Format('[SendPaintMessage] WindowInfo^.Canvas=%s', [dbghex(PtrInt(WindowInfo.Canvas))]));
|
|
{$endif}
|
|
|
|
// main processing
|
|
WinProcess := false;
|
|
try
|
|
if ControlDC = 0 then
|
|
begin
|
|
// ignore first erase background on themed control, paint will do everything
|
|
DC := Windows.BeginPaint(Window, @PS);
|
|
end else begin
|
|
DC := ControlDC;
|
|
PaintRegion := 0;
|
|
end;
|
|
|
|
// Draw the form
|
|
RenderForm(WindowInfo.Image, WindowInfo.Canvas, TCustomForm(lWinControl));
|
|
|
|
// Now convert the rawimage to a HBITMAP and draw it to the screen
|
|
WindowInfo.Image.GetRawImage(lRawImage);
|
|
WinProc_RawImage_CreateBitmaps(lRawImage, lBitmap, lMask, True);
|
|
Windows.SelectObject(WindowInfo.BitmapDC, lBitmap);
|
|
Windows.BitBlt(DC, 0, 0, WindowWidth, WindowHeight, WindowInfo.BitmapDC, 0, 0, SRCCOPY);
|
|
Windows.SelectObject(WindowInfo.BitmapDC, WindowInfo.Bitmap);
|
|
Windows.DeleteObject(lBitmap);
|
|
|
|
if ControlDC = 0 then
|
|
Windows.EndPaint(Window, @PS);
|
|
finally
|
|
end;
|
|
{$ifdef VerboseCDMessages}
|
|
DebugLn(':< [SendPaintMessage] Finish');
|
|
{$endif}
|
|
end;
|
|
|
|
procedure HandleSetCursor;
|
|
var
|
|
lControl: TControl;
|
|
BoundsOffset: TRect;
|
|
ACursor: TCursor;
|
|
begin
|
|
if (lWinControl <> nil) and not (csDesigning in lWinControl.ComponentState)
|
|
and (Lo(LParam) = HTCLIENT) then
|
|
begin
|
|
Windows.GetCursorPos(@(Windows.POINT(P)));
|
|
Windows.ScreenToClient(Window, @(Windows.POINT(P)));
|
|
if GetLCLClientBoundsOffset(lWinControl, BoundsOffset) then
|
|
begin
|
|
Dec(P.X, BoundsOffset.Left);
|
|
Dec(P.Y, BoundsOffset.Top);
|
|
end;
|
|
ACursor := Screen.RealCursor;
|
|
if ACursor = crDefault then
|
|
begin
|
|
// statictext controls do not get WM_SETCURSOR messages...
|
|
lControl := lWinControl.ControlAtPos(P, [capfOnlyClientAreas,
|
|
capfAllowWinControls, capfHasScrollOffset, capfRecursive]);
|
|
if lControl = nil then
|
|
lControl := lWinControl;
|
|
ACursor := lControl.Cursor;
|
|
end;
|
|
if ACursor <> crDefault then
|
|
begin
|
|
Windows.SetCursor(Screen.Cursors[ACursor]);
|
|
LMessage.Result := 1;
|
|
end;
|
|
end;
|
|
if LMessage.Result = 0 then
|
|
begin
|
|
LMessage.Msg := LM_SETCURSOR;
|
|
LMessage.WParam := WParam;
|
|
LMessage.LParam := LParam;
|
|
end;
|
|
WinProcess := false;
|
|
end;
|
|
|
|
procedure HandleSysCommand;
|
|
var
|
|
ParentForm: TCustomForm;
|
|
prevFocus: HWND;
|
|
begin
|
|
// forward keystroke to show window menu, if parent form has no menu
|
|
// if wparam contains SC_KEYMENU, lparam contains key pressed
|
|
// keymenu+space should always bring up system menu
|
|
case (WParam and $FFF0) of
|
|
SC_KEYMENU:
|
|
if (lWinControl <> nil) and (lParam <> VK_SPACE) then
|
|
begin
|
|
ParentForm := GetParentForm(lWinControl);
|
|
if (ParentForm <> nil) and (ParentForm.Menu = nil)
|
|
and (Application <> nil) and (Application.MainForm <> nil)
|
|
and (Application.MainForm <> ParentForm)
|
|
and Application.MainForm.HandleAllocated then
|
|
begin
|
|
targetWindow := Application.MainForm.Handle;
|
|
if IsWindowEnabled(targetWindow) and IsWindowVisible(targetWindow) then
|
|
begin
|
|
prevFocus := Windows.GetFocus;
|
|
Windows.SetFocus(targetWindow);
|
|
PLMsg^.Result := Windows.SendMessageW(targetWindow, WM_SYSCOMMAND, WParam, LParam);
|
|
Windows.SetFocus(prevFocus);
|
|
WinProcess := false;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//roozbeh : we do not have these in wince!
|
|
{ SC_MINIMIZE:
|
|
begin
|
|
|
|
if (Application <> nil) and (lWinControl <> nil)
|
|
and (Application.MainForm <> nil)
|
|
and (Application.MainForm = lWinControl) then
|
|
Window := TWinCEWidgetSet(WidgetSet).AppHandle;//redirection
|
|
|
|
if (Window = TWinCEWidgetSet(WidgetSet).AppHandle)
|
|
and (Application <> nil)
|
|
and (Application.MainForm<>nil) then
|
|
begin
|
|
Windows.SetWindowPos(Window, HWND_TOP,
|
|
Application.MainForm.Left, Application.MainForm.Top,
|
|
Application.MainForm.Width, 0, SWP_NOACTIVATE);
|
|
if Application.MainForm.HandleAllocated then
|
|
Windows.ShowWindow(Application.MainForm.Handle,SW_HIDE);
|
|
|
|
Application.IntfAppMinimize;
|
|
end;
|
|
end;}
|
|
|
|
{SC_RESTORE:
|
|
begin
|
|
|
|
if (Window = TWinCEWidgetSet(WidgetSet).AppHandle)
|
|
and (Application <> nil)
|
|
and (Application.MainForm<>nil)
|
|
and Application.MainForm.HandleAllocated then
|
|
begin
|
|
PLMsg^.Result := Windows.DefWindowProc(Window, WM_SYSCOMMAND, WParam, LParam);
|
|
Windows.ShowWindow(Application.MainForm.Handle,SW_SHOW);
|
|
if Windows.IsWindowEnabled(Application.MainForm.Handle)
|
|
then Windows.SetActiveWindow(Application.MainForm.Handle);
|
|
WinProcess := false;
|
|
|
|
Application.IntfAppRestore;
|
|
end;
|
|
end;}
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
//DebugLn('Trace:WindowProc - Start');
|
|
|
|
LMessage.Result := 0;
|
|
LMessage.Msg := LM_NULL;
|
|
PLMsg := @LMessage;
|
|
WinProcess := True;
|
|
NotifyUserInput := False;
|
|
|
|
{$ifdef VerboseCDMessages}
|
|
DebugLn(Format('WindowProc Window= %x FAppHandle=%x MSG=%s',
|
|
[Window, CDWidgetset.FAppHandle, WM_To_String(Msg)]));
|
|
{$endif}
|
|
|
|
//DebugLn('Trace:WindowProc - Getting Object with Callback Procedure');
|
|
WindowInfo := GetWindowInfo(Window);
|
|
lWinControl := WindowInfo.LCLForm;
|
|
|
|
{$ifdef VerboseCDMessages}
|
|
DebugLn('WindowProc lWinControl: ',DbgSName(lWinControl));
|
|
{$endif}
|
|
|
|
if (IgnoreNextCharWindow <> 0) and ((Msg = WM_CHAR) or (Msg = WM_SYSCHAR)) then
|
|
begin
|
|
if IgnoreNextCharWindow = Window then
|
|
begin
|
|
IgnoreNextCharWindow := 0;
|
|
Result := 1;
|
|
exit;
|
|
end;
|
|
IgnoreNextCharWindow := 0;
|
|
end;
|
|
|
|
{$ifdef MSG_DEBUG}
|
|
DebugLn('Trace:WindowProc - Case Msg of');
|
|
{$endif}
|
|
|
|
case Msg Of
|
|
WM_NULL:
|
|
begin
|
|
CheckSynchronize;
|
|
{TCDWidgetset(Widgetset).CheckPipeEvents;}
|
|
end;
|
|
WM_ACTIVATE:
|
|
begin
|
|
LMessage.Msg := LM_ACTIVATE;
|
|
end;
|
|
WM_CAPTURECHANGED:
|
|
begin
|
|
LMessage.Msg := LM_CAPTURECHANGED;
|
|
end;
|
|
WM_CHAR:
|
|
begin
|
|
UTF8Char := UTF8Encode(widestring(WideChar(WParam)));
|
|
CallbackKeyChar(WindowInfo, Word(Char(WideChar(WParam))), UTF8Char);
|
|
Result := 1;
|
|
Exit;
|
|
end;
|
|
WM_CLOSE:
|
|
begin
|
|
if (Window = TCDWidgetSet(WidgetSet).AppHandle) and
|
|
(Application.MainForm <> nil) then
|
|
begin
|
|
Windows.SendMessage(Application.MainForm.Handle, WM_CLOSE, 0, 0);
|
|
end else begin
|
|
LMessage.Msg := LM_CLOSEQUERY;
|
|
end;
|
|
// default is to destroy window, inhibit
|
|
WinProcess := false;
|
|
end;
|
|
{
|
|
WM_COMMAND
|
|
|
|
Parameters:
|
|
|
|
wNotifyCode = HIWORD(wParam);
|
|
wID = LOWORD(wParam);
|
|
hwndCtl = (HWND) lParam;
|
|
|
|
If wID is IDOK, then we have received a close message from the
|
|
"OK" button in the title of dialog windows.
|
|
}
|
|
WM_COMMAND:
|
|
begin
|
|
{ Handles the "OK" button in the title bar of dialogs }
|
|
if Lo(wParam) = IDOK then
|
|
begin
|
|
if (lWinControl is TCustomForm) and (fsModal in TCustomForm(lWinControl).FormState) then
|
|
TCustomForm(lWinControl).ModalResult := mrOK
|
|
else
|
|
SendMessage(Window, WM_CLOSE, 0, 0);
|
|
end;
|
|
(* else
|
|
begin
|
|
{ Handles other reasons for WM_COMMAND }
|
|
|
|
if Hi(WParam) < 2 then //1 for accelerator 0 for menu
|
|
begin
|
|
{$ifdef VerboseWinCEMenu}
|
|
DebugLn('[wincecallback] Hi(WParam) < 2');
|
|
{$endif}
|
|
TargetObject := GetMenuItemObject();
|
|
end
|
|
else // menuitem or shortcut
|
|
begin
|
|
TargetObject := nil;
|
|
end;
|
|
|
|
if TargetObject is TMenuItem then
|
|
begin
|
|
{$ifdef VerboseWinCEMenu}
|
|
DebugLn('[wincecallback] Sending menuitem Click');
|
|
{$endif}
|
|
|
|
LMessage.Msg := LM_ACTIVATE;
|
|
TargetObject.Dispatch(LMessage);
|
|
lWinControl := nil;
|
|
end
|
|
else
|
|
begin
|
|
lWinControl := GetWindowInfo(LParam)^.WinControl;
|
|
// buddy controls use 'awincontrol' to designate associated wincontrol
|
|
if lWinControl = nil then
|
|
lWinControl := GetWindowInfo(LParam)^.AWinControl;
|
|
end;
|
|
|
|
// no specific message found? try send a general msg
|
|
if (LMessage.Msg = LM_NULL) and (lWinControl <> nil) then
|
|
lWinControl.Perform(CN_COMMAND, WParam, LParam);
|
|
end;*)
|
|
end;
|
|
{
|
|
* Besides the fact that LCL does not respond to LM_CREATE, this code is
|
|
probably never reached anyway, as the callback is not set until after
|
|
window creation
|
|
|
|
WM_CREATE:
|
|
begin
|
|
//DebugLn('Trace:WindowProc - Got WM_CREATE');
|
|
LMessage.Msg := LM_CREATE;
|
|
end;
|
|
}
|
|
WM_CLEAR:
|
|
begin
|
|
LMessage.Msg := LM_CLEAR;
|
|
end;
|
|
WM_COPY:
|
|
begin
|
|
LMessage.Msg := LM_COPY;
|
|
end;
|
|
WM_CUT:
|
|
begin
|
|
LMessage.Msg := LM_CUT;
|
|
end;
|
|
WM_DESTROY:
|
|
begin
|
|
LMessage.Msg := LM_DESTROY;
|
|
end;
|
|
WM_DESTROYCLIPBOARD:
|
|
begin
|
|
if assigned(OnClipBoardRequest) then begin
|
|
// {$IFDEF VerboseWin32Clipbrd}
|
|
// debugln('WM_DESTROYCLIPBOARD');
|
|
// {$ENDIF}
|
|
OnClipBoardRequest(0, nil);
|
|
OnClipBoardRequest := nil;
|
|
LMessage.Result := 0;
|
|
end;
|
|
end;
|
|
WM_ENABLE:
|
|
begin
|
|
if WParam <> 0 then
|
|
LMessage.Msg := LM_SETEDITABLE;
|
|
if Window = TCDWidgetSet(WidgetSet).FAppHandle then
|
|
if WParam = 0 then
|
|
DisabledForms := Screen.DisableForms(nil, DisabledForms)
|
|
else
|
|
Screen.EnableForms(DisabledForms);
|
|
end;
|
|
WM_ENTERIDLE: Application.Idle(False);
|
|
WM_ERASEBKGND:
|
|
begin
|
|
{eraseBkgndCommand := TEraseBkgndCommand(EraseBkgndStack and EraseBkgndStackMask);
|
|
if eraseBkgndCommand = ecDoubleBufferNoRemove then
|
|
begin
|
|
end
|
|
else
|
|
if eraseBkgndCommand <> ecDiscardNoRemove then
|
|
EraseBkgndStack := EraseBkgndStack shr EraseBkgndStackShift;
|
|
if eraseBkgndCommand in [ecDiscard, ecDiscardNoRemove] then
|
|
begin
|
|
Result := 0;
|
|
exit;
|
|
end;
|
|
if not False or (eraseBkgndCommand = ecDoubleBufferNoRemove) then
|
|
begin
|
|
LMessage.Msg := LM_ERASEBKGND;
|
|
LMessage.WParam := WParam;
|
|
LMessage.LParam := LParam;
|
|
end else
|
|
begin
|
|
SendPaintMessage(HDC(WParam));
|
|
LMessage.Result := 1;
|
|
end;}
|
|
WinProcess := False;
|
|
end;
|
|
|
|
{ WM_EXITMENULOOP:
|
|
// is it a popup menu
|
|
if longbool(WPARAM) and assigned(WindowInfo^.PopupMenu) then
|
|
WindowInfo^.PopupMenu.Close;
|
|
WM_GETDLGCODE:
|
|
begin
|
|
LMessage.Result := DLGC_WANTALLKEYS;
|
|
WinProcess := false;
|
|
end;}
|
|
{
|
|
* TODO: make it work... icon does not show up yet, so better disable it
|
|
WM_GETICON:
|
|
begin
|
|
if WindowInfo^.WinControl is TCustomForm then
|
|
begin
|
|
LMessage.Result := TCustomForm(WindowInfo^.WinControl).GetIconHandle;
|
|
WinProcess := false;
|
|
end;
|
|
end;
|
|
}
|
|
WM_KEYDOWN:
|
|
begin
|
|
CallbackKeyDown(WindowInfo, Word(WParam));
|
|
Result := 1;
|
|
Exit;
|
|
end;
|
|
WM_KEYUP:
|
|
begin
|
|
CallbackKeyUp(WindowInfo, Word(WParam));
|
|
Result := 1;
|
|
Exit;
|
|
end;
|
|
WM_KILLFOCUS:
|
|
begin
|
|
{$ifdef DEBUG_CARET}
|
|
DebugLn('WM_KILLFOCUS received for window ', IntToHex(Window, 8));
|
|
{$endif}
|
|
LMessage.Msg := LM_KILLFOCUS;
|
|
LMessage.WParam := WParam;
|
|
end;
|
|
//TODO:LM_KILLCHAR,LM_KILLWORD,LM_KILLLINE
|
|
WM_LBUTTONDBLCLK:
|
|
begin
|
|
NotifyUserInput := True;
|
|
PLMsg:=@LMMouse;
|
|
with LMMouse Do
|
|
begin
|
|
Msg := LM_LBUTTONDBLCLK;
|
|
XPos := SmallInt(Lo(LParam));
|
|
YPos := SmallInt(Hi(LParam));
|
|
Keys := WParam;
|
|
lEventX := XPos;
|
|
lEventY := YPos;
|
|
end;
|
|
end;
|
|
WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN:
|
|
begin
|
|
{$ifdef wince}
|
|
// Gesture recognition process to enable popup menus.
|
|
if (lWinControl.PopupMenu <> nil) and (Msg = WM_LBUTTONDOWN) then
|
|
begin
|
|
Info.cbSize := SizeOf(SHRGINFO);
|
|
Info.dwFlags := SHRG_RETURNCMD;
|
|
Info.hwndClient := Window;
|
|
Info.ptDown.x := Lo(LParam);
|
|
Info.ptDown.y := Hi(LParam);
|
|
|
|
SHRecognizeGesture(Info);
|
|
end;
|
|
{$endif}
|
|
|
|
XPos := SmallInt(Lo(LParam));
|
|
YPos := SmallInt(Hi(LParam));
|
|
if GetLCLClientBoundsOffset(WindowInfo, R) then
|
|
begin
|
|
Dec(XPos, R.Left);
|
|
Dec(YPos, R.Top);
|
|
end;
|
|
WParamShiftState := KeysToShiftState(WParam); //MsgKeyDataToShiftState
|
|
case Msg of
|
|
WM_LBUTTONDOWN: MouseButton := mbLeft;
|
|
WM_MBUTTONDOWN: MouseButton := mbMiddle;
|
|
WM_RBUTTONDOWN: MouseButton := mbRight;
|
|
end;
|
|
|
|
CallbackMouseDown(WindowInfo, XPos, YPos, MouseButton, WParamShiftState);
|
|
Result := 1;
|
|
|
|
// focus window
|
|
if (Windows.GetFocus <> Window) and
|
|
((lWinControl = nil) or (lWinControl.CanFocus)) then
|
|
Windows.SetFocus(Window);
|
|
|
|
Exit;
|
|
end;
|
|
WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP:
|
|
begin
|
|
XPos := SmallInt(Lo(LParam));
|
|
YPos := SmallInt(Hi(LParam));
|
|
|
|
case Msg of
|
|
WM_LBUTTONUP: MouseButton := mbLeft;
|
|
WM_MBUTTONUP: MouseButton := mbMiddle;
|
|
WM_RBUTTONUP: MouseButton := mbRight;
|
|
end;
|
|
|
|
WParamShiftState := KeysToShiftState(WParam); //MsgKeyDataToShiftState
|
|
CallbackMouseUp(WindowInfo, XPos, YPos, MouseButton, WParamShiftState);
|
|
Result := 1;
|
|
Exit;
|
|
end;
|
|
WM_MBUTTONDBLCLK:
|
|
begin
|
|
NotifyUserInput := True;
|
|
PLMsg:=@LMMouse;
|
|
with LMMouse Do
|
|
begin
|
|
Msg := LM_MBUTTONDBLCLK;
|
|
XPos := SmallInt(Lo(LParam));
|
|
YPos := SmallInt(Hi(LParam));
|
|
Keys := WParam;
|
|
lEventX := XPos;
|
|
lEventY := YPos;
|
|
end;
|
|
end;
|
|
WM_MOUSEHOVER:
|
|
begin
|
|
NotifyUserInput := True;
|
|
LMessage.Msg := LM_ENTER;
|
|
end;
|
|
WM_MOUSELEAVE:
|
|
begin
|
|
NotifyUserInput := True;
|
|
LMessage.Msg := LM_LEAVE;
|
|
end;
|
|
WM_MOUSEMOVE:
|
|
begin
|
|
XPos := SmallInt(Lo(LParam));
|
|
YPos := SmallInt(Hi(LParam));
|
|
if GetLCLClientBoundsOffset(WindowInfo, R) then
|
|
begin
|
|
Dec(XPos, R.Left);
|
|
Dec(YPos, R.Top);
|
|
end;
|
|
WParamShiftState := KeysToShiftState(WParam);
|
|
|
|
CallbackMouseMove(WindowInfo, XPos, YPos, WParamShiftState);
|
|
Result := 1;
|
|
Exit;
|
|
end;
|
|
WM_MOUSEWHEEL:
|
|
begin
|
|
NotifyUserInput := True;
|
|
PLMsg:=@LMMouseEvent;
|
|
with LMMouseEvent Do
|
|
begin
|
|
X := SmallInt(Lo(LParam));
|
|
Y := SmallInt(Hi(LParam));
|
|
// check if mouse cursor within this window, otherwise send message to window the mouse is hovering over
|
|
P.X := X;
|
|
P.Y := Y;
|
|
lEventX := X;
|
|
lEventY := Y;
|
|
TargetWindow := TCDWidgetSet(WidgetSet).WindowFromPoint(P);
|
|
if TargetWindow = HWND(nil) then
|
|
exit;
|
|
|
|
// the mousewheel message is for us
|
|
// windows handles combobox's mousewheel messages
|
|
if (lWinControl=nil) or (lWinControl.FCompStyle <> csComboBox) then
|
|
begin
|
|
Msg := LM_MOUSEWHEEL;
|
|
Button := Lo(WParam);
|
|
WheelDelta := SmallInt(Hi(WParam));
|
|
State := KeysToShiftState(Button);
|
|
UserData := Pointer(GetWindowLong(Window, GWL_USERDATA));
|
|
WinProcess := false;
|
|
end;
|
|
end;
|
|
end;
|
|
{$IFDEF EnableWMDropFiles}
|
|
WM_DROPFILES:
|
|
begin
|
|
LMessage.Msg := LM_DROPFILES;
|
|
LMessage.WParam := WParam;
|
|
LMessage.LParam := LParam;
|
|
end;
|
|
{$ENDIF}
|
|
//TODO:LM_MOVEPAGE,LM_MOVETOROW,LM_MOVETOCOLUMN
|
|
WM_NCACTIVATE:
|
|
begin
|
|
// do not allow main form to be deactivated
|
|
if (Application <> nil) and (Application.MainForm <> nil) and
|
|
Application.MainForm.HandleAllocated and (Window = Application.MainForm.Handle) and
|
|
(WParam = 0) then
|
|
begin
|
|
WParam := 1;
|
|
end;
|
|
end;
|
|
WM_NCHITTEST:
|
|
begin
|
|
if (lWinControl <> nil) then begin
|
|
if (lWinControl.FCompStyle = csHintWindow) then
|
|
begin
|
|
LMessage.Result := HTTRANSPARENT;
|
|
WinProcess := false;
|
|
end;
|
|
end;
|
|
end;
|
|
WM_NCLBUTTONDOWN:
|
|
begin
|
|
NotifyUserInput := True;
|
|
//DebugLn('Trace:WindowProc - Got WM_NCLBUTTONDOWN');
|
|
end;
|
|
WM_PAINT:
|
|
begin
|
|
SendPaintMessage(HDC(WParam));
|
|
// SendPaintMessage sets winprocess to false
|
|
end;
|
|
WM_PRINTCLIENT:
|
|
begin
|
|
if ((LParam and PRF_CLIENT) = PRF_CLIENT) and (lWinControl <> nil) then
|
|
SendPaintMessage(HDC(WParam));
|
|
end;
|
|
WM_PASTE:
|
|
begin
|
|
LMessage.Msg := LM_PASTE;
|
|
end;
|
|
WM_RBUTTONDBLCLK:
|
|
begin
|
|
NotifyUserInput := True;
|
|
PLMsg:=@LMMouse;
|
|
with LMMouse Do
|
|
begin
|
|
Msg := LM_RBUTTONDBLCLK;
|
|
XPos := SmallInt(Lo(LParam));
|
|
YPos := SmallInt(Hi(LParam));
|
|
Keys := WParam;
|
|
end;
|
|
end;
|
|
WM_CONTEXTMENU:
|
|
begin
|
|
{$ifndef WinCE}
|
|
WinProcess := false;
|
|
NotifyUserInput := True;
|
|
PLMsg := @LMContextMenu;
|
|
with LMContextMenu do
|
|
begin
|
|
Msg := LM_CONTEXTMENU;
|
|
XPos := GET_X_LPARAM(LParam);
|
|
YPos := GET_Y_LPARAM(LParam);
|
|
hWnd := Window;
|
|
Result := 0;
|
|
end;
|
|
{$endif}
|
|
end;
|
|
WM_SETCURSOR:
|
|
begin
|
|
HandleSetCursor;
|
|
end;
|
|
WM_SETFOCUS:
|
|
begin
|
|
{$ifdef DEBUG_CARET}
|
|
DebugLn('WM_SETFOCUS received for window ', IntToHex(Window, 8));
|
|
{$endif}
|
|
// handle feature mouse-click, setfocus, mouse-click -> double-click
|
|
if (Window <> MouseDownWindow) and (MouseDownFocusStatus <> mfNone) then
|
|
begin
|
|
MouseDownFocusStatus := mfFocusChanged;
|
|
MouseDownFocusWindow := Window;
|
|
end;
|
|
LMessage.Msg := LM_SETFOCUS;
|
|
if (lWinControl <> nil) and (lWinControl.FCompStyle = csEdit) then
|
|
Windows.SendMessage(Window, EM_SETSEL, 0, -1);
|
|
end;
|
|
WM_SHOWWINDOW:
|
|
begin
|
|
//DebugLn('Trace:WindowProc - Got WM_SHOWWINDOW');
|
|
with TLMShowWindow(LMessage) Do
|
|
begin
|
|
Msg := LM_SHOWWINDOW;
|
|
Show := WParam <> 0;
|
|
Status := LParam;
|
|
end;
|
|
|
|
if assigned(lWinControl) and ((WParam<>0) or not lWinControl.Visible)
|
|
and ((WParam=0) or lWinControl.Visible)
|
|
and (Application<>nil) and (lWinControl=Application.MainForm) then
|
|
begin
|
|
if WParam=0 then
|
|
Flags := SW_HIDE
|
|
else
|
|
Flags := SW_SHOWNOACTIVATE;
|
|
Windows.ShowWindow(TCDWidgetSet(WidgetSet).FAppHandle, Flags);
|
|
end;
|
|
end;
|
|
WM_SYSCHAR:
|
|
begin
|
|
PLMsg:=@LMChar;
|
|
with LMChar Do
|
|
begin
|
|
Msg := CN_SYSCHAR;
|
|
KeyData := LParam;
|
|
CharCode := Word(WParam);
|
|
Result := 0;
|
|
//DebugLn(Format('WM_CHAR KeyData= %d CharCode= %d ',[KeyData,CharCode]));
|
|
end;
|
|
WinProcess := false;
|
|
end;
|
|
WM_SYSCOMMAND:
|
|
begin
|
|
HandleSysCommand;
|
|
end;
|
|
WM_SYSKEYDOWN:
|
|
begin
|
|
NotifyUserInput := True;
|
|
PLMsg:=@LMKey;
|
|
with LMKey Do
|
|
begin
|
|
Msg := CN_SYSKEYDOWN;
|
|
KeyData := LParam;
|
|
CharCode := Word(WParam);
|
|
Result := 0;
|
|
end;
|
|
WinProcess := false;
|
|
end;
|
|
WM_SYSKEYUP:
|
|
begin
|
|
NotifyUserInput := True;
|
|
PLMsg:=@LMKey;
|
|
with LMKey Do
|
|
begin
|
|
Msg := CN_SYSKEYUP;
|
|
KeyData := LParam;
|
|
CharCode := Word(WParam);
|
|
Result := 0;
|
|
end;
|
|
WinProcess := false;
|
|
end;
|
|
WM_TIMER:
|
|
begin
|
|
LMessage.Msg := LM_TIMER;
|
|
LMessage.WParam := WParam;
|
|
LMessage.LParam := LParam;
|
|
end;
|
|
WM_WINDOWPOSCHANGED:
|
|
begin
|
|
with TLMWindowPosMsg(LMessage) Do
|
|
begin
|
|
Msg := LM_WINDOWPOSCHANGED;
|
|
Unused := WParam;
|
|
WindowPos := PWindowPos(LParam);
|
|
end;
|
|
// cross-interface compatible: complete invalidate on resize
|
|
if (PWindowPos(LParam)^.flags and SWP_NOSIZE) = 0 then
|
|
Windows.InvalidateRect(Window, nil, true);
|
|
end;
|
|
{ WM_LCL_SOCK_ASYNC:
|
|
begin
|
|
if (Window = TWinCEWidgetSet(WidgetSet).AppHandle) and
|
|
Assigned(TWinCEWidgetSet(WidgetSet).FOnAsyncSocketMsg) then
|
|
exit(TWinCEWidgetSet(WidgetSet).FOnAsyncSocketMsg(WParam, LParam))
|
|
end;}
|
|
{$ifdef wince}
|
|
WM_HOTKEY:
|
|
begin
|
|
// Implements back-key sending to edits, instead of hiding the form
|
|
// See http://bugs.freepascal.org/view.php?id=16699
|
|
{if HIWORD(lParam) = VK_ESCAPE then
|
|
begin
|
|
SHSendBackToFocusWindow(Msg, wParam, lParam);
|
|
Exit;
|
|
end;}
|
|
end;
|
|
{$endif}
|
|
else
|
|
// pass along user defined messages
|
|
if Msg >= WM_USER then
|
|
begin
|
|
LMessage.Msg := Msg;
|
|
LMessage.WParam := WParam;
|
|
LMessage.LParam := LParam;
|
|
WinProcess := false;
|
|
end;
|
|
end;
|
|
|
|
{$ifdef MSG_DEBUG}
|
|
DebugLn('Trace:WindowProc - End Case Msg of');
|
|
{$endif}
|
|
|
|
if WinProcess Then
|
|
begin
|
|
{$ifdef MSG_DEBUG}
|
|
DebugLn('Trace:WindowProc - if WinProcess Then');
|
|
{$endif}
|
|
PLMsg^.Result := CallDefaultWindowProc(Window, Msg, WParam, LParam);
|
|
WinProcess := false;
|
|
{$ifdef MSG_DEBUG}
|
|
DebugLn('Trace:WindowProc - End if WinProcess Then');
|
|
{$endif}
|
|
end;
|
|
|
|
case Msg of
|
|
WM_MOVE:
|
|
begin
|
|
{$ifndef WinCE}
|
|
PLMsg:=@LMMove;
|
|
with LMMove Do
|
|
begin
|
|
Msg := LM_MOVE;
|
|
// MoveType := WParam; WParam is not defined!
|
|
MoveType := Move_SourceIsInterface;
|
|
if GetWindowLong(Window, GWL_STYLE) and WS_CHILD = 0 then
|
|
begin
|
|
WindowPlacement.length := SizeOf(WindowPlacement);
|
|
if IsIconic(Window) and GetWindowPlacement(Window, @WindowPlacement) then
|
|
begin
|
|
with WindowPlacement.rcNormalPosition do
|
|
begin
|
|
XPos := Left;
|
|
YPos := Top;
|
|
end;
|
|
end
|
|
else
|
|
if Windows.GetWindowRect(Window, @R) then
|
|
begin
|
|
XPos := R.Left;
|
|
YPos := R.Top;
|
|
end
|
|
else
|
|
Msg := LM_NULL;
|
|
end else
|
|
begin
|
|
if LCLIntf.GetWindowRelativePosition(HWND(WindowInfo), NewLeft, NewTop) then
|
|
begin
|
|
XPos := NewLeft;
|
|
YPos := NewTop;
|
|
end
|
|
else
|
|
Msg := LM_NULL;
|
|
end;
|
|
if lWinControl <> nil then
|
|
begin
|
|
{$IFDEF VerboseSizeMsg}
|
|
DebugLn('Win32CallBack WM_MOVE ', dbgsName(lWinControl),
|
|
' NewPos=',dbgs(XPos),',',dbgs(YPos));
|
|
{$ENDIF}
|
|
if (lWinControl.Left = XPos) and (lWinControl.Top = YPos) then
|
|
Exit;
|
|
end;
|
|
end;
|
|
{$endif}
|
|
end;
|
|
WM_SIZE:
|
|
begin
|
|
with TLMSize(LMessage) do
|
|
begin
|
|
Msg := LM_SIZE;
|
|
SizeType := WParam or Size_SourceIsInterface;
|
|
if Window = CDWidgetSet.AppHandle then
|
|
begin
|
|
if Assigned(Application.MainForm) and Application.MainForm.HandleAllocated then
|
|
begin
|
|
lWinControl := Application.MainForm;
|
|
Window := Application.MainFormHandle;
|
|
end;
|
|
end;
|
|
LCLIntf.GetWindowSize(HWND(WindowInfo), NewWidth, NewHeight);
|
|
Width := NewWidth;
|
|
Height := NewHeight;
|
|
if Assigned(lWinControl) then
|
|
begin
|
|
{$IFDEF VerboseSizeMsg}
|
|
GetClientRect(Window,R);
|
|
DebugLn('Win32Callback: WM_SIZE '+ dbgsName(lWinControl)+
|
|
' NewSize=', dbgs(Width)+','+dbgs(Height)+
|
|
' HasVScroll='+dbgs((GetWindowLong(Window, GWL_STYLE) and WS_VSCROLL) <> 0)+
|
|
' HasHScroll='+dbgs((GetWindowLong(Window, GWL_STYLE) and WS_HSCROLL) <> 0)+
|
|
' OldClientSize='+dbgs(lWinControl.CachedClientWidth)+','+dbgs(lWinControl.CachedClientHeight)+
|
|
' NewClientSize='+dbgs(R.Right)+','+dbgs(R.Bottom));
|
|
{$ENDIF}
|
|
if (lWinControl.Width <> Width) or
|
|
(lWinControl.Height <> Height) or
|
|
lWinControl.ClientRectNeedsInterfaceUpdate then
|
|
lWinControl.DoAdjustClientRectChange
|
|
else
|
|
// If we get form size message then we probably changed it state
|
|
// (minimized/maximized -> normal). Form adjust its clientrect in the
|
|
// second WM_SIZE but WM_MOVE also updates clientrect without adjustment
|
|
// thus we need to call DoAdjustClientRectChange. It is safe since this
|
|
// methods checks whether it need to adjust something really.
|
|
if (lWinControl is TCustomForm) and (lWinControl.Parent = nil) and
|
|
(WParam = Size_Restored) then
|
|
lWinControl.DoAdjustClientRectChange(False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{WM_ENDSESSION:
|
|
begin
|
|
if (Application<>nil) and (TWinCEWidgetSet(WidgetSet).AppHandle=Window) and
|
|
(WParam>0) and (LParam=0) then
|
|
begin
|
|
LMessage.Msg := LM_NULL; // no need to go through delivermessage
|
|
Application.IntfEndSession();
|
|
LMessage.Result := 0;
|
|
end;
|
|
end;}
|
|
|
|
{WM_QUERYENDSESSION:
|
|
begin
|
|
if (Application<>nil) and (TWinCEWidgetSet(WidgetSet).AppHandle=Window) and
|
|
(LParam=0) then
|
|
begin
|
|
LMessage.Msg := LM_NULL; // no need to go through delivermessage
|
|
CancelEndSession := LMessage.Result=0;
|
|
Application.IntfQueryEndSession(CancelEndSession);
|
|
if CancelEndSession
|
|
then LMessage.Result := 0
|
|
else LMessage.Result := 1;
|
|
end;
|
|
end;}
|
|
|
|
end;
|
|
|
|
// convert from wince client to lcl client pos.
|
|
//
|
|
// hack to prevent GetLCLClientBoundsOffset from changing mouse client
|
|
// coordinates for TScrollingWinControls, this is required in
|
|
// IsControlMouseMsg and ControlAtPos where unscrolled client coordinates
|
|
// are expected.
|
|
if (PLMsg = @LMMouseMove) and not (lWinControl is TScrollingWinControl) then
|
|
begin
|
|
if GetLCLClientBoundsOffset(WindowInfo, R) then
|
|
begin
|
|
Dec(LMMouseMove.XPos, R.Left);
|
|
Dec(LMMouseMove.YPos, R.Top);
|
|
end;
|
|
end else
|
|
if (PLMsg = @LMMouse) and not (lWinControl is TScrollingWinControl) then
|
|
begin
|
|
if GetLCLClientBoundsOffset(WindowInfo, R) then
|
|
begin
|
|
Dec(LMMouse.XPos, R.Left);
|
|
Dec(LMMouse.YPos, R.Top);
|
|
end;
|
|
end;
|
|
|
|
// application processing
|
|
if NotifyUserInput then
|
|
NotifyApplicationUserInput(lWinControl, PLMsg^.Msg);
|
|
|
|
if (lWinControl <> nil) and (PLMsg^.Msg <> LM_NULL) then
|
|
begin
|
|
if (lEventX < 0) or (lEventY < 0) then
|
|
begin
|
|
DeliverMessage(lWinControl, PLMsg^);
|
|
end
|
|
else
|
|
begin
|
|
lEventReceiver := FindControlWhichReceivedEvent(
|
|
TCustomForm(lWinControl),
|
|
GetCDWinControlList(TCustomForm(lWinControl)),
|
|
lEventX, lEventY);
|
|
DeliverMessage(lEventReceiver, PLMsg^);
|
|
end;
|
|
end;
|
|
|
|
// respond to result of LCL handling the message
|
|
case PLMsg^.Msg of
|
|
LM_ERASEBKGND, LM_SETCURSOR, LM_RBUTTONUP:
|
|
begin
|
|
if PLMsg^.Result = 0 then
|
|
WinProcess := true;
|
|
end;
|
|
|
|
CN_CHAR, CN_SYSCHAR:
|
|
begin
|
|
// if key not yet processed, let windows process it
|
|
|
|
WinProcess := LMChar.Result = 0;
|
|
if (LMChar.Result=1) or (OrgCharCode<>LMChar.CharCode) then
|
|
WParam := Word(WideChar(Char(LMChar.CharCode)));
|
|
// WParam := LMChar.CharCode;
|
|
end;
|
|
|
|
CN_KEYDOWN, CN_KEYUP, CN_SYSKEYDOWN, CN_SYSKEYUP:
|
|
begin
|
|
// if key not yet processed, let windows process it
|
|
WinProcess := LMKey.Result = 0;
|
|
WParam := LMKey.CharCode;
|
|
end;
|
|
|
|
else
|
|
case Msg of
|
|
WM_LBUTTONDOWN, WM_LBUTTONUP:
|
|
begin
|
|
if MouseDownFocusStatus = mfFocusSense then
|
|
MouseDownFocusStatus := mfNone;
|
|
end;
|
|
WM_NCDESTROY:
|
|
begin
|
|
WindowInfo.Free;
|
|
WindowInfo := nil;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if WinProcess then
|
|
begin
|
|
PLMsg^.Result := CallDefaultWindowProc(Window, Msg, WParam, LParam);
|
|
case Msg of
|
|
WM_CHAR, WM_KEYDOWN, WM_KEYUP,
|
|
WM_SYSCHAR, WM_SYSKEYDOWN, WM_SYSKEYUP:
|
|
begin
|
|
PLMsg^.Result := 0;
|
|
case Msg of
|
|
WM_CHAR:
|
|
begin
|
|
// if want chars, then handled already
|
|
PLMsg^.Result := CallDefaultWindowProc(Window, WM_GETDLGCODE, WParam, 0) and DLGC_WANTCHARS;
|
|
LMChar.CharCode := Word(WParam);
|
|
LMChar.Msg := LM_CHAR;
|
|
end;
|
|
WM_SYSCHAR:
|
|
begin
|
|
LMChar.CharCode := Word(WParam);
|
|
LMChar.Msg := LM_SYSCHAR;
|
|
end;
|
|
WM_KEYDOWN:
|
|
begin
|
|
LMKey.CharCode := Word(WParam);
|
|
LMKey.Msg := LM_KEYDOWN;
|
|
end;
|
|
WM_KEYUP:
|
|
begin
|
|
LMKey.CharCode := Word(WParam);
|
|
LMKey.Msg := LM_KEYUP;
|
|
end;
|
|
WM_SYSKEYDOWN:
|
|
begin
|
|
LMKey.CharCode := Word(WParam);
|
|
LMKey.Msg := LM_SYSKEYDOWN;
|
|
end;
|
|
WM_SYSKEYUP:
|
|
begin
|
|
LMKey.CharCode := Word(WParam);
|
|
LMKey.Msg := LM_SYSKEYUP;
|
|
end;
|
|
end;
|
|
|
|
// we cannot tell for sure windows didn't want the key
|
|
// for WM_CHAR check WM_GETDLGCODE/DLGC_WANTCHARS
|
|
// winapi too inconsistent about return value
|
|
if PLMsg^.Result = 0 then
|
|
DeliverMessage(lWinControl, PLMsg^);
|
|
|
|
{ // handle the hardware back key (= VK_ESCAPE) for edit controls
|
|
// It should work as the backspace
|
|
if (PLMsg^.Result = 0) and (Msg = WM_KEYDOWN) and (WParam = VK_ESCAPE)
|
|
{and (GetKeyState(VK_CONTROL) >= 0) and (GetKeyState(VK_MENU) >= 0)} then
|
|
begin
|
|
if (WndClassName(Window) = EditClsName) then
|
|
begin
|
|
Windows.SendMessage(Window, WM_KEYDOWN, VK_BACK, -1);
|
|
end;
|
|
end;}
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// ignore WM_(SYS)CHAR message if LCL handled WM_(SYS)KEYDOWN
|
|
if ((Msg = WM_KEYDOWN) or (Msg = WM_SYSKEYDOWN)) then
|
|
begin
|
|
if (PLMsg^.Result <> 0) then
|
|
begin
|
|
IgnoreNextCharWindow := Window;
|
|
end else begin
|
|
// stop ignoring if KEYUP has come by (not all keys generate CHAR)
|
|
// assume WM_CHAR is always preceded by WM_KEYDOWN
|
|
IgnoreNextCharWindow := 0;
|
|
end;
|
|
end;
|
|
|
|
{ LMMouseEvent and LMInsertText have no Result field }
|
|
|
|
if PLMsg = @LMScroll then Result := LMScroll.Result
|
|
else if PLMsg = @LMKey then Result := LMKey.Result
|
|
else if PLMsg = @LMChar then Result := LMChar.Result
|
|
else if PLMsg = @LMMouse then Result := LMMouse.Result
|
|
else if PLMsg = @LMMouseMove then Result := LMMouseMove.Result
|
|
else if PLMsg = @LMMove then Result := LMMove.Result
|
|
else if PLMsg = @LMNotify then Result := LMNotify.Result
|
|
else if PLMsg = @LMMouseEvent then Result := 1
|
|
else Result := PLMsg^.Result;
|
|
|
|
//DebugLn('Trace:WindowProc - Exit');
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Procedure: TimerCallBackProc
|
|
Params: window_hnd - handle of window for timer message, not set in this implementation
|
|
msg - WM_TIMER message
|
|
idEvent - timer identifier
|
|
dwTime - current system time
|
|
|
|
Calls the timerfunction in the Timer Object in the LCL
|
|
------------------------------------------------------------------------------}
|
|
|
|
procedure TimerCallBackProc(window_hwnd : hwnd; msg :UINT; idEvent: UINT_PTR; dwTime: DWORD);
|
|
{$if defined(win32) or defined(win64)}stdcall{$else}cdecl{$endif};
|
|
Var
|
|
TimerInfo: PWinCETimerInfo;
|
|
n: Integer;
|
|
begin
|
|
n := FTimerData.Count;
|
|
while (n>0) do begin
|
|
dec(n);
|
|
TimerInfo := FTimerData[n];
|
|
if TimerInfo^.TimerID=idEvent then begin
|
|
TimerInfo^.TimerFunc;
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|