#include #include #include #include #include #include #include #if bios == 1 # include #elif uefi == 1 # include #endif int getchar_internal(uint8_t scancode, uint8_t ascii, uint32_t shift_state) { switch (scancode) { #if bios == 1 case 0x44: return GETCHAR_F10; case 0x4b: return GETCHAR_CURSOR_LEFT; case 0x4d: return GETCHAR_CURSOR_RIGHT; case 0x48: return GETCHAR_CURSOR_UP; case 0x50: return GETCHAR_CURSOR_DOWN; case 0x53: return GETCHAR_DELETE; case 0x4f: return GETCHAR_END; case 0x47: return GETCHAR_HOME; case 0x49: return GETCHAR_PGUP; case 0x51: return GETCHAR_PGDOWN; case 0x01: return GETCHAR_ESCAPE; #elif uefi == 1 case SCAN_F10: return GETCHAR_F10; case SCAN_LEFT: return GETCHAR_CURSOR_LEFT; case SCAN_RIGHT: return GETCHAR_CURSOR_RIGHT; case SCAN_UP: return GETCHAR_CURSOR_UP; case SCAN_DOWN: return GETCHAR_CURSOR_DOWN; case SCAN_DELETE: return GETCHAR_DELETE; case SCAN_END: return GETCHAR_END; case SCAN_HOME: return GETCHAR_HOME; case SCAN_PAGE_UP: return GETCHAR_PGUP; case SCAN_PAGE_DOWN: return GETCHAR_PGDOWN; case SCAN_ESC: return GETCHAR_ESCAPE; #endif } switch (ascii) { case '\r': return '\n'; 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; } return 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); 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; } int _pit_sleep_and_quit_on_keypress(uint32_t ticks); int pit_sleep_and_quit_on_keypress(int seconds) { return _pit_sleep_and_quit_on_keypress(seconds * 18); } #endif #if uefi == 1 int getchar(void) { EFI_KEY_DATA kd; UINTN which; EFI_EVENT events[1]; 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; } 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); } 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, kd.KeyState.KeyShiftState); if (ret == -1) { goto again; } return ret; } int pit_sleep_and_quit_on_keypress(int seconds) { EFI_KEY_DATA kd; UINTN which; EFI_EVENT events[2]; 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->SetTimer(events[1], TimerRelative, 10000000 * seconds); again: memset(&kd, 0, sizeof(EFI_KEY_DATA)); gBS->WaitForEvent(2, events, &which); if (which == 1) { return 0; } 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, kd.KeyState.KeyShiftState); if (ret == -1) { goto again; } return ret; } #endif static void reprint_string(int x, int y, const char *s) { size_t orig_x, orig_y; disable_cursor(); get_cursor_pos(&orig_x, &orig_y); set_cursor_pos(x, y); term_write((uintptr_t)s, strlen(s)); set_cursor_pos(orig_x, orig_y); enable_cursor(); } static void cursor_back(void) { size_t x, y; get_cursor_pos(&x, &y); if (x) { x--; } else if (y) { y--; x = term_cols - 1; } set_cursor_pos(x, y); } static void cursor_fwd(void) { size_t x, y; get_cursor_pos(&x, &y); if (x < term_cols - 1) { x++; } else if (y < term_rows - 1) { y++; x = 0; } set_cursor_pos(x, y); } void readline(const char *orig_str, char *buf, size_t limit) { bool prev_autoflush = term_autoflush; term_autoflush = false; size_t orig_str_len = strlen(orig_str); memmove(buf, orig_str, orig_str_len); buf[orig_str_len] = 0; size_t orig_x, orig_y; get_cursor_pos(&orig_x, &orig_y); term_write((uintptr_t)orig_str, orig_str_len); for (size_t i = orig_str_len; ; ) { term_double_buffer_flush(); int c = getchar(); switch (c) { case GETCHAR_CURSOR_LEFT: if (i) { i--; cursor_back(); } continue; case GETCHAR_CURSOR_RIGHT: if (i < strlen(buf)) { i++; cursor_fwd(); } continue; case '\b': if (i) { i--; cursor_back(); case GETCHAR_DELETE:; size_t j; for (j = i; ; j++) { buf[j] = buf[j+1]; if (!buf[j]) { buf[j] = ' '; break; } } reprint_string(orig_x, orig_y, buf); buf[j] = 0; } continue; case '\n': term_write((uintptr_t)"\n", 1); goto out; default: { if (strlen(buf) < limit - 1) { for (size_t j = strlen(buf); ; j--) { buf[j+1] = buf[j]; if (j == i) break; } buf[i] = c; i++; cursor_fwd(); reprint_string(orig_x, orig_y, buf); } } } } out: term_double_buffer_flush(); term_autoflush = prev_autoflush; }