// this file has been taken from WinUAE's sources and slightly modified
// to fulfil my needs
#include <windows.h>

#include "inputevent.h"
#include "keyboard.h"

extern void SendEvent( char Class, short Code, short Qual, short MX, short MY );

static char keystate[ AK_RCTRL + 1 ];


static int getcapslock( void )
{
    BYTE keyState[256];

    GetKeyboardState( keyState );

	return( keyState[ VK_CAPITAL ] & 1 );
}

inline int getrwin( void )
{
	return(( GetAsyncKeyState( VK_RWIN ) & 0x8000 ) ? TRUE : FALSE );
}

inline int getlwin( void )
{
	return(( GetAsyncKeyState( VK_LWIN ) & 0x8000 ) ? TRUE : FALSE );
}

static char getascii( UINT vk, UINT scancode )
{
    BYTE	keyState[256];
    char	buffer[2];
    int		result;

    GetKeyboardState( keyState );

    result = ToAscii( vk, scancode, keyState, (LPWORD)buffer, 0 );

    if( result == 1 )
        result = buffer[0];

    return( result );
}

/* there's a problem remaining with the semantics of the '#' key on U.S. keyboards */
static int scancode2amiga( int keycode, int scancode )
{
	switch( keycode & 0xff ) {

		case VK_INSERT:			return AK_LAMI;
		case VK_HOME:			return AK_RAMI;
     
		case VK_MENU:			return(( scancode & KF_EXTENDED ) ? AK_RALT : AK_LALT );
     
		case VK_APPS:			return AK_RALT;

		case VK_SCROLL:			return( -2 );
		case VK_PRIOR:			return( -3 );
		case VK_F12:			return( -5 );
		case VK_CAPITAL:		return( -4 );

		case VK_DECIMAL:		return AK_NPDEL;
		case VK_DIVIDE:			return AK_NPDIV;
		case VK_MULTIPLY:		return AK_NPMUL;
		case VK_SUBTRACT:		return AK_NPSUB;
		case VK_ADD:			return AK_NPADD;
		case VK_NUMPAD0:		return AK_NP0;
		case VK_NUMPAD1:		return AK_NP1;
		case VK_NUMPAD2:        return AK_NP2;
		case VK_NUMPAD3:        return AK_NP3;
		case VK_NUMPAD4:        return AK_NP4;
		case VK_NUMPAD5:        return AK_NP5;
		case VK_NUMPAD6:        return AK_NP6;
		case VK_NUMPAD7:        return AK_NP7;
		case VK_NUMPAD8:        return AK_NP8;
		case VK_NUMPAD9:        return AK_NP9;
		case VK_UP:				return AK_UP;
		case VK_DOWN:			return AK_DN;
		case VK_LEFT:			return AK_LF;
		case VK_RIGHT:			return AK_RT;
		case VK_CONTROL:		return(( scancode & KF_EXTENDED ) ? AK_RCTRL : AK_CTRL );
		case VK_RETURN:			return(( scancode & KF_EXTENDED ) ? AK_ENT : AK_RET );	
		case VK_F1:				return AK_F1;
		case VK_F2:				return AK_F2;
		case VK_F3:				return AK_F3;
		case VK_F4:				return AK_F4;
		case VK_F5:				return AK_F5;
		case VK_F6:				return AK_F6;
		case VK_F7:				return AK_F7;
		case VK_F8:				return AK_F8;
		case VK_F9:				return AK_F9;
		case VK_F10:			return AK_F10;
		case VK_HELP:
		case VK_PAUSE:
		case VK_NEXT:			return AK_HELP;
    }

    switch( scancode ) {
		case 0x01:	return AK_ESC;
		case 0x29:	return AK_BACKQUOTE;
		case 0x02:	return AK_1;
		case 0x03:	return AK_2;
		case 0x04:	return AK_3;
		case 0x05:	return AK_4;
		case 0x06:	return AK_5;
		case 0x07:	return AK_6;
		case 0x08:	return AK_7;
		case 0x09:	return AK_8;
		case 0x0a:	return AK_9;
		case 0x0b:	return AK_0;
		case 0x0c:	return AK_MINUS;
		case 0x0d:	return AK_EQUAL;
		case 0x57:  return AK_BACKSLASH; /* This is F11 */ 
		case 0x0e:	return AK_BS;
		case 0x0f:	return AK_TAB;
		case 0x10:	return AK_Q;
		case 0x11:	return AK_W;
		case 0x12:	return AK_E;
		case 0x13:	return AK_R;
		case 0x14:	return AK_T;
		case 0x15:	return AK_Y;
		case 0x16:	return AK_U;
		case 0x17:	return AK_I;
		case 0x18:	return AK_O;
		case 0x19:	return AK_P;
		case 0x1a:	return AK_LBRACKET;
		case 0x1b:	return AK_RBRACKET;
		case 0x3a:	return AK_CAPSLOCK;
		case 0x1e:	return AK_A;
		case 0x1f:	return AK_S;
		case 0x20:	return AK_D;
		case 0x21:	return AK_F;
		case 0x22:	return AK_G;
		case 0x23:	return AK_H;
		case 0x24:	return AK_J;
		case 0x25:	return AK_K;
		case 0x26:	return AK_L;
		case 0x27:	return AK_SEMICOLON;
		case 0x28:	return AK_QUOTE;
		case 0x2b: /* This scancode is \ on US keyboards, but # on German ones - figure out which! */
			switch( getascii( keycode & 0xFF, scancode )) {
				
				case '\\':
					return AK_BACKSLASH;

				default:
					return AK_NUMBERSIGN;
			}
		case 0x2a:	return AK_LSH;
		case 0x56:	return AK_LTGT;
		case 0x2c:	return AK_Z;
		case 0x2d:	return AK_X;
		case 0x2e:	return AK_C;
		case 0x2f:	return AK_V;
		case 0x30:	return AK_B;
		case 0x31:	return AK_N;
		case 0x32:	return AK_M;
		case 0x33:	return AK_COMMA;
		case 0x34:	return AK_PERIOD;
		case 0x35:	return AK_SLASH;
		case 0x36:	return AK_RSH;
		case 0x38:	return AK_LALT;
		case 0x39:	return AK_SPC;
		case 0x153:	return AK_DEL;
		case 0x51:	return AK_HELP;
//		case 0x52:	return AK_LAMI;
//		case 0x47:	return AK_RAMI;
		case 0x4b:	return AK_LF;
		case 0x50:	return AK_DN;
		case 0x4d:	return AK_RT;
		case 0x48:	return AK_UP;
		case 0x4e:	return AK_NPADD;
		case 0x4a:	return AK_NPSUB;
		case 0x37:	return AK_NPMUL;
    }

    return( -1 );
}

int my_kbd_handler( int keycode, int scancode, int newstate, int repeat )
{
    int akey = scancode2amiga( keycode, scancode );

	switch( akey ) {

		case -3:
			if( !newstate )
				SendEvent( IECLASS_RAWMOUSE, IECODE_MBUTTON, 0, 0, 0 );
			return( FALSE );


		case -4:
			if( newstate ) {
				akey     = AK_CAPSLOCK;
				newstate = getcapslock();
			}
			break;

		case -5:
			return( TRUE );

		default:
			if( newstate && ( akey >= -17 ) && ( akey <= -10 ))
				akey = -10 - akey;
			break;
	}

	if( akey >= 0 ) {
		unsigned short qual = 0;

		if( newstate && keystate[ akey ] )
			qual |= IEQUALIFIER_REPEAT;

		keystate[ akey ] = newstate;

		if( !newstate )
			akey |= IECODE_UP_PREFIX;

		while( repeat-- > 0 )
			SendEvent( IECLASS_RAWKEY, akey, qual, 0, 0 );
	}

	return( FALSE );
}

unsigned short GetQualifiers( void )
{
	unsigned short qual = 0;

	if( keystate[ AK_CAPSLOCK ] )
		qual |= IEQUALIFIER_CAPSLOCK;

	if( keystate[ AK_LSH ] )
		qual |= IEQUALIFIER_LSHIFT;

	if( keystate[ AK_RSH ] )
		qual |= IEQUALIFIER_RSHIFT;

	if( keystate[ AK_LALT ] )
		qual |= IEQUALIFIER_LALT;

	if( keystate[ AK_RALT ] )
		qual |= IEQUALIFIER_RALT;

	if( keystate[ AK_LAMI ] || getlwin() )
		qual |= IEQUALIFIER_LCOMMAND;

	if( keystate[ AK_RAMI ] || getrwin() )
		qual |= IEQUALIFIER_RCOMMAND;

	if( keystate[ AK_CTRL ] || keystate[ AK_RCTRL ] )
		qual |= IEQUALIFIER_CONTROL;

	return( qual );
}

void InitKeyboard( void )
{
	memset( keystate, 0, sizeof( keystate ));

	keystate[ AK_CAPSLOCK ] = getcapslock();
}