Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenlineinput.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS CSRSS 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: subsystems/win32/csrss/win32csr/lineinput.c 00005 * PURPOSE: Console line input functions 00006 * PROGRAMMERS: Jeffrey Morlan 00007 */ 00008 00009 /* INCLUDES ******************************************************************/ 00010 00011 #define NDEBUG 00012 #include "w32csr.h" 00013 #include <debug.h> 00014 00015 typedef struct tagHISTORY_BUFFER 00016 { 00017 LIST_ENTRY ListEntry; 00018 WORD Position; 00019 WORD MaxEntries; 00020 WORD NumEntries; 00021 PUNICODE_STRING Entries; 00022 UNICODE_STRING ExeName; 00023 } HISTORY_BUFFER, *PHISTORY_BUFFER; 00024 00025 /* FUNCTIONS *****************************************************************/ 00026 00027 static PHISTORY_BUFFER 00028 HistoryCurrentBuffer(PCSRSS_CONSOLE Console) 00029 { 00030 /* TODO: use actual EXE name sent from process that called ReadConsole */ 00031 UNICODE_STRING ExeName = { 14, 14, L"cmd.exe" }; 00032 PLIST_ENTRY Entry = Console->HistoryBuffers.Flink; 00033 PHISTORY_BUFFER Hist; 00034 00035 for (; Entry != &Console->HistoryBuffers; Entry = Entry->Flink) 00036 { 00037 Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry); 00038 if (RtlEqualUnicodeString(&ExeName, &Hist->ExeName, FALSE)) 00039 return Hist; 00040 } 00041 00042 /* Couldn't find the buffer, create a new one */ 00043 Hist = HeapAlloc(Win32CsrApiHeap, 0, sizeof(HISTORY_BUFFER) + ExeName.Length); 00044 if (!Hist) 00045 return NULL; 00046 Hist->MaxEntries = Console->HistoryBufferSize; 00047 Hist->NumEntries = 0; 00048 Hist->Entries = HeapAlloc(Win32CsrApiHeap, 0, Hist->MaxEntries * sizeof(UNICODE_STRING)); 00049 if (!Hist->Entries) 00050 { 00051 HeapFree(Win32CsrApiHeap, 0, Hist); 00052 return NULL; 00053 } 00054 Hist->ExeName.Length = Hist->ExeName.MaximumLength = ExeName.Length; 00055 Hist->ExeName.Buffer = (PWCHAR)(Hist + 1); 00056 memcpy(Hist->ExeName.Buffer, ExeName.Buffer, ExeName.Length); 00057 InsertHeadList(&Console->HistoryBuffers, &Hist->ListEntry); 00058 return Hist; 00059 } 00060 00061 static VOID 00062 HistoryAddEntry(PCSRSS_CONSOLE Console) 00063 { 00064 UNICODE_STRING NewEntry; 00065 PHISTORY_BUFFER Hist; 00066 INT i; 00067 00068 NewEntry.Length = NewEntry.MaximumLength = Console->LineSize * sizeof(WCHAR); 00069 NewEntry.Buffer = Console->LineBuffer; 00070 00071 if (!(Hist = HistoryCurrentBuffer(Console))) 00072 return; 00073 00074 /* Don't add blank or duplicate entries */ 00075 if (NewEntry.Length == 0 || Hist->MaxEntries == 0 || 00076 (Hist->NumEntries > 0 && 00077 RtlEqualUnicodeString(&Hist->Entries[Hist->NumEntries - 1], &NewEntry, FALSE))) 00078 { 00079 return; 00080 } 00081 00082 if (Console->HistoryNoDup) 00083 { 00084 /* Check if this line has been entered before */ 00085 for (i = Hist->NumEntries - 1; i >= 0; i--) 00086 { 00087 if (RtlEqualUnicodeString(&Hist->Entries[i], &NewEntry, FALSE)) 00088 { 00089 /* Just rotate the list to bring this entry to the end */ 00090 NewEntry = Hist->Entries[i]; 00091 memmove(&Hist->Entries[i], &Hist->Entries[i + 1], 00092 (Hist->NumEntries - (i + 1)) * sizeof(UNICODE_STRING)); 00093 Hist->Entries[Hist->NumEntries - 1] = NewEntry; 00094 Hist->Position = Hist->NumEntries - 1; 00095 return; 00096 } 00097 } 00098 } 00099 00100 if (Hist->NumEntries == Hist->MaxEntries) 00101 { 00102 /* List is full, remove oldest entry */ 00103 RtlFreeUnicodeString(&Hist->Entries[0]); 00104 memmove(&Hist->Entries[0], &Hist->Entries[1], 00105 --Hist->NumEntries * sizeof(UNICODE_STRING)); 00106 } 00107 00108 if (NT_SUCCESS(RtlDuplicateUnicodeString(0, &NewEntry, &Hist->Entries[Hist->NumEntries]))) 00109 Hist->NumEntries++; 00110 Hist->Position = Hist->NumEntries - 1; 00111 } 00112 00113 static VOID 00114 HistoryGetCurrentEntry(PCSRSS_CONSOLE Console, PUNICODE_STRING Entry) 00115 { 00116 PHISTORY_BUFFER Hist; 00117 if (!(Hist = HistoryCurrentBuffer(Console)) || Hist->NumEntries == 0) 00118 Entry->Length = 0; 00119 else 00120 *Entry = Hist->Entries[Hist->Position]; 00121 } 00122 00123 static PHISTORY_BUFFER 00124 HistoryFindBuffer(PCSRSS_CONSOLE Console, PUNICODE_STRING ExeName) 00125 { 00126 PLIST_ENTRY Entry = Console->HistoryBuffers.Flink; 00127 while (Entry != &Console->HistoryBuffers) 00128 { 00129 /* For the history APIs, the caller is allowed to give only part of the name */ 00130 PHISTORY_BUFFER Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry); 00131 if (RtlPrefixUnicodeString(ExeName, &Hist->ExeName, TRUE)) 00132 return Hist; 00133 Entry = Entry->Flink; 00134 } 00135 return NULL; 00136 } 00137 00138 VOID FASTCALL 00139 HistoryDeleteBuffer(PHISTORY_BUFFER Hist) 00140 { 00141 if (!Hist) 00142 return; 00143 while (Hist->NumEntries != 0) 00144 RtlFreeUnicodeString(&Hist->Entries[--Hist->NumEntries]); 00145 HeapFree(Win32CsrApiHeap, 0, Hist->Entries); 00146 RemoveEntryList(&Hist->ListEntry); 00147 HeapFree(Win32CsrApiHeap, 0, Hist); 00148 } 00149 00150 CSR_API(CsrGetCommandHistoryLength) 00151 { 00152 PCSRSS_CONSOLE Console; 00153 NTSTATUS Status; 00154 PHISTORY_BUFFER Hist; 00155 ULONG Length = 0; 00156 INT i; 00157 00158 if (!Win32CsrValidateBuffer(ProcessData, 00159 Request->Data.GetCommandHistoryLength.ExeName.Buffer, 00160 Request->Data.GetCommandHistoryLength.ExeName.Length, 1)) 00161 { 00162 return STATUS_ACCESS_VIOLATION; 00163 } 00164 00165 Status = ConioConsoleFromProcessData(ProcessData, &Console); 00166 if (NT_SUCCESS(Status)) 00167 { 00168 Hist = HistoryFindBuffer(Console, &Request->Data.GetCommandHistory.ExeName); 00169 if (Hist) 00170 { 00171 for (i = 0; i < Hist->NumEntries; i++) 00172 Length += Hist->Entries[i].Length + sizeof(WCHAR); 00173 } 00174 Request->Data.GetCommandHistoryLength.Length = Length; 00175 ConioUnlockConsole(Console); 00176 } 00177 return Status; 00178 } 00179 00180 CSR_API(CsrGetCommandHistory) 00181 { 00182 PCSRSS_CONSOLE Console; 00183 NTSTATUS Status; 00184 PHISTORY_BUFFER Hist; 00185 PBYTE Buffer = (PBYTE)Request->Data.GetCommandHistory.History; 00186 ULONG BufferSize = Request->Data.GetCommandHistory.Length; 00187 INT i; 00188 00189 if (!Win32CsrValidateBuffer(ProcessData, Buffer, BufferSize, 1) || 00190 !Win32CsrValidateBuffer(ProcessData, 00191 Request->Data.GetCommandHistory.ExeName.Buffer, 00192 Request->Data.GetCommandHistory.ExeName.Length, 1)) 00193 { 00194 return STATUS_ACCESS_VIOLATION; 00195 } 00196 00197 Status = ConioConsoleFromProcessData(ProcessData, &Console); 00198 if (NT_SUCCESS(Status)) 00199 { 00200 Hist = HistoryFindBuffer(Console, &Request->Data.GetCommandHistory.ExeName); 00201 if (Hist) 00202 { 00203 for (i = 0; i < Hist->NumEntries; i++) 00204 { 00205 if (BufferSize < (Hist->Entries[i].Length + sizeof(WCHAR))) 00206 { 00207 Status = STATUS_BUFFER_OVERFLOW; 00208 break; 00209 } 00210 memcpy(Buffer, Hist->Entries[i].Buffer, Hist->Entries[i].Length); 00211 Buffer += Hist->Entries[i].Length; 00212 *(PWCHAR)Buffer = L'\0'; 00213 Buffer += sizeof(WCHAR); 00214 } 00215 } 00216 Request->Data.GetCommandHistory.Length = Buffer - (PBYTE)Request->Data.GetCommandHistory.History; 00217 ConioUnlockConsole(Console); 00218 } 00219 return Status; 00220 } 00221 00222 CSR_API(CsrExpungeCommandHistory) 00223 { 00224 PCSRSS_CONSOLE Console; 00225 PHISTORY_BUFFER Hist; 00226 NTSTATUS Status; 00227 00228 if (!Win32CsrValidateBuffer(ProcessData, 00229 Request->Data.ExpungeCommandHistory.ExeName.Buffer, 00230 Request->Data.ExpungeCommandHistory.ExeName.Length, 1)) 00231 { 00232 return STATUS_ACCESS_VIOLATION; 00233 } 00234 00235 Status = ConioConsoleFromProcessData(ProcessData, &Console); 00236 if (NT_SUCCESS(Status)) 00237 { 00238 Hist = HistoryFindBuffer(Console, &Request->Data.ExpungeCommandHistory.ExeName); 00239 HistoryDeleteBuffer(Hist); 00240 ConioUnlockConsole(Console); 00241 } 00242 return Status; 00243 } 00244 00245 CSR_API(CsrSetHistoryNumberCommands) 00246 { 00247 PCSRSS_CONSOLE Console; 00248 PHISTORY_BUFFER Hist; 00249 NTSTATUS Status; 00250 WORD MaxEntries = Request->Data.SetHistoryNumberCommands.NumCommands; 00251 PUNICODE_STRING OldEntryList, NewEntryList; 00252 00253 if (!Win32CsrValidateBuffer(ProcessData, 00254 Request->Data.SetHistoryNumberCommands.ExeName.Buffer, 00255 Request->Data.SetHistoryNumberCommands.ExeName.Length, 1)) 00256 { 00257 return STATUS_ACCESS_VIOLATION; 00258 } 00259 00260 Status = ConioConsoleFromProcessData(ProcessData, &Console); 00261 if (NT_SUCCESS(Status)) 00262 { 00263 Hist = HistoryFindBuffer(Console, &Request->Data.SetHistoryNumberCommands.ExeName); 00264 if (Hist) 00265 { 00266 OldEntryList = Hist->Entries; 00267 NewEntryList = HeapAlloc(Win32CsrApiHeap, 0, 00268 MaxEntries * sizeof(UNICODE_STRING)); 00269 if (!NewEntryList) 00270 { 00271 Status = STATUS_NO_MEMORY; 00272 } 00273 else 00274 { 00275 /* If necessary, shrink by removing oldest entries */ 00276 for (; Hist->NumEntries > MaxEntries; Hist->NumEntries--) 00277 { 00278 RtlFreeUnicodeString(Hist->Entries++); 00279 Hist->Position += (Hist->Position == 0); 00280 } 00281 00282 Hist->MaxEntries = MaxEntries; 00283 Hist->Entries = memcpy(NewEntryList, Hist->Entries, 00284 Hist->NumEntries * sizeof(UNICODE_STRING)); 00285 HeapFree(Win32CsrApiHeap, 0, OldEntryList); 00286 } 00287 } 00288 ConioUnlockConsole(Console); 00289 } 00290 return Status; 00291 } 00292 00293 CSR_API(CsrGetHistoryInfo) 00294 { 00295 PCSRSS_CONSOLE Console; 00296 NTSTATUS Status = ConioConsoleFromProcessData(ProcessData, &Console); 00297 if (NT_SUCCESS(Status)) 00298 { 00299 Request->Data.SetHistoryInfo.HistoryBufferSize = Console->HistoryBufferSize; 00300 Request->Data.SetHistoryInfo.NumberOfHistoryBuffers = Console->NumberOfHistoryBuffers; 00301 Request->Data.SetHistoryInfo.dwFlags = Console->HistoryNoDup; 00302 ConioUnlockConsole(Console); 00303 } 00304 return Status; 00305 } 00306 00307 CSR_API(CsrSetHistoryInfo) 00308 { 00309 PCSRSS_CONSOLE Console; 00310 NTSTATUS Status = ConioConsoleFromProcessData(ProcessData, &Console); 00311 if (NT_SUCCESS(Status)) 00312 { 00313 Console->HistoryBufferSize = (WORD)Request->Data.SetHistoryInfo.HistoryBufferSize; 00314 Console->NumberOfHistoryBuffers = (WORD)Request->Data.SetHistoryInfo.NumberOfHistoryBuffers; 00315 Console->HistoryNoDup = Request->Data.SetHistoryInfo.dwFlags & HISTORY_NO_DUP_FLAG; 00316 ConioUnlockConsole(Console); 00317 } 00318 return Status; 00319 } 00320 00321 static VOID 00322 LineInputSetPos(PCSRSS_CONSOLE Console, UINT Pos) 00323 { 00324 if (Pos != Console->LinePos && Console->Mode & ENABLE_ECHO_INPUT) 00325 { 00326 PCSRSS_SCREEN_BUFFER Buffer = Console->ActiveBuffer; 00327 UINT OldCursorX = Buffer->CurrentX; 00328 UINT OldCursorY = Buffer->CurrentY; 00329 INT XY = OldCursorY * Buffer->MaxX + OldCursorX; 00330 00331 XY += (Pos - Console->LinePos); 00332 if (XY < 0) 00333 XY = 0; 00334 else if (XY >= Buffer->MaxY * Buffer->MaxX) 00335 XY = Buffer->MaxY * Buffer->MaxX - 1; 00336 00337 Buffer->CurrentX = XY % Buffer->MaxX; 00338 Buffer->CurrentY = XY / Buffer->MaxX; 00339 ConioSetScreenInfo(Console, Buffer, OldCursorX, OldCursorY); 00340 } 00341 00342 Console->LinePos = Pos; 00343 } 00344 00345 static VOID 00346 LineInputEdit(PCSRSS_CONSOLE Console, UINT NumToDelete, UINT NumToInsert, WCHAR *Insertion) 00347 { 00348 UINT Pos = Console->LinePos; 00349 UINT NewSize = Console->LineSize - NumToDelete + NumToInsert; 00350 INT i; 00351 00352 /* Make sure there's always enough room for ending \r\n */ 00353 if (NewSize + 2 > Console->LineMaxSize) 00354 return; 00355 00356 memmove(&Console->LineBuffer[Pos + NumToInsert], 00357 &Console->LineBuffer[Pos + NumToDelete], 00358 (Console->LineSize - (Pos + NumToDelete)) * sizeof(WCHAR)); 00359 memcpy(&Console->LineBuffer[Pos], Insertion, NumToInsert * sizeof(WCHAR)); 00360 00361 if (Console->Mode & ENABLE_ECHO_INPUT) 00362 { 00363 for (i = Pos; i < NewSize; i++) 00364 { 00365 CHAR AsciiChar; 00366 WideCharToMultiByte(Console->OutputCodePage, 0, 00367 &Console->LineBuffer[i], 1, 00368 &AsciiChar, 1, NULL, NULL); 00369 ConioWriteConsole(Console, Console->ActiveBuffer, &AsciiChar, 1, TRUE); 00370 } 00371 for (; i < Console->LineSize; i++) 00372 { 00373 ConioWriteConsole(Console, Console->ActiveBuffer, " ", 1, TRUE); 00374 } 00375 Console->LinePos = i; 00376 } 00377 00378 Console->LineSize = NewSize; 00379 LineInputSetPos(Console, Pos + NumToInsert); 00380 } 00381 00382 static VOID 00383 LineInputRecallHistory(PCSRSS_CONSOLE Console, INT Offset) 00384 { 00385 PHISTORY_BUFFER Hist; 00386 00387 if (!(Hist = HistoryCurrentBuffer(Console)) || Hist->NumEntries == 0) 00388 return; 00389 00390 Offset += Hist->Position; 00391 Offset = max(Offset, 0); 00392 Offset = min(Offset, Hist->NumEntries - 1); 00393 Hist->Position = Offset; 00394 00395 LineInputSetPos(Console, 0); 00396 LineInputEdit(Console, Console->LineSize, 00397 Hist->Entries[Offset].Length / sizeof(WCHAR), 00398 Hist->Entries[Offset].Buffer); 00399 } 00400 00401 VOID FASTCALL 00402 LineInputKeyDown(PCSRSS_CONSOLE Console, KEY_EVENT_RECORD *KeyEvent) 00403 { 00404 UINT Pos = Console->LinePos; 00405 PHISTORY_BUFFER Hist; 00406 UNICODE_STRING Entry; 00407 INT HistPos; 00408 00409 switch (KeyEvent->wVirtualKeyCode) 00410 { 00411 case VK_ESCAPE: 00412 /* Clear entire line */ 00413 LineInputSetPos(Console, 0); 00414 LineInputEdit(Console, Console->LineSize, 0, NULL); 00415 return; 00416 case VK_HOME: 00417 /* Move to start of line. With ctrl, erase everything left of cursor */ 00418 LineInputSetPos(Console, 0); 00419 if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) 00420 LineInputEdit(Console, Pos, 0, NULL); 00421 return; 00422 case VK_END: 00423 /* Move to end of line. With ctrl, erase everything right of cursor */ 00424 if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) 00425 LineInputEdit(Console, Console->LineSize - Pos, 0, NULL); 00426 else 00427 LineInputSetPos(Console, Console->LineSize); 00428 return; 00429 case VK_LEFT: 00430 /* Move left. With ctrl, move to beginning of previous word */ 00431 if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) 00432 { 00433 while (Pos > 0 && Console->LineBuffer[Pos - 1] == L' ') Pos--; 00434 while (Pos > 0 && Console->LineBuffer[Pos - 1] != L' ') Pos--; 00435 } 00436 else 00437 { 00438 Pos -= (Pos > 0); 00439 } 00440 LineInputSetPos(Console, Pos); 00441 return; 00442 case VK_RIGHT: 00443 case VK_F1: 00444 /* Move right. With ctrl, move to beginning of next word */ 00445 if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) 00446 { 00447 while (Pos < Console->LineSize && Console->LineBuffer[Pos] != L' ') Pos++; 00448 while (Pos < Console->LineSize && Console->LineBuffer[Pos] == L' ') Pos++; 00449 LineInputSetPos(Console, Pos); 00450 return; 00451 } 00452 else 00453 { 00454 /* Recall one character (but don't overwrite current line) */ 00455 HistoryGetCurrentEntry(Console, &Entry); 00456 if (Pos < Console->LineSize) 00457 LineInputSetPos(Console, Pos + 1); 00458 else if (Pos * sizeof(WCHAR) < Entry.Length) 00459 LineInputEdit(Console, 0, 1, &Entry.Buffer[Pos]); 00460 } 00461 return; 00462 case VK_INSERT: 00463 /* Toggle between insert and overstrike */ 00464 Console->LineInsertToggle = !Console->LineInsertToggle; 00465 ConioSetCursorInfo(Console, Console->ActiveBuffer); 00466 return; 00467 case VK_DELETE: 00468 /* Remove character to right of cursor */ 00469 if (Pos != Console->LineSize) 00470 LineInputEdit(Console, 1, 0, NULL); 00471 return; 00472 case VK_PRIOR: 00473 /* Recall first history entry */ 00474 LineInputRecallHistory(Console, -((WORD)-1)); 00475 return; 00476 case VK_NEXT: 00477 /* Recall last history entry */ 00478 LineInputRecallHistory(Console, +((WORD)-1)); 00479 return; 00480 case VK_UP: 00481 case VK_F5: 00482 /* Recall previous history entry. On first time, actually recall the 00483 * current (usually last) entry; on subsequent times go back. */ 00484 LineInputRecallHistory(Console, Console->LineUpPressed ? -1 : 0); 00485 Console->LineUpPressed = TRUE; 00486 return; 00487 case VK_DOWN: 00488 /* Recall next history entry */ 00489 LineInputRecallHistory(Console, +1); 00490 return; 00491 case VK_F3: 00492 /* Recall remainder of current history entry */ 00493 HistoryGetCurrentEntry(Console, &Entry); 00494 if (Pos * sizeof(WCHAR) < Entry.Length) 00495 { 00496 UINT InsertSize = (Entry.Length / sizeof(WCHAR) - Pos); 00497 UINT DeleteSize = min(Console->LineSize - Pos, InsertSize); 00498 LineInputEdit(Console, DeleteSize, InsertSize, &Entry.Buffer[Pos]); 00499 } 00500 return; 00501 case VK_F6: 00502 /* Insert a ^Z character */ 00503 KeyEvent->uChar.UnicodeChar = 26; 00504 break; 00505 case VK_F7: 00506 if (KeyEvent->dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) 00507 HistoryDeleteBuffer(HistoryCurrentBuffer(Console)); 00508 return; 00509 case VK_F8: 00510 /* Search for history entries starting with input. */ 00511 if (!(Hist = HistoryCurrentBuffer(Console)) || Hist->NumEntries == 0) 00512 return; 00513 00514 /* Like Up/F5, on first time start from current (usually last) entry, 00515 * but on subsequent times start at previous entry. */ 00516 if (Console->LineUpPressed) 00517 Hist->Position = (Hist->Position ? Hist->Position : Hist->NumEntries) - 1; 00518 Console->LineUpPressed = TRUE; 00519 00520 Entry.Length = Console->LinePos * sizeof(WCHAR); 00521 Entry.Buffer = Console->LineBuffer; 00522 00523 /* Keep going backwards, even wrapping around to the end, 00524 * until we get back to starting point */ 00525 HistPos = Hist->Position; 00526 do 00527 { 00528 if (RtlPrefixUnicodeString(&Entry, &Hist->Entries[HistPos], FALSE)) 00529 { 00530 Hist->Position = HistPos; 00531 LineInputEdit(Console, Console->LineSize - Pos, 00532 Hist->Entries[HistPos].Length / sizeof(WCHAR) - Pos, 00533 &Hist->Entries[HistPos].Buffer[Pos]); 00534 /* Cursor stays where it was */ 00535 LineInputSetPos(Console, Pos); 00536 return; 00537 } 00538 if (--HistPos < 0) HistPos += Hist->NumEntries; 00539 } while (HistPos != Hist->Position); 00540 return; 00541 } 00542 00543 if (KeyEvent->uChar.UnicodeChar == L'\b' && Console->Mode & ENABLE_PROCESSED_INPUT) 00544 { 00545 /* backspace handling - if processed input enabled then we handle it here 00546 * otherwise we treat it like a normal char. */ 00547 if (Pos > 0) 00548 { 00549 LineInputSetPos(Console, Pos - 1); 00550 LineInputEdit(Console, 1, 0, NULL); 00551 } 00552 } 00553 else if (KeyEvent->uChar.UnicodeChar == L'\r') 00554 { 00555 HistoryAddEntry(Console); 00556 00557 /* TODO: Expand aliases */ 00558 00559 LineInputSetPos(Console, Console->LineSize); 00560 Console->LineBuffer[Console->LineSize++] = L'\r'; 00561 if (Console->Mode & ENABLE_ECHO_INPUT) 00562 ConioWriteConsole(Console, Console->ActiveBuffer, "\r", 1, TRUE); 00563 00564 /* Add \n if processed input. There should usually be room for it, 00565 * but an exception to the rule exists: the buffer could have been 00566 * pre-filled with LineMaxSize - 1 characters. */ 00567 if (Console->Mode & ENABLE_PROCESSED_INPUT && 00568 Console->LineSize < Console->LineMaxSize) 00569 { 00570 Console->LineBuffer[Console->LineSize++] = L'\n'; 00571 if (Console->Mode & ENABLE_ECHO_INPUT) 00572 ConioWriteConsole(Console, Console->ActiveBuffer, "\n", 1, TRUE); 00573 } 00574 Console->LineComplete = TRUE; 00575 Console->LinePos = 0; 00576 } 00577 else if (KeyEvent->uChar.UnicodeChar != L'\0') 00578 { 00579 if (KeyEvent->uChar.UnicodeChar < 0x20 && 00580 Console->LineWakeupMask & (1 << KeyEvent->uChar.UnicodeChar)) 00581 { 00582 /* Control key client wants to handle itself (e.g. for tab completion) */ 00583 Console->LineBuffer[Console->LineSize++] = L' '; 00584 Console->LineBuffer[Console->LinePos] = KeyEvent->uChar.UnicodeChar; 00585 Console->LineComplete = TRUE; 00586 Console->LinePos = 0; 00587 } 00588 else 00589 { 00590 /* Normal character */ 00591 BOOL Overstrike = Console->LineInsertToggle && Console->LinePos != Console->LineSize; 00592 LineInputEdit(Console, Overstrike, 1, &KeyEvent->uChar.UnicodeChar); 00593 } 00594 } 00595 } 00596 00597 /* EOF */ Generated on Sun May 27 2012 04:38:45 for ReactOS by
1.7.6.1
|