unit uutlEventManager; { Package: Utils Prefix: utl - UTiLs Beschreibung: diese Unit verwaltet Events und verteilt diese an registrierte Programm-Teile } {$mode objfpc}{$H+} interface uses Classes, SysUtils, Controls, uutlEvent; type ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TutlMouseButtons = set of TMouseButton; TutlWinControlEvent = class(TutlEvent) private fSender: TControl; public property Sender: TControl read fSender; constructor Create( const aEventType: TutlEventType; const aSender: TControl); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TutlMouseEvent = class(TutlWinControlEvent) private fButtons: TutlMouseButtons; fClientPos: TPoint; fScreenPos: TPoint; public property Buttons: TutlMouseButtons read fButtons; property ClientPos: TPoint read fClientPos; property ScreenPos: TPoint read fScreenPos; constructor Create( const aEventType: TutlEventType; const aSender: TControl; const aButtons: TutlMouseButtons; const aClientPos: TPoint); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TutlMouseWheelEvent = class(TutlWinControlEvent) private fWheelDelta: Integer; fClientPos: TPoint; fScreenPos: TPoint; public property WheelDelta: Integer read fWheelDelta; property ClientPos: TPoint read fClientPos; property ScreenPos: TPoint read fScreenPos; constructor Create( const aSender: TControl; const aWheelDelta: Integer; const aClientPos: TPoint); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TutlKeyEvent = class(TutlWinControlEvent) private fCharCode: WideChar; fKeyCode: Word; public property CharCode: WideChar read fCharCode; property KeyCode: Word read fKeyCode; constructor Create( const aEventType: TutlEventType; const aSender: TControl; const aCharCode: WideChar; const aKeyCode: Word); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TutlWindowEvent = class(TutlWinControlEvent) private fScreenRect: TRect; fClientWidth: Cardinal; fClientHeight: Cardinal; public property ScreenRect: TRect read fScreenRect; property ClientWidth: Cardinal read fClientWidth; property ClientHeight: Cardinal read fClientHeight; constructor Create( const aEventType: TutlEventType; const aSender: TControl; const aScreenRect: TRect; const aClientWidth: Cardinal; const aClientHeight: Cardinal); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TutlWinControlEventManager = class(TutlEventListenerSet) public const EVENT_MOUSE_DOWN = 0; EVENT_MOUSE_UP = 1; EVENT_MOUSE_WHEEL_UP = 2; EVENT_MOUSE_WHEEL_DOWN = 3; EVENT_MOUSE_MOVE = 4; EVENT_MOUSE_ENTER = 5; EVENT_MOUSE_LEAVE = 6; EVENT_MOUSE_CLICK = 7; EVENT_MOUSE_DBL_CLICK = 8; EVENT_KEY_DOWN = 10; EVENT_KEY_REPEAT = 11; EVENT_KEY_UP = 12; EVENT_WINDOW_RESIZE = 15; EVENT_WINDOW_ACTIVATE = 16; EVENT_WINDOW_DEACTIVATE = 17; EVENTS_MOUSE: TutlEventTypes = [ EVENT_MOUSE_DOWN, EVENT_MOUSE_UP, EVENT_MOUSE_WHEEL_UP, EVENT_MOUSE_WHEEL_DOWN, EVENT_MOUSE_MOVE, EVENT_MOUSE_ENTER, EVENT_MOUSE_LEAVE, EVENT_MOUSE_CLICK, EVENT_MOUSE_DBL_CLICK ]; EVENTS_KEYBOARD: TutlEventTypes = [ EVENT_KEY_DOWN, EVENT_KEY_REPEAT, EVENT_KEY_UP ]; EVENTS_WINDOW: TutlEventTypes = [ EVENT_WINDOW_RESIZE, EVENT_WINDOW_ACTIVATE, EVENT_WINDOW_DEACTIVATE ]; private type TKeyboardState = record Modifiers: TShiftState; KeyState: array[Byte] of Boolean; end; TMouseState = record ScreenPos: TPoint; ClientPos: TPoint; Buttons: TutlMouseButtons; end; TWindowState = record Active: Boolean; ScreenRect: TRect; ClientWidth: Integer; ClientHeight: Integer; end; private fKeyboard: TKeyboardState; fMouse: TMouseState; fWindow: TWindowState; procedure HandlerMouseDown (Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure HandlerMouseUp (Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure HandlerMouseMove (Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure HandlerMouseEnter (Sender: TObject); procedure HandlerMouseLeave (Sender: TObject); procedure HandlerClick (Sender: TObject); procedure HandlerDblClick (Sender: TObject); procedure HandlerMouseWheel (Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); procedure HandlerKeyDown (Sender: TObject; var Key: Word; Shift: TShiftState); procedure HandlerKeyUp (Sender: TObject; var Key: Word; Shift: TShiftState); procedure HandlerResize (Sender: TObject); procedure HandlerActivate (Sender: TObject); procedure HandlerDeactivate (Sender: TObject); protected procedure RecordEvent(const aEvent: IutlEvent); virtual; function CreateMouseEvent( aSender: TObject; aType: TutlEventType; aButtons: TutlMouseButtons; aClientPos: TPoint): TutlMouseEvent; virtual; function CreateMouseWheelEvent( aSender: TObject; aDelta: Integer; aClientPos: TPoint): TutlMouseWheelEvent; virtual; function CreateKeyEvent( aSender: TObject; aType: TutlEventType; aKey: Word): TutlKeyEvent; virtual; function CreateWindowEvent( aSender: TObject; aType: TutlEventType): TutlWindowEvent; virtual; public property Keyboard: TKeyboardState read fKeyboard; property Mouse: TMouseState read fMouse; property Window: TWindowState read fWindow; procedure DispatchEvent(const aEvent: IutlEvent); override; procedure AttachEvents(const aControl: TWinControl; const aTypes: TutlEventTypes); end; implementation uses LCLIntf, Forms, uutlKeyCodes; type TWinControlVisibilityClass = class(TWinControl) published property OnMouseDown; property OnMouseMove; property OnMouseUp; property OnMouseWheel; property OnMouseEnter; property OnMouseLeave; property OnClick; property OnDblClick; end; TCustomFormVisibilityClass = class(TCustomForm) published property OnActivate; property OnDeactivate; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlWinControlEvent//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TutlWinControlEvent.Create(const aEventType: TutlEventType; const aSender: TControl); begin inherited Create(aEventType); fSender := aSender; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlMouseEvent///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TutlMouseEvent.Create( const aEventType: TutlEventType; const aSender: TControl; const aButtons: TutlMouseButtons; const aClientPos: TPoint); begin inherited Create(aEventType, aSender); fButtons := aButtons; fClientPos := aClientPos; fScreenPos := fSender.ClientToScreen(fClientPos); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlMouseWheelEvent//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TutlMouseWheelEvent.Create( const aSender: TControl; const aWheelDelta: Integer; const aClientPos: TPoint); begin if (aWheelDelta < 0) then inherited Create(TutlWinControlEventManager.EVENT_MOUSE_WHEEL_DOWN, aSender) else inherited Create(TutlWinControlEventManager.EVENT_MOUSE_WHEEL_UP, aSender); fWheelDelta := aWheelDelta; fClientPos := aClientPos; fScreenPos := fSender.ClientToScreen(fClientPos); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlKeyEvent/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TutlKeyEvent.Create( const aEventType: TutlEventType; const aSender: TControl; const aCharCode: WideChar; const aKeyCode: Word); begin inherited Create(aEventType, aSender); fCharCode := aCharCode; fKeyCode := aKeyCode; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlWindowEvent//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TutlWindowEvent.Create( const aEventType: TutlEventType; const aSender: TControl; const aScreenRect: TRect; const aClientWidth: Cardinal; const aClientHeight: Cardinal); begin inherited Create(aEventType, aSender); fScreenRect := aScreenRect; fClientWidth := aClientWidth; fClientHeight := aClientHeight; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlWinControlEventManager///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlWinControlEventManager.HandlerMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin DispatchEvent(CreateMouseEvent(Sender, EVENT_MOUSE_DOWN, [ Button ], Point(X, Y))); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlWinControlEventManager.HandlerMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin DispatchEvent(CreateMouseEvent(Sender, EVENT_MOUSE_UP, [Button], Point(X, Y))); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlWinControlEventManager.HandlerMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin DispatchEvent(CreateMouseEvent(Sender, EVENT_MOUSE_MOVE, [], Point(X, Y))); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlWinControlEventManager.HandlerMouseEnter(Sender: TObject); begin DispatchEvent(CreateMouseEvent(Sender, EVENT_MOUSE_ENTER, [], TControl(Sender).ScreenToClient(Controls.Mouse.CursorPos))); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlWinControlEventManager.HandlerMouseLeave(Sender: TObject); begin DispatchEvent(CreateMouseEvent(Sender, EVENT_MOUSE_LEAVE, [], TControl(Sender).ScreenToClient(Controls.Mouse.CursorPos))); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlWinControlEventManager.HandlerClick(Sender: TObject); begin DispatchEvent(CreateMouseEvent(Sender, EVENT_MOUSE_CLICK, [], TControl(Sender).ScreenToClient(Controls.Mouse.CursorPos))); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlWinControlEventManager.HandlerDblClick(Sender: TObject); begin DispatchEvent(CreateMouseEvent(Sender, EVENT_MOUSE_DBL_CLICK, [], TControl(Sender).ScreenToClient(Controls.Mouse.CursorPos))); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlWinControlEventManager.HandlerMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); begin DispatchEvent(CreateMouseWheelEvent(Sender, WheelDelta, MousePos)); Handled := false; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlWinControlEventManager.HandlerKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin DispatchEvent(CreateKeyEvent(Sender, EVENT_KEY_DOWN, Key)); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlWinControlEventManager.HandlerKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin DispatchEvent(CreateKeyEvent(Sender, EVENT_KEY_UP, Key)); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlWinControlEventManager.HandlerResize(Sender: TObject); begin DispatchEvent(CreateWindowEvent(Sender, EVENT_WINDOW_RESIZE)); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlWinControlEventManager.HandlerActivate(Sender: TObject); begin DispatchEvent(CreateWindowEvent(Sender, EVENT_WINDOW_ACTIVATE)); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlWinControlEventManager.HandlerDeactivate(Sender: TObject); begin DispatchEvent(CreateWindowEvent(Sender, EVENT_WINDOW_DEACTIVATE)); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlWinControlEventManager.RecordEvent(const aEvent: IutlEvent); var me: TutlMouseEvent; ke: TutlKeyEvent; we: TutlWindowEvent; function GetPressedButtons: TutlMouseButtons; begin result := []; if (GetKeyState(VK_LBUTTON) < 0) then result := result + [mbLeft]; if (GetKeyState(VK_RBUTTON) < 0) then result := result + [mbRight]; if (GetKeyState(VK_MBUTTON) < 0) then result := result + [mbMiddle]; if (GetKeyState(VK_XBUTTON1) < 0) then result := result + [mbExtra1]; if (GetKeyState(VK_XBUTTON2) < 0) then result := result + [mbExtra2]; end; begin if Supports(aEvent, TutlMouseEvent, me) then begin fMouse.ClientPos := me.ClientPos; fMouse.ScreenPos := me.ScreenPos; case me.EventType of EVENT_MOUSE_DOWN: fMouse.Buttons := fMouse.Buttons + me.Buttons; EVENT_MOUSE_UP: fMouse.Buttons := fMouse.Buttons - me.Buttons; EVENT_MOUSE_LEAVE: fMouse.Buttons := []; EVENT_MOUSE_ENTER: fMouse.Buttons := GetPressedButtons; end; end else if Supports(aEvent, TutlKeyEvent, ke) then begin case ke.EventType of EVENT_KEY_DOWN, EVENT_KEY_REPEAT: begin fKeyboard.KeyState[ke.KeyCode and $FF] := true; case ke.KeyCode of VK_SHIFT: Include(fKeyboard.Modifiers, ssShift); VK_MENU: Include(fKeyboard.Modifiers, ssAlt); VK_CONTROL: Include(fKeyboard.Modifiers, ssCtrl); end; end; EVENT_KEY_UP: begin fKeyboard.KeyState[ke.KeyCode and $FF] := false; case ke.KeyCode of VK_SHIFT: Exclude(fKeyboard.Modifiers, ssShift); VK_MENU: Exclude(fKeyboard.Modifiers, ssAlt); VK_CONTROL: Exclude(fKeyboard.Modifiers, ssCtrl); end; end; end; if ([ssCtrl, ssAlt] - fKeyboard.Modifiers = []) then include(fKeyboard.Modifiers, ssAltGr) else exclude(fKeyboard.Modifiers, ssAltGr); end else if Supports(aEvent, TutlWindowEvent, we) then begin case we.EventType of EVENT_WINDOW_ACTIVATE: fWindow.Active := true; EVENT_WINDOW_DEACTIVATE: fWindow.Active := false; EVENT_WINDOW_RESIZE: begin fWindow.ScreenRect := we.ScreenRect; fWindow.ClientWidth := we.ClientWidth; fWindow.ClientHeight := we.ClientHeight; end; end; end; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlWinControlEventManager.CreateMouseEvent(aSender: TObject; aType: TutlEventType; aButtons: TutlMouseButtons; aClientPos: TPoint): TutlMouseEvent; begin result := TutlMouseEvent.Create( aType, (aSender as TControl), aButtons, aClientPos); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlWinControlEventManager.CreateMouseWheelEvent(aSender: TObject; aDelta: Integer; aClientPos: TPoint): TutlMouseWheelEvent; begin result := TutlMouseWheelEvent.Create( (aSender as TControl), aDelta, aClientPos); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlWinControlEventManager.CreateKeyEvent(aSender: TObject; aType: TutlEventType; aKey: Word): TutlKeyEvent; begin if (aType = EVENT_KEY_DOWN) and fKeyboard.KeyState[aKey and $FF] then aType := EVENT_KEY_REPEAT; result := TutlKeyEvent.Create( aType, (aSender as TControl), VKCodeToCharCode(aKey, fKeyboard.Modifiers), aKey); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlWinControlEventManager.CreateWindowEvent(aSender: TObject; aType: TutlEventType): TutlWindowEvent; var p0, p1: TPoint; begin with TControl(aSender) do begin p0 := ClientToScreen(Point(0, 0)); p1 := ClientToScreen(Point(Width, Height)); end; result := TutlWindowEvent.Create( aType, (aSender as TControl), Rect(p0.x, p0.y, p1.x, p1.y), (aSender as TWinControl).ClientWidth, (aSender as TWinControl).ClientHeight); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlWinControlEventManager.DispatchEvent(const aEvent: IutlEvent); begin RecordEvent(aEvent); inherited DispatchEvent(aEvent); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlWinControlEventManager.AttachEvents(const aControl: TWinControl; const aTypes: TutlEventTypes); var ctl: TWinControlVisibilityClass; frm: TCustomFormVisibilityClass; begin ctl := TWinControlVisibilityClass(aControl); // mouse events if (EVENT_MOUSE_DOWN in aTypes) then ctl.OnMouseDown := @HandlerMouseDown; if (EVENT_MOUSE_UP in aTypes) then ctl.OnMouseUp := @HandlerMouseUp; if (EVENT_MOUSE_MOVE in aTypes) then ctl.OnMouseMove := @HandlerMouseMove; if (EVENT_MOUSE_ENTER in aTypes) then ctl.OnMouseEnter := @HandlerMouseEnter; if (EVENT_MOUSE_LEAVE in aTypes) then ctl.OnMouseLeave := @HandlerMouseLeave; if (EVENT_MOUSE_CLICK in aTypes) then ctl.OnClick := @HandlerClick; if (EVENT_MOUSE_DBL_CLICK in aTypes) then ctl.OnDblClick := @HandlerDblClick; if (EVENT_MOUSE_WHEEL_DOWN in aTypes) or (EVENT_MOUSE_WHEEL_UP in aTypes) then ctl.OnMouseWheel := @HandlerMouseWheel; // key events if (EVENT_KEY_DOWN in aTypes) then ctl.OnKeyDown := @HandlerKeyDown; if (EVENT_KEY_UP in aTypes) then ctl.OnKeyUp := @HandlerKeyUp; // window events if (EVENT_WINDOW_RESIZE in aTypes) then begin ctl.OnResize := @HandlerResize; fWindow.ClientWidth := ctl.ClientWidth; fWindow.ClientHeight := ctl.ClientHeight; end; if (aControl is TCustomForm) then begin frm := TCustomFormVisibilityClass(aControl); frm.KeyPreview := true; if (EVENT_WINDOW_ACTIVATE in aTypes) then frm.OnActivate := @HandlerActivate; if (EVENT_WINDOW_DEACTIVATE in aTypes) then frm.OnDeactivate := @HandlerDeactivate; end; end; end.