readline: UEFI: getchar() rework

This commit is contained in:
mintsuki 2021-08-26 18:22:09 +02:00
parent 3d6a1db420
commit 0af1cdb72a

View File

@ -120,55 +120,48 @@ int pit_sleep_and_quit_on_keypress(int seconds) {
#endif #endif
#if uefi == 1 #if uefi == 1
static EFI_KEY_DATA _read_efi_key(EFI_HANDLE device) { int getchar(void) {
EFI_KEY_DATA out = { EFI_KEY_DATA kd;
/* default to no modifiers */
.KeyState = { 0 }, UINTN which;
};
EFI_EVENT events[1];
EFI_GUID exproto_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID; EFI_GUID exproto_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
EFI_GUID sproto_guid = EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID; EFI_GUID sproto_guid = EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *exproto = NULL; EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *exproto = NULL;
EFI_SIMPLE_TEXT_IN_PROTOCOL *sproto = NULL; EFI_SIMPLE_TEXT_IN_PROTOCOL *sproto = NULL;
if (gBS->HandleProtocol(device, &exproto_guid, (void **)&exproto) != EFI_SUCCESS) { if (gBS->HandleProtocol(gST->ConsoleInHandle, &exproto_guid, (void **)&exproto) != EFI_SUCCESS) {
if (gBS->HandleProtocol(device, &sproto_guid, (void **)&sproto) if (gBS->HandleProtocol(gST->ConsoleInHandle, &sproto_guid, (void **)&sproto) != EFI_SUCCESS) {
!= EFI_SUCCESS) {
panic("Your input device doesn't have an input protocol!"); panic("Your input device doesn't have an input protocol!");
} }
}
EFI_STATUS status = EFI_UNSUPPORTED; events[0] = sproto->WaitForKey;
if (exproto) {
status = exproto->ReadKeyStrokeEx(exproto, &out);
} else { } else {
status = sproto->ReadKeyStroke(sproto, &out.Key); events[0] = exproto->WaitForKeyEx;
}
again:
memset(&kd, 0, sizeof(EFI_KEY_DATA));
gBS->WaitForEvent(1, events, &which);
EFI_STATUS status;
if (events[0] == sproto->WaitForKey) {
status = sproto->ReadKeyStroke(sproto, &kd.Key);
} else {
status = exproto->ReadKeyStrokeEx(exproto, &kd);
} }
/* there is definitely a key pending here, if there isn't, there's
* something very wrong, as the caller should be waiting on a key.
*/
if (status != EFI_SUCCESS) { if (status != EFI_SUCCESS) {
panic("Failed to read from the keyboard"); goto again;
} }
if (!(out.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID)) { if ((kd.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) == 0) {
out.KeyState.KeyShiftState = 0; kd.KeyState.KeyShiftState = 0;
} }
return out;
}
int getchar(void) {
again:;
EFI_KEY_DATA kd;
UINTN which;
gBS->WaitForEvent(1, (EFI_EVENT[]){ gST->ConIn->WaitForKey }, &which);
kd = _read_efi_key(gST->ConsoleInHandle);
int ret = getchar_internal(kd.Key.ScanCode, kd.Key.UnicodeChar, int ret = getchar_internal(kd.Key.ScanCode, kd.Key.UnicodeChar,
kd.KeyState.KeyShiftState); kd.KeyState.KeyShiftState);
@ -186,20 +179,48 @@ int pit_sleep_and_quit_on_keypress(int seconds) {
EFI_EVENT events[2]; EFI_EVENT events[2];
events[0] = gST->ConIn->WaitForKey; EFI_GUID exproto_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
EFI_GUID sproto_guid = EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *exproto = NULL;
EFI_SIMPLE_TEXT_IN_PROTOCOL *sproto = NULL;
if (gBS->HandleProtocol(gST->ConsoleInHandle, &exproto_guid, (void **)&exproto) != EFI_SUCCESS) {
if (gBS->HandleProtocol(gST->ConsoleInHandle, &sproto_guid, (void **)&sproto) != EFI_SUCCESS) {
panic("Your input device doesn't have an input protocol!");
}
events[0] = sproto->WaitForKey;
} else {
events[0] = exproto->WaitForKeyEx;
}
gBS->CreateEvent(EVT_TIMER, TPL_CALLBACK, NULL, NULL, &events[1]); gBS->CreateEvent(EVT_TIMER, TPL_CALLBACK, NULL, NULL, &events[1]);
gBS->SetTimer(events[1], TimerRelative, 10000000 * seconds); gBS->SetTimer(events[1], TimerRelative, 10000000 * seconds);
again: again:
memset(&kd, 0, sizeof(EFI_KEY_DATA));
gBS->WaitForEvent(2, events, &which); gBS->WaitForEvent(2, events, &which);
if (which == 1) { if (which == 1) {
return 0; return 0;
} }
kd = _read_efi_key(gST->ConsoleInHandle); EFI_STATUS status;
if (events[0] == sproto->WaitForKey) {
status = sproto->ReadKeyStroke(sproto, &kd.Key);
} else {
status = exproto->ReadKeyStrokeEx(exproto, &kd);
}
if (status != EFI_SUCCESS) {
goto again;
}
if ((kd.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) == 0) {
kd.KeyState.KeyShiftState = 0;
}
int ret = getchar_internal(kd.Key.ScanCode, kd.Key.UnicodeChar, int ret = getchar_internal(kd.Key.ScanCode, kd.Key.UnicodeChar,
kd.KeyState.KeyShiftState); kd.KeyState.KeyShiftState);