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
6
Event Handling unit for setting Keyboard and Mouse Handlers
8
See the file COPYING.FPC, included in this distribution,
9
for details about the copyright.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
**********************************************************************}
20
We need this unit to implement keyboard and mouse,
21
because win32 uses only one message queue for mouse and key events
28
TEventProcedure = Procedure(var ir:INPUT_RECORD);
30
{ these procedures must be used to set the event handlers }
31
{ these doesn't do something, they signal only the }
32
{ the upper layer that an event occured, this event }
33
{ must be handled with Win32-API function by the upper }
35
Procedure SetMouseEventHandler(p : TEventProcedure);
36
Procedure SetKeyboardEventHandler(p : TEventProcedure);
37
Procedure SetFocusEventHandler(p : TEventProcedure);
38
Procedure SetMenuEventHandler(p : TEventProcedure);
39
Procedure SetResizeEventHandler(p : TEventProcedure);
40
Procedure SetUnknownEventHandler(p : TEventProcedure);
42
{ these procedures must be used to get the event handlers }
43
Function GetMouseEventHandler : TEventProcedure;
44
Function GetKeyboardEventHandler : TEventProcedure;
45
Function GetFocusEventHandler : TEventProcedure;
46
Function GetMenuEventHandler : TEventProcedure;
47
Function GetResizeEventHandler : TEventProcedure;
48
Function GetUnknownEventHandler : TEventProcedure;
53
{ these procedures are called if an event occurs }
54
MouseEventHandler : TEventProcedure = nil;
55
KeyboardEventHandler : TEventProcedure = nil;
56
FocusEventHandler : TEventProcedure = nil;
57
MenuEventHandler : TEventProcedure = nil;
58
ResizeEventHandler : TEventProcedure = nil;
59
UnknownEventHandler : TEventProcedure = nil;
61
{ if this counter is zero, the event handler thread is killed }
62
InstalledHandlers : Byte = 0;
65
HandlerChanging : TCriticalSection;
66
EventThreadHandle : Handle;
67
EventThreadID : DWord;
69
{ true, if the event handler should be stoped }
70
ExitEventHandleThread : boolean;
72
Function GetMouseEventHandler : TEventProcedure;
74
GetMouseEventHandler:=MouseEventHandler;
78
Function GetKeyboardEventHandler : TEventProcedure;
80
GetKeyboardEventHandler:=KeyboardEventHandler;
84
Function GetFocusEventHandler : TEventProcedure;
86
GetFocusEventHandler:=FocusEventHandler;
90
Function GetMenuEventHandler : TEventProcedure;
92
GetMenuEventHandler:=MenuEventHandler;
96
Function GetResizeEventHandler : TEventProcedure;
98
GetResizeEventHandler:=ResizeEventHandler;
102
Function GetUnknownEventHandler : TEventProcedure;
104
GetUnknownEventHandler:=UnknownEventHandler;
108
Function EventHandleThread(p : pointer) : DWord;StdCall;
112
ir : array[0..irsize-1] of TInputRecord;
115
while not(ExitEventHandleThread) do
117
{ wait for an event }
118
WaitForSingleObject(StdInputHandle,INFINITE);
119
{ guard this code, else it is doomed to crash, if the
120
thread is switched between the assigned test and
121
the call and the handler is removed
123
if not(ExitEventHandleThread) then
125
EnterCriticalSection(HandlerChanging);
126
{ read, but don't remove the event }
127
if ReadConsoleInput(StdInputHandle,ir[0],irsize,dwRead) then
133
case ir[i].EventType of
136
if assigned(KeyboardEventHandler) then
137
KeyboardEventHandler(ir[i]);
142
if assigned(MouseEventHandler) then
143
MouseEventHandler(ir[i]);
146
WINDOW_BUFFER_SIZE_EVENT:
148
if assigned(ResizeEventHandler) then
149
ResizeEventHandler(ir[i]);
154
if assigned(MenuEventHandler) then
155
MenuEventHandler(ir[i]);
160
if assigned(FocusEventHandler) then
161
FocusEventHandler(ir[i]);
166
if assigned(UnknownEventHandler) then
167
UnknownEventHandler(ir[i]);
173
LeaveCriticalSection(HandlerChanging);
176
EventHandleThread:=0;
179
Procedure NewEventHandlerInstalled(p,oldp : TEventProcedure);
185
oldcount:=InstalledHandlers;
186
if Pointer(oldp)<>nil then
187
dec(InstalledHandlers);
188
if Pointer(p)<>nil then
189
inc(InstalledHandlers);
190
{ start event handler thread }
191
if (oldcount=0) and (InstalledHandlers=1) then
193
ExitEventHandleThread:=false;
194
EventThreadHandle:=CreateThread(nil,0,@EventHandleThread,
195
nil,0,EventThreadID);
197
{ stop and destroy event handler thread }
198
else if (oldcount=1) and (InstalledHandlers=0) then
200
ExitEventHandleThread:=true;
201
{ create a dummy event and sent it to the thread, so
202
we can leave WaitForSingleObject }
203
ir.EventType:=KEY_EVENT;
204
{ mouse event can be disabled by mouse.inc code
206
so use a key event instead PM }
207
WriteConsoleInput(StdInputHandle,ir,1,written);
208
{ wait, til the thread is ready }
209
WaitForSingleObject(EventThreadHandle,INFINITE);
210
CloseHandle(EventThreadHandle);
215
Procedure SetMouseEventHandler(p : TEventProcedure);
217
oldp : TEventProcedure;
219
EnterCriticalSection(HandlerChanging);
220
oldp:=MouseEventHandler;
221
MouseEventHandler:=p;
222
NewEventHandlerInstalled(MouseEventHandler,oldp);
223
LeaveCriticalSection(HandlerChanging);
227
Procedure SetKeyboardEventHandler(p : TEventProcedure);
229
oldp : TEventProcedure;
231
EnterCriticalSection(HandlerChanging);
232
oldp:=KeyboardEventHandler;
233
KeyboardEventHandler:=p;
234
NewEventHandlerInstalled(KeyboardEventHandler,oldp);
235
LeaveCriticalSection(HandlerChanging);
239
Procedure SetFocusEventHandler(p : TEventProcedure);
241
oldp : TEventProcedure;
243
EnterCriticalSection(HandlerChanging);
244
oldp:=FocusEventHandler;
245
FocusEventHandler:=p;
246
NewEventHandlerInstalled(FocusEventHandler,oldp);
247
LeaveCriticalSection(HandlerChanging);
251
Procedure SetMenuEventHandler(p : TEventProcedure);
253
oldp : TEventProcedure;
255
EnterCriticalSection(HandlerChanging);
256
oldp:=MenuEventHandler;
258
NewEventHandlerInstalled(MenuEventHandler,oldp);
259
LeaveCriticalSection(HandlerChanging);
263
Procedure SetResizeEventHandler(p : TEventProcedure);
265
oldp : TEventProcedure;
267
EnterCriticalSection(HandlerChanging);
268
oldp:=ResizeEventHandler;
269
ResizeEventHandler:=p;
270
NewEventHandlerInstalled(ResizeEventHandler,oldp);
271
LeaveCriticalSection(HandlerChanging);
275
Procedure SetUnknownEventHandler(p : TEventProcedure);
277
oldp : TEventProcedure;
279
EnterCriticalSection(HandlerChanging);
280
oldp:=UnknownEventHandler;
281
UnknownEventHandler:=p;
282
NewEventHandlerInstalled(UnknownEventHandler,oldp);
283
LeaveCriticalSection(HandlerChanging);
288
InitializeCriticalSection(HandlerChanging);
291
{ Uninstall all handlers }
292
{ this stops also the event handler thread }
293
SetMouseEventHandler(nil);
294
SetKeyboardEventHandler(nil);
295
SetFocusEventHandler(nil);
296
SetMenuEventHandler(nil);
297
SetResizeEventHandler(nil);
298
SetUnknownEventHandler(nil);
299
{ delete the critical section object }
300
DeleteCriticalSection(HandlerChanging);