Merge pull request #104 from ArsenArsen/trunk

readline: re-add emacs key support
This commit is contained in:
mint 2021-08-26 00:17:55 +02:00 committed by GitHub
commit 9d8fd54127
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 10 deletions

View File

@ -4,13 +4,14 @@
#include <lib/libc.h>
#include <lib/blib.h>
#include <lib/term.h>
#include <lib/print.h>
#if bios == 1
# include <lib/real.h>
#elif uefi == 1
# include <efi.h>
#endif
int getchar_internal(uint8_t scancode, uint8_t ascii) {
int getchar_internal(uint8_t scancode, uint8_t ascii, uint32_t shift_state) {
switch (scancode) {
#if bios == 1
case 0x44:
@ -66,6 +67,17 @@ int getchar_internal(uint8_t scancode, uint8_t ascii) {
case '\b':
return '\b';
}
if (shift_state & (GETCHAR_LCTRL | GETCHAR_RCTRL)) {
switch (ascii) {
case 'p': return GETCHAR_CURSOR_UP;
case 'n': return GETCHAR_CURSOR_DOWN;
case 'b': return GETCHAR_CURSOR_LEFT;
case 'f': return GETCHAR_CURSOR_RIGHT;
default: break;
}
}
// Guard against non-printable values
if (ascii < 0x20 || ascii > 0x7e) {
return -1;
@ -75,10 +87,26 @@ int getchar_internal(uint8_t scancode, uint8_t ascii) {
#if bios == 1
int getchar(void) {
uint8_t scancode = 0;
uint8_t ascii = 0;
uint32_t mods = 0;
again:;
struct rm_regs r = {0};
rm_int(0x16, &r, &r);
int ret = getchar_internal((r.eax >> 8) & 0xff, r.eax);
scancode = (r.eax >> 8) & 0xff;
ascii = r.eax & 0xff;
r = (struct rm_regs){ 0 };
r.eax = 0x0200; // GET SHIFT FLAGS
rm_int(0x16, &r, &r);
if (r.eax & GETCHAR_LCTRL) {
/* the bios subtracts 0x60 from ascii if ctrl is pressed */
mods = GETCHAR_LCTRL;
ascii += 0x60;
}
int ret = getchar_internal(scancode, ascii, mods);
if (ret == -1)
goto again;
return ret;
@ -92,26 +120,67 @@ int pit_sleep_and_quit_on_keypress(int seconds) {
#endif
#if uefi == 1
static EFI_KEY_DATA _read_efi_key(EFI_HANDLE device) {
EFI_KEY_DATA out = {
/* default to no modifiers */
.KeyState = { 0 },
};
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(device, &exproto_guid, (void **)&exproto) != EFI_SUCCESS) {
if (gBS->HandleProtocol(device, &sproto_guid, (void **)&sproto)
!= EFI_SUCCESS) {
panic("Your input device doesn't have an input protocol!");
}
}
EFI_STATUS status = EFI_UNSUPPORTED;
if (exproto) {
status = exproto->ReadKeyStrokeEx(exproto, &out);
} else {
status = sproto->ReadKeyStroke(sproto, &out.Key);
}
/* 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) {
panic("Failed to read from the keyboard");
}
if (!(out.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID)) {
out.KeyState.KeyShiftState = 0;
}
return out;
}
int getchar(void) {
again:;
EFI_INPUT_KEY key = {0};
EFI_KEY_DATA kd;
UINTN which;
gBS->WaitForEvent(1, (EFI_EVENT[]){ gST->ConIn->WaitForKey }, &which);
gST->ConIn->ReadKeyStroke(gST->ConIn, &key);
kd = _read_efi_key(gST->ConsoleInHandle);
int ret = getchar_internal(key.ScanCode, key.UnicodeChar);
int ret = getchar_internal(kd.Key.ScanCode, kd.Key.UnicodeChar,
kd.KeyState.KeyShiftState);
if (ret == -1)
if (ret == -1) {
goto again;
}
return ret;
}
int pit_sleep_and_quit_on_keypress(int seconds) {
EFI_INPUT_KEY key = {0};
EFI_KEY_DATA kd;
UINTN which;
@ -130,12 +199,14 @@ again:
return 0;
}
gST->ConIn->ReadKeyStroke(gST->ConIn, &key);
kd = _read_efi_key(gST->ConsoleInHandle);
int ret = getchar_internal(key.ScanCode, key.UnicodeChar);
int ret = getchar_internal(kd.Key.ScanCode, kd.Key.UnicodeChar,
kd.KeyState.KeyShiftState);
if (ret == -1)
if (ret == -1) {
goto again;
}
return ret;
}

View File

@ -15,6 +15,14 @@
#define GETCHAR_F10 (-19)
#define GETCHAR_ESCAPE (-20)
#if bios == 1
# define GETCHAR_RCTRL 0x4
# define GETCHAR_LCTRL GETCHAR_RCTRL
#elif uefi == 1
# define GETCHAR_RCTRL EFI_RIGHT_CONTROL_PRESSED
# define GETCHAR_LCTRL EFI_LEFT_CONTROL_PRESSED
#endif
int getchar(void);
void readline(const char *orig_str, char *buf, size_t limit);