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
18class 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
39class 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
64class 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
80class 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
96static 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
115struct Screen *gScreen;
116static int16 sFontWidth, sFontHeight;
117static int sScreenTopOffset = 16;
118int16 ConsoleHandle::fX = 0;
119int16 ConsoleHandle::fY = 0;
120
121FILE *stdin, *stdout, *stderr, *dbgerr;
122
123
124//	#pragma mark -
125
126ConsoleHandle::ConsoleHandle()
127	: CharHandle()
128{
129}
130
131
132ssize_t
133ConsoleHandle::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
142ssize_t
143ConsoleHandle::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
172void
173ConsoleHandle::Clear()
174{
175	Move(&gScreen->RastPort, 0, sScreenTopOffset);
176	ClearScreen(&gScreen->RastPort);
177}
178
179
180void
181ConsoleHandle::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
192void
193ConsoleHandle::SetColor(int32 foreground, int32 background)
194{
195	SetAPen(&gScreen->RastPort, foreground);
196	SetBPen(&gScreen->RastPort, background);
197}
198
199
200int
201ConsoleHandle::Columns()
202{
203	int columnCount = gScreen->Width / sFontWidth;
204	return columnCount;
205}
206
207
208int
209ConsoleHandle::Rows()
210{
211	int lineCount = (gScreen->Height - sScreenTopOffset) / sFontHeight;
212	return lineCount;
213}
214
215
216// #pragma mark -
217
218
219ConsoleDevice::ConsoleDevice(const char *title)
220	: ExecDevice(),
221	fTitle(title),
222	fWindow(NULL)
223{
224}
225
226
227ConsoleDevice::~ConsoleDevice()
228{
229}
230
231
232status_t
233ConsoleDevice::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
289ssize_t
290ConsoleDevice::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
291{
292	return ExecDevice::ReadAt(cookie, pos, buffer, bufferSize);
293}
294
295
296int
297ConsoleDevice::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
344ssize_t
345ConsoleDevice::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
346{
347	return ExecDevice::WriteAt(cookie, pos, buffer, bufferSize);
348}
349
350
351void
352ConsoleDevice::Clear()
353{
354	char buff[] = "\x0c";
355	WriteAt(NULL, 0LL, buff, sizeof(buff) - 1);
356}
357
358
359void
360ConsoleDevice::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
372void
373ConsoleDevice::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
403int
404ConsoleDevice::Columns()
405{
406	struct ConUnit *unit = (struct ConUnit *)fIOStdReq->io_Unit;
407	return unit->cu_XMax;
408}
409
410
411int
412ConsoleDevice::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
422KeyboardDevice::KeyboardDevice()
423	: ExecDevice()
424{
425}
426
427
428KeyboardDevice::~KeyboardDevice()
429{
430}
431
432
433status_t
434KeyboardDevice::Open()
435{
436	return ExecDevice::Open("keyboard.device");
437}
438
439
440status_t
441KeyboardDevice::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
459ssize_t
460KeyboardDevice::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
481int
482KeyboardDevice::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
522ssize_t
523KeyboardDevice::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
532LLKeyboardDevice::LLKeyboardDevice()
533	: CharHandle()
534{
535}
536
537
538LLKeyboardDevice::~LLKeyboardDevice()
539{
540}
541
542
543status_t
544LLKeyboardDevice::Open()
545{
546	if (LowLevelBase == NULL)
547		LowLevelBase = (Library *)OldOpenLibrary(LOWLEVELNAME);
548	return (LowLevelBase == NULL) ? B_ERROR : B_OK;
549}
550
551
552ssize_t
553LLKeyboardDevice::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
578int
579LLKeyboardDevice::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
621ssize_t
622LLKeyboardDevice::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
631static ConsoleDevice sOutput(NULL);
632//static ConsoleHandle sOutput;
633//static ConsoleHandle sErrorOutput;
634//static ConsoleHandle sDebugOutput;
635static ConsoleDevice sDebugOutput("Debug");
636
637//static KeyboardDevice sInput;
638static ConsoleDevice &sInput = sOutput;
639
640
641status_t
642console_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
740void
741console_clear_screen(void)
742{
743	sOutput.Clear();
744}
745
746
747int32
748console_width(void)
749{
750	return sOutput.Columns();
751}
752
753
754int32
755console_height(void)
756{
757	return sOutput.Rows();
758}
759
760
761void
762console_set_cursor(int32 x, int32 y)
763{
764	sOutput.MoveTo(x, y);
765}
766
767
768void
769console_set_color(int32 foreground, int32 background)
770{
771	sOutput.SetColor(foreground, background);
772}
773
774
775void
776console_show_cursor(void)
777{
778}
779
780
781void
782console_hide_cursor(void)
783{
784}
785
786
787int
788console_wait_for_key(void)
789{
790	int key = sInput.WaitForKey();
791	//dprintf("k: %08x '%c'\n", key, key);
792	return key;
793}
794
795