ReactOS  0.4.15-dev-1070-ge1a01de
coninput.c
Go to the documentation of this file.
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 /* PRIVATE FUNCTIONS **********************************************************/
18 
19 // ConDrvAddInputEvents
20 static NTSTATUS
22  PINPUT_RECORD InputRecords, // InputEvent
23  ULONG NumEventsToWrite,
24  PULONG NumEventsWritten,
25  BOOLEAN AppendToEnd)
26 {
28  ULONG i = 0;
29  BOOLEAN SetWaitEvent = FALSE;
30 
31  if (NumEventsWritten) *NumEventsWritten = 0;
32 
33  /*
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.
37  */
38  if (NumEventsToWrite == 1 && !IsListEmpty(&Console->InputBuffer.InputEvents))
39  {
40  PINPUT_RECORD InputRecord = InputRecords; // Only one element
41  PINPUT_RECORD LastInputRecord;
42  ConsoleInput* ConInRec; // Input
43 
44  /* Get the "next" event of the input buffer */
45  if (AppendToEnd)
46  {
47  /* Get the tail element */
48  ConInRec = CONTAINING_RECORD(Console->InputBuffer.InputEvents.Blink,
49  ConsoleInput, ListEntry);
50  }
51  else
52  {
53  /* Get the head element */
54  ConInRec = CONTAINING_RECORD(Console->InputBuffer.InputEvents.Flink,
55  ConsoleInput, ListEntry);
56  }
57  LastInputRecord = &ConInRec->InputEvent;
58 
59  if (InputRecord->EventType == MOUSE_EVENT &&
60  InputRecord->Event.MouseEvent.dwEventFlags == MOUSE_MOVED)
61  {
62  if (LastInputRecord->EventType == MOUSE_EVENT &&
63  LastInputRecord->Event.MouseEvent.dwEventFlags == MOUSE_MOVED)
64  {
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;
70 
71  i = 1;
72  // return STATUS_SUCCESS;
74  }
75  }
76  else if (InputRecord->EventType == KEY_EVENT &&
77  InputRecord->Event.KeyEvent.bKeyDown)
78  {
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) )
87  {
88  /* Update the repeat count */
89  LastInputRecord->Event.KeyEvent.wRepeatCount +=
90  InputRecord->Event.KeyEvent.wRepeatCount;
91 
92  i = 1;
93  // return STATUS_SUCCESS;
95  }
96  }
97  }
98 
99  /* If we coalesced the only one element, we can quit */
100  if (i == 1 && Status == STATUS_SUCCESS /* && NumEventsToWrite == 1 */)
101  goto Done;
102 
103  /*
104  * No event coalesced, add them in the usual way.
105  */
106 
107  if (AppendToEnd)
108  {
109  /* Go to the beginning of the list */
110  // InputRecords = InputRecords;
111  }
112  else
113  {
114  /* Go to the end of the list */
115  InputRecords = &InputRecords[NumEventsToWrite - 1];
116  }
117 
118  /* Set the event if the list is going to be non-empty */
119  if (IsListEmpty(&Console->InputBuffer.InputEvents))
120  SetWaitEvent = TRUE;
121 
122  for (i = 0; i < NumEventsToWrite && NT_SUCCESS(Status); ++i)
123  {
124  PINPUT_RECORD InputRecord;
125  ConsoleInput* ConInRec;
126 
127  if (AppendToEnd)
128  {
129  /* Select the event and go to the next one */
130  InputRecord = InputRecords++;
131  }
132  else
133  {
134  /* Select the event and go to the previous one */
135  InputRecord = InputRecords--;
136  }
137 
138  /* Add event to the queue */
139  ConInRec = ConsoleAllocHeap(0, sizeof(ConsoleInput));
140  if (ConInRec == NULL)
141  {
142  // return STATUS_INSUFFICIENT_RESOURCES;
144  continue;
145  }
146 
147  ConInRec->InputEvent = *InputRecord;
148 
149  if (AppendToEnd)
150  {
151  /* Append the event to the end of the queue */
152  InsertTailList(&Console->InputBuffer.InputEvents, &ConInRec->ListEntry);
153  }
154  else
155  {
156  /* Append the event to the beginning of the queue */
157  InsertHeadList(&Console->InputBuffer.InputEvents, &ConInRec->ListEntry);
158  }
159  _InterlockedIncrement((PLONG)&Console->InputBuffer.NumberOfEvents);
160 
161  // return STATUS_SUCCESS;
163  }
164 
165  if (SetWaitEvent) NtSetEvent(Console->InputBuffer.ActiveEvent, NULL);
166 
167 Done:
168  if (NumEventsWritten) *NumEventsWritten = i;
169 
170  return Status;
171 }
172 
173 static VOID
175 {
176  PLIST_ENTRY CurrentEntry;
178 
179  /* Discard all entries in the input event queue */
180  _InterlockedExchange((PLONG)&InputBuffer->NumberOfEvents, 0);
181  while (!IsListEmpty(&InputBuffer->InputEvents))
182  {
183  CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents);
184  Event = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
186  }
187 
188  // NtClose(Console->InputBuffer.ActiveEvent);
189 }
190 
193  IN ULONG InputBufferSize)
194 {
197 
198  ConSrvInitObject(&Console->InputBuffer.Header, INPUT_BUFFER, Console);
199 
201  NULL,
202  OBJ_INHERIT,
203  NULL,
204  NULL);
205 
206  Status = NtCreateEvent(&Console->InputBuffer.ActiveEvent, EVENT_ALL_ACCESS,
208  if (!NT_SUCCESS(Status))
209  return Status;
210 
211  Console->InputBuffer.InputBufferSize = InputBufferSize;
212  Console->InputBuffer.NumberOfEvents = 0;
213  InitializeListHead(&Console->InputBuffer.InputEvents);
214  Console->InputBuffer.Mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
216 
217  return STATUS_SUCCESS;
218 }
219 
220 VOID NTAPI
222 {
223  PurgeInputBuffer(&Console->InputBuffer);
224  NtClose(Console->InputBuffer.ActiveEvent);
225 }
226 
227 
228 /* PUBLIC DRIVER APIS *********************************************************/
229 
233  IN BOOLEAN Unicode,
234  OUT PVOID Buffer,
235  IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl,
237  IN ULONG NumCharsToRead,
238  OUT PULONG NumCharsRead OPTIONAL)
239 {
240  // STATUS_PENDING : Wait if more to read ; STATUS_SUCCESS : Don't wait.
241  // NTSTATUS Status; = STATUS_PENDING;
242 
243  if (Console == NULL || InputBuffer == NULL || /* Buffer == NULL || */
244  ReadControl == NULL || ReadControl->nLength != sizeof(CONSOLE_READCONSOLE_CONTROL))
245  {
247  }
248 
249  /* Validity checks */
250  ASSERT(Console == InputBuffer->Header.Console);
251  ASSERT((Buffer != NULL) || (Buffer == NULL && NumCharsToRead == 0));
252 
253  /* Call the line-discipline */
254  return TermReadStream(Console,
255  Unicode,
256  Buffer,
257  ReadControl,
258  Parameter,
259  NumCharsToRead,
260  NumCharsRead);
261 }
262 
266  IN BOOLEAN KeepEvents,
267  IN BOOLEAN WaitForMoreEvents,
268  OUT PINPUT_RECORD InputRecord,
269  IN ULONG NumEventsToRead,
270  OUT PULONG NumEventsRead OPTIONAL)
271 {
272  PLIST_ENTRY CurrentInput;
274  ULONG i = 0;
275 
276  if (Console == NULL || InputBuffer == NULL /* || InputRecord == NULL */)
278 
279  /* Validity checks */
280  ASSERT(Console == InputBuffer->Header.Console);
281  ASSERT((InputRecord != NULL) || (InputRecord == NULL && NumEventsToRead == 0));
282 
283  if (NumEventsRead) *NumEventsRead = 0;
284 
285  if (IsListEmpty(&InputBuffer->InputEvents))
286  {
287  /*
288  * No input is available. Wait for more input if requested,
289  * otherwise, we don't wait, so we return success.
290  */
291  return (WaitForMoreEvents ? STATUS_PENDING : STATUS_SUCCESS);
292  }
293 
294  /* Only get input if there is any */
295  CurrentInput = InputBuffer->InputEvents.Flink;
296  i = 0;
297  while ((CurrentInput != &InputBuffer->InputEvents) && (i < NumEventsToRead))
298  {
299  Input = CONTAINING_RECORD(CurrentInput, ConsoleInput, ListEntry);
300 
301  *InputRecord = Input->InputEvent;
302 
303  ++InputRecord;
304  ++i;
305  CurrentInput = CurrentInput->Flink;
306 
307  /* Remove the events from the queue if needed */
308  if (!KeepEvents)
309  {
310  _InterlockedDecrement((PLONG)&InputBuffer->NumberOfEvents);
311  RemoveEntryList(&Input->ListEntry);
313  }
314  }
315 
316  if (NumEventsRead) *NumEventsRead = i;
317 
318  if (IsListEmpty(&InputBuffer->InputEvents))
319  {
320  NtClearEvent(InputBuffer->ActiveEvent);
321  }
322 
323  // FIXME: If we add back UNICODE support, it's here that we need to do the translation.
324 
325  /* We read all the inputs available, we return success */
326  return STATUS_SUCCESS;
327 }
328 
332  IN BOOLEAN AppendToEnd,
333  IN PINPUT_RECORD InputRecord,
334  IN ULONG NumEventsToWrite,
335  OUT PULONG NumEventsWritten OPTIONAL)
336 {
337  if (Console == NULL || InputBuffer == NULL /* || InputRecord == NULL */)
339 
340  /* Validity checks */
341  ASSERT(Console == InputBuffer->Header.Console);
342  ASSERT((InputRecord != NULL) || (InputRecord == NULL && NumEventsToWrite == 0));
343 
344  /* Now, add the events */
345  if (NumEventsWritten) *NumEventsWritten = 0;
346 
347  // FIXME: If we add back UNICODE support, it's here that we need to do the translation.
348 
349  return AddInputEvents(Console,
350  InputRecord,
351  NumEventsToWrite,
352  NumEventsWritten,
353  AppendToEnd);
354 }
355 
359 {
360  if (Console == NULL || InputBuffer == NULL)
362 
363  /* Validity check */
364  ASSERT(Console == InputBuffer->Header.Console);
365 
366  /* Discard all entries in the input event queue */
368  NtClearEvent(InputBuffer->ActiveEvent);
369 
370  return STATUS_SUCCESS;
371 }
372 
376  OUT PULONG NumberOfEvents)
377 {
378  if (Console == NULL || InputBuffer == NULL || NumberOfEvents == NULL)
380 
381  /* Validity check */
382  ASSERT(Console == InputBuffer->Header.Console);
383 
384  *NumberOfEvents = InputBuffer->NumberOfEvents;
385  return STATUS_SUCCESS;
386 }
387 
388 /* EOF */
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
#define IN
Definition: typedefs.h:39
WCHAR UnicodeChar
Definition: wincon.h:245
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
union _KEY_EVENT_RECORD::@3234 uChar
DWORD dwEventFlags
Definition: wincon.h:260
WORD wVirtualScanCode
Definition: wincon.h:243
#define TRUE
Definition: types.h:120
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
FORCEINLINE VOID InsertHeadList(_Inout_ PLIST_ENTRY ListHead, _Inout_ __drv_aliasesMem PLIST_ENTRY Entry)
Definition: rtlfuncs.h:201
long __cdecl _InterlockedExchange(_Interlocked_operand_ long volatile *_Target, long _Value)
LONG NTSTATUS
Definition: precomp.h:26
#define ConsoleAllocHeap(Flags, Size)
Definition: heap.h:14
DWORD dwControlKeyState
Definition: wincon.h:248
Definition: arc.h:84
NTSTATUS NTAPI NtCreateEvent(OUT PHANDLE EventHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN EVENT_TYPE EventType, IN BOOLEAN InitialState)
Definition: event.c:100
INPUT_RECORD InputEvent
Definition: coninput.h:15
_In_ PVOID Parameter
Definition: ldrtypes.h:241
#define InsertTailList(ListHead, Entry)
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
CHAR InputBuffer[80]
Definition: conmgr.c:33
#define TermReadStream(Console, Unicode, Buffer, ReadControl, Parameter, NumCharsToRead, NumCharsRead)
Definition: term.h:13
#define ENABLE_ECHO_INPUT
Definition: wincon.h:80
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
NTSTATUS NTAPI ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console, IN PCONSOLE_INPUT_BUFFER InputBuffer)
Definition: coninput.c:357
#define MOUSE_MOVED
Definition: wincon.h:168
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
long __cdecl _InterlockedIncrement(_Interlocked_operand_ long volatile *_Addend)
WORD wRepeatCount
Definition: wincon.h:241
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
#define EVENT_ALL_ACCESS
Definition: isotest.c:82
VOID NTAPI ConDrvDeinitInputBuffer(IN PCONSOLE Console)
Definition: coninput.c:221
#define KEY_EVENT
Definition: wincon.h:128
_In_ PVOID _In_ ULONG Event
Definition: iotypes.h:450
COORD dwMousePosition
Definition: wincon.h:257
unsigned char BOOLEAN
long __cdecl _InterlockedDecrement(_Interlocked_operand_ long volatile *_Addend)
smooth NULL
Definition: ftsmooth.c:416
FORCEINLINE PLIST_ENTRY RemoveHeadList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:128
Definition: bufpool.h:45
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
ULONG X
Definition: bl.h:1340
NTSTATUS NTAPI ConDrvReadConsole(IN PCONSOLE Console, IN PCONSOLE_INPUT_BUFFER InputBuffer, IN BOOLEAN Unicode, OUT PVOID Buffer, IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl, IN PVOID Parameter OPTIONAL, IN ULONG NumCharsToRead, OUT PULONG NumCharsRead OPTIONAL)
Definition: coninput.c:231
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
NTSTATUS NTAPI NtSetEvent(IN HANDLE EventHandle, OUT PLONG PreviousState OPTIONAL)
Definition: event.c:458
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
#define OBJ_INHERIT
Definition: winternl.h:225
#define MOUSE_EVENT
Definition: wincon.h:129
KEY_EVENT_RECORD KeyEvent
Definition: wincon.h:278
LIST_ENTRY ListEntry
Definition: coninput.h:14
#define ENABLE_LINE_INPUT
Definition: wincon.h:79
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3399
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define ENABLE_MOUSE_INPUT
Definition: wincon.h:82
Status
Definition: gdiplustypes.h:24
Definition: typedefs.h:119
VOID ConSrvInitObject(IN OUT PCONSOLE_IO_OBJECT Object, IN CONSOLE_IO_OBJECT_TYPE Type, IN PCONSOLE Console)
Definition: handle.c:211
union _INPUT_RECORD::@3235 Event
#define ENABLE_PROCESSED_INPUT
Definition: wincon.h:78
static NTSTATUS AddInputEvents(PCONSOLE Console, PINPUT_RECORD InputRecords, ULONG NumEventsToWrite, PULONG NumEventsWritten, BOOLEAN AppendToEnd)
Definition: coninput.c:21
NTSTATUS NTAPI ConDrvInitInputBuffer(IN PCONSOLE Console, IN ULONG InputBufferSize)
Definition: coninput.c:192
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
unsigned int * PULONG
Definition: retypes.h:1
CConsole Console
WORD EventType
Definition: wincon.h:276
#define ConsoleFreeHeap(HeapBase)
Definition: heap.h:15
MOUSE_EVENT_RECORD MouseEvent
Definition: wincon.h:279
#define OUT
Definition: typedefs.h:40
NTSTATUS NTAPI NtClearEvent(IN HANDLE EventHandle)
Definition: event.c:69
unsigned int ULONG
Definition: retypes.h:1
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
NTSTATUS NTAPI ConDrvGetConsoleNumberOfInputEvents(IN PCONSOLE Console, IN PCONSOLE_INPUT_BUFFER InputBuffer, OUT PULONG NumberOfEvents)
Definition: coninput.c:374
static VOID PurgeInputBuffer(IN PCONSOLE_INPUT_BUFFER InputBuffer)
Definition: coninput.c:174
return STATUS_SUCCESS
Definition: btrfs.c:3014
ULONG Y
Definition: bl.h:1341
NTSTATUS NTAPI ConDrvWriteConsoleInput(IN PCONSOLE Console, IN PCONSOLE_INPUT_BUFFER InputBuffer, IN BOOLEAN AppendToEnd, IN PINPUT_RECORD InputRecord, IN ULONG NumEventsToWrite, OUT PULONG NumEventsWritten OPTIONAL)
Definition: coninput.c:330
signed int * PLONG
Definition: retypes.h:5
NTSTATUS NTAPI ConDrvGetConsoleInput(IN PCONSOLE Console, IN PCONSOLE_INPUT_BUFFER InputBuffer, IN BOOLEAN KeepEvents, IN BOOLEAN WaitForMoreEvents, OUT PINPUT_RECORD InputRecord, IN ULONG NumEventsToRead, OUT PULONG NumEventsRead OPTIONAL)
Definition: coninput.c:264
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68