//----------------------------------------------------------------------------- // 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 #include //----------------------------------------------------------------------------- // 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; dvEnumDevicesBySemantics(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(); }