1 /* 2 * Copyright 2007, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT license. 4 * 5 * Author: 6 * François Revol, revol@free.fr. 7 */ 8 9 #include <SupportDefs.h> 10 #include <string.h> 11 #include "rom_calls.h" 12 #include <util/kernel_cpp.h> 13 14 #include "Handle.h" 15 #include "console.h" 16 #include "keyboard.h" 17 18 class ConsoleHandle : public CharHandle { 19 public: 20 ConsoleHandle(); 21 22 virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, 23 size_t bufferSize); 24 virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, 25 size_t bufferSize); 26 27 void Clear(); 28 void MoveTo(int16 x, int16 y); 29 void SetColor(int32 foreground, int32 background); 30 int Columns(); 31 int Rows(); 32 33 private: 34 static int16 fX; 35 static int16 fY; 36 uint16 fPen; 37 }; 38 39 class ConsoleDevice : public ExecDevice { 40 public: 41 ConsoleDevice(const char *title); 42 virtual ~ConsoleDevice(); 43 44 status_t Open(); 45 46 virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize); 47 virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize); 48 49 void Clear(); 50 void MoveTo(int16 x, int16 y); 51 void SetColor(int32 foreground, int32 background); 52 53 int Columns(); 54 int Rows(); 55 56 int WaitForKey(); 57 58 protected: 59 const char *fTitle; 60 struct Window *fWindow; 61 int fRows, fCols; 62 }; 63 64 class KeyboardDevice : public ExecDevice { 65 public: 66 KeyboardDevice(); 67 virtual ~KeyboardDevice(); 68 69 status_t Open(); 70 71 virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize); 72 virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize); 73 74 int WaitForKey(); 75 status_t ReadEvent(struct InputEvent *event); 76 77 protected: 78 }; 79 80 class LLKeyboardDevice : public CharHandle { 81 public: 82 LLKeyboardDevice(); 83 virtual ~LLKeyboardDevice(); 84 85 status_t Open(); 86 87 virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize); 88 virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize); 89 90 int WaitForKey(); 91 92 protected: 93 }; 94 95 96 static const uint16 kPalette[] = { 97 0x000, 98 0x00a, 99 0x0a0, 100 0x0aa, 101 0xa00, 102 0xa0a, 103 0xa50, 104 0xaaa, 105 0x555, 106 0x55f, 107 0x5f5, 108 0x5ff, 109 0xf55, 110 0xf5f, 111 0xff5, 112 0xfff 113 }; 114 115 struct Screen *gScreen; 116 static int16 sFontWidth, sFontHeight; 117 static int sScreenTopOffset = 16; 118 int16 ConsoleHandle::fX = 0; 119 int16 ConsoleHandle::fY = 0; 120 121 FILE *stdin, *stdout, *stderr, *dbgerr; 122 123 124 // #pragma mark - 125 126 ConsoleHandle::ConsoleHandle() 127 : CharHandle() 128 { 129 } 130 131 132 ssize_t 133 ConsoleHandle::ReadAt(void */*cookie*/, off_t /*pos*/, void *buffer, 134 size_t bufferSize) 135 { 136 // don't seek in character devices 137 // not implemented (and not yet? needed) 138 return B_ERROR; 139 } 140 141 142 ssize_t 143 ConsoleHandle::WriteAt(void */*cookie*/, off_t /*pos*/, const void *buffer, 144 size_t bufferSize) 145 { 146 const char *string = (const char *)buffer; 147 size_t i, len; 148 149 // be nice to our audience and replace single "\n" with "\r\n" 150 151 for (i = 0, len = 0; i < bufferSize; i++, len++) { 152 if (string[i] == '\0') 153 break; 154 if (string[i] == '\n') { 155 //Text(&gScreen->RastPort, &string[i - len], len); 156 fX = 0; 157 fY++; 158 if (fY >= console_height()) 159 fY = 0; 160 len = 0; 161 console_set_cursor(fX, fY); 162 continue; 163 } 164 Text(&gScreen->RastPort, &string[i], 1); 165 } 166 167 // not exactly, but we don't care... 168 return bufferSize; 169 } 170 171 172 void 173 ConsoleHandle::Clear() 174 { 175 Move(&gScreen->RastPort, 0, sScreenTopOffset); 176 ClearScreen(&gScreen->RastPort); 177 } 178 179 180 void 181 ConsoleHandle::MoveTo(int16 x, int16 y) 182 { 183 fX = x; 184 fY = y; 185 Move(&gScreen->RastPort, sFontWidth * x, 186 sFontHeight * y + sScreenTopOffset); 187 // why do I have to add this to keep the title ? 188 189 } 190 191 192 void 193 ConsoleHandle::SetColor(int32 foreground, int32 background) 194 { 195 SetAPen(&gScreen->RastPort, foreground); 196 SetBPen(&gScreen->RastPort, background); 197 } 198 199 200 int 201 ConsoleHandle::Columns() 202 { 203 int columnCount = gScreen->Width / sFontWidth; 204 return columnCount; 205 } 206 207 208 int 209 ConsoleHandle::Rows() 210 { 211 int lineCount = (gScreen->Height - sScreenTopOffset) / sFontHeight; 212 return lineCount; 213 } 214 215 216 // #pragma mark - 217 218 219 ConsoleDevice::ConsoleDevice(const char *title) 220 : ExecDevice(), 221 fTitle(title), 222 fWindow(NULL) 223 { 224 } 225 226 227 ConsoleDevice::~ConsoleDevice() 228 { 229 } 230 231 232 status_t 233 ConsoleDevice::Open() 234 { 235 status_t err; 236 237 if (fWindow) 238 return B_ERROR; 239 240 err = AllocRequest(sizeof(struct IOStdReq)); 241 if (err < B_OK) 242 panic("AllocRequest");; 243 if (err < B_OK) 244 return err; 245 246 int16 topEdge = gScreen->Height - 60; 247 int height = 60; 248 249 if (fTitle == NULL) { 250 topEdge = 10; 251 height = gScreen->Height - 40; 252 fTitle = "Console"; 253 } 254 255 struct NewWindow newWindow = { 256 0, topEdge, 257 gScreen->Width, height, 258 BLACK, WHITE, 259 IDCMP_CLOSEWINDOW, 260 WFLG_SIZEGADGET | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_SIMPLE_REFRESH 261 | WFLG_ACTIVATE, 262 NULL, 263 NULL, 264 fTitle, 265 gScreen, 266 NULL, 267 100, 45, 268 gScreen->Width, gScreen->Height, 269 CUSTOMSCREEN 270 }; 271 272 fWindow = OpenWindow(&newWindow); 273 if (fWindow == NULL) 274 panic("OpenWindow");; 275 if (fWindow == NULL) 276 return B_ERROR; 277 fIOStdReq->io_Data = fWindow; 278 fIOStdReq->io_Length = sizeof(struct Window); 279 err = ExecDevice::Open(CONSOLENAME, CONU_STANDARD, 0); 280 if (err < B_OK) 281 return err; 282 283 MoveTo(0, 0); 284 SetColor(WHITE, BLACK); 285 Clear(); 286 } 287 288 289 ssize_t 290 ConsoleDevice::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) 291 { 292 return ExecDevice::ReadAt(cookie, pos, buffer, bufferSize); 293 } 294 295 296 int 297 ConsoleDevice::WaitForKey() 298 { 299 char ascii; 300 301 if (Read(&ascii, 1) < 1) 302 return TEXT_CONSOLE_NO_KEY; 303 //dprintf("ascii %d %c\n", ascii, ascii); 304 305 if (ascii == (char)0x9b) { 306 if (Read(&ascii, 1) < 1) 307 return TEXT_CONSOLE_NO_KEY; 308 //dprintf(">ascii %d %c\n", ascii, ascii); 309 switch (ascii) { 310 case 'A': 311 return TEXT_CONSOLE_KEY_UP; 312 case 'B': 313 return TEXT_CONSOLE_KEY_DOWN; 314 case 'D': 315 return TEXT_CONSOLE_KEY_LEFT; 316 case 'C': 317 return TEXT_CONSOLE_KEY_RIGHT; 318 case '4': 319 { 320 if (Read(&ascii, 1) < 1) 321 return TEXT_CONSOLE_NO_KEY; 322 if (ascii == '~') 323 return TEXT_CONSOLE_NO_KEY; 324 switch (ascii) { 325 case '1': 326 Read(&ascii, 1); // ~ 327 return TEXT_CONSOLE_KEY_PAGE_UP; 328 case '2': 329 Read(&ascii, 1); // ~ 330 return TEXT_CONSOLE_KEY_PAGE_UP; 331 default: 332 return TEXT_CONSOLE_NO_KEY; 333 } 334 return TEXT_CONSOLE_NO_KEY; 335 } 336 default: 337 break; 338 } 339 } 340 return ascii; 341 } 342 343 344 ssize_t 345 ConsoleDevice::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize) 346 { 347 return ExecDevice::WriteAt(cookie, pos, buffer, bufferSize); 348 } 349 350 351 void 352 ConsoleDevice::Clear() 353 { 354 char buff[] = "\x0c"; 355 WriteAt(NULL, 0LL, buff, sizeof(buff) - 1); 356 } 357 358 359 void 360 ConsoleDevice::MoveTo(int16 x, int16 y) 361 { 362 char buff[32]; 363 x = MIN(79,MAX(0,x)); 364 y = MIN(24,MAX(0,y)); 365 sprintf(buff, "\x9b%02d;%02d\x48", y + 1, x + 1); 366 //buff[4] += (char)x; 367 //buff[2] += (char)y; 368 WriteAt(NULL, 0LL, buff, strlen(buff)); 369 } 370 371 372 void 373 ConsoleDevice::SetColor(int32 foreground, int32 background) 374 { 375 //char buff[] = "\x9b37;40m"; 376 char buff[] = "\2330;30;40m"; 377 378 379 if (foreground >= 8) { 380 foreground -= 8; 381 //buff[1] = '1'; // bold 382 } 383 384 // else 385 // buff[1] = '2'; 386 //if (background >= 8) 387 // background -= 8; 388 389 if (foreground == background) { 390 foreground = 7 - background; 391 } 392 393 if (foreground < 8) 394 buff[4] += foreground; 395 396 if (background < 8) 397 buff[7] += background; 398 399 WriteAt(NULL, 0LL, buff, sizeof(buff) - 1); 400 } 401 402 403 int 404 ConsoleDevice::Columns() 405 { 406 struct ConUnit *unit = (struct ConUnit *)fIOStdReq->io_Unit; 407 return unit->cu_XMax; 408 } 409 410 411 int 412 ConsoleDevice::Rows() 413 { 414 struct ConUnit *unit = (struct ConUnit *)fIOStdReq->io_Unit; 415 return unit->cu_YMax - 1; 416 } 417 418 419 // #pragma mark - 420 421 422 KeyboardDevice::KeyboardDevice() 423 : ExecDevice() 424 { 425 } 426 427 428 KeyboardDevice::~KeyboardDevice() 429 { 430 } 431 432 433 status_t 434 KeyboardDevice::Open() 435 { 436 return ExecDevice::Open("keyboard.device"); 437 } 438 439 440 status_t 441 KeyboardDevice::ReadEvent(struct InputEvent *event) 442 { 443 fIOStdReq->io_Command = KBD_READEVENT; 444 fIOStdReq->io_Flags = IOF_QUICK; 445 fIOStdReq->io_Length = sizeof(struct InputEvent); 446 fIOStdReq->io_Data = event; 447 status_t err = Do(); 448 if (err < B_OK) 449 return err; 450 /* 451 dprintf("key: class %d sclass %d code %d 0x%02x qual 0x%04x\n", 452 event->ie_Class, event->ie_SubClass, 453 event->ie_Code, event->ie_Code, event->ie_Qualifier); 454 */ 455 return B_OK; 456 } 457 458 459 ssize_t 460 KeyboardDevice::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) 461 { 462 struct InputEvent event; 463 ssize_t actual; 464 status_t err; 465 466 do { 467 err = ReadEvent(&event); 468 if (err < B_OK) 469 return err; 470 } while (event.ie_Code > IECODE_UP_PREFIX); 471 472 actual = MapRawKey(&event, (char *)buffer, bufferSize, NULL); 473 //dprintf("%s actual %d\n", __FUNCTION__, actual); 474 if (actual > 0) { 475 return actual; 476 } 477 return B_ERROR; 478 } 479 480 481 int 482 KeyboardDevice::WaitForKey() 483 { 484 struct InputEvent event; 485 char ascii; 486 ssize_t actual; 487 status_t err; 488 489 do { 490 err = ReadEvent(&event); 491 if (err < B_OK) 492 return err; 493 } while (event.ie_Code < IECODE_UP_PREFIX); 494 495 event.ie_Code &= ~IECODE_UP_PREFIX; 496 497 switch (event.ie_Code) { 498 case IECODE_KEY_UP: 499 return TEXT_CONSOLE_KEY_UP; 500 case IECODE_KEY_DOWN: 501 return TEXT_CONSOLE_KEY_DOWN; 502 case IECODE_KEY_LEFT: 503 return TEXT_CONSOLE_KEY_LEFT; 504 case IECODE_KEY_RIGHT: 505 return TEXT_CONSOLE_KEY_RIGHT; 506 case IECODE_KEY_PAGE_UP: 507 return TEXT_CONSOLE_KEY_PAGE_UP; 508 case IECODE_KEY_PAGE_DOWN: 509 return TEXT_CONSOLE_KEY_PAGE_DOWN; 510 default: 511 break; 512 } 513 514 actual = MapRawKey(&event, &ascii, 1, NULL); 515 //dprintf("%s actual %d\n", __FUNCTION__, actual); 516 if (actual > 0) 517 return ascii; 518 return TEXT_CONSOLE_NO_KEY; 519 } 520 521 522 ssize_t 523 KeyboardDevice::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize) 524 { 525 return B_ERROR; 526 } 527 528 529 // #pragma mark - 530 531 532 LLKeyboardDevice::LLKeyboardDevice() 533 : CharHandle() 534 { 535 } 536 537 538 LLKeyboardDevice::~LLKeyboardDevice() 539 { 540 } 541 542 543 status_t 544 LLKeyboardDevice::Open() 545 { 546 if (LowLevelBase == NULL) 547 LowLevelBase = (Library *)OldOpenLibrary(LOWLEVELNAME); 548 return (LowLevelBase == NULL) ? B_ERROR : B_OK; 549 } 550 551 552 ssize_t 553 LLKeyboardDevice::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) 554 { 555 struct InputEvent event; 556 ssize_t actual; 557 status_t err; 558 uint32 key; 559 560 561 key = GetKey(); 562 if (key & 0x0000ffff == 0x0ff) 563 return B_ERROR; 564 event.ie_Class = IECLASS_RAWKEY; 565 event.ie_SubClass = IESUBCLASS_RAWKEY; 566 event.ie_Code = (uint16)(key & 0x0000ffff); 567 event.ie_Qualifier = (key & 0xffff0000) >> 16; 568 569 actual = MapRawKey(&event, (char *)buffer, bufferSize, NULL); 570 //dprintf("%s actual %d\n", __FUNCTION__, actual); 571 if (actual > 0) { 572 return actual; 573 } 574 return B_ERROR; 575 } 576 577 578 int 579 LLKeyboardDevice::WaitForKey() 580 { 581 struct InputEvent event; 582 uint32 key; 583 char ascii; 584 ssize_t actual; 585 status_t err; 586 587 do { 588 key = GetKey(); 589 } while (key & 0x0000ffff == 0x0ff); 590 591 event.ie_Class = IECLASS_RAWKEY; 592 event.ie_SubClass = IESUBCLASS_RAWKEY; 593 event.ie_Code = (uint16)(key & 0x0000ffff); 594 event.ie_Qualifier = (key & 0xffff0000) >> 16; 595 596 switch (event.ie_Code) { 597 case IECODE_KEY_UP: 598 return TEXT_CONSOLE_KEY_UP; 599 case IECODE_KEY_DOWN: 600 return TEXT_CONSOLE_KEY_DOWN; 601 case IECODE_KEY_LEFT: 602 return TEXT_CONSOLE_KEY_LEFT; 603 case IECODE_KEY_RIGHT: 604 return TEXT_CONSOLE_KEY_RIGHT; 605 case IECODE_KEY_PAGE_UP: 606 return TEXT_CONSOLE_KEY_PAGE_UP; 607 case IECODE_KEY_PAGE_DOWN: 608 return TEXT_CONSOLE_KEY_PAGE_DOWN; 609 default: 610 break; 611 } 612 613 actual = MapRawKey(&event, &ascii, 1, NULL); 614 //dprintf("%s actual %d\n", __FUNCTION__, actual); 615 if (actual > 0) 616 return ascii; 617 return TEXT_CONSOLE_NO_KEY; 618 } 619 620 621 ssize_t 622 LLKeyboardDevice::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize) 623 { 624 return B_ERROR; 625 } 626 627 628 // #pragma mark - 629 630 631 static ConsoleDevice sOutput(NULL); 632 //static ConsoleHandle sOutput; 633 //static ConsoleHandle sErrorOutput; 634 //static ConsoleHandle sDebugOutput; 635 static ConsoleDevice sDebugOutput("Debug"); 636 637 //static KeyboardDevice sInput; 638 static ConsoleDevice &sInput = sOutput; 639 640 641 status_t 642 console_init(void) 643 { 644 status_t err; 645 646 GRAPHICS_BASE_NAME = (GfxBase *)OldOpenLibrary(GRAPHICSNAME); 647 if (GRAPHICS_BASE_NAME == NULL) 648 panic("Cannot open %s", GRAPHICSNAME); 649 650 static NewScreen newScreen = { 651 0, 0, 652 640, -1, 653 4, 654 BLACK, WHITE, 655 0x8000, 656 0x11, 657 NULL, 658 "Haiku Loader", 659 NULL, 660 NULL 661 }; 662 663 gScreen = OpenScreen(&newScreen); 664 if (gScreen == NULL) 665 panic("OpenScreen()\n"); 666 667 LoadRGB4(&gScreen->ViewPort, kPalette, 16); 668 669 SetDrMd(&gScreen->RastPort, JAM2); 670 671 // seems not necessary, there is a default font already set. 672 /* 673 TextAttr attrs = { "Topaz", 8, 0, 0}; 674 TextFont *font = OpenFont(&attrs); 675 */ 676 TextFont *font = OpenFont(gScreen->Font); 677 if (font == NULL) 678 panic("OpenFont()\n"); 679 sFontHeight = gScreen->Font->ta_YSize; 680 sFontWidth = font->tf_XSize; 681 682 sScreenTopOffset = gScreen->BarHeight * 2; // ??? 683 684 685 //ClearScreen(&gScreen->RastPort); 686 687 688 err = sDebugOutput.Open(); 689 if (err < B_OK) 690 panic("sDebugOutput.Open() 0x%08lx\n", err); 691 dbgerr = stderr = (FILE *)&sDebugOutput; 692 693 694 err = sOutput.Open(); 695 if (err < B_OK) 696 panic("sOutput.Open() 0x%08lx\n", err); 697 698 stdout = (FILE *)&sOutput; 699 700 console_set_cursor(0, 0); 701 702 /* 703 dprintf("LeftEdge %d\n", gScreen->LeftEdge); 704 dprintf("TopEdge %d\n", gScreen->TopEdge); 705 dprintf("Width %d\n", gScreen->Width); 706 dprintf("Height %d\n", gScreen->Height); 707 dprintf("MouseX %d\n", gScreen->MouseX); 708 dprintf("MouseY %d\n", gScreen->MouseY); 709 dprintf("Flags 0x%08x\n", gScreen->Flags); 710 dprintf("BarHeight %d\n", gScreen->BarHeight); 711 dprintf("BarVBorder %d\n", gScreen->BarVBorder); 712 dprintf("BarHBorder %d\n", gScreen->BarHBorder); 713 dprintf("MenuVBorder %d\n", gScreen->MenuVBorder); 714 dprintf("MenuHBorder %d\n", gScreen->MenuHBorder); 715 dprintf("WBorTop %d\n", gScreen->WBorTop); 716 dprintf("WBorLeft %d\n", gScreen->WBorLeft); 717 dprintf("WBorRight %d\n", gScreen->WBorRight); 718 dprintf("WBorBottom %d\n", gScreen->WBorBottom); 719 */ 720 721 KEYMAP_BASE_NAME = (Library *)OldOpenLibrary(KEYMAPNAME); 722 if (KEYMAP_BASE_NAME == NULL) 723 panic("Cannot open %s", KEYMAPNAME); 724 725 726 /* 727 err = sInput.Open(); 728 if (err < B_OK) 729 panic("sInput.Open() 0x%08lx\n", err); 730 */ 731 stdin = (FILE *)&sInput; 732 733 return B_OK; 734 } 735 736 737 // #pragma mark - 738 739 740 void 741 console_clear_screen(void) 742 { 743 sOutput.Clear(); 744 } 745 746 747 int32 748 console_width(void) 749 { 750 return sOutput.Columns(); 751 } 752 753 754 int32 755 console_height(void) 756 { 757 return sOutput.Rows(); 758 } 759 760 761 void 762 console_set_cursor(int32 x, int32 y) 763 { 764 sOutput.MoveTo(x, y); 765 } 766 767 768 void 769 console_set_color(int32 foreground, int32 background) 770 { 771 sOutput.SetColor(foreground, background); 772 } 773 774 775 void 776 console_show_cursor(void) 777 { 778 } 779 780 781 void 782 console_hide_cursor(void) 783 { 784 } 785 786 787 int 788 console_wait_for_key(void) 789 { 790 int key = sInput.WaitForKey(); 791 //dprintf("k: %08x '%c'\n", key, key); 792 return key; 793 } 794 795