// Copyright 1994 Brad Pitzel
//
// Feel free to use/distribute/modify as long as credit for myself 
// and contributors are included.
//
// Parts of Keyboard.c and Keyboard.h contain code taken from the rawkey
// library written by Russel Marks.

#include "Keyboard.h"

unsigned char Keyboard::hitState[NR_KEYS];
int      Keyboard::delay[NR_KEYS];
int      Keyboard::count[NR_KEYS];
int 	 Keyboard::keymap[NR_KEYS];   // scancode -> ASCII translation
int      Keyboard::asciimap[256];     // ASCII -> scancode translation

//////////////////////////////////////////////////////////////////////////////
int Keyboard::init()
	{
	int i;

	for(i=0; i<NR_KEYS; i++)
		{
		hitState[i]=0;
		delay[i]=0;
		count[i]=0;
		}
	
	if (keyboard_init()<0)
		{
		cerr << "Keyboard:: keyboard_init() failed \n";
		return -1;
		}
		
	make_keyb_map();
	make_ascii_map();
	return 0;	
	}

//////////////////////////////////////////////////////////////////////////////
void Keyboard::update()
	{
	int key,j,k;
	
	keyboard_update();	//svgalib call

	// check for time-outs on all keys	
	for(key=0; key<NR_KEYS; key++)
		{
		if (k=delay[key]) // yes, I want assignment here
		    if (keyboard_keypressed(key))
			{
			j=count[key];
			count[key] = (j+1)%k;

			// reset hitstate if key timed out and still pressed
			if (j==0) 
				hitState[key]=1;
			}
		    else	count[key]=0;
		}
	}

//////////////////////////////////////////////////////////////////////////////
// clear any pending keyhits.
void Keyboard::clearhit()
	{
	int key;
	
	for(key=0; key<NR_KEYS; key++)
		hitState[key]=0;
	}

//////////////////////////////////////////////////////////////////////////////
void Keyboard::setdelay(int key, int ticks)
	{
	if (ticks<0) ticks=0;
	
	if ( (key>0)&(key<NR_KEYS) )
		delay[key]=ticks;	
	}
	

//////////////////////////////////////////////////////////////////////////////
// The rest of this file is code from Russel Marks' rawkey library.
//////////////////////////////////////////////////////////////////////////////

/* it's really easy to translate the scancodes these days, we just
 * use the keytable stuff!
 *
 * returns 0 on error, 1 if ok
 */
int Keyboard::make_keyb_map()
	{
	struct kbentry keyb_ent;
	int f, tty_fd;
	
	if ((tty_fd = open("/dev/console", O_RDONLY)) < 0)
		{
		cerr << "Keyboard::make_keyb_map, cannot open /dev/console.\n";
		return -1;
		}

	keyb_ent.kb_table=0;	/* unshifted */
	for(f=0;f<NR_KEYS;f++)
		{
	 	keyb_ent.kb_index=f;
	  
		if(ioctl(tty_fd,KDGKBENT,(unsigned int)&keyb_ent))
		return(0);
    
		keymap[f]=keyb_ent.kb_value;
		}
	close(tty_fd);
	return(1);
	}

//////////////////////////////////////////////////////////////////////////////
void Keyboard::make_ascii_map()
	{
	int f,i,found;

	for(f=0;f<256;f++)
		{
  		found=0;
  		for(i=0;i<NR_KEYS;i++)
    			if ((KTYP(keymap[i])==KT_LATIN || 
    			     KTYP(keymap[i])==KT_LETTER ||
        		     KTYP(keymap[i])==KT_ASCII) && 
        		     KVAL(keymap[i])==f)
      				{
      				found=1;
      				break;
      				}
      
  		asciimap[f]=found?i:-1;
  		}
	}

//////////////////////////////////////////////////////////////////////////////
/* converts scancode to key binding */
int Keyboard::keymap_trans(int sc)
	{
	if(sc<0 || sc>NR_KEYS) return(-1);
	
	return(keymap[sc]);
	}

/* converts ASCII to scancode */
int Keyboard::scancode_trans(int asc)
	{
	if(asc<0 || asc>255) return(-1);
	
	return(asciimap[asc]);
	}
