/* Copyright (C) 1996,1997 Robert H”hne, see COPYING.RH for details */
/* This file is part of RHIDE. */
#ifdef __DJGPP__

#include <go32.h>
#include <sys/farptr.h>
#include <dpmi.h>
#include <pc.h>
#define REGS __dpmi_regs
#define INTR(nr,r) __dpmi_int(nr,&r)

int use_real_keyboard_bios = 0;
int convert_num_pad = 0;
unsigned short rh_getraw_key();
int rh_kbhit();
unsigned short gkey_shifts_flags;
unsigned char gkey_raw_value;
unsigned short gkey_raw_code;

unsigned short getshiftstate(void)
{
  if (use_real_keyboard_bios)
  {
    REGS r;
    r.h.ah = 0x12;
    INTR(0x16,r);
    return r.x.ax;
  }
  else
    return _farpeekw(_dos_ds,0x417);
}

unsigned short rh_getraw_key()
{
  unsigned short key;
  if (use_real_keyboard_bios)
  {
    REGS r;
    r.h.ah = 0x10;
    INTR(0x16,r);
    key = r.x.ax;
  }
  else
  {
    _farsetsel(_dos_ds);
    unsigned short keybuf_start = _farnspeekw(0x41a);
    key = _farnspeekw(0x400 + keybuf_start);
    keybuf_start += 2;
    if (keybuf_start > 0x3d) keybuf_start = 0x1e;
    _farnspokew(0x41a, keybuf_start);
    // Why is Alt+Backspace different ???
    key = key == 0x0ef0 ? 0x0e00 : key;
    // Why is numpad '5' different ???
    key = key == 0x4cf0 ? 0x4c00 : key;
  }
  gkey_raw_code = key;
  unsigned short sstate = getshiftstate();
  if (convert_num_pad)
  {
#   define K(_x,_y) case _x: key = _y; break;
    switch (key) { // convert the following keys every time
      K(0xE00D,0x1C0D)  // Enter
      K(0xE00A,0x1C0A)  // Ctrl+Enter
      K(0xA600,0x1C00)  // Alt+Enter
      K(0x4E2B,0x1B2B)  // +
      K(0x9000,0x1B1D)  // ^+
      K(0x4E00,0x1B00)  // A+
      K(0x4A2D,0x352D)  // -
      K(0x4A00,0x3500)  // A-
      K(0x3725,0x1B2A)  // *
      K(0x9600,0x1B1D)  // ^*
      K(0xE02F,0x082F)  // /
    }
    if ((sstate & (32 | 3)) == 3) // numlock disabled and shift pressed
    {
      switch (key) { // convert the keys to the function keys, e.g: '0' to ins
        K(0x5230,0x5200)  // ins
        K(0x532E,0x5300)  // del //added by Vik
        K(0x532C,0x5300)  // del
        K(0x4F31,0x4F00)  // end
        K(0x5032,0x5000)  // down
        K(0x5133,0x5100)  // pgdwn
        K(0x4B34,0x4B00)  // left
        K(0x4D36,0x4D00)  // right
        K(0x4737,0x4700)  // home
        K(0x4838,0x4800)  // up
        K(0x4939,0x4900)  // pgup
      }
    }
    else if ((sstate & (32 | 3)) == 32) // numlock enabled and no shift
    {
      switch (key) { // convert the scancodes, when numlock is on
                     // to use the digits, '+', '-', '*', '/', ',' and enter
        K(0x5230,0x0B30)  // 0
        K(0x4F31,0x0231)  // 1
        K(0x5032,0x0332)  // 2
        K(0x5133,0x0433)  // 3
        K(0x4B34,0x0534)  // 4
        K(0x4C35,0x0635)  // 5
        K(0x4D36,0x0736)  // 6
        K(0x4737,0x0837)  // 7
        K(0x4838,0x0938)  // 8
        K(0x4939,0x0A39)  // 9
        K(0x532C,0x332C)  // ,
        K(0x532E,0x342E)  // . //added by Vik
      }
    }
#   undef K
  }
  return key;
}

unsigned short gkey(void)
{
  union
  {
    struct
    {
      unsigned short ax;
    } x;
    struct
    {
      unsigned char al;
      unsigned char ah;
    } h;
  } r;
  r.x.ax = rh_getraw_key();
  gkey_shifts_flags = getshiftstate();
  gkey_raw_value = r.h.ah;
  if (r.h.al == 0xE0 && r.h.ah != 0) r.h.al = 0;
  /* Old translation disabled, and re-enabled only to test if make interference */
#define _shifts_flags gkey_shifts_flags
  switch (r.h.ah)
  {
    case 0x39: if (_shifts_flags & 0x0008) r.x.ax = 0x0200; break; // kbAltSpace
    case 0x92: if ((_shifts_flags & 4) && (_shifts_flags & 3))
                 {
                  r.x.ax = 0x0410;
                  break; // kbCtrlShiftIns
                 }
               if (_shifts_flags & 4)
                  r.h.ah = 0x04;
               break; // kbCtrlIns
    case 0x52: if (_shifts_flags & 0x0003) r.h.ah = 0x05;   break; // kbShiftIns
    case 0x93: if ((_shifts_flags & 0x0004) && (_shifts_flags & 0x0003))
                 {
                  r.x.ax = 0x0610;
                  break; // kbCtrlShiftDel
                 }
               if (_shifts_flags & 0x0004)
                  r.h.ah = 0x06;
               break; // kbCtrlDel
    case 0x53: if (_shifts_flags & 0x0003) r.h.ah = 0x07;   break; // kbShiftDel
  }
  return r.x.ax;
}

int rh_kbhit()
{
  if (use_real_keyboard_bios)
    return kbhit();
  else
    return (_farpeekw(_dos_ds, 0x41a) != _farpeekw(_dos_ds, 0x41c));
}

void clear_keybuf()
{
  if (!use_real_keyboard_bios)
    _farpokel(_dos_ds,0x41A,0x001E001EUL);
  // the bios has no function for clearing the key buffer
}

#endif // __DJGPP__

#ifdef GKEY
#define Uses_TScreen
#define Uses_TKeys
#define Uses_TEventQueue
#include <tv.h>
#include <stdio.h>

extern int use_real_keyboard_bios;
extern int convert_num_pad;
extern unsigned short gkey_raw_code;

static TScreen sc;

int main(int argc, char *argv[])
{
  unsigned short key;
  TEventQueue::resume();
  while (argc > 1)
  {
    if (strcmp(argv[1],"-K") == 0)
    {
      use_real_keyboard_bios = 1;
    }
    else if (strcmp(argv[1],"-p") == 0)
    {
      convert_num_pad = 0;
    }
    argc--;
    argv++;
  }
  do
  {
    while (!rh_kbhit());
    key = gkey();
    fprintf(stderr,"Shiftstate: %04x KeyCode: %04x ScanCode: %02x RawCode: %04x",
        gkey_shifts_flags,key,gkey_raw_value,gkey_raw_code);
   fprintf(stderr,"\r\n");
  } while (key != kbEnter);
  TEventQueue::suspend();
}

#endif // GKEY

