event.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. {
  2. $Id$
  3. Event handling for the Win32 version of the FPC API
  4. Copyright (c) 1999 by Florian Klaempfl
  5. This library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Library General Public
  7. License as published by the Free Software Foundation; either
  8. version 2 of the License, or (at your option) any later version.
  9. This library 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. See the GNU
  12. Library General Public License for more details.
  13. You should have received a copy of the GNU Library General Public
  14. License along with this library; if not, write to the Free
  15. Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. }
  17. unit Event;
  18. {
  19. We need this unit to implement keyboard and mouse,
  20. because win32 uses only one message queue for mouse and key events
  21. }
  22. interface
  23. type
  24. TEventProcedure = Procedure;
  25. { these procedures must be used to set the event handlers }
  26. { these doesn't do something, they signal only the }
  27. { the upper layer that an event occured, this event }
  28. { must be handled with Win32-API function by the upper }
  29. { layer }
  30. Procedure SetMouseEventHandler(p : TEventProcedure);
  31. Procedure SetKeyboardEventHandler(p : TEventProcedure);
  32. Procedure SetFocusEventHandler(p : TEventProcedure);
  33. Procedure SetMenuEventHandler(p : TEventProcedure);
  34. Procedure SetResizeEventHandler(p : TEventProcedure);
  35. Procedure SetUnknownEventHandler(p : TEventProcedure);
  36. { these procedures must be used to get the event handlers }
  37. Function GetMouseEventHandler : TEventProcedure;
  38. Function GetKeyboardEventHandler : TEventProcedure;
  39. Function GetFocusEventHandler : TEventProcedure;
  40. Function GetMenuEventHandler : TEventProcedure;
  41. Function GetResizeEventHandler : TEventProcedure;
  42. Function GetUnknownEventHandler : TEventProcedure;
  43. implementation
  44. uses
  45. windows, dos;
  46. const
  47. { these procedures are called if an event occurs }
  48. MouseEventHandler : procedure = nil;
  49. KeyboardEventHandler : procedure = nil;
  50. FocusEventHandler : procedure = nil;
  51. MenuEventHandler : procedure = nil;
  52. ResizeEventHandler : procedure = nil;
  53. UnknownEventHandler : procedure = nil;
  54. { if this counter is zero, the event handler thread is killed }
  55. InstalledHandlers : Byte = 0;
  56. var
  57. HandlerChanging : TCriticalSection;
  58. OldExitProc : Pointer;
  59. EventThreadHandle : Handle;
  60. EventThreadID : DWord;
  61. { true, if the event handler should be stoped }
  62. ExitEventHandleThread : boolean;
  63. Function GetMouseEventHandler : TEventProcedure;
  64. begin
  65. GetMouseEventHandler:=MouseEventHandler;
  66. end;
  67. Function GetKeyboardEventHandler : TEventProcedure;
  68. begin
  69. GetKeyboardEventHandler:=KeyboardEventHandler;
  70. end;
  71. Function GetFocusEventHandler : TEventProcedure;
  72. begin
  73. GetFocusEventHandler:=FocusEventHandler;
  74. end;
  75. Function GetMenuEventHandler : TEventProcedure;
  76. begin
  77. GetMenuEventHandler:=MenuEventHandler;
  78. end;
  79. Function GetResizeEventHandler : TEventProcedure;
  80. begin
  81. GetResizeEventHandler:=ResizeEventHandler;
  82. end;
  83. Function GetUnknownEventHandler : TEventProcedure;
  84. begin
  85. GetUnknownEventHandler:=UnknownEventHandler;
  86. end;
  87. { removes an event from the event queue }
  88. { necessary, if no handler is installed }
  89. Procedure DestroyOneEvent;
  90. var
  91. ir : TInputRecord;
  92. dwRead : DWord;
  93. begin
  94. ReadConsoleInput(TextRec(Input).Handle,ir,1,dwRead);
  95. end;
  96. Function EventHandleThread(p : pointer) : DWord;StdCall;
  97. var
  98. ir : TInputRecord;
  99. dwRead : DWord;
  100. begin
  101. while not(ExitEventHandleThread) do
  102. begin
  103. { wait for an event }
  104. WaitForSingleObject(TextRec(Input).Handle,INFINITE);
  105. { guard this code, else it is doomed to crash, if the
  106. thread is switched between the assigned test and
  107. the call and the handler is removed
  108. }
  109. if not(ExitEventHandleThread) then
  110. begin
  111. EnterCriticalSection(HandlerChanging);
  112. { read, but don't remove the event }
  113. if (PeekConsoleInput(TextRec(Input).Handle,ir,1,dwRead)) and
  114. (dwRead>0) then
  115. { call the handler }
  116. case ir.EventType of
  117. KEY_EVENT:
  118. begin
  119. if assigned(KeyboardEventHandler) then
  120. KeyboardEventHandler
  121. else
  122. DestroyOneEvent;
  123. end;
  124. _MOUSE_EVENT:
  125. begin
  126. if assigned(MouseEventHandler) then
  127. MouseEventHandler
  128. else
  129. DestroyOneEvent;
  130. end;
  131. WINDOW_BUFFER_SIZE_EVENT:
  132. begin
  133. if assigned(ResizeEventHandler) then
  134. ResizeEventHandler
  135. else
  136. DestroyOneEvent;
  137. end;
  138. MENU_EVENT:
  139. begin
  140. if assigned(MenuEventHandler) then
  141. MenuEventHandler
  142. else
  143. DestroyOneEvent;
  144. end;
  145. FOCUS_EVENT:
  146. begin
  147. if assigned(FocusEventHandler) then
  148. FocusEventHandler
  149. else
  150. DestroyOneEvent;
  151. end;
  152. else
  153. begin
  154. if assigned(UnknownEventHandler) then
  155. UnknownEventHandler
  156. else
  157. DestroyOneEvent;
  158. end;
  159. end;
  160. LeaveCriticalSection(HandlerChanging);
  161. end;
  162. end;
  163. end;
  164. Procedure NewEventHandlerInstalled(p,oldp : TEventProcedure);
  165. var
  166. oldcount : Byte;
  167. ir : TInputRecord;
  168. written : DWord;
  169. begin
  170. oldcount:=InstalledHandlers;
  171. if Pointer(oldp)<>nil then
  172. dec(InstalledHandlers);
  173. if Pointer(p)<>nil then
  174. inc(InstalledHandlers);
  175. { start event handler thread }
  176. if (oldcount=0) and (InstalledHandlers=1) then
  177. begin
  178. ExitEventHandleThread:=false;
  179. EventThreadHandle:=CreateThread(nil,0,@EventHandleThread,
  180. nil,0,EventThreadID);
  181. end
  182. { stop and destroy event handler thread }
  183. else if (oldcount=1) and (InstalledHandlers=0) then
  184. begin
  185. ExitEventHandleThread:=true;
  186. { create a dummy event and sent it to the thread, so
  187. we can leave WatiForSingleObject }
  188. ir.EventType:=KEY_EVENT;
  189. { mouse event can be disabled by mouse.inc code
  190. in DoneMouse
  191. so use a key event instead PM }
  192. WriteConsoleInput(TextRec(Input).Handle,ir,1,written);
  193. { wait, til the thread is ready }
  194. WaitForSingleObject(EventThreadHandle,INFINITE);
  195. CloseHandle(EventThreadHandle);
  196. end;
  197. end;
  198. Procedure SetMouseEventHandler(p : TEventProcedure);
  199. var
  200. oldp : TEventProcedure;
  201. begin
  202. EnterCriticalSection(HandlerChanging);
  203. oldp:=MouseEventHandler;
  204. MouseEventHandler:=p;
  205. NewEventHandlerInstalled(MouseEventHandler,oldp);
  206. LeaveCriticalSection(HandlerChanging);
  207. end;
  208. Procedure SetKeyboardEventHandler(p : TEventProcedure);
  209. var
  210. oldp : TEventProcedure;
  211. begin
  212. EnterCriticalSection(HandlerChanging);
  213. oldp:=KeyboardEventHandler;
  214. KeyboardEventHandler:=p;
  215. NewEventHandlerInstalled(KeyboardEventHandler,oldp);
  216. LeaveCriticalSection(HandlerChanging);
  217. end;
  218. Procedure SetFocusEventHandler(p : TEventProcedure);
  219. var
  220. oldp : TEventProcedure;
  221. begin
  222. EnterCriticalSection(HandlerChanging);
  223. oldp:=FocusEventHandler;
  224. FocusEventHandler:=p;
  225. NewEventHandlerInstalled(FocusEventHandler,oldp);
  226. LeaveCriticalSection(HandlerChanging);
  227. end;
  228. Procedure SetMenuEventHandler(p : TEventProcedure);
  229. var
  230. oldp : TEventProcedure;
  231. begin
  232. EnterCriticalSection(HandlerChanging);
  233. oldp:=MenuEventHandler;
  234. MenuEventHandler:=p;
  235. NewEventHandlerInstalled(MenuEventHandler,oldp);
  236. LeaveCriticalSection(HandlerChanging);
  237. end;
  238. Procedure SetResizeEventHandler(p : TEventProcedure);
  239. var
  240. oldp : TEventProcedure;
  241. begin
  242. EnterCriticalSection(HandlerChanging);
  243. oldp:=ResizeEventHandler;
  244. ResizeEventHandler:=p;
  245. NewEventHandlerInstalled(ResizeEventHandler,oldp);
  246. LeaveCriticalSection(HandlerChanging);
  247. end;
  248. Procedure SetUnknownEventHandler(p : TEventProcedure);
  249. var
  250. oldp : TEventProcedure;
  251. begin
  252. EnterCriticalSection(HandlerChanging);
  253. oldp:=UnknownEventHandler;
  254. UnknownEventHandler:=p;
  255. NewEventHandlerInstalled(UnknownEventHandler,oldp);
  256. LeaveCriticalSection(HandlerChanging);
  257. end;
  258. Procedure DoExit;
  259. begin
  260. { Uninstall all handlers }
  261. { this stops also the event handler thread }
  262. SetMouseEventHandler(nil);
  263. SetKeyboardEventHandler(nil);
  264. SetFocusEventHandler(nil);
  265. SetMenuEventHandler(nil);
  266. SetResizeEventHandler(nil);
  267. SetUnknownEventHandler(nil);
  268. { delete the critical section object }
  269. DeleteCriticalSection(HandlerChanging);
  270. ExitProc:=OldExitProc;
  271. end;
  272. begin
  273. InitializeCriticalSection(HandlerChanging);
  274. OldExitProc:=ExitProc;
  275. ExitProc:=@DoExit;
  276. end.
  277. {
  278. $Log$
  279. Revision 1.1 2000-07-13 06:29:41 michael
  280. + Initial import
  281. Revision 1.1 2000/01/06 01:20:31 peter
  282. * moved out of packages/ back to topdir
  283. Revision 1.1 1999/11/24 23:36:38 peter
  284. * moved to packages dir
  285. Revision 1.5 1999/09/22 12:55:18 pierre
  286. * use KEY_EVENT for Closing Handle Thread
  287. Revision 1.4 1999/07/17 17:21:35 florian
  288. * fixed the win32 keyboard event handling
  289. Revision 1.3 1999/07/14 08:45:15 florian
  290. * commited a new keyboard by Armin Diehl
  291. * fixed event handling, mainly the prototype of eventhandlethread was wrong
  292. Revision 1.2 1999/06/21 16:43:51 peter
  293. * win32 updates from Maarten Bekkers
  294. Revision 1.1 1999/01/08 14:37:03 florian
  295. + initial version, not working yet
  296. }