2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/consrv/coninput.c
5 * PURPOSE: Console Input functions
6 * PROGRAMMERS: Jeffrey Morlan
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 /* INCLUDES *******************************************************************/
17 /* GLOBALS ********************************************************************/
19 #define ConSrvGetInputBuffer(ProcessData, Handle, Ptr, Access, LockConsole) \
20 ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), NULL, \
21 (Access), (LockConsole), INPUT_BUFFER)
22 #define ConSrvGetInputBufferAndHandleEntry(ProcessData, Handle, Ptr, Entry, Access, LockConsole) \
23 ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), (Entry), \
24 (Access), (LockConsole), INPUT_BUFFER)
25 #define ConSrvReleaseInputBuffer(Buff, IsConsoleLocked) \
26 ConSrvReleaseObject(&(Buff)->Header, (IsConsoleLocked))
29 typedef struct _GET_INPUT_INFO
31 PCSR_THREAD CallingThread
; // The thread which called the input API.
32 PVOID HandleEntry
; // The handle data associated with the wait thread.
33 PCONSOLE_INPUT_BUFFER InputBuffer
; // The input buffer corresponding to the handle.
34 } GET_INPUT_INFO
, *PGET_INPUT_INFO
;
37 /* PRIVATE FUNCTIONS **********************************************************/
40 WaitBeforeReading(IN PGET_INPUT_INFO InputInfo
,
41 IN PCSR_API_MESSAGE ApiMessage
,
42 IN CSR_WAIT_FUNCTION WaitFunction OPTIONAL
,
43 IN BOOLEAN CreateWaitBlock OPTIONAL
)
47 PGET_INPUT_INFO CapturedInputInfo
;
49 CapturedInputInfo
= ConsoleAllocHeap(0, sizeof(GET_INPUT_INFO
));
50 if (!CapturedInputInfo
) return STATUS_NO_MEMORY
;
52 RtlMoveMemory(CapturedInputInfo
, InputInfo
, sizeof(GET_INPUT_INFO
));
54 if (!CsrCreateWait(&InputInfo
->InputBuffer
->Header
.Console
->ReadWaitQueue
,
56 InputInfo
->CallingThread
,
60 ConsoleFreeHeap(CapturedInputInfo
);
61 return STATUS_NO_MEMORY
;
66 return STATUS_PENDING
;
70 ReadChars(IN PGET_INPUT_INFO InputInfo
,
71 IN PCSR_API_MESSAGE ApiMessage
,
72 IN BOOLEAN CreateWaitBlock OPTIONAL
);
74 // Wait function CSR_WAIT_FUNCTION
77 ReadCharsThread(IN PLIST_ENTRY WaitList
,
78 IN PCSR_THREAD WaitThread
,
79 IN PCSR_API_MESSAGE WaitApiMessage
,
81 IN PVOID WaitArgument1
,
82 IN PVOID WaitArgument2
,
86 PGET_INPUT_INFO InputInfo
= (PGET_INPUT_INFO
)WaitContext
;
88 PVOID InputHandle
= WaitArgument2
;
90 DPRINT("ReadCharsThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
93 * If we are notified of the process termination via a call
94 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
95 * CsrDestroyThread, just return.
97 if (WaitFlags
& CsrProcessTerminating
)
99 Status
= STATUS_THREAD_IS_TERMINATING
;
104 * Somebody is closing a handle to this input buffer,
105 * by calling ConSrvCloseHandleEntry.
106 * See whether we are linked to that handle (ie. we
107 * are a waiter for this handle), and if so, return.
108 * Otherwise, ignore the call and continue waiting.
110 if (InputHandle
!= NULL
)
112 Status
= (InputHandle
== InputInfo
->HandleEntry
? STATUS_ALERTED
118 * If we go there, that means we are notified for some new input.
119 * The console is therefore already locked.
121 Status
= ReadChars(InputInfo
, WaitApiMessage
, FALSE
);
124 if (Status
!= STATUS_PENDING
)
126 WaitApiMessage
->Status
= Status
;
127 ConsoleFreeHeap(InputInfo
);
130 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
134 ConDrvReadConsole(IN PCONSOLE Console
,
135 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
138 IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl
,
139 IN ULONG NumCharsToRead
,
140 OUT PULONG NumCharsRead OPTIONAL
);
142 ReadChars(IN PGET_INPUT_INFO InputInfo
,
143 IN PCSR_API_MESSAGE ApiMessage
,
144 IN BOOLEAN CreateWaitBlock OPTIONAL
)
147 PCONSOLE_READCONSOLE ReadConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadConsoleRequest
;
148 PCONSOLE_INPUT_BUFFER InputBuffer
= InputInfo
->InputBuffer
;
149 CONSOLE_READCONSOLE_CONTROL ReadControl
;
151 ReadControl
.nLength
= sizeof(CONSOLE_READCONSOLE_CONTROL
);
152 ReadControl
.nInitialChars
= ReadConsoleRequest
->NrCharactersRead
;
153 ReadControl
.dwCtrlWakeupMask
= ReadConsoleRequest
->CtrlWakeupMask
;
154 ReadControl
.dwControlKeyState
= ReadConsoleRequest
->ControlKeyState
;
156 Status
= ConDrvReadConsole(InputBuffer
->Header
.Console
,
158 ReadConsoleRequest
->Unicode
,
159 ReadConsoleRequest
->Buffer
,
161 ReadConsoleRequest
->NrCharactersToRead
,
162 &ReadConsoleRequest
->NrCharactersRead
);
164 ReadConsoleRequest
->ControlKeyState
= ReadControl
.dwControlKeyState
;
166 if (Status
== STATUS_PENDING
)
168 /* We haven't completed a read, so start a wait */
169 return WaitBeforeReading(InputInfo
,
176 /* We read all what we wanted, we return the error code we were given */
178 // return STATUS_SUCCESS;
183 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo
,
184 IN PCSR_API_MESSAGE ApiMessage
,
185 IN BOOLEAN CreateWaitBlock OPTIONAL
);
187 // Wait function CSR_WAIT_FUNCTION
190 ReadInputBufferThread(IN PLIST_ENTRY WaitList
,
191 IN PCSR_THREAD WaitThread
,
192 IN PCSR_API_MESSAGE WaitApiMessage
,
193 IN PVOID WaitContext
,
194 IN PVOID WaitArgument1
,
195 IN PVOID WaitArgument2
,
199 PGET_INPUT_INFO InputInfo
= (PGET_INPUT_INFO
)WaitContext
;
201 PVOID InputHandle
= WaitArgument2
;
203 DPRINT("ReadInputBufferThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
206 * If we are notified of the process termination via a call
207 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
208 * CsrDestroyThread, just return.
210 if (WaitFlags
& CsrProcessTerminating
)
212 Status
= STATUS_THREAD_IS_TERMINATING
;
217 * Somebody is closing a handle to this input buffer,
218 * by calling ConSrvCloseHandleEntry.
219 * See whether we are linked to that handle (ie. we
220 * are a waiter for this handle), and if so, return.
221 * Otherwise, ignore the call and continue waiting.
223 if (InputHandle
!= NULL
)
225 Status
= (InputHandle
== InputInfo
->HandleEntry
? STATUS_ALERTED
231 * If we go there, that means we are notified for some new input.
232 * The console is therefore already locked.
234 Status
= ReadInputBuffer(InputInfo
, WaitApiMessage
, FALSE
);
237 if (Status
!= STATUS_PENDING
)
239 WaitApiMessage
->Status
= Status
;
240 ConsoleFreeHeap(InputInfo
);
243 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
247 ConDrvGetConsoleInput(IN PCONSOLE Console
,
248 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
249 IN BOOLEAN KeepEvents
,
250 IN BOOLEAN WaitForMoreEvents
,
252 OUT PINPUT_RECORD InputRecord
,
253 IN ULONG NumEventsToRead
,
254 OUT PULONG NumEventsRead OPTIONAL
);
256 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo
,
257 IN PCSR_API_MESSAGE ApiMessage
,
258 IN BOOLEAN CreateWaitBlock OPTIONAL
)
261 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetInputRequest
;
262 PCONSOLE_INPUT_BUFFER InputBuffer
= InputInfo
->InputBuffer
;
264 // GetInputRequest->InputsRead = 0;
266 Status
= ConDrvGetConsoleInput(InputBuffer
->Header
.Console
,
268 (GetInputRequest
->wFlags
& CONSOLE_READ_KEEPEVENT
) != 0,
269 (GetInputRequest
->wFlags
& CONSOLE_READ_CONTINUE
) == 0,
270 GetInputRequest
->Unicode
,
271 GetInputRequest
->InputRecord
,
272 GetInputRequest
->Length
,
273 &GetInputRequest
->InputsRead
);
275 if (Status
== STATUS_PENDING
)
277 /* We haven't completed a read, so start a wait */
278 return WaitBeforeReading(InputInfo
,
280 ReadInputBufferThread
,
285 /* We read all what we wanted, we return the error code we were given */
287 // return STATUS_SUCCESS;
292 /* PUBLIC SERVER APIS *********************************************************/
294 CSR_API(SrvReadConsole
)
297 PCONSOLE_READCONSOLE ReadConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadConsoleRequest
;
298 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
300 PCONSOLE_INPUT_BUFFER InputBuffer
;
301 GET_INPUT_INFO InputInfo
;
303 DPRINT("SrvReadConsole\n");
305 if (!CsrValidateMessageBuffer(ApiMessage
,
306 (PVOID
*)&ReadConsoleRequest
->Buffer
,
307 ReadConsoleRequest
->BufferSize
,
310 return STATUS_INVALID_PARAMETER
;
313 if (ReadConsoleRequest
->NrCharactersRead
> ReadConsoleRequest
->NrCharactersToRead
)
315 return STATUS_INVALID_PARAMETER
;
318 Status
= ConSrvGetInputBufferAndHandleEntry(ProcessData
, ReadConsoleRequest
->InputHandle
, &InputBuffer
, &HandleEntry
, GENERIC_READ
, TRUE
);
319 if (!NT_SUCCESS(Status
)) return Status
;
321 // This member is set by the caller (IntReadConsole in kernel32)
322 // ReadConsoleRequest->NrCharactersRead = 0;
324 InputInfo
.CallingThread
= CsrGetClientThread();
325 InputInfo
.HandleEntry
= HandleEntry
;
326 InputInfo
.InputBuffer
= InputBuffer
;
328 Status
= ReadChars(&InputInfo
, ApiMessage
, TRUE
);
330 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
332 if (Status
== STATUS_PENDING
) *ReplyCode
= CsrReplyPending
;
337 CSR_API(SrvGetConsoleInput
)
340 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetInputRequest
;
341 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
343 PCONSOLE_INPUT_BUFFER InputBuffer
;
344 GET_INPUT_INFO InputInfo
;
346 DPRINT("SrvGetConsoleInput\n");
348 if (GetInputRequest
->wFlags
& ~(CONSOLE_READ_KEEPEVENT
| CONSOLE_READ_CONTINUE
))
349 return STATUS_INVALID_PARAMETER
;
351 if (!CsrValidateMessageBuffer(ApiMessage
,
352 (PVOID
*)&GetInputRequest
->InputRecord
,
353 GetInputRequest
->Length
,
354 sizeof(INPUT_RECORD
)))
356 return STATUS_INVALID_PARAMETER
;
359 Status
= ConSrvGetInputBufferAndHandleEntry(ProcessData
, GetInputRequest
->InputHandle
, &InputBuffer
, &HandleEntry
, GENERIC_READ
, TRUE
);
360 if (!NT_SUCCESS(Status
)) return Status
;
362 GetInputRequest
->InputsRead
= 0;
364 InputInfo
.CallingThread
= CsrGetClientThread();
365 InputInfo
.HandleEntry
= HandleEntry
;
366 InputInfo
.InputBuffer
= InputBuffer
;
368 Status
= ReadInputBuffer(&InputInfo
, ApiMessage
, TRUE
);
370 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
372 if (Status
== STATUS_PENDING
) *ReplyCode
= CsrReplyPending
;
378 ConDrvWriteConsoleInput(IN PCONSOLE Console
,
379 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
381 IN BOOLEAN AppendToEnd
,
382 IN PINPUT_RECORD InputRecord
,
383 IN ULONG NumEventsToWrite
,
384 OUT PULONG NumEventsWritten OPTIONAL
);
385 CSR_API(SrvWriteConsoleInput
)
388 PCONSOLE_WRITEINPUT WriteInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.WriteInputRequest
;
389 PCONSOLE_INPUT_BUFFER InputBuffer
;
390 ULONG NumEventsWritten
;
392 DPRINT("SrvWriteConsoleInput\n");
394 if (!CsrValidateMessageBuffer(ApiMessage
,
395 (PVOID
*)&WriteInputRequest
->InputRecord
,
396 WriteInputRequest
->Length
,
397 sizeof(INPUT_RECORD
)))
399 return STATUS_INVALID_PARAMETER
;
402 Status
= ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
403 WriteInputRequest
->InputHandle
,
404 &InputBuffer
, GENERIC_WRITE
, TRUE
);
405 if (!NT_SUCCESS(Status
)) return Status
;
407 NumEventsWritten
= 0;
408 Status
= ConDrvWriteConsoleInput(InputBuffer
->Header
.Console
,
410 WriteInputRequest
->Unicode
,
411 WriteInputRequest
->AppendToEnd
,
412 WriteInputRequest
->InputRecord
,
413 WriteInputRequest
->Length
,
415 WriteInputRequest
->Length
= NumEventsWritten
;
417 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
422 ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console
,
423 IN PCONSOLE_INPUT_BUFFER InputBuffer
);
424 CSR_API(SrvFlushConsoleInputBuffer
)
427 PCONSOLE_FLUSHINPUTBUFFER FlushInputBufferRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.FlushInputBufferRequest
;
428 PCONSOLE_INPUT_BUFFER InputBuffer
;
430 DPRINT("SrvFlushConsoleInputBuffer\n");
432 Status
= ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
433 FlushInputBufferRequest
->InputHandle
,
434 &InputBuffer
, GENERIC_WRITE
, TRUE
);
435 if (!NT_SUCCESS(Status
)) return Status
;
437 Status
= ConDrvFlushConsoleInputBuffer(InputBuffer
->Header
.Console
,
440 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
445 ConDrvGetConsoleNumberOfInputEvents(IN PCONSOLE Console
,
446 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
447 OUT PULONG NumberOfEvents
);
448 CSR_API(SrvGetConsoleNumberOfInputEvents
)
451 PCONSOLE_GETNUMINPUTEVENTS GetNumInputEventsRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetNumInputEventsRequest
;
452 PCONSOLE_INPUT_BUFFER InputBuffer
;
454 DPRINT("SrvGetConsoleNumberOfInputEvents\n");
456 Status
= ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
457 GetNumInputEventsRequest
->InputHandle
,
458 &InputBuffer
, GENERIC_READ
, TRUE
);
459 if (!NT_SUCCESS(Status
)) return Status
;
461 Status
= ConDrvGetConsoleNumberOfInputEvents(InputBuffer
->Header
.Console
,
463 &GetNumInputEventsRequest
->NumberOfEvents
);
465 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);