Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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