/*
 * DOS interrupt 09h handler (IRQ1 - KEYBOARD)
 */

#include <stdlib.h>
#include <string.h>
#include "winuser.h"
#include "miscemu.h"
#include "input.h"
#include "debugtools.h"
#include "dosexe.h"

DEFAULT_DEBUG_CHANNEL(int)

typedef struct {
  BYTE queuelen,queue[15];
} KBDSYSTEM;

/**********************************************************************
 *	    INT_Int09Handler
 *
 * Handler for int 09h.
 */
void WINAPI INT_Int09Handler( CONTEXT86 *context )
{
  BYTE scan = INT_Int09ReadScan();
  UINT vkey = MapVirtualKeyA(scan&0x7f, 1);
  BYTE ch[2];
  int cnt;

  if (!(scan & 0x80)) {
    /* as in TranslateMessage, windows/input.c */
    cnt = ToAscii(vkey, scan&0x7f, QueueKeyStateTable, (LPWORD)ch, 0);
    if (cnt==1) {
      FIXME("enter character %c into console input, not implemented\n",ch[0]);
    }
  }
  DOSVM_PIC_ioport_out(0x20, 0x20); /* send EOI */
}

static void KbdRelay( LPDOSTASK lpDosTask, CONTEXT86 *context, void *data )
{
  KBDSYSTEM *sys = (KBDSYSTEM *)DOSVM_GetSystemData(0x09);

  if (sys && sys->queuelen) {
    /* cleanup operation, called from DOSVM_PIC_ioport_out:
     * we'll remove current scancode from keyboard buffer here,
     * rather than in ReadScan, because some DOS apps depend on
     * the scancode being available for reading multiple times... */
    if (--sys->queuelen)
      memmove(sys->queue,sys->queue+1,sys->queuelen);
  }
}

void WINAPI INT_Int09SendScan( BYTE scan )
{
  KBDSYSTEM *sys = (KBDSYSTEM *)DOSVM_GetSystemData(0x09);
  if (!sys) {
    sys = calloc(1,sizeof(KBDSYSTEM));
    DOSVM_SetSystemData(0x09,sys);
  }
  /* add scancode to queue */
  sys->queue[sys->queuelen++] = scan;
  /* tell app to read it by triggering IRQ 1 (int 09) */
  DOSVM_QueueEvent(1,DOS_PRIORITY_KEYBOARD,KbdRelay,NULL);
}

BYTE WINAPI INT_Int09ReadScan( void )
{
  KBDSYSTEM *sys = (KBDSYSTEM *)DOSVM_GetSystemData(0x09);
  if (sys)
    return sys->queue[0];
  else
    return 0;
}
