winevent.pp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Florian Klaempfl
  4. member of the Free Pascal development team
  5. Event Handling unit for setting Keyboard and Mouse Handlers
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit WinEvent;
  13. interface
  14. {
  15. We need this unit to implement keyboard and mouse,
  16. because win32 uses only one message queue for mouse and key events
  17. }
  18. uses
  19. Windows;
  20. type
  21. TEventProcedure = Procedure(var ir:INPUT_RECORD);
  22. { these procedures must be used to set the event handlers }
  23. { these doesn't do something, they signal only the }
  24. { the upper layer that an event occured, this event }
  25. { must be handled with Win32-API function by the upper }
  26. { layer }
  27. Procedure SetMouseEventHandler(p : TEventProcedure);
  28. Procedure SetKeyboardEventHandler(p : TEventProcedure);
  29. Procedure SetFocusEventHandler(p : TEventProcedure);
  30. Procedure SetMenuEventHandler(p : TEventProcedure);
  31. Procedure SetResizeEventHandler(p : TEventProcedure);
  32. Procedure SetUnknownEventHandler(p : TEventProcedure);
  33. { these procedures must be used to get the event handlers }
  34. Function GetMouseEventHandler : TEventProcedure;
  35. Function GetKeyboardEventHandler : TEventProcedure;
  36. Function GetFocusEventHandler : TEventProcedure;
  37. Function GetMenuEventHandler : TEventProcedure;
  38. Function GetResizeEventHandler : TEventProcedure;
  39. Function GetUnknownEventHandler : TEventProcedure;
  40. implementation
  41. const
  42. { these procedures are called if an event occurs }
  43. MouseEventHandler : TEventProcedure = nil;
  44. KeyboardEventHandler : TEventProcedure = nil;
  45. FocusEventHandler : TEventProcedure = nil;
  46. MenuEventHandler : TEventProcedure = nil;
  47. ResizeEventHandler : TEventProcedure = nil;
  48. UnknownEventHandler : TEventProcedure = nil;
  49. { if this counter is zero, the event handler thread is killed }
  50. InstalledHandlers : Byte = 0;
  51. var
  52. HandlerChanging : TCriticalSection;
  53. EventThreadHandle : Handle;
  54. EventThreadID : DWord;
  55. { true, if the event handler should be stoped }
  56. ExitEventHandleThread : boolean;
  57. Function GetMouseEventHandler : TEventProcedure;
  58. begin
  59. GetMouseEventHandler:=MouseEventHandler;
  60. end;
  61. Function GetKeyboardEventHandler : TEventProcedure;
  62. begin
  63. GetKeyboardEventHandler:=KeyboardEventHandler;
  64. end;
  65. Function GetFocusEventHandler : TEventProcedure;
  66. begin
  67. GetFocusEventHandler:=FocusEventHandler;
  68. end;
  69. Function GetMenuEventHandler : TEventProcedure;
  70. begin
  71. GetMenuEventHandler:=MenuEventHandler;
  72. end;
  73. Function GetResizeEventHandler : TEventProcedure;
  74. begin
  75. GetResizeEventHandler:=ResizeEventHandler;
  76. end;
  77. Function GetUnknownEventHandler : TEventProcedure;
  78. begin
  79. GetUnknownEventHandler:=UnknownEventHandler;
  80. end;
  81. Function EventHandleThread(p : pointer) : DWord;StdCall;
  82. const
  83. irsize = 10;
  84. var
  85. ir : array[0..irsize-1] of TInputRecord;
  86. i,dwRead : DWord;
  87. begin
  88. while not(ExitEventHandleThread) do
  89. begin
  90. { wait for an event }
  91. WaitForSingleObject(StdInputHandle,INFINITE);
  92. { guard this code, else it is doomed to crash, if the
  93. thread is switched between the assigned test and
  94. the call and the handler is removed
  95. }
  96. if not(ExitEventHandleThread) then
  97. begin
  98. if ReadConsoleInput(StdInputHandle,ir[0],irsize,dwRead) then
  99. begin
  100. i:=0;
  101. EnterCriticalSection(HandlerChanging);
  102. while i<dwRead do
  103. begin
  104. { call the handler }
  105. case ir[i].EventType of
  106. KEY_EVENT:
  107. begin
  108. if assigned(KeyboardEventHandler) then
  109. KeyboardEventHandler(ir[i]);
  110. end;
  111. _MOUSE_EVENT:
  112. begin
  113. if assigned(MouseEventHandler) then
  114. MouseEventHandler(ir[i]);
  115. end;
  116. WINDOW_BUFFER_SIZE_EVENT:
  117. begin
  118. if assigned(ResizeEventHandler) then
  119. ResizeEventHandler(ir[i]);
  120. end;
  121. MENU_EVENT:
  122. begin
  123. if assigned(MenuEventHandler) then
  124. MenuEventHandler(ir[i]);
  125. end;
  126. FOCUS_EVENT:
  127. begin
  128. if assigned(FocusEventHandler) then
  129. FocusEventHandler(ir[i]);
  130. end;
  131. else
  132. begin
  133. if assigned(UnknownEventHandler) then
  134. UnknownEventHandler(ir[i]);
  135. end;
  136. end;
  137. inc(i);
  138. end;
  139. LeaveCriticalSection(HandlerChanging);
  140. end;
  141. end;
  142. end;
  143. EventHandleThread:=0;
  144. end;
  145. Procedure NewEventHandlerInstalled(p,oldp : TEventProcedure);
  146. var
  147. oldcount : Byte;
  148. ir : TInputRecord;
  149. written : DWord;
  150. begin
  151. oldcount:=InstalledHandlers;
  152. if Pointer(oldp)<>nil then
  153. dec(InstalledHandlers);
  154. if Pointer(p)<>nil then
  155. inc(InstalledHandlers);
  156. { start event handler thread }
  157. if (oldcount=0) and (InstalledHandlers=1) then
  158. begin
  159. ExitEventHandleThread:=false;
  160. EventThreadHandle:=CreateThread(nil,0,@EventHandleThread,
  161. nil,0,EventThreadID);
  162. end
  163. { stop and destroy event handler thread }
  164. else if (oldcount=1) and (InstalledHandlers=0) then
  165. begin
  166. ExitEventHandleThread:=true;
  167. { create a dummy event and sent it to the thread, so
  168. we can leave WaitForSingleObject }
  169. ir.EventType:=KEY_EVENT;
  170. { mouse event can be disabled by mouse.inc code
  171. in DoneMouse
  172. so use a key event instead PM }
  173. WriteConsoleInput(StdInputHandle,ir,1,written);
  174. { wait, til the thread is ready }
  175. WaitForSingleObject(EventThreadHandle,INFINITE);
  176. CloseHandle(EventThreadHandle);
  177. end;
  178. end;
  179. Procedure SetMouseEventHandler(p : TEventProcedure);
  180. var
  181. oldp : TEventProcedure;
  182. begin
  183. EnterCriticalSection(HandlerChanging);
  184. oldp:=MouseEventHandler;
  185. MouseEventHandler:=p;
  186. LeaveCriticalSection(HandlerChanging);
  187. NewEventHandlerInstalled(MouseEventHandler,oldp);
  188. end;
  189. Procedure SetKeyboardEventHandler(p : TEventProcedure);
  190. var
  191. oldp : TEventProcedure;
  192. begin
  193. EnterCriticalSection(HandlerChanging);
  194. oldp:=KeyboardEventHandler;
  195. KeyboardEventHandler:=p;
  196. LeaveCriticalSection(HandlerChanging);
  197. NewEventHandlerInstalled(KeyboardEventHandler,oldp);
  198. end;
  199. Procedure SetFocusEventHandler(p : TEventProcedure);
  200. var
  201. oldp : TEventProcedure;
  202. begin
  203. EnterCriticalSection(HandlerChanging);
  204. oldp:=FocusEventHandler;
  205. FocusEventHandler:=p;
  206. LeaveCriticalSection(HandlerChanging);
  207. NewEventHandlerInstalled(FocusEventHandler,oldp);
  208. end;
  209. Procedure SetMenuEventHandler(p : TEventProcedure);
  210. var
  211. oldp : TEventProcedure;
  212. begin
  213. EnterCriticalSection(HandlerChanging);
  214. oldp:=MenuEventHandler;
  215. MenuEventHandler:=p;
  216. LeaveCriticalSection(HandlerChanging);
  217. NewEventHandlerInstalled(MenuEventHandler,oldp);
  218. end;
  219. Procedure SetResizeEventHandler(p : TEventProcedure);
  220. var
  221. oldp : TEventProcedure;
  222. begin
  223. EnterCriticalSection(HandlerChanging);
  224. oldp:=ResizeEventHandler;
  225. ResizeEventHandler:=p;
  226. LeaveCriticalSection(HandlerChanging);
  227. NewEventHandlerInstalled(ResizeEventHandler,oldp);
  228. end;
  229. Procedure SetUnknownEventHandler(p : TEventProcedure);
  230. var
  231. oldp : TEventProcedure;
  232. begin
  233. EnterCriticalSection(HandlerChanging);
  234. oldp:=UnknownEventHandler;
  235. UnknownEventHandler:=p;
  236. LeaveCriticalSection(HandlerChanging);
  237. NewEventHandlerInstalled(UnknownEventHandler,oldp);
  238. end;
  239. initialization
  240. InitializeCriticalSection(HandlerChanging);
  241. finalization
  242. { Uninstall all handlers }
  243. { this stops also the event handler thread }
  244. SetMouseEventHandler(nil);
  245. SetKeyboardEventHandler(nil);
  246. SetFocusEventHandler(nil);
  247. SetMenuEventHandler(nil);
  248. SetResizeEventHandler(nil);
  249. SetUnknownEventHandler(nil);
  250. { delete the critical section object }
  251. DeleteCriticalSection(HandlerChanging);
  252. end.