readline: re-add emacs key support
This time, we properly check shift flags from both the firmware options, as to not lead to conflicts with existing code. The logic for checking whether Ctrl is being held is also a lot cleaner now.
This commit is contained in:
parent
31f52c2b30
commit
50dcc58a77
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue