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/conio2.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
81 ReadCharsThread(IN PLIST_ENTRY WaitList
,
82 IN PCSR_THREAD WaitThread
,
83 IN PCSR_API_MESSAGE WaitApiMessage
,
85 IN PVOID WaitArgument1
,
86 IN PVOID WaitArgument2
,
90 PGET_INPUT_INFO InputInfo
= (PGET_INPUT_INFO
)WaitContext
;
92 PVOID InputHandle
= WaitArgument2
;
94 DPRINT("ReadCharsThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
97 * If we are notified of the process termination via a call
98 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
99 * CsrDestroyThread, just return.
101 if (WaitFlags
& CsrProcessTerminating
)
103 Status
= STATUS_THREAD_IS_TERMINATING
;
108 * Somebody is closing a handle to this input buffer,
109 * by calling ConSrvCloseHandleEntry.
110 * See whether we are linked to that handle (ie. we
111 * are a waiter for this handle), and if so, return.
112 * Otherwise, ignore the call and continue waiting.
114 if (InputHandle
!= NULL
)
116 Status
= (InputHandle
== InputInfo
->HandleEntry
? STATUS_ALERTED
122 * If we go there, that means we are notified for some new input.
123 * The console is therefore already locked.
125 Status
= ReadChars(InputInfo
,
130 if (Status
!= STATUS_PENDING
)
132 WaitApiMessage
->Status
= Status
;
133 ConsoleFreeHeap(InputInfo
);
136 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
140 ConDrvReadConsole(IN PCONSOLE Console
,
141 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
144 IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl
,
145 IN ULONG NumCharsToRead
,
146 OUT PULONG NumCharsRead OPTIONAL
);
148 ReadChars(IN PGET_INPUT_INFO InputInfo
,
149 IN PCSR_API_MESSAGE ApiMessage
,
150 IN BOOL CreateWaitBlock OPTIONAL
)
153 PCONSOLE_READCONSOLE ReadConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadConsoleRequest
;
154 PCONSOLE_INPUT_BUFFER InputBuffer
= InputInfo
->InputBuffer
;
155 CONSOLE_READCONSOLE_CONTROL ReadControl
;
157 ReadControl
.nLength
= sizeof(CONSOLE_READCONSOLE_CONTROL
);
158 ReadControl
.nInitialChars
= ReadConsoleRequest
->NrCharactersRead
;
159 ReadControl
.dwCtrlWakeupMask
= ReadConsoleRequest
->CtrlWakeupMask
;
160 ReadControl
.dwControlKeyState
= ReadConsoleRequest
->ControlKeyState
;
162 Status
= ConDrvReadConsole(InputBuffer
->Header
.Console
,
164 ReadConsoleRequest
->Unicode
,
165 ReadConsoleRequest
->Buffer
,
167 ReadConsoleRequest
->NrCharactersToRead
,
168 &ReadConsoleRequest
->NrCharactersRead
);
170 ReadConsoleRequest
->ControlKeyState
= ReadControl
.dwControlKeyState
;
172 if (Status
== STATUS_PENDING
)
174 /* We haven't completed a read, so start a wait */
175 return WaitBeforeReading(InputInfo
,
182 /* We read all what we wanted, we return the error code we were given */
184 // return STATUS_SUCCESS;
189 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo
,
191 IN PCSR_API_MESSAGE ApiMessage
,
192 IN BOOL CreateWaitBlock OPTIONAL
);
194 // Wait function CSR_WAIT_FUNCTION
196 ReadInputBufferThread(IN PLIST_ENTRY WaitList
,
197 IN PCSR_THREAD WaitThread
,
198 IN PCSR_API_MESSAGE WaitApiMessage
,
199 IN PVOID WaitContext
,
200 IN PVOID WaitArgument1
,
201 IN PVOID WaitArgument2
,
205 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)WaitApiMessage
)->Data
.GetInputRequest
;
206 PGET_INPUT_INFO InputInfo
= (PGET_INPUT_INFO
)WaitContext
;
208 PVOID InputHandle
= WaitArgument2
;
210 DPRINT("ReadInputBufferThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
213 * If we are notified of the process termination via a call
214 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
215 * CsrDestroyThread, just return.
217 if (WaitFlags
& CsrProcessTerminating
)
219 Status
= STATUS_THREAD_IS_TERMINATING
;
224 * Somebody is closing a handle to this input buffer,
225 * by calling ConSrvCloseHandleEntry.
226 * See whether we are linked to that handle (ie. we
227 * are a waiter for this handle), and if so, return.
228 * Otherwise, ignore the call and continue waiting.
230 if (InputHandle
!= NULL
)
232 Status
= (InputHandle
== InputInfo
->HandleEntry
? STATUS_ALERTED
238 * If we go there, that means we are notified for some new input.
239 * The console is therefore already locked.
241 Status
= ReadInputBuffer(InputInfo
,
242 GetInputRequest
->bRead
,
247 if (Status
!= STATUS_PENDING
)
249 WaitApiMessage
->Status
= Status
;
250 ConsoleFreeHeap(InputInfo
);
253 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
257 ConDrvGetConsoleInput(IN PCONSOLE Console
,
258 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
259 IN BOOLEAN WaitForMoreEvents
,
261 OUT PINPUT_RECORD InputRecord
,
262 IN ULONG NumEventsToRead
,
263 OUT PULONG NumEventsRead
);
265 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo
,
266 IN BOOL Wait
, // TRUE --> Read ; FALSE --> Peek
267 IN PCSR_API_MESSAGE ApiMessage
,
268 IN BOOL CreateWaitBlock OPTIONAL
)
271 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetInputRequest
;
272 PCONSOLE_INPUT_BUFFER InputBuffer
= InputInfo
->InputBuffer
;
274 // GetInputRequest->InputsRead = 0;
276 Status
= ConDrvGetConsoleInput(InputBuffer
->Header
.Console
,
279 GetInputRequest
->Unicode
,
280 GetInputRequest
->InputRecord
,
281 GetInputRequest
->Length
,
282 &GetInputRequest
->InputsRead
);
284 if (Status
== STATUS_PENDING
)
286 /* We haven't completed a read, so start a wait */
287 return WaitBeforeReading(InputInfo
,
289 ReadInputBufferThread
,
294 /* We read all what we wanted, we return the error code we were given */
296 // return STATUS_SUCCESS;
301 /* PUBLIC SERVER APIS *********************************************************/
303 CSR_API(SrvReadConsole
)
306 PCONSOLE_READCONSOLE ReadConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadConsoleRequest
;
307 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
309 PCONSOLE_INPUT_BUFFER InputBuffer
;
310 GET_INPUT_INFO InputInfo
;
312 DPRINT("SrvReadConsole\n");
314 if (!CsrValidateMessageBuffer(ApiMessage
,
315 (PVOID
*)&ReadConsoleRequest
->Buffer
,
316 ReadConsoleRequest
->BufferSize
,
319 return STATUS_INVALID_PARAMETER
;
322 if (ReadConsoleRequest
->NrCharactersRead
> ReadConsoleRequest
->NrCharactersToRead
)
324 return STATUS_INVALID_PARAMETER
;
327 Status
= ConSrvGetInputBufferAndHandleEntry(ProcessData
, ReadConsoleRequest
->InputHandle
, &InputBuffer
, &HandleEntry
, GENERIC_READ
, TRUE
);
328 if (!NT_SUCCESS(Status
)) return Status
;
330 // This member is set by the caller (IntReadConsole in kernel32)
331 // ReadConsoleRequest->NrCharactersRead = 0;
333 InputInfo
.CallingThread
= CsrGetClientThread();
334 InputInfo
.HandleEntry
= HandleEntry
;
335 InputInfo
.InputBuffer
= InputBuffer
;
337 Status
= ReadChars(&InputInfo
,
341 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
343 if (Status
== STATUS_PENDING
) *ReplyCode
= CsrReplyPending
;
348 CSR_API(SrvGetConsoleInput
)
351 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetInputRequest
;
352 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
354 PCONSOLE_INPUT_BUFFER InputBuffer
;
355 GET_INPUT_INFO InputInfo
;
357 DPRINT("SrvGetConsoleInput\n");
359 if (!CsrValidateMessageBuffer(ApiMessage
,
360 (PVOID
*)&GetInputRequest
->InputRecord
,
361 GetInputRequest
->Length
,
362 sizeof(INPUT_RECORD
)))
364 return STATUS_INVALID_PARAMETER
;
367 Status
= ConSrvGetInputBufferAndHandleEntry(ProcessData
, GetInputRequest
->InputHandle
, &InputBuffer
, &HandleEntry
, GENERIC_READ
, TRUE
);
368 if (!NT_SUCCESS(Status
)) return Status
;
370 GetInputRequest
->InputsRead
= 0;
372 InputInfo
.CallingThread
= CsrGetClientThread();
373 InputInfo
.HandleEntry
= HandleEntry
;
374 InputInfo
.InputBuffer
= InputBuffer
;
376 Status
= ReadInputBuffer(&InputInfo
,
377 GetInputRequest
->bRead
,
381 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
383 if (Status
== STATUS_PENDING
) *ReplyCode
= CsrReplyPending
;
389 ConDrvWriteConsoleInput(IN PCONSOLE Console
,
390 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
392 IN PINPUT_RECORD InputRecord
,
393 IN ULONG NumEventsToWrite
,
394 OUT PULONG NumEventsWritten OPTIONAL
);
395 CSR_API(SrvWriteConsoleInput
)
398 PCONSOLE_WRITEINPUT WriteInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.WriteInputRequest
;
399 PCONSOLE_INPUT_BUFFER InputBuffer
;
400 ULONG NumEventsWritten
;
402 DPRINT("SrvWriteConsoleInput\n");
404 if (!CsrValidateMessageBuffer(ApiMessage
,
405 (PVOID
*)&WriteInputRequest
->InputRecord
,
406 WriteInputRequest
->Length
,
407 sizeof(INPUT_RECORD
)))
409 return STATUS_INVALID_PARAMETER
;
412 Status
= ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
413 WriteInputRequest
->InputHandle
,
414 &InputBuffer
, GENERIC_WRITE
, TRUE
);
415 if (!NT_SUCCESS(Status
)) return Status
;
417 NumEventsWritten
= 0;
418 Status
= ConDrvWriteConsoleInput(InputBuffer
->Header
.Console
,
420 WriteInputRequest
->Unicode
,
421 WriteInputRequest
->InputRecord
,
422 WriteInputRequest
->Length
,
424 WriteInputRequest
->Length
= NumEventsWritten
;
426 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
431 ConDrvFlushConsoleInputBuffer(IN PCONSOLE Console
,
432 IN PCONSOLE_INPUT_BUFFER InputBuffer
);
433 CSR_API(SrvFlushConsoleInputBuffer
)
436 PCONSOLE_FLUSHINPUTBUFFER FlushInputBufferRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.FlushInputBufferRequest
;
437 PCONSOLE_INPUT_BUFFER InputBuffer
;
439 DPRINT("SrvFlushConsoleInputBuffer\n");
441 Status
= ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
442 FlushInputBufferRequest
->InputHandle
,
443 &InputBuffer
, GENERIC_WRITE
, TRUE
);
444 if (!NT_SUCCESS(Status
)) return Status
;
446 Status
= ConDrvFlushConsoleInputBuffer(InputBuffer
->Header
.Console
,
449 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
454 ConDrvGetConsoleNumberOfInputEvents(IN PCONSOLE Console
,
455 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
456 OUT PULONG NumEvents
);
457 CSR_API(SrvGetConsoleNumberOfInputEvents
)
460 PCONSOLE_GETNUMINPUTEVENTS GetNumInputEventsRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetNumInputEventsRequest
;
461 PCONSOLE_INPUT_BUFFER InputBuffer
;
463 DPRINT("SrvGetConsoleNumberOfInputEvents\n");
465 Status
= ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
466 GetNumInputEventsRequest
->InputHandle
,
467 &InputBuffer
, GENERIC_READ
, TRUE
);
468 if (!NT_SUCCESS(Status
)) return Status
;
470 Status
= ConDrvGetConsoleNumberOfInputEvents(InputBuffer
->Header
.Console
,
472 &GetNumInputEventsRequest
->NumInputEvents
);
474 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);