/* FCE Ultra - NES/Famicom Emulator
 *
 * Copyright notice for this file:
 *  Copyright (C) 2002 Xodnizel
 *
 * 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
 */

#include "common.h"
#include <dinput.h>

#include "input.h"
#include "keyboard.h"

static HRESULT  ddrval; //mbg merge 7/17/06 made static

static LPDIRECTINPUTDEVICE7 lpdid=0;

void KeyboardClose(void)
{
 if(lpdid) IDirectInputDevice7_Unacquire(lpdid);
 lpdid=0;
}

static unsigned char keys[256] = {0,}; // with repeat
static unsigned char keys_nr[256] = {0,}; // non-repeating
static unsigned char keys_jd[256] = {0,}; // just-down
static unsigned char keys_jd_lock[256] = {0,}; // just-down released lock
int autoHoldKey = 0, autoHoldClearKey = 0;
void KeyboardUpdateState(void)
{
 unsigned char tk[256];

 ddrval=IDirectInputDevice7_GetDeviceState(lpdid,256,tk);

 // HACK because DirectInput is totally wacky about recognizing the PAUSE/BREAK key
 if(GetAsyncKeyState(VK_PAUSE)) // normally this should have & 0x8000, but apparently this key is too special for that to work
	 tk[0xC5] = 0x80;

 switch(ddrval)
 {
	case DI_OK: //memcpy(keys,tk,256);break;
	{
		extern int soundoptions;
		#define SO_OLDUP      32

		extern int soundo;
		extern int32 fps_scale;
		int notAlternateThrottle = !(soundoptions&SO_OLDUP) && soundo && ((NoWaiting&1)?(256*16):fps_scale) >= 64;
		#define KEY_REPEAT_INITIAL_DELAY ((!notAlternateThrottle) ? (16) : (64)) // must be >= 0 and <= 255
		#define KEY_REPEAT_REPEATING_DELAY (6) // must be >= 1 and <= 255
		#define KEY_JUST_DOWN_DURATION (4) // must be >= 1 and <= 255

		int i;
		for(i = 0 ; i < 256 ; i++)
			if(tk[i])
				if(keys_nr[i] < 255)
					keys_nr[i]++; // activate key, and count up for repeat
				else
					keys_nr[i] = 255 - KEY_REPEAT_REPEATING_DELAY; // oscillate for repeat
			else
				keys_nr[i] = 0; // deactivate key

		memcpy(keys,keys_nr,256);

		// key-down detection
		for(i = 0 ; i < 256 ; i++)
			if(!keys_nr[i])
			{
				keys_jd[i] = 0;
				keys_jd_lock[i] = 0;
			}
			else if(keys_jd_lock[i])
			{}
			else if(keys_jd[i]
			/*&& (i != 0x2A && i != 0x36 && i != 0x1D && i != 0x38)*/)
			{
				if(++keys_jd[i] > KEY_JUST_DOWN_DURATION)
				{
					keys_jd[i] = 0;
					keys_jd_lock[i] = 1;
				}
			}
			else
				keys_jd[i] = 1;

		// key repeat
		for(i = 0 ; i < 256 ; i++)
			if(keys[i] >= KEY_REPEAT_INITIAL_DELAY && !(keys[i]%KEY_REPEAT_REPEATING_DELAY))
				keys[i] = 0;
	}	   
	break;


   case DIERR_INPUTLOST:
   case DIERR_NOTACQUIRED:
                         memset(keys,0,256);
                         IDirectInputDevice7_Acquire(lpdid);
                         break;
  }

  extern uint8 autoHoldOn, autoHoldReset;
  autoHoldOn = autoHoldKey && keys[autoHoldKey] != 0;
  autoHoldReset = autoHoldClearKey && keys[autoHoldClearKey] != 0;
}

unsigned char *GetKeyboard(void)
{
 return(keys);
}
unsigned char *GetKeyboard_nr(void)
{
 return(keys_nr);
}
unsigned char *GetKeyboard_jd(void)
{
 return(keys_jd);
}

int KeyboardInitialize(void)
{
 if(lpdid)
  return(1);

 //mbg merge 7/17/06 changed:
 ddrval=IDirectInput7_CreateDeviceEx(lpDI, GUID_SysKeyboard,IID_IDirectInputDevice7, (LPVOID *)&lpdid,0);
 //ddrval=IDirectInput7_CreateDeviceEx(lpDI, &GUID_SysKeyboard,&IID_IDirectInputDevice7, (LPVOID *)&lpdid,0);
 if(ddrval != DI_OK)
 {
  FCEUD_PrintError("DirectInput: Error creating keyboard device.");
  return 0;
 }

 ddrval=IDirectInputDevice7_SetCooperativeLevel(lpdid, hAppWnd,DISCL_FOREGROUND|DISCL_NONEXCLUSIVE);
 if(ddrval != DI_OK)
 {
  FCEUD_PrintError("DirectInput: Error setting keyboard cooperative level.");
  return 0;
 }

 ddrval=IDirectInputDevice7_SetDataFormat(lpdid,&c_dfDIKeyboard);
 if(ddrval != DI_OK)
 {
  FCEUD_PrintError("DirectInput: Error setting keyboard data format.");
  return 0;
 }

 ddrval=IDirectInputDevice7_Acquire(lpdid);
 /* Not really a fatal error. */
 //if(ddrval != DI_OK)
 //{
 // FCEUD_PrintError("DirectInput: Error acquiring keyboard.");
 // return 0;
 //}
 return 1;
}

int KeyboardSetBackgroundAccess(int on)
{
 if(!lpdid)
  return(0);

 ddrval=IDirectInputDevice7_Unacquire(lpdid);

 if(on)
  ddrval=IDirectInputDevice7_SetCooperativeLevel(lpdid, hAppWnd,DISCL_BACKGROUND|DISCL_NONEXCLUSIVE);
 else
  ddrval=IDirectInputDevice7_SetCooperativeLevel(lpdid, hAppWnd,DISCL_FOREGROUND|DISCL_NONEXCLUSIVE);
 if(ddrval != DI_OK)
 {
  FCEUD_PrintError("DirectInput: Error setting keyboard cooperative level.");
  return 0;
 }

 ddrval=IDirectInputDevice7_Acquire(lpdid);
 return 1;
}
