reactos/base/setup/usetup/console.c
Hermès Bélusca-Maïto bfd8a84865
[BLUE] Improve initialization and interfacing with INBV.
CORE-15901

This fixes display reset transition when an external module acquired
INBV ownership and then released it, similarly to what was done in
commit 0ad65796 for VIDEOPRT.

For this a backup screenbuffer is used to store the contents of the
screen just before an INBV screen acquire transition, and these contents
are restored when it is detected that INBV ownership has been released.
Also, the active text font associated with the active console code-page
is restored, as well as the cursor state and shape.

In addition, any user of BLUE.SYS is now required to explicitly issue
a new IOCTL_CONSOLE_RESET_SCREEN to either enable or disable the screen.
This allows avoiding nasty unwanted screen mode switches when a handle
to the \Device\BlueScreen device is opened but no screen mode switch was
actually wanted - This "fixes" this annoyance on ReactOS and Windows,
when these are running witha VGA-compatible video driver and one wants
to look at properties of the \Device\BlueScreen device using
Sysinternals' WinObj.

Following this, we don't need to check anymore for explicit INBV
ownership by issuing calls to InbvCheckDisplayOwnership(), but instead
we check whether the screen has beeen manually enabled using the
aforementioned IOCTL. This partly supersedes commit 8b553a4b, and allows
fixing the second bug, namely that if we start ReactOS without the
/NOGUIBOOT option (and thus, INBV is active during boot), USETUP would
not show up anything because BLUE.SYS wouldn't display anything on screen.
See CORE-15901.

[USETUP][CONSRV] Call IOCTL_CONSOLE_RESET_SCREEN to tell BlueScreen device to enable the screen.
2019-12-15 03:37:52 +01:00

689 lines
19 KiB
C

/*
* ReactOS kernel
* Copyright (C) 2002 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS text-mode setup
* FILE: base/setup/usetup/console.c
* PURPOSE: Console support functions
* PROGRAMMER:
*/
/* INCLUDES ******************************************************************/
#include <usetup.h>
/* Blue Driver Header */
#include <blue/ntddblue.h>
#include "keytrans.h"
#define NDEBUG
#include <debug.h>
/* DATA **********************************************************************/
static BOOLEAN InputQueueEmpty;
static BOOLEAN WaitForInput;
static KEYBOARD_INPUT_DATA InputDataQueue; // Only one element!
static IO_STATUS_BLOCK InputIosb;
/* FUNCTIONS *****************************************************************/
BOOL
WINAPI
AllocConsole(VOID)
{
NTSTATUS Status;
UNICODE_STRING ScreenName = RTL_CONSTANT_STRING(L"\\??\\BlueScreen");
UNICODE_STRING KeyboardName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardClass0");
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
ULONG Enable;
/* Open the screen */
InitializeObjectAttributes(&ObjectAttributes,
&ScreenName,
0,
NULL,
NULL);
Status = NtOpenFile(&StdOutput,
FILE_ALL_ACCESS,
&ObjectAttributes,
&IoStatusBlock,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_ALERT);
if (!NT_SUCCESS(Status))
return FALSE;
/* Enable it */
Enable = TRUE;
Status = NtDeviceIoControlFile(StdOutput,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_CONSOLE_RESET_SCREEN,
&Enable,
sizeof(Enable),
NULL,
0);
if (!NT_SUCCESS(Status))
{
NtClose(StdOutput);
return FALSE;
}
/* Open the keyboard */
InitializeObjectAttributes(&ObjectAttributes,
&KeyboardName,
0,
NULL,
NULL);
Status = NtOpenFile(&StdInput,
FILE_ALL_ACCESS,
&ObjectAttributes,
&IoStatusBlock,
FILE_OPEN,
0);
if (!NT_SUCCESS(Status))
{
NtClose(StdOutput);
return FALSE;
}
/* Reset the queue state */
InputQueueEmpty = TRUE;
WaitForInput = FALSE;
return TRUE;
}
BOOL
WINAPI
AttachConsole(
IN DWORD dwProcessId)
{
return FALSE;
}
BOOL
WINAPI
FreeConsole(VOID)
{
/* Reset the queue state */
InputQueueEmpty = TRUE;
WaitForInput = FALSE;
if (StdInput != INVALID_HANDLE_VALUE)
NtClose(StdInput);
if (StdOutput != INVALID_HANDLE_VALUE)
NtClose(StdOutput);
return TRUE;
}
BOOL
WINAPI
WriteConsole(
IN HANDLE hConsoleOutput,
IN const VOID *lpBuffer,
IN DWORD nNumberOfCharsToWrite,
OUT LPDWORD lpNumberOfCharsWritten,
IN LPVOID lpReserved)
{
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
Status = NtWriteFile(hConsoleOutput,
NULL,
NULL,
NULL,
&IoStatusBlock,
(PVOID)lpBuffer,
nNumberOfCharsToWrite,
NULL,
NULL);
if (!NT_SUCCESS(Status))
return FALSE;
*lpNumberOfCharsWritten = IoStatusBlock.Information;
return TRUE;
}
HANDLE
WINAPI
GetStdHandle(
IN DWORD nStdHandle)
{
switch (nStdHandle)
{
case STD_INPUT_HANDLE:
return StdInput;
case STD_OUTPUT_HANDLE:
return StdOutput;
default:
return INVALID_HANDLE_VALUE;
}
}
BOOL
WINAPI
FlushConsoleInputBuffer(
IN HANDLE hConsoleInput)
{
NTSTATUS Status;
LARGE_INTEGER Offset, Timeout;
IO_STATUS_BLOCK IoStatusBlock;
KEYBOARD_INPUT_DATA InputData;
/* Cancel any pending read */
if (WaitForInput)
NtCancelIoFile(hConsoleInput, &IoStatusBlock);
/* Reset the queue state */
InputQueueEmpty = TRUE;
WaitForInput = FALSE;
/* Flush the keyboard buffer */
do
{
Offset.QuadPart = 0;
Status = NtReadFile(hConsoleInput,
NULL,
NULL,
NULL,
&IoStatusBlock,
&InputData,
sizeof(InputData),
&Offset,
NULL);
if (Status == STATUS_PENDING)
{
Timeout.QuadPart = -100;
Status = NtWaitForSingleObject(hConsoleInput, FALSE, &Timeout);
if (Status == STATUS_TIMEOUT)
{
NtCancelIoFile(hConsoleInput, &IoStatusBlock);
return TRUE;
}
}
} while (NT_SUCCESS(Status));
return FALSE;
}
BOOL
WINAPI
PeekConsoleInput(
IN HANDLE hConsoleInput,
OUT PINPUT_RECORD lpBuffer,
IN DWORD nLength,
OUT LPDWORD lpNumberOfEventsRead)
{
NTSTATUS Status;
LARGE_INTEGER Offset, Timeout;
KEYBOARD_INPUT_DATA InputData;
if (InputQueueEmpty)
{
/* Read the keyboard for an event, without waiting */
if (!WaitForInput)
{
Offset.QuadPart = 0;
Status = NtReadFile(hConsoleInput,
NULL,
NULL,
NULL,
&InputIosb,
&InputDataQueue,
sizeof(InputDataQueue),
&Offset,
NULL);
if (!NT_SUCCESS(Status))
return FALSE;
if (Status == STATUS_PENDING)
{
/* No input yet, we will have to wait next time */
*lpNumberOfEventsRead = 0;
WaitForInput = TRUE;
return TRUE;
}
}
else
{
/*
* We already tried to read from the keyboard and are
* waiting for data, check whether something showed up.
*/
Timeout.QuadPart = -100; // Wait just a little bit.
Status = NtWaitForSingleObject(hConsoleInput, FALSE, &Timeout);
if (Status == STATUS_TIMEOUT)
{
/* Nothing yet, continue waiting next time */
*lpNumberOfEventsRead = 0;
WaitForInput = TRUE;
return TRUE;
}
WaitForInput = FALSE;
if (!NT_SUCCESS(Status))
return FALSE;
}
/* We got something in the queue */
InputQueueEmpty = FALSE;
WaitForInput = FALSE;
}
/* Fetch from the queue but keep it inside */
InputData = InputDataQueue;
lpBuffer->EventType = KEY_EVENT;
Status = IntTranslateKey(hConsoleInput, &InputData, &lpBuffer->Event.KeyEvent);
if (!NT_SUCCESS(Status))
return FALSE;
*lpNumberOfEventsRead = 1;
return TRUE;
}
BOOL
WINAPI
ReadConsoleInput(
IN HANDLE hConsoleInput,
OUT PINPUT_RECORD lpBuffer,
IN DWORD nLength,
OUT LPDWORD lpNumberOfEventsRead)
{
NTSTATUS Status;
LARGE_INTEGER Offset;
KEYBOARD_INPUT_DATA InputData;
if (InputQueueEmpty)
{
/* Read the keyboard and wait for an event, skipping the queue */
if (!WaitForInput)
{
Offset.QuadPart = 0;
Status = NtReadFile(hConsoleInput,
NULL,
NULL,
NULL,
&InputIosb,
&InputDataQueue,
sizeof(InputDataQueue),
&Offset,
NULL);
if (Status == STATUS_PENDING)
{
/* Block and wait for input */
WaitForInput = TRUE;
Status = NtWaitForSingleObject(hConsoleInput, FALSE, NULL);
WaitForInput = FALSE;
Status = InputIosb.Status;
}
if (!NT_SUCCESS(Status))
return FALSE;
}
else
{
/*
* We already tried to read from the keyboard and are
* waiting for data, block and wait for input.
*/
Status = NtWaitForSingleObject(hConsoleInput, FALSE, NULL);
WaitForInput = FALSE;
Status = InputIosb.Status;
if (!NT_SUCCESS(Status))
return FALSE;
}
}
/* Fetch from the queue and empty it */
InputData = InputDataQueue;
InputQueueEmpty = TRUE;
lpBuffer->EventType = KEY_EVENT;
Status = IntTranslateKey(hConsoleInput, &InputData, &lpBuffer->Event.KeyEvent);
if (!NT_SUCCESS(Status))
return FALSE;
*lpNumberOfEventsRead = 1;
return TRUE;
}
BOOL
WINAPI
WriteConsoleOutputCharacterA(
HANDLE hConsoleOutput,
IN LPCSTR lpCharacter,
IN DWORD nLength,
IN COORD dwWriteCoord,
OUT LPDWORD lpNumberOfCharsWritten)
{
IO_STATUS_BLOCK IoStatusBlock;
PCHAR Buffer;
COORD *pCoord;
PCHAR pText;
NTSTATUS Status;
Buffer = (CHAR*)RtlAllocateHeap(ProcessHeap,
0,
nLength + sizeof(COORD));
pCoord = (COORD *)Buffer;
pText = (PCHAR)(pCoord + 1);
*pCoord = dwWriteCoord;
memcpy(pText, lpCharacter, nLength);
Status = NtDeviceIoControlFile(hConsoleOutput,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
NULL,
0,
Buffer,
nLength + sizeof(COORD));
RtlFreeHeap(ProcessHeap, 0, Buffer);
if (!NT_SUCCESS(Status))
return FALSE;
*lpNumberOfCharsWritten = IoStatusBlock.Information;
return TRUE;
}
BOOL
WINAPI
WriteConsoleOutputCharacterW(
HANDLE hConsoleOutput,
IN LPCWSTR lpCharacter,
IN DWORD nLength,
IN COORD dwWriteCoord,
OUT LPDWORD lpNumberOfCharsWritten)
{
IO_STATUS_BLOCK IoStatusBlock;
PCHAR Buffer;
COORD *pCoord;
PCHAR pText;
NTSTATUS Status;
// ULONG i;
UNICODE_STRING UnicodeString;
OEM_STRING OemString;
ULONG OemLength;
UnicodeString.Length = nLength * sizeof(WCHAR);
UnicodeString.MaximumLength = nLength * sizeof(WCHAR);
UnicodeString.Buffer = (PWSTR)lpCharacter;
OemLength = RtlUnicodeStringToOemSize(&UnicodeString);
Buffer = (CHAR*)RtlAllocateHeap(ProcessHeap,
0,
OemLength + sizeof(COORD));
// nLength + sizeof(COORD));
if (Buffer== NULL)
return FALSE;
pCoord = (COORD *)Buffer;
pText = (PCHAR)(pCoord + 1);
*pCoord = dwWriteCoord;
OemString.Length = 0;
OemString.MaximumLength = OemLength;
OemString.Buffer = pText;
Status = RtlUnicodeStringToOemString(&OemString,
&UnicodeString,
FALSE);
if (!NT_SUCCESS(Status))
goto done;
/* FIXME: use real unicode->oem conversion */
// for (i = 0; i < nLength; i++)
// pText[i] = (CHAR)lpCharacter[i];
Status = NtDeviceIoControlFile(hConsoleOutput,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
NULL,
0,
Buffer,
nLength + sizeof(COORD));
done:
RtlFreeHeap(ProcessHeap, 0, Buffer);
if (!NT_SUCCESS(Status))
return FALSE;
*lpNumberOfCharsWritten = IoStatusBlock.Information;
return TRUE;
}
BOOL
WINAPI
FillConsoleOutputAttribute(
IN HANDLE hConsoleOutput,
IN WORD wAttribute,
IN DWORD nLength,
IN COORD dwWriteCoord,
OUT LPDWORD lpNumberOfAttrsWritten)
{
IO_STATUS_BLOCK IoStatusBlock;
OUTPUT_ATTRIBUTE Buffer;
NTSTATUS Status;
Buffer.wAttribute = wAttribute;
Buffer.nLength = nLength;
Buffer.dwCoord = dwWriteCoord;
Status = NtDeviceIoControlFile(hConsoleOutput,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE,
&Buffer,
sizeof(OUTPUT_ATTRIBUTE),
&Buffer,
sizeof(OUTPUT_ATTRIBUTE));
if (!NT_SUCCESS(Status))
return FALSE;
*lpNumberOfAttrsWritten = Buffer.dwTransfered;
return TRUE;
}
BOOL
WINAPI
FillConsoleOutputCharacterA(
IN HANDLE hConsoleOutput,
IN CHAR cCharacter,
IN DWORD nLength,
IN COORD dwWriteCoord,
OUT LPDWORD lpNumberOfCharsWritten)
{
IO_STATUS_BLOCK IoStatusBlock;
OUTPUT_CHARACTER Buffer;
NTSTATUS Status;
Buffer.cCharacter = cCharacter;
Buffer.nLength = nLength;
Buffer.dwCoord = dwWriteCoord;
Status = NtDeviceIoControlFile(hConsoleOutput,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER,
&Buffer,
sizeof(OUTPUT_CHARACTER),
&Buffer,
sizeof(OUTPUT_CHARACTER));
if (!NT_SUCCESS(Status))
return FALSE;
*lpNumberOfCharsWritten = Buffer.dwTransfered;
return TRUE;
}
BOOL
WINAPI
GetConsoleScreenBufferInfo(
IN HANDLE hConsoleOutput,
OUT PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo)
{
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
Status = NtDeviceIoControlFile(hConsoleOutput,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO,
NULL,
0,
lpConsoleScreenBufferInfo,
sizeof(CONSOLE_SCREEN_BUFFER_INFO));
return NT_SUCCESS(Status);
}
BOOL
WINAPI
SetConsoleCursorInfo(
IN HANDLE hConsoleOutput,
IN const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo)
{
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
Status = NtDeviceIoControlFile(hConsoleOutput,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_CONSOLE_SET_CURSOR_INFO,
(PCONSOLE_CURSOR_INFO)lpConsoleCursorInfo,
sizeof(CONSOLE_CURSOR_INFO),
NULL,
0);
return NT_SUCCESS(Status);
}
BOOL
WINAPI
SetConsoleCursorPosition(
IN HANDLE hConsoleOutput,
IN COORD dwCursorPosition)
{
CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
Status = GetConsoleScreenBufferInfo(hConsoleOutput, &ConsoleScreenBufferInfo);
if (!NT_SUCCESS(Status))
return FALSE;
ConsoleScreenBufferInfo.dwCursorPosition.X = dwCursorPosition.X;
ConsoleScreenBufferInfo.dwCursorPosition.Y = dwCursorPosition.Y;
Status = NtDeviceIoControlFile(hConsoleOutput,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO,
&ConsoleScreenBufferInfo,
sizeof(CONSOLE_SCREEN_BUFFER_INFO),
NULL,
0);
return NT_SUCCESS(Status);
}
BOOL
WINAPI
SetConsoleTextAttribute(
IN HANDLE hConsoleOutput,
IN WORD wAttributes)
{
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
Status = NtDeviceIoControlFile(hConsoleOutput,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE,
&wAttributes,
sizeof(USHORT),
NULL,
0);
return NT_SUCCESS(Status);
}
BOOL
WINAPI
SetConsoleOutputCP(
IN UINT wCodepage)
{
HANDLE hConsoleOutput;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
Status = NtDeviceIoControlFile(hConsoleOutput,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_CONSOLE_LOADFONT,
&wCodepage,
sizeof(ULONG),
NULL,
0);
return NT_SUCCESS(Status);
}
/* EOF */