/*
    exDOS - Experimental 32 Bit protected mode scripted operating system
    (C) 2005 Jason Hunt
    
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    Contact: nulluser@gmail.com
    
    File: keyboard.c
*/

#include "types.h"
#include "stdio.h"
#include "video.h"
#include "system.h"

#define key_buff_size   512                     // Size of keyboard buffer

volatile byte keyboard_buffer[key_buff_size];   // Keyboard queue
volatile word key_head = 0;                     // Head index
volatile word key_tail = 0;                     // Tail index
volatile word num_keys_down = 0;                // Number of keys down
volatile word key_intr_count = 0;               // Keyboard interrupt counter

// Keyboard states
byte shift_down =   0;


/* Index is a scan code, value at index is the key */
byte key_table_normal[] = { 
   //  0   1    2   3   4   5   6   7    8   9   a   b   c   d   e   f
        0,0x1b,'1','2','3','4','5','6', '7','8','9','0', '-', '=',  8,  0,  // 00-0f
       'q','w','e','r','t','y','u','i', 'o','p','[',']',0xa,  0,'a','s',  // 10-1f
       'd','f','g','h','j','k','l',';','\'',  0,  0,  0,'z','x','c','v',  // 20-2f
       'b','n','m',',','.','/',  0,  0,   0, ' ', 0,  0,  0,  0,  0,  0,  // 30-3f
         0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,  // 40-4f
         0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,  // 50-5f
         0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,  // 60-6f
         0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0 };// 70-7f

byte key_table_shift[] = { 
   //  0   1    2   3   4   5   6   7    8   9   a   b   c   d   e   f
        0,0x1b,'!','@','#','$','%','^','&','*','(',')','_','+',  8,  0,  // 00-0f
      'Q', 'W','E','R','T','Y','U','I','O','P','{','}',0xa,  0,'A','S',  // 10-1f
      'D', 'F','G','H','J','K','L',':','"',  0,  0,  0,'Z','X','C','V',  // 20-2f
      'B', 'N','M','<','>','?',  0,  0,  0,' ',  0,  0,  0,  0,  0,  0,  // 30-3f
        0,   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 40-4f
        0,   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 50-5f
        0,   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 60-6f
        0,   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0}; // 70-7f



/* C language keyboard interrupt */
void key_intr( void )
{
    byte c;

    key_intr_count++;

    while ((in_byte(0x64) & 0x01) == 0);                // Wait for char
    
    c = in_byte(0x60);                                  // Get the scan code

    if (c == 0x2a || c == 0x36) shift_down = 1;         // Shift press
    if (c == 0xaa || c == 0xb6) shift_down = 0;         // Shift release
            
    if (!(c & 0x80))                                    // Check for key down
    {
        c &= 0x7f;                                      // Mask to linit to table size

        if (shift_down)                                 // Determine which table to use
           c = key_table_shift[c];                      // and convert to char
        else
           c = key_table_normal[c];

        // Add the key to the queue
        if (num_keys_down < key_buff_size)
        {
            keyboard_buffer[key_tail++] = c;

            // Check for wrap around
            if (key_tail >= key_buff_size)
                key_tail -= key_buff_size;

            num_keys_down++;
        }        
    }    
}
/* End of keyboard_intr */


/* Returns true if a key is down */
byte key_hit( void )
{
    return (num_keys_down);        
}
/* End of key_hit */


/* Wait for a keyboard char and return it */
char key_get_char()
{
    byte c;
    
    while(num_keys_down == 0);      // Wait for keypress

    c = keyboard_buffer[key_head++];

    // Check for wrap around
    if (key_head >= key_buff_size)
        key_head -= key_buff_size;

    num_keys_down--;


    return(c);
}
/* End of get char */


/* Get a line of input */
void key_get_line(char *l, byte max)
{
    byte start_x, start_y;
    byte c;    

    byte x_pos;

    vga_get_cursor(&start_x, &start_y);

    x_pos = start_x;

    if (max == 0)
    {
        *l = 0;
        return;
    }       

    max--;  // Make room for null

    while (max)
    {
        c = getchar();

        if (c == '\n') max = 0; else    // New line
        if (c == 0x08)                  // Backspace
        {
            if (x_pos > start_x)
            {
                --x_pos;                        // Erase last char
                vga_set_cursor(x_pos, start_y);
                putchar(' ');       
                vga_set_cursor(x_pos, start_y);                
                vga_update_cursor();
                l--;                            // Delete plast char
                max++;                          // One more position left
            }    
        }
        else        
        if (c >= 0x20)                          // Printable?
        {         
            *l++ = c;                           // Add to the string
            putchar(c);                         // Echo
            max--;                              // Reduce positions left
            x_pos++;
        }       
    }     
    
    *l = 0;                                     // Null terminate
    
    putchar('\n');                      
}        
/* End of get_line */



