#define DIRECTINPUT_VERSION 0x800
#define  _CRT_SECURE_NO_WARNINGS

#include <windows.h>
#include <dinput.h>
#include "dxwnd.h"
#include "dxhook.h"
#include "dxwcore.hpp"
#include "syslibs.h"
#include "dxhelper.h"

typedef HRESULT (WINAPI *QueryInterface_Type)(void *, REFIID, LPVOID *);
typedef HRESULT (WINAPI *DirectInputCreate_Type)(HINSTANCE, DWORD, LPDIRECTINPUT *, LPUNKNOWN);
typedef HRESULT (WINAPI *DirectInputCreateEx_Type)(HINSTANCE, DWORD, REFIID, LPVOID *, LPUNKNOWN);
typedef HRESULT (WINAPI *DICreateDevice_Type)(LPDIRECTINPUT, REFGUID, LPDIRECTINPUTDEVICE *, LPUNKNOWN);
typedef HRESULT (WINAPI *DICreateDeviceEx_Type)(LPDIRECTINPUT, REFGUID, REFIID, LPVOID *, LPUNKNOWN);
typedef HRESULT (WINAPI *GetDeviceData_Type)(LPDIRECTINPUTDEVICE, DWORD, LPVOID, LPDWORD, DWORD);
typedef HRESULT (WINAPI *GetDeviceState_Type)(LPDIRECTINPUTDEVICE, DWORD, LPDIMOUSESTATE);
typedef HRESULT (WINAPI *DISetCooperativeLevel_Type)(LPDIRECTINPUTDEVICE, HWND, DWORD);
typedef HRESULT (WINAPI *SetDataFormat_Type)(LPDIRECTINPUTDEVICE, LPCDIDATAFORMAT);
typedef HRESULT (WINAPI *DIEnumDevices_Type)(void *, DWORD, LPDIENUMDEVICESCALLBACK, LPVOID, DWORD);

HRESULT WINAPI extDirectInputCreateA(HINSTANCE, DWORD, LPDIRECTINPUT *, LPUNKNOWN);
HRESULT WINAPI extDirectInputCreateW(HINSTANCE, DWORD, LPDIRECTINPUT *, LPUNKNOWN);
HRESULT WINAPI extDirectInputCreateEx(HINSTANCE, DWORD, REFIID, LPVOID *, LPUNKNOWN);
HRESULT WINAPI extDirectInput8Create(HINSTANCE, DWORD, REFIID, LPVOID *, LPUNKNOWN);
HRESULT WINAPI extDICreateDevice(LPDIRECTINPUT, REFGUID, LPDIRECTINPUTDEVICE *, LPUNKNOWN);
HRESULT WINAPI extDICreateDeviceEx(LPDIRECTINPUT, REFGUID, REFIID, LPVOID *, LPUNKNOWN);
HRESULT WINAPI extGetDeviceData(LPDIRECTINPUTDEVICE, DWORD, LPVOID, LPDWORD, DWORD);
HRESULT WINAPI extGetDeviceState(LPDIRECTINPUTDEVICE, DWORD, LPDIMOUSESTATE);
HRESULT WINAPI extDISetCooperativeLevel(LPDIRECTINPUTDEVICE, HWND, DWORD);
HRESULT WINAPI extSetDataFormat(LPDIRECTINPUTDEVICE, LPCDIDATAFORMAT);
HRESULT WINAPI extDIQueryInterface(void *, REFIID, LPVOID *);
HRESULT WINAPI extDIEnumDevices(void *, DWORD, LPDIENUMDEVICESCALLBACK, LPVOID, DWORD);

DirectInputCreate_Type pDirectInputCreateA = 0;
DirectInputCreate_Type pDirectInputCreateW = 0;
DirectInputCreateEx_Type pDirectInputCreateEx = 0;
DICreateDevice_Type pDICreateDevice = 0;
DICreateDeviceEx_Type pDICreateDeviceEx = 0;
GetDeviceData_Type pGetDeviceData = 0;
GetDeviceState_Type pGetDeviceState = 0;
DISetCooperativeLevel_Type pDISetCooperativeLevel = 0;
SetDataFormat_Type pSetDataFormat = 0;
QueryInterface_Type pDIQueryInterface = 0;
DIEnumDevices_Type pDIEnumDevices = 0;

//static HookEntry_Type diHooks[]={
//	{HOOK_HOT_CANDIDATE, "DirectInputCreateA", (FARPROC)NULL, (FARPROC *)&pDirectInputCreateA, (FARPROC)extDirectInputCreateA},
//	{HOOK_HOT_CANDIDATE, "DirectInputCreateW", (FARPROC)NULL, (FARPROC *)&pDirectInputCreateW, (FARPROC)extDirectInputCreateW},
//	{HOOK_HOT_CANDIDATE, "DirectInputCreateEx", (FARPROC)NULL, (FARPROC *)&pDirectInputCreateEx, (FARPROC)extDirectInputCreateEx},
//	{HOOK_HOT_CANDIDATE, "DirectInput8Create", (FARPROC)NULL, (FARPROC *)&pDirectInput8Create, (FARPROC)extDirectInput8Create},
//	{HOOK_IAT_CANDIDATE, 0, NULL, 0, 0} // terminator
//};

void GetMousePosition(int *, int *);
void InitPosition(int, int, int, int, int, int);
	

int iCursorX;
int iCursorY;
int iCursorXBuf;
int iCursorYBuf;
int iCurMinX;
int iCurMinY;
int iCurMaxX;
int iCurMaxY;

int HookDirectInput(HMODULE module, int version)
{
	HINSTANCE hinst;
	void *tmp;
	LPDIRECTINPUT lpdi;
	const GUID di7 = {0x9A4CB684,0x236D,0x11D3,0x8E,0x9D,0x00,0xC0,0x4F,0x68,0x44,0xAE};
	const GUID di8 = {0xBF798030,0x483A,0x4DA2,0xAA,0x99,0x5D,0x64,0xED,0x36,0x97,0x00};

	tmp = HookAPI(module, "dinput.dll", NULL, "DirectInputCreateA", extDirectInputCreateA);
	if(tmp) pDirectInputCreateA = (DirectInputCreate_Type)tmp;
	tmp = HookAPI(module, "dinput.dll", NULL, "DirectInputCreateW", extDirectInputCreateW);
	if(tmp) pDirectInputCreateW = (DirectInputCreate_Type)tmp;
	tmp = HookAPI(module, "dinput.dll", NULL, "DirectInputCreateEx", extDirectInputCreateEx);
	if(tmp) pDirectInputCreateEx = (DirectInputCreateEx_Type)tmp;
	tmp = HookAPI(module, "dinput8.dll", NULL, "DirectInput8Create", extDirectInput8Create);
	if(tmp) pDirectInputCreateEx = (DirectInputCreateEx_Type)tmp;
	if(!pDirectInputCreateA && !pDirectInputCreateW && !pDirectInputCreateEx){
		if(version < 8){
			hinst = LoadLibrary("dinput.dll");
			pDirectInputCreateA =
				(DirectInputCreate_Type)GetProcAddress(hinst, "DirectInputCreateA");
			if(pDirectInputCreateA)
				if(!extDirectInputCreateA(GetModuleHandle(0), DIRECTINPUT_VERSION,
					&lpdi, 0)) lpdi->Release();
			pDirectInputCreateEx =
				(DirectInputCreateEx_Type)GetProcAddress(hinst, "DirectInputCreateEx");
			if(pDirectInputCreateEx)
				if(!extDirectInputCreateEx(GetModuleHandle(0), DIRECTINPUT_VERSION,
					di7, (void **)&lpdi, 0)) lpdi->Release();
		}
		else{
			hinst = LoadLibrary("dinput8.dll");
			pDirectInputCreateEx =
				(DirectInputCreateEx_Type)GetProcAddress(hinst, "DirectInput8Create");
			if(pDirectInputCreateEx)
				if(!extDirectInputCreateEx(GetModuleHandle(0), DIRECTINPUT_VERSION,
					di8, (void **)&lpdi, 0)) lpdi->Release();
		}
	}
	if(pDirectInputCreateA || pDirectInputCreateW || pDirectInputCreateEx) return 1;
	return 0;
}

HRESULT WINAPI extDirectInputCreate(HINSTANCE hinst,
	DWORD dwversion, LPDIRECTINPUT *lplpdi, LPUNKNOWN pu, DirectInputCreate_Type pDirectInputCreate, char *apiname)
{
	HRESULT res;

	OutTraceDW("%s: dwVersion=%x\n", apiname, dwversion);

	res = (*pDirectInputCreate)(hinst, dwversion, lplpdi, pu);
	if(res) {
		OutTraceE("%s: ERROR err=%x(%s)\n", apiname, res, ExplainDDError(res));
		return res;
	}
	SetHook((void *)(**(DWORD **)lplpdi), extDIQueryInterface, (void **)&pDIQueryInterface, "QueryInterface(I)");
	SetHook((void *)(**(DWORD **)lplpdi + 12), extDICreateDevice, (void **)&pDICreateDevice, "CreateDevice(I)");
	SetHook((void *)(**(DWORD **)lplpdi + 16), extDIEnumDevices, (void **)&pDIEnumDevices, "EnumDevices(I)");
	return 0;
}

HRESULT WINAPI extDirectInputCreateA(HINSTANCE hinst, DWORD dwversion, LPDIRECTINPUT *lplpdi, LPUNKNOWN pu)
{
	return extDirectInputCreate(hinst, dwversion, lplpdi, pu, pDirectInputCreateA, "DirectInputCreateA");
}

HRESULT WINAPI extDirectInputCreateW(HINSTANCE hinst, DWORD dwversion, LPDIRECTINPUT *lplpdi, LPUNKNOWN pu)
{
	return extDirectInputCreate(hinst, dwversion, lplpdi, pu, pDirectInputCreateW, "DirectInputCreateW");
}

HRESULT WINAPI extDirectInputCreateEx(HINSTANCE hinst,
	DWORD dwversion, REFIID riidltf, LPVOID *ppvout, LPUNKNOWN pu)
{
	HRESULT res;

	OutTraceDW("DirectInputCreateEx: dwVersion=%x REFIID=%x\n",
		dwversion, riidltf.Data1);

	res = (*pDirectInputCreateEx)(hinst, dwversion, riidltf, ppvout, pu);
	if(res) {
		OutTraceE("DirectInputCreateEx: ERROR err=%x(%s)\n", res, ExplainDDError(res));
		return res;
	}
	SetHook((void *)(**(DWORD **)ppvout + 12), extDICreateDevice, (void **)&pDICreateDevice, "CreateDevice(I)");
	SetHook((void *)(**(DWORD **)ppvout + 16), extDIEnumDevices, (void **)&pDIEnumDevices, "EnumDevices(I)");
	if(dwversion > 700)
		SetHook((void *)(**(DWORD **)ppvout + 36), extDICreateDeviceEx, (void **)&pDICreateDeviceEx, "DICreateDeviceEx(I)");
	return 0;
}

HRESULT WINAPI extDIQueryInterface(void * lpdi, REFIID riid, LPVOID *obp)
{
	HRESULT res;

	OutTraceDW("QueryInterface(I): REFIID=%x\n",
		riid.Data1);

	res = (*pDIQueryInterface)(lpdi, riid, obp);
	if(res) return res;

	switch(riid.Data1){
	case 0x5944E662:		//DirectInput2A
	case 0x5944E663:		//DirectInput2W
		SetHook((void *)(**(DWORD **)obp + 12), extDICreateDevice, (void **)&pDICreateDevice, "CreateDevice(I)");
		SetHook((void *)(**(DWORD **)obp + 16), extDIEnumDevices, (void **)&pDIEnumDevices, "EnumDevices(I)");
		break;
	}
	return 0;
}

HRESULT WINAPI extDirectInput8Create(HINSTANCE hinst,
	DWORD dwversion, REFIID riidltf, LPVOID *ppvout, LPUNKNOWN pu)
{
	HRESULT res;

	OutTraceDW("DirectInput8Create: dwVersion=%x REFIID=%x\n",
		dwversion, riidltf.Data1);

	res = (*pDirectInputCreateEx)(hinst, dwversion, riidltf, ppvout, pu);
	if(res) {
		OutTraceE("DirectInput8Create: ERROR res=%x\n", res);
		return res;
	}
	OutTraceDW("DirectInput8Create: di=%x\n", *ppvout);
	SetHook((void *)(**(DWORD **)ppvout + 12), extDICreateDevice, (void **)&pDICreateDevice, "CreateDevice(I8)");
	return 0;
}

HRESULT WINAPI extDICreateDevice(LPDIRECTINPUT lpdi, REFGUID rguid,
	LPDIRECTINPUTDEVICE *lplpdid, LPUNKNOWN pu)
{
	HRESULT res;

	OutTraceDW("CreateDevice(I): REFGUID=%x\n", rguid.Data1);

	res = (*pDICreateDevice)(lpdi, rguid, lplpdid, pu);
	if(res) {
		OutTraceE("CreateDevice(I): ERROR res=%x\n", res);
		return res;
	}
	OutTraceDW("CreateDevice(I): did=%x\n", *lplpdid);
	SetHook((void *)(**(DWORD **)lplpdid + 36), extGetDeviceState, (void **)&pGetDeviceState, "GetDeviceState(I)");
	SetHook((void *)(**(DWORD **)lplpdid + 40), extGetDeviceData, (void **)&pGetDeviceData, "GetDeviceData(I)");
	SetHook((void *)(**(DWORD **)lplpdid + 44), extSetDataFormat, (void **)&pSetDataFormat, "SetDataFormat(I)");
	SetHook((void *)(**(DWORD **)lplpdid + 52), extDISetCooperativeLevel, (void **)&pDISetCooperativeLevel, "SetCooperativeLevel(I)");
	return 0;
}

HRESULT WINAPI extDICreateDeviceEx(LPDIRECTINPUT lpdi, REFGUID rguid,
	REFIID riid, LPVOID *pvout, LPUNKNOWN pu)
{
	HRESULT res;

	OutTraceDW("CreateDeviceEx(I): GUID=%x REFIID=%x\n", rguid.Data1, riid.Data1);

	res = (*pDICreateDeviceEx)(lpdi, rguid, riid, pvout, pu);
	if(res) {
		OutTraceE("CreateDeviceEx(I): ERROR res=%x\n", res);
		return res;
	}
	OutTraceDW("CreateDeviceEx(I): did=%x\n", *pvout);
	SetHook((void *)(**(DWORD **)pvout + 36), extGetDeviceState, (void **)&pGetDeviceState, "GetDeviceState(I)");
	SetHook((void *)(**(DWORD **)pvout + 40), extGetDeviceData, (void **)&pGetDeviceData, "GetDeviceData(I)");
	SetHook((void *)(**(DWORD **)pvout + 44), extSetDataFormat, (void **)&pSetDataFormat, "SetDataFormat(I)");
	SetHook((void *)(**(DWORD **)pvout + 52), extDISetCooperativeLevel, (void **)&pDISetCooperativeLevel, "SetCooperativeLevel(I)");
	return 0;
}

/* from MSDN:
cbObjectData
    Size of the DIDEVICEOBJECTDATA structure, in bytes. 
rgdod
    Array of DIDEVICEOBJECTDATA structures to receive the buffered data. 
	The number of elements in this array must be equal to the value of the pdwInOut parameter. 
	If this parameter is NULL, the buffered data is not stored anywhere, but all other side effects take place. 
pdwInOut
    On entry, the number of elements in the array pointed to by the rgdod parameter. 
	On exit, the number of elements actually obtained. 
dwFlags
    Flags that control the manner in which data is obtained. 
	This value can be 0 or the following flag.

    DIGDD_PEEK
        Do not remove the items from the buffer. A subsequent IDirectInputDevice8::GetDeviceData call will read the same data. 
		Normally, data is removed from the buffer after it is read.
*/

HRESULT WINAPI extGetDeviceData(LPDIRECTINPUTDEVICE lpdid, DWORD cbdata, LPVOID rgdod, LPDWORD pdwinout, DWORD dwflags)
{
	HRESULT res;
	BYTE *tmp;
	unsigned int i;
	POINT p;

	OutTraceDW("GetDeviceData(I): did=%x cbdata=%i rgdod=%x, inout=%d flags=%x\n", 
		lpdid, cbdata, rgdod, *pdwinout, dwflags);

	res = (*pGetDeviceData)(lpdid, cbdata, rgdod, pdwinout, dwflags);
	if(res) {
		OutTraceE("GetDeviceData(I) ERROR: err=%x(%s)\n", res, ExplainDDError(res)); 
		return res;
	}

	if(!dxw.bActive) {
		*pdwinout = 0;
		return DI_OK;
	}

	if(dxw.dwFlags4 & RELEASEMOUSE){
		POINT curr;
		RECT client;
		extern GetCursorPos_Type pGetCursorPos;
		extern GetClientRect_Type pGetClientRect;
		extern ScreenToClient_Type pScreenToClient;
		(*pGetCursorPos)(&curr);
		(*pScreenToClient)(dxw.GethWnd(), &curr);
		(*pGetClientRect)(dxw.GethWnd(), &client);
		if ((curr.x < client.left) || (curr.y < client.top) || (curr.x > client.right) || (curr.y > client.bottom)){
			*pdwinout = 0;
			return DI_OK;
		}
	}

	if(cbdata == 20 || cbdata == 24 || cbdata == 16){
		tmp = (BYTE *)rgdod;
		if(dxw.bDInputAbs){
			GetMousePosition((int *)&p.x, (int *)&p.y);
			for(i = 0; i < *pdwinout; i ++){
				if(((LPDIDEVICEOBJECTDATA)tmp)->dwOfs == DIMOFS_X)((LPDIDEVICEOBJECTDATA)tmp)->dwData = p.x;
				if(((LPDIDEVICEOBJECTDATA)tmp)->dwOfs == DIMOFS_Y)((LPDIDEVICEOBJECTDATA)tmp)->dwData = p.y;
				tmp += cbdata;
			}
			OutTraceB("GetDeviceData(I): ABS mousedata=(%d,%d)\n", p.x, p.y);
		}
		else{
			for(i = 0; i < *pdwinout; i ++){
				if(((LPDIDEVICEOBJECTDATA)tmp)->dwOfs == DIMOFS_X) OutTraceB("GetDeviceData(I): REL mousedata X=%d\n", ((LPDIDEVICEOBJECTDATA)tmp)->dwData);
				if(((LPDIDEVICEOBJECTDATA)tmp)->dwOfs == DIMOFS_Y) OutTraceB("GetDeviceData(I): REL mousedata Y=%d\n", ((LPDIDEVICEOBJECTDATA)tmp)->dwData);
				tmp += cbdata;
			}
		}
	}

	return DI_OK;
}

HRESULT WINAPI extGetDeviceState(LPDIRECTINPUTDEVICE lpdid, DWORD cbdata, LPDIMOUSESTATE lpvdata)
{
	HRESULT res;
	POINT p = {0, 0};

	OutTraceDW("GetDeviceState(I): did=%x cbData=%i,%i\n", lpdid, cbdata, dxw.bActive);

	res = (*pGetDeviceState)(lpdid, cbdata, lpvdata);
	if(res) {
		OutTraceE("GetDeviceState(I) ERROR: err=%x(%s)\n", res, ExplainDDError(res)); 
		return res;
	}

	if(	cbdata == sizeof(DIMOUSESTATE) || cbdata == sizeof(DIMOUSESTATE2) 
	//	|| cbdata == sizeof(DIJOYSTATE) || cbdata == sizeof(DIJOYSTATE2) 
	){
		GetMousePosition((int *)&p.x, (int *)&p.y);
		lpvdata->lX = p.x;
		lpvdata->lY = p.y;
		if(!dxw.bDInputAbs){
			if(p.x < iCurMinX) p.x = iCurMinX;
			if(p.x > iCurMaxX) p.x = iCurMaxX;
			if(p.y < iCurMinY) p.y = iCurMinY;
			if(p.y > iCurMaxY) p.y = iCurMaxY;
			lpvdata->lX = p.x - iCursorX;
			lpvdata->lY = p.y - iCursorY;
			iCursorX = p.x;
			iCursorY = p.y;
		}
		if(!dxw.bActive){
			lpvdata->lZ = 0;
			*(DWORD *)lpvdata->rgbButtons = 0;
		}
		OutTraceB("GetDeviceState(I): DEBUG mousestate=(%d,%d)\n", p.x, p.y);
	}
	
	if(cbdata == 256 && !dxw.bActive) ZeroMemory(lpvdata, 256);
	return DI_OK;
}

//static char *dftype(LPCDIDATAFORMAT lpdf)
//{
//	if(lpdf == &c_dfDIMouse)		return "mouse";
//	if(lpdf == &c_dfDIKeyboard)		return "keyboard";
//	if(lpdf == &c_dfDIMouse2)		return "mouse2";
//	if(lpdf == &c_dfDIJoystick)		return "joy";
//	if(lpdf == &c_dfDIJoystick2)	return "joy2";
//	return "custom";
//}

static char *didftype(DWORD c)
{
	static char eb[256];
	unsigned int l;
	strcpy(eb,"DIDFT_");
	switch (c & 0x00000003){
		case DIDFT_RELAXIS: strcat(eb, "RELAXIS+"); break;
		case DIDFT_ABSAXIS: strcat(eb, "ABSAXIS+"); break;
		case DIDFT_AXIS: strcat(eb, "AXIS+"); break;
	}
	switch (c & 0x0000000C){
		case DIDFT_PSHBUTTON: strcat(eb, "PSHBUTTON+"); break;
		case DIDFT_TGLBUTTON: strcat(eb, "TGLBUTTON+"); break;
		case DIDFT_BUTTON: strcat(eb, "BUTTON+"); break;
	}
	if (c & DIDFT_POV) strcat(eb, "POV+");
	if (c & DIDFT_COLLECTION) strcat(eb, "COLLECTION+");
	if (c & DIDFT_NODATA) strcat(eb, "NODATA+");
	if (c & DIDFT_FFACTUATOR) strcat(eb, "FFACTUATOR+");
	if (c & DIDFT_FFEFFECTTRIGGER) strcat(eb, "FFEFFECTTRIGGER+");
	if (c & DIDFT_VENDORDEFINED) strcat(eb, "VENDORDEFINED+");
	if (c & DIDFT_OUTPUT) strcat(eb, "OUTPUT+");
	if (c & DIDFT_ALIAS) strcat(eb, "ALIAS+");
	if (c & DIDFT_OPTIONAL) strcat(eb, "OPTIONAL+");
	l=strlen(eb);
	if (l>strlen("DIDFT_")) eb[l-1]=0; // delete last '+' if any
	else eb[0]=0;
	return(eb);
}
static char *ExplainDataFormatFlags(DWORD f)
{
	char *s;
	s="unknown";
	switch(f){
		case DIDF_ABSAXIS: s="DIDF_ABSAXIS";
		case DIDF_RELAXIS: s="DIDF_RELAXIS";
	}
	return s;
}

HRESULT WINAPI extSetDataFormat(LPDIRECTINPUTDEVICE lpdid, LPCDIDATAFORMAT lpdf)
{
	OutTraceDW("SetDataFormat(I): did=%x lpdf=%x size=%d objsize=%d flags=0x%x(%s) datasize=%d numobjects=%d\n", 
		lpdid, lpdf, lpdf->dwSize, lpdf->dwObjSize, lpdf->dwFlags, ExplainDataFormatFlags(lpdf->dwFlags), lpdf->dwDataSize, lpdf->dwNumObjs);
	if(IsDebug){
		DIOBJECTDATAFORMAT *df;
		df = lpdf->rgodf;
		for(DWORD i=0; i<lpdf->dwNumObjs; i++){
			OutTrace("SetDataFormat(I): DataFormat[%d] ofs=%x flags=%x type=%x(%s)\n", 
				i, df[i].dwOfs, df[i].dwFlags, df[i].dwType, didftype(df[i].dwType));
		}
	}

	if(lpdf->dwFlags & DIDF_ABSAXIS) dxw.bDInputAbs = 1;
	if(lpdf->dwFlags & DIDF_RELAXIS) dxw.bDInputAbs = 0;
	return (*pSetDataFormat)(lpdid, lpdf);
}

HRESULT WINAPI extDISetCooperativeLevel(LPDIRECTINPUTDEVICE lpdid, HWND hwnd, DWORD dwflags)
{
	HRESULT res;

	OutTraceDW("SetCooperativeLevel(I): did=%x hwnd=%x flags=%x(%s)\n", 
		lpdid, hwnd, dwflags, ExplainDICooperativeFlags(dwflags));

	if(dxw.IsRealDesktop(hwnd)) hwnd=dxw.GethWnd();
	dwflags = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND;
	res = (*pDISetCooperativeLevel)(lpdid, hwnd, dwflags);
	if(res != DD_OK){
		OutTraceE("SetCooperativeLevel(I) ERROR: err=%x(%s)\n", res, ExplainDDError(res)); 
	}

	return res;
}

// Simplified version, taking in proper account the GetCursorPos API hooking & coordinate processing
void GetMousePosition(int *x, int *y)
{
	POINT p;

	extern BOOL WINAPI extGetCursorPos(LPPOINT);
	extGetCursorPos(&p);
	*x = p.x;
	*y = p.y;
	OutTraceDW("GetMousePosition(I): x,y=(%d,%d)\n", *x, *y);
}

void InitPosition(int x, int y, int minx, int miny, int maxx, int maxy)
{
	iCursorX = x;
	iCursorY = y;
	iCursorXBuf = x;
	iCursorYBuf = y;
	iCurMinX = minx;
	iCurMinY = miny;
	iCurMaxX = maxx;
	iCurMaxY = maxy;
}

typedef struct {
	LPDIENUMDEVICESCALLBACK cb;
	LPVOID arg;
} CallbackArg;

HRESULT WINAPI extDeviceProxy(LPCDIDEVICEINSTANCE dev, LPVOID arg)
{
	HRESULT res;
	char *p;
	switch (dev->dwSize) {
		case sizeof(DIDEVICEINSTANCEA): p="ASCII"; break;
		case sizeof(DIDEVICEINSTANCEW): p="WIDECHAR"; break;
		default: p="UNKNOWN"; break;
	}
	OutTraceDW("EnumDevices(I): CALLBACK size=%d(%s) GUID=(%x.%x.%x.%x) type=%x InstanceName=\"%s\", ProductName=\"%s\"\n", 
		dev->dwSize, p, dev->guidInstance.Data1, dev->guidInstance.Data2, dev->guidInstance.Data3, dev->guidInstance.Data4, 
		dev->dwDevType, dev->tszInstanceName, dev->tszProductName);

	res = (*(((CallbackArg *)arg)->cb))(dev, ((CallbackArg *)arg)->arg);
	OutTraceDW("EnumDevices: CALLBACK ret=%x\n", res);
	return res;
}

HRESULT WINAPI extDIEnumDevices(void *lpdi, DWORD dwDevType, LPDIENUMDEVICESCALLBACK lpCallback, LPVOID pvRef, DWORD dwFlags)
{
	HRESULT res;
	CallbackArg Arg;
	OutTraceDW("EnumDevices(I): di=%x DevType=%x CallBack=%x Ref=%x Flags=%x\n", lpdi, dwDevType, lpCallback, pvRef, dwFlags);
	Arg.cb= lpCallback;
	Arg.arg=pvRef;
	res=(*pDIEnumDevices)( lpdi, dwDevType, (LPDIENUMDEVICESCALLBACK)extDeviceProxy, &Arg, dwFlags); // V2.02.80 fix
	//res=(*pDIEnumDevices)( lpdi, dwDevType, lpCallback, pvRef, dwFlags);
	OutTraceDW("EnumDevices(I): res=%x\n", res);
	return res;
}

