2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/consrv/coninput.c
5 * PURPOSE: Console I/O functions
9 /* INCLUDES *******************************************************************/
18 /* GLOBALS ********************************************************************/
20 #define ConsoleInputUnicodeCharToAnsiChar(Console, dChar, sWChar) \
21 WideCharToMultiByte((Console)->CodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
23 #define ConsoleInputAnsiCharToUnicodeChar(Console, dWChar, sChar) \
24 MultiByteToWideChar((Console)->CodePage, 0, (sChar), 1, (dWChar), 1)
27 typedef struct _GET_INPUT_INFO
29 PCSR_THREAD CallingThread
; // The thread which called the input API.
30 PCONSOLE_IO_HANDLE HandleEntry
; // The handle data associated with the wait thread.
31 PCONSOLE_INPUT_BUFFER InputBuffer
; // The input buffer corresponding to the handle.
32 } GET_INPUT_INFO
, *PGET_INPUT_INFO
;
35 /* PRIVATE FUNCTIONS **********************************************************/
38 ConioInputEventToAnsi(PCONSOLE Console
, PINPUT_RECORD InputEvent
)
40 if (InputEvent
->EventType
== KEY_EVENT
)
42 WCHAR UnicodeChar
= InputEvent
->Event
.KeyEvent
.uChar
.UnicodeChar
;
43 InputEvent
->Event
.KeyEvent
.uChar
.UnicodeChar
= 0;
44 ConsoleInputUnicodeCharToAnsiChar(Console
,
45 &InputEvent
->Event
.KeyEvent
.uChar
.AsciiChar
,
50 static NTSTATUS FASTCALL
51 ConioProcessChar(PCONSOLE Console
,
52 PINPUT_RECORD InputEvent
)
54 ConsoleInput
*ConInRec
;
56 /* Check for pause or unpause */
57 if (InputEvent
->EventType
== KEY_EVENT
&& InputEvent
->Event
.KeyEvent
.bKeyDown
)
59 WORD vk
= InputEvent
->Event
.KeyEvent
.wVirtualKeyCode
;
60 if (!(Console
->PauseFlags
& PAUSED_FROM_KEYBOARD
))
62 DWORD cks
= InputEvent
->Event
.KeyEvent
.dwControlKeyState
;
63 if (Console
->InputBuffer
.Mode
& ENABLE_LINE_INPUT
&&
64 (vk
== VK_PAUSE
|| (vk
== 'S' &&
65 (cks
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
)) &&
66 !(cks
& (LEFT_ALT_PRESSED
| RIGHT_ALT_PRESSED
)))))
68 ConioPause(Console
, PAUSED_FROM_KEYBOARD
);
69 return STATUS_SUCCESS
;
74 if ((vk
< VK_SHIFT
|| vk
> VK_CAPITAL
) && vk
!= VK_LWIN
&&
75 vk
!= VK_RWIN
&& vk
!= VK_NUMLOCK
&& vk
!= VK_SCROLL
)
77 ConioUnpause(Console
, PAUSED_FROM_KEYBOARD
);
78 return STATUS_SUCCESS
;
83 /* add event to the queue */
84 ConInRec
= RtlAllocateHeap(ConSrvHeap
, 0, sizeof(ConsoleInput
));
86 return STATUS_INSUFFICIENT_RESOURCES
;
87 ConInRec
->InputEvent
= *InputEvent
;
88 InsertTailList(&Console
->InputBuffer
.InputEvents
, &ConInRec
->ListEntry
);
90 SetEvent(Console
->InputBuffer
.ActiveEvent
);
91 CsrNotifyWait(&Console
->InputBuffer
.ReadWaitQueue
,
95 if (!IsListEmpty(&Console
->InputBuffer
.ReadWaitQueue
))
97 CsrDereferenceWait(&Console
->InputBuffer
.ReadWaitQueue
);
100 return STATUS_SUCCESS
;
103 static DWORD FASTCALL
104 ConioGetShiftState(PBYTE KeyState
)
108 if (KeyState
[VK_CAPITAL
] & 1)
109 ssOut
|= CAPSLOCK_ON
;
111 if (KeyState
[VK_NUMLOCK
] & 1)
114 if (KeyState
[VK_SCROLL
] & 1)
115 ssOut
|= SCROLLLOCK_ON
;
117 if (KeyState
[VK_SHIFT
] & 0x80)
118 ssOut
|= SHIFT_PRESSED
;
120 if (KeyState
[VK_LCONTROL
] & 0x80)
121 ssOut
|= LEFT_CTRL_PRESSED
;
122 if (KeyState
[VK_RCONTROL
] & 0x80)
123 ssOut
|= RIGHT_CTRL_PRESSED
;
125 if (KeyState
[VK_LMENU
] & 0x80)
126 ssOut
|= LEFT_ALT_PRESSED
;
127 if (KeyState
[VK_RMENU
] & 0x80)
128 ssOut
|= RIGHT_ALT_PRESSED
;
134 ConioProcessKey(PCONSOLE Console
, MSG
* msg
)
136 static BYTE KeyState
[256] = { 0 };
137 /* MSDN mentions that you should use the last virtual key code received
138 * when putting a virtual key identity to a WM_CHAR message since multiple
139 * or translated keys may be involved. */
140 static UINT LastVirtualKey
= 0;
145 UINT VirtualScanCode
;
148 BOOLEAN Fake
; // synthesized, not a real event
149 BOOLEAN NotChar
; // message should not be used to return a character
153 DPRINT1("No Active Console!\n");
158 VirtualScanCode
= (msg
->lParam
>> 16) & 0xff;
159 Down
= msg
->message
== WM_KEYDOWN
|| msg
->message
== WM_CHAR
||
160 msg
->message
== WM_SYSKEYDOWN
|| msg
->message
== WM_SYSCHAR
;
162 GetKeyboardState(KeyState
);
163 ShiftState
= ConioGetShiftState(KeyState
);
165 if (msg
->message
== WM_CHAR
|| msg
->message
== WM_SYSCHAR
)
167 VirtualKeyCode
= LastVirtualKey
;
168 UnicodeChar
= msg
->wParam
;
175 VirtualKeyCode
= msg
->wParam
;
176 RetChars
= ToUnicodeEx(VirtualKeyCode
,
183 UnicodeChar
= (1 == RetChars
? Chars
[0] : 0);
186 er
.EventType
= KEY_EVENT
;
187 er
.Event
.KeyEvent
.bKeyDown
= Down
;
188 er
.Event
.KeyEvent
.wRepeatCount
= RepeatCount
;
189 er
.Event
.KeyEvent
.uChar
.UnicodeChar
= UnicodeChar
;
190 er
.Event
.KeyEvent
.dwControlKeyState
= ShiftState
;
191 er
.Event
.KeyEvent
.wVirtualKeyCode
= VirtualKeyCode
;
192 er
.Event
.KeyEvent
.wVirtualScanCode
= VirtualScanCode
;
194 if (ConioProcessKeyCallback(Console
,
204 Fake
= UnicodeChar
&&
205 (msg
->message
!= WM_CHAR
&& msg
->message
!= WM_SYSCHAR
&&
206 msg
->message
!= WM_KEYUP
&& msg
->message
!= WM_SYSKEYUP
);
207 NotChar
= (msg
->message
!= WM_CHAR
&& msg
->message
!= WM_SYSCHAR
);
208 if (NotChar
) LastVirtualKey
= msg
->wParam
;
210 DPRINT("CONSRV: %s %s %s %s %02x %02x '%lc' %04x\n",
211 Down
? "down" : "up ",
212 (msg
->message
== WM_CHAR
|| msg
->message
== WM_SYSCHAR
) ?
214 Fake
? "fake" : "real",
215 NotChar
? "notc" : "char",
218 (UnicodeChar
>= L
' ') ? UnicodeChar
: L
'.',
223 /* process Ctrl-C and Ctrl-Break */
224 if (Console
->InputBuffer
.Mode
& ENABLE_PROCESSED_INPUT
&&
225 er
.Event
.KeyEvent
.bKeyDown
&&
226 ((er
.Event
.KeyEvent
.wVirtualKeyCode
== VK_PAUSE
) ||
227 (er
.Event
.KeyEvent
.wVirtualKeyCode
== 'C')) &&
228 (er
.Event
.KeyEvent
.dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
) || KeyState
[VK_CONTROL
] & 0x80))
230 DPRINT1("Console_Api Ctrl-C\n");
231 ConSrvConsoleProcessCtrlEvent(Console
, 0, CTRL_C_EVENT
);
233 if (Console
->LineBuffer
&& !Console
->LineComplete
)
235 /* Line input is in progress; end it */
236 Console
->LinePos
= Console
->LineSize
= 0;
237 Console
->LineComplete
= TRUE
;
242 if (0 != (er
.Event
.KeyEvent
.dwControlKeyState
243 & (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
))
244 && (VK_UP
== er
.Event
.KeyEvent
.wVirtualKeyCode
245 || VK_DOWN
== er
.Event
.KeyEvent
.wVirtualKeyCode
))
247 if (er
.Event
.KeyEvent
.bKeyDown
)
249 /* scroll up or down */
250 if (VK_UP
== er
.Event
.KeyEvent
.wVirtualKeyCode
)
252 /* only scroll up if there is room to scroll up into */
253 if (Console
->ActiveBuffer
->CursorPosition
.Y
!= Console
->ActiveBuffer
->ScreenBufferSize
.Y
- 1)
255 Console
->ActiveBuffer
->VirtualY
= (Console
->ActiveBuffer
->VirtualY
+
256 Console
->ActiveBuffer
->ScreenBufferSize
.Y
- 1) %
257 Console
->ActiveBuffer
->ScreenBufferSize
.Y
;
258 Console
->ActiveBuffer
->CursorPosition
.Y
++;
263 /* only scroll down if there is room to scroll down into */
264 if (Console
->ActiveBuffer
->CursorPosition
.Y
!= 0)
266 Console
->ActiveBuffer
->VirtualY
= (Console
->ActiveBuffer
->VirtualY
+ 1) %
267 Console
->ActiveBuffer
->ScreenBufferSize
.Y
;
268 Console
->ActiveBuffer
->CursorPosition
.Y
--;
271 ConioDrawConsole(Console
);
275 ConioProcessChar(Console
, &er
);
279 WaitBeforeReading(IN PGET_INPUT_INFO InputInfo
,
280 IN PCSR_API_MESSAGE ApiMessage
,
281 IN CSR_WAIT_FUNCTION WaitFunction OPTIONAL
,
282 IN BOOL CreateWaitBlock OPTIONAL
)
286 PGET_INPUT_INFO CapturedInputInfo
;
288 CapturedInputInfo
= RtlAllocateHeap(ConSrvHeap
, 0, sizeof(GET_INPUT_INFO
));
289 if (!CapturedInputInfo
) return STATUS_NO_MEMORY
;
291 RtlMoveMemory(CapturedInputInfo
, InputInfo
, sizeof(GET_INPUT_INFO
));
293 if (!CsrCreateWait(&InputInfo
->InputBuffer
->ReadWaitQueue
,
295 InputInfo
->CallingThread
,
300 RtlFreeHeap(ConSrvHeap
, 0, CapturedInputInfo
);
301 return STATUS_NO_MEMORY
;
306 return STATUS_PENDING
;
310 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo
,
312 IN PCSR_API_MESSAGE ApiMessage
,
313 IN BOOL CreateWaitBlock OPTIONAL
);
315 // Wait function CSR_WAIT_FUNCTION
317 ReadInputBufferThread(IN PLIST_ENTRY WaitList
,
318 IN PCSR_THREAD WaitThread
,
319 IN PCSR_API_MESSAGE WaitApiMessage
,
320 IN PVOID WaitContext
,
321 IN PVOID WaitArgument1
,
322 IN PVOID WaitArgument2
,
326 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)WaitApiMessage
)->Data
.GetInputRequest
;
327 PGET_INPUT_INFO InputInfo
= (PGET_INPUT_INFO
)WaitContext
;
329 PCONSOLE_IO_HANDLE InputHandle
= (PCONSOLE_IO_HANDLE
)WaitArgument2
;
331 DPRINT1("ReadInputBufferThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
334 * If we are notified of the process termination via a call
335 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
336 * CsrDestroyThread, just return.
338 if (WaitFlags
& CsrProcessTerminating
)
340 Status
= STATUS_THREAD_IS_TERMINATING
;
345 * Somebody is closing a handle to this input buffer,
346 * by calling ConSrvCloseHandleEntry.
347 * See whether we are linked to that handle (ie. we
348 * are a waiter for this handle), and if so, return.
349 * Otherwise, ignore the call and continue waiting.
351 if (InputHandle
!= NULL
)
353 Status
= (InputHandle
== InputInfo
->HandleEntry
? STATUS_ALERTED
359 * If we go there, that means we are notified for some new input.
360 * The console is therefore already locked.
362 Status
= ReadInputBuffer(InputInfo
,
363 GetInputRequest
->bRead
,
368 if (Status
!= STATUS_PENDING
)
370 WaitApiMessage
->Status
= Status
;
371 RtlFreeHeap(ConSrvHeap
, 0, InputInfo
);
374 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
378 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo
,
379 IN BOOL Wait
, // TRUE --> Read ; FALSE --> Peek
380 IN PCSR_API_MESSAGE ApiMessage
,
381 IN BOOL CreateWaitBlock OPTIONAL
)
383 PCONSOLE_INPUT_BUFFER InputBuffer
= InputInfo
->InputBuffer
;
385 if (IsListEmpty(&InputBuffer
->InputEvents
))
389 return WaitBeforeReading(InputInfo
,
391 ReadInputBufferThread
,
396 /* No input available and we don't wait, so we return success */
397 return STATUS_SUCCESS
;
402 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetInputRequest
;
403 PLIST_ENTRY CurrentInput
;
405 ULONG Length
= GetInputRequest
->Length
;
406 PINPUT_RECORD InputRecord
= GetInputRequest
->InputRecord
;
408 /* Only get input if there is any */
409 CurrentInput
= InputBuffer
->InputEvents
.Flink
;
411 while ( CurrentInput
!= &InputBuffer
->InputEvents
&&
412 GetInputRequest
->InputsRead
< Length
)
414 Input
= CONTAINING_RECORD(CurrentInput
, ConsoleInput
, ListEntry
);
416 GetInputRequest
->InputsRead
++;
417 *InputRecord
= Input
->InputEvent
;
419 if (GetInputRequest
->Unicode
== FALSE
)
421 ConioInputEventToAnsi(InputBuffer
->Header
.Console
, InputRecord
);
425 CurrentInput
= CurrentInput
->Flink
;
427 if (Wait
) // TRUE --> Read, we remove inputs from the buffer ; FALSE --> Peek, we keep inputs.
429 RemoveEntryList(&Input
->ListEntry
);
430 RtlFreeHeap(ConSrvHeap
, 0, Input
);
434 if (IsListEmpty(&InputBuffer
->InputEvents
))
436 ResetEvent(InputBuffer
->ActiveEvent
);
439 /* We read all the inputs available, we return success */
440 return STATUS_SUCCESS
;
445 ReadChars(IN PGET_INPUT_INFO InputInfo
,
446 IN PCSR_API_MESSAGE ApiMessage
,
447 IN BOOL CreateWaitBlock OPTIONAL
);
449 // Wait function CSR_WAIT_FUNCTION
451 ReadCharsThread(IN PLIST_ENTRY WaitList
,
452 IN PCSR_THREAD WaitThread
,
453 IN PCSR_API_MESSAGE WaitApiMessage
,
454 IN PVOID WaitContext
,
455 IN PVOID WaitArgument1
,
456 IN PVOID WaitArgument2
,
460 PGET_INPUT_INFO InputInfo
= (PGET_INPUT_INFO
)WaitContext
;
462 PCONSOLE_IO_HANDLE InputHandle
= (PCONSOLE_IO_HANDLE
)WaitArgument2
;
464 DPRINT1("ReadCharsThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
467 * If we are notified of the process termination via a call
468 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
469 * CsrDestroyThread, just return.
471 if (WaitFlags
& CsrProcessTerminating
)
473 Status
= STATUS_THREAD_IS_TERMINATING
;
478 * Somebody is closing a handle to this input buffer,
479 * by calling ConSrvCloseHandleEntry.
480 * See whether we are linked to that handle (ie. we
481 * are a waiter for this handle), and if so, return.
482 * Otherwise, ignore the call and continue waiting.
484 if (InputHandle
!= NULL
)
486 Status
= (InputHandle
== InputInfo
->HandleEntry
? STATUS_ALERTED
492 * If we go there, that means we are notified for some new input.
493 * The console is therefore already locked.
495 Status
= ReadChars(InputInfo
,
500 if (Status
!= STATUS_PENDING
)
502 WaitApiMessage
->Status
= Status
;
503 RtlFreeHeap(ConSrvHeap
, 0, InputInfo
);
506 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
510 ReadChars(IN PGET_INPUT_INFO InputInfo
,
511 IN PCSR_API_MESSAGE ApiMessage
,
512 IN BOOL CreateWaitBlock OPTIONAL
)
514 BOOL WaitForMoreToRead
= TRUE
; // TRUE : Wait if more to read ; FALSE : Don't wait.
516 PCONSOLE_READCONSOLE ReadConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadConsoleRequest
;
517 PCONSOLE_INPUT_BUFFER InputBuffer
= InputInfo
->InputBuffer
;
518 PCONSOLE Console
= InputBuffer
->Header
.Console
;
519 PLIST_ENTRY CurrentEntry
;
521 PCHAR Buffer
= (PCHAR
)ReadConsoleRequest
->Buffer
;
522 PWCHAR UnicodeBuffer
= (PWCHAR
)Buffer
;
523 ULONG nNumberOfCharsToRead
= ReadConsoleRequest
->NrCharactersToRead
;
525 /* We haven't read anything (yet) */
527 if (InputBuffer
->Mode
& ENABLE_LINE_INPUT
)
529 if (Console
->LineBuffer
== NULL
)
531 /* Starting a new line */
532 Console
->LineMaxSize
= max(256, nNumberOfCharsToRead
);
533 Console
->LineBuffer
= RtlAllocateHeap(ConSrvHeap
, 0, Console
->LineMaxSize
* sizeof(WCHAR
));
534 if (Console
->LineBuffer
== NULL
)
536 return STATUS_NO_MEMORY
;
538 Console
->LineComplete
= FALSE
;
539 Console
->LineUpPressed
= FALSE
;
540 Console
->LineInsertToggle
= 0;
541 Console
->LineWakeupMask
= ReadConsoleRequest
->CtrlWakeupMask
;
542 Console
->LineSize
= ReadConsoleRequest
->NrCharactersRead
;
543 Console
->LinePos
= Console
->LineSize
;
546 * Pre-filling the buffer is only allowed in the Unicode API,
547 * so we don't need to worry about ANSI <-> Unicode conversion.
549 memcpy(Console
->LineBuffer
, Buffer
, Console
->LineSize
* sizeof(WCHAR
));
550 if (Console
->LineSize
== Console
->LineMaxSize
)
552 Console
->LineComplete
= TRUE
;
553 Console
->LinePos
= 0;
557 /* If we don't have a complete line yet, process the pending input */
558 while ( !Console
->LineComplete
&&
559 !IsListEmpty(&InputBuffer
->InputEvents
) )
561 /* Remove input event from queue */
562 CurrentEntry
= RemoveHeadList(&InputBuffer
->InputEvents
);
563 if (IsListEmpty(&InputBuffer
->InputEvents
))
565 ResetEvent(InputBuffer
->ActiveEvent
);
567 Input
= CONTAINING_RECORD(CurrentEntry
, ConsoleInput
, ListEntry
);
569 /* Only pay attention to key down */
570 if (KEY_EVENT
== Input
->InputEvent
.EventType
571 && Input
->InputEvent
.Event
.KeyEvent
.bKeyDown
)
573 LineInputKeyDown(Console
, &Input
->InputEvent
.Event
.KeyEvent
);
574 ReadConsoleRequest
->ControlKeyState
= Input
->InputEvent
.Event
.KeyEvent
.dwControlKeyState
;
576 RtlFreeHeap(ConSrvHeap
, 0, Input
);
579 /* Check if we have a complete line to read from */
580 if (Console
->LineComplete
)
582 while ( ReadConsoleRequest
->NrCharactersRead
< nNumberOfCharsToRead
&&
583 Console
->LinePos
!= Console
->LineSize
)
585 WCHAR Char
= Console
->LineBuffer
[Console
->LinePos
++];
587 if (ReadConsoleRequest
->Unicode
)
589 UnicodeBuffer
[ReadConsoleRequest
->NrCharactersRead
] = Char
;
593 ConsoleInputUnicodeCharToAnsiChar(Console
,
594 &Buffer
[ReadConsoleRequest
->NrCharactersRead
],
598 ReadConsoleRequest
->NrCharactersRead
++;
601 if (Console
->LinePos
== Console
->LineSize
)
603 /* Entire line has been read */
604 RtlFreeHeap(ConSrvHeap
, 0, Console
->LineBuffer
);
605 Console
->LineBuffer
= NULL
;
608 WaitForMoreToRead
= FALSE
;
613 /* Character input */
614 while ( ReadConsoleRequest
->NrCharactersRead
< nNumberOfCharsToRead
&&
615 !IsListEmpty(&InputBuffer
->InputEvents
) )
617 /* Remove input event from queue */
618 CurrentEntry
= RemoveHeadList(&InputBuffer
->InputEvents
);
619 if (IsListEmpty(&InputBuffer
->InputEvents
))
621 ResetEvent(InputBuffer
->ActiveEvent
);
623 Input
= CONTAINING_RECORD(CurrentEntry
, ConsoleInput
, ListEntry
);
625 /* Only pay attention to valid ascii chars, on key down */
626 if (KEY_EVENT
== Input
->InputEvent
.EventType
627 && Input
->InputEvent
.Event
.KeyEvent
.bKeyDown
628 && Input
->InputEvent
.Event
.KeyEvent
.uChar
.UnicodeChar
!= L
'\0')
630 WCHAR Char
= Input
->InputEvent
.Event
.KeyEvent
.uChar
.UnicodeChar
;
632 if (ReadConsoleRequest
->Unicode
)
634 UnicodeBuffer
[ReadConsoleRequest
->NrCharactersRead
] = Char
;
638 ConsoleInputUnicodeCharToAnsiChar(Console
,
639 &Buffer
[ReadConsoleRequest
->NrCharactersRead
],
643 ReadConsoleRequest
->NrCharactersRead
++;
645 /* Did read something */
646 WaitForMoreToRead
= FALSE
;
648 RtlFreeHeap(ConSrvHeap
, 0, Input
);
652 /* We haven't completed a read, so start a wait */
653 if (WaitForMoreToRead
== TRUE
)
655 return WaitBeforeReading(InputInfo
,
660 else /* We read all what we wanted, we return success */
662 return STATUS_SUCCESS
;
667 /* PUBLIC SERVER APIS *********************************************************/
669 CSR_API(SrvReadConsole
)
672 PCONSOLE_READCONSOLE ReadConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadConsoleRequest
;
673 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
674 PCONSOLE_IO_HANDLE HandleEntry
;
675 PCONSOLE_INPUT_BUFFER InputBuffer
;
676 GET_INPUT_INFO InputInfo
;
678 DPRINT("SrvReadConsole\n");
680 if (!CsrValidateMessageBuffer(ApiMessage
,
681 (PVOID
*)&ReadConsoleRequest
->Buffer
,
682 ReadConsoleRequest
->BufferSize
,
685 return STATUS_INVALID_PARAMETER
;
688 if (ReadConsoleRequest
->NrCharactersRead
> ReadConsoleRequest
->NrCharactersToRead
)
690 return STATUS_INVALID_PARAMETER
;
693 Status
= ConSrvGetInputBufferAndHandleEntry(ProcessData
, ReadConsoleRequest
->InputHandle
, &InputBuffer
, &HandleEntry
, GENERIC_READ
, TRUE
);
694 if (!NT_SUCCESS(Status
)) return Status
;
696 ReadConsoleRequest
->NrCharactersRead
= 0;
698 InputInfo
.CallingThread
= CsrGetClientThread();
699 InputInfo
.HandleEntry
= HandleEntry
;
700 InputInfo
.InputBuffer
= InputBuffer
;
702 Status
= ReadChars(&InputInfo
,
706 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
708 if (Status
== STATUS_PENDING
)
709 *ReplyCode
= CsrReplyPending
;
714 CSR_API(SrvGetConsoleInput
)
717 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetInputRequest
;
718 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
719 PCONSOLE_IO_HANDLE HandleEntry
;
720 PCONSOLE_INPUT_BUFFER InputBuffer
;
721 GET_INPUT_INFO InputInfo
;
723 DPRINT("SrvGetConsoleInput\n");
725 if (!CsrValidateMessageBuffer(ApiMessage
,
726 (PVOID
*)&GetInputRequest
->InputRecord
,
727 GetInputRequest
->Length
,
728 sizeof(INPUT_RECORD
)))
730 return STATUS_INVALID_PARAMETER
;
733 GetInputRequest
->InputsRead
= 0;
735 Status
= ConSrvGetInputBufferAndHandleEntry(ProcessData
, GetInputRequest
->InputHandle
, &InputBuffer
, &HandleEntry
, GENERIC_READ
, TRUE
);
736 if(!NT_SUCCESS(Status
)) return Status
;
738 InputInfo
.CallingThread
= CsrGetClientThread();
739 InputInfo
.HandleEntry
= HandleEntry
;
740 InputInfo
.InputBuffer
= InputBuffer
;
742 Status
= ReadInputBuffer(&InputInfo
,
743 GetInputRequest
->bRead
,
747 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
749 if (Status
== STATUS_PENDING
)
750 *ReplyCode
= CsrReplyPending
;
755 CSR_API(SrvWriteConsoleInput
)
758 PCONSOLE_WRITEINPUT WriteInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.WriteInputRequest
;
759 PINPUT_RECORD InputRecord
;
760 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
761 PCONSOLE_INPUT_BUFFER InputBuffer
;
766 DPRINT("SrvWriteConsoleInput\n");
768 if (!CsrValidateMessageBuffer(ApiMessage
,
769 (PVOID
*)&WriteInputRequest
->InputRecord
,
770 WriteInputRequest
->Length
,
771 sizeof(INPUT_RECORD
)))
773 return STATUS_INVALID_PARAMETER
;
776 Status
= ConSrvGetInputBuffer(ProcessData
, WriteInputRequest
->InputHandle
, &InputBuffer
, GENERIC_WRITE
, TRUE
);
777 if (!NT_SUCCESS(Status
)) return Status
;
779 Console
= InputBuffer
->Header
.Console
;
780 InputRecord
= WriteInputRequest
->InputRecord
;
781 Length
= WriteInputRequest
->Length
;
783 for (i
= 0; i
< Length
&& NT_SUCCESS(Status
); i
++)
785 if (!WriteInputRequest
->Unicode
&&
786 InputRecord
->EventType
== KEY_EVENT
)
788 CHAR AsciiChar
= InputRecord
->Event
.KeyEvent
.uChar
.AsciiChar
;
789 ConsoleInputAnsiCharToUnicodeChar(Console
,
790 &InputRecord
->Event
.KeyEvent
.uChar
.UnicodeChar
,
794 Status
= ConioProcessChar(Console
, InputRecord
++);
797 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
799 WriteInputRequest
->Length
= i
;
804 CSR_API(SrvFlushConsoleInputBuffer
)
807 PCONSOLE_FLUSHINPUTBUFFER FlushInputBufferRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.FlushInputBufferRequest
;
808 PLIST_ENTRY CurrentEntry
;
809 PCONSOLE_INPUT_BUFFER InputBuffer
;
812 DPRINT("SrvFlushConsoleInputBuffer\n");
814 Status
= ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
815 FlushInputBufferRequest
->InputHandle
,
819 if(!NT_SUCCESS(Status
)) return Status
;
821 /* Discard all entries in the input event queue */
822 while (!IsListEmpty(&InputBuffer
->InputEvents
))
824 CurrentEntry
= RemoveHeadList(&InputBuffer
->InputEvents
);
825 Event
= CONTAINING_RECORD(CurrentEntry
, ConsoleInput
, ListEntry
);
826 RtlFreeHeap(ConSrvHeap
, 0, Event
);
828 ResetEvent(InputBuffer
->ActiveEvent
);
830 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
831 return STATUS_SUCCESS
;
834 CSR_API(SrvGetConsoleNumberOfInputEvents
)
837 PCONSOLE_GETNUMINPUTEVENTS GetNumInputEventsRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetNumInputEventsRequest
;
838 PCONSOLE_INPUT_BUFFER InputBuffer
;
839 PLIST_ENTRY CurrentInput
;
842 DPRINT("SrvGetConsoleNumberOfInputEvents\n");
844 Status
= ConSrvGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), GetNumInputEventsRequest
->InputHandle
, &InputBuffer
, GENERIC_READ
, TRUE
);
845 if (!NT_SUCCESS(Status
)) return Status
;
847 CurrentInput
= InputBuffer
->InputEvents
.Flink
;
848 /* GetNumInputEventsRequest->NumInputEvents = */ NumEvents
= 0;
850 /* If there are any events ... */
851 while (CurrentInput
!= &InputBuffer
->InputEvents
)
853 CurrentInput
= CurrentInput
->Flink
;
857 ConSrvReleaseInputBuffer(InputBuffer
, TRUE
);
859 GetNumInputEventsRequest
->NumInputEvents
= NumEvents
;
861 return STATUS_SUCCESS
;