You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

731 lines
29 KiB

  1. unit uutlEventManager;
  2. { Package: Utils
  3. Prefix: utl - UTiLs
  4. Beschreibung: diese Unit verwaltet Events und verteilt diese an registrierte Programm-Teile }
  5. {$mode objfpc}{$H+}
  6. interface
  7. uses
  8. Classes, SysUtils, syncobjs, Controls,
  9. uutlGenerics;
  10. type
  11. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  12. TutlEventManager = class(TObject)
  13. public type
  14. TEventType = 0..63;
  15. TEventTypeMask = UInt64;
  16. ////////////////////////////////////////////////////////////////////////////
  17. TEvent = class
  18. public
  19. EventType: TEventType;
  20. Timestamp: QWord;
  21. function Clone: TEvent;
  22. procedure Assign(const aEvent: TEvent); virtual;
  23. constructor Create; virtual;
  24. end;
  25. TEventClass = class of TEvent;
  26. TEventList = specialize TutlList<TEvent>;
  27. ////////////////////////////////////////////////////////////////////////////
  28. TEventListener = class(TObject)
  29. public
  30. function DispatchEvent(const aEvent: TEvent): Boolean; virtual;
  31. end;
  32. TEventListenerSet = specialize TutlHashSet<TEventListener>;
  33. ////////////////////////////////////////////////////////////////////////////
  34. TEventHandlerCallback = procedure(aSender: TObject; aEvent: TEvent) of object;
  35. TCallbackEventListener = class(TEventListener)
  36. public
  37. Callback: TEventHandlerCallback;
  38. Filter: TEventTypeMask;
  39. function DispatchEvent(const aEvent: TEvent): Boolean; override;
  40. end;
  41. private
  42. fEventQueue: TEventList;
  43. fEventQueueLock: TCriticalSection;
  44. fEventListener: TEventListenerSet;
  45. procedure DispatchEvent(const aEvent: TEvent);
  46. protected
  47. procedure PushEvent(const aEvent: TEvent); virtual;
  48. procedure RecordEvent(const aEvent: TEvent); virtual;
  49. public
  50. procedure RegisterListener(const aEventMask: TEventTypeMask; const aCallback: TEventHandlerCallback);
  51. procedure RegisterListener(const aListener: TEventListener);
  52. procedure UnregisterListener(const aHandler: TEventHandlerCallback);
  53. procedure UnregisterListener(const aListener: TEventListener);
  54. procedure DispatchEvents;
  55. constructor Create;
  56. destructor Destroy; override;
  57. public
  58. class function MakeMask (const aTypes: array of TEventType): TEventTypeMask;
  59. class function CombineMasks(const aMasks: array of TEventTypeMask): TEventTypeMask;
  60. class function MaskHasType (const aMask: TEventTypeMask; const aType: TEventType): Boolean; inline;
  61. end;
  62. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  63. TutlWinControlEventManager = class(TutlEventManager)
  64. public type
  65. ////////////////////////////////////////////////////////////////////////////
  66. TMouseEvent = class(TEvent)
  67. public
  68. Button: TMouseButton;
  69. ClientPos: TPoint;
  70. ScreenPos: TPoint;
  71. procedure Assign(const aEvent: TEvent); override;
  72. end;
  73. ////////////////////////////////////////////////////////////////////////////
  74. TMouseWheelEvent = class(TEvent)
  75. public
  76. WheelDelta: Integer;
  77. ClientPos: TPoint;
  78. ScreenPos: TPoint;
  79. procedure Assign(const aEvent: TEvent); override;
  80. end;
  81. ////////////////////////////////////////////////////////////////////////////
  82. TKeyEvent = class(TEvent)
  83. public
  84. CharCode: WideChar;
  85. KeyCode: Word;
  86. procedure Assign(const aEvent: TEvent); override;
  87. end;
  88. ////////////////////////////////////////////////////////////////////////////
  89. TWindowEvent = class(TEvent)
  90. public
  91. ScreenRect: TRect;
  92. ClientWidth: Cardinal;
  93. ClientHeight: Cardinal;
  94. procedure Assign(const aEvent: TEvent); override;
  95. end;
  96. ////////////////////////////////////////////////////////////////////////////
  97. TMouseButtons = set of TMouseButton;
  98. TKeyboardState = record
  99. Modifiers: TShiftState;
  100. KeyState: array[Byte] of Boolean;
  101. end;
  102. TMouseState = record
  103. ScreenPos, ClientPos: TPoint;
  104. Buttons: TMouseButtons;
  105. end;
  106. TWindowState = record
  107. Active: boolean;
  108. ScreenRect: TRect;
  109. ClientWidth: Integer;
  110. ClientHeight: Integer;
  111. end;
  112. public const
  113. MOUSE_DOWN = 0;
  114. MOUSE_UP = 1;
  115. MOUSE_WHEEL_UP = 2;
  116. MOUSE_WHEEL_DOWN = 3;
  117. MOUSE_MOVE = 4;
  118. MOUSE_ENTER = 5;
  119. MOUSE_LEAVE = 6;
  120. MOUSE_CLICK = 7;
  121. MOUSE_DBL_CLICK = 8;
  122. KEY_DOWN = 10;
  123. KEY_REPEAT = 11;
  124. KEY_UP = 12;
  125. WINDOW_RESIZE = 15;
  126. WINDOW_ACTIVATE = 16;
  127. WINDOW_DEACTIVATE = 17;
  128. EVENTS_MOUSE: TEventTypeMask =
  129. (1 shl MOUSE_DOWN) or
  130. (1 shl MOUSE_UP) or
  131. (1 shl MOUSE_WHEEL_UP) or
  132. (1 shl MOUSE_WHEEL_DOWN) or
  133. (1 shl MOUSE_MOVE) or
  134. (1 shl MOUSE_ENTER) or
  135. (1 shl MOUSE_LEAVE) or
  136. (1 shl MOUSE_CLICK) or
  137. (1 shl MOUSE_DBL_CLICK);
  138. EVENTS_KEYBOARD: TEventTypeMask =
  139. (1 shl KEY_DOWN) or
  140. (1 shl KEY_REPEAT) or
  141. (1 shl KEY_UP);
  142. EVENTS_WINDOW: TEventTypeMask =
  143. (1 shl WINDOW_RESIZE) or
  144. (1 shl WINDOW_ACTIVATE) or
  145. (1 shl WINDOW_DEACTIVATE);
  146. private
  147. fKeyboard: TKeyboardState;
  148. fMouse: TMouseState;
  149. fWindow: TWindowState;
  150. private
  151. procedure HandlerMouseDown (Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  152. procedure HandlerMouseUp (Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  153. procedure HandlerMouseMove (Sender: TObject; Shift: TShiftState; X, Y: Integer);
  154. procedure HandlerMouseEnter (Sender: TObject);
  155. procedure HandlerMouseLeave (Sender: TObject);
  156. procedure HandlerClick (Sender: TObject);
  157. procedure HandlerDblClick (Sender: TObject);
  158. procedure HandlerMouseWheel (Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
  159. procedure HandlerKeyDown (Sender: TObject; var Key: Word; Shift: TShiftState);
  160. procedure HandlerKeyUp (Sender: TObject; var Key: Word; Shift: TShiftState);
  161. procedure HandlerResize (Sender: TObject);
  162. procedure HandlerActivate (Sender: TObject);
  163. procedure HandlerDeactivate (Sender: TObject);
  164. protected
  165. procedure RecordEvent(const aEvent: TEvent); override;
  166. protected
  167. function CreateMouseEvent (aEvent: TMouseEvent; aType: TEventType; aButton: TMouseButton; aClientPos, aScreenPos: TPoint): TMouseEvent; virtual;
  168. function CreateMouseWheelEvent(aEvent: TMouseWheelEvent; aSender: TWinControl; aDelta: Integer; aClientPos: TPoint): TMouseWheelEvent; virtual;
  169. function CreateKeyEvent (aEvent: TKeyEvent; aType: TEventType; aKey: Word): TKeyEvent; virtual;
  170. function CreateWindowEvent (aEvent: TWindowEvent; aType: TEventType; aSender: TControl): TWindowEvent; virtual;
  171. public
  172. property Keyboard: TKeyboardState read fKeyboard;
  173. property Mouse: TMouseState read fMouse;
  174. property Window: TWindowState read fWindow;
  175. procedure AttachEvents(const aControl: TWinControl; const aMask: TEventTypeMask);
  176. end;
  177. implementation
  178. uses
  179. LCLIntf, Forms,
  180. uutlTiming, uutlConversion, uutlKeyCodes;
  181. type
  182. TWinControlVisibilityClass = class(TWinControl)
  183. published
  184. property OnMouseDown;
  185. property OnMouseMove;
  186. property OnMouseUp;
  187. property OnMouseWheel;
  188. property OnMouseEnter;
  189. property OnMouseLeave;
  190. property OnClick;
  191. property OnDblClick;
  192. end;
  193. TCustomFormVisibilityClass = class(TCustomForm)
  194. published
  195. property OnActivate;
  196. property OnDeactivate;
  197. end;
  198. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  199. //TutlEventManager.TEvent////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  200. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  201. function TutlEventManager.TEvent.Clone: TEvent;
  202. begin
  203. result := TEventClass(ClassType).Create;
  204. result.Assign(self);
  205. end;
  206. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  207. procedure TutlEventManager.TEvent.Assign(const aEvent: TEvent);
  208. begin
  209. Timestamp := aEvent.Timestamp;
  210. end;
  211. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  212. constructor TutlEventManager.TEvent.Create;
  213. begin
  214. inherited Create;
  215. Timestamp := GetMicroTime;
  216. end;
  217. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  218. //TutlEventManager.TEventListener////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  219. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  220. function TutlEventManager.TEventListener.DispatchEvent(const aEvent: TEvent): Boolean;
  221. begin
  222. result := false;
  223. end;
  224. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  225. //TutlEventManager.TCallbackEventListener////////////////////////////////////////////////////////////////////////////////////////////////////////////
  226. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  227. function TutlEventManager.TCallbackEventListener.DispatchEvent(const aEvent: TEvent): Boolean;
  228. begin
  229. result := inherited DispatchEvent(aEvent);
  230. if TutlEventManager.MaskHasType(Filter, aEvent.EventType) then
  231. Callback(self, aEvent);
  232. end;
  233. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  234. //TutlEventManager///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  235. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  236. procedure TutlEventManager.DispatchEvent(const aEvent: TEvent);
  237. var
  238. l: TEventListener;
  239. begin
  240. for l in fEventListener do begin
  241. if l.DispatchEvent(aEvent) then
  242. break;
  243. end;
  244. end;
  245. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  246. procedure TutlEventManager.PushEvent(const aEvent: TEvent);
  247. begin
  248. fEventQueueLock.Enter;
  249. try
  250. if Assigned(fEventQueue) then
  251. fEventQueue.Add(aEvent)
  252. else if Assigned(aEvent) then
  253. aEvent.Free;
  254. finally
  255. fEventQueueLock.Leave;
  256. end;
  257. end;
  258. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  259. procedure TutlEventManager.RecordEvent(const aEvent: TEvent);
  260. begin
  261. // DUMMY
  262. end;
  263. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  264. procedure TutlEventManager.RegisterListener(const aEventMask: TEventTypeMask; const aCallback: TEventHandlerCallback);
  265. var
  266. l: TCallbackEventListener;
  267. begin
  268. UnregisterListener(aCallback);
  269. l := TCallbackEventListener.Create;
  270. try
  271. l.Filter := aEventMask;
  272. l.Callback := aCallback;
  273. RegisterListener(l);
  274. except
  275. FreeAndNil(l);
  276. end;
  277. end;
  278. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  279. procedure TutlEventManager.RegisterListener(const aListener: TEventListener);
  280. begin
  281. fEventListener.Add(aListener);
  282. end;
  283. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  284. procedure TutlEventManager.UnregisterListener(const aHandler: TEventHandlerCallback);
  285. var
  286. i: Integer;
  287. m1, m2: TMethod;
  288. cel: TCallbackEventListener;
  289. begin
  290. m1 := TMethod(aHandler);
  291. for i := fEventListener.Count-1 downto 0 do
  292. if Supports(fEventListener[i], TCallbackEventListener, cel) then begin
  293. m2 := TMethod(cel.Callback);
  294. if (m1.Data = m2.Data) and
  295. (m1.Code = m2.Code) then
  296. fEventListener.Delete(i);
  297. end;
  298. end;
  299. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  300. procedure TutlEventManager.UnregisterListener(const aListener: TEventListener);
  301. begin
  302. fEventListener.Remove(aListener);
  303. end;
  304. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  305. procedure TutlEventManager.DispatchEvents;
  306. var
  307. e: TEvent;
  308. begin
  309. fEventQueueLock.Acquire;
  310. try
  311. if Assigned(fEventQueue) then begin
  312. for e in fEventQueue do begin
  313. DispatchEvent(e);
  314. RecordEvent(e);
  315. end;
  316. fEventQueue.Clear;
  317. end;
  318. finally
  319. fEventQueueLock.Release;
  320. end;
  321. end;
  322. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  323. constructor TutlEventManager.Create;
  324. begin
  325. inherited Create;
  326. fEventListener := TEventListenerSet.Create(true);
  327. fEventQueue := TEventList.Create(true);
  328. fEventQueueLock := TCriticalSection.Create;
  329. end;
  330. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  331. destructor TutlEventManager.Destroy;
  332. begin
  333. fEventQueueLock.Enter;
  334. try
  335. FreeAndNil(fEventQueue);
  336. finally
  337. fEventQueueLock.Leave;
  338. end;
  339. FreeAndNil(fEventQueueLock);
  340. FreeAndNil(fEventListener);
  341. inherited Destroy;
  342. end;
  343. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  344. class function TutlEventManager.MakeMask(const aTypes: array of TEventType): TEventTypeMask;
  345. var
  346. e: TEventType;
  347. begin
  348. result := 0;
  349. for e in aTypes do
  350. result := result or (1 shl e);
  351. end;
  352. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  353. class function TutlEventManager.CombineMasks(const aMasks: array of TEventTypeMask): TEventTypeMask;
  354. var
  355. m: TEventTypeMask;
  356. begin
  357. result := 0;
  358. for m in aMasks do
  359. result := result or m;
  360. end;
  361. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  362. class function TutlEventManager.MaskHasType(const aMask: TEventTypeMask; const aType: TEventType): Boolean;
  363. begin
  364. result := ((aMask and (1 shl aType)) <> 0);
  365. end;
  366. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  367. //TutlWinControlEventManager.TMouseEvent/////////////////////////////////////////////////////////////////////////////////////////////////////////////
  368. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  369. procedure TutlWinControlEventManager.TMouseEvent.Assign(const aEvent: TEvent);
  370. var
  371. me: TMouseEvent;
  372. begin
  373. inherited Assign(aEvent);
  374. if Supports(aEvent, TMouseEvent, me) then begin
  375. Button := me.Button;
  376. ClientPos := me.ClientPos;
  377. ScreenPos := me.ScreenPos;
  378. end;
  379. end;
  380. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  381. //TutlWinControlEventManager.TMouseWheelEvent////////////////////////////////////////////////////////////////////////////////////////////////////////
  382. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  383. procedure TutlWinControlEventManager.TMouseWheelEvent.Assign(const aEvent: TEvent);
  384. var
  385. mwe: TMouseWheelEvent;
  386. begin
  387. inherited Assign(aEvent);
  388. if Supports(aEvent, TMouseWheelEvent, mwe) then begin
  389. WheelDelta := mwe.WheelDelta;
  390. ClientPos := mwe.ClientPos;
  391. ScreenPos := mwe.ScreenPos;
  392. end;
  393. end;
  394. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  395. //TutlWinControlEventManager.TKeyEvent///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  396. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  397. procedure TutlWinControlEventManager.TKeyEvent.Assign(const aEvent: TEvent);
  398. var
  399. ke: TKeyEvent;
  400. begin
  401. inherited Assign(aEvent);
  402. if Supports(aEvent, TKeyEvent, ke) then begin
  403. CharCode := ke.CharCode;
  404. KeyCode := ke.KeyCode;
  405. end;
  406. end;
  407. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  408. //TutlWinControlEventManager.TWindowEvent////////////////////////////////////////////////////////////////////////////////////////////////////////////
  409. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  410. procedure TutlWinControlEventManager.TWindowEvent.Assign(const aEvent: TEvent);
  411. var
  412. we: TWindowEvent;
  413. begin
  414. inherited Assign(aEvent);
  415. if Supports(aEvent, TWindowEvent, we) then begin
  416. ScreenRect := we.ScreenRect;
  417. ClientWidth := we.ClientWidth;
  418. ClientHeight := we.ClientHeight;
  419. end;
  420. end;
  421. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  422. //TutlWinControlEventManager/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  423. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  424. procedure TutlWinControlEventManager.HandlerMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  425. begin
  426. PushEvent(CreateMouseEvent(nil, MOUSE_DOWN, Button, Point(X, Y), TWinControl(Sender).ClientToScreen(Point(X, Y))));
  427. end;
  428. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  429. procedure TutlWinControlEventManager.HandlerMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  430. begin
  431. PushEvent(CreateMouseEvent(nil, MOUSE_UP, Button, Point(X, Y), TWinControl(Sender).ClientToScreen(Point(X, Y))));
  432. end;
  433. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  434. procedure TutlWinControlEventManager.HandlerMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  435. begin
  436. PushEvent(CreateMouseEvent(nil, MOUSE_MOVE, mbLeft, Point(X, Y), TWinControl(Sender).ClientToScreen(Point(X, Y))));
  437. end;
  438. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  439. procedure TutlWinControlEventManager.HandlerMouseEnter(Sender: TObject);
  440. begin
  441. PushEvent(CreateMouseEvent(nil, MOUSE_ENTER, mbLeft, TWinControl(Sender).ScreenToClient(Controls.Mouse.CursorPos), Controls.Mouse.CursorPos));
  442. end;
  443. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  444. procedure TutlWinControlEventManager.HandlerMouseLeave(Sender: TObject);
  445. begin
  446. PushEvent(CreateMouseEvent(nil, MOUSE_LEAVE, mbLeft, TWinControl(Sender).ScreenToClient(Controls.Mouse.CursorPos), Controls.Mouse.CursorPos));
  447. end;
  448. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  449. procedure TutlWinControlEventManager.HandlerClick(Sender: TObject);
  450. begin
  451. PushEvent(CreateMouseEvent(nil, MOUSE_CLICK, mbLeft, TWinControl(Sender).ScreenToClient(Controls.Mouse.CursorPos), Controls.Mouse.CursorPos));
  452. end;
  453. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  454. procedure TutlWinControlEventManager.HandlerDblClick(Sender: TObject);
  455. begin
  456. PushEvent(CreateMouseEvent(nil, MOUSE_DBL_CLICK, mbLeft, TWinControl(Sender).ScreenToClient(Controls.Mouse.CursorPos), Controls.Mouse.CursorPos));
  457. end;
  458. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  459. procedure TutlWinControlEventManager.HandlerMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
  460. begin
  461. PushEvent(CreateMouseWheelEvent(nil, TWinControl(Sender), WheelDelta, MousePos));
  462. Handled := false;
  463. end;
  464. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  465. procedure TutlWinControlEventManager.HandlerKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  466. begin
  467. PushEvent(CreateKeyEvent(nil, KEY_DOWN, Key));
  468. end;
  469. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  470. procedure TutlWinControlEventManager.HandlerKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
  471. begin
  472. PushEvent(CreateKeyEvent(nil, KEY_UP, Key));
  473. end;
  474. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  475. procedure TutlWinControlEventManager.HandlerResize(Sender: TObject);
  476. begin
  477. PushEvent(CreateWindowEvent(nil, WINDOW_RESIZE, TControl(Sender)));
  478. end;
  479. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  480. procedure TutlWinControlEventManager.HandlerActivate(Sender: TObject);
  481. begin
  482. PushEvent(CreateWindowEvent(nil, WINDOW_ACTIVATE, TControl(Sender)));
  483. end;
  484. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  485. procedure TutlWinControlEventManager.HandlerDeactivate(Sender: TObject);
  486. begin
  487. PushEvent(CreateWindowEvent(nil, WINDOW_DEACTIVATE, TControl(Sender)));
  488. end;
  489. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  490. procedure TutlWinControlEventManager.RecordEvent(const aEvent: TEvent);
  491. var
  492. me: TMouseEvent;
  493. ke: TKeyEvent;
  494. we: TWindowEvent;
  495. function GetPressedButtons: TMouseButtons;
  496. begin
  497. result := [];
  498. if (GetKeyState(VK_LBUTTON) < 0) then
  499. result := result + [mbLeft];
  500. if (GetKeyState(VK_RBUTTON) < 0) then
  501. result := result + [mbRight];
  502. if (GetKeyState(VK_MBUTTON) < 0) then
  503. result := result + [mbMiddle];
  504. if (GetKeyState(VK_XBUTTON1) < 0) then
  505. result := result + [mbExtra1];
  506. if (GetKeyState(VK_XBUTTON2) < 0) then
  507. result := result + [mbExtra2];
  508. end;
  509. begin
  510. inherited RecordEvent(aEvent);
  511. if Supports(aEvent, TMouseEvent, me) then begin
  512. fMouse.ClientPos := me.ClientPos;
  513. fMouse.ScreenPos := me.ScreenPos;
  514. case me.EventType of
  515. MOUSE_DOWN:
  516. Include(fMouse.Buttons, me.Button);
  517. MOUSE_UP:
  518. Exclude(fMouse.Buttons, me.Button);
  519. MOUSE_LEAVE:
  520. fMouse.Buttons := [];
  521. MOUSE_ENTER:
  522. fMouse.Buttons := GetPressedButtons;
  523. end;
  524. end else if Supports(aEvent, TKeyEvent, ke) then begin
  525. case ke.EventType of
  526. KEY_DOWN,
  527. KEY_REPEAT: begin
  528. fKeyboard.KeyState[ke.KeyCode and $FF] := true;
  529. case ke.KeyCode of
  530. VK_SHIFT: Include(fKeyboard.Modifiers, ssShift);
  531. VK_MENU: Include(fKeyboard.Modifiers, ssAlt);
  532. VK_CONTROL: Include(fKeyboard.Modifiers, ssCtrl);
  533. end;
  534. end;
  535. KEY_UP: begin
  536. fKeyboard.KeyState[ke.KeyCode and $FF] := false;
  537. case ke.KeyCode of
  538. VK_SHIFT: Exclude(fKeyboard.Modifiers, ssShift);
  539. VK_MENU: Exclude(fKeyboard.Modifiers, ssAlt);
  540. VK_CONTROL: Exclude(fKeyboard.Modifiers, ssCtrl);
  541. end;
  542. end;
  543. end;
  544. if ([ssCtrl, ssAlt] - fKeyboard.Modifiers = [])
  545. then include(fKeyboard.Modifiers, ssAltGr)
  546. else exclude(fKeyboard.Modifiers, ssAltGr);
  547. end else if Supports(aEvent, TWindowEvent, we) then begin
  548. case we.EventType of
  549. WINDOW_ACTIVATE:
  550. fWindow.Active := true;
  551. WINDOW_DEACTIVATE:
  552. fWindow.Active := false;
  553. WINDOW_RESIZE: begin
  554. fWindow.ScreenRect := we.ScreenRect;
  555. fWindow.ClientWidth := we.ClientWidth;
  556. fWindow.ClientHeight := we.ClientHeight;
  557. end;
  558. end;
  559. end;
  560. end;
  561. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  562. function TutlWinControlEventManager.CreateMouseEvent(aEvent: TMouseEvent; aType: TEventType; aButton: TMouseButton; aClientPos, aScreenPos: TPoint): TMouseEvent;
  563. begin
  564. result := aEvent;
  565. if not Assigned(result) then
  566. result := TMouseEvent.Create;
  567. result.EventType := aType;
  568. result.Button := aButton;
  569. result.ClientPos := aClientPos;
  570. result.ScreenPos := aScreenPos;
  571. end;
  572. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  573. function TutlWinControlEventManager.CreateMouseWheelEvent(aEvent: TMouseWheelEvent; aSender: TWinControl; aDelta: Integer; aClientPos: TPoint): TMouseWheelEvent;
  574. begin
  575. result := aEvent;
  576. if not Assigned(result) then
  577. result := TMouseWheelEvent.Create;
  578. result.ClientPos := aClientPos;
  579. result.ScreenPos := aSender.ClientToScreen(aClientPos);
  580. result.WheelDelta := aDelta;
  581. if (aDelta < 0)
  582. then result.EventType := MOUSE_WHEEL_DOWN
  583. else result.EventType := MOUSE_WHEEL_UP;
  584. end;
  585. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  586. function TutlWinControlEventManager.CreateKeyEvent(aEvent: TKeyEvent; aType: TEventType; aKey: Word): TKeyEvent;
  587. begin
  588. result := aEvent;
  589. if not Assigned(result) then
  590. result := TKeyEvent.Create;
  591. result.EventType := aType;
  592. if (aType = KEY_DOWN) and fKeyboard.KeyState[aKey and $FF] then
  593. result.EventType := KEY_REPEAT;
  594. result.KeyCode := aKey;
  595. result.CharCode := VKCodeToCharCode(aKey, fKeyboard.Modifiers);
  596. end;
  597. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  598. function TutlWinControlEventManager.CreateWindowEvent(aEvent: TWindowEvent; aType: TEventType; aSender: TControl): TWindowEvent;
  599. var
  600. p: TPoint;
  601. begin
  602. p := aSender.ScreenToClient(Point(0, 0));
  603. result := aEvent;
  604. if not Assigned(result) then
  605. result := TWindowEvent.Create;
  606. result.EventType := aType;
  607. result.ClientWidth := aSender.ClientWidth;
  608. result.ClientHeight := aSender.ClientHeight;
  609. result.ScreenRect := Rect(p.x, p.y, p.x + result.ClientWidth, p.y + result.ClientHeight);
  610. end;
  611. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  612. procedure TutlWinControlEventManager.AttachEvents(const aControl: TWinControl; const aMask: TEventTypeMask);
  613. var
  614. ctl: TWinControlVisibilityClass;
  615. frm: TCustomFormVisibilityClass;
  616. begin
  617. ctl := TWinControlVisibilityClass(aControl);
  618. // mouse events
  619. if MaskHasType(aMask, MOUSE_DOWN) then ctl.OnMouseDown := @HandlerMouseDown;
  620. if MaskHasType(aMask, MOUSE_UP) then ctl.OnMouseUp := @HandlerMouseUp;
  621. if MaskHasType(aMask, MOUSE_MOVE) then ctl.OnMouseMove := @HandlerMouseMove;
  622. if MaskHasType(aMask, MOUSE_ENTER) then ctl.OnMouseEnter := @HandlerMouseEnter;
  623. if MaskHasType(aMask, MOUSE_LEAVE) then ctl.OnMouseLeave := @HandlerMouseLeave;
  624. if MaskHasType(aMask, MOUSE_CLICK) then ctl.OnClick := @HandlerClick;
  625. if MaskHasType(aMask, MOUSE_DBL_CLICK) then ctl.OnDblClick := @HandlerDblClick;
  626. if MaskHasType(aMask, MOUSE_WHEEL_DOWN) or
  627. MaskHasType(aMask, MOUSE_WHEEL_UP) then ctl.OnMouseWheel := @HandlerMouseWheel;
  628. // key events
  629. if MaskHasType(aMask, KEY_DOWN) then ctl.OnKeyDown := @HandlerKeyDown;
  630. if MaskHasType(aMask, KEY_UP) then ctl.OnKeyUp := @HandlerKeyUp;
  631. // window events
  632. if MaskHasType(aMask, WINDOW_RESIZE) then begin
  633. ctl.OnResize := @HandlerResize;
  634. fWindow.ClientWidth := ctl.ClientWidth;
  635. fWindow.ClientHeight := ctl.ClientHeight;
  636. end;
  637. if (aControl is TCustomForm) then begin
  638. frm := TCustomFormVisibilityClass(aControl);
  639. frm.KeyPreview := true;
  640. if MaskHasType(aMask, WINDOW_ACTIVATE) then frm.OnActivate := @HandlerActivate;
  641. if MaskHasType(aMask, WINDOW_DEACTIVATE) then frm.OnDeactivate := @HandlerDeactivate;
  642. end;
  643. end;
  644. end.