/*
	Keyboard handler for GCC - version 0.65
	Made by Ismo Horppu on 1996 - 1997
	
	NOTE:
	- pause won't work because 0xE1 special keyboard codes not supported
*/

#include <dpmi.h>
#include <stdio.h>
#include <pc.h>
#include <go32.h>
#include <dos.h>
#include "types.h"
#include "timer.h"
#include "ct2kb.h"

void enter_keyname (int key_slot, char *name)
{
	keynames[key_slot] = name;
}

void namekey (char *name)
{
	keynames[xkey_slot] = name;
	xkey_slot++;
}

void setkeynames (void)
{
	xkey_slot = 0;

	/*
		name the normal keys
	*/
	namekey (NULL);
	namekey ("ESC");
	namekey ("1");
	namekey ("2");
	namekey ("3");
	namekey ("4");
	namekey ("5");
	namekey ("6");
	namekey ("7");
	namekey ("8");
	namekey ("9");
	namekey ("0");
	namekey ("MINUS");
	namekey ("EQUAL");
	namekey ("BACKSPACE");
	namekey ("TAB");
	namekey ("Q");
	namekey ("W");
	namekey ("E");
	namekey ("R");
	namekey ("T");
	namekey ("Y");
	namekey ("U");
	namekey ("I");
	namekey ("O");
	namekey ("P");
	namekey ("OPENBRACE");
	namekey ("CLOSEBRACE");
	namekey ("ENTER");
	namekey ("LEFTCONTROL");
	namekey ("A");
	namekey ("S");
	namekey ("D");
	namekey ("F");
	namekey ("G");
	namekey ("H");
	namekey ("J");
	namekey ("K");
	namekey ("L");
	namekey ("COLON");
	namekey ("QUOTE");
	namekey ("BACKQUOTE");
	namekey ("LEFTSHIFT");
	namekey ("BACKSLASH");
	namekey ("Z");
	namekey ("X");
	namekey ("C"),
	namekey ("V"),
	namekey ("B"),
	namekey ("N"),
	namekey ("M"),
	namekey ("COMMA");
	namekey ("PERIOD");
	namekey ("SLASH");
	namekey ("RIGHTSHIFT");
	namekey ("PAD_MULTIPLY");
	namekey ("LEFTALT");
	namekey ("SPACE");
	namekey ("CAPSLOCK");
	namekey ("F1");
	namekey ("F2");
	namekey ("F3");
	namekey ("F4");
	namekey ("F5");
	namekey ("F6");
	namekey ("F7");
	namekey ("F8");
	namekey ("F9");
	namekey ("F10");
	namekey ("NUMLOCK");
	namekey ("SCRLOCK");
	namekey ("PAD 7");
	namekey ("PAD 8");
	namekey ("PAD 9");
	namekey ("PAD MINUS");
	namekey ("PAD 4");
	namekey ("PAD 5");
	namekey ("PAD 6");
	namekey ("PAD PLUS");
	namekey ("PAD 1");
	namekey ("PAD 2");
	namekey ("PAD 3");
	namekey ("PAD 0");
	namekey ("PAD PERIOD");
	namekey ("LAST CONSOLE");
	namekey (NULL);
	namekey ("LESS");
	namekey ("F11");
	namekey ("F12");

	/*
		name the extended keys
	*/
	enter_keyname (0x9D, "RIGHTCONTROL");
	enter_keyname (0xB8, "RIGHTALT");
	enter_keyname (0xB5, "PAD_DIVIDE");
	enter_keyname (0x9C, "PAD_ENTER");
	enter_keyname (0xAA, "PRINTSCRN");
	enter_keyname (0xC5, "PAUSE");

	/*
		name missing known keys
	*/

	// arrow keys
	enter_keyname (0xCB, "LEFTARROW");
	enter_keyname (0xCD, "RIGHTARROW");
	enter_keyname (0xC8, "UPARROW");
	enter_keyname (0xD0, "DOWNARROW");

	// 6 special keys
	enter_keyname (0xD2, "INSERT");
	enter_keyname (0xC7, "HOME");
	enter_keyname (0xC9, "PAGEUP");
	enter_keyname (0xD3, "DELETE");
	enter_keyname (0xCF, "END");
	enter_keyname (0xD1, "PAGEDOWN");

	/*
		name the win95 keyboard extended keys
	*/
	enter_keyname (0xDD, "RIGHTMENU");
	enter_keyname (0xDC, "RIGHTWINFLAG");
	enter_keyname (0xDB, "LEFTWINFLAG");
}

/*	
	keyboard handler routine
*/
void kb_handler ()
{
	inb = inportb (0x60);

	if (inb != 0xFF){

		// special
		if (inb >= 0xE0){
			more = inb - 0xE0 + 1;	// count of add. IRQs 
		}

		//0xE1, 0x1D, 0x45
		else{
			// normal key
			if (more == 0){
				keytable[inb & 127] = inb & 128;
			}

			// extended key
			else{
				if (more == 1){
					keytable[(inb & 127) + 128] = inb & 128;
					more = 0;
				}

				else{
					more--;
				}
			}
		}
	}
	
	outportb (0x20, 0x20);
}

void Set_Keyboard ()
{
	int c;
	
	for (c = 0; c < KEY_ENTRIES; c++){
		keytable[c] = UNPRESSED;
	}

	setkeynames ();
	same = 0;
	
	asm ("cli");
	_go32_dpmi_lock_code (kb_handler, (DWORD) (Set_Keyboard - kb_handler));
	_go32_dpmi_lock_data (&keytable[0], KEY_ENTRIES * 4);
	_go32_dpmi_lock_data (&inb, 4);
	_go32_dpmi_lock_data (&more, 4);
	
	// realmode init (interrupt)
	_go32_dpmi_get_real_mode_interrupt_vector (INTR, &old_vector);
	info.pm_offset = (DWORD) kb_handler;
	
	_go32_dpmi_allocate_real_mode_callback_iret (&info, &regs);
	_go32_dpmi_set_real_mode_interrupt_vector (INTR, &info);
	
	// pmode init irq
	_go32_dpmi_get_protected_mode_interrupt_vector (INTR, &pmode_old_handler);
	pmode_new_handler.pm_offset = (DWORD) kb_handler;
	pmode_new_handler.pm_selector = _go32_my_cs ();

	// chain our handler 
	_go32_dpmi_chain_protected_mode_interrupt_vector (INTR, &pmode_new_handler);
	asm ("sti");
}

void Restore_Keyboard (void)
{
	asm ("cli");
	_go32_dpmi_set_real_mode_interrupt_vector (INTR, &old_vector);
//	_go32_dpmi_free_real_mode_callback (&info);
	_go32_dpmi_set_protected_mode_interrupt_vector (INTR, &pmode_old_handler);
	asm ("sti");
}

void ResetKB (void)
{
	int c;
	int kbc;

	kbc = 0;

	while (1){
		if (keytable[kbc] != UNPRESSED){
			kbc = 0;
		}

		kbc++;
		if (kbc >= KEY_ENTRIES) break;
	}

	for (c = 0; c < KEY_ENTRIES; c++){
		keytable[c] = UNPRESSED;
	}
}

/*	
	sets repeat time in ms (1000 = 1 sec = 1 char / sec)
	DO NOT CALL THIS FUNCTION UNLESS YOU ARE 100%
	SURE WHAT YOU DO 
*/
void SetRepeat (WORD new_first_repeat, WORD new_next_repeat)
{
	if (new_first_repeat >= 1000){
		first_repeat = 1000;
	}
	
	else{
		first_repeat = new_first_repeat;
	}
	
	if (new_next_repeat >= 1000){
		next_repeat = 1000;
	}
	
	else{
		next_repeat = new_next_repeat;
	}
}

/*	
	simple getkey type routine
*/
BYTE xgetkey (void)
{
	int c = 0;
	int key = -1;
	
	while (1){
		if (keytable[c] == PRESSED) c = 0;
		c++;
		if (c >= KEY_ENTRIES) break;
	}
	
	while (1){
		for (c = 0; c < KEY_ENTRIES; c++){
			if (keytable[c] == PRESSED) key = c;
		}
		
		if (key != -1) break;
	}
	
	//delay (NEXT_DEFAULT);
	xdelay (next_repeat);
	return key;
}

BYTE ygetkey (void)
{
	int c = 0;
	int key = 0;
	
	for (c = 0; c < KEY_ENTRIES; c++){
		if (keytable[c] == PRESSED) key = c;
	}
	
	if (key != oldkb){
		xdelay (next_repeat);
	}
	
	else{
		xdelay (next_repeat);
	}
	
	oldkb = key;
	//delay (NEXT_DEFAULT);
	return key;
}

BYTE zgetkey (void)
{
	int c = 0;
	int key = -1;
	
	// wait until no keys pressed
	while (1){
		if (keytable[c] == PRESSED) c = 0;
		c++;
		if (c >= KEY_ENTRIES) break;
	}
	
	while (1){
		for (c = 0; c < KEY_ENTRIES; c++){
			if (keytable[c] == PRESSED) key = c;
		}
		
		if (key != -1) break;
	}
	
	return key;
}


/*
	getkey type routine
*/
BYTE WaitKB (void)
{
	int c = 0;
	BYTE pkey;
	
	while (1){
		if (keytable[c] == 0){
			pkey = c;
			
			while (1){
				if (keytable[c] == 0){
					pkey = c;
				}
			
				c++;
				
				if (c >= KEY_ENTRIES){
					// here is the new repeat code :)

					if (pkey == oldkey){
						same++;
						
						if (same == 1){
							xdelay (first_repeat);
						}
						
						else{
							xdelay (next_repeat);
						}
						
						/*
							continue next
						*/
						if (same == 255){
							same = 3;
						}
				
						if (keytable[pkey] == 0){
							/*
							delay_ticks = 0;
							delay_start = 0;*/
							return pkey;
						}
						
						c = 0;
						
					}

					else{
						same = 0;
						oldkey = pkey;
						return pkey;
					}
				}
			}
		}

		c++;

		if (c >= KEY_ENTRIES){
			c = 0;
		}
	}

	return pkey;
}

int no_key (void)
{
	int c;
	
	for (c = 0; c < KEY_ENTRIES; c++){
		if (keytable[c] == PRESSED) return 0;
	}
	
	return 1;
}