2
0

winevent.pp 9.8 KB

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