Beispiel #1
0
static VOID
LineInputEdit(PCONSRV_CONSOLE Console,
              UINT NumToDelete,
              UINT NumToInsert,
              PWCHAR Insertion)
{
    PTEXTMODE_SCREEN_BUFFER ActiveBuffer;
    UINT Pos = Console->LinePos;
    UINT NewSize = Console->LineSize - NumToDelete + NumToInsert;
    UINT i;

    if (GetType(Console->ActiveBuffer) != TEXTMODE_BUFFER) return;
    ActiveBuffer = (PTEXTMODE_SCREEN_BUFFER)Console->ActiveBuffer;

    /* 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 (GetConsoleInputBufferMode(Console) & ENABLE_ECHO_INPUT)
    {
        for (i = Pos; i < NewSize; i++)
        {
            TermWriteStream(Console, ActiveBuffer, &Console->LineBuffer[i], 1, TRUE);
        }
        for (; i < Console->LineSize; i++)
        {
            TermWriteStream(Console, ActiveBuffer, L" ", 1, TRUE);
        }
        Console->LinePos = i;
    }

    Console->LineSize = NewSize;
    LineInputSetPos(Console, Pos + NumToInsert);
}
Beispiel #2
0
NTSTATUS NTAPI
ConDrvWriteConsole(IN PCONSOLE Console,
                   IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
                   IN BOOLEAN Unicode,
                   IN PVOID StringBuffer,
                   IN ULONG NumCharsToWrite,
                   OUT PULONG NumCharsWritten OPTIONAL)
{
    NTSTATUS Status = STATUS_SUCCESS;
    PWCHAR Buffer = NULL;
    ULONG Written = 0;
    ULONG Length;

    if (Console == NULL || ScreenBuffer == NULL /* || StringBuffer == NULL */)
        return STATUS_INVALID_PARAMETER;

    /* Validity checks */
    ASSERT(Console == ScreenBuffer->Header.Console);
    ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCharsToWrite == 0));

    /* Stop here if the console is paused */
    if (Console->UnpauseEvent != NULL) return STATUS_PENDING;

    /* Convert the string to UNICODE */
    if (Unicode)
    {
        Buffer = StringBuffer;
    }
    else
    {
        Length = MultiByteToWideChar(Console->OutputCodePage, 0,
                                     (PCHAR)StringBuffer,
                                     NumCharsToWrite,
                                     NULL, 0);
        Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
        if (Buffer)
        {
            MultiByteToWideChar(Console->OutputCodePage, 0,
                                (PCHAR)StringBuffer,
                                NumCharsToWrite,
                                (PWCHAR)Buffer, Length);
        }
        else
        {
            Status = STATUS_NO_MEMORY;
        }
    }

    /* Send it */
    if (Buffer)
    {
        if (NT_SUCCESS(Status))
        {
            Status = TermWriteStream(Console,
                                     ScreenBuffer,
                                     Buffer,
                                     NumCharsToWrite,
                                     TRUE);
            if (NT_SUCCESS(Status))
            {
                Written = NumCharsToWrite;
            }
        }

        if (!Unicode) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
    }

    if (NumCharsWritten) *NumCharsWritten = Written;

    return Status;
}
Beispiel #3
0
VOID
LineInputKeyDown(PCONSRV_CONSOLE Console,
                 PUNICODE_STRING ExeName,
                 KEY_EVENT_RECORD *KeyEvent)
{
    UINT Pos = Console->LinePos;
    UNICODE_STRING Entry;

    /*
     * First, deal with control keys...
     */

    switch (KeyEvent->wVirtualKeyCode)
    {
    case VK_ESCAPE:
    {
        /* Clear entire line */
        LineInputSetPos(Console, 0);
        LineInputEdit(Console, Console->LineSize, 0, NULL);

        // TESTS!!
        if (Popup)
        {
            DestroyPopupWindow(Popup);
            Popup = 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);
        }
        else
        {
            /* Recall one character (but don't overwrite current line) */
            HistoryGetCurrentEntry(Console, ExeName, &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_INSERT:
    {
        /* Toggle between insert and overstrike */
        Console->LineInsertToggle = !Console->LineInsertToggle;
        TermSetCursorInfo(Console, Console->ActiveBuffer);
        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, ExeName, -((WORD)-1));
        return;
    }

    case VK_NEXT:
    {
        /* Recall last history entry */
        LineInputRecallHistory(Console, ExeName, +((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, ExeName, Console->LineUpPressed ? -1 : 0);
        Console->LineUpPressed = TRUE;
        return;
    }

    case VK_DOWN:
    {
        /* Recall next history entry */
        LineInputRecallHistory(Console, ExeName, +1);
        return;
    }

    case VK_F3:
    {
        /* Recall remainder of current history entry */
        HistoryGetCurrentEntry(Console, ExeName, &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))
            HistoryDeleteCurrentBuffer(Console, ExeName);
        else
        {
            if (Popup) DestroyPopupWindow(Popup);
            Popup = HistoryDisplayCurrentHistory(Console, ExeName);
        }
        return;
    }

    case VK_F8:
    {
        UNICODE_STRING EntryFound;

        Entry.Length = Console->LinePos * sizeof(WCHAR); // == Pos * sizeof(WCHAR)
        Entry.Buffer = Console->LineBuffer;

        if (HistoryFindEntryByPrefix(Console, ExeName, &Entry, &EntryFound))
        {
            LineInputEdit(Console, Console->LineSize - Pos,
                          EntryFound.Length / sizeof(WCHAR) - Pos,
                          &EntryFound.Buffer[Pos]);
            /* Cursor stays where it was */
            LineInputSetPos(Console, Pos);
        }

        return;
    }
#if 0
    {
        PHISTORY_BUFFER Hist;
        INT HistPos;

        /* Search for history entries starting with input. */
        Hist = HistoryCurrentBuffer(Console, ExeName);
        if (!Hist || 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); // == Pos * 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;
    }
#endif

    return;
    }


    /*
     * OK, we deal with normal keys, we can continue...
     */

    if (KeyEvent->uChar.UnicodeChar == L'\b' && GetConsoleInputBufferMode(Console) & 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')
    {
        Entry.Length = Entry.MaximumLength = Console->LineSize * sizeof(WCHAR);
        Entry.Buffer = Console->LineBuffer;
        HistoryAddEntry(Console, ExeName, &Entry);

        /* TODO: Expand aliases */
        DPRINT1("TODO: Expand aliases\n");

        LineInputSetPos(Console, Console->LineSize);
        Console->LineBuffer[Console->LineSize++] = L'\r';
        if (GetConsoleInputBufferMode(Console) & ENABLE_ECHO_INPUT)
        {
            if (GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER)
            {
                TermWriteStream(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), L"\r", 1, TRUE);
            }
        }

        /*
         * Add \n if processed input. There should usually be room for it,
         * but an exception to the rule exists: the buffer could have been
         * pre-filled with LineMaxSize - 1 characters.
         */
        if (GetConsoleInputBufferMode(Console) & ENABLE_PROCESSED_INPUT &&
                Console->LineSize < Console->LineMaxSize)
        {
            Console->LineBuffer[Console->LineSize++] = L'\n';
            if (GetConsoleInputBufferMode(Console) & ENABLE_ECHO_INPUT)
            {
                if (GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER)
                {
                    TermWriteStream(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), L"\n", 1, TRUE);
                }
            }
        }
        Console->LineComplete = TRUE;
        Console->LinePos = 0;
    }
    else if (KeyEvent->uChar.UnicodeChar != L'\0')
    {
        if (KeyEvent->uChar.UnicodeChar < 0x20 &&
                Console->LineWakeupMask & (1 << KeyEvent->uChar.UnicodeChar))
        {
            /* Control key client wants to handle itself (e.g. for tab completion) */
            Console->LineBuffer[Console->LineSize++] = L' ';
            Console->LineBuffer[Console->LinePos] = KeyEvent->uChar.UnicodeChar;
            Console->LineComplete = TRUE;
            Console->LinePos = 0;
        }
        else
        {
            /* Normal character */
            BOOL Overstrike = !Console->LineInsertToggle && (Console->LinePos != Console->LineSize);
            DPRINT("Overstrike = %s\n", Overstrike ? "true" : "false");
            LineInputEdit(Console, (Overstrike ? 1 : 0), 1, &KeyEvent->uChar.UnicodeChar);
        }
    }
}