NTSTATUS NTAPI ConDrvWriteConsoleInput(IN PCONSOLE Console, IN PCONSOLE_INPUT_BUFFER InputBuffer, IN BOOLEAN Unicode, IN PINPUT_RECORD InputRecord, IN ULONG NumEventsToWrite, OUT PULONG NumEventsWritten OPTIONAL) { NTSTATUS Status = STATUS_SUCCESS; ULONG i; if (Console == NULL || InputBuffer == NULL /* || InputRecord == NULL */) return STATUS_INVALID_PARAMETER; /* Validity checks */ ASSERT(Console == InputBuffer->Header.Console); ASSERT( (InputRecord != NULL && NumEventsToWrite >= 0) || (InputRecord == NULL && NumEventsToWrite == 0) ); // Do NOT do that !! Use the existing number of events already written, if any... // if (NumEventsWritten) *NumEventsWritten = 0; for (i = (NumEventsWritten ? *NumEventsWritten : 0); i < NumEventsToWrite && NT_SUCCESS(Status); ++i) { if (InputRecord->EventType == KEY_EVENT && !Unicode) { CHAR AsciiChar = InputRecord->Event.KeyEvent.uChar.AsciiChar; ConsoleInputAnsiCharToUnicodeChar(Console, &InputRecord->Event.KeyEvent.uChar.UnicodeChar, &AsciiChar); } Status = ConioProcessInputEvent(Console, InputRecord++); } if (NumEventsWritten) *NumEventsWritten = i; return Status; }
VOID GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer, PGUI_CONSOLE_DATA GuiData) { /* * This function supposes that the system clipboard was opened. */ PCONSRV_CONSOLE Console = Buffer->Header.Console; HANDLE hData; LPWSTR str; WCHAR CurChar = 0; USHORT VkKey; // MAKEWORD(low = vkey_code, high = shift_state); INPUT_RECORD er; hData = GetClipboardData(CF_UNICODETEXT); if (hData == NULL) return; str = GlobalLock(hData); if (str == NULL) return; DPRINT("Got data <%S> from clipboard\n", str); er.EventType = KEY_EVENT; er.Event.KeyEvent.wRepeatCount = 1; while (*str) { /* \r or \n characters. Go to the line only if we get "\r\n" sequence. */ if (CurChar == L'\r' && *str == L'\n') { str++; continue; } CurChar = *str++; /* Get the key code (+ shift state) corresponding to the character */ VkKey = VkKeyScanW(CurChar); if (VkKey == 0xFFFF) { DPRINT1("FIXME: TODO: VkKeyScanW failed - Should simulate the key!\n"); /* * We don't really need the scan/key code because we actually only * use the UnicodeChar for output purposes. It may pose few problems * later on but it's not of big importance. One trick would be to * convert the character to OEM / multibyte and use MapVirtualKey * on each byte (simulating an Alt-0xxx OEM keyboard press). */ } /* Pressing some control keys */ /* Pressing the character key, with the control keys maintained pressed */ er.Event.KeyEvent.bKeyDown = TRUE; er.Event.KeyEvent.wVirtualKeyCode = LOBYTE(VkKey); er.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW(LOBYTE(VkKey), MAPVK_VK_TO_VSC); er.Event.KeyEvent.uChar.UnicodeChar = CurChar; er.Event.KeyEvent.dwControlKeyState = 0; if (HIBYTE(VkKey) & 1) er.Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED; if (HIBYTE(VkKey) & 2) er.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; // RIGHT_CTRL_PRESSED; if (HIBYTE(VkKey) & 4) er.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED; // RIGHT_ALT_PRESSED; ConioProcessInputEvent(Console, &er); /* Up all the character and control keys */ er.Event.KeyEvent.bKeyDown = FALSE; ConioProcessInputEvent(Console, &er); } GlobalUnlock(hData); }
VOID NTAPI ConioProcessKey(PCONSRV_CONSOLE Console, MSG* msg) { static BYTE KeyState[256] = { 0 }; /* MSDN mentions that you should use the last virtual key code received * when putting a virtual key identity to a WM_CHAR message since multiple * or translated keys may be involved. */ static UINT LastVirtualKey = 0; DWORD ShiftState; WCHAR UnicodeChar; UINT VirtualKeyCode; UINT VirtualScanCode; BOOL Down = FALSE; BOOLEAN Fake; // Synthesized, not a real event BOOLEAN NotChar; // Message should not be used to return a character INPUT_RECORD er; if (Console == NULL) { DPRINT1("No Active Console!\n"); return; } VirtualScanCode = HIWORD(msg->lParam) & 0xFF; Down = msg->message == WM_KEYDOWN || msg->message == WM_CHAR || msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSCHAR; GetKeyboardState(KeyState); ShiftState = ConioGetShiftState(KeyState, msg->lParam); if (msg->message == WM_CHAR || msg->message == WM_SYSCHAR) { VirtualKeyCode = LastVirtualKey; UnicodeChar = msg->wParam; } else { WCHAR Chars[2]; INT RetChars = 0; VirtualKeyCode = msg->wParam; RetChars = ToUnicodeEx(VirtualKeyCode, VirtualScanCode, KeyState, Chars, 2, 0, NULL); UnicodeChar = (RetChars == 1 ? Chars[0] : 0); } Fake = UnicodeChar && (msg->message != WM_CHAR && msg->message != WM_SYSCHAR && msg->message != WM_KEYUP && msg->message != WM_SYSKEYUP); NotChar = (msg->message != WM_CHAR && msg->message != WM_SYSCHAR); if (NotChar) LastVirtualKey = msg->wParam; DPRINT("CONSRV: %s %s %s %s %02x %02x '%lc' %04x\n", Down ? "down" : "up ", (msg->message == WM_CHAR || msg->message == WM_SYSCHAR) ? "char" : "key ", Fake ? "fake" : "real", NotChar ? "notc" : "char", VirtualScanCode, VirtualKeyCode, (UnicodeChar >= L' ') ? UnicodeChar : L'.', ShiftState); if (Fake) return; /* Process Ctrl-C and Ctrl-Break */ if ( Console->InputBuffer.Mode & ENABLE_PROCESSED_INPUT && Down && (VirtualKeyCode == VK_PAUSE || VirtualKeyCode == 'C') && (ShiftState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) || KeyState[VK_CONTROL] & 0x80) ) { DPRINT1("Console_Api Ctrl-C\n"); ConSrvConsoleProcessCtrlEvent(Console, 0, CTRL_C_EVENT); if (Console->LineBuffer && !Console->LineComplete) { /* Line input is in progress; end it */ Console->LinePos = Console->LineSize = 0; Console->LineComplete = TRUE; } return; } if ( (ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) != 0 && (VirtualKeyCode == VK_UP || VirtualKeyCode == VK_DOWN) ) { if (!Down) return; /* Scroll up or down */ if (VirtualKeyCode == VK_UP) { /* Only scroll up if there is room to scroll up into */ if (Console->ActiveBuffer->CursorPosition.Y != Console->ActiveBuffer->ScreenBufferSize.Y - 1) { Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY + Console->ActiveBuffer->ScreenBufferSize.Y - 1) % Console->ActiveBuffer->ScreenBufferSize.Y; Console->ActiveBuffer->CursorPosition.Y++; } } else { /* Only scroll down if there is room to scroll down into */ if (Console->ActiveBuffer->CursorPosition.Y != 0) { Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY + 1) % Console->ActiveBuffer->ScreenBufferSize.Y; Console->ActiveBuffer->CursorPosition.Y--; } } ConioDrawConsole(Console); return; } /* Send the key press to the console driver */ er.EventType = KEY_EVENT; er.Event.KeyEvent.bKeyDown = Down; er.Event.KeyEvent.wRepeatCount = 1; er.Event.KeyEvent.wVirtualKeyCode = VirtualKeyCode; er.Event.KeyEvent.wVirtualScanCode = VirtualScanCode; er.Event.KeyEvent.uChar.UnicodeChar = UnicodeChar; er.Event.KeyEvent.dwControlKeyState = ShiftState; ConioProcessInputEvent(Console, &er); }
/* * This function explicitely references Console->ActiveBuffer * (and also makes use of keyboard functions...). * It is possible that it will move into frontends... */ VOID NTAPI ConDrvProcessKey(IN PCONSOLE Console, IN BOOLEAN Down, IN UINT VirtualKeyCode, IN UINT VirtualScanCode, IN WCHAR UnicodeChar, IN ULONG ShiftState, IN BYTE KeyStateCtrl) { INPUT_RECORD er; /* process Ctrl-C and Ctrl-Break */ if ( Console->InputBuffer.Mode & ENABLE_PROCESSED_INPUT && Down && (VirtualKeyCode == VK_PAUSE || VirtualKeyCode == 'C') && (ShiftState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) || KeyStateCtrl & 0x80) ) { DPRINT1("Console_Api Ctrl-C\n"); ConDrvConsoleProcessCtrlEvent(Console, 0, CTRL_C_EVENT); if (Console->LineBuffer && !Console->LineComplete) { /* Line input is in progress; end it */ Console->LinePos = Console->LineSize = 0; Console->LineComplete = TRUE; } return; } if ( (ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) != 0 && (VK_UP == VirtualKeyCode || VK_DOWN == VirtualKeyCode) ) { if (!Down) return; /* scroll up or down */ if (VK_UP == VirtualKeyCode) { /* only scroll up if there is room to scroll up into */ if (Console->ActiveBuffer->CursorPosition.Y != Console->ActiveBuffer->ScreenBufferSize.Y - 1) { Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY + Console->ActiveBuffer->ScreenBufferSize.Y - 1) % Console->ActiveBuffer->ScreenBufferSize.Y; Console->ActiveBuffer->CursorPosition.Y++; } } else { /* only scroll down if there is room to scroll down into */ if (Console->ActiveBuffer->CursorPosition.Y != 0) { Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY + 1) % Console->ActiveBuffer->ScreenBufferSize.Y; Console->ActiveBuffer->CursorPosition.Y--; } } ConioDrawConsole(Console); return; } er.EventType = KEY_EVENT; er.Event.KeyEvent.bKeyDown = Down; er.Event.KeyEvent.wRepeatCount = 1; er.Event.KeyEvent.wVirtualKeyCode = VirtualKeyCode; er.Event.KeyEvent.wVirtualScanCode = VirtualScanCode; er.Event.KeyEvent.uChar.UnicodeChar = UnicodeChar; er.Event.KeyEvent.dwControlKeyState = ShiftState; ConioProcessInputEvent(Console, &er); }
VOID GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer, PGUI_CONSOLE_DATA GuiData) { /* * This function supposes that the system clipboard was opened. */ PCONSRV_CONSOLE Console = Buffer->Header.Console; HANDLE hData; LPWSTR str; WCHAR CurChar = 0; USHORT VkKey; // MAKEWORD(low = vkey_code, high = shift_state); INPUT_RECORD er; hData = GetClipboardData(CF_UNICODETEXT); if (hData == NULL) return; str = GlobalLock(hData); if (str == NULL) return; DPRINT("Got data <%S> from clipboard\n", str); er.EventType = KEY_EVENT; er.Event.KeyEvent.wRepeatCount = 1; while (*str) { /* \r or \n characters. Go to the line only if we get "\r\n" sequence. */ if (CurChar == L'\r' && *str == L'\n') { str++; continue; } CurChar = *str++; /* Get the key code (+ shift state) corresponding to the character */ VkKey = VkKeyScanW(CurChar); if (VkKey == 0xFFFF) { DPRINT1("VkKeyScanW failed - Should simulate the key...\n"); continue; } /* Pressing some control keys */ /* Pressing the character key, with the control keys maintained pressed */ er.Event.KeyEvent.bKeyDown = TRUE; er.Event.KeyEvent.wVirtualKeyCode = LOBYTE(VkKey); er.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW(LOBYTE(VkKey), MAPVK_VK_TO_CHAR); er.Event.KeyEvent.uChar.UnicodeChar = CurChar; er.Event.KeyEvent.dwControlKeyState = 0; if (HIBYTE(VkKey) & 1) er.Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED; if (HIBYTE(VkKey) & 2) er.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; // RIGHT_CTRL_PRESSED; if (HIBYTE(VkKey) & 4) er.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED; // RIGHT_ALT_PRESSED; ConioProcessInputEvent(Console, &er); /* Up all the character and control keys */ er.Event.KeyEvent.bKeyDown = FALSE; ConioProcessInputEvent(Console, &er); } GlobalUnlock(hData); }
NTSTATUS ConioResizeBuffer(PCONSOLE Console, PTEXTMODE_SCREEN_BUFFER ScreenBuffer, COORD Size) { PCHAR_INFO Buffer; DWORD Offset = 0; PCHAR_INFO ptr; WORD CurrentAttribute; USHORT CurrentY; PCHAR_INFO OldBuffer; DWORD i; DWORD diff; /* Buffer size is not allowed to be smaller than the view size */ if (Size.X < ScreenBuffer->ViewSize.X || Size.Y < ScreenBuffer->ViewSize.Y) return STATUS_INVALID_PARAMETER; if (Size.X == ScreenBuffer->ScreenBufferSize.X && Size.Y == ScreenBuffer->ScreenBufferSize.Y) { // FIXME: Trigger a buffer resize event ?? return STATUS_SUCCESS; } if (Console->FixedSize) { /* * The console is in fixed-size mode, so we cannot resize anything * at the moment. However, keep those settings somewhere so that * we can try to set them up when we will be allowed to do so. */ ScreenBuffer->OldScreenBufferSize = Size; return STATUS_NOT_SUPPORTED; // STATUS_SUCCESS } Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size.X * Size.Y * sizeof(CHAR_INFO)); if (!Buffer) return STATUS_NO_MEMORY; DPRINT1("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer->ScreenBufferSize.X, ScreenBuffer->ScreenBufferSize.Y, Size.X, Size.Y); OldBuffer = ScreenBuffer->Buffer; for (CurrentY = 0; CurrentY < ScreenBuffer->ScreenBufferSize.Y && CurrentY < Size.Y; CurrentY++) { ptr = ConioCoordToPointer(ScreenBuffer, 0, CurrentY); if (Size.X <= ScreenBuffer->ScreenBufferSize.X) { /* Reduce size */ RtlCopyMemory(Buffer + Offset, ptr, Size.X * sizeof(CHAR_INFO)); Offset += Size.X; } else { /* Enlarge size */ RtlCopyMemory(Buffer + Offset, ptr, ScreenBuffer->ScreenBufferSize.X * sizeof(CHAR_INFO)); Offset += ScreenBuffer->ScreenBufferSize.X; /* The attribute to be used is the one of the last cell of the current line */ CurrentAttribute = ConioCoordToPointer(ScreenBuffer, ScreenBuffer->ScreenBufferSize.X - 1, CurrentY)->Attributes; diff = Size.X - ScreenBuffer->ScreenBufferSize.X; /* Zero-out the new part of the buffer */ for (i = 0; i < diff; i++) { ptr = Buffer + Offset; ptr->Char.UnicodeChar = L' '; ptr->Attributes = CurrentAttribute; ++Offset; } } } if (Size.Y > ScreenBuffer->ScreenBufferSize.Y) { diff = Size.X * (Size.Y - ScreenBuffer->ScreenBufferSize.Y); /* Zero-out the new part of the buffer */ for (i = 0; i < diff; i++) { ptr = Buffer + Offset; ptr->Char.UnicodeChar = L' '; ptr->Attributes = ScreenBuffer->ScreenDefaultAttrib; ++Offset; } } (void)InterlockedExchangePointer((PVOID volatile*)&ScreenBuffer->Buffer, Buffer); ConsoleFreeHeap(OldBuffer); ScreenBuffer->ScreenBufferSize = ScreenBuffer->OldScreenBufferSize = Size; ScreenBuffer->VirtualY = 0; /* Ensure cursor and window are within buffer */ if (ScreenBuffer->CursorPosition.X >= Size.X) ScreenBuffer->CursorPosition.X = Size.X - 1; if (ScreenBuffer->CursorPosition.Y >= Size.Y) ScreenBuffer->CursorPosition.Y = Size.Y - 1; if (ScreenBuffer->ViewOrigin.X > Size.X - ScreenBuffer->ViewSize.X) ScreenBuffer->ViewOrigin.X = Size.X - ScreenBuffer->ViewSize.X; if (ScreenBuffer->ViewOrigin.Y > Size.Y - ScreenBuffer->ViewSize.Y) ScreenBuffer->ViewOrigin.Y = Size.Y - ScreenBuffer->ViewSize.Y; /* * Trigger a buffer resize event */ if (Console->InputBuffer.Mode & ENABLE_WINDOW_INPUT) { INPUT_RECORD er; er.EventType = WINDOW_BUFFER_SIZE_EVENT; er.Event.WindowBufferSizeEvent.dwSize = ScreenBuffer->ScreenBufferSize; ConioProcessInputEvent(Console, &er); } return STATUS_SUCCESS; }