#include <windows.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>

#if 0
typedef struct _INPUT_RECORD { // ir
    WORD EventType;
    union {
        KEY_EVENT_RECORD KeyEvent;
        MOUSE_EVENT_RECORD MouseEvent;
        WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
        MENU_EVENT_RECORD MenuEvent;
        FOCUS_EVENT_RECORD FocusEvent;
    } Event;
} INPUT_RECORD;
typedef struct _KEY_EVENT_RECORD {
    BOOL bKeyDown;
    WORD wRepeatCount;
    WORD wVirtualKeyCode;
    WORD wVirtualScanCode;
    union {
        WCHAR UnicodeChar;
        CHAR  AsciiChar;
    } uChar;
    DWORD dwControlKeyState;
} KEY_EVENT_RECORD;

typedef struct _MOUSE_EVENT_RECORD {
    COORD dwMousePosition;
    DWORD dwButtonState;
    DWORD dwControlKeyState;
    DWORD dwEventFlags;
} MOUSE_EVENT_RECORD;


#endif

/*
 * dwControlKeyState
 * 
 * Indicates the state of the control keys. This member can be a
 * combination of the following values:
 * 
 * CAPSLOCK_ON        The CAPS LOCK light is on.
 * ENHANCED_KEY       The key is enhanced.
 * LEFT_ALT_PRESSED   The left ALT key is pressed.
 * LEFT_CTRL_PRESSED  The left CTRL key is pressed.
 * NUMLOCK_ON         The NUM LOCK light is on.
 * RIGHT_ALT_PRESSED  The right ALT key is pressed.
 * RIGHT_CTRL_PRESSED The right CTRL key is pressed.
 * SCROLLLOCK_ON      The SCROLL LOCK light is on.
 * SHIFT_PRESSED      The SHIFT key is pressed.
 * 
 * Enhanced keys for the IBM 101/102 keyboards are the INS, DEL, HOME,
 * END, PAGE UP, PAGE DOWN, and direction keys in the clusters to the
 * left of the keypad; and the DIVIDE and ENTER keys in the keypad.
 */
#if 0
#define CAPSLOCK_ON     128
#define ENHANCED_KEY    256
#define LEFT_ALT_PRESSED        2
#define LEFT_CTRL_PRESSED       8
#define NUMLOCK_ON      32
#define RIGHT_ALT_PRESSED       1
#define RIGHT_CTRL_PRESSED      4
#define SCROLLLOCK_ON   64
#define SHIFT_PRESSED   16
#endif

#define ALT_PRESSED (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
#define CTRL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
#define IsKey(x) ((keystate & x) != 0)

long assemble(c,scancode,keystate) int c,scancode; long keystate;{
long X,Y;
  Y=(scancode & 255)+256*c;
  X=(keystate & 0x0000FFFF)       /* nine (9) bits */
    +Y*256*256;
  return X;
}

char *display(k) long k;{
unsigned char k1,k2,k3,k4;
char *p;
static char buf[64];
 p=(char *)&buf[0];
 k1=k;
 k2=k/256;
 k3=(k/256)/256;
 k4=((k/256)/256)/256;
 sprintf(p,"%03d %03d %03o.%03o",k4,k3,k2,k1);
 return p;
}

void translate(k,p) long k; char *p; {
unsigned char k1,k2,k3,k4;
unsigned short x;
 x=k;                   /* modifiers */
 k3=(k/256)/256;        /* keycode */
 k4=((k/256)/256)/256;  /* c */
/* 
RIGHT_ALT_PRESSED       1
LEFT_ALT_PRESSED        2
RIGHT_CTRL_PRESSED      4
LEFT_CTRL_PRESSED       8
SHIFT_PRESSED          16
NUMLOCK_ON             32
SCROLLLOCK_ON          64
CAPSLOCK_ON           128
ENHANCED_KEY          256
*/

p[0]=0;
if((x&(RIGHT_ALT_PRESSED +LEFT_ALT_PRESSED))!=0) strcat(p,"ALT ");
if((x&(RIGHT_CTRL_PRESSED+LEFT_CTRL_PRESSED))!=0) strcat(p,"CTRL ");
if((x&SHIFT_PRESSED)!=0 && (x&CAPSLOCK_ON)==0) strcat(p,"Shift ");
if((x&SHIFT_PRESSED)==0 && (x&CAPSLOCK_ON)!=0) strcat(p,"Shift ");
sprintf(p+strlen(p),"Ascii=%03d[%c], Scan=%03d",k4,(isprint(k4)?k4:'#'),k3);
}

void keybanger(){
int c;
HANDLE hStdin,hStdout;
INPUT_RECORD Buffer;
PINPUT_RECORD Buf= &Buffer;
long NumRead;
COORD mp;
char s[256];

    hStdout=GetStdHandle(STD_OUTPUT_HANDLE);
    hStdin=GetStdHandle(STD_INPUT_HANDLE);
    SetConsoleMode(hStdin,0 /*ENABLE_MOUSE_INPUT*/); /* noecho, no ctrl-c */
    /* ReadConsoleInput waits for an event. Ctrl-C is not passed through
       unless ENABLE_PROCESSED_INPUT has been turned off */
    while(1){
    int result,scancode; long keystate; char *p;
      result=ReadConsoleInput(hStdin,Buf,(DWORD)1,(LPDWORD)&NumRead);
      if(result==0) {printf("Got zero. Likely running illegally in XFree86.\n");exit(1);}
        if(Buffer.EventType==KEY_EVENT){
          c=Buffer.Event.KeyEvent.uChar.AsciiChar;
          scancode=Buffer.Event.KeyEvent.wVirtualKeyCode;
          keystate=Buffer.Event.KeyEvent.dwControlKeyState;
          if(Buffer.Event.KeyEvent.bKeyDown==0){
            p=display(keystate);
            printf("Key = %02d, scan=%02d, keystate=%s\n",c,scancode,p);
            p=display(assemble(c,scancode,keystate));
            printf("assembled keystate=%s\n",p);
            translate(assemble(c,scancode,keystate),s);
            printf("%s\n",s);
            if(c == 'Q' || c == 'q') break;
            if(c == 3) printf("Use Q or q to quit\n");
          }
      }
    } /* end while(1) */

    printf("All done with keybanger\n");
}

/* Once stdout has been redefined to point to the current console, */
/* then all printf output goes to that console.                    */

SECURITY_ATTRIBUTES sec_none;
void launchconsole(){
#if 0
int hCrt; FILE *hf; long hStdout,hStdin;
  FreeConsole();
  AllocConsole();            /* Open a console window */
  hStdout=(long)GetStdHandle(STD_OUTPUT_HANDLE);
  hCrt= _open_osfhandle(hStdout,_O_TEXT); /* Get file descriptor */
  hf= fdopen(hCrt,"w" ); /* Get Ansi-C handle for file descriptor*/
  *stdout = *hf;            /* Change stdout to this one */
  setvbuf( stdout, NULL, _IONBF, 0 ); /* no buffering */
  hStdin=(long)GetStdHandle(STD_INPUT_HANDLE);
  hCrt= _open_osfhandle(hStdin,_O_TEXT); /* Get file descriptor */
  hf= fdopen(hCrt,"r" ); /* Get Ansi-C handle for file descriptor*/
  *stdin = *hf;            /* Change stdout to this one */
  setvbuf( stdin, NULL, _IONBF, 0 ); /* no buffering */
#endif
}

int main(void){
  (void)launchconsole();
  (void)keybanger();
  return 0; // C runtime cleans up the file opens
}
