[CONSRV]: Code cleaning.
[reactos.git] / win32ss / user / winsrv / consrv / condrv / coninput.c
1 /*
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)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <consrv.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS ********************************************************************/
18
19 typedef struct ConsoleInput_t
20 {
21 LIST_ENTRY ListEntry;
22 INPUT_RECORD InputEvent;
23 } ConsoleInput;
24
25
26 /* PRIVATE FUNCTIONS **********************************************************/
27
28 // ConDrvAddInputEvents
29 static NTSTATUS
30 AddInputEvents(PCONSOLE Console,
31 PINPUT_RECORD InputRecords, // InputEvent
32 ULONG NumEventsToWrite,
33 PULONG NumEventsWritten,
34 BOOLEAN AppendToEnd)
35 {
36 NTSTATUS Status = STATUS_SUCCESS;
37 ULONG i = 0;
38 BOOLEAN SetWaitEvent = FALSE;
39
40 if (NumEventsWritten) *NumEventsWritten = 0;
41
42 /*
43 * When adding many single events, in the case of repeated mouse move or
44 * key down events, we try to coalesce them so that we do not saturate
45 * too quickly the input buffer.
46 */
47 if (NumEventsToWrite == 1 && !IsListEmpty(&Console->InputBuffer.InputEvents))
48 {
49 PINPUT_RECORD InputRecord = InputRecords; // Only one element
50 PINPUT_RECORD LastInputRecord;
51 ConsoleInput* ConInRec; // Input
52
53 /* Get the "next" event of the input buffer */
54 if (AppendToEnd)
55 {
56 /* Get the tail element */
57 ConInRec = CONTAINING_RECORD(Console->InputBuffer.InputEvents.Blink,
58 ConsoleInput, ListEntry);
59 }
60 else
61 {
62 /* Get the head element */
63 ConInRec = CONTAINING_RECORD(Console->InputBuffer.InputEvents.Flink,
64 ConsoleInput, ListEntry);
65 }
66 LastInputRecord = &ConInRec->InputEvent;
67
68 if (InputRecord->EventType == MOUSE_EVENT &&
69 InputRecord->Event.MouseEvent.dwEventFlags == MOUSE_MOVED)
70 {
71 if (LastInputRecord->EventType == MOUSE_EVENT &&
72 LastInputRecord->Event.MouseEvent.dwEventFlags == MOUSE_MOVED)
73 {
74 /* Update the mouse position */
75 LastInputRecord->Event.MouseEvent.dwMousePosition.X =
76 InputRecord->Event.MouseEvent.dwMousePosition.X;
77 LastInputRecord->Event.MouseEvent.dwMousePosition.Y =
78 InputRecord->Event.MouseEvent.dwMousePosition.Y;
79
80 i = 1;
81 // return STATUS_SUCCESS;
82 Status = STATUS_SUCCESS;
83 }
84 }
85 else if (InputRecord->EventType == KEY_EVENT &&
86 InputRecord->Event.KeyEvent.bKeyDown)
87 {
88 if (LastInputRecord->EventType == KEY_EVENT &&
89 LastInputRecord->Event.KeyEvent.bKeyDown &&
90 (LastInputRecord->Event.KeyEvent.wVirtualScanCode == // Same scancode
91 InputRecord->Event.KeyEvent.wVirtualScanCode) &&
92 (LastInputRecord->Event.KeyEvent.uChar.UnicodeChar == // Same character
93 InputRecord->Event.KeyEvent.uChar.UnicodeChar) &&
94 (LastInputRecord->Event.KeyEvent.dwControlKeyState == // Same Ctrl/Alt/Shift state
95 InputRecord->Event.KeyEvent.dwControlKeyState) )
96 {
97 /* Update the repeat count */
98 LastInputRecord->Event.KeyEvent.wRepeatCount +=
99 InputRecord->Event.KeyEvent.wRepeatCount;
100
101 i = 1;
102 // return STATUS_SUCCESS;
103 Status = STATUS_SUCCESS;
104 }
105 }
106 }
107
108 /* If we coalesced the only one element, we can quit */
109 if (i == 1 && Status == STATUS_SUCCESS /* && NumEventsToWrite == 1 */)
110 goto Done;
111
112 /*
113 * No event coalesced, add them in the usual way.
114 */
115
116 if (AppendToEnd)
117 {
118 /* Go to the beginning of the list */
119 // InputRecords = InputRecords;
120 }
121 else
122 {
123 /* Go to the end of the list */
124 InputRecords = &InputRecords[NumEventsToWrite - 1];
125 }
126
127 /* Set the event if the list is going to be non-empty */
128 if (IsListEmpty(&Console->InputBuffer.InputEvents))
129 SetWaitEvent = TRUE;
130
131 for (i = 0; i < NumEventsToWrite && NT_SUCCESS(Status); ++i)
132 {
133 PINPUT_RECORD InputRecord;
134 ConsoleInput* ConInRec;
135
136 if (AppendToEnd)
137 {
138 /* Select the event and go to the next one */
139 InputRecord = InputRecords++;
140 }
141 else
142 {
143 /* Select the event and go to the previous one */
144 InputRecord = InputRecords--;
145 }
146
147 /* Add event to the queue */
148 ConInRec = ConsoleAllocHeap(0, sizeof(ConsoleInput));
149 if (ConInRec == NULL)
150 {
151 // return STATUS_INSUFFICIENT_RESOURCES;
152 Status = STATUS_INSUFFICIENT_RESOURCES;
153 continue;
154 }
155
156 ConInRec->InputEvent = *InputRecord;
157
158 if (AppendToEnd)
159 {
160 /* Append the event to the end of the queue */
161 InsertTailList(&Console->InputBuffer.InputEvents, &ConInRec->ListEntry);
162 }
163 else
164 {
165 /* Append the event to the beginning of the queue */
166 InsertHeadList(&Console->InputBuffer.InputEvents, &ConInRec->ListEntry);
167 }
168
169 // return STATUS_SUCCESS;
170 Status = STATUS_SUCCESS;
171 }
172
173 if (SetWaitEvent) SetEvent(Console->InputBuffer.ActiveEvent);
174
175 Done:
176 if (NumEventsWritten) *NumEventsWritten = i;
177
178 return Status;
179 }
180
181 VOID
182 PurgeInputBuffer(PCONSOLE Console)
183 {
184 PLIST_ENTRY CurrentEntry;
185 ConsoleInput* Event;
186
187 while (!IsListEmpty(&Console->InputBuffer.InputEvents))
188 {
189 CurrentEntry = RemoveHeadList(&Console->InputBuffer.InputEvents);
190 Event = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
191 ConsoleFreeHeap(Event);
192 }
193
194 CloseHandle(Console->InputBuffer.ActiveEvent);
195 }
196
197
198 /* PUBLIC DRIVER APIS *********************************************************/
199
200 NTSTATUS NTAPI
201 ConDrvReadConsole(IN PCONSOLE Console,
202 IN PCONSOLE_INPUT_BUFFER InputBuffer,
203 /**/IN PUNICODE_STRING ExeName /**/OPTIONAL/**/,/**/
204 IN BOOLEAN Unicode,
205 OUT PVOID Buffer,
206 IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl,
207 IN ULONG NumCharsToRead,
208 OUT PULONG NumCharsRead OPTIONAL)
209 {
210 // STATUS_PENDING : Wait if more to read ; STATUS_SUCCESS : Don't wait.
211 // NTSTATUS Status; = STATUS_PENDING;
212
213 if (Console == NULL || InputBuffer == NULL || /* Buffer == NULL || */
214 ReadControl == NULL || ReadControl->nLength != sizeof(CONSOLE_READCONSOLE_CONTROL))
215 {
216 return STATUS_INVALID_PARAMETER;
217 }
218
219 /* Validity checks */
220 ASSERT(Console == InputBuffer->Header.Console);
221 ASSERT((Buffer != NULL) || (Buffer == NULL && NumCharsToRead == 0));
222
223 /* Call the line-discipline */
224 return TermReadStream(Console,
225 ExeName,
226 Unicode,
227 Buffer,
228 ReadControl,
229 NumCharsToRead,
230 NumCharsRead);
231 }
232
233 NTSTATUS NTAPI
234 ConDrvGetConsoleInput(IN PCONSOLE Console,
235 IN PCONSOLE_INPUT_BUFFER InputBuffer,
236 IN BOOLEAN KeepEvents,
237 IN BOOLEAN WaitForMoreEvents,
238 OUT PINPUT_RECORD InputRecord,
239 IN ULONG NumEventsToRead,
240 OUT PULONG NumEventsRead OPTIONAL)
241 {
242 PLIST_ENTRY CurrentInput;
243 ConsoleInput* Input;
244 ULONG i = 0;
245
246 if (Console == NULL || InputBuffer == NULL /* || InputRecord == NULL */)
247 return STATUS_INVALID_PARAMETER;
248
249 /* Validity checks */
250 ASSERT(Console == InputBuffer->Header.Console);
251 ASSERT((InputRecord != NULL) || (InputRecord == NULL && NumEventsToRead == 0));
252
253 if (NumEventsRead) *NumEventsRead = 0;
254
255 if (IsListEmpty(&InputBuffer->InputEvents))
256 {
257 /*
258 * No input is available. Wait for more input if requested,
259 * otherwise, we don't wait, so we return success.
260 */
261 return (WaitForMoreEvents ? STATUS_PENDING : STATUS_SUCCESS);
262 }
263
264 /* Only get input if there is any */
265 CurrentInput = InputBuffer->InputEvents.Flink;
266 i = 0;
267 while ((CurrentInput != &InputBuffer->InputEvents) && (i < NumEventsToRead))
268 {
269 Input = CONTAINING_RECORD(CurrentInput, ConsoleInput, ListEntry);
270
271 *InputRecord = Input->InputEvent;
272
273 ++InputRecord;
274 ++i;
275 CurrentInput = CurrentInput->Flink;
276
277 /* Remove the events from the queue if needed */
278 if (!KeepEvents)
279 {
280 RemoveEntryList(&Input->ListEntry);
281 ConsoleFreeHeap(Input);
282 }
283 }
284
285 if (NumEventsRead) *NumEventsRead = i;
286
287 if (IsListEmpty(&InputBuffer->InputEvents))
288 {
289 ResetEvent(InputBuffer->ActiveEvent);
290 }
291
292 // FIXME: If we add back UNICODE support, it's here that we need to do the translation.
293
294 /* We read all the inputs available, we return success */
295 return STATUS_SUCCESS;
296 }
297
298 NTSTATUS NTAPI
299 ConDrvWriteConsoleInput(IN PCONSOLE Console,
300 IN PCONSOLE_INPUT_BUFFER InputBuffer,
301 IN BOOLEAN AppendToEnd,
302 IN PINPUT_RECORD InputRecord,
303 IN ULONG NumEventsToWrite,
304 OUT PULONG NumEventsWritten OPTIONAL)
305 {
306 if (Console == NULL || InputBuffer == NULL /* || InputRecord == NULL */)
307 return STATUS_INVALID_PARAMETER;
308
309 /* Validity checks */
310 ASSERT(Console == InputBuffer->Header.Console);
311 ASSERT((InputRecord != NULL) || (InputRecord == NULL && NumEventsToWrite == 0));
312
313 /* Now, add the events */
314 if (NumEventsWritten) *NumEventsWritten = 0;
315
316 // FIXME: If we add back UNICODE support, it's here that we need to do the translation.
317
318 return AddInputEvents(Console,
319 InputRecord,
320 NumEventsToWrite,
321 NumEventsWritten,
322 AppendToEnd);
323 }
324
325 NTSTATUS NTAPI
326 ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console,
327 IN PCONSOLE_INPUT_BUFFER InputBuffer)
328 {
329 PLIST_ENTRY CurrentEntry;
330 ConsoleInput* Event;
331
332 if (Console == NULL || InputBuffer == NULL)
333 return STATUS_INVALID_PARAMETER;
334
335 /* Validity check */
336 ASSERT(Console == InputBuffer->Header.Console);
337
338 /* Discard all entries in the input event queue */
339 while (!IsListEmpty(&InputBuffer->InputEvents))
340 {
341 CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents);
342 Event = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
343 ConsoleFreeHeap(Event);
344 }
345 ResetEvent(InputBuffer->ActiveEvent);
346
347 return STATUS_SUCCESS;
348 }
349
350 NTSTATUS NTAPI
351 ConDrvGetConsoleNumberOfInputEvents(IN PCONSOLE Console,
352 IN PCONSOLE_INPUT_BUFFER InputBuffer,
353 OUT PULONG NumberOfEvents)
354 {
355 PLIST_ENTRY CurrentInput;
356
357 if (Console == NULL || InputBuffer == NULL || NumberOfEvents == NULL)
358 return STATUS_INVALID_PARAMETER;
359
360 /* Validity check */
361 ASSERT(Console == InputBuffer->Header.Console);
362
363 *NumberOfEvents = 0;
364
365 /* If there are any events ... */
366 CurrentInput = InputBuffer->InputEvents.Flink;
367 while (CurrentInput != &InputBuffer->InputEvents)
368 {
369 CurrentInput = CurrentInput->Flink;
370 (*NumberOfEvents)++;
371 }
372
373 return STATUS_SUCCESS;
374 }
375
376 /* EOF */