2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Driver DLL
4 * FILE: win32ss/user/winsrv/consrv/condrv/coninput.c
5 * PURPOSE: Console Input functions
6 * PROGRAMMERS: Jeffrey Morlan
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 /* INCLUDES *******************************************************************/
17 /* PRIVATE FUNCTIONS **********************************************************/
19 // ConDrvAddInputEvents
21 AddInputEvents(PCONSOLE Console
,
22 PINPUT_RECORD InputRecords
, // InputEvent
23 ULONG NumEventsToWrite
,
24 PULONG NumEventsWritten
,
27 NTSTATUS Status
= STATUS_SUCCESS
;
29 BOOLEAN SetWaitEvent
= FALSE
;
31 if (NumEventsWritten
) *NumEventsWritten
= 0;
34 * When adding many single events, in the case of repeated mouse move or
35 * key down events, we try to coalesce them so that we do not saturate
36 * too quickly the input buffer.
38 if (NumEventsToWrite
== 1 && !IsListEmpty(&Console
->InputBuffer
.InputEvents
))
40 PINPUT_RECORD InputRecord
= InputRecords
; // Only one element
41 PINPUT_RECORD LastInputRecord
;
42 ConsoleInput
* ConInRec
; // Input
44 /* Get the "next" event of the input buffer */
47 /* Get the tail element */
48 ConInRec
= CONTAINING_RECORD(Console
->InputBuffer
.InputEvents
.Blink
,
49 ConsoleInput
, ListEntry
);
53 /* Get the head element */
54 ConInRec
= CONTAINING_RECORD(Console
->InputBuffer
.InputEvents
.Flink
,
55 ConsoleInput
, ListEntry
);
57 LastInputRecord
= &ConInRec
->InputEvent
;
59 if (InputRecord
->EventType
== MOUSE_EVENT
&&
60 InputRecord
->Event
.MouseEvent
.dwEventFlags
== MOUSE_MOVED
)
62 if (LastInputRecord
->EventType
== MOUSE_EVENT
&&
63 LastInputRecord
->Event
.MouseEvent
.dwEventFlags
== MOUSE_MOVED
)
65 /* Update the mouse position */
66 LastInputRecord
->Event
.MouseEvent
.dwMousePosition
.X
=
67 InputRecord
->Event
.MouseEvent
.dwMousePosition
.X
;
68 LastInputRecord
->Event
.MouseEvent
.dwMousePosition
.Y
=
69 InputRecord
->Event
.MouseEvent
.dwMousePosition
.Y
;
72 // return STATUS_SUCCESS;
73 Status
= STATUS_SUCCESS
;
76 else if (InputRecord
->EventType
== KEY_EVENT
&&
77 InputRecord
->Event
.KeyEvent
.bKeyDown
)
79 if (LastInputRecord
->EventType
== KEY_EVENT
&&
80 LastInputRecord
->Event
.KeyEvent
.bKeyDown
&&
81 (LastInputRecord
->Event
.KeyEvent
.wVirtualScanCode
== // Same scancode
82 InputRecord
->Event
.KeyEvent
.wVirtualScanCode
) &&
83 (LastInputRecord
->Event
.KeyEvent
.uChar
.UnicodeChar
== // Same character
84 InputRecord
->Event
.KeyEvent
.uChar
.UnicodeChar
) &&
85 (LastInputRecord
->Event
.KeyEvent
.dwControlKeyState
== // Same Ctrl/Alt/Shift state
86 InputRecord
->Event
.KeyEvent
.dwControlKeyState
) )
88 /* Update the repeat count */
89 LastInputRecord
->Event
.KeyEvent
.wRepeatCount
+=
90 InputRecord
->Event
.KeyEvent
.wRepeatCount
;
93 // return STATUS_SUCCESS;
94 Status
= STATUS_SUCCESS
;
99 /* If we coalesced the only one element, we can quit */
100 if (i
== 1 && Status
== STATUS_SUCCESS
/* && NumEventsToWrite == 1 */)
104 * No event coalesced, add them in the usual way.
109 /* Go to the beginning of the list */
110 // InputRecords = InputRecords;
114 /* Go to the end of the list */
115 InputRecords
= &InputRecords
[NumEventsToWrite
- 1];
118 /* Set the event if the list is going to be non-empty */
119 if (IsListEmpty(&Console
->InputBuffer
.InputEvents
))
122 for (i
= 0; i
< NumEventsToWrite
&& NT_SUCCESS(Status
); ++i
)
124 PINPUT_RECORD InputRecord
;
125 ConsoleInput
* ConInRec
;
129 /* Select the event and go to the next one */
130 InputRecord
= InputRecords
++;
134 /* Select the event and go to the previous one */
135 InputRecord
= InputRecords
--;
138 /* Add event to the queue */
139 ConInRec
= ConsoleAllocHeap(0, sizeof(ConsoleInput
));
140 if (ConInRec
== NULL
)
142 // return STATUS_INSUFFICIENT_RESOURCES;
143 Status
= STATUS_INSUFFICIENT_RESOURCES
;
147 ConInRec
->InputEvent
= *InputRecord
;
151 /* Append the event to the end of the queue */
152 InsertTailList(&Console
->InputBuffer
.InputEvents
, &ConInRec
->ListEntry
);
156 /* Append the event to the beginning of the queue */
157 InsertHeadList(&Console
->InputBuffer
.InputEvents
, &ConInRec
->ListEntry
);
160 // return STATUS_SUCCESS;
161 Status
= STATUS_SUCCESS
;
164 if (SetWaitEvent
) NtSetEvent(Console
->InputBuffer
.ActiveEvent
, NULL
);
167 if (NumEventsWritten
) *NumEventsWritten
= i
;
173 PurgeInputBuffer(PCONSOLE Console
)
175 PLIST_ENTRY CurrentEntry
;
178 while (!IsListEmpty(&Console
->InputBuffer
.InputEvents
))
180 CurrentEntry
= RemoveHeadList(&Console
->InputBuffer
.InputEvents
);
181 Event
= CONTAINING_RECORD(CurrentEntry
, ConsoleInput
, ListEntry
);
182 ConsoleFreeHeap(Event
);
185 // CloseHandle(Console->InputBuffer.ActiveEvent);
189 ConDrvInitInputBuffer(IN PCONSOLE Console
,
190 IN ULONG InputBufferSize
)
193 OBJECT_ATTRIBUTES ObjectAttributes
;
195 ConSrvInitObject(&Console
->InputBuffer
.Header
, INPUT_BUFFER
, Console
);
197 InitializeObjectAttributes(&ObjectAttributes
,
203 Status
= NtCreateEvent(&Console
->InputBuffer
.ActiveEvent
, EVENT_ALL_ACCESS
,
204 &ObjectAttributes
, NotificationEvent
, FALSE
);
205 if (!NT_SUCCESS(Status
))
208 Console
->InputBuffer
.InputBufferSize
= InputBufferSize
;
209 InitializeListHead(&Console
->InputBuffer
.InputEvents
);
210 Console
->InputBuffer
.Mode
= ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
|
211 ENABLE_ECHO_INPUT
| ENABLE_MOUSE_INPUT
;
213 return STATUS_SUCCESS
;
217 ConDrvDeinitInputBuffer(IN PCONSOLE Console
)
219 PurgeInputBuffer(Console
);
220 CloseHandle(Console
->InputBuffer
.ActiveEvent
);
224 /* PUBLIC DRIVER APIS *********************************************************/
227 ConDrvReadConsole(IN PCONSOLE Console
,
228 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
231 IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl
,
232 IN PVOID Parameter OPTIONAL
,
233 IN ULONG NumCharsToRead
,
234 OUT PULONG NumCharsRead OPTIONAL
)
236 // STATUS_PENDING : Wait if more to read ; STATUS_SUCCESS : Don't wait.
237 // NTSTATUS Status; = STATUS_PENDING;
239 if (Console
== NULL
|| InputBuffer
== NULL
|| /* Buffer == NULL || */
240 ReadControl
== NULL
|| ReadControl
->nLength
!= sizeof(CONSOLE_READCONSOLE_CONTROL
))
242 return STATUS_INVALID_PARAMETER
;
245 /* Validity checks */
246 ASSERT(Console
== InputBuffer
->Header
.Console
);
247 ASSERT((Buffer
!= NULL
) || (Buffer
== NULL
&& NumCharsToRead
== 0));
249 /* Call the line-discipline */
250 return TermReadStream(Console
,
260 ConDrvGetConsoleInput(IN PCONSOLE Console
,
261 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
262 IN BOOLEAN KeepEvents
,
263 IN BOOLEAN WaitForMoreEvents
,
264 OUT PINPUT_RECORD InputRecord
,
265 IN ULONG NumEventsToRead
,
266 OUT PULONG NumEventsRead OPTIONAL
)
268 PLIST_ENTRY CurrentInput
;
272 if (Console
== NULL
|| InputBuffer
== NULL
/* || InputRecord == NULL */)
273 return STATUS_INVALID_PARAMETER
;
275 /* Validity checks */
276 ASSERT(Console
== InputBuffer
->Header
.Console
);
277 ASSERT((InputRecord
!= NULL
) || (InputRecord
== NULL
&& NumEventsToRead
== 0));
279 if (NumEventsRead
) *NumEventsRead
= 0;
281 if (IsListEmpty(&InputBuffer
->InputEvents
))
284 * No input is available. Wait for more input if requested,
285 * otherwise, we don't wait, so we return success.
287 return (WaitForMoreEvents
? STATUS_PENDING
: STATUS_SUCCESS
);
290 /* Only get input if there is any */
291 CurrentInput
= InputBuffer
->InputEvents
.Flink
;
293 while ((CurrentInput
!= &InputBuffer
->InputEvents
) && (i
< NumEventsToRead
))
295 Input
= CONTAINING_RECORD(CurrentInput
, ConsoleInput
, ListEntry
);
297 *InputRecord
= Input
->InputEvent
;
301 CurrentInput
= CurrentInput
->Flink
;
303 /* Remove the events from the queue if needed */
306 RemoveEntryList(&Input
->ListEntry
);
307 ConsoleFreeHeap(Input
);
311 if (NumEventsRead
) *NumEventsRead
= i
;
313 if (IsListEmpty(&InputBuffer
->InputEvents
))
315 ResetEvent(InputBuffer
->ActiveEvent
);
318 // FIXME: If we add back UNICODE support, it's here that we need to do the translation.
320 /* We read all the inputs available, we return success */
321 return STATUS_SUCCESS
;
325 ConDrvWriteConsoleInput(IN PCONSOLE Console
,
326 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
327 IN BOOLEAN AppendToEnd
,
328 IN PINPUT_RECORD InputRecord
,
329 IN ULONG NumEventsToWrite
,
330 OUT PULONG NumEventsWritten OPTIONAL
)
332 if (Console
== NULL
|| InputBuffer
== NULL
/* || InputRecord == NULL */)
333 return STATUS_INVALID_PARAMETER
;
335 /* Validity checks */
336 ASSERT(Console
== InputBuffer
->Header
.Console
);
337 ASSERT((InputRecord
!= NULL
) || (InputRecord
== NULL
&& NumEventsToWrite
== 0));
339 /* Now, add the events */
340 if (NumEventsWritten
) *NumEventsWritten
= 0;
342 // FIXME: If we add back UNICODE support, it's here that we need to do the translation.
344 return AddInputEvents(Console
,
352 ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console
,
353 IN PCONSOLE_INPUT_BUFFER InputBuffer
)
355 PLIST_ENTRY CurrentEntry
;
358 if (Console
== NULL
|| InputBuffer
== NULL
)
359 return STATUS_INVALID_PARAMETER
;
362 ASSERT(Console
== InputBuffer
->Header
.Console
);
364 /* Discard all entries in the input event queue */
365 while (!IsListEmpty(&InputBuffer
->InputEvents
))
367 CurrentEntry
= RemoveHeadList(&InputBuffer
->InputEvents
);
368 Event
= CONTAINING_RECORD(CurrentEntry
, ConsoleInput
, ListEntry
);
369 ConsoleFreeHeap(Event
);
371 ResetEvent(InputBuffer
->ActiveEvent
);
373 return STATUS_SUCCESS
;
377 ConDrvGetConsoleNumberOfInputEvents(IN PCONSOLE Console
,
378 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
379 OUT PULONG NumberOfEvents
)
381 PLIST_ENTRY CurrentInput
;
383 if (Console
== NULL
|| InputBuffer
== NULL
|| NumberOfEvents
== NULL
)
384 return STATUS_INVALID_PARAMETER
;
387 ASSERT(Console
== InputBuffer
->Header
.Console
);
391 /* If there are any events ... */
392 CurrentInput
= InputBuffer
->InputEvents
.Flink
;
393 while (CurrentInput
!= &InputBuffer
->InputEvents
)
395 CurrentInput
= CurrentInput
->Flink
;
399 return STATUS_SUCCESS
;