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
ConsoleHandle()126 ConsoleHandle::ConsoleHandle()
127 : CharHandle()
128 {
129 }
130
131
132 ssize_t
ReadAt(void *,off_t,void * buffer,size_t bufferSize)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
WriteAt(void *,off_t,const void * buffer,size_t bufferSize)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
Clear()173 ConsoleHandle::Clear()
174 {
175 Move(&gScreen->RastPort, 0, sScreenTopOffset);
176 ClearScreen(&gScreen->RastPort);
177 }
178
179
180 void
MoveTo(int16 x,int16 y)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
SetColor(int32 foreground,int32 background)193 ConsoleHandle::SetColor(int32 foreground, int32 background)
194 {
195 SetAPen(&gScreen->RastPort, foreground);
196 SetBPen(&gScreen->RastPort, background);
197 }
198
199
200 int
Columns()201 ConsoleHandle::Columns()
202 {
203 int columnCount = gScreen->Width / sFontWidth;
204 return columnCount;
205 }
206
207
208 int
Rows()209 ConsoleHandle::Rows()
210 {
211 int lineCount = (gScreen->Height - sScreenTopOffset) / sFontHeight;
212 return lineCount;
213 }
214
215
216 // #pragma mark -
217
218
ConsoleDevice(const char * title)219 ConsoleDevice::ConsoleDevice(const char *title)
220 : ExecDevice(),
221 fTitle(title),
222 fWindow(NULL)
223 {
224 }
225
226
~ConsoleDevice()227 ConsoleDevice::~ConsoleDevice()
228 {
229 }
230
231
232 status_t
Open()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
ReadAt(void * cookie,off_t pos,void * buffer,size_t bufferSize)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
WaitForKey()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
WriteAt(void * cookie,off_t pos,const void * buffer,size_t bufferSize)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
Clear()352 ConsoleDevice::Clear()
353 {
354 char buff[] = "\x0c";
355 WriteAt(NULL, 0LL, buff, sizeof(buff) - 1);
356 }
357
358
359 void
MoveTo(int16 x,int16 y)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
SetColor(int32 foreground,int32 background)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
Columns()404 ConsoleDevice::Columns()
405 {
406 struct ConUnit *unit = (struct ConUnit *)fIOStdReq->io_Unit;
407 return unit->cu_XMax;
408 }
409
410
411 int
Rows()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
KeyboardDevice()422 KeyboardDevice::KeyboardDevice()
423 : ExecDevice()
424 {
425 }
426
427
~KeyboardDevice()428 KeyboardDevice::~KeyboardDevice()
429 {
430 }
431
432
433 status_t
Open()434 KeyboardDevice::Open()
435 {
436 return ExecDevice::Open("keyboard.device");
437 }
438
439
440 status_t
ReadEvent(struct InputEvent * event)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
ReadAt(void * cookie,off_t pos,void * buffer,size_t bufferSize)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
WaitForKey()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
WriteAt(void * cookie,off_t pos,const void * buffer,size_t bufferSize)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
LLKeyboardDevice()532 LLKeyboardDevice::LLKeyboardDevice()
533 : CharHandle()
534 {
535 }
536
537
~LLKeyboardDevice()538 LLKeyboardDevice::~LLKeyboardDevice()
539 {
540 }
541
542
543 status_t
Open()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
ReadAt(void * cookie,off_t pos,void * buffer,size_t bufferSize)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
WaitForKey()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
WriteAt(void * cookie,off_t pos,const void * buffer,size_t bufferSize)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
console_init(void)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
console_clear_screen(void)741 console_clear_screen(void)
742 {
743 sOutput.Clear();
744 }
745
746
747 int32
console_width(void)748 console_width(void)
749 {
750 return sOutput.Columns();
751 }
752
753
754 int32
console_height(void)755 console_height(void)
756 {
757 return sOutput.Rows();
758 }
759
760
761 void
console_set_cursor(int32 x,int32 y)762 console_set_cursor(int32 x, int32 y)
763 {
764 sOutput.MoveTo(x, y);
765 }
766
767
768 void
console_set_color(int32 foreground,int32 background)769 console_set_color(int32 foreground, int32 background)
770 {
771 sOutput.SetColor(foreground, background);
772 }
773
774
775 void
console_show_cursor(void)776 console_show_cursor(void)
777 {
778 }
779
780
781 void
console_hide_cursor(void)782 console_hide_cursor(void)
783 {
784 }
785
786
787 int
console_wait_for_key(void)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