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.
 
 

713 lines
21 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, uutlGenerics, syncobjs, uutlTiming, Controls, Forms, uutlMessageThread, uutlMessages;
  9. type
  10. TutlEventType = (
  11. MOUSE_DOWN = 10,
  12. MOUSE_UP,
  13. MOUSE_WHEEL_UP,
  14. MOUSE_WHEEL_DOWN,
  15. MOUSE_MOVE,
  16. MOUSE_ENTER,
  17. MOUSE_LEAVE,
  18. MOUSE_CLICK,
  19. MOUSE_DBL_CLICK,
  20. KEY_DOWN = 20,
  21. KEY_REPEAT,
  22. KEY_UP,
  23. WINDOW_RESIZE = 30,
  24. WINDOW_ACTIVATE,
  25. WINDOW_DEACTIVATE
  26. );
  27. TutlEventTypes = set of TutlEventType;
  28. { TutlInputEvent }
  29. TutlInputEvent = class
  30. protected
  31. function CreateInstance: TutlInputEvent; virtual;
  32. procedure Assign(const aEvent: TutlInputEvent); virtual;
  33. public
  34. Timestamp: QWord;
  35. EventType: TutlEventType;
  36. function Clone: TutlInputEvent;
  37. constructor Create(aType: TutlEventType);
  38. end;
  39. TutlInputEventList = specialize TutlList<TutlInputEvent>;
  40. { TutlMouseEvent }
  41. TutlMouseEvent = class(TutlInputEvent)
  42. protected
  43. function CreateInstance: TutlInputEvent; override;
  44. procedure Assign(const aEvent: TutlInputEvent); override;
  45. public
  46. Button: TMouseButton;
  47. ClientPos,
  48. ScreenPos: TPoint;
  49. constructor Create(aType: TutlEventType; aButton: TMouseButton; aClientPos, aScreenPos: TPoint);
  50. constructor Create(aType: TutlEventType; aClientPos, aScreenPos: TPoint);
  51. end;
  52. { TutlKeyEvent }
  53. TutlKeyEvent = class(TutlInputEvent)
  54. protected
  55. function CreateInstance: TutlInputEvent; override;
  56. procedure Assign(const aEvent: TutlInputEvent); override;
  57. public
  58. CharCode: WideChar;
  59. KeyCode: Word;
  60. constructor Create(aType: TutlEventType; aCharCode: WideChar; aKeyCode: Word);
  61. end;
  62. { TutlWindowEvent }
  63. TutlWindowEvent = class(TutlInputEvent)
  64. protected
  65. function CreateInstance: TutlInputEvent; override;
  66. procedure Assign(const aEvent: TutlInputEvent); override;
  67. public
  68. ScreenRect: TRect;
  69. ClientWidth,
  70. ClientHeight: Cardinal;
  71. constructor Create(aType: TutlEventType; aScreenRect: TRect; aClientWidth, aClientHeight: Cardinal);
  72. constructor Create(aType: TutlEventType; aScreenTopLeft: TPoint; aClientWidth, aClientHeight: Cardinal);
  73. end;
  74. { TutlEventManager }
  75. TutlInputEventHandler = procedure (Sender: TObject; Event: TutlInputEvent; var DoneEvent: boolean) of object;
  76. TMouseButtons = set of TMouseButton;
  77. TutlEventManager = class
  78. private type
  79. TInputState = record
  80. Keyboard: record
  81. Modifiers: TShiftState;
  82. KeyState: array[Byte] of Boolean;
  83. end;
  84. Mouse: record
  85. ScreenPos, ClientPos: TPoint;
  86. Buttons: TMouseButtons;
  87. end;
  88. Window: record
  89. Active: boolean;
  90. ScreenRect: TRect;
  91. ClientWidth: Integer;
  92. ClientHeight: Integer;
  93. end;
  94. end;
  95. TEventListener = class
  96. ThreadID: TThreadID;
  97. Synchronous: Boolean;
  98. Filter: TutlEventTypes;
  99. Handler: TutlInputEventHandler;
  100. end;
  101. TEventListenerList = specialize TutlList<TEventListener>;
  102. TInputEventMsg = class(TutlCallbackMsg)
  103. private
  104. fSender: TObject;
  105. fHandler: TutlInputEventHandler;
  106. fInputEvent: TutlInputEvent;
  107. public
  108. procedure ExecuteCallback; override;
  109. constructor Create(const aSender: TObject; const aHandler: TutlInputEventHandler; const aInputEvent: TutlInputEvent);
  110. destructor Destroy; override;
  111. end;
  112. TSyncInputEventMsg = class(TutlSyncCallbackMsg)
  113. private
  114. fSender: TObject;
  115. fHandler: TutlInputEventHandler;
  116. fInputEvent: TutlInputEvent;
  117. fDoneEvent: Boolean;
  118. public
  119. property DoneEvent: Boolean read fDoneEvent;
  120. procedure ExecuteCallback; override;
  121. constructor Create(const aSender: TObject; const aHandler: TutlInputEventHandler; const aInputEvent: TutlInputEvent);
  122. destructor Destroy; override;
  123. end;
  124. private
  125. fEventQueue: TutlInputEventList;
  126. fEventQueueLock: TCriticalSection;
  127. fListeners: TEventListenerList;
  128. protected
  129. fCanonicalState: TInputState;
  130. procedure EventHandlerMouseDown(Sender: TObject; Button: TMouseButton; {%H-}Shift: TShiftState; X, Y: Integer);
  131. procedure EventHandlerMouseUp(Sender: TObject; Button: TMouseButton; {%H-}Shift: TShiftState; X, Y: Integer);
  132. procedure EventHandlerMouseWheel(Sender: TObject; {%H-}Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
  133. procedure EventHandlerMouseMove(Sender: TObject; {%H-}Shift: TShiftState; X, Y: Integer);
  134. procedure EventHandlerMouseEnter(Sender: TObject);
  135. procedure EventHandlerMouseLeave(Sender: TObject);
  136. procedure EventHandlerClick(Sender: TObject);
  137. procedure EventHandlerDblClick(Sender: TObject);
  138. procedure EventHandlerKeyDown(Sender: TObject; var Key: Word; {%H-}Shift: TShiftState);
  139. procedure EventHandlerKeyUp(Sender: TObject; var Key: Word; {%H-}Shift: TShiftState);
  140. procedure EventHandlerResize(Sender: TObject);
  141. procedure EventHandlerActivate(Sender: TObject);
  142. procedure EventHandlerDeactivate(Sender: TObject);
  143. function QueuePush(const aEvent: TutlInputEvent): TutlInputEvent;
  144. function DispatchEvent(const aEvent: TutlInputEvent): boolean;
  145. procedure RecordEvent(const aEvent: TutlInputEvent);
  146. public
  147. property CanonicalState: TInputState read fCanonicalState;
  148. procedure AttachEvents(const fControl: TCustomForm; aEventMask: TutlEventTypes);
  149. function IsKeyDown(const aChar: Char): Boolean;
  150. procedure RegisterListener(const aEventMask: TutlEventTypes; const aHandler: TutlInputEventHandler; const aSynchronous: Boolean = false);
  151. procedure UnregisterListener(const aHandler: TutlInputEventHandler);
  152. procedure DispatchEvents;
  153. constructor Create;
  154. destructor Destroy; override;
  155. end;
  156. function utlEventManager: TutlEventManager;
  157. const
  158. utlInput_Events_Mouse = [MOUSE_DOWN, MOUSE_UP, MOUSE_WHEEL_UP, MOUSE_WHEEL_DOWN, MOUSE_MOVE,
  159. MOUSE_ENTER, MOUSE_LEAVE, MOUSE_CLICK, MOUSE_DBL_CLICK];
  160. utlInput_Events_Keyboard = [KEY_DOWN, KEY_REPEAT, KEY_UP];
  161. utlInput_Events_Window = [WINDOW_RESIZE, WINDOW_ACTIVATE, WINDOW_DEACTIVATE];
  162. utlInput_Events_All = utlInput_Events_Mouse+utlInput_Events_Keyboard+utlInput_Events_Window;
  163. implementation
  164. uses uutlKeyCodes, uutlLogger, LCLIntf;
  165. type
  166. TCustomFormVisibilityClass = class(TCustomForm)
  167. published
  168. property OnMouseDown;
  169. property OnMouseMove;
  170. property OnMouseUp;
  171. property OnMouseWheel;
  172. property OnMouseEnter;
  173. property OnMouseLeave;
  174. property OnActivate;
  175. property OnDeactivate;
  176. property OnClick;
  177. property OnDblClick;
  178. end;
  179. var
  180. utlEventManager_Singleton: TutlEventManager;
  181. function utlEventManager: TutlEventManager;
  182. begin
  183. if not Assigned(utlEventManager_Singleton) then
  184. utlEventManager_Singleton := TutlEventManager.Create;
  185. result := utlEventManager_Singleton;
  186. end;
  187. { TSyncInputEventMsg }
  188. procedure TutlEventManager.TSyncInputEventMsg.ExecuteCallback;
  189. begin
  190. fHandler(fSender, fInputEvent, fDoneEvent);
  191. end;
  192. constructor TutlEventManager.TSyncInputEventMsg.Create(const aSender: TObject;
  193. const aHandler: TutlInputEventHandler; const aInputEvent: TutlInputEvent);
  194. begin
  195. inherited Create;
  196. fSender := aSender;
  197. fInputEvent := aInputEvent.Clone;
  198. fHandler := aHandler;
  199. fDoneEvent := false;
  200. end;
  201. destructor TutlEventManager.TSyncInputEventMsg.Destroy;
  202. begin
  203. FreeAndNil(fInputEvent);
  204. inherited Destroy;
  205. end;
  206. { TInputEventMsg }
  207. procedure TutlEventManager.TInputEventMsg.ExecuteCallback;
  208. var
  209. done: Boolean;
  210. begin
  211. done := false;
  212. fHandler(fSender, fInputEvent, done);
  213. end;
  214. constructor TutlEventManager.TInputEventMsg.Create(const aSender: TObject;
  215. const aHandler: TutlInputEventHandler; const aInputEvent: TutlInputEvent);
  216. begin
  217. inherited Create;
  218. fSender := aSender;
  219. fInputEvent := aInputEvent.Clone;
  220. fHandler := aHandler;
  221. end;
  222. destructor TutlEventManager.TInputEventMsg.Destroy;
  223. begin
  224. FreeAndNil(fInputEvent);
  225. inherited Destroy;
  226. end;
  227. { TutlInputEvent }
  228. function TutlInputEvent.CreateInstance: TutlInputEvent;
  229. begin
  230. result := TutlInputEvent.Create(EventType);
  231. end;
  232. procedure TutlInputEvent.Assign(const aEvent: TutlInputEvent);
  233. begin
  234. EventType := aEvent.EventType;
  235. Timestamp := aEvent.Timestamp;
  236. end;
  237. function TutlInputEvent.Clone: TutlInputEvent;
  238. begin
  239. result := CreateInstance;
  240. result.Assign(self);
  241. end;
  242. constructor TutlInputEvent.Create(aType: TutlEventType);
  243. begin
  244. inherited Create;
  245. Timestamp:= GetMicroTime;
  246. EventType:= aType;
  247. end;
  248. { TutlMouseEvent }
  249. function TutlMouseEvent.CreateInstance: TutlInputEvent;
  250. begin
  251. result := TutlMouseEvent.Create(EventType, ClientPos, ScreenPos);
  252. end;
  253. procedure TutlMouseEvent.Assign(const aEvent: TutlInputEvent);
  254. var
  255. e: TutlMouseEvent;
  256. begin
  257. inherited Assign(aEvent);
  258. e := aEvent as TutlMouseEvent;
  259. Button := e.Button;
  260. ClientPos := e.ClientPos;
  261. ScreenPos := e.ScreenPos;
  262. end;
  263. constructor TutlMouseEvent.Create(aType: TutlEventType; aButton: TMouseButton; aClientPos, aScreenPos: TPoint);
  264. begin
  265. inherited Create(aType);
  266. Button:= aButton;
  267. ClientPos:= aClientPos;
  268. ScreenPos:= aScreenPos;
  269. end;
  270. constructor TutlMouseEvent.Create(aType: TutlEventType; aClientPos, aScreenPos: TPoint);
  271. begin
  272. inherited Create(aType);
  273. ClientPos:= aClientPos;
  274. ScreenPos:= aScreenPos;
  275. end;
  276. { TutlKeyEvent }
  277. function TutlKeyEvent.CreateInstance: TutlInputEvent;
  278. begin
  279. result := TutlKeyEvent.Create(EventType, CharCode, KeyCode);
  280. end;
  281. procedure TutlKeyEvent.Assign(const aEvent: TutlInputEvent);
  282. var
  283. e: TutlKeyEvent;
  284. begin
  285. inherited Assign(aEvent);
  286. e := (aEvent as TutlKeyEvent);
  287. CharCode := e.CharCode;
  288. KeyCode := e.KeyCode;
  289. end;
  290. constructor TutlKeyEvent.Create(aType: TutlEventType; aCharCode: WideChar; aKeyCode: Word);
  291. begin
  292. inherited Create(aType);
  293. CharCode:= aCharCode;
  294. KeyCode:= aKeyCode;
  295. end;
  296. { TutlWindowEvent }
  297. function TutlWindowEvent.CreateInstance: TutlInputEvent;
  298. begin
  299. result := TutlWindowEvent.Create(EventType, ScreenRect, ClientWidth, ClientHeight);
  300. end;
  301. procedure TutlWindowEvent.Assign(const aEvent: TutlInputEvent);
  302. var
  303. e: TutlWindowEvent;
  304. begin
  305. inherited Assign(aEvent);
  306. e := (aEvent as TutlWindowEvent);
  307. ScreenRect := e.ScreenRect;
  308. ClientWidth := e.ClientWidth;
  309. ClientHeight := e.ClientHeight;
  310. end;
  311. constructor TutlWindowEvent.Create(aType: TutlEventType; aScreenRect: TRect; aClientWidth,
  312. aClientHeight: Cardinal);
  313. begin
  314. inherited Create(aType);
  315. ScreenRect:= aScreenRect;
  316. ClientWidth:= aClientWidth;
  317. ClientHeight:= aClientHeight;
  318. end;
  319. constructor TutlWindowEvent.Create(aType: TutlEventType; aScreenTopLeft: TPoint; aClientWidth, aClientHeight: Cardinal);
  320. begin
  321. inherited Create(aType);
  322. ClientWidth:= aClientWidth;
  323. ClientHeight:= aClientHeight;
  324. ScreenRect.TopLeft:= aScreenTopLeft;
  325. ScreenRect.BottomRight:= aScreenTopLeft;
  326. inc(ScreenRect.Right, ClientWidth);
  327. inc(ScreenRect.Bottom, ClientHeight);
  328. end;
  329. { TutlEventManager }
  330. {$REGION EventHandler}
  331. procedure TutlEventManager.EventHandlerMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  332. begin
  333. QueuePush(TutlMouseEvent.Create(MOUSE_DOWN, Button, Point(X,Y), TWinControl(Sender).ClientToScreen(Point(X,Y))));
  334. end;
  335. procedure TutlEventManager.EventHandlerMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  336. begin
  337. QueuePush(TutlMouseEvent.Create(MOUSE_MOVE, Point(X,Y), TWinControl(Sender).ClientToScreen(Point(X,Y))));
  338. end;
  339. procedure TutlEventManager.EventHandlerMouseEnter(Sender: TObject);
  340. begin
  341. QueuePush(TutlMouseEvent.Create(MOUSE_ENTER, TWinControl(Sender).ScreenToClient(Mouse.CursorPos), Mouse.CursorPos));
  342. end;
  343. procedure TutlEventManager.EventHandlerMouseLeave(Sender: TObject);
  344. begin
  345. QueuePush(TutlMouseEvent.Create(MOUSE_LEAVE, TWinControl(Sender).ScreenToClient(Mouse.CursorPos), Mouse.CursorPos));
  346. end;
  347. procedure TutlEventManager.EventHandlerClick(Sender: TObject);
  348. begin
  349. QueuePush(TutlMouseEvent.Create(MOUSE_CLICK, TWinControl(Sender).ScreenToClient(Mouse.CursorPos), Mouse.CursorPos));
  350. end;
  351. procedure TutlEventManager.EventHandlerDblClick(Sender: TObject);
  352. begin
  353. QueuePush(TutlMouseEvent.Create(MOUSE_DBL_CLICK, TWinControl(Sender).ScreenToClient(Mouse.CursorPos), Mouse.CursorPos));
  354. end;
  355. procedure TutlEventManager.EventHandlerMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  356. begin
  357. QueuePush(TutlMouseEvent.Create(MOUSE_UP, Button, Point(X,Y), TWinControl(Sender).ClientToScreen(Point(X,Y))));
  358. end;
  359. procedure TutlEventManager.EventHandlerMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
  360. begin
  361. if WheelDelta < 0 then
  362. QueuePush(TutlMouseEvent.Create(MOUSE_WHEEL_DOWN, MousePos, TWinControl(Sender).ClientToScreen(MousePos)))
  363. else
  364. QueuePush(TutlMouseEvent.Create(MOUSE_WHEEL_UP, MousePos, TWinControl(Sender).ClientToScreen(MousePos)));
  365. Handled:= false;
  366. end;
  367. procedure TutlEventManager.EventHandlerKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  368. var
  369. ch: WideChar;
  370. begin
  371. ch:= VKCodeToCharCode(Key, fCanonicalState.Keyboard.Modifiers);
  372. if fCanonicalState.Keyboard.KeyState[Key and $FF] then
  373. QueuePush(TutlKeyEvent.Create(KEY_REPEAT, ch, Key))
  374. else
  375. QueuePush(TutlKeyEvent.Create(KEY_DOWN, ch, Key));
  376. end;
  377. procedure TutlEventManager.EventHandlerKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
  378. var
  379. ch: WideChar;
  380. begin
  381. ch:= VKCodeToCharCode(Key, fCanonicalState.Keyboard.Modifiers);
  382. QueuePush(TutlKeyEvent.Create(KEY_UP, ch, Key));
  383. end;
  384. procedure TutlEventManager.EventHandlerResize(Sender: TObject);
  385. var
  386. w: TControl;
  387. begin
  388. w := (Sender as TControl);
  389. QueuePush(TutlWindowEvent.Create(WINDOW_RESIZE, w.ClientToScreen(Point(0,0)), w.ClientWidth, w.ClientHeight));
  390. end;
  391. procedure TutlEventManager.EventHandlerActivate(Sender: TObject);
  392. var
  393. w: TControl;
  394. begin
  395. w := (Sender as TControl);
  396. QueuePush(TutlWindowEvent.Create(WINDOW_ACTIVATE, w.ClientToScreen(Point(0,0)), w.ClientWidth, w.ClientHeight));
  397. end;
  398. procedure TutlEventManager.EventHandlerDeactivate(Sender: TObject);
  399. var
  400. w: TControl;
  401. begin
  402. w := (Sender as TControl);
  403. QueuePush(TutlWindowEvent.Create(WINDOW_DEACTIVATE, w.ClientToScreen(Point(0,0)), w.ClientWidth, w.ClientHeight));
  404. end;
  405. {$ENDREGION}
  406. function TutlEventManager.QueuePush(const aEvent: TutlInputEvent): TutlInputEvent;
  407. begin
  408. fEventQueueLock.Acquire;
  409. try
  410. if Assigned(fEventQueue) then
  411. fEventQueue.Add(aEvent);
  412. Result:= aEvent;
  413. finally
  414. fEventQueueLock.Release;
  415. end;
  416. end;
  417. function TutlEventManager.DispatchEvent(const aEvent: TutlInputEvent): boolean;
  418. var
  419. i: integer;
  420. ls: TEventListener;
  421. msg: TSyncInputEventMsg;
  422. begin
  423. Result:= false;
  424. for i:= 0 to fListeners.Count-1 do begin
  425. if aEvent.EventType in fListeners[i].Filter then begin
  426. ls := fListeners[i];
  427. if (GetCurrentThreadId <> ls.ThreadID) then begin
  428. if (ls.Synchronous) then begin
  429. msg := TSyncInputEventMsg.Create(self, ls.Handler, aEvent);
  430. if utlSendMessage(ls.ThreadID, msg, 5000) = wrSignaled then begin
  431. result := msg.DoneEvent;
  432. msg.Free; //only free on wrSignal, otherwise thread will free message
  433. end
  434. end else
  435. utlPostMessage(ls.ThreadID, TInputEventMsg.Create(self, ls.Handler, aEvent));
  436. end else
  437. fListeners[i].Handler(Self, aEvent, Result);
  438. end;
  439. if Result then
  440. break;
  441. end;
  442. end;
  443. procedure TutlEventManager.RecordEvent(const aEvent: TutlInputEvent);
  444. function GetPressedButtons: TMouseButtons;
  445. begin
  446. result := [];
  447. if (GetKeyState(VK_LBUTTON) < 0) then
  448. result := result + [mbLeft];
  449. if (GetKeyState(VK_RBUTTON) < 0) then
  450. result := result + [mbRight];
  451. if (GetKeyState(VK_MBUTTON) < 0) then
  452. result := result + [mbMiddle];
  453. if (GetKeyState(VK_XBUTTON1) < 0) then
  454. result := result + [mbExtra1];
  455. if (GetKeyState(VK_XBUTTON2) < 0) then
  456. result := result + [mbExtra2];
  457. end;
  458. begin
  459. if aEvent is TutlMouseEvent then
  460. with TutlMouseEvent(aEvent) do begin
  461. fCanonicalState.Mouse.ClientPos := ClientPos;
  462. fCanonicalState.Mouse.ScreenPos := ScreenPos;
  463. case EventType of
  464. MOUSE_DOWN:
  465. Include(fCanonicalState.Mouse.Buttons, Button);
  466. MOUSE_UP:
  467. Exclude(fCanonicalState.Mouse.Buttons, Button);
  468. MOUSE_LEAVE:
  469. fCanonicalState.Mouse.Buttons := [];
  470. MOUSE_ENTER:
  471. fCanonicalState.Mouse.Buttons := GetPressedButtons;
  472. MOUSE_CLICK,
  473. MOUSE_DBL_CLICK,
  474. MOUSE_MOVE,
  475. MOUSE_WHEEL_DOWN,
  476. MOUSE_WHEEL_UP: ; //nothing to record here
  477. end;
  478. end
  479. else if aEvent is TutlKeyEvent then
  480. with TutlKeyEvent(aEvent) do begin
  481. case EventType of
  482. KEY_DOWN,
  483. KEY_REPEAT: begin
  484. fCanonicalState.Keyboard.KeyState[KeyCode and $FF]:= true;
  485. case KeyCode of
  486. VK_SHIFT: include(fCanonicalState.Keyboard.Modifiers, ssShift);
  487. VK_MENU: include(fCanonicalState.Keyboard.Modifiers, ssAlt);
  488. VK_CONTROL: include(fCanonicalState.Keyboard.Modifiers, ssCtrl);
  489. end;
  490. end;
  491. KEY_UP: begin
  492. fCanonicalState.Keyboard.KeyState[KeyCode and $FF]:= false;
  493. case KeyCode of
  494. VK_SHIFT: Exclude(fCanonicalState.Keyboard.Modifiers, ssShift);
  495. VK_MENU: Exclude(fCanonicalState.Keyboard.Modifiers, ssAlt);
  496. VK_CONTROL: Exclude(fCanonicalState.Keyboard.Modifiers, ssCtrl);
  497. end;
  498. end;
  499. end;
  500. if [ssCtrl, ssAlt] - fCanonicalState.Keyboard.Modifiers = [] then
  501. include(fCanonicalState.Keyboard.Modifiers, ssAltGr)
  502. else
  503. exclude(fCanonicalState.Keyboard.Modifiers, ssAltGr);
  504. end
  505. else if aEvent is TutlWindowEvent then
  506. with TutlWindowEvent(aEvent) do begin
  507. case EventType of
  508. WINDOW_ACTIVATE: fCanonicalState.Window.Active:= true;
  509. WINDOW_DEACTIVATE: fCanonicalState.Window.Active:= true;
  510. WINDOW_RESIZE: begin
  511. fCanonicalState.Window.ScreenRect := ScreenRect;
  512. fCanonicalState.Window.ClientWidth := ClientWidth;
  513. fCanonicalState.Window.ClientHeight := ClientHeight;
  514. end;
  515. end;
  516. end
  517. end;
  518. procedure TutlEventManager.DispatchEvents;
  519. var
  520. i: integer;
  521. begin
  522. fEventQueueLock.Acquire;
  523. try
  524. if Assigned(fEventQueue) then begin
  525. //process ALL events
  526. for i:= 0 to fEventQueue.Count-1 do begin
  527. DispatchEvent(fEventQueue[i]);
  528. RecordEvent(fEventQueue[i]);
  529. end;
  530. //now that we're done, free them
  531. fEventQueue.Clear;
  532. end;
  533. finally
  534. fEventQueueLock.Release;
  535. end;
  536. end;
  537. procedure TutlEventManager.AttachEvents(const fControl: TCustomForm; aEventMask: TutlEventTypes);
  538. var
  539. ctl: TCustomFormVisibilityClass;
  540. begin
  541. ctl:= TCustomFormVisibilityClass(fControl);
  542. ctl.KeyPreview:= true;
  543. if MOUSE_DOWN in aEventMask then ctl.OnMouseDown:= @EventHandlerMouseDown;
  544. if MOUSE_UP in aEventMask then ctl.OnMouseUp:= @EventHandlerMouseUp;
  545. if (MOUSE_WHEEL_DOWN in aEventMask) or
  546. (MOUSE_WHEEL_UP in aEventMask) then ctl.OnMouseWheel:= @EventHandlerMouseWheel;
  547. if MOUSE_MOVE in aEventMask then ctl.OnMouseMove:= @EventHandlerMouseMove;
  548. if MOUSE_ENTER in aEventMask then ctl.OnMouseEnter := @EventHandlerMouseEnter;
  549. if MOUSE_LEAVE in aEventMask then ctl.OnMouseLeave := @EventHandlerMouseLeave;
  550. if MOUSE_CLICK in aEventMask then ctl.OnClick := @EventHandlerClick;
  551. if MOUSE_DBL_CLICK in aEventMask then ctl.OnDblClick := @EventHandlerDblClick;
  552. if KEY_DOWN in aEventMask then ctl.OnKeyDown:= @EventHandlerKeyDown;
  553. if KEY_UP in aEventMask then ctl.OnKeyUp:= @EventHandlerKeyUp;
  554. if WINDOW_RESIZE in aEventMask then ctl.OnResize:= @EventHandlerResize;
  555. if WINDOW_ACTIVATE in aEventMask then ctl.OnActivate:= @EventHandlerActivate;
  556. if WINDOW_DEACTIVATE in aEventMask then ctl.OnDeactivate:= @EventHandlerDeactivate;
  557. end;
  558. function TutlEventManager.IsKeyDown(const aChar: Char): Boolean;
  559. begin
  560. result := CanonicalState.Keyboard.KeyState[Ord(UpCase(aChar))];
  561. end;
  562. procedure TutlEventManager.RegisterListener(const aEventMask: TutlEventTypes;
  563. const aHandler: TutlInputEventHandler; const aSynchronous: Boolean);
  564. var
  565. ls: TEventListener;
  566. begin
  567. UnregisterListener(aHandler);
  568. ls:= TEventListener.Create;
  569. try
  570. ls.Filter := aEventMask;
  571. ls.Handler := aHandler;
  572. ls.ThreadID := GetCurrentThreadId;
  573. ls.Synchronous := aSynchronous;
  574. fListeners.Add(ls);
  575. except
  576. ls.Free;
  577. end;
  578. end;
  579. procedure TutlEventManager.UnregisterListener(const aHandler: TutlInputEventHandler);
  580. var
  581. i: integer;
  582. m1, m2: TMethod;
  583. begin
  584. m1 := TMethod(aHandler);
  585. for i:= fListeners.Count-1 downto 0 do begin
  586. m2 := TMethod(fListeners[i].Handler);
  587. if (m1.Data = m2.Data) and
  588. (m2.Code = m2.Code)then
  589. fListeners.Delete(i);
  590. end;
  591. end;
  592. constructor TutlEventManager.Create;
  593. begin
  594. inherited Create;
  595. fEventQueue:= TutlInputEventList.Create(true);
  596. fEventQueueLock:= TCriticalSection.Create;
  597. fListeners:= TEventListenerList.Create(true);
  598. end;
  599. destructor TutlEventManager.Destroy;
  600. begin
  601. FreeAndNil(fListeners);
  602. fEventQueueLock.Acquire;
  603. try
  604. fEventQueue.Clear;
  605. FreeAndNil(fEventQueue);
  606. finally
  607. fEventQueueLock.Release;
  608. end;
  609. FreeAndNil(fEventQueueLock);
  610. inherited Destroy;
  611. end;
  612. finalization
  613. if Assigned(utlEventManager_Singleton) then
  614. FreeAndNil(utlEventManager_Singleton);
  615. end.