You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
495 lines
11 KiB
495 lines
11 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
input.c
|
|
|
|
Author:
|
|
|
|
Ken Reneris Oct-2-1997
|
|
|
|
Abstract:
|
|
|
|
--*/
|
|
|
|
#if defined (_IA64_)
|
|
#include "bootia64.h"
|
|
#endif
|
|
|
|
#if defined (_X86_)
|
|
#include "bldrx86.h"
|
|
#endif
|
|
|
|
#include "displayp.h"
|
|
#include "stdio.h"
|
|
|
|
#include "efi.h"
|
|
#include "efip.h"
|
|
#include "flop.h"
|
|
|
|
#include "bootefi.h"
|
|
|
|
//
|
|
// Externals
|
|
//
|
|
extern BOOT_CONTEXT BootContext;
|
|
extern EFI_HANDLE EfiImageHandle;
|
|
extern EFI_SYSTEM_TABLE *EfiST;
|
|
extern EFI_BOOT_SERVICES *EfiBS;
|
|
extern EFI_RUNTIME_SERVICES *EfiRS;
|
|
extern EFI_GUID EfiDevicePathProtocol;
|
|
extern EFI_GUID EfiBlockIoProtocol;
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
ULONGLONG InputTimeout = 0;
|
|
|
|
|
|
//
|
|
// Takes any pending input and converts it into a KEY value. Non-blocking, returning 0 if no input available.
|
|
//
|
|
ULONG
|
|
BlGetKey()
|
|
{
|
|
ULONG Key = 0;
|
|
UCHAR Ch;
|
|
ULONG Count;
|
|
|
|
if (ArcGetReadStatus(BlConsoleInDeviceId) == ESUCCESS) {
|
|
|
|
ArcRead(BlConsoleInDeviceId, &Ch, sizeof(Ch), &Count);
|
|
|
|
if (Ch == ASCI_CSI_IN) {
|
|
|
|
if (ArcGetReadStatus(BlConsoleInDeviceId) == ESUCCESS) {
|
|
|
|
ArcRead(BlConsoleInDeviceId, &Ch, sizeof(Ch), &Count);
|
|
|
|
//
|
|
// All the function keys start with ESC-O
|
|
//
|
|
switch (Ch) {
|
|
case 'O':
|
|
|
|
ArcRead(BlConsoleInDeviceId, &Ch, sizeof(Ch), &Count); // will not or block, as the buffer is already filled
|
|
|
|
switch (Ch) {
|
|
case 'P':
|
|
Key = F1_KEY;
|
|
break;
|
|
|
|
case 'Q':
|
|
Key = F2_KEY;
|
|
break;
|
|
|
|
case 'w':
|
|
Key = F3_KEY;
|
|
break;
|
|
|
|
case 'x':
|
|
Key = F4_KEY;
|
|
break;
|
|
|
|
case 't':
|
|
Key = F5_KEY;
|
|
break;
|
|
|
|
case 'u':
|
|
Key = F6_KEY;
|
|
break;
|
|
|
|
case 'r':
|
|
Key = F8_KEY;
|
|
break;
|
|
|
|
case 'M':
|
|
Key = F10_KEY;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 'A':
|
|
Key = UP_ARROW;
|
|
break;
|
|
|
|
case 'B':
|
|
Key = DOWN_ARROW;
|
|
break;
|
|
|
|
case 'C':
|
|
Key = RIGHT_KEY;
|
|
break;
|
|
|
|
case 'D':
|
|
Key = LEFT_KEY;
|
|
break;
|
|
|
|
case 'H':
|
|
Key = HOME_KEY;
|
|
break;
|
|
|
|
case 'K':
|
|
Key = END_KEY;
|
|
break;
|
|
|
|
case '@':
|
|
Key = INS_KEY;
|
|
break;
|
|
|
|
case 'P':
|
|
Key = DEL_KEY;
|
|
break;
|
|
|
|
case TAB_KEY:
|
|
Key = BACKTAB_KEY;
|
|
break;
|
|
|
|
}
|
|
|
|
} else { // Single escape key, as no input is waiting.
|
|
|
|
Key = ESCAPE_KEY;
|
|
|
|
}
|
|
|
|
} else if (Ch == 0x8) {
|
|
|
|
Key = BKSP_KEY;
|
|
|
|
} else {
|
|
|
|
Key = (ULONG)Ch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Key;
|
|
}
|
|
|
|
|
|
VOID
|
|
BlInputString(
|
|
IN ULONG Prompt,
|
|
IN ULONG CursorX,
|
|
IN ULONG PosY,
|
|
IN PUCHAR String,
|
|
IN ULONG MaxLength
|
|
)
|
|
{
|
|
PTCHAR PromptString;
|
|
ULONG TextX, TextY;
|
|
ULONG Length, Index;
|
|
_TUCHAR CursorChar[2];
|
|
ULONG Key;
|
|
_PTUCHAR p;
|
|
ULONG i;
|
|
ULONG Count;
|
|
_PTUCHAR pString;
|
|
#ifdef UNICODE
|
|
WCHAR StringW[200];
|
|
UNICODE_STRING uString;
|
|
ANSI_STRING aString;
|
|
pString = StringW;
|
|
uString.Buffer = StringW;
|
|
uString.MaximumLength = sizeof(StringW);
|
|
RtlInitAnsiString(&aString, (PCHAR)String );
|
|
RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
|
|
#else
|
|
pString = String;
|
|
#endif
|
|
|
|
|
|
PromptString = BlFindMessage(Prompt);
|
|
Length = (ULONG)strlen((PCHAR)String);
|
|
CursorChar[1] = TEXT('\0');
|
|
|
|
//
|
|
// Print prompt
|
|
//
|
|
|
|
BlEfiPositionCursor( PosY, CursorX );
|
|
BlEfiEnableCursor( TRUE );
|
|
ArcWrite(BlConsoleOutDeviceId, PromptString, (ULONG)_tcslen(PromptString)*sizeof(TCHAR), &Count);
|
|
|
|
//
|
|
// Indent cursor to right of prompt
|
|
//
|
|
|
|
CursorX += (ULONG)_tcslen(PromptString);
|
|
TextX = CursorX;
|
|
Key = 0;
|
|
|
|
for (; ;) {
|
|
|
|
TextY = TextX + Length;
|
|
if (CursorX > TextY) {
|
|
CursorX = TextY;
|
|
}
|
|
if (CursorX < TextX) {
|
|
CursorX = TextX;
|
|
}
|
|
|
|
Index = CursorX - TextX;
|
|
pString[Length] = 0;
|
|
|
|
//
|
|
// Display current string
|
|
//
|
|
|
|
BlEfiPositionCursor( TextY, TextX );
|
|
ArcWrite(
|
|
BlConsoleOutDeviceId,
|
|
pString,
|
|
(ULONG)_tcslen(pString)*sizeof(TCHAR),
|
|
&Count);
|
|
ArcWrite(BlConsoleOutDeviceId, TEXT(" "), sizeof(TEXT(" ")), &Count);
|
|
if (Key == 0x0d) { // enter key?
|
|
break ;
|
|
}
|
|
|
|
//
|
|
// Display cursor
|
|
//
|
|
BlEfiPositionCursor( PosY, CursorX );
|
|
BlEfiSetInverseMode( TRUE );
|
|
CursorChar[0] = pString[Index] ? pString[Index] : TEXT(' ');
|
|
ArcWrite(BlConsoleOutDeviceId, CursorChar, sizeof(_TUCHAR), &Count);
|
|
BlEfiSetInverseMode( FALSE );
|
|
BlEfiPositionCursor( PosY, CursorX );
|
|
BlEfiEnableCursor(TRUE);
|
|
|
|
//
|
|
// Get key and process it
|
|
//
|
|
|
|
while ((Key = BlGetKey()) == 0) ;
|
|
|
|
switch (Key) {
|
|
case HOME_KEY:
|
|
CursorX = TextX;
|
|
break;
|
|
|
|
case END_KEY:
|
|
CursorX = TextY;
|
|
break;
|
|
|
|
case LEFT_KEY:
|
|
CursorX -= 1;
|
|
break;
|
|
|
|
case RIGHT_KEY:
|
|
CursorX += 1;
|
|
break;
|
|
|
|
case BKSP_KEY:
|
|
if (!Index) {
|
|
break;
|
|
}
|
|
|
|
CursorX -= 1;
|
|
pString[Index-1] = CursorChar[0];
|
|
// fallthough to DEL_KEY
|
|
case DEL_KEY:
|
|
if (Length) {
|
|
p = pString+Index;
|
|
i = Length-Index+1;
|
|
while (i) {
|
|
p[0] = p[1];
|
|
p += 1;
|
|
i -= 1;
|
|
}
|
|
Length -= 1;
|
|
}
|
|
break;
|
|
|
|
case INS_KEY:
|
|
if (Length < MaxLength) {
|
|
p = pString+Length;
|
|
i = Length-Index+1;
|
|
while (i) {
|
|
p[1] = p[0];
|
|
p -= 1;
|
|
i -= 1;
|
|
}
|
|
pString[Index] = TEXT(' ');
|
|
Length += 1;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Key = Key & 0xff;
|
|
|
|
if (Key >= ' ' && Key <= 'z') {
|
|
if (CursorX == TextY && Length < MaxLength) {
|
|
Length += 1;
|
|
}
|
|
|
|
pString[Index] = (_TUCHAR)Key;
|
|
pString[MaxLength] = 0;
|
|
CursorX += 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
ULONGLONG
|
|
BlSetInputTimeout(
|
|
ULONGLONG Timeout
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the InputTimeout value. This is used
|
|
when getting local input. When attempting
|
|
to get local input, we will wait for up
|
|
to InputTimeout for a local key to be
|
|
pressed.
|
|
|
|
Arguments:
|
|
|
|
Timeout - Value to set the global InputTimeout to
|
|
(in 100 nanoseconds)
|
|
|
|
Return Value:
|
|
|
|
The value stored in InputTimeout
|
|
|
|
--*/
|
|
{
|
|
InputTimeout = Timeout;
|
|
|
|
return InputTimeout;
|
|
}
|
|
|
|
|
|
ULONGLONG
|
|
BlGetInputTimeout(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets the InputTimeout value. This is used
|
|
when getting local input. When attempting
|
|
to get local input, we will wait for up
|
|
to InputTimeout for a local key to be
|
|
pressed.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
The value stored in InputTimeout
|
|
|
|
--*/
|
|
{
|
|
return InputTimeout;
|
|
}
|
|
|
|
EFI_STATUS
|
|
BlWaitForInput(
|
|
EFI_INPUT_KEY *Key,
|
|
ULONGLONG Timeout
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
creates an event consisting of a time interval
|
|
and an efi event (local input). Once event
|
|
is signaled, will check for input
|
|
|
|
Assumes it is being called in PHYSICAL mode
|
|
|
|
Arguments:
|
|
|
|
Key - input key structure to return
|
|
input in
|
|
Timeout - Timer interval to wait.
|
|
|
|
Return Value:
|
|
|
|
EFI_TIMEOUT if timer interval met
|
|
EFI_SUCCESS if passed in event is met.
|
|
other error if EFI call failed.
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
|
|
//
|
|
// start by seeing if there is any pending input
|
|
//
|
|
Status = EfiST->ConIn->ReadKeyStroke(EfiST->ConIn,
|
|
Key
|
|
);
|
|
if (Status == EFI_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// create events to wait on
|
|
//
|
|
if (Timeout) {
|
|
EFI_EVENT Event;
|
|
EFI_EVENT TimerEvent;
|
|
EFI_EVENT WaitList[2];
|
|
UINTN Index;
|
|
|
|
Event = EfiST->ConIn->WaitForKey;
|
|
|
|
//
|
|
// Create a timer event
|
|
//
|
|
|
|
Status = EfiBS->CreateEvent(EVT_TIMER, 0, NULL, NULL, &TimerEvent);
|
|
if (Status == EFI_SUCCESS) {
|
|
//
|
|
// set the timer event
|
|
//
|
|
EfiBS->SetTimer(TimerEvent,
|
|
TimerRelative,
|
|
Timeout
|
|
);
|
|
|
|
//
|
|
// Wait for the original event or timer
|
|
//
|
|
WaitList[0] = Event;
|
|
WaitList[1] = TimerEvent;
|
|
Status = EfiBS->WaitForEvent(2,
|
|
WaitList,
|
|
&Index
|
|
);
|
|
EfiBS->CloseEvent(TimerEvent);
|
|
|
|
//
|
|
// if the timer expired, change the return to timed out
|
|
//
|
|
if(Status == EFI_SUCCESS && Index == 1) {
|
|
Status = EFI_TIMEOUT;
|
|
}
|
|
|
|
//
|
|
// attempt to read local input
|
|
//
|
|
if (Status == EFI_SUCCESS) {
|
|
Status = EfiST->ConIn->ReadKeyStroke(EfiST->ConIn,
|
|
Key
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|