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 *******************************************************************/
13 #include "tuiconsole.h"
19 /* GLOBALS ********************************************************************/
21 #define ConsoleInputUnicodeCharToAnsiChar(Console, dChar, sWChar) \
22 WideCharToMultiByte((Console)->CodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
24 #define ConsoleInputAnsiCharToUnicodeChar(Console, dWChar, sChar) \
25 MultiByteToWideChar((Console)->CodePage, 0, (sChar), 1, (dWChar), 1)
28 typedef struct _GET_INPUT_INFO
30 PCSR_THREAD CallingThread
; // The thread which called the input API.
31 PCONSOLE_IO_HANDLE HandleEntry
; // The handle data associated with the wait thread.
32 PCONSOLE_INPUT_BUFFER InputBuffer
; // The input buffer corresponding to the handle.
33 } GET_INPUT_INFO
, *PGET_INPUT_INFO
;
36 /* PRIVATE FUNCTIONS **********************************************************/
39 ConioInputEventToAnsi(PCONSOLE Console
, PINPUT_RECORD InputEvent
)
41 if (InputEvent
->EventType
== KEY_EVENT
)
43 WCHAR UnicodeChar
= InputEvent
->Event
.KeyEvent
.uChar
.UnicodeChar
;
44 InputEvent
->Event
.KeyEvent
.uChar
.UnicodeChar
= 0;
45 ConsoleInputUnicodeCharToAnsiChar(Console
,
46 &InputEvent
->Event
.KeyEvent
.uChar
.AsciiChar
,
51 static NTSTATUS FASTCALL
52 ConioProcessChar(PCONSOLE Console
,
53 PINPUT_RECORD InputEvent
)
55 ConsoleInput
*ConInRec
;
57 /* Check for pause or unpause */
58 if (InputEvent
->EventType
== KEY_EVENT
&& InputEvent
->Event
.KeyEvent
.bKeyDown
)
60 WORD vk
= InputEvent
->Event
.KeyEvent
.wVirtualKeyCode
;
61 if (!(Console
->PauseFlags
& PAUSED_FROM_KEYBOARD
))
63 DWORD cks
= InputEvent
->Event
.KeyEvent
.dwControlKeyState
;
64 if (Console
->InputBuffer
.Mode
& ENABLE_LINE_INPUT
&&
65 (vk
== VK_PAUSE
|| (vk
== 'S' &&
66 (cks
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
)) &&
67 !(cks
& (LEFT_ALT_PRESSED
| RIGHT_ALT_PRESSED
)))))
69 ConioPause(Console
, PAUSED_FROM_KEYBOARD
);
70 return STATUS_SUCCESS
;
75 if ((vk
< VK_SHIFT
|| vk
> VK_CAPITAL
) && vk
!= VK_LWIN
&&
76 vk
!= VK_RWIN
&& vk
!= VK_NUMLOCK
&& vk
!= VK_SCROLL
)
78 ConioUnpause(Console
, PAUSED_FROM_KEYBOARD
);
79 return STATUS_SUCCESS
;
84 /* add event to the queue */
85 ConInRec
= RtlAllocateHeap(ConSrvHeap
, 0, sizeof(ConsoleInput
));
87 return STATUS_INSUFFICIENT_RESOURCES
;
88 ConInRec
->InputEvent
= *InputEvent
;
89 InsertTailList(&Console
->InputBuffer
.InputEvents
, &ConInRec
->ListEntry
);
91 SetEvent(Console
->InputBuffer
.ActiveEvent
);
92 CsrNotifyWait(&Console
->InputBuffer
.ReadWaitQueue
,
97 return STATUS_SUCCESS
;
100 static DWORD FASTCALL
101 ConioGetShiftState(PBYTE KeyState
)
105 if (KeyState
[VK_CAPITAL
] & 1)
106 ssOut
|= CAPSLOCK_ON
;
108 if (KeyState
[VK_NUMLOCK
] & 1)
111 if (KeyState
[VK_SCROLL
] & 1)
112 ssOut
|= SCROLLLOCK_ON
;
114 if (KeyState
[VK_SHIFT
] & 0x80)
115 ssOut
|= SHIFT_PRESSED
;
117 if (KeyState
[VK_LCONTROL
] & 0x80)
118 ssOut
|= LEFT_CTRL_PRESSED
;
119 if (KeyState
[VK_RCONTROL
] & 0x80)
120 ssOut
|= RIGHT_CTRL_PRESSED
;
122 if (KeyState
[VK_LMENU
] & 0x80)
123 ssOut
|= LEFT_ALT_PRESSED
;
124 if (KeyState
[VK_RMENU
] & 0x80)
125 ssOut
|= RIGHT_ALT_PRESSED
;
131 ConioProcessKey(MSG
*msg
, PCONSOLE Console
, BOOL TextMode
)
133 static BYTE KeyState
[256] = { 0 };
134 /* MSDN mentions that you should use the last virtual key code received
135 * when putting a virtual key identity to a WM_CHAR message since multiple
136 * or translated keys may be involved. */
137 static UINT LastVirtualKey
= 0;
142 UINT VirtualScanCode
;
145 BOOLEAN Fake
; // synthesized, not a real event
146 BOOLEAN NotChar
; // message should not be used to return a character
149 VirtualScanCode
= (msg
->lParam
>> 16) & 0xff;
150 Down
= msg
->message
== WM_KEYDOWN
|| msg
->message
== WM_CHAR
||
151 msg
->message
== WM_SYSKEYDOWN
|| msg
->message
== WM_SYSCHAR
;
153 GetKeyboardState(KeyState
);
154 ShiftState
= ConioGetShiftState(KeyState
);
156 if (msg
->message
== WM_CHAR
|| msg
->message
== WM_SYSCHAR
)
158 VirtualKeyCode
= LastVirtualKey
;
159 UnicodeChar
= msg
->wParam
;
166 VirtualKeyCode
= msg
->wParam
;
167 RetChars
= ToUnicodeEx(VirtualKeyCode
,
174 UnicodeChar
= (1 == RetChars
? Chars
[0] : 0);
177 er
.EventType
= KEY_EVENT
;
178 er
.Event
.KeyEvent
.bKeyDown
= Down
;
179 er
.Event
.KeyEvent
.wRepeatCount
= RepeatCount
;
180 er
.Event
.KeyEvent
.uChar
.UnicodeChar
= UnicodeChar
;
181 er
.Event
.KeyEvent
.dwControlKeyState
= ShiftState
;
182 er
.Event
.KeyEvent
.wVirtualKeyCode
= VirtualKeyCode
;
183 er
.Event
.KeyEvent
.wVirtualScanCode
= VirtualScanCode
;
187 if (0 != (ShiftState
& (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
))
188 && VK_TAB
== VirtualKeyCode
)
192 TuiSwapConsole(ShiftState
& SHIFT_PRESSED
? -1 : 1);
197 else if (VK_MENU
== VirtualKeyCode
&& ! Down
)
199 if (TuiSwapConsole(0))
207 if ((ShiftState
& (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
) || KeyState
[VK_MENU
] & 0x80) &&
208 (VirtualKeyCode
== VK_ESCAPE
|| VirtualKeyCode
== VK_TAB
|| VirtualKeyCode
== VK_SPACE
))
210 DefWindowProcW(msg
->hwnd
, msg
->message
, msg
->wParam
, msg
->lParam
);
217 DPRINT1("No Active Console!\n");
221 Fake
= UnicodeChar
&&
222 (msg
->message
!= WM_CHAR
&& msg
->message
!= WM_SYSCHAR
&&
223 msg
->message
!= WM_KEYUP
&& msg
->message
!= WM_SYSKEYUP
);
224 NotChar
= (msg
->message
!= WM_CHAR
&& msg
->message
!= WM_SYSCHAR
);
226 LastVirtualKey
= msg
->wParam
;
228 DPRINT("CONSRV: %s %s %s %s %02x %02x '%lc' %04x\n",
229 Down
? "down" : "up ",
230 (msg
->message
== WM_CHAR
|| msg
->message
== WM_SYSCHAR
) ?
232 Fake
? "fake" : "real",
233 NotChar
? "notc" : "char",
236 (UnicodeChar
>= L
' ') ? UnicodeChar
: L
'.',
242 /* process Ctrl-C and Ctrl-Break */
243 if (Console
->InputBuffer
.Mode
& ENABLE_PROCESSED_INPUT
&&
244 er
.Event
.KeyEvent
.bKeyDown
&&
245 ((er
.Event
.KeyEvent
.wVirtualKeyCode
== VK_PAUSE
) ||
246 (er
.Event
.KeyEvent
.wVirtualKeyCode
== 'C')) &&
247 (er
.Event
.KeyEvent
.dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
) || KeyState
[VK_CONTROL
] & 0x80))
249 PCONSOLE_PROCESS_DATA current
;
250 PLIST_ENTRY current_entry
;
252 DPRINT1("Console_Api Ctrl-C\n");
254 current_entry
= Console
->ProcessList
.Flink
;
255 while (current_entry
!= &Console
->ProcessList
)
257 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
258 current_entry
= current_entry
->Flink
;
259 ConioConsoleCtrlEvent(CTRL_C_EVENT
, current
);
261 if (Console
->LineBuffer
&& !Console
->LineComplete
)
263 /* Line input is in progress; end it */
264 Console
->LinePos
= Console
->LineSize
= 0;
265 Console
->LineComplete
= TRUE
;
270 if (0 != (er
.Event
.KeyEvent
.dwControlKeyState
271 & (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
))
272 && (VK_UP
== er
.Event
.KeyEvent
.wVirtualKeyCode
273 || VK_DOWN
== er
.Event
.KeyEvent
.wVirtualKeyCode
))
275 if (er
.Event
.KeyEvent
.bKeyDown
)
277 /* scroll up or down */
278 if (VK_UP
== er
.Event
.KeyEvent
.wVirtualKeyCode
)
280 /* only scroll up if there is room to scroll up into */
281 if (Console
->ActiveBuffer
->CurrentY
!= Console
->ActiveBuffer
->MaxY
- 1)
283 Console
->ActiveBuffer
->VirtualY
= (Console
->ActiveBuffer
->VirtualY
+
284 Console
->ActiveBuffer
->MaxY
- 1) %
285 Console
->ActiveBuffer
->MaxY
;
286 Console
->ActiveBuffer
->CurrentY
++;
291 /* only scroll down if there is room to scroll down into */
292 if (Console
->ActiveBuffer
->CurrentY
!= 0)
294 Console
->ActiveBuffer
->VirtualY
= (Console
->ActiveBuffer
->VirtualY
+ 1) %
295 Console
->ActiveBuffer
->MaxY
;
296 Console
->ActiveBuffer
->CurrentY
--;
299 ConioDrawConsole(Console
);
303 ConioProcessChar(Console
, &er
);
307 WaitBeforeReading(IN PGET_INPUT_INFO InputInfo
,
308 IN PCSR_API_MESSAGE ApiMessage
,
309 IN CSR_WAIT_FUNCTION WaitFunction OPTIONAL
,
310 IN BOOL CreateWaitBlock OPTIONAL
)
314 PGET_INPUT_INFO CapturedInputInfo
;
316 CapturedInputInfo
= RtlAllocateHeap(ConSrvHeap
, 0, sizeof(GET_INPUT_INFO
));
317 if (!CapturedInputInfo
) return STATUS_NO_MEMORY
;
319 RtlMoveMemory(CapturedInputInfo
, InputInfo
, sizeof(GET_INPUT_INFO
));
321 if (!CsrCreateWait(&InputInfo
->InputBuffer
->ReadWaitQueue
,
323 InputInfo
->CallingThread
,
328 RtlFreeHeap(ConSrvHeap
, 0, CapturedInputInfo
);
329 return STATUS_NO_MEMORY
;
334 return STATUS_PENDING
;
338 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo
,
340 IN PCSR_API_MESSAGE ApiMessage
,
341 IN BOOL CreateWaitBlock OPTIONAL
);
343 // Wait function CSR_WAIT_FUNCTION
345 ReadInputBufferThread(IN PLIST_ENTRY WaitList
,
346 IN PCSR_THREAD WaitThread
,
347 IN PCSR_API_MESSAGE WaitApiMessage
,
348 IN PVOID WaitContext
,
349 IN PVOID WaitArgument1
,
350 IN PVOID WaitArgument2
,
354 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)WaitApiMessage
)->Data
.GetInputRequest
;
355 PGET_INPUT_INFO InputInfo
= (PGET_INPUT_INFO
)WaitContext
;
357 PCONSOLE_IO_HANDLE InputHandle
= (PCONSOLE_IO_HANDLE
)WaitArgument2
;
359 DPRINT1("ReadInputBufferThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
362 * Somebody is closing a handle to this input buffer,
363 * by calling Win32CsrCloseHandleEntry.
364 * See whether we are linked to that handle (ie. we
365 * are a waiter for this handle), and if so, return.
367 if (InputHandle
== InputInfo
->HandleEntry
)
369 Status
= STATUS_ALERTED
;
374 * If we are notified of the process termination via a call
375 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
376 * CsrDestroyThread, just return.
378 if (WaitFlags
& CsrProcessTerminating
)
380 Status
= STATUS_THREAD_IS_TERMINATING
;
385 * If we go there, that means we are notified for some new input.
386 * The console is therefore already locked.
388 Status
= ReadInputBuffer(InputInfo
,
389 GetInputRequest
->bRead
,
394 if (Status
!= STATUS_PENDING
)
396 WaitApiMessage
->Status
= Status
;
397 RtlFreeHeap(ConSrvHeap
, 0, InputInfo
);
400 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
404 ReadInputBuffer(IN PGET_INPUT_INFO InputInfo
,
405 IN BOOL Wait
, // TRUE --> Read ; FALSE --> Peek
406 IN PCSR_API_MESSAGE ApiMessage
,
407 IN BOOL CreateWaitBlock OPTIONAL
)
409 PCONSOLE_INPUT_BUFFER InputBuffer
= InputInfo
->InputBuffer
;
411 if (IsListEmpty(&InputBuffer
->InputEvents
))
415 return WaitBeforeReading(InputInfo
,
417 ReadInputBufferThread
,
422 /* No input available and we don't wait, so we return success */
423 return STATUS_SUCCESS
;
428 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetInputRequest
;
429 PLIST_ENTRY CurrentInput
;
431 ULONG Length
= GetInputRequest
->Length
;
432 PINPUT_RECORD InputRecord
= GetInputRequest
->InputRecord
;
434 /* Only get input if there is any */
435 CurrentInput
= InputBuffer
->InputEvents
.Flink
;
437 while ( CurrentInput
!= &InputBuffer
->InputEvents
&&
438 GetInputRequest
->InputsRead
< Length
)
440 Input
= CONTAINING_RECORD(CurrentInput
, ConsoleInput
, ListEntry
);
442 GetInputRequest
->InputsRead
++;
443 *InputRecord
= Input
->InputEvent
;
445 if (GetInputRequest
->Unicode
== FALSE
)
447 ConioInputEventToAnsi(InputBuffer
->Header
.Console
, InputRecord
);
451 CurrentInput
= CurrentInput
->Flink
;
453 if (Wait
) // TRUE --> Read, we remove inputs from the buffer ; FALSE --> Peek, we keep inputs.
455 RemoveEntryList(&Input
->ListEntry
);
456 RtlFreeHeap(ConSrvHeap
, 0, Input
);
460 if (IsListEmpty(&InputBuffer
->InputEvents
))
462 ResetEvent(InputBuffer
->ActiveEvent
);
465 /* We read all the inputs available, we return success */
466 return STATUS_SUCCESS
;
471 ReadChars(IN PGET_INPUT_INFO InputInfo
,
472 IN PCSR_API_MESSAGE ApiMessage
,
473 IN BOOL CreateWaitBlock OPTIONAL
);
475 // Wait function CSR_WAIT_FUNCTION
477 ReadCharsThread(IN PLIST_ENTRY WaitList
,
478 IN PCSR_THREAD WaitThread
,
479 IN PCSR_API_MESSAGE WaitApiMessage
,
480 IN PVOID WaitContext
,
481 IN PVOID WaitArgument1
,
482 IN PVOID WaitArgument2
,
486 PGET_INPUT_INFO InputInfo
= (PGET_INPUT_INFO
)WaitContext
;
488 PCONSOLE_IO_HANDLE InputHandle
= (PCONSOLE_IO_HANDLE
)WaitArgument2
;
490 DPRINT1("ReadCharsThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext
, WaitArgument1
, WaitArgument2
, WaitFlags
);
493 * Somebody is closing a handle to this input buffer,
494 * by calling Win32CsrCloseHandleEntry.
495 * See whether we are linked to that handle (ie. we
496 * are a waiter for this handle), and if so, return.
498 if (InputHandle
== InputInfo
->HandleEntry
)
500 Status
= STATUS_ALERTED
;
505 * If we are notified of the process termination via a call
506 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
507 * CsrDestroyThread, just return.
509 if (WaitFlags
& CsrProcessTerminating
)
511 Status
= STATUS_THREAD_IS_TERMINATING
;
516 * If we go there, that means we are notified for some new input.
517 * The console is therefore already locked.
519 Status
= ReadChars(InputInfo
,
524 if (Status
!= STATUS_PENDING
)
526 WaitApiMessage
->Status
= Status
;
527 RtlFreeHeap(ConSrvHeap
, 0, InputInfo
);
530 return (Status
== STATUS_PENDING
? FALSE
: TRUE
);
534 ReadChars(IN PGET_INPUT_INFO InputInfo
,
535 IN PCSR_API_MESSAGE ApiMessage
,
536 IN BOOL CreateWaitBlock OPTIONAL
)
538 BOOL WaitForMoreToRead
= TRUE
; // TRUE : Wait if more to read ; FALSE : Don't wait.
540 PCONSOLE_READCONSOLE ReadConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadConsoleRequest
;
541 PCONSOLE_INPUT_BUFFER InputBuffer
= InputInfo
->InputBuffer
;
542 PCONSOLE Console
= InputBuffer
->Header
.Console
;
543 PLIST_ENTRY CurrentEntry
;
545 PCHAR Buffer
= (PCHAR
)ReadConsoleRequest
->Buffer
;
546 PWCHAR UnicodeBuffer
= (PWCHAR
)Buffer
;
547 ULONG nNumberOfCharsToRead
= ReadConsoleRequest
->NrCharactersToRead
;
549 /* We haven't read anything (yet) */
551 if (InputBuffer
->Mode
& ENABLE_LINE_INPUT
)
553 if (Console
->LineBuffer
== NULL
)
555 /* Starting a new line */
556 Console
->LineMaxSize
= max(256, nNumberOfCharsToRead
);
557 Console
->LineBuffer
= RtlAllocateHeap(ConSrvHeap
, 0, Console
->LineMaxSize
* sizeof(WCHAR
));
558 if (Console
->LineBuffer
== NULL
)
560 return STATUS_NO_MEMORY
;
562 Console
->LineComplete
= FALSE
;
563 Console
->LineUpPressed
= FALSE
;
564 Console
->LineInsertToggle
= 0;
565 Console
->LineWakeupMask
= ReadConsoleRequest
->CtrlWakeupMask
;
566 Console
->LineSize
= ReadConsoleRequest
->NrCharactersRead
;
567 Console
->LinePos
= Console
->LineSize
;
570 * Pre-filling the buffer is only allowed in the Unicode API,
571 * so we don't need to worry about ANSI <-> Unicode conversion.
573 memcpy(Console
->LineBuffer
, Buffer
, Console
->LineSize
* sizeof(WCHAR
));
574 if (Console
->LineSize
== Console
->LineMaxSize
)
576 Console
->LineComplete
= TRUE
;
577 Console
->LinePos
= 0;
581 /* If we don't have a complete line yet, process the pending input */
582 while ( !Console
->LineComplete
&&
583 !IsListEmpty(&InputBuffer
->InputEvents
) )
585 /* Remove input event from queue */
586 CurrentEntry
= RemoveHeadList(&InputBuffer
->InputEvents
);
587 if (IsListEmpty(&InputBuffer
->InputEvents
))
589 ResetEvent(InputBuffer
->ActiveEvent
);
591 Input
= CONTAINING_RECORD(CurrentEntry
, ConsoleInput
, ListEntry
);
593 /* Only pay attention to key down */
594 if (KEY_EVENT
== Input
->InputEvent
.EventType
595 && Input
->InputEvent
.Event
.KeyEvent
.bKeyDown
)
597 LineInputKeyDown(Console
, &Input
->InputEvent
.Event
.KeyEvent
);
598 ReadConsoleRequest
->ControlKeyState
= Input
->InputEvent
.Event
.KeyEvent
.dwControlKeyState
;
600 RtlFreeHeap(ConSrvHeap
, 0, Input
);
603 /* Check if we have a complete line to read from */
604 if (Console
->LineComplete
)
606 while ( ReadConsoleRequest
->NrCharactersRead
< nNumberOfCharsToRead
&&
607 Console
->LinePos
!= Console
->LineSize
)
609 WCHAR Char
= Console
->LineBuffer
[Console
->LinePos
++];
611 if (ReadConsoleRequest
->Unicode
)
613 UnicodeBuffer
[ReadConsoleRequest
->NrCharactersRead
] = Char
;
617 ConsoleInputUnicodeCharToAnsiChar(Console
,
618 &Buffer
[ReadConsoleRequest
->NrCharactersRead
],
622 ReadConsoleRequest
->NrCharactersRead
++;
625 if (Console
->LinePos
== Console
->LineSize
)
627 /* Entire line has been read */
628 RtlFreeHeap(ConSrvHeap
, 0, Console
->LineBuffer
);
629 Console
->LineBuffer
= NULL
;
632 WaitForMoreToRead
= FALSE
;
637 /* Character input */
638 while ( ReadConsoleRequest
->NrCharactersRead
< nNumberOfCharsToRead
&&
639 !IsListEmpty(&InputBuffer
->InputEvents
) )
641 /* Remove input event from queue */
642 CurrentEntry
= RemoveHeadList(&InputBuffer
->InputEvents
);
643 if (IsListEmpty(&InputBuffer
->InputEvents
))
645 ResetEvent(InputBuffer
->ActiveEvent
);
647 Input
= CONTAINING_RECORD(CurrentEntry
, ConsoleInput
, ListEntry
);
649 /* Only pay attention to valid ascii chars, on key down */
650 if (KEY_EVENT
== Input
->InputEvent
.EventType
651 && Input
->InputEvent
.Event
.KeyEvent
.bKeyDown
652 && Input
->InputEvent
.Event
.KeyEvent
.uChar
.UnicodeChar
!= L
'\0')
654 WCHAR Char
= Input
->InputEvent
.Event
.KeyEvent
.uChar
.UnicodeChar
;
656 if (ReadConsoleRequest
->Unicode
)
658 UnicodeBuffer
[ReadConsoleRequest
->NrCharactersRead
] = Char
;
662 ConsoleInputUnicodeCharToAnsiChar(Console
,
663 &Buffer
[ReadConsoleRequest
->NrCharactersRead
],
667 ReadConsoleRequest
->NrCharactersRead
++;
669 /* Did read something */
670 WaitForMoreToRead
= FALSE
;
672 RtlFreeHeap(ConSrvHeap
, 0, Input
);
676 /* We haven't completed a read, so start a wait */
677 if (WaitForMoreToRead
== TRUE
)
679 return WaitBeforeReading(InputInfo
,
684 else /* We read all what we wanted, we return success */
686 return STATUS_SUCCESS
;
691 /* PUBLIC APIS ****************************************************************/
693 CSR_API(SrvReadConsole
)
696 PCONSOLE_READCONSOLE ReadConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ReadConsoleRequest
;
697 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
698 PCONSOLE_IO_HANDLE HandleEntry
;
699 PCONSOLE_INPUT_BUFFER InputBuffer
;
700 GET_INPUT_INFO InputInfo
;
702 DPRINT("SrvReadConsole\n");
704 if (!CsrValidateMessageBuffer(ApiMessage
,
705 (PVOID
*)&ReadConsoleRequest
->Buffer
,
706 ReadConsoleRequest
->BufferSize
,
709 return STATUS_INVALID_PARAMETER
;
712 // if (Request->Data.ReadConsoleRequest.NrCharactersRead * sizeof(WCHAR) > nNumberOfCharsToRead * CharSize)
713 if (ReadConsoleRequest
->NrCharactersRead
> ReadConsoleRequest
->NrCharactersToRead
)
715 return STATUS_INVALID_PARAMETER
;
718 Status
= ConioGetInputBufferAndHandleEntry(ProcessData
, ReadConsoleRequest
->InputHandle
, &InputBuffer
, &HandleEntry
, GENERIC_READ
, TRUE
);
719 if (!NT_SUCCESS(Status
)) return Status
;
721 ReadConsoleRequest
->NrCharactersRead
= 0;
723 InputInfo
.CallingThread
= CsrGetClientThread();
724 InputInfo
.HandleEntry
= HandleEntry
;
725 InputInfo
.InputBuffer
= InputBuffer
;
727 Status
= ReadChars(&InputInfo
,
731 ConioReleaseInputBuffer(InputBuffer
, TRUE
);
733 if (Status
== STATUS_PENDING
)
734 *ReplyCode
= CsrReplyPending
;
739 CSR_API(SrvGetConsoleInput
)
742 PCONSOLE_GETINPUT GetInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetInputRequest
;
743 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
744 PCONSOLE_IO_HANDLE HandleEntry
;
745 PCONSOLE_INPUT_BUFFER InputBuffer
;
746 GET_INPUT_INFO InputInfo
;
748 DPRINT("SrvGetConsoleInput\n");
750 if (!CsrValidateMessageBuffer(ApiMessage
,
751 (PVOID
*)&GetInputRequest
->InputRecord
,
752 GetInputRequest
->Length
,
753 sizeof(INPUT_RECORD
)))
755 return STATUS_INVALID_PARAMETER
;
758 GetInputRequest
->InputsRead
= 0;
760 Status
= ConioGetInputBufferAndHandleEntry(ProcessData
, GetInputRequest
->InputHandle
, &InputBuffer
, &HandleEntry
, GENERIC_READ
, TRUE
);
761 if(!NT_SUCCESS(Status
)) return Status
;
763 InputInfo
.CallingThread
= CsrGetClientThread();
764 InputInfo
.HandleEntry
= HandleEntry
;
765 InputInfo
.InputBuffer
= InputBuffer
;
767 Status
= ReadInputBuffer(&InputInfo
,
768 GetInputRequest
->bRead
,
772 ConioReleaseInputBuffer(InputBuffer
, TRUE
);
774 if (Status
== STATUS_PENDING
)
775 *ReplyCode
= CsrReplyPending
;
780 CSR_API(SrvWriteConsoleInput
)
783 PCONSOLE_WRITEINPUT WriteInputRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.WriteInputRequest
;
784 PINPUT_RECORD InputRecord
;
785 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
786 PCONSOLE_INPUT_BUFFER InputBuffer
;
791 DPRINT("SrvWriteConsoleInput\n");
793 if (!CsrValidateMessageBuffer(ApiMessage
,
794 (PVOID
*)&WriteInputRequest
->InputRecord
,
795 WriteInputRequest
->Length
,
796 sizeof(INPUT_RECORD
)))
798 return STATUS_INVALID_PARAMETER
;
801 Status
= ConioGetInputBuffer(ProcessData
, WriteInputRequest
->InputHandle
, &InputBuffer
, GENERIC_WRITE
, TRUE
);
802 if (!NT_SUCCESS(Status
)) return Status
;
804 Console
= InputBuffer
->Header
.Console
;
805 InputRecord
= WriteInputRequest
->InputRecord
;
806 Length
= WriteInputRequest
->Length
;
808 for (i
= 0; i
< Length
&& NT_SUCCESS(Status
); i
++)
810 if (!WriteInputRequest
->Unicode
&&
811 InputRecord
->EventType
== KEY_EVENT
)
813 CHAR AsciiChar
= InputRecord
->Event
.KeyEvent
.uChar
.AsciiChar
;
814 ConsoleInputAnsiCharToUnicodeChar(Console
,
815 &InputRecord
->Event
.KeyEvent
.uChar
.UnicodeChar
,
819 Status
= ConioProcessChar(Console
, InputRecord
++);
822 ConioReleaseInputBuffer(InputBuffer
, TRUE
);
824 WriteInputRequest
->Length
= i
;
829 CSR_API(SrvFlushConsoleInputBuffer
)
832 PCONSOLE_FLUSHINPUTBUFFER FlushInputBufferRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.FlushInputBufferRequest
;
833 PLIST_ENTRY CurrentEntry
;
834 PCONSOLE_INPUT_BUFFER InputBuffer
;
837 DPRINT("SrvFlushConsoleInputBuffer\n");
839 Status
= ConioGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
840 FlushInputBufferRequest
->InputHandle
,
844 if(!NT_SUCCESS(Status
)) return Status
;
846 /* Discard all entries in the input event queue */
847 while (!IsListEmpty(&InputBuffer
->InputEvents
))
849 CurrentEntry
= RemoveHeadList(&InputBuffer
->InputEvents
);
850 Input
= CONTAINING_RECORD(CurrentEntry
, ConsoleInput
, ListEntry
);
851 /* Destroy the event */
852 RtlFreeHeap(ConSrvHeap
, 0, Input
);
854 ResetEvent(InputBuffer
->ActiveEvent
);
856 ConioReleaseInputBuffer(InputBuffer
, TRUE
);
858 return STATUS_SUCCESS
;
861 CSR_API(SrvGetConsoleNumberOfInputEvents
)
864 PCONSOLE_GETNUMINPUTEVENTS GetNumInputEventsRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetNumInputEventsRequest
;
865 PCONSOLE_INPUT_BUFFER InputBuffer
;
866 PLIST_ENTRY CurrentInput
;
869 DPRINT("SrvGetConsoleNumberOfInputEvents\n");
871 Status
= ConioGetInputBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), GetNumInputEventsRequest
->InputHandle
, &InputBuffer
, GENERIC_READ
, TRUE
);
872 if (!NT_SUCCESS(Status
)) return Status
;
874 CurrentInput
= InputBuffer
->InputEvents
.Flink
;
877 /* If there are any events ... */
878 while (CurrentInput
!= &InputBuffer
->InputEvents
)
880 CurrentInput
= CurrentInput
->Flink
;
884 ConioReleaseInputBuffer(InputBuffer
, TRUE
);
886 GetNumInputEventsRequest
->NumInputEvents
= NumEvents
;
888 return STATUS_SUCCESS
;