Merge pull request #104 from ArsenArsen/trunk
readline: re-add emacs key support
This commit is contained in:
commit
9d8fd54127
@ -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
Block a user