winevent.pp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  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. EnterCriticalSection(HandlerChanging);
  99. { read, but don't remove the event }
  100. if ReadConsoleInput(StdInputHandle,ir[0],irsize,dwRead) then
  101. begin
  102. i:=0;
  103. while (i<dwRead) do
  104. begin
  105. { call the handler }
  106. case ir[i].EventType of
  107. KEY_EVENT:
  108. begin
  109. if assigned(KeyboardEventHandler) then
  110. KeyboardEventHandler(ir[i]);
  111. end;
  112. _MOUSE_EVENT:
  113. begin
  114. if assigned(MouseEventHandler) then
  115. MouseEventHandler(ir[i]);
  116. end;
  117. WINDOW_BUFFER_SIZE_EVENT:
  118. begin
  119. if assigned(ResizeEventHandler) then
  120. ResizeEventHandler(ir[i]);
  121. end;
  122. MENU_EVENT:
  123. begin
  124. if assigned(MenuEventHandler) then
  125. MenuEventHandler(ir[i]);
  126. end;
  127. FOCUS_EVENT:
  128. begin
  129. if assigned(FocusEventHandler) then
  130. FocusEventHandler(ir[i]);
  131. end;
  132. else
  133. begin
  134. if assigned(UnknownEventHandler) then
  135. UnknownEventHandler(ir[i]);
  136. end;
  137. end;
  138. inc(i);
  139. end;
  140. end;
  141. LeaveCriticalSection(HandlerChanging);
  142. end;
  143. end;
  144. EventHandleThread:=0;
  145. end;
  146. Procedure NewEventHandlerInstalled(p,oldp : TEventProcedure);
  147. var
  148. oldcount : Byte;
  149. ir : TInputRecord;
  150. written : DWord;
  151. begin
  152. oldcount:=InstalledHandlers;
  153. if Pointer(oldp)<>nil then
  154. dec(InstalledHandlers);
  155. if Pointer(p)<>nil then
  156. inc(InstalledHandlers);
  157. { start event handler thread }
  158. if (oldcount=0) and (InstalledHandlers=1) then
  159. begin
  160. ExitEventHandleThread:=false;
  161. EventThreadHandle:=CreateThread(nil,0,@EventHandleThread,
  162. nil,0,EventThreadID);
  163. end
  164. { stop and destroy event handler thread }
  165. else if (oldcount=1) and (InstalledHandlers=0) then
  166. begin
  167. ExitEventHandleThread:=true;
  168. { create a dummy event and sent it to the thread, so
  169. we can leave WaitForSingleObject }
  170. ir.EventType:=KEY_EVENT;
  171. { mouse event can be disabled by mouse.inc code
  172. in DoneMouse
  173. so use a key event instead PM }
  174. WriteConsoleInput(StdInputHandle,ir,1,written);
  175. { wait, til the thread is ready }
  176. WaitForSingleObject(EventThreadHandle,INFINITE);
  177. CloseHandle(EventThreadHandle);
  178. end;
  179. end;
  180. Procedure SetMouseEventHandler(p : TEventProcedure);
  181. var
  182. oldp : TEventProcedure;
  183. begin
  184. EnterCriticalSection(HandlerChanging);
  185. oldp:=MouseEventHandler;
  186. MouseEventHandler:=p;
  187. NewEventHandlerInstalled(MouseEventHandler,oldp);
  188. LeaveCriticalSection(HandlerChanging);
  189. end;
  190. Procedure SetKeyboardEventHandler(p : TEventProcedure);
  191. var
  192. oldp : TEventProcedure;
  193. begin
  194. EnterCriticalSection(HandlerChanging);
  195. oldp:=KeyboardEventHandler;
  196. KeyboardEventHandler:=p;
  197. NewEventHandlerInstalled(KeyboardEventHandler,oldp);
  198. LeaveCriticalSection(HandlerChanging);
  199. end;
  200. Procedure SetFocusEventHandler(p : TEventProcedure);
  201. var
  202. oldp : TEventProcedure;
  203. begin
  204. EnterCriticalSection(HandlerChanging);
  205. oldp:=FocusEventHandler;
  206. FocusEventHandler:=p;
  207. NewEventHandlerInstalled(FocusEventHandler,oldp);
  208. LeaveCriticalSection(HandlerChanging);
  209. end;
  210. Procedure SetMenuEventHandler(p : TEventProcedure);
  211. var
  212. oldp : TEventProcedure;
  213. begin
  214. EnterCriticalSection(HandlerChanging);
  215. oldp:=MenuEventHandler;
  216. MenuEventHandler:=p;
  217. NewEventHandlerInstalled(MenuEventHandler,oldp);
  218. LeaveCriticalSection(HandlerChanging);
  219. end;
  220. Procedure SetResizeEventHandler(p : TEventProcedure);
  221. var
  222. oldp : TEventProcedure;
  223. begin
  224. EnterCriticalSection(HandlerChanging);
  225. oldp:=ResizeEventHandler;
  226. ResizeEventHandler:=p;
  227. NewEventHandlerInstalled(ResizeEventHandler,oldp);
  228. LeaveCriticalSection(HandlerChanging);
  229. end;
  230. Procedure SetUnknownEventHandler(p : TEventProcedure);
  231. var
  232. oldp : TEventProcedure;
  233. begin
  234. EnterCriticalSection(HandlerChanging);
  235. oldp:=UnknownEventHandler;
  236. UnknownEventHandler:=p;
  237. NewEventHandlerInstalled(UnknownEventHandler,oldp);
  238. LeaveCriticalSection(HandlerChanging);
  239. end;
  240. initialization
  241. InitializeCriticalSection(HandlerChanging);
  242. finalization
  243. { Uninstall all handlers }
  244. { this stops also the event handler thread }
  245. SetMouseEventHandler(nil);
  246. SetKeyboardEventHandler(nil);
  247. SetFocusEventHandler(nil);
  248. SetMenuEventHandler(nil);
  249. SetResizeEventHandler(nil);
  250. SetUnknownEventHandler(nil);
  251. { delete the critical section object }
  252. DeleteCriticalSection(HandlerChanging);
  253. end.