#include "StdAfx.h"
#include "DirectInput.h"
#pragma comment(lib, "dinput8.lib")
#pragma comment(lib, "dxguid.lib")
using namespace System::Runtime::InteropServices;
using namespace System::Windows::Forms;
#pragma unmanaged
extern "C" HRESULT CallEnumDevicesBySemantics(IDirectInput8 *pDI,
LPCTSTR lpsz, DIACTIONFORMAT *pDIAF,
[MarshalAs(UnmanagedType::FunctionPtr)] Sunlight::DirectX::Input::DirectInput::DIEnumDevicesBySemanticsCallbackDelegate *pd,
LPVOID pvRef, DWORD dwFlags);
extern "C" HRESULT CallConfigureDevices(IDirectInput8 *pDI,
[MarshalAs(UnmanagedType::FunctionPtr)] Sunlight::DirectX::Input::DirectInput::DIConfigureDevicesCallbackDelegate *pCallback,
LPDICONFIGUREDEVICESPARAMS lpdiCDParams, DWORD dwFlags, LPVOID pvRef);
#pragma managed
namespace Sunlight
{
namespace DirectX
{
namespace Input
{
bool DirectInput::EnumDevicesBySemanticsCallback(int nddi, int ndid, int , int dwRemaining, int )
{
HRESULT h;
DIACTIONFORMAT __pin *pDIAF = &m_diaf;
LPCDIDEVICEINSTANCE lpddi = (LPCDIDEVICEINSTANCE)nddi;
IDirectInputDevice8 __nogc *lpdid = (IDirectInputDevice8 __nogc *)ndid;
if (GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_DEVICECTRL)
return DIENUM_CONTINUE;
h = lpdid->BuildActionMap(pDIAF, NULL, DIDBAM_DEFAULT);
if (FAILED(h))
return DIENUM_CONTINUE;
for (DWORD i = 0; i < pDIAF->dwNumActions; i++)
{
if (pDIAF->rgoAction[i].dwHow != DIAH_UNMAPPED)
{
h = lpdid->SetCooperativeLevel((HWND)m_pParentWindow->Handle.ToPointer(), DISCL_EXCLUSIVE | DISCL_FOREGROUND);
if (FAILED(h))
return DIENUM_CONTINUE;
h = lpdid->SetActionMap(pDIAF, NULL, DIDSAM_DEFAULT);
if (FAILED(h))
return DIENUM_CONTINUE;
m_pDeviceArray->Add(new Device(lpdid));
return DIENUM_CONTINUE;
}
}
return DIENUM_CONTINUE;
}
DirectInput::DirectInput() :
Direct3DDevice(NULL),
m_pDI(NULL),
m_pDeviceArray(new Collections::ArrayList(5)),
Actions(new ActionMap()),
ActionMapName(NULL),
Genre(Genres::None),
AppID(Guid::Empty),
m_bCreated(false)
{
}
DirectInput::~DirectInput()
{
if (m_pDI != NULL)
{
m_pDI->Release();
m_pDI = NULL;
}
if (m_pActions != NULL)
{
for (DWORD i = 0; i < m_diaf.dwNumActions; i++)
CoTaskMemFree((LPVOID)m_pActions[i].lptszActionName);
delete m_pActions;
m_pActions = NULL;
}
}
void DirectInput::Create()
{
if (m_bCreated)
return;
if (m_pParentWindow == NULL)
throw new ArgumentNullException(S"ParentWindow");
IDirectInput8 __nogc *pDI;
HRESULT h;
h = ::DirectInput8Create(::GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8,
(void __nogc * __nogc *)&pDI, NULL);
if (FAILED(h))
throw new Sunlight::DirectX::DirectXException(S"::DirectInput8Create", h);
m_pDI = pDI;
BuildDIAF();
EnumDevices();
m_bCreated = true;
}
void DirectInput::BuildDIAF()
{
DIACTIONFORMAT __pin *pDIAF = &m_diaf;
ZeroMemory(pDIAF, sizeof(DIACTIONFORMAT));
m_diaf.dwSize = sizeof(DIACTIONFORMAT);
m_diaf.dwActionSize = sizeof(DIACTION);
m_diaf.dwNumActions = Actions->Count;
m_diaf.dwDataSize = m_diaf.dwNumActions * sizeof(DWORD);
Marshal::Copy(AppID.ToByteArray(), 0, &pDIAF->guidActionMap, sizeof(GUID));
m_pActions = new DIACTION[m_diaf.dwNumActions];
ZeroMemory(m_pActions, sizeof(DIACTION) * m_diaf.dwNumActions);
m_diaf.rgoAction = m_pActions;
for (DWORD i = 0; i < m_diaf.dwNumActions; i++)
{
ActionMap::Entry *pEntry = Actions->Item(i);
m_pActions[i].uAppData = pEntry->ID;
m_pActions[i].dwSemantic = pEntry->Semantic;
#ifdef _UNICODE
LPWSTR p = (LPWSTR)(void *)Marshal::StringToCoTaskMemUni(pEntry->Name);
#else
LPSTR p = (LPSTR)(void *)Marshal::StringToCoTaskMemAnsi(pEntry->Name);
#endif
m_pActions[i].lptszActionName = p;
}
m_diaf.dwGenre = Genre;
m_diaf.dwBufferSize = 16;
m_diaf.lAxisMin = -100;
m_diaf.lAxisMax = 100;
#ifdef _UNICODE
LPWSTR p = (LPWSTR)(void *)Marshal::StringToCoTaskMemUni(ActionMapName);
#else
LPSTR p = (LPSTR)(void *)Marshal::StringToCoTaskMemAnsi(ActionMapName);
#endif
lstrcpy(pDIAF->tszActionMap, p);
CoTaskMemFree(p);
}
void DirectInput::EnumDevices()
{
DIACTIONFORMAT __pin *pDIAF = &m_diaf;
HRESULT h = CallEnumDevicesBySemantics(m_pDI, NULL, pDIAF,
new DIEnumDevicesBySemanticsCallbackDelegate(this, &DirectInput::EnumDevicesBySemanticsCallback),
NULL, DIEDBSFL_ATTACHEDONLY);
if (FAILED(h))
throw new Sunlight::DirectX::DirectXException(S"IDirectInput8::EnumDevicesBySemantics", h);
}
void DirectInput::OnFormActivated(Object *sender, EventArgs *e)
{
Acquire();
}
void DirectInput::OnFormDeactivated(Object *sender, EventArgs *e)
{
Unacquire();
}
void DirectInput::Acquire()
{
Create();
Cursor::Hide();
for (int iDevice = 0; iDevice < m_pDeviceArray->Count; iDevice++)
static_cast<Device *>(m_pDeviceArray->Item[iDevice])->m_pDevice->Acquire();
}
void DirectInput::Unacquire()
{
for (int iDevice = 0; iDevice < m_pDeviceArray->Count; iDevice++)
static_cast<Device *>(m_pDeviceArray->Item[iDevice])->m_pDevice->Unacquire();
Cursor::Show();
}
Form *DirectInput::get_ParentWindow()
{
return m_pParentWindow;
}
void DirectInput::set_ParentWindow(Form *pParentWindow)
{
m_pParentWindow = pParentWindow;
__hook(&System::Windows::Forms::Form::Activated, m_pParentWindow, &DirectInput::OnFormActivated, this);
__hook(&System::Windows::Forms::Form::Deactivate, m_pParentWindow, &DirectInput::OnFormDeactivated, this);
__hook(&System::Windows::Forms::Form::Closed, m_pParentWindow, &DirectInput::OnFormDeactivated, this);
}
#define INPUT_DATA_LIMIT 20
void DirectInput::Check()
{
DIDEVICEOBJECTDATA pdidod[INPUT_DATA_LIMIT];
DWORD dwObjCount;
if (m_pDeviceArray == NULL)
return;
for (int iDevice = 0; iDevice < m_pDeviceArray->Count; iDevice++)
{
Device *pDev = static_cast<Device *>(m_pDeviceArray->Item[iDevice]);
pDev->m_pDevice->Poll();
dwObjCount = INPUT_DATA_LIMIT;
pDev->m_pDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), pdidod, &dwObjCount, 0);
if (Action != NULL)
{
for (DWORD i = 0; i < dwObjCount; i++)
__raise Action(this, new DirectInputEventArgs(pdidod[i].uAppData, (int)pdidod[i].dwData));
}
}
}
void DirectInput::ConfigureDevicesCallback(int lpDDSTarget, int )
{
IDirect3DSurface8 *pSurface, *pBackBuffer;
if (!Direct3DDevice->Paused)
{
((::IUnknown *)lpDDSTarget)->QueryInterface(IID_IDirect3DSurface8, (void **)&pSurface);
((LPDIRECT3DDEVICE8)Direct3DDevice->Direct3DDevice)->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
((LPDIRECT3DDEVICE8)Direct3DDevice->Direct3DDevice)->CopyRects(pSurface, NULL, 0, pBackBuffer, NULL);
Direct3DDevice->Flip();
pSurface->Release();
pBackBuffer->Release();
}
}
void DirectInput::Configure()
{
Create();
HRESULT h;
DICONFIGUREDEVICESPARAMS dicdp;
DIACTIONFORMAT __pin *pDIAF = &m_diaf;
ZeroMemory(&dicdp, sizeof(dicdp));
dicdp.dwSize = sizeof(dicdp);
dicdp.dwcUsers = 1;
dicdp.lptszUserNames = NULL;
dicdp.dwcFormats = 1;
dicdp.lprgFormats = pDIAF;
dicdp.hwnd = (HWND)m_pParentWindow->Handle.ToPointer();
dicdp.lpUnkDDSTarget = NULL;
if (Direct3DDevice != NULL)
{
IDirect3DSurface8 *pSurface;
h = ((LPDIRECT3DDEVICE8)Direct3DDevice->Direct3DDevice)->CreateImageSurface(Direct3DDevice->Width, Direct3DDevice->Height,
(D3DFORMAT)Direct3DDevice->Format, &pSurface);
if (FAILED(h))
throw new DirectXException(S"IDirect3DDevice8::CreateImageSurface", h);
pSurface->QueryInterface(IID_IUnknown, (void **)&dicdp.lpUnkDDSTarget);
pSurface->Release();
}
dicdp.dics.dwSize = sizeof(DICOLORSET);
Unacquire();
if (dicdp.lpUnkDDSTarget == NULL)
h = m_pDI->ConfigureDevices(NULL, &dicdp, DICD_EDIT, NULL);
else
{
h = CallConfigureDevices(m_pDI,
new DIConfigureDevicesCallbackDelegate(this, &DirectInput::ConfigureDevicesCallback),
&dicdp, DICD_EDIT, NULL);
dicdp.lpUnkDDSTarget->Release();
}
if (FAILED(h))
{
Acquire();
throw new DirectXException(S"IDirectInput8::ConfigureDevices", h);
}
m_pDeviceArray->Clear();
EnumDevices();
Acquire();
}
void DirectInput::Display()
{
Create();
HRESULT h;
DICONFIGUREDEVICESPARAMS dicdp;
DIACTIONFORMAT __pin *pDIAF = &m_diaf;
ZeroMemory(&dicdp, sizeof(dicdp));
dicdp.dwSize = sizeof(dicdp);
dicdp.dwcUsers = 1;
dicdp.lptszUserNames = NULL;
dicdp.dwcFormats = 1;
dicdp.lprgFormats = pDIAF;
dicdp.hwnd = (HWND)m_pParentWindow->Handle.ToPointer();
dicdp.lpUnkDDSTarget = NULL;
if (Direct3DDevice != NULL)
{
IDirect3DSurface8 *pSurface;
h = ((LPDIRECT3DDEVICE8)Direct3DDevice->Direct3DDevice)->CreateImageSurface(Direct3DDevice->Width, Direct3DDevice->Height,
(D3DFORMAT)Direct3DDevice->Format, &pSurface);
if (FAILED(h))
throw new DirectXException(S"IDirect3DDevice8::CreateImageSurface", h);
pSurface->QueryInterface(IID_IUnknown, (void **)&dicdp.lpUnkDDSTarget);
pSurface->Release();
}
dicdp.dics.dwSize = sizeof(DICOLORSET);
Unacquire();
if (dicdp.lpUnkDDSTarget == NULL)
h = m_pDI->ConfigureDevices(NULL, &dicdp, DICD_DEFAULT, NULL);
else
{
h = CallConfigureDevices(m_pDI,
new DIConfigureDevicesCallbackDelegate(this, &DirectInput::ConfigureDevicesCallback),
&dicdp, DICD_DEFAULT, NULL);
dicdp.lpUnkDDSTarget->Release();
}
Acquire();
if (FAILED(h))
throw new DirectXException(S"IDirectInput8::ConfigureDevices", h);
}
}
}
}