windows-nt/Source/XPSP1/NT/multimedia/directx/dinput/dx8/tdonuts/diutil.cpp
2020-09-26 16:20:57 +08:00

417 lines
11 KiB
C++

//-----------------------------------------------------------------------------
// File: diutil.cpp
//
// Desc: DirectInput support
//
// Copyright (C) 1995-1999 Microsoft Corporation. All Rights Reserved.
//-----------------------------------------------------------------------------
#define STRICT
#include "DIUtil.h"
#include "resource.h"
#include "ddraw.h"
#include <tchar.h>
#include <stdio.h>
//-----------------------------------------------------------------------------
// Function prototypes
//-----------------------------------------------------------------------------
BOOL CALLBACK EnumSuitableDevicesCallback(LPCDIDEVICEINSTANCE lpDIDI, LPDIRECTINPUTDEVICE8A pdiDev8A, DWORD dwFlags, DWORD dwDeviceRemaining, LPVOID lpVoid);
static HRESULT CreateJoystick( HWND, LPDIRECTINPUTDEVICE2 pdidDevice );
BOOL CALLBACK ConfigureDevicesCallback(LPVOID lpVoid, LPVOID lpUser);
//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
#define NUMBER_OF_SEMANTICS ( sizeof(g_rgGameAction) / sizeof(DIACTION) )
extern LPDIRECTDRAW7 g_pDD;
static DIDEVICEINSTANCE g_didiDevices[MAX_INPUT_DEVICES+1];
IDirectInput8* g_pDI = NULL; // DirectInput object
IDirectInputDevice8* g_pDevices[NUMBER_OF_PLAYERS][MAX_INPUT_DEVICES+1]; //IDirectInputDevice8 ptrs
DWORD g_dwNumDevices[NUMBER_OF_PLAYERS];
DIACTIONFORMAT diActF;
//user name
TCHAR UserName[UNLEN+1];
LPTSTR lpUserName = UserName;
extern LPDIRECTDRAWSURFACE7 g_pddsFrontBuffer;
extern DWORD dwInputState[NUMBER_OF_PLAYERS];
// {238D8220-7A5D-11d3-8FB2-00C04F8EC627}
static const GUID g_AppGuid =
{ 0x238d8220, 0x7a5d, 0x11d3, { 0x8f, 0xb2, 0x0, 0xc0, 0x4f, 0x8e, 0xc6, 0x27 } };
DIACTION g_rgGameAction[] = {
{AXIS_UD, DIAXIS_FPS_MOVE, 0, TEXT("Forward"),},
{AXIS_LR, DIAXIS_FPS_ROTATE, 0, TEXT("Rotate"),},
{KEY_FIRE, DIBUTTON_FPS_FIRE, 0, TEXT("Fire"),},
{KEY_THROW, DIBUTTON_FPS_WEAPONS, 0, TEXT("Change Weapon"),},
{KEY_SHIELD, DIBUTTON_FPS_APPLY, 0, TEXT("Shield"),},
{KEY_STOP, DIBUTTON_FPS_SELECT, 0, TEXT("Pause"),},
{KEY_THROW, DIBUTTON_FPS_CROUCH, 0, TEXT("Hyper space"),},
{KEY_THROW, DIBUTTON_FPS_JUMP, 0, TEXT("Launch Probe"),},
{KEY_DISPLAY,DIBUTTON_FPS_DISPLAY, 0, TEXT("Display"),},
{KEY_QUIT, DIBUTTON_FPS_MENU, 0, TEXT("Quit Game"),},
{KEY_EDIT, DIBUTTON_FPS_DODGE, 0, TEXT("Edit Configuration"),},
{KEY_LEFT, DIKEYBOARD_LEFT, 0, TEXT("Turn +"),},
{KEY_RIGHT, DIKEYBOARD_RIGHT, 0, TEXT("Turn -"),},
{KEY_UP, DIKEYBOARD_UP, 0, TEXT("Move Up"),},
{KEY_DOWN, DIKEYBOARD_DOWN, 0, TEXT("Move Down"),},
{KEY_STOP, DIKEYBOARD_S, 0, TEXT("Stop Game"),},
{KEY_FIRE, DIKEYBOARD_SPACE, 0, TEXT("Shoot"),},
{KEY_THROW, DIKEYBOARD_T, 0, TEXT("Throw"),},
{KEY_SHIELD, DIKEYBOARD_H, 0, TEXT("Shield"),},
{KEY_DISPLAY,DIKEYBOARD_D, 0, TEXT("Display"),},
{KEY_QUIT, DIKEYBOARD_Q, 0, TEXT("Quit Game"),},
{KEY_EDIT, DIKEYBOARD_E, 0, TEXT("Edit Configuration"),},
{AXIS_LR, DIMOUSE_XAXIS, 0, TEXT("Turn"), },
{AXIS_UD, DIMOUSE_YAXIS, 0, TEXT("Move"), },
{KEY_FIRE, DIMOUSE_BUTTON0, 0, TEXT("Fire"), },
{KEY_SHIELD, DIMOUSE_BUTTON1, 0, TEXT("Shield"),},
{KEY_THROW, DIMOUSE_BUTTON2, 0, TEXT("Change Weapon"),},
// {KEY_THROW, DIMOUSE_BUTTON3, 0, TEXT("Hyper Space"),},
// {KEY_THROW, DIMOUSE_BUTTON4, 0, TEXT("Launch Probe"),},
// {KEY_THROW, DIMOUSE_WHEEL, 0, TEXT("Next Level"),},
};
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
BOOL CALLBACK EnumSuitableDevicesCallback(LPCDIDEVICEINSTANCE lpDIDI, LPDIRECTINPUTDEVICE8A pdiDev8A, DWORD dwFlags, DWORD dwDeviceRemaining, LPVOID lpVoid)
{
int* ppl = (int*)(lpVoid);
int pl = *ppl;
pdiDev8A->AddRef();
g_pDevices[pl][g_dwNumDevices[pl]] = pdiDev8A;
//set up the action map
TCHAR Player [UNLEN+1] = "Player";
TCHAR nr[10];
strcat(Player, _itoa(pl+1, nr, 10));
g_pDevices[pl][g_dwNumDevices[pl]]->BuildActionMap(&diActF, Player, 0);
g_pDevices[pl][g_dwNumDevices[pl]]->SetActionMap(&diActF, Player, 0);
g_dwNumDevices[pl]++;
return TRUE;
}
HRESULT DIUtil_InitEnumHelper()
{
HRESULT hr = S_OK;
int pl, dv;
if (g_pDI == NULL)
return E_FAIL;
for (pl = 0; pl < NUMBER_OF_PLAYERS; pl++)
{
for (dv=0; dv<MAX_INPUT_DEVICES+1; dv++)
{
g_pDevices[pl][dv] = NULL;
}
}
//DIACTIONFORMAT diActF;
ZeroMemory(&diActF, sizeof(DIACTIONFORMAT));
diActF.dwSize = sizeof(DIACTIONFORMAT);
diActF.dwActionSize = sizeof(DIACTION);
diActF.dwDataSize = NUMBER_OF_SEMANTICS * sizeof(DWORD);
diActF.guidActionMap = g_AppGuid;
diActF.dwGenre = DIVIRTUAL_FIGHTING_FPS;
diActF.dwNumActions = NUMBER_OF_SEMANTICS;
diActF.rgoAction = g_rgGameAction;
diActF.lAxisMin = -100;
diActF.lAxisMax = 100;
diActF.dwBufferSize = 16;
strcpy(diActF.tszActionMap, "TDonuts");
//reset the number of devices
for (pl = 0; pl < NUMBER_OF_PLAYERS; pl ++)
{
g_dwNumDevices[pl] = 0;
}
// Enumerate suitable DirectInput devices -- per player
for (pl = 0; pl < NUMBER_OF_PLAYERS; pl++)
{
TCHAR Player [UNLEN+1] = "Player";
TCHAR nr[10];
strcat(Player, _itoa(pl+1, nr, 10));
hr = g_pDI->EnumDevicesBySemantics(Player, &diActF, EnumSuitableDevicesCallback, (LPVOID) &pl,
DIEDBSFL_THISUSER);
if( FAILED(hr) )
return hr;
}
#define UI_USER_ASSIGNMENT
#ifndef UI_USER_ASSIGNMENT
//hardcoding to test on my machine because no owner assignment in UI yet.
//assign user 2 a device
if (g_pDevices[0][2] != NULL)
{
g_pDevices[1][0] = g_pDevices[0][0];
g_pDevices[0][0] = g_pDevices[0][g_dwNumDevices[0] - 1];
g_pDevices[0][g_dwNumDevices[0] - 1] = NULL;
g_dwNumDevices[0] --;
g_dwNumDevices[1] ++;
}
#endif
//draw "ships" for all users
UpdateShips();
return hr;
}
//-----------------------------------------------------------------------------
// Name: Initialize()
// Desc: Creates and initializes DirectInput objects
//-----------------------------------------------------------------------------
HRESULT DIUtil_Initialize( HWND hWnd )
{
HRESULT hr;
// Create the base DirectInput object
hr = DirectInput8Create( (HINSTANCE)(GetWindowLongPtr( hWnd,GWLP_HINSTANCE )),
DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID*) &g_pDI, NULL );
if( FAILED(hr) )
return hr;
//get and save the user name
DWORD nBuffSize = UNLEN+1;
if (!GetUserName(lpUserName, &nBuffSize))
{
lstrcpy(lpUserName, "");
}
//enumerate and stuff
hr = DIUtil_InitEnumHelper();
if (FAILED(hr))
return hr;
//acquire all the devices
for (int pl = 0; pl < NUMBER_OF_PLAYERS; pl++)
{
for (int dv = 0; dv< (int) g_dwNumDevices[pl]; dv++)
{
if (g_pDevices[pl][dv] != NULL)
{
hr = g_pDevices[pl][dv]->Acquire();
}
}
}
return S_OK;
}
HRESULT DIUtil_ReleaseDevices()
{
HRESULT hr = S_OK;
for (int pl = 0; pl < NUMBER_OF_PLAYERS; pl++)
{
for (int dv = 0; dv< (int) g_dwNumDevices[pl]; dv++)
{
if (g_pDevices[pl][dv] != NULL)
{
g_pDevices[pl][dv]->Unacquire();
hr = g_pDevices[pl][dv]->Release();
g_pDevices[pl][dv] = NULL;
}
}
}
return hr;
}
void DIUtil_ResetState()
{
//unset the buttons in the persistent state
for (int pl = 0; pl < NUMBER_OF_PLAYERS; pl ++)
{
DWORD inputState = (dwInputState[pl] & AXIS_MASK);
//blow out all of the axis data
inputState &= ~(KEY_RIGHT);
inputState &= ~(KEY_LEFT);
inputState &= ~(KEY_UP);
inputState &= ~(KEY_DOWN);
dwInputState[pl] = inputState;
}
}
HRESULT DIUtil_SetUpDevices()
{
//first, release the devices
HRESULT hr = S_OK;
hr = DIUtil_ReleaseDevices();
//reset the persisted state
DIUtil_ResetState();
//enumerate and stuff
hr = DIUtil_InitEnumHelper();
if (FAILED(hr))
return hr;
//acquire all the devices
for (int pl = 0; pl < NUMBER_OF_PLAYERS; pl++)
{
for (int dv = 0; dv< (int) g_dwNumDevices[pl]; dv++)
{
if (g_pDevices[pl][dv] != NULL)
{
hr = g_pDevices[pl][dv]->Acquire();
}
}
}
return hr;
}
HRESULT DIUtil_ConfigureDevices(HWND hWnd, IUnknown FAR * pddsDIConfig, DWORD dwFlags)
{
HRESULT hr = S_OK;
DICONFIGUREDEVICESPARAMS diconfparams;
ZeroMemory(&diconfparams, sizeof(DICONFIGUREDEVICESPARAMS));
// for testing, have 2 user names
TCHAR Names[MAX_PATH]; //BUGBUG this could be too small
CHAR* lpNames = Names;
for (int pl = 0; pl < NUMBER_OF_PLAYERS; pl ++)
{
char buffer[10];
_stprintf(lpNames, TEXT("%s%s%c"), "Player", _itoa(pl+1, buffer, 10), TEXT('\0'));
if (pl < 9)
{
lpNames += 8;
}
else
{
//don't worry about more than 99 players
lpNames += 9;
}
}
//extra '\0'
_stprintf(lpNames, TEXT("%c"), TEXT('\0'));
//for testing, have 2 DIACTIONFORMATs
DIACTIONFORMAT ActF[NUMBER_OF_ACTIONFORMATS];
for( int i =0x0; i < NUMBER_OF_ACTIONFORMATS; i++)
{
ActF[i] = diActF;
}
//fill in all the params
diconfparams.dwSize = sizeof(DICONFIGUREDEVICESPARAMS);
diconfparams.dwcUsers = NUMBER_OF_PLAYERS;
diconfparams.lptszUserNames = (LPTSTR)&Names;
diconfparams.dwcFormats = NUMBER_OF_ACTIONFORMATS;
diconfparams.lprgFormats = (LPDIACTIONFORMAT) &ActF;
diconfparams.hwnd = hWnd;
diconfparams.dics.dwSize = sizeof(DICOLORSET);
diconfparams.lpUnkDDSTarget = pddsDIConfig;
//unacquire the devices so that mouse doesn't control the game while in control panel
for (int pl = 0; pl < NUMBER_OF_PLAYERS; pl++)
{
for (int dv = 0; dv< (int) g_dwNumDevices[pl]; dv++)
{
if (g_pDevices[pl][dv] != NULL)
{
hr = g_pDevices[pl][dv]->Unacquire();
}
}
}
//and reset the state, since no useful data is coming through anyway
DIUtil_ResetState();
//call ConfigureDevices with all the user names!
switch (dwFlags)
{
case DICD_DEFAULT: default:
{
hr = g_pDI->ConfigureDevices((LPDICONFIGUREDEVICESCALLBACK)ConfigureDevicesCallback, &diconfparams, DICD_DEFAULT, NULL);
//re-acquire the devices
for (int pl = 0; pl < NUMBER_OF_PLAYERS; pl++)
{
for (int dv = 0; dv< (int) g_dwNumDevices[pl]; dv++)
{
if (g_pDevices[pl][dv] != NULL)
{
hr = g_pDevices[pl][dv]->Acquire();
}
}
}
break;
}
case DICD_EDIT:
{
hr = g_pDI->ConfigureDevices((LPDICONFIGUREDEVICESCALLBACK)ConfigureDevicesCallback, &diconfparams, DICD_EDIT, NULL);
//re-set up the devices
DIUtil_SetUpDevices();
//re-set up ships
UpdateShips();
break;
}
}
return hr;
}
//-----------------------------------------------------------------------------
// Name: DIUtil_CleanupDirectInput()
// Desc: Cleans up DirectInput objects
//-----------------------------------------------------------------------------
VOID DIUtil_CleanupDirectInput()
{
//release devices
DIUtil_ReleaseDevices();
// Release() base object
if( g_pDI )
{
g_pDI->Release();
}
g_pDI = NULL;
//call CoUninitialize();
CoUninitialize();
}