Author: jmorlan
Date: Sat Jun 5 20:17:42 2010
New Revision: 47597
URL:
http://svn.reactos.org/svn/reactos?rev=47597&view=rev
Log:
[WIN32CSR]
- Implement basic support for history in line editing
- Reorganize code to reflect that line input is more coupled to history than it is to
character input
Added:
trunk/reactos/subsystems/win32/csrss/win32csr/lineinput.c
- copied, changed from r47581,
trunk/reactos/subsystems/win32/csrss/win32csr/history.c
Removed:
trunk/reactos/subsystems/win32/csrss/win32csr/history.c
Modified:
trunk/reactos/subsystems/win32/csrss/win32csr/coninput.c
trunk/reactos/subsystems/win32/csrss/win32csr/conio.h
trunk/reactos/subsystems/win32/csrss/win32csr/win32csr.rbuild
Modified: trunk/reactos/subsystems/win32/csrss/win32csr/coninput.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/csrss/win…
==============================================================================
--- trunk/reactos/subsystems/win32/csrss/win32csr/coninput.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/win32/csrss/win32csr/coninput.c [iso-8859-1] Sat Jun 5
20:17:42 2010
@@ -21,162 +21,6 @@
MultiByteToWideChar((Console)->CodePage, 0, (sChar), 1, (dWChar), 1)
/* FUNCTIONS *****************************************************************/
-
-static VOID
-ConioLineInputSetPos(PCSRSS_CONSOLE Console, UINT Pos)
-{
- if (Pos != Console->LinePos && Console->Mode & ENABLE_ECHO_INPUT)
- {
- PCSRSS_SCREEN_BUFFER Buffer = Console->ActiveBuffer;
- UINT OldCursorX = Buffer->CurrentX;
- UINT OldCursorY = Buffer->CurrentY;
- INT XY = OldCursorY * Buffer->MaxX + OldCursorX;
-
- XY += (Pos - Console->LinePos);
- if (XY < 0)
- XY = 0;
- else if (XY >= Buffer->MaxY * Buffer->MaxX)
- XY = Buffer->MaxY * Buffer->MaxX - 1;
-
- Buffer->CurrentX = XY % Buffer->MaxX;
- Buffer->CurrentY = XY / Buffer->MaxX;
- ConioSetScreenInfo(Console, Buffer, OldCursorX, OldCursorY);
- }
-
- Console->LinePos = Pos;
-}
-
-static VOID
-ConioLineInputEdit(PCSRSS_CONSOLE Console, UINT NumToDelete, UINT NumToInsert, WCHAR
*Insertion)
-{
- UINT Pos = Console->LinePos;
- UINT NewSize = Console->LineSize - NumToDelete + NumToInsert;
- INT i;
-
- /* Make sure there's always enough room for ending \r\n */
- if (NewSize + 2 > Console->LineMaxSize)
- return;
-
- memmove(&Console->LineBuffer[Pos + NumToInsert],
- &Console->LineBuffer[Pos + NumToDelete],
- (Console->LineSize - (Pos + NumToDelete)) * sizeof(WCHAR));
- memcpy(&Console->LineBuffer[Pos], Insertion, NumToInsert * sizeof(WCHAR));
-
- if (Console->Mode & ENABLE_ECHO_INPUT)
- {
- for (i = Pos; i < NewSize; i++)
- {
- CHAR AsciiChar;
- WideCharToMultiByte(Console->OutputCodePage, 0,
- &Console->LineBuffer[i], 1,
- &AsciiChar, 1, NULL, NULL);
- ConioWriteConsole(Console, Console->ActiveBuffer, &AsciiChar, 1,
TRUE);
- }
- for (; i < Console->LineSize; i++)
- {
- ConioWriteConsole(Console, Console->ActiveBuffer, " ", 1,
TRUE);
- }
- Console->LinePos = i;
- }
-
- Console->LineSize = NewSize;
- ConioLineInputSetPos(Console, Pos + NumToInsert);
-}
-
-static VOID
-ConioLineInputKeyDown(PCSRSS_CONSOLE Console, KEY_EVENT_RECORD *KeyEvent)
-{
- UINT Pos = Console->LinePos;
- switch (KeyEvent->wVirtualKeyCode)
- {
- case VK_ESCAPE:
- /* Clear entire line */
- ConioLineInputSetPos(Console, 0);
- ConioLineInputEdit(Console, Console->LineSize, 0, NULL);
- return;
- case VK_HOME:
- /* Move to start of line. With ctrl, erase everything left of cursor */
- ConioLineInputSetPos(Console, 0);
- if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED |
RIGHT_CTRL_PRESSED))
- ConioLineInputEdit(Console, Pos, 0, NULL);
- return;
- case VK_END:
- /* Move to end of line. With ctrl, erase everything right of cursor */
- if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED |
RIGHT_CTRL_PRESSED))
- ConioLineInputEdit(Console, Console->LineSize - Pos, 0, NULL);
- else
- ConioLineInputSetPos(Console, Console->LineSize);
- return;
- case VK_LEFT:
- /* Move left. With ctrl, move to beginning of previous word */
- if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED |
RIGHT_CTRL_PRESSED))
- {
- while (Pos > 0 && Console->LineBuffer[Pos - 1] == L' ')
Pos--;
- while (Pos > 0 && Console->LineBuffer[Pos - 1] != L' ')
Pos--;
- }
- else
- {
- Pos -= (Pos > 0);
- }
- ConioLineInputSetPos(Console, Pos);
- return;
- case VK_RIGHT:
- /* Move right. With ctrl, move to beginning of next word */
- if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED |
RIGHT_CTRL_PRESSED))
- {
- while (Pos < Console->LineSize && Console->LineBuffer[Pos]
!= L' ') Pos++;
- while (Pos < Console->LineSize && Console->LineBuffer[Pos]
== L' ') Pos++;
- }
- else
- {
- Pos += (Pos < Console->LineSize);
- }
- ConioLineInputSetPos(Console, Pos);
- return;
- case VK_DELETE:
- /* Remove character to right of cursor */
- if (Pos != Console->LineSize)
- ConioLineInputEdit(Console, 1, 0, NULL);
- return;
- case VK_F6:
- /* Insert a ^Z character */
- KeyEvent->uChar.UnicodeChar = 26;
- break;
- }
-
- if (KeyEvent->uChar.UnicodeChar == L'\b' && Console->Mode &
ENABLE_PROCESSED_INPUT)
- {
- /* backspace handling - if processed input enabled then we handle it here
- * otherwise we treat it like a normal char. */
- if (Pos > 0)
- {
- ConioLineInputSetPos(Console, Pos - 1);
- ConioLineInputEdit(Console, 1, 0, NULL);
- }
- }
- else if (KeyEvent->uChar.UnicodeChar == L'\r')
- {
- HistoryAddEntry(Console);
-
- ConioLineInputSetPos(Console, Console->LineSize);
- Console->LineBuffer[Console->LineSize++] = L'\r';
- if (Console->Mode & ENABLE_ECHO_INPUT)
- ConioWriteConsole(Console, Console->ActiveBuffer, "\r", 1,
TRUE);
- if (Console->Mode & ENABLE_PROCESSED_INPUT)
- {
- Console->LineBuffer[Console->LineSize++] = L'\n';
- if (Console->Mode & ENABLE_ECHO_INPUT)
- ConioWriteConsole(Console, Console->ActiveBuffer, "\n", 1,
TRUE);
- }
- Console->LineComplete = TRUE;
- Console->LinePos = 0;
- }
- else if (KeyEvent->uChar.UnicodeChar != L'\0')
- {
- /* Normal character */
- ConioLineInputEdit(Console, 0, 1, &KeyEvent->uChar.UnicodeChar);
- }
-}
CSR_API(CsrReadConsole)
{
@@ -224,6 +68,7 @@
Console->LineComplete = FALSE;
Console->LineSize = 0;
Console->LinePos = 0;
+ Console->LineUpPressed = FALSE;
}
/* If we don't have a complete line yet, process the pending input */
@@ -241,7 +86,7 @@
if (KEY_EVENT == Input->InputEvent.EventType
&& Input->InputEvent.Event.KeyEvent.bKeyDown)
{
- ConioLineInputKeyDown(Console,
&Input->InputEvent.Event.KeyEvent);
+ LineInputKeyDown(Console, &Input->InputEvent.Event.KeyEvent);
}
HeapFree(Win32CsrApiHeap, 0, Input);
}
Modified: trunk/reactos/subsystems/win32/csrss/win32csr/conio.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/csrss/win…
==============================================================================
--- trunk/reactos/subsystems/win32/csrss/win32csr/conio.h [iso-8859-1] (original)
+++ trunk/reactos/subsystems/win32/csrss/win32csr/conio.h [iso-8859-1] Sat Jun 5 20:17:42
2010
@@ -80,6 +80,7 @@
WORD LineSize; /* current size of line */
WORD LinePos; /* current position within line */
BOOLEAN LineComplete; /* user pressed enter, ready to send back to
client */
+ BOOLEAN LineUpPressed;
LIST_ENTRY HistoryBuffers;
WORD HistoryBufferSize; /* size for newly created history buffers */
WORD NumberOfHistoryBuffers; /* maximum number of history buffers allowed */
@@ -220,9 +221,8 @@
CSR_API(CsrGetConsoleAliasesExes);
CSR_API(CsrGetConsoleAliasesExesLength);
-/* history.c */
+/* lineinput.c */
struct tagHISTORY_BUFFER;
-VOID FASTCALL HistoryAddEntry(PCSRSS_CONSOLE Console);
VOID FASTCALL HistoryDeleteBuffer(struct tagHISTORY_BUFFER *Hist);
CSR_API(CsrGetCommandHistoryLength);
CSR_API(CsrGetCommandHistory);
@@ -230,5 +230,6 @@
CSR_API(CsrSetHistoryNumberCommands);
CSR_API(CsrGetHistoryInfo);
CSR_API(CsrSetHistoryInfo);
+VOID FASTCALL LineInputKeyDown(PCSRSS_CONSOLE Console, KEY_EVENT_RECORD *KeyEvent);
/* EOF */
Removed: trunk/reactos/subsystems/win32/csrss/win32csr/history.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/csrss/win…
==============================================================================
--- trunk/reactos/subsystems/win32/csrss/win32csr/history.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/win32/csrss/win32csr/history.c (removed)
@@ -1,304 +1,0 @@
-/*
- * PROJECT: ReactOS CSRSS
- * LICENSE: GPL - See COPYING in the top level directory
- * FILE: subsystems/win32/csrss/win32csr/history.c
- * PURPOSE: Console input history functions
- * PROGRAMMERS: Jeffrey Morlan
- */
-
-/* INCLUDES ******************************************************************/
-
-#define NDEBUG
-#include "w32csr.h"
-#include <debug.h>
-
-typedef struct tagHISTORY_BUFFER
-{
- LIST_ENTRY ListEntry;
- WORD MaxEntries;
- WORD NumEntries;
- PUNICODE_STRING Entries;
- UNICODE_STRING ExeName;
-} HISTORY_BUFFER, *PHISTORY_BUFFER;
-
-/* FUNCTIONS *****************************************************************/
-
-static PHISTORY_BUFFER
-HistoryGetBuffer(PCSRSS_CONSOLE Console)
-{
- /* TODO: use actual EXE name sent from process that called ReadConsole */
- UNICODE_STRING ExeName = { 14, 14, L"cmd.exe" };
- PLIST_ENTRY Entry = Console->HistoryBuffers.Flink;
- PHISTORY_BUFFER Hist;
-
- for (; Entry != &Console->HistoryBuffers; Entry = Entry->Flink)
- {
- Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry);
- if (RtlEqualUnicodeString(&ExeName, &Hist->ExeName, FALSE))
- return Hist;
- }
-
- /* Couldn't find the buffer, create a new one */
- Hist = HeapAlloc(Win32CsrApiHeap, 0, sizeof(HISTORY_BUFFER) + ExeName.Length);
- if (!Hist)
- return NULL;
- Hist->MaxEntries = Console->HistoryBufferSize;
- Hist->NumEntries = 0;
- Hist->Entries = HeapAlloc(Win32CsrApiHeap, 0, Hist->MaxEntries *
sizeof(UNICODE_STRING));
- if (!Hist->Entries)
- {
- HeapFree(Win32CsrApiHeap, 0, Hist);
- return NULL;
- }
- Hist->ExeName.Length = Hist->ExeName.MaximumLength = ExeName.Length;
- Hist->ExeName.Buffer = (PWCHAR)(Hist + 1);
- memcpy(Hist->ExeName.Buffer, ExeName.Buffer, ExeName.Length);
- InsertHeadList(&Console->HistoryBuffers, &Hist->ListEntry);
- return Hist;
-}
-
-VOID FASTCALL
-HistoryAddEntry(PCSRSS_CONSOLE Console)
-{
- UNICODE_STRING NewEntry;
- PHISTORY_BUFFER Hist;
- INT i;
-
- NewEntry.Length = NewEntry.MaximumLength = Console->LineSize * sizeof(WCHAR);
- NewEntry.Buffer = Console->LineBuffer;
-
- if (!(Hist = HistoryGetBuffer(Console)))
- return;
-
- /* Don't add blank or duplicate entries */
- if (NewEntry.Length == 0 || Hist->MaxEntries == 0 ||
- (Hist->NumEntries > 0 &&
- RtlEqualUnicodeString(&Hist->Entries[Hist->NumEntries - 1],
&NewEntry, FALSE)))
- {
- return;
- }
-
- if (Console->HistoryNoDup)
- {
- /* Check if this line has been entered before */
- for (i = Hist->NumEntries - 1; i >= 0; i--)
- {
- if (RtlEqualUnicodeString(&Hist->Entries[i], &NewEntry, FALSE))
- {
- /* Just rotate the list to bring this entry to the end */
- NewEntry = Hist->Entries[i];
- memmove(&Hist->Entries[i], &Hist->Entries[i + 1],
- (Hist->NumEntries - (i + 1)) * sizeof(UNICODE_STRING));
- Hist->Entries[Hist->NumEntries - 1] = NewEntry;
- return;
- }
- }
- }
-
- if (Hist->NumEntries == Hist->MaxEntries)
- {
- /* List is full, remove oldest entry */
- RtlFreeUnicodeString(&Hist->Entries[0]);
- memmove(&Hist->Entries[0], &Hist->Entries[1],
- --Hist->NumEntries * sizeof(UNICODE_STRING));
- }
-
- if (NT_SUCCESS(RtlDuplicateUnicodeString(0, &NewEntry,
&Hist->Entries[Hist->NumEntries])))
- Hist->NumEntries++;
-}
-
-static PHISTORY_BUFFER
-HistoryFindBuffer(PCSRSS_CONSOLE Console, PUNICODE_STRING ExeName)
-{
- PLIST_ENTRY Entry = Console->HistoryBuffers.Flink;
- while (Entry != &Console->HistoryBuffers)
- {
- /* For the history APIs, the caller is allowed to give only part of the name */
- PHISTORY_BUFFER Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry);
- if (RtlPrefixUnicodeString(ExeName, &Hist->ExeName, TRUE))
- return Hist;
- Entry = Entry->Flink;
- }
- return NULL;
-}
-
-VOID FASTCALL
-HistoryDeleteBuffer(PHISTORY_BUFFER Hist)
-{
- while (Hist->NumEntries != 0)
- RtlFreeUnicodeString(&Hist->Entries[--Hist->NumEntries]);
- HeapFree(Win32CsrApiHeap, 0, Hist->Entries);
- RemoveEntryList(&Hist->ListEntry);
- HeapFree(Win32CsrApiHeap, 0, Hist);
-}
-
-CSR_API(CsrGetCommandHistoryLength)
-{
- PCSRSS_CONSOLE Console;
- NTSTATUS Status;
- PHISTORY_BUFFER Hist;
- ULONG Length = 0;
- INT i;
-
- if (!Win32CsrValidateBuffer(ProcessData,
- Request->Data.GetCommandHistoryLength.ExeName.Buffer,
- Request->Data.GetCommandHistoryLength.ExeName.Length,
1))
- {
- return STATUS_ACCESS_VIOLATION;
- }
-
- Status = ConioConsoleFromProcessData(ProcessData, &Console);
- if (NT_SUCCESS(Status))
- {
- Hist = HistoryFindBuffer(Console,
&Request->Data.GetCommandHistory.ExeName);
- if (Hist)
- {
- for (i = 0; i < Hist->NumEntries; i++)
- Length += Hist->Entries[i].Length + sizeof(WCHAR);
- }
- Request->Data.GetCommandHistoryLength.Length = Length;
- ConioUnlockConsole(Console);
- }
- return Status;
-}
-
-CSR_API(CsrGetCommandHistory)
-{
- PCSRSS_CONSOLE Console;
- NTSTATUS Status;
- PHISTORY_BUFFER Hist;
- PBYTE Buffer = (PBYTE)Request->Data.GetCommandHistory.History;
- ULONG BufferSize = Request->Data.GetCommandHistory.Length;
- INT i;
-
- if (!Win32CsrValidateBuffer(ProcessData, Buffer, BufferSize, 1) ||
- !Win32CsrValidateBuffer(ProcessData,
- Request->Data.GetCommandHistory.ExeName.Buffer,
- Request->Data.GetCommandHistory.ExeName.Length, 1))
- {
- return STATUS_ACCESS_VIOLATION;
- }
-
- Status = ConioConsoleFromProcessData(ProcessData, &Console);
- if (NT_SUCCESS(Status))
- {
- Hist = HistoryFindBuffer(Console,
&Request->Data.GetCommandHistory.ExeName);
- if (Hist)
- {
- for (i = 0; i < Hist->NumEntries; i++)
- {
- if (BufferSize < (Hist->Entries[i].Length + sizeof(WCHAR)))
- {
- Status = STATUS_BUFFER_OVERFLOW;
- break;
- }
- memcpy(Buffer, Hist->Entries[i].Buffer, Hist->Entries[i].Length);
- Buffer += Hist->Entries[i].Length;
- *(PWCHAR)Buffer = L'\0';
- Buffer += sizeof(WCHAR);
- }
- }
- Request->Data.GetCommandHistory.Length = Buffer -
(PBYTE)Request->Data.GetCommandHistory.History;
- ConioUnlockConsole(Console);
- }
- return Status;
-}
-
-CSR_API(CsrExpungeCommandHistory)
-{
- PCSRSS_CONSOLE Console;
- PHISTORY_BUFFER Hist;
- NTSTATUS Status;
-
- if (!Win32CsrValidateBuffer(ProcessData,
- Request->Data.ExpungeCommandHistory.ExeName.Buffer,
- Request->Data.ExpungeCommandHistory.ExeName.Length,
1))
- {
- return STATUS_ACCESS_VIOLATION;
- }
-
- Status = ConioConsoleFromProcessData(ProcessData, &Console);
- if (NT_SUCCESS(Status))
- {
- Hist = HistoryFindBuffer(Console,
&Request->Data.ExpungeCommandHistory.ExeName);
- if (Hist)
- HistoryDeleteBuffer(Hist);
- ConioUnlockConsole(Console);
- }
- return Status;
-}
-
-CSR_API(CsrSetHistoryNumberCommands)
-{
- PCSRSS_CONSOLE Console;
- PHISTORY_BUFFER Hist;
- NTSTATUS Status;
- WORD MaxEntries = Request->Data.SetHistoryNumberCommands.NumCommands;
- PUNICODE_STRING OldEntryList, NewEntryList;
-
- if (!Win32CsrValidateBuffer(ProcessData,
-
Request->Data.SetHistoryNumberCommands.ExeName.Buffer,
- Request->Data.SetHistoryNumberCommands.ExeName.Length,
1))
- {
- return STATUS_ACCESS_VIOLATION;
- }
-
- Status = ConioConsoleFromProcessData(ProcessData, &Console);
- if (NT_SUCCESS(Status))
- {
- Hist = HistoryFindBuffer(Console,
&Request->Data.SetHistoryNumberCommands.ExeName);
- if (Hist)
- {
- OldEntryList = Hist->Entries;
- NewEntryList = HeapAlloc(Win32CsrApiHeap, 0,
- MaxEntries * sizeof(UNICODE_STRING));
- if (!NewEntryList)
- {
- Status = STATUS_NO_MEMORY;
- }
- else
- {
- /* If necessary, shrink by removing oldest entries */
- for (; Hist->NumEntries > MaxEntries; Hist->NumEntries--)
- RtlFreeUnicodeString(Hist->Entries++);
-
- Hist->MaxEntries = MaxEntries;
- Hist->Entries = memcpy(NewEntryList, Hist->Entries,
- Hist->NumEntries * sizeof(UNICODE_STRING));
- HeapFree(Win32CsrApiHeap, 0, OldEntryList);
- }
- }
- ConioUnlockConsole(Console);
- }
- return Status;
-}
-
-CSR_API(CsrGetHistoryInfo)
-{
- PCSRSS_CONSOLE Console;
- NTSTATUS Status = ConioConsoleFromProcessData(ProcessData, &Console);
- if (NT_SUCCESS(Status))
- {
- Request->Data.SetHistoryInfo.HistoryBufferSize =
Console->HistoryBufferSize;
- Request->Data.SetHistoryInfo.NumberOfHistoryBuffers =
Console->NumberOfHistoryBuffers;
- Request->Data.SetHistoryInfo.dwFlags =
Console->HistoryNoDup;
- ConioUnlockConsole(Console);
- }
- return Status;
-}
-
-CSR_API(CsrSetHistoryInfo)
-{
- PCSRSS_CONSOLE Console;
- NTSTATUS Status = ConioConsoleFromProcessData(ProcessData, &Console);
- if (NT_SUCCESS(Status))
- {
- Console->HistoryBufferSize =
(WORD)Request->Data.SetHistoryInfo.HistoryBufferSize;
- Console->NumberOfHistoryBuffers =
(WORD)Request->Data.SetHistoryInfo.NumberOfHistoryBuffers;
- Console->HistoryNoDup = Request->Data.SetHistoryInfo.dwFlags
& HISTORY_NO_DUP_FLAG;
- ConioUnlockConsole(Console);
- }
- return Status;
-}
-
-/* EOF */
Copied: trunk/reactos/subsystems/win32/csrss/win32csr/lineinput.c (from r47581,
trunk/reactos/subsystems/win32/csrss/win32csr/history.c)
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/csrss/win…
==============================================================================
--- trunk/reactos/subsystems/win32/csrss/win32csr/history.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/win32/csrss/win32csr/lineinput.c [iso-8859-1] Sat Jun 5
20:17:42 2010
@@ -1,8 +1,8 @@
/*
* PROJECT: ReactOS CSRSS
* LICENSE: GPL - See COPYING in the top level directory
- * FILE: subsystems/win32/csrss/win32csr/history.c
- * PURPOSE: Console input history functions
+ * FILE: subsystems/win32/csrss/win32csr/lineinput.c
+ * PURPOSE: Console line input functions
* PROGRAMMERS: Jeffrey Morlan
*/
@@ -15,6 +15,7 @@
typedef struct tagHISTORY_BUFFER
{
LIST_ENTRY ListEntry;
+ WORD Position;
WORD MaxEntries;
WORD NumEntries;
PUNICODE_STRING Entries;
@@ -24,7 +25,7 @@
/* FUNCTIONS *****************************************************************/
static PHISTORY_BUFFER
-HistoryGetBuffer(PCSRSS_CONSOLE Console)
+HistoryCurrentBuffer(PCSRSS_CONSOLE Console)
{
/* TODO: use actual EXE name sent from process that called ReadConsole */
UNICODE_STRING ExeName = { 14, 14, L"cmd.exe" };
@@ -57,7 +58,7 @@
return Hist;
}
-VOID FASTCALL
+static VOID
HistoryAddEntry(PCSRSS_CONSOLE Console)
{
UNICODE_STRING NewEntry;
@@ -67,7 +68,7 @@
NewEntry.Length = NewEntry.MaximumLength = Console->LineSize * sizeof(WCHAR);
NewEntry.Buffer = Console->LineBuffer;
- if (!(Hist = HistoryGetBuffer(Console)))
+ if (!(Hist = HistoryCurrentBuffer(Console)))
return;
/* Don't add blank or duplicate entries */
@@ -90,6 +91,7 @@
memmove(&Hist->Entries[i], &Hist->Entries[i + 1],
(Hist->NumEntries - (i + 1)) * sizeof(UNICODE_STRING));
Hist->Entries[Hist->NumEntries - 1] = NewEntry;
+ Hist->Position = Hist->NumEntries - 1;
return;
}
}
@@ -105,6 +107,17 @@
if (NT_SUCCESS(RtlDuplicateUnicodeString(0, &NewEntry,
&Hist->Entries[Hist->NumEntries])))
Hist->NumEntries++;
+ Hist->Position = Hist->NumEntries - 1;
+}
+
+static VOID
+HistoryGetCurrentEntry(PCSRSS_CONSOLE Console, PUNICODE_STRING Entry)
+{
+ PHISTORY_BUFFER Hist;
+ if (!(Hist = HistoryCurrentBuffer(Console)) || Hist->NumEntries == 0)
+ Entry->Length = 0;
+ else
+ *Entry = Hist->Entries[Hist->Position];
}
static PHISTORY_BUFFER
@@ -125,6 +138,8 @@
VOID FASTCALL
HistoryDeleteBuffer(PHISTORY_BUFFER Hist)
{
+ if (!Hist)
+ return;
while (Hist->NumEntries != 0)
RtlFreeUnicodeString(&Hist->Entries[--Hist->NumEntries]);
HeapFree(Win32CsrApiHeap, 0, Hist->Entries);
@@ -221,8 +236,7 @@
if (NT_SUCCESS(Status))
{
Hist = HistoryFindBuffer(Console,
&Request->Data.ExpungeCommandHistory.ExeName);
- if (Hist)
- HistoryDeleteBuffer(Hist);
+ HistoryDeleteBuffer(Hist);
ConioUnlockConsole(Console);
}
return Status;
@@ -260,7 +274,10 @@
{
/* If necessary, shrink by removing oldest entries */
for (; Hist->NumEntries > MaxEntries; Hist->NumEntries--)
+ {
RtlFreeUnicodeString(Hist->Entries++);
+ Hist->Position += (Hist->Position == 0);
+ }
Hist->MaxEntries = MaxEntries;
Hist->Entries = memcpy(NewEntryList, Hist->Entries,
@@ -301,4 +318,257 @@
return Status;
}
+static VOID
+LineInputSetPos(PCSRSS_CONSOLE Console, UINT Pos)
+{
+ if (Pos != Console->LinePos && Console->Mode & ENABLE_ECHO_INPUT)
+ {
+ PCSRSS_SCREEN_BUFFER Buffer = Console->ActiveBuffer;
+ UINT OldCursorX = Buffer->CurrentX;
+ UINT OldCursorY = Buffer->CurrentY;
+ INT XY = OldCursorY * Buffer->MaxX + OldCursorX;
+
+ XY += (Pos - Console->LinePos);
+ if (XY < 0)
+ XY = 0;
+ else if (XY >= Buffer->MaxY * Buffer->MaxX)
+ XY = Buffer->MaxY * Buffer->MaxX - 1;
+
+ Buffer->CurrentX = XY % Buffer->MaxX;
+ Buffer->CurrentY = XY / Buffer->MaxX;
+ ConioSetScreenInfo(Console, Buffer, OldCursorX, OldCursorY);
+ }
+
+ Console->LinePos = Pos;
+}
+
+static VOID
+LineInputEdit(PCSRSS_CONSOLE Console, UINT NumToDelete, UINT NumToInsert, WCHAR
*Insertion)
+{
+ UINT Pos = Console->LinePos;
+ UINT NewSize = Console->LineSize - NumToDelete + NumToInsert;
+ INT i;
+
+ /* Make sure there's always enough room for ending \r\n */
+ if (NewSize + 2 > Console->LineMaxSize)
+ return;
+
+ memmove(&Console->LineBuffer[Pos + NumToInsert],
+ &Console->LineBuffer[Pos + NumToDelete],
+ (Console->LineSize - (Pos + NumToDelete)) * sizeof(WCHAR));
+ memcpy(&Console->LineBuffer[Pos], Insertion, NumToInsert * sizeof(WCHAR));
+
+ if (Console->Mode & ENABLE_ECHO_INPUT)
+ {
+ for (i = Pos; i < NewSize; i++)
+ {
+ CHAR AsciiChar;
+ WideCharToMultiByte(Console->OutputCodePage, 0,
+ &Console->LineBuffer[i], 1,
+ &AsciiChar, 1, NULL, NULL);
+ ConioWriteConsole(Console, Console->ActiveBuffer, &AsciiChar, 1,
TRUE);
+ }
+ for (; i < Console->LineSize; i++)
+ {
+ ConioWriteConsole(Console, Console->ActiveBuffer, " ", 1,
TRUE);
+ }
+ Console->LinePos = i;
+ }
+
+ Console->LineSize = NewSize;
+ LineInputSetPos(Console, Pos + NumToInsert);
+}
+
+static VOID
+LineInputRecallHistory(PCSRSS_CONSOLE Console, INT Offset)
+{
+ PHISTORY_BUFFER Hist;
+
+ if (!(Hist = HistoryCurrentBuffer(Console)) || Hist->NumEntries == 0)
+ return;
+
+ Offset += Hist->Position;
+ Offset = max(Offset, 0);
+ Offset = min(Offset, Hist->NumEntries - 1);
+ Hist->Position = Offset;
+
+ LineInputSetPos(Console, 0);
+ LineInputEdit(Console, Console->LineSize,
+ Hist->Entries[Offset].Length / sizeof(WCHAR),
+ Hist->Entries[Offset].Buffer);
+}
+
+VOID FASTCALL
+LineInputKeyDown(PCSRSS_CONSOLE Console, KEY_EVENT_RECORD *KeyEvent)
+{
+ UINT Pos = Console->LinePos;
+ PHISTORY_BUFFER Hist;
+ UNICODE_STRING Entry;
+ INT HistPos;
+
+ switch (KeyEvent->wVirtualKeyCode)
+ {
+ case VK_ESCAPE:
+ /* Clear entire line */
+ LineInputSetPos(Console, 0);
+ LineInputEdit(Console, Console->LineSize, 0, NULL);
+ return;
+ case VK_HOME:
+ /* Move to start of line. With ctrl, erase everything left of cursor */
+ LineInputSetPos(Console, 0);
+ if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED |
RIGHT_CTRL_PRESSED))
+ LineInputEdit(Console, Pos, 0, NULL);
+ return;
+ case VK_END:
+ /* Move to end of line. With ctrl, erase everything right of cursor */
+ if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED |
RIGHT_CTRL_PRESSED))
+ LineInputEdit(Console, Console->LineSize - Pos, 0, NULL);
+ else
+ LineInputSetPos(Console, Console->LineSize);
+ return;
+ case VK_LEFT:
+ /* Move left. With ctrl, move to beginning of previous word */
+ if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED |
RIGHT_CTRL_PRESSED))
+ {
+ while (Pos > 0 && Console->LineBuffer[Pos - 1] == L' ')
Pos--;
+ while (Pos > 0 && Console->LineBuffer[Pos - 1] != L' ')
Pos--;
+ }
+ else
+ {
+ Pos -= (Pos > 0);
+ }
+ LineInputSetPos(Console, Pos);
+ return;
+ case VK_RIGHT:
+ case VK_F1:
+ /* Move right. With ctrl, move to beginning of next word */
+ if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED |
RIGHT_CTRL_PRESSED))
+ {
+ while (Pos < Console->LineSize && Console->LineBuffer[Pos]
!= L' ') Pos++;
+ while (Pos < Console->LineSize && Console->LineBuffer[Pos]
== L' ') Pos++;
+ LineInputSetPos(Console, Pos);
+ return;
+ }
+ else
+ {
+ /* Recall one character (but don't overwrite current line) */
+ HistoryGetCurrentEntry(Console, &Entry);
+ if (Pos < Console->LineSize)
+ LineInputSetPos(Console, Pos + 1);
+ else if (Pos * sizeof(WCHAR) < Entry.Length)
+ LineInputEdit(Console, 0, 1, &Entry.Buffer[Pos]);
+ }
+ return;
+ case VK_DELETE:
+ /* Remove character to right of cursor */
+ if (Pos != Console->LineSize)
+ LineInputEdit(Console, 1, 0, NULL);
+ return;
+ case VK_PRIOR:
+ /* Recall first history entry */
+ LineInputRecallHistory(Console, -((WORD)-1));
+ return;
+ case VK_NEXT:
+ /* Recall last history entry */
+ LineInputRecallHistory(Console, +((WORD)-1));
+ return;
+ case VK_UP:
+ case VK_F5:
+ /* Recall previous history entry. On first time, actually recall the
+ * current (usually last) entry; on subsequent times go back. */
+ LineInputRecallHistory(Console, Console->LineUpPressed ? -1 : 0);
+ Console->LineUpPressed = TRUE;
+ return;
+ case VK_DOWN:
+ /* Recall next history entry */
+ LineInputRecallHistory(Console, +1);
+ return;
+ case VK_F3:
+ /* Recall remainder of current history entry */
+ HistoryGetCurrentEntry(Console, &Entry);
+ if (Pos * sizeof(WCHAR) < Entry.Length)
+ {
+ UINT InsertSize = (Entry.Length / sizeof(WCHAR) - Pos);
+ UINT DeleteSize = min(Console->LineSize - Pos, InsertSize);
+ LineInputEdit(Console, DeleteSize, InsertSize, &Entry.Buffer[Pos]);
+ }
+ return;
+ case VK_F6:
+ /* Insert a ^Z character */
+ KeyEvent->uChar.UnicodeChar = 26;
+ break;
+ case VK_F7:
+ if (KeyEvent->dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
+ HistoryDeleteBuffer(HistoryCurrentBuffer(Console));
+ return;
+ case VK_F8:
+ /* Search for history entries starting with input. */
+ if (!(Hist = HistoryCurrentBuffer(Console)) || Hist->NumEntries == 0)
+ return;
+
+ /* Like Up/F5, on first time start from current (usually last) entry,
+ * but on subsequent times start at previous entry. */
+ if (Console->LineUpPressed)
+ Hist->Position = (Hist->Position ? Hist->Position :
Hist->NumEntries) - 1;
+ Console->LineUpPressed = TRUE;
+
+ Entry.Length = Console->LinePos * sizeof(WCHAR);
+ Entry.Buffer = Console->LineBuffer;
+
+ /* Keep going backwards, even wrapping around to the end,
+ * until we get back to starting point */
+ HistPos = Hist->Position;
+ do
+ {
+ if (RtlPrefixUnicodeString(&Entry, &Hist->Entries[HistPos],
FALSE))
+ {
+ Hist->Position = HistPos;
+ LineInputEdit(Console, Console->LineSize - Pos,
+ Hist->Entries[HistPos].Length / sizeof(WCHAR) - Pos,
+ &Hist->Entries[HistPos].Buffer[Pos]);
+ /* Cursor stays where it was */
+ LineInputSetPos(Console, Pos);
+ return;
+ }
+ if (--HistPos < 0) HistPos += Hist->NumEntries;
+ } while (HistPos != Hist->Position);
+ return;
+ }
+
+ if (KeyEvent->uChar.UnicodeChar == L'\b' && Console->Mode &
ENABLE_PROCESSED_INPUT)
+ {
+ /* backspace handling - if processed input enabled then we handle it here
+ * otherwise we treat it like a normal char. */
+ if (Pos > 0)
+ {
+ LineInputSetPos(Console, Pos - 1);
+ LineInputEdit(Console, 1, 0, NULL);
+ }
+ }
+ else if (KeyEvent->uChar.UnicodeChar == L'\r')
+ {
+ HistoryAddEntry(Console);
+
+ /* TODO: Expand aliases */
+
+ LineInputSetPos(Console, Console->LineSize);
+ Console->LineBuffer[Console->LineSize++] = L'\r';
+ if (Console->Mode & ENABLE_ECHO_INPUT)
+ ConioWriteConsole(Console, Console->ActiveBuffer, "\r", 1,
TRUE);
+ if (Console->Mode & ENABLE_PROCESSED_INPUT)
+ {
+ Console->LineBuffer[Console->LineSize++] = L'\n';
+ if (Console->Mode & ENABLE_ECHO_INPUT)
+ ConioWriteConsole(Console, Console->ActiveBuffer, "\n", 1,
TRUE);
+ }
+ Console->LineComplete = TRUE;
+ Console->LinePos = 0;
+ }
+ else if (KeyEvent->uChar.UnicodeChar != L'\0')
+ {
+ /* Normal character */
+ LineInputEdit(Console, 0, 1, &KeyEvent->uChar.UnicodeChar);
+ }
+}
+
/* EOF */
Modified: trunk/reactos/subsystems/win32/csrss/win32csr/win32csr.rbuild
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/csrss/win…
==============================================================================
--- trunk/reactos/subsystems/win32/csrss/win32csr/win32csr.rbuild [iso-8859-1] (original)
+++ trunk/reactos/subsystems/win32/csrss/win32csr/win32csr.rbuild [iso-8859-1] Sat Jun 5
20:17:42 2010
@@ -26,7 +26,7 @@
<file>guiconsole.c</file>
<file>handle.c</file>
<file>harderror.c</file>
- <file>history.c</file>
+ <file>lineinput.c</file>
<file>tuiconsole.c</file>
<file>appswitch.c</file>
<file>win32csr.rc</file>