/* * Copyright 2014-2016 Haiku, Inc. All rights reserved. * Copyright 2013 Fredrik Holmqvist, fredrik.holmqvist@gmail.com. All rights * reserved. * Distributed under the terms of the MIT License. */ #include "console.h" #include #include #include #include #include #include "efi_platform.h" class Console : public ConsoleNode { public: Console(); virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize); virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize); }; static uint32 sScreenWidth; static uint32 sScreenHeight; static uint32 sScreenMode; static Console sInput, sOutput; FILE *stdin, *stdout, *stderr; // #pragma mark - Console::Console() : ConsoleNode() { } ssize_t Console::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) { return B_ERROR; } ssize_t Console::WriteAt(void *cookie, off_t /*pos*/, const void *buffer, size_t bufferSize) { const char *string = (const char *)buffer; char16_t ucsBuffer[bufferSize + 3]; uint32 j = 0; for (uint32 i = 0; i < bufferSize; i++) { switch (string[i]) { case '\n': { ucsBuffer[j++] = '\r'; ucsBuffer[j++] = '\n'; } //fallthrough case 0 : { //Not sure if we should keep going or abort for 0. //Keep going was easy anyway. ucsBuffer[j] = 0; kSystemTable->ConOut->OutputString(kSystemTable->ConOut, ucsBuffer); j = 0; continue; } default: ucsBuffer[j++] = (char16_t)string[i]; } } if (j > 0) { ucsBuffer[j] = 0; kSystemTable->ConOut->OutputString(kSystemTable->ConOut, ucsBuffer); } return bufferSize; } // #pragma mark - void console_clear_screen(void) { kSystemTable->ConOut->ClearScreen(kSystemTable->ConOut); } int32 console_width(void) { return sScreenWidth; } int32 console_height(void) { return sScreenHeight; } void console_set_cursor(int32 x, int32 y) { kSystemTable->ConOut->SetCursorPosition(kSystemTable->ConOut, x, y); } void console_show_cursor(void) { kSystemTable->ConOut->EnableCursor(kSystemTable->ConOut, true); } void console_hide_cursor(void) { kSystemTable->ConOut->EnableCursor(kSystemTable->ConOut, false); } void console_set_color(int32 foreground, int32 background) { kSystemTable->ConOut->SetAttribute(kSystemTable->ConOut, EFI_TEXT_ATTR((foreground & 0xf), (background & 0xf))); } int console_wait_for_key(void) { size_t index; efi_status status; efi_input_key key; efi_event event = kSystemTable->ConIn->WaitForKey; do { kBootServices->WaitForEvent(1, &event, &index); status = kSystemTable->ConIn->ReadKeyStroke(kSystemTable->ConIn, &key); } while (status == EFI_NOT_READY); if (key.UnicodeChar > 0) return (int) key.UnicodeChar; switch (key.ScanCode) { case SCAN_ESC: return TEXT_CONSOLE_KEY_ESCAPE; case SCAN_UP: return TEXT_CONSOLE_KEY_UP; case SCAN_DOWN: return TEXT_CONSOLE_KEY_DOWN; case SCAN_LEFT: return TEXT_CONSOLE_KEY_LEFT; case SCAN_RIGHT: return TEXT_CONSOLE_KEY_RIGHT; case SCAN_PAGE_UP: return TEXT_CONSOLE_KEY_PAGE_UP; case SCAN_PAGE_DOWN: return TEXT_CONSOLE_KEY_PAGE_DOWN; case SCAN_HOME: return TEXT_CONSOLE_KEY_HOME; case SCAN_END: return TEXT_CONSOLE_KEY_END; } return 0; } static void update_screen_size(void) { size_t width, height; size_t area = 0; efi_simple_text_output_protocol *ConOut = kSystemTable->ConOut; for (int mode = 0; mode < ConOut->Mode->MaxMode; ++mode) { if (ConOut->QueryMode(ConOut, mode, &width, &height) == EFI_SUCCESS) { if (width * height > area) { sScreenWidth = width; sScreenHeight = height; sScreenMode = mode; } } } ConOut->SetMode(ConOut, sScreenMode); } status_t console_init(void) { update_screen_size(); console_hide_cursor(); console_clear_screen(); // enable stdio functionality stdin = (FILE *)&sInput; stdout = stderr = (FILE *)&sOutput; return B_OK; } uint32 console_check_boot_keys(void) { efi_status status; efi_input_key key; // give the user a chance to press a key kBootServices->Stall(500000); status = kSystemTable->ConIn->ReadKeyStroke(kSystemTable->ConIn, &key); if (status != EFI_SUCCESS) return 0; if (key.UnicodeChar == 0 && key.ScanCode == SCAN_ESC) return BOOT_OPTION_DEBUG_OUTPUT; if (key.UnicodeChar == ' ') return BOOT_OPTION_MENU; return 0; } extern "C" void platform_switch_to_text_mode(void) { kSystemTable->ConOut->Reset(kSystemTable->ConOut, false); kSystemTable->ConOut->SetMode(kSystemTable->ConOut, sScreenMode); }