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 *******************************************************************/
13 #include "include/conio.h"
14 #include "include/term.h"
16 #include "lineinput.h"
22 /* GLOBALS ********************************************************************/
24 #define ConSrvGetInputBuffer(ProcessData, Handle, Ptr, Access, LockConsole) \
25 ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), NULL, \
26 (Access), (LockConsole), INPUT_BUFFER)
27 #define ConSrvGetInputBufferAndHandleEntry(ProcessData, Handle, Ptr, Entry, Access, LockConsole) \
28 ConSrvGetObject((ProcessData), (Handle), (PCONSOLE_IO_OBJECT*)(Ptr), (Entry), \
29 (Access), (LockConsole), INPUT_BUFFER)
30 #define ConSrvReleaseInputBuffer(Buff, IsConsoleLocked) \
31 ConSrvReleaseObject(&(Buff)->Header, (IsConsoleLocked))
34 typedef struct _GET_INPUT_INFO
36 PCSR_THREAD CallingThread
; // The thread which called the input API.
37 PVOID HandleEntry
; // The handle data associated with the wait thread.
38 PCONSOLE_INPUT_BUFFER InputBuffer
; // The input buffer corresponding to the handle.
39 } GET_INPUT_INFO
, *PGET_INPUT_INFO
;
42 /* PRIVATE FUNCTIONS **********************************************************/
45 WaitBeforeReading(IN PGET_INPUT_INFO InputInfo
,
46 IN PCSR_API_MESSAGE ApiMessage
,
47 IN CSR_WAIT_FUNCTION WaitFunction OPTIONAL
,
48 IN BOOL CreateWaitBlock OPTIONAL
)
52 PGET_INPUT_INFO CapturedInputInfo
;
54 CapturedInputInfo
= ConsoleAllocHeap(0, sizeof(GET_INPUT_INFO
));
55 if (!CapturedInputInfo
) return STATUS_NO_MEMORY
;
57 RtlMoveMemory(CapturedInputInfo
, InputInfo
, sizeof(GET_INPUT_INFO
));
59 if (!CsrCreateWait(&InputInfo
->InputBuffer
->ReadWaitQueue
,
61 InputInfo
->CallingThread
,
65 ConsoleFreeHeap(CapturedInputInfo
);
66 return STATUS_NO_MEMORY
;
71 return STATUS_PENDING
;
75 ReadChars(IN PGET_INPUT_INFO InputInfo
,
76 IN PCSR_API_MESSAGE ApiMessage
,
77 IN BOOL CreateWaitBlock OPTIONAL
);
79 // Wait function CSR_WAIT_FUNCTION
82 ReadCharsThread(IN PLIST_ENTRY WaitList
,
83 IN PCSR_THREAD WaitThread
,
84 IN PCSR_API_MESSAGE WaitApiMessage
,
86 IN PVOID WaitArgument1
,
87 IN PVOID WaitArgument2
,
91 PGET_INPUT_INFO InputInfo
= (PGET_INPUT_INFO
)WaitContext
;
93 PVOID InputHandle
= WaitArgument2
;
95 DPRINT("ReadCharsThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
98 * If we are notified of the process termination via a call
99 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
100 * CsrDestroyThread, just return.
102 if (WaitFlags
& CsrProcessTerminating
)
104 Status
= STATUS_THREAD_IS_TERMINATING
;
109 * Somebody is closing a handle to this input buffer,
110 * by calling ConSrvCloseHandleEntry.
111 * See whether we are linked to that handle (ie. we
112 * are a waiter for this handle), and if so, return.
113 * Otherwise, ignore the call and continue waiting.
115 if (InputHandle
!= NULL
)
117 Status
= (InputHandle
== InputInfo
->HandleEntry
? STATUS_ALERTED
123 * If we go there, that means we are notified for some new input.
124 * The console is therefore already locked.
126 Status
= ReadChars(InputInfo
,
131 if (Status
!= STATUS_PENDING
)
133 WaitApiMessage
->Status
= Status
;
134 ConsoleFreeHeap(InputInfo
);
137 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
141 ConDrvReadConsole(IN PCONSOLE Console
,
142 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
145 IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl
,
146 IN ULONG NumCharsToRead
,
147 OUT PULONG NumCharsRead OPTIONAL
);
149 ReadChars(IN PGET_INPUT_INFO InputInfo
,
150 IN PCSR_API_MESSAGE ApiMessage
,
151 IN BOOL CreateWaitBlock OPTIONAL
)
154 PCONSOLE_READCONSOLE ReadConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadConsoleRequest
;
155 PCONSOLE_INPUT_BUFFER InputBuffer
= InputInfo
->InputBuffer
;
156 CONSOLE_READCONSOLE_CONTROL ReadControl
;
158 ReadControl
.nLength
= sizeof(CONSOLE_READCONSOLE_CONTROL
);
159 ReadControl
.nInitialChars
= ReadConsoleRequest
->NrCharactersRead
;
160 ReadControl
.dwCtrlWakeupMask
= ReadConsoleRequest
->CtrlWakeupMask
;
161 ReadControl
.dwControlKeyState
= ReadConsoleRequest
->ControlKeyState
;
163 Status
= ConDrvReadConsole(InputBuffer
->Header
.Console
,
165 ReadConsoleRequest
->Unicode
,
166 ReadConsoleRequest
->Buffer
,
168 ReadConsoleRequest
->NrCharactersToRead
,
169 &ReadConsoleRequest
->NrCharactersRead
);
171 ReadConsoleRequest
->ControlKeyState
= ReadControl
.dwControlKeyState
;
173 if (Status
== STATUS_PENDING
)
175 /* We haven't completed a read, so start a wait */
176 return WaitBeforeReading(InputInfo
,
183 /* We read all what we wanted, we return the error code we were given */
185 // return STATUS_SUCCESS;
190 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo
,
192 IN PCSR_API_MESSAGE ApiMessage
,
193 IN BOOL CreateWaitBlock OPTIONAL
);
195 // Wait function CSR_WAIT_FUNCTION
198 ReadInputBufferThread(IN PLIST_ENTRY WaitList
,
199 IN PCSR_THREAD WaitThread
,
200 IN PCSR_API_MESSAGE WaitApiMessage
,
201 IN PVOID WaitContext
,
202 IN PVOID WaitArgument1
,
203 IN PVOID WaitArgument2
,
207 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)WaitApiMessage
)->Data
.GetInputRequest
;
208 PGET_INPUT_INFO InputInfo
= (PGET_INPUT_INFO
)WaitContext
;
210 PVOID InputHandle
= WaitArgument2
;
212 DPRINT("ReadInputBufferThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
215 * If we are notified of the process termination via a call
216 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
217 * CsrDestroyThread, just return.
219 if (WaitFlags
& CsrProcessTerminating
)
221 Status
= STATUS_THREAD_IS_TERMINATING
;
226 * Somebody is closing a handle to this input buffer,
227 * by calling ConSrvCloseHandleEntry.
228 * See whether we are linked to that handle (ie. we
229 * are a waiter for this handle), and if so, return.
230 * Otherwise, ignore the call and continue waiting.
232 if (InputHandle
!= NULL
)
234 Status
= (InputHandle
== InputInfo
->HandleEntry
? STATUS_ALERTED
240 * If we go there, that means we are notified for some new input.
241 * The console is therefore already locked.
243 Status
= ReadInputBuffer(InputInfo
,
244 GetInputRequest
->bRead
,
249 if (Status
!= STATUS_PENDING
)
251 WaitApiMessage
->Status
= Status
;
252 ConsoleFreeHeap(InputInfo
);
255 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
259 ConDrvGetConsoleInput(IN PCONSOLE Console
,
260 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
261 IN BOOLEAN WaitForMoreEvents
,
263 OUT PINPUT_RECORD InputRecord
,
264 IN ULONG NumEventsToRead
,
265 OUT PULONG NumEventsRead
);
267 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo
,
268 IN BOOL Wait
, // TRUE --> Read ; FALSE --> Peek
269 IN PCSR_API_MESSAGE ApiMessage
,
270 IN BOOL CreateWaitBlock OPTIONAL
)
273 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetInputRequest
;
274 PCONSOLE_INPUT_BUFFER InputBuffer
= InputInfo
->InputBuffer
;
276 // GetInputRequest->InputsRead = 0;
278 Status
= ConDrvGetConsoleInput(InputBuffer
->Header
.Console
,
281 GetInputRequest
->Unicode
,
282 GetInputRequest
->InputRecord
,
283 GetInputRequest
->Length
,
284 &GetInputRequest
->InputsRead
);
286 if (Status
== STATUS_PENDING
)
288 /* We haven't completed a read, so start a wait */
289 return WaitBeforeReading(InputInfo
,
291 ReadInputBufferThread
,
296 /* We read all what we wanted, we return the error code we were given */
298 // return STATUS_SUCCESS;
303 /* PUBLIC SERVER APIS *********************************************************/
305 CSR_API(SrvReadConsole
)
308 PCONSOLE_READCONSOLE ReadConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadConsoleRequest
;
309 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
311 PCONSOLE_INPUT_BUFFER InputBuffer
;
312 GET_INPUT_INFO InputInfo
;
314 DPRINT("SrvReadConsole\n");
316 if (!CsrValidateMessageBuffer(ApiMessage
,
317 (PVOID
*)&ReadConsoleRequest
->Buffer
,
318 ReadConsoleRequest
->BufferSize
,
321 return STATUS_INVALID_PARAMETER
;
324 if (ReadConsoleRequest
->NrCharactersRead
> ReadConsoleRequest
->NrCharactersToRead
)
326 return STATUS_INVALID_PARAMETER
;
329 Status
= ConSrvGetInputBufferAndHandleEntry(ProcessData
, ReadConsoleRequest
->InputHandle
, &InputBuffer
, &HandleEntry
, GENERIC_READ
, TRUE
);
330 if (!NT_SUCCESS(Status
)) return Status
;
332 // This member is set by the caller (IntReadConsole in kernel32)
333 // ReadConsoleRequest->NrCharactersRead = 0;
335 InputInfo
.CallingThread
= CsrGetClientThread();
336 InputInfo
.HandleEntry
= HandleEntry
;
337 InputInfo
.InputBuffer
= InputBuffer
;
339 Status
= ReadChars(&InputInfo
,
343 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
345 if (Status
== STATUS_PENDING
) *ReplyCode
= CsrReplyPending
;
350 CSR_API(SrvGetConsoleInput
)
353 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetInputRequest
;
354 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
356 PCONSOLE_INPUT_BUFFER InputBuffer
;
357 GET_INPUT_INFO InputInfo
;
359 DPRINT("SrvGetConsoleInput\n");
361 if (!CsrValidateMessageBuffer(ApiMessage
,
362 (PVOID
*)&GetInputRequest
->InputRecord
,
363 GetInputRequest
->Length
,
364 sizeof(INPUT_RECORD
)))
366 return STATUS_INVALID_PARAMETER
;
369 Status
= ConSrvGetInputBufferAndHandleEntry(ProcessData
, GetInputRequest
->InputHandle
, &InputBuffer
, &HandleEntry
, GENERIC_READ
, TRUE
);
370 if (!NT_SUCCESS(Status
)) return Status
;
372 GetInputRequest
->InputsRead
= 0;
374 InputInfo
.CallingThread
= CsrGetClientThread();
375 InputInfo
.HandleEntry
= HandleEntry
;
376 InputInfo
.InputBuffer
= InputBuffer
;
378 Status
= ReadInputBuffer(&InputInfo
,
379 GetInputRequest
->bRead
,
383 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
385 if (Status
== STATUS_PENDING
) *ReplyCode
= CsrReplyPending
;
391 ConDrvWriteConsoleInput(IN PCONSOLE Console
,
392 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
394 IN PINPUT_RECORD InputRecord
,
395 IN ULONG NumEventsToWrite
,
396 OUT PULONG NumEventsWritten OPTIONAL
);
397 CSR_API(SrvWriteConsoleInput
)
400 PCONSOLE_WRITEINPUT WriteInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.WriteInputRequest
;
401 PCONSOLE_INPUT_BUFFER InputBuffer
;
402 ULONG NumEventsWritten
;
404 DPRINT("SrvWriteConsoleInput\n");
406 if (!CsrValidateMessageBuffer(ApiMessage
,
407 (PVOID
*)&WriteInputRequest
->InputRecord
,
408 WriteInputRequest
->Length
,
409 sizeof(INPUT_RECORD
)))
411 return STATUS_INVALID_PARAMETER
;
414 Status
= ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
415 WriteInputRequest
->InputHandle
,
416 &InputBuffer
, GENERIC_WRITE
, TRUE
);
417 if (!NT_SUCCESS(Status
)) return Status
;
419 NumEventsWritten
= 0;
420 Status
= ConDrvWriteConsoleInput(InputBuffer
->Header
.Console
,
422 WriteInputRequest
->Unicode
,
423 WriteInputRequest
->InputRecord
,
424 WriteInputRequest
->Length
,
426 WriteInputRequest
->Length
= NumEventsWritten
;
428 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
433 ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console
,
434 IN PCONSOLE_INPUT_BUFFER InputBuffer
);
435 CSR_API(SrvFlushConsoleInputBuffer
)
438 PCONSOLE_FLUSHINPUTBUFFER FlushInputBufferRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.FlushInputBufferRequest
;
439 PCONSOLE_INPUT_BUFFER InputBuffer
;
441 DPRINT("SrvFlushConsoleInputBuffer\n");
443 Status
= ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
444 FlushInputBufferRequest
->InputHandle
,
445 &InputBuffer
, GENERIC_WRITE
, TRUE
);
446 if (!NT_SUCCESS(Status
)) return Status
;
448 Status
= ConDrvFlushConsoleInputBuffer(InputBuffer
->Header
.Console
,
451 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
456 ConDrvGetConsoleNumberOfInputEvents(IN PCONSOLE Console
,
457 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
458 OUT PULONG NumEvents
);
459 CSR_API(SrvGetConsoleNumberOfInputEvents
)
462 PCONSOLE_GETNUMINPUTEVENTS GetNumInputEventsRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetNumInputEventsRequest
;
463 PCONSOLE_INPUT_BUFFER InputBuffer
;
465 DPRINT("SrvGetConsoleNumberOfInputEvents\n");
467 Status
= ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
468 GetNumInputEventsRequest
->InputHandle
,
469 &InputBuffer
, GENERIC_READ
, TRUE
);
470 if (!NT_SUCCESS(Status
)) return Status
;
472 Status
= ConDrvGetConsoleNumberOfInputEvents(InputBuffer
->Header
.Console
,
474 &GetNumInputEventsRequest
->NumInputEvents
);
476 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);