1579 lines
52 KiB
C++
1579 lines
52 KiB
C++
/*
|
|
File: add.cpp
|
|
Project: Universal Joystick Control Panel OLE Client
|
|
Author: Brycej
|
|
Date: 14/Feb/97
|
|
Comments:
|
|
window proc for add dialog
|
|
|
|
Copyright (c) 1995, Microsoft Corporation
|
|
*/
|
|
|
|
#include <afxcmn.h>
|
|
#include <windowsx.h>
|
|
#include <regstr.h> // for REGSTR_VAL_JOYOEMNAME reference!
|
|
|
|
#include "cpanel.h"
|
|
#include "joyarray.h"
|
|
|
|
#include <initguid.h>
|
|
|
|
#pragma warning(disable:4200)
|
|
#include <gameport.h>
|
|
#pragma warning(default:4200)
|
|
|
|
// table of default joystick configs
|
|
extern WCHAR *pwszTypeArray[MAX_DEVICES]; // List of enumerated gameport devices
|
|
extern WCHAR *pwszGameportBus[MAX_BUSSES]; // List of enumerated gameport buses
|
|
extern PJOY pAssigned[MAX_ASSIGNED]; // List of assigned devices
|
|
extern BYTE nAssigned; // Number of elements in pAssigned array
|
|
extern BYTE nTargetAssigned; // Number of elements expected when pending adds complete
|
|
extern BYTE nReEnum; // Counter used to decide when to reenumerate
|
|
|
|
extern GUID guidOccupied[MAX_BUSSES]; //Whether the gameport bus has been occupied.
|
|
|
|
extern BYTE nGameportBus, nGamingDevices;
|
|
|
|
extern IDirectInputJoyConfig *pDIJoyConfig;
|
|
extern short iItem;
|
|
extern short nFlags; // Flags set in CPANEL.CPP!
|
|
|
|
// extern functions defined in CPANEL.CPP
|
|
extern void OnContextMenu(WPARAM wParam, LPARAM lParam);
|
|
extern void OnHelp (LPARAM);
|
|
|
|
|
|
// local message handlers
|
|
static BOOL OnInitDialog(HWND, HWND, LPARAM);
|
|
static void OnClose(HWND);
|
|
static void OnCommand(HWND, int, HWND, UINT);
|
|
|
|
static char AddSelectedItem( HWND hDlg );
|
|
static BOOL UpdateListCtrl ( HWND hCtrl );
|
|
static char GetNextAvailableID( void );
|
|
static BOOL IsTypeActive( short *nArrayIndex );
|
|
static BOOL GetNextAvailableVIDPID(LPWSTR lpwszType );
|
|
//static BOOL IsCustomType(BYTE nIndex);
|
|
|
|
static void PostHScrollBar(HWND hCtrl, LPCTSTR lpStr, BYTE nStrLen);
|
|
|
|
extern const DWORD g_aHelpIDs[];
|
|
|
|
extern HINSTANCE ghInstance;
|
|
|
|
LPTSTR lpszAutoDetect;
|
|
|
|
const int NO_ITEM = -1;
|
|
#define MAX_ANALOG_BUTTONS 4
|
|
#define MAX_ANALOG_AXIS 4
|
|
|
|
// This will become a problem when we support > 500 ports!
|
|
#define AUTODETECT_PORT 100
|
|
|
|
// Consider achieving this from calculation of width of listview
|
|
static short iAddItem = NO_ITEM;
|
|
|
|
|
|
INT_PTR CALLBACK AddDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch( uMsg )
|
|
{
|
|
case WM_DESTROY:
|
|
DestroyIcon((HICON)SendMessage(hDlg, WM_GETICON, (WPARAM)ICON_SMALL, 0));
|
|
|
|
if( nGameportBus > 1 )
|
|
if( lpszAutoDetect )
|
|
delete[] (lpszAutoDetect);
|
|
break;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
// Click Drag service for PropSheets!
|
|
PostMessage(hDlg, WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lParam);
|
|
break;
|
|
|
|
case WM_INITDIALOG:
|
|
return(BOOL)HANDLE_WM_INITDIALOG(hDlg, wParam, lParam, OnInitDialog);
|
|
|
|
case WM_COMMAND:
|
|
HANDLE_WM_COMMAND(hDlg, wParam, lParam, OnCommand);
|
|
return(1);
|
|
|
|
case WM_VKEYTOITEM:
|
|
if( LOWORD(wParam) == VK_DELETE )
|
|
{
|
|
HWND hWnd = GetDlgItem(hDlg, IDC_DEVICE_LIST);
|
|
|
|
// determine if it's a custom type... if so... delete it
|
|
// Get the next object with the SELECTED attribute
|
|
iAddItem = (short)::SendMessage(hWnd, LB_GETCURSEL, 0, 0);
|
|
|
|
short nArrayIndex = (short)::SendMessage(hWnd, LB_GETITEMDATA, (WPARAM)iAddItem, 0);
|
|
|
|
// test to make sure they aren't trying to delete a standard type
|
|
if( *pwszTypeArray[nArrayIndex] == L'#' )
|
|
break;
|
|
|
|
// test that the device is a custom type (user or IHV defined)
|
|
// ISSUE-2001/03/29-timgill the number of times we retrieve the same data is ridiculous
|
|
LPDIJOYTYPEINFO lpdiJoyInfo = new (DIJOYTYPEINFO);
|
|
ASSERT (lpdiJoyInfo);
|
|
|
|
if( lpdiJoyInfo )
|
|
{
|
|
/*
|
|
* warning, abuse of S_OK == 0 == strcmp( identical strings ) ahead
|
|
*/
|
|
HRESULT CmpRes;
|
|
|
|
ZeroMemory(lpdiJoyInfo, sizeof(*lpdiJoyInfo));
|
|
|
|
lpdiJoyInfo->dwSize = sizeof(*lpdiJoyInfo);
|
|
|
|
/*
|
|
* Test the hardware ID
|
|
*/
|
|
CmpRes = pDIJoyConfig->GetTypeInfo(pwszTypeArray[nArrayIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_HARDWAREID);
|
|
if( SUCCEEDED( CmpRes ) )
|
|
{
|
|
#ifndef WINNT
|
|
if( lpdiJoyInfo->wszHardwareId[0] == L'\0' )
|
|
{
|
|
/*
|
|
* No hardware ID, so look for a callout VxD
|
|
* If there is none, we have a custom type.
|
|
*/
|
|
CmpRes = pDIJoyConfig->GetTypeInfo(pwszTypeArray[nArrayIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_CALLOUT);
|
|
CmpRes = ( SUCCEEDED( CmpRes ) && ( lpdiJoyInfo->wszCallout[0] == L'\0' ) )
|
|
? S_OK : S_FALSE;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
const WCHAR wszAnalogRoot[] = L"gameport\\vid_045e&pid_01";
|
|
|
|
CmpRes = (HRESULT)_wcsnicmp( lpdiJoyInfo->wszHardwareId, wszAnalogRoot,
|
|
(sizeof(wszAnalogRoot)/sizeof(wszAnalogRoot[0]) ) - 1 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CmpRes = S_FALSE;
|
|
}
|
|
|
|
// clean-up!
|
|
delete (lpdiJoyInfo);
|
|
|
|
if( CmpRes != S_OK )
|
|
{
|
|
// This is not an analog type so leave alone
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If we can't test the type, do nothing
|
|
break;
|
|
}
|
|
|
|
|
|
// test to make sure you are not deleting objects
|
|
if( IsTypeActive(&nArrayIndex) )
|
|
{
|
|
Error((short)IDS_GEN_AREYOUSURE_TITLE, (short)IDS_NO_REMOVE);
|
|
break;
|
|
}
|
|
|
|
// This buffer has to be big enough for the name and the "are you sure..." message!
|
|
LPTSTR pszMsg = new TCHAR[MAX_STR_LEN+STR_LEN_64];
|
|
ASSERT (pszMsg);
|
|
|
|
LPTSTR pszTitle = new TCHAR[STR_LEN_128];
|
|
ASSERT (pszTitle);
|
|
|
|
// Query user if they are sure!
|
|
VERIFY(LoadString(ghInstance, IDS_GEN_AREYOUSURE, pszTitle, MAX_STR_LEN));
|
|
|
|
LPTSTR pszTmp = new TCHAR[(short)SendMessage(hWnd, LB_GETTEXTLEN, (WPARAM)iAddItem, 0)+1];
|
|
ASSERT (pszTmp);
|
|
|
|
SendMessage(hWnd, LB_GETTEXT, (WPARAM)iAddItem, (LPARAM)(LPCTSTR)pszTmp);
|
|
|
|
wsprintf( pszMsg, pszTitle, pszTmp);
|
|
|
|
if( pszTmp )
|
|
delete[] (pszTmp);
|
|
|
|
VERIFY(LoadString(ghInstance, IDS_GEN_AREYOUSURE_TITLE, pszTitle, STR_LEN_128));
|
|
|
|
HRESULT hr = MessageBox(hWnd, pszMsg, pszTitle, MB_ICONQUESTION | MB_YESNO | MB_APPLMODAL);
|
|
|
|
if( pszMsg ) delete[] (pszMsg);
|
|
if( pszTitle ) delete[] (pszTitle);
|
|
|
|
if( IDYES == hr )
|
|
{
|
|
|
|
if( SUCCEEDED(hr = pDIJoyConfig->Acquire()) )
|
|
{
|
|
// traverse the list and delete any configuration that may have this type assigned to it!
|
|
//DeleteAssignedType( pwszTypeArray[nArrayIndex] );
|
|
|
|
// returns E_ACCESSDENIED if it's a default item.
|
|
hr = pDIJoyConfig->DeleteType(pwszTypeArray[nArrayIndex]);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
pDIJoyConfig->Unacquire();
|
|
|
|
// the dec is for the zero based device list!
|
|
// decrement the indexes
|
|
nGamingDevices--;
|
|
|
|
// don't move if you're on the last entry!
|
|
if( nArrayIndex != nGamingDevices )
|
|
{
|
|
// To avoid deleting and recreating...
|
|
// Let's see if we have room to put this string!
|
|
BYTE nLen = (BYTE)wcslen(pwszTypeArray[nArrayIndex])+1;
|
|
|
|
// Make sure pwszTypeArray[nArrayIndex] is larger than pwszTypeArray[nCount]
|
|
if( nLen < (BYTE)wcslen(pwszTypeArray[nGamingDevices])+1 )
|
|
{
|
|
if( pwszTypeArray[nArrayIndex] )
|
|
free(pwszTypeArray[nArrayIndex]);
|
|
|
|
pwszTypeArray[nArrayIndex] = _wcsdup(pwszTypeArray[nGamingDevices]);
|
|
ASSERT (pwszTypeArray[nArrayIndex]);
|
|
}
|
|
// move the end element to the place of the deleted one
|
|
else wcsncpy(pwszTypeArray[nArrayIndex], pwszTypeArray[nGamingDevices], wcslen(pwszTypeArray[nGamingDevices])+1);
|
|
|
|
// update the extra memory to reflect the new index!
|
|
// First, find the item in the listbox and get the index...
|
|
LPDIJOYTYPEINFO_DX5 lpdiJoyInfo = new (DIJOYTYPEINFO_DX5);
|
|
ASSERT (lpdiJoyInfo);
|
|
|
|
ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
|
|
|
|
lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
|
|
|
|
if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[nArrayIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_DISPLAYNAME)) )
|
|
{
|
|
char n = (char)SendMessage(hWnd, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)lpdiJoyInfo->wszDisplayName);
|
|
SendMessage(hWnd, LB_SETITEMDATA, (WPARAM)n, (LPARAM)nArrayIndex);
|
|
}
|
|
|
|
// clean-up!
|
|
if( lpdiJoyInfo )
|
|
delete (lpdiJoyInfo);
|
|
}
|
|
|
|
// delete the end element from the array
|
|
if( pwszTypeArray[nGamingDevices] )
|
|
{
|
|
free(pwszTypeArray[nGamingDevices]);
|
|
pwszTypeArray[nGamingDevices] = 0;
|
|
}
|
|
|
|
// Remove the entry from the list control
|
|
SendMessage(hWnd, LB_DELETESTRING, (WPARAM)iAddItem, 0);
|
|
|
|
// Enable the buttons!
|
|
if( nGamingDevices < MAX_DEVICES-1 )
|
|
{
|
|
HWND hParent = GetParent(hWnd);
|
|
ASSERT (hParent);
|
|
|
|
PostDlgItemEnableWindow(hParent, IDC_CUSTOM, TRUE);
|
|
PostDlgItemEnableWindow(hParent, IDC_ADD_NEW, TRUE);
|
|
}
|
|
|
|
if( iAddItem != nGamingDevices-1 )
|
|
iAddItem--;
|
|
|
|
// Set the focus to the next available item
|
|
PostMessage(hWnd, LB_SETCURSEL, (WPARAM)(iAddItem == NO_ITEM) ? 0 : iAddItem, 0);
|
|
}
|
|
}
|
|
break;
|
|
} else return(-1);
|
|
|
|
// case WM_NOTIFY:
|
|
/// return HANDLE_WM_NOTIFY(hDlg, wParam, lParam, OnNotify);
|
|
|
|
case WM_HELP:
|
|
OnHelp(lParam);
|
|
return(1);
|
|
|
|
case WM_CONTEXTMENU:
|
|
OnContextMenu(wParam, lParam);
|
|
return(1);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
BOOL OnInitDialog(HWND hDlg, HWND hWnd, LPARAM lParam)
|
|
{
|
|
HICON hIcon = (HICON)LoadImage(ghInstance, MAKEINTRESOURCE(IDI_CPANEL), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
|
|
ASSERT (hIcon);
|
|
|
|
if( hIcon )
|
|
::PostMessage(hDlg, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
|
|
|
|
if( nFlags & ON_NT )
|
|
DestroyWindow(GetDlgItem(hDlg, IDC_WDM));
|
|
else
|
|
{
|
|
HKEY hKey;
|
|
|
|
// remove the WDM flag unless otherwise specified!
|
|
if( RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Control\\MediaResources\\joystick\\<FixedKey>"), &hKey) == ERROR_SUCCESS )
|
|
{
|
|
DWORD n;
|
|
DWORD dwSize = sizeof (DWORD);
|
|
|
|
if( RegQueryValueEx(hKey, TEXT("UseWDM"), 0, 0, (LPBYTE)&n, &dwSize) == ERROR_SUCCESS )
|
|
{
|
|
if( n )
|
|
DestroyWindow(GetDlgItem(hDlg, IDC_WDM));
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
|
|
// a simple debug test to verify that the template hasn't gotten DIALOGEX style again!
|
|
HWND hCtrl = GetDlgItem(hDlg, IDC_DEVICE_LIST);
|
|
ASSERT (hCtrl);
|
|
|
|
// Fill up the Device List
|
|
if( !UpdateListCtrl(hCtrl) )
|
|
{
|
|
TRACE(TEXT("JOY.CPL: ADD.CPP: Failed UpdateListCtrl!\n"));
|
|
return(FALSE);
|
|
}
|
|
|
|
// If there is only one, don't confuse the user with the combo box
|
|
if( nGameportBus > 1 )
|
|
{
|
|
// Allocate for AutoDetect Gameport!
|
|
lpszAutoDetect = new (TCHAR[STR_LEN_32]);
|
|
ASSERT (lpszAutoDetect);
|
|
|
|
VERIFY(LoadString(ghInstance, IDS_AUTO_DETECT, lpszAutoDetect, STR_LEN_32));
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_GAMEPORTLIST);
|
|
ASSERT (hCtrl);
|
|
|
|
if( !PopulatePortList(hCtrl) )
|
|
{
|
|
TRACE(TEXT("JOY.CPL: ADD.CPP: Failed PopulatePortList!\n"));
|
|
return(FALSE);
|
|
}
|
|
|
|
LPDIJOYTYPEINFO lpdiJoyInfo = new DIJOYTYPEINFO;
|
|
ASSERT (lpdiJoyInfo);
|
|
|
|
ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO));
|
|
|
|
lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO);
|
|
|
|
VERIFY(SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[0], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_FLAGS1)));
|
|
|
|
// Search for AutoDetect in the list!
|
|
char nIndex = (char)::SendMessage(hCtrl, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCTSTR)lpszAutoDetect);
|
|
|
|
// If it's got the JOYTYPE_NOAUTODETECTGAMEPORT flag, remove AutoDetect from the ListCtrl
|
|
if( lpdiJoyInfo->dwFlags1 & JOYTYPE_NOAUTODETECTGAMEPORT )
|
|
{
|
|
// it could fail because the entry is not available...
|
|
if( nIndex != CB_ERR )
|
|
::SendMessage(hCtrl, CB_DELETESTRING, (WPARAM)nIndex, 0);
|
|
|
|
}
|
|
// Otherwise, verify that AutoDetect is present... if not, add it!
|
|
else
|
|
{
|
|
// it could fail because the entry is not available...
|
|
if( nIndex == CB_ERR )
|
|
::SendMessage(hCtrl, CB_SETITEMDATA, ::SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpszAutoDetect), AUTODETECT_PORT);
|
|
}
|
|
|
|
if( lpdiJoyInfo )
|
|
delete (lpdiJoyInfo);
|
|
|
|
SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
|
|
|
|
SetWindowPos( GetDlgItem(hDlg, IDC_GAMEPORT), NULL, NULL, NULL, NULL, NULL,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
|
|
}
|
|
|
|
// blj: Warning Message that you can't add any more devices!
|
|
if( nGamingDevices == MAX_DEVICES-1 )
|
|
{
|
|
// Disable the Custom Button!
|
|
PostDlgItemEnableWindow(hDlg, IDC_CUSTOM, FALSE);
|
|
PostDlgItemEnableWindow(hDlg, IDC_ADD_NEW, FALSE);
|
|
|
|
// Give the user a error message!
|
|
Error((short)IDS_MAX_DEVICES_TITLE, (short)IDS_MAX_DEVICES_MSG);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTION: OnCommand(HWND hDlg, int id, HWND hWndCtl, UINT code)
|
|
//
|
|
// PARAMETERS: hDlg -
|
|
// id -
|
|
// hWndCtl -
|
|
// code -
|
|
//
|
|
// PURPOSE: WM_COMMAND message handler
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void OnCommand(HWND hDlg, int id, HWND hWndCtl, UINT code)
|
|
{
|
|
switch( id )
|
|
{
|
|
case IDC_ADD_NEW:
|
|
if( SUCCEEDED(pDIJoyConfig->AddNewHardware(hDlg, GUID_MediaClass)) )
|
|
{
|
|
ClearArrays();
|
|
|
|
if( FAILED(pDIJoyConfig->EnumTypes((LPDIJOYTYPECALLBACK)DIEnumJoyTypeProc, NULL)) )
|
|
{
|
|
TRACE(TEXT("JOY.CPL: ADD.CPP: Failed BuildEnumList!\n"));
|
|
return;
|
|
}
|
|
|
|
// Warning Message that you can't add any more devices!
|
|
if( nGamingDevices == MAX_DEVICES-1 )
|
|
{
|
|
// Disable the Custom Button!
|
|
PostDlgItemEnableWindow(hDlg, IDC_CUSTOM, FALSE);
|
|
PostDlgItemEnableWindow(hDlg, IDC_ADD_NEW, FALSE);
|
|
|
|
// Give the user a error message!
|
|
Error((short)IDS_MAX_DEVICES_TITLE, (short)IDS_MAX_DEVICES_MSG);
|
|
}
|
|
|
|
if( !UpdateListCtrl(GetDlgItem(hDlg, IDC_DEVICE_LIST)) )
|
|
{
|
|
TRACE(TEXT("JOY.CPL: ADD.CPP: Failed to update the list control on the add page!\n"));
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDC_CUSTOM:
|
|
// DialogBox returns either IDCANCEL or the index into the list of
|
|
// defined types!
|
|
if( IDOK == DialogBox(ghInstance, (PTSTR)IDD_CUSTOM, hDlg, CustomDialogProc) )
|
|
{
|
|
HWND hCtrl = GetDlgItem(hDlg, IDC_DEVICE_LIST);
|
|
|
|
// blj: Warning Message that you can't add any more devices!
|
|
if( nGamingDevices == MAX_DEVICES-1 )
|
|
{
|
|
// Disable the Custom Button!
|
|
PostDlgItemEnableWindow(hDlg, IDC_CUSTOM, FALSE);
|
|
|
|
// Give the user a error message!
|
|
Error((short)IDS_MAX_DEVICES_TITLE, (short)IDS_MAX_DEVICES_MSG);
|
|
}
|
|
|
|
// Now, put the focus on the newly created item!
|
|
LPDIJOYTYPEINFO_DX5 lpdiJoyInfo = new (DIJOYTYPEINFO_DX5);
|
|
ASSERT (lpdiJoyInfo);
|
|
|
|
ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
|
|
|
|
lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
|
|
|
|
// Get nGamingDevices from pwszTypeArray
|
|
// Subtract 1 from nGamingDevices because the list is 0 based!
|
|
if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[nGamingDevices-1], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_DISPLAYNAME | DITC_REGHWSETTINGS)) )
|
|
{
|
|
#ifdef _UNICODE
|
|
iAddItem = (short)SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpdiJoyInfo->wszDisplayName);
|
|
SendMessage(hCtrl, LB_SETITEMDATA, (WPARAM)iAddItem, (LPARAM)nGamingDevices-1);
|
|
PostHScrollBar(hCtrl, lpdiJoyInfo->wszDisplayName, (BYTE)wcslen(lpdiJoyInfo->wszDisplayName));
|
|
#else
|
|
USES_CONVERSION;
|
|
iAddItem = (short)SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)W2A(lpdiJoyInfo->wszDisplayName));
|
|
SendMessage(hCtrl, LB_SETITEMDATA, (WPARAM)iAddItem, (LPARAM)nGamingDevices-1);
|
|
PostHScrollBar(hCtrl, W2A(lpdiJoyInfo->wszDisplayName), (BYTE)wcslen(lpdiJoyInfo->wszDisplayName));
|
|
#endif
|
|
// SetFocus to that item!
|
|
SendMessage(hCtrl, LB_SETCURSEL, (WPARAM)iAddItem, 0);
|
|
|
|
OnCommand(hDlg, IDC_DEVICE_LIST, 0, LBN_SELCHANGE);
|
|
}
|
|
|
|
|
|
// clean-up!
|
|
if( lpdiJoyInfo )
|
|
delete (lpdiJoyInfo);
|
|
}
|
|
break;
|
|
|
|
case IDC_DEVICE_LIST:
|
|
if( code == LBN_SELCHANGE )
|
|
{
|
|
iAddItem = (short)SendMessage(hWndCtl, LB_GETCURSEL, 0, 0);
|
|
|
|
BYTE nArrayID = (BYTE)SendMessage(hWndCtl, LB_GETITEMDATA, (WPARAM)iAddItem, 0);
|
|
|
|
LPDIJOYTYPEINFO lpdiJoyInfo = new DIJOYTYPEINFO;
|
|
ASSERT (lpdiJoyInfo);
|
|
|
|
ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO));
|
|
|
|
lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO);
|
|
|
|
DWORD dwFlags = DITC_REGHWSETTINGS;
|
|
|
|
if( nGameportBus > 1 )
|
|
dwFlags |= DITC_FLAGS1;
|
|
|
|
VERIFY(SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[nArrayID], (LPDIJOYTYPEINFO)lpdiJoyInfo, dwFlags)));
|
|
/*
|
|
if (nGameportBus > 1)
|
|
{
|
|
HWND hCtrl = GetDlgItem(hDlg, IDC_GAMEPORTLIST);
|
|
|
|
// Search for AutoDetect in the list!
|
|
char nIndex = (char)::SendMessage(hCtrl, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCTSTR)lpszAutoDetect);
|
|
|
|
// If it's got the JOYTYPE_NOAUTODETECTGAMEPORT flag, remove AutoDetect from the ListCtrl
|
|
if (lpdiJoyInfo->dwFlags1 & JOYTYPE_NOAUTODETECTGAMEPORT)
|
|
{
|
|
// it could fail because the entry is not available...
|
|
if (nIndex != CB_ERR)
|
|
::SendMessage(hCtrl, CB_DELETESTRING, (WPARAM)nIndex, 0);
|
|
|
|
}
|
|
// Otherwise, verify that AutoDetect is present... if not, add it!
|
|
else
|
|
{
|
|
// it could fail because the entry is not available...
|
|
if (nIndex == CB_ERR)
|
|
::SendMessage(hCtrl, CB_SETITEMDATA, ::SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpszAutoDetect), AUTODETECT_PORT);
|
|
}
|
|
|
|
::PostMessage(hCtrl, CB_SETCURSEL, (WPARAM)0, (LPARAM)0);
|
|
}
|
|
*/
|
|
|
|
PostDlgItemEnableWindow(hDlg, IDC_JOY1HASRUDDER, (lpdiJoyInfo->hws.dwFlags & JOY_HWS_HASR) ? FALSE : TRUE);
|
|
|
|
if( lpdiJoyInfo )
|
|
delete (lpdiJoyInfo);
|
|
|
|
break;
|
|
}
|
|
|
|
if( code != LBN_DBLCLK )
|
|
break;
|
|
|
|
case IDOK:
|
|
iAddItem = (short)SendDlgItemMessage(hDlg, IDC_DEVICE_LIST, LB_GETCURSEL, 0, 0);
|
|
|
|
if( iAddItem == NO_ITEM )
|
|
break;
|
|
|
|
// Check to see if they have a GamePortList
|
|
{
|
|
HWND hCtrl = GetDlgItem(hDlg, IDC_GAMEPORTLIST);
|
|
ASSERT (hCtrl);
|
|
|
|
if( IsWindowVisible(hCtrl) )
|
|
{
|
|
// Check to see if the user has a port selected!
|
|
if( SendMessage(hCtrl, CB_GETCURSEL, 0, 0) == CB_ERR )
|
|
{
|
|
// blj: TODO: Clear this message with UE
|
|
Error((short)IDS_NO_GAMEPORT_TITLE, (short)IDS_NO_GAMEPORT);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
iItem = 0;
|
|
AddSelectedItem(hDlg);
|
|
|
|
case IDCANCEL:
|
|
EndDialog(hDlg, id);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// Custom Dialog procedure
|
|
INT_PTR CALLBACK CustomDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static LPWSTR lpwszVIDPID;
|
|
|
|
switch( uMsg )
|
|
{
|
|
case WM_DESTROY:
|
|
{
|
|
HICON hIcon = (HICON)SendMessage(hDlg, WM_GETICON, (WPARAM)ICON_SMALL, 0);
|
|
DestroyIcon(hIcon);
|
|
}
|
|
break;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
// Click Drag service for PropSheets!
|
|
PostMessage(hDlg, WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lParam);
|
|
break;
|
|
|
|
case WM_HELP:
|
|
OnHelp(lParam);
|
|
return(1);
|
|
|
|
case WM_CONTEXTMENU:
|
|
OnContextMenu(wParam, lParam);
|
|
return(TRUE);
|
|
|
|
case WM_INITDIALOG:
|
|
// Set up the Buttons and Axis combo boxs!
|
|
{
|
|
HICON hIcon = (HICON)LoadImage(ghInstance, MAKEINTRESOURCE(IDI_CPANEL), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
|
|
ASSERT (hIcon);
|
|
|
|
if( hIcon )
|
|
::PostMessage(hDlg, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
|
|
|
|
// Return if no available VID/PIDs found!
|
|
lpwszVIDPID = new (WCHAR[STR_LEN_32]);
|
|
ASSERT (lpwszVIDPID);
|
|
|
|
pDIJoyConfig->Acquire();
|
|
|
|
if( !GetNextAvailableVIDPID(lpwszVIDPID) )
|
|
{
|
|
if( lpwszVIDPID )
|
|
delete[] (lpwszVIDPID);
|
|
|
|
EndDialog(hDlg, IDCANCEL);
|
|
|
|
// Let the user know that they need to remove some "Custom" devices!
|
|
Error((short)IDS_NO_NAME_TITLE, (short)IDS_NOAVAILABLEVIDPID );
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
// init id list
|
|
BYTE nButtons = MAX_ANALOG_BUTTONS;
|
|
TCHAR szTmp[3];
|
|
|
|
HWND hCtrl = GetDlgItem(hDlg, IDC_COMBO_BUTTONS);
|
|
|
|
// Fill the Buttons combo...
|
|
do
|
|
{
|
|
itoa(nButtons, (LPTSTR)&szTmp);
|
|
SendMessage(hCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)(LPCTSTR)szTmp);
|
|
} while( nButtons-- );
|
|
|
|
// Set Default to four buttons
|
|
SendMessage(hCtrl, CB_SETCURSEL, MAX_ANALOG_BUTTONS, 0);
|
|
|
|
// Use nButtons for Axis...
|
|
nButtons = MAX_ANALOG_AXIS;
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_COMBO_AXIS);
|
|
|
|
// Fill the Axis combo...
|
|
do
|
|
{
|
|
itoa(nButtons--, (LPTSTR)&szTmp);
|
|
SendMessage(hCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)(LPCTSTR)szTmp);
|
|
} while( nButtons > 1 );
|
|
|
|
// Set Default to two Axis
|
|
SendMessage(hCtrl, CB_SETCURSEL, 0, 0);
|
|
}
|
|
|
|
::PostMessage(GetDlgItem(hDlg, IDC_SPECIAL_JOYSTICK), BM_SETCHECK, BST_CHECKED, 0);
|
|
|
|
SendDlgItemMessage(hDlg, IDC_EDIT_NAME, EM_LIMITTEXT, (WPARAM)MAX_STR_LEN, 0);
|
|
return(1);
|
|
|
|
case WM_COMMAND:
|
|
switch( LOWORD(wParam) )
|
|
{
|
|
case IDOK:
|
|
{
|
|
// defines for error states!
|
|
#define DUPLICATE_NAME 0x01
|
|
#define NO_NAME 0x02
|
|
#define INVALID_NAME 0x04
|
|
|
|
BYTE nLen = (BYTE)SendDlgItemMessage(hDlg, IDC_EDIT_NAME, EM_LINELENGTH, 0, 0);
|
|
|
|
LPTSTR pszTypeName = NULL;
|
|
|
|
if( nLen )
|
|
{
|
|
pszTypeName = new (TCHAR[nLen+1]);
|
|
ASSERT (pszTypeName);
|
|
|
|
// Get the Type/Display Name
|
|
GetDlgItemText(hDlg, IDC_EDIT_NAME, (LPTSTR)pszTypeName, nLen+1);
|
|
|
|
if( _tcschr(pszTypeName, TEXT('\\')) )
|
|
nLen = INVALID_NAME;
|
|
else
|
|
{
|
|
// Make sure it's not a duplicate!
|
|
// start of fix #9269
|
|
LPDIJOYTYPEINFO_DX5 lpdiGetJoyInfo = new DIJOYTYPEINFO_DX5;
|
|
ASSERT (lpdiGetJoyInfo);
|
|
|
|
ZeroMemory(lpdiGetJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
|
|
|
|
lpdiGetJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
|
|
|
|
// Clean-up nLen!
|
|
BYTE n = nLen = 0;
|
|
|
|
// Search for a Duplicate Display Name!!!
|
|
while( pwszTypeArray[n] )
|
|
{
|
|
if( FAILED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[n++], (LPDIJOYTYPEINFO)lpdiGetJoyInfo, DITC_DISPLAYNAME)) )
|
|
{
|
|
TRACE(TEXT("JOY.CPL: ADD.CPP: GetTypeInfo Failed!\n"));
|
|
continue;
|
|
}
|
|
#ifndef _UNICODE
|
|
USES_CONVERSION;
|
|
#endif
|
|
|
|
if( _tcsncmp(pszTypeName,
|
|
#ifdef _UNICODE
|
|
lpdiGetJoyInfo->wszDisplayName,
|
|
#else
|
|
W2A(lpdiGetJoyInfo->wszDisplayName),
|
|
#endif
|
|
wcslen(lpdiGetJoyInfo->wszDisplayName)+1) == 0 )
|
|
{
|
|
nLen = DUPLICATE_NAME;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( lpdiGetJoyInfo ) {
|
|
delete (lpdiGetJoyInfo);
|
|
}
|
|
// end of fix #9269
|
|
|
|
}
|
|
} else nLen = NO_NAME;
|
|
|
|
// Check for an error!
|
|
if( nLen )
|
|
{
|
|
if( pszTypeName )
|
|
delete[] (pszTypeName);
|
|
|
|
// Give the user the appropriate error!
|
|
switch( nLen )
|
|
{
|
|
case DUPLICATE_NAME:
|
|
Error((SHORT)IDS_NO_NAME_TITLE, (SHORT)IDS_DUPLICATE_TYPE);
|
|
break;
|
|
|
|
case NO_NAME:
|
|
Error((short)IDS_NO_NAME_TITLE, (short)IDS_NO_NAME);
|
|
break;
|
|
|
|
case INVALID_NAME:
|
|
Error((short)IDS_NO_NAME_TITLE, (short)IDS_INVALID_NAME);
|
|
break;
|
|
}
|
|
|
|
// Set Focus to the Dialog
|
|
SetFocus(hDlg);
|
|
|
|
HWND hCtrl = GetDlgItem(hDlg, IDC_EDIT_NAME);
|
|
ASSERT (hCtrl);
|
|
|
|
// Set Focus to the Control
|
|
SetFocus(hCtrl);
|
|
|
|
// hilite the error
|
|
PostMessage(hCtrl, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
// set the type information
|
|
LPDIJOYTYPEINFO lpdiJoyInfo = new (DIJOYTYPEINFO);
|
|
ASSERT (lpdiJoyInfo);
|
|
|
|
ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO));
|
|
|
|
lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO);
|
|
|
|
#ifndef _UNICODE
|
|
USES_CONVERSION;
|
|
#endif
|
|
|
|
// Set the Display Name
|
|
wcsncpy(lpdiJoyInfo->wszDisplayName,
|
|
#ifdef _UNICODE
|
|
pszTypeName,
|
|
#else
|
|
A2W(pszTypeName),
|
|
#endif // _UNICODE
|
|
lstrlen(pszTypeName)+1);
|
|
|
|
if( pszTypeName )
|
|
delete[] (pszTypeName);
|
|
|
|
// Set the GUID - default to LegacyServer
|
|
// Per Marcus, we don't want to do this anymore!
|
|
//lpdiJoyInfo->clsidConfig = CLSID_LegacyServer;
|
|
|
|
// Set the Hardware Settings
|
|
lpdiJoyInfo->hws.dwNumButtons = (DWORD)SendDlgItemMessage(hDlg, IDC_COMBO_BUTTONS, CB_GETCURSEL, 0, 0);
|
|
|
|
switch( SendDlgItemMessage(hDlg, IDC_COMBO_AXIS, CB_GETCURSEL, 0, 0) )
|
|
{
|
|
// R Axis
|
|
case 1:
|
|
// Check to see which button got checked...
|
|
lpdiJoyInfo->hws.dwFlags |= ::SendMessage(GetDlgItem(hDlg, IDC_HASRUDDER), BM_GETCHECK, 0, 0) ? JOY_HWS_HASR : JOY_HWS_HASZ;
|
|
break;
|
|
|
|
// Z Axis
|
|
case 2:
|
|
lpdiJoyInfo->hws.dwFlags |= JOY_HWS_HASR;
|
|
lpdiJoyInfo->hws.dwFlags |= JOY_HWS_HASZ;
|
|
break;
|
|
|
|
// X/Y are default!
|
|
default:
|
|
lpdiJoyInfo->hws.dwFlags = 0;
|
|
break;
|
|
}
|
|
|
|
lpdiJoyInfo->hws.dwFlags |= ::SendMessage(GetDlgItem(hDlg, IDS_CUSTOM_HASPOV), BM_GETCHECK, 0, 0) ? JOY_HWS_HASPOV : 0;
|
|
|
|
// Get Special char's status
|
|
lpdiJoyInfo->hws.dwFlags |= ::SendMessage(GetDlgItem(hDlg, IDC_SPECIAL_JOYSTICK), BM_GETCHECK, 0, 0) ? 0
|
|
: ::SendMessage(GetDlgItem(hDlg, IDC_SPECIAL_PAD), BM_GETCHECK, 0, 0) ? JOY_HWS_ISGAMEPAD
|
|
: ::SendMessage(GetDlgItem(hDlg, IDC_SPECIAL_AUTO), BM_GETCHECK, 0, 0) ? JOY_HWS_ISCARCTRL
|
|
: JOY_HWS_ISYOKE; // default to Yoke!
|
|
|
|
// Set up wszHardwareId
|
|
wcscpy(lpdiJoyInfo->wszHardwareId, L"GamePort\\");
|
|
|
|
// This blocks the Huge DisplayName bug!
|
|
// DINPUT change requires VID/PID at the end of the hardware ID... it was
|
|
//StrNCatW(lpdiJoyInfo->wszHardwareId, lpwszVIDPID, 245);
|
|
// Win95 does not like StrNCatW, we will use wcsncat
|
|
|
|
wcsncat(lpdiJoyInfo->wszHardwareId, lpwszVIDPID, 245);
|
|
|
|
if( SUCCEEDED(pDIJoyConfig->Acquire()) )
|
|
{
|
|
#ifdef _UNICODE
|
|
if( FAILED(pDIJoyConfig->SetTypeInfo(lpwszVIDPID, lpdiJoyInfo, DITC_DISPLAYNAME | DITC_CLSIDCONFIG | DITC_REGHWSETTINGS | DITC_HARDWAREID)) )
|
|
#else
|
|
if( FAILED(pDIJoyConfig->SetTypeInfo(lpwszVIDPID, lpdiJoyInfo, DITC_DISPLAYNAME | DITC_CLSIDCONFIG | DITC_REGHWSETTINGS ) ) )
|
|
#endif
|
|
{
|
|
#ifdef _DEBUG
|
|
OutputDebugString(TEXT("JOY.CPL: ADD.CPP: CustomDlgProc: SetTypeInfo Failed!\n"));
|
|
#endif
|
|
}
|
|
|
|
// Create the memory for the Custom device and stick it into the array!
|
|
pwszTypeArray[nGamingDevices++] = _wcsdup(lpwszVIDPID);
|
|
|
|
pDIJoyConfig->Unacquire();
|
|
}
|
|
|
|
if( lpdiJoyInfo ) delete (lpdiJoyInfo);
|
|
}
|
|
|
|
case IDCANCEL:
|
|
if( lpwszVIDPID )
|
|
delete[] (lpwszVIDPID);
|
|
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
break;
|
|
|
|
case IDC_SPECIAL_JOYSTICK:
|
|
case IDC_SPECIAL_YOKE:
|
|
case IDC_SPECIAL_PAD:
|
|
case IDC_SPECIAL_AUTO:
|
|
CheckRadioButton(hDlg, IDC_SPECIAL_JOYSTICK, IDC_SPECIAL_AUTO, IDC_SPECIAL_JOYSTICK);
|
|
break;
|
|
|
|
case IDC_COMBO_AXIS:
|
|
// Show/Hide IDC_HASRUDDER based on Selection of 3 Axis
|
|
if( HIWORD(wParam) == CBN_SELCHANGE )
|
|
{
|
|
const USHORT nCtrlArray[] = {IDC_HASRUDDER, IDC_HASZAXIS};
|
|
BYTE nCtrls = sizeof(nCtrlArray)/sizeof(short);
|
|
|
|
// the '1' in the comparison is because the CB is Zero based!
|
|
BOOL bShow = (BOOL)(SendDlgItemMessage(hDlg, IDC_COMBO_AXIS, CB_GETCURSEL, 0, 0) == 1);
|
|
|
|
do
|
|
{
|
|
SetWindowPos( GetDlgItem(hDlg, nCtrlArray[--nCtrls]), NULL, NULL, NULL, NULL, NULL,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | ((bShow) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
|
|
} while( nCtrls );
|
|
|
|
if( bShow )
|
|
::PostMessage(GetDlgItem(hDlg, IDC_HASZAXIS), BM_SETCHECK, BST_CHECKED, 0);
|
|
}
|
|
break;
|
|
}
|
|
return(1);
|
|
|
|
case WM_CLOSE:
|
|
EndDialog(hDlg, 0);
|
|
return(1);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
char GetNextAvailableID( void )
|
|
{
|
|
LPDIJOYCONFIG_DX5 pJoyConfig = new (DIJOYCONFIG_DX5);
|
|
ASSERT (pJoyConfig);
|
|
|
|
ZeroMemory(pJoyConfig, sizeof(DIJOYCONFIG_DX5));
|
|
|
|
pJoyConfig->dwSize = sizeof (DIJOYCONFIG_DX5);
|
|
|
|
char i = 0;
|
|
|
|
do
|
|
{
|
|
switch( pDIJoyConfig->GetConfig(i, (LPDIJOYCONFIG)pJoyConfig, DIJC_REGHWCONFIGTYPE) )
|
|
{
|
|
case S_FALSE:
|
|
case DIERR_NOMOREITEMS:
|
|
case DIERR_NOTFOUND:
|
|
case E_FAIL:
|
|
goto EXIT;
|
|
|
|
|
|
default:
|
|
i++;
|
|
break;
|
|
}
|
|
} while( i < NUMJOYDEVS );
|
|
|
|
i = -1;
|
|
|
|
// And it's Error time!
|
|
Error((short)IDS_NO_IDS_TITLE, (short)IDS_NO_IDS);
|
|
|
|
EXIT:
|
|
if( pJoyConfig )
|
|
delete (pJoyConfig);
|
|
|
|
return(i);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTION: AddSelectedItem(HWND hDlg)
|
|
//
|
|
// PARAMETERS: hDlg - Handle to page
|
|
//
|
|
// PURPOSE: Adds selected item from List box.
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
char AddSelectedItem( HWND hDlg )
|
|
{
|
|
static BYTE n;
|
|
DWORD dwFlags;
|
|
HRESULT hr;
|
|
int nID;
|
|
#ifdef SUPPORT_TWO_2A2B
|
|
BOOL f2_2A2B = FALSE;
|
|
#endif
|
|
|
|
nID = GetNextAvailableID();
|
|
|
|
// GetNextAvailableID returns -1 if it fails!
|
|
if( nID < 0 )
|
|
return((char)nID);
|
|
|
|
// Type info
|
|
LPDIJOYTYPEINFO_DX5 lpdiJoyInfo = new (DIJOYTYPEINFO_DX5);
|
|
ASSERT (lpdiJoyInfo);
|
|
|
|
ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
|
|
|
|
lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
|
|
|
|
BYTE nArrayID = (BYTE)SendDlgItemMessage(hDlg, IDC_DEVICE_LIST, LB_GETITEMDATA, (WPARAM)iAddItem, 0);
|
|
|
|
VERIFY(SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[nArrayID], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_REGHWSETTINGS | DITC_CALLOUT | DITC_DISPLAYNAME)));
|
|
|
|
#ifdef SUPPORT_TWO_2A2B
|
|
#ifndef _UNICODE
|
|
if( wcscmp( pwszTypeArray[nArrayID], L"#<" ) == 0 ) {
|
|
f2_2A2B = TRUE;
|
|
lpdiJoyInfo->hws.dwFlags = 0;
|
|
pwszTypeArray[nArrayID][1] = L'2';
|
|
} else {
|
|
f2_2A2B = FALSE;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
LPDIJOYCONFIG pTempJoyConfig = new DIJOYCONFIG;
|
|
ASSERT (pTempJoyConfig);
|
|
|
|
ZeroMemory(pTempJoyConfig, sizeof(DIJOYCONFIG));
|
|
|
|
pTempJoyConfig->dwSize = sizeof (DIJOYCONFIG);
|
|
|
|
pTempJoyConfig->hwc.hws = lpdiJoyInfo->hws;
|
|
pTempJoyConfig->hwc.hws.dwFlags |= JOY_HWS_ISANALOGPORTDRIVER;
|
|
|
|
// Do the Rudder Flags!
|
|
if( ::SendMessage(GetDlgItem(hDlg, IDC_JOY1HASRUDDER), BM_GETCHECK, 0, 0) )
|
|
{
|
|
pTempJoyConfig->hwc.hws.dwFlags |= JOY_HWS_HASR;
|
|
pTempJoyConfig->hwc.dwUsageSettings |= JOY_US_HASRUDDER;
|
|
}
|
|
|
|
// set default to present
|
|
pTempJoyConfig->hwc.dwUsageSettings |= JOY_US_PRESENT;
|
|
|
|
pTempJoyConfig->hwc.dwType = nArrayID;
|
|
|
|
wcsncpy(pTempJoyConfig->wszCallout, lpdiJoyInfo->wszCallout, wcslen(lpdiJoyInfo->wszCallout)+1);
|
|
|
|
wcsncpy(pTempJoyConfig->wszType, pwszTypeArray[nArrayID], wcslen(pwszTypeArray[nArrayID])+1);
|
|
|
|
LPWSTR lpszPortName = NULL;
|
|
|
|
if( SUCCEEDED(pDIJoyConfig->Acquire()) )
|
|
{
|
|
// This stops Memphis and gameport-less systems!!!
|
|
if( nGameportBus )
|
|
{
|
|
|
|
// no point asking the Combo box if there's really no choice!
|
|
if( nGameportBus > 1 )
|
|
{
|
|
n = (BYTE)SendDlgItemMessage(hDlg, IDC_GAMEPORTLIST, CB_GETITEMDATA,
|
|
(WPARAM)SendDlgItemMessage(hDlg, IDC_GAMEPORTLIST, CB_GETCURSEL, 0, 0), 0);
|
|
} else
|
|
{
|
|
n = 0;
|
|
}
|
|
|
|
|
|
if( n == AUTODETECT_PORT )
|
|
{
|
|
#ifdef _DEBUG
|
|
OutputDebugString(TEXT("JOY.CPL: ADD.CPP: Selected Port is AutoDetect!\n"));
|
|
#endif
|
|
pTempJoyConfig->guidGameport = GUID_GAMEENUM_BUS_ENUMERATOR;
|
|
} else
|
|
{
|
|
// Zero the memory because the buffer still contains the old data!!!
|
|
ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
|
|
lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
|
|
|
|
#ifdef _DEBUG
|
|
TRACE(TEXT("JOY.CPL: ADD.CPP: Port List index is %d or %s!\n"), n, pwszGameportBus[n]);
|
|
#endif
|
|
if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszGameportBus[n], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_CLSIDCONFIG | DITC_DISPLAYNAME)) )
|
|
{
|
|
pTempJoyConfig->guidGameport = lpdiJoyInfo->clsidConfig;
|
|
lpszPortName = _wcsdup(lpdiJoyInfo->wszDisplayName);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// This is for Memphis and odd case NT systems!
|
|
if( pTempJoyConfig->guidGameport == GUID_NULL )
|
|
{
|
|
pTempJoyConfig->guidGameport = GUID_GAMEENUM_BUS_ENUMERATOR;
|
|
#ifdef _DEBUG
|
|
OutputDebugString(TEXT("JOY.CPL: ADD.CPP: Selected Port did not return a clsidConfig so AutoDetect is being used!\n"));
|
|
#endif
|
|
}
|
|
|
|
// Set the hour glass
|
|
SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
// ISSUE-2001/03/29-timgill (MarcAnd) Why would we want to block updates when we're adding a device?
|
|
#if 1
|
|
// Unblock the WM_DEVICECHANGE message handler!
|
|
nFlags &= ~BLOCK_UPDATE;
|
|
nFlags |= ON_PAGE;
|
|
|
|
/*
|
|
* Set the nReEnum counter going so that for the next n WM_TIMER
|
|
* messages (or until the device arrives) we can consider
|
|
* doing a refresh.
|
|
* The value is somewhat arbitrary.
|
|
*/
|
|
nReEnum = 43;
|
|
/*
|
|
* Set a target for the number of devices so that the extra
|
|
* reenumerations can be avoided if this target is reached.
|
|
*/
|
|
nTargetAssigned = nAssigned+1;
|
|
#else
|
|
nFlags |= BLOCK_UPDATE;
|
|
#endif
|
|
|
|
dwFlags = DIJC_REGHWCONFIGTYPE | DIJC_CALLOUT;
|
|
dwFlags |= ::SendDlgItemMessage(hDlg, IDC_WDM, BM_GETCHECK, 0, 0) ? DIJC_WDMGAMEPORT : 0;
|
|
|
|
if( FAILED(hr = pDIJoyConfig->SetConfig(nID, pTempJoyConfig, dwFlags)) )
|
|
{
|
|
// Let the user know what happend!
|
|
if( hr == E_ACCESSDENIED )
|
|
{
|
|
// Let the use know that the port is already occupied and that they need to remove that device or
|
|
// re-assign the device to an unoccupied port.
|
|
|
|
LPDIJOYCONFIG lpJoyCfg = new (DIJOYCONFIG);
|
|
ASSERT (lpJoyCfg);
|
|
|
|
ZeroMemory(lpJoyCfg, sizeof(DIJOYCONFIG));
|
|
|
|
lpJoyCfg->dwSize = sizeof(DIJOYCONFIG);
|
|
|
|
// Cycle threw pAssigned and find the device with the same port name!
|
|
BYTE nIndex = nAssigned;
|
|
|
|
do
|
|
{
|
|
if( SUCCEEDED(pDIJoyConfig->GetConfig(pAssigned[--nIndex]->ID, lpJoyCfg, DIJC_WDMGAMEPORT)) )
|
|
{
|
|
if( lpJoyCfg->guidGameport == pTempJoyConfig->guidGameport )
|
|
break;
|
|
}
|
|
} while( nIndex );
|
|
|
|
if( lpJoyCfg )
|
|
delete (lpJoyCfg);
|
|
|
|
DIPROPSTRING *pDIPropStr = new (DIPROPSTRING);
|
|
ASSERT (pDIPropStr);
|
|
|
|
ZeroMemory(pDIPropStr, sizeof(DIPROPSTRING));
|
|
|
|
pDIPropStr->diph.dwSize = sizeof(DIPROPSTRING);
|
|
pDIPropStr->diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
|
pDIPropStr->diph.dwHow = DIPH_DEVICE;
|
|
|
|
// Ok now.. you found it... use the Device pointer to get it's Friendly name!
|
|
if( SUCCEEDED(pAssigned[nIndex]->fnDeviceInterface->GetProperty(DIPROP_INSTANCENAME, &pDIPropStr->diph)) )
|
|
{
|
|
// Put ellipse in text to avoid buffer over-flow.
|
|
// Limit displayed name to 50 chars... not completely arbitrary,
|
|
// we need to leave room in the Message string...
|
|
// who knows how long the string will get when translated!
|
|
if( wcslen(pDIPropStr->wsz) > 50 )
|
|
{
|
|
pDIPropStr->wsz[47] = pDIPropStr->wsz[48] = pDIPropStr->wsz[49] = L'.';
|
|
pDIPropStr->wsz[50] = L'\0';
|
|
}
|
|
|
|
LPTSTR lptszMsgFormat = new (TCHAR[MAX_STR_LEN]);
|
|
ASSERT (lptszMsgFormat);
|
|
VERIFY(LoadString(ghInstance, IDS_ADD_PORT_MSGFORMAT, lptszMsgFormat, MAX_STR_LEN));
|
|
|
|
LPTSTR lptszMsg = new (TCHAR[MAX_STR_LEN]);
|
|
ASSERT (lptszMsg);
|
|
|
|
// Format the message
|
|
wsprintf(lptszMsg, lptszMsgFormat, pDIPropStr->wsz, lpszPortName, pAssigned[nIndex]->ID+1);
|
|
|
|
VERIFY(LoadString(ghInstance, IDS_ADD_PORT_OCCUPIED, lptszMsgFormat, MAX_STR_LEN));
|
|
|
|
MessageBox(hDlg, lptszMsg, lptszMsgFormat, MB_ICONHAND | MB_OK | MB_APPLMODAL);
|
|
|
|
if( lptszMsgFormat )
|
|
delete[] (lptszMsgFormat);
|
|
|
|
if( lptszMsg )
|
|
delete[] (lptszMsg);
|
|
}
|
|
|
|
if( pDIPropStr )
|
|
delete (pDIPropStr);
|
|
} else if( hr == DIERR_DEVICEFULL )
|
|
{
|
|
Error((short)IDS_GAMEPORT_OCCUPIED_TITLE, (short)IDS_GAMEPORT_OCCUPIED);
|
|
} else
|
|
{
|
|
// Something Ugly happened!
|
|
Error((short)IDS_NO_GAMENUM_TITLE, (short)IDS_NO_GAMENUM);
|
|
}
|
|
} else
|
|
{
|
|
#ifdef _UNICODE
|
|
// Fix #55524
|
|
if( SUCCEEDED(pDIJoyConfig->GetConfig(nID, pTempJoyConfig, DIJC_REGHWCONFIGTYPE)) )
|
|
{
|
|
if( !(pTempJoyConfig->hwc.dwUsageSettings & JOY_US_PRESENT) )
|
|
{
|
|
pTempJoyConfig->hwc.dwUsageSettings |= JOY_US_PRESENT;
|
|
pTempJoyConfig->hwc.hwv.dwCalFlags |= 0x80000000;
|
|
pTempJoyConfig->hwc.hws.dwFlags |= JOY_HWS_ISANALOGPORTDRIVER;
|
|
|
|
VERIFY(SUCCEEDED(pDIJoyConfig->SetConfig(nID, pTempJoyConfig, DIJC_REGHWCONFIGTYPE)));
|
|
}
|
|
}
|
|
// end of Fix #55524
|
|
#endif
|
|
|
|
// make sure VJOYD is notified
|
|
if( !(nFlags & ON_NT) ) {
|
|
pDIJoyConfig->SendNotify();
|
|
Sleep(10);
|
|
pDIJoyConfig->SendNotify();
|
|
}
|
|
|
|
#ifndef _UNICODE
|
|
#ifdef SUPPORT_TWO_2A2B
|
|
/*
|
|
* Add the other part of Two_2Axis_2Button joystick.
|
|
*/
|
|
if( f2_2A2B ) {
|
|
nID = GetNextAvailableID();
|
|
if( nID >= 0 ){
|
|
hr = pDIJoyConfig->SetConfig(nID, pTempJoyConfig, dwFlags);
|
|
|
|
if( SUCCEEDED(hr) ) {
|
|
if( !(nFlags & ON_NT) )
|
|
pDIJoyConfig->SendNotify();
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
}
|
|
|
|
if( lpszPortName )
|
|
free(lpszPortName);
|
|
|
|
// Set the standard pointer
|
|
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
|
|
|
pDIJoyConfig->Unacquire();
|
|
}
|
|
|
|
if( lpdiJoyInfo )
|
|
delete (lpdiJoyInfo);
|
|
|
|
if( pTempJoyConfig )
|
|
delete (pTempJoyConfig);
|
|
|
|
return((char)nID);
|
|
}
|
|
|
|
BOOL UpdateListCtrl( HWND hCtrl )
|
|
{
|
|
// Turn Redraw off here else it will flicker!
|
|
::SendMessage(hCtrl, WM_SETREDRAW, (WPARAM)FALSE, 0);
|
|
|
|
// delete all existing entries
|
|
::SendMessage(hCtrl, LB_RESETCONTENT, 0, 0);
|
|
|
|
// Type info
|
|
LPDIJOYTYPEINFO_DX5 lpdiJoyInfo = new (DIJOYTYPEINFO_DX5);
|
|
ASSERT (lpdiJoyInfo);
|
|
|
|
ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
|
|
|
|
lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
|
|
|
|
#ifndef _UNICODE
|
|
USES_CONVERSION;
|
|
#endif
|
|
|
|
BYTE nIndex = nGamingDevices-1;
|
|
|
|
::SendMessage(hCtrl, LB_SETCOUNT, (WPARAM)(int)nIndex, 0);
|
|
|
|
LPWSTR lpStr = new WCHAR[MAX_STR_LEN];
|
|
ASSERT (lpStr);
|
|
|
|
BYTE nLargestStringLen = 0;
|
|
|
|
do
|
|
{
|
|
if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[nIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_DISPLAYNAME)) )
|
|
{
|
|
#ifdef _UNICODE
|
|
::SendMessage(hCtrl, LB_SETITEMDATA,
|
|
(WPARAM)::SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpdiJoyInfo->wszDisplayName), (LPARAM)nIndex);
|
|
#else
|
|
::SendMessage(hCtrl, LB_SETITEMDATA,
|
|
(WPARAM)::SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)W2A(lpdiJoyInfo->wszDisplayName)), (LPARAM)nIndex);
|
|
#endif
|
|
if( wcslen(lpdiJoyInfo->wszDisplayName) > nLargestStringLen )
|
|
{
|
|
nLargestStringLen = (BYTE)wcslen(lpdiJoyInfo->wszDisplayName);
|
|
wcscpy(lpStr, lpdiJoyInfo->wszDisplayName);
|
|
}
|
|
}
|
|
} while( nIndex-- );
|
|
|
|
if( lpdiJoyInfo )
|
|
delete (lpdiJoyInfo);
|
|
|
|
#ifdef _UNICODE
|
|
PostHScrollBar(hCtrl, lpStr, nLargestStringLen);
|
|
#else
|
|
PostHScrollBar(hCtrl, W2A(lpStr), nLargestStringLen);
|
|
#endif
|
|
|
|
if( lpStr )
|
|
delete[] (lpStr);
|
|
|
|
// Select the default selection to the 0th device type
|
|
iAddItem = 0;
|
|
|
|
::PostMessage(hCtrl, LB_SETCURSEL, (WPARAM)iAddItem, 0);
|
|
|
|
// Turn the redraw flag back on!
|
|
::SendMessage (hCtrl, WM_SETREDRAW, (WPARAM)TRUE, 0);
|
|
InvalidateRect(hCtrl, NULL, TRUE);
|
|
return(TRUE);
|
|
}
|
|
|
|
// Please check to see if nGameportBus is > 0 before a call to this function!
|
|
// It will work, but What a waste!
|
|
BOOL PopulatePortList( HWND hCtrl )
|
|
{
|
|
if( !::IsWindow(hCtrl) )
|
|
{
|
|
TRACE(TEXT("JOY.CPL: PopulatePortList: HWND passed to PopulatePortList is NOT a valid Window!\n"));
|
|
return(FALSE);
|
|
}
|
|
|
|
SendMessage(hCtrl, CB_SETEXTENDEDUI, TRUE, 0);
|
|
|
|
// temp so we don't damage the global!
|
|
BYTE n = nGameportBus;
|
|
|
|
LPDIJOYTYPEINFO lpDIJoyTypeInfo = new (DIJOYTYPEINFO);
|
|
ASSERT(lpDIJoyTypeInfo);
|
|
|
|
#ifndef _UNICODE
|
|
USES_CONVERSION;
|
|
#endif
|
|
|
|
lpDIJoyTypeInfo->dwSize = sizeof(DIJOYTYPEINFO);
|
|
|
|
// Populate the list as they were enumerated.
|
|
do
|
|
{
|
|
if( FAILED(pDIJoyConfig->GetTypeInfo(pwszGameportBus[--n], lpDIJoyTypeInfo, DITC_DISPLAYNAME)) )
|
|
{
|
|
TRACE(TEXT("JOY.CPL: ADD.CPP: GetTypeInfo failed!\n"));
|
|
continue;
|
|
}
|
|
|
|
// put the name in the list and place the index of the port array
|
|
// in it's item data...
|
|
SendMessage(hCtrl, CB_SETITEMDATA,
|
|
#ifdef _UNICODE
|
|
SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpDIJoyTypeInfo->wszDisplayName), n);
|
|
#else
|
|
SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)W2A(lpDIJoyTypeInfo->wszDisplayName)), n);
|
|
#endif
|
|
|
|
// Just in case you're curious, we're going backwards so the default
|
|
// port is the lowest available one.
|
|
} while( n );
|
|
|
|
// Don't forget Auto-Detect!
|
|
// But only if there's more than one port!
|
|
::SendMessage(hCtrl, CB_SETITEMDATA, ::SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpszAutoDetect), AUTODETECT_PORT);
|
|
|
|
// While you're at it, check to see if one is available...
|
|
// if so, put it as the default!
|
|
::PostMessage(hCtrl, CB_SETCURSEL, (WPARAM)0, (LPARAM)0);
|
|
|
|
if( lpDIJoyTypeInfo )
|
|
delete (lpDIJoyTypeInfo);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
static BOOL IsTypeActive( short *nArrayIndex )
|
|
{
|
|
if( *nArrayIndex > nGamingDevices )
|
|
{
|
|
#ifdef _DEBUG
|
|
OutputDebugString(TEXT("JOY.CPL: IsTypeActive: nArrayIndex > nGamingDevices!\n"));
|
|
#endif
|
|
return(FALSE);
|
|
}
|
|
|
|
BOOL bRet = FALSE;
|
|
|
|
BYTE nIndex = nAssigned;
|
|
BYTE nStrLen = (BYTE)wcslen(pwszTypeArray[*nArrayIndex])+1;
|
|
|
|
LPDIJOYCONFIG_DX5 lpDIJoyConfig = new (DIJOYCONFIG_DX5);
|
|
ASSERT (lpDIJoyConfig);
|
|
|
|
ZeroMemory(lpDIJoyConfig, sizeof(DIJOYCONFIG_DX5));
|
|
|
|
lpDIJoyConfig->dwSize = sizeof (DIJOYCONFIG_DX5);
|
|
|
|
// find the assigned ID's
|
|
while( nIndex-- )
|
|
{
|
|
if( SUCCEEDED(pDIJoyConfig->GetConfig(pAssigned[nIndex]->ID, (LPDIJOYCONFIG)lpDIJoyConfig, DIJC_REGHWCONFIGTYPE)) )
|
|
{
|
|
// if you find it... break out!
|
|
if( wcsncmp(lpDIJoyConfig->wszType, pwszTypeArray[*nArrayIndex], nStrLen) == 0 )
|
|
{
|
|
bRet = TRUE;
|
|
*nArrayIndex = nIndex;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( lpDIJoyConfig )
|
|
delete (lpDIJoyConfig);
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
BOOL GetNextAvailableVIDPID(LPWSTR lpwszType )
|
|
{
|
|
// Make the VID/PID to compare from the following formula
|
|
// VID_045e&PID_100+JOY_HW_LASTENTRY to 100+JOY_HW_LASTENTRY+0xf
|
|
|
|
HKEY hKey;
|
|
BYTE n = JOY_HW_LASTENTRY;
|
|
|
|
wcsncpy(lpwszType, L"VID_045E&PID_0100", 18);
|
|
|
|
const WCHAR wszLookup[] = L"0123456789ABCDEF";
|
|
|
|
do
|
|
{
|
|
if( n < 0x10 )
|
|
{
|
|
lpwszType[16] = wszLookup[n];
|
|
} else
|
|
{
|
|
lpwszType[15] = wszLookup[1];
|
|
lpwszType[16] = wszLookup[n%0x10];
|
|
}
|
|
|
|
n++;
|
|
|
|
if( FAILED(pDIJoyConfig->OpenTypeKey(lpwszType, KEY_READ, &hKey)) )
|
|
break;
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
} while( n < (JOY_HW_LASTENTRY+0x11) );
|
|
|
|
return(BOOL)(n < 0x1d);
|
|
}
|
|
|
|
//
|
|
// PostDlgItemEnableWindow(HWND hDlg, USHORT nItem, BOOL bEnabled)
|
|
//
|
|
void PostDlgItemEnableWindow(HWND hDlg, USHORT nItem, BOOL bEnabled)
|
|
{
|
|
HWND hCtrl = GetDlgItem(hDlg, nItem);
|
|
|
|
if( hCtrl )
|
|
PostEnableWindow(hCtrl, bEnabled);
|
|
}
|
|
|
|
//
|
|
// PostEnableWindow(HWND hCtrl, BOOL bEnabled)
|
|
//
|
|
void PostEnableWindow(HWND hCtrl, BOOL bEnabled)
|
|
{
|
|
DWORD dwStyle = GetWindowLong(hCtrl, GWL_STYLE);
|
|
|
|
// No point Redrawing the Window if there's no change!
|
|
if( bEnabled )
|
|
{
|
|
if( dwStyle & WS_DISABLED )
|
|
dwStyle &= ~WS_DISABLED;
|
|
else return;
|
|
} else
|
|
{
|
|
if( !(dwStyle & WS_DISABLED) )
|
|
dwStyle |= WS_DISABLED;
|
|
else return;
|
|
}
|
|
|
|
SetWindowLong(hCtrl, GWL_STYLE, dwStyle);
|
|
|
|
RedrawWindow(hCtrl, NULL, NULL, RDW_INTERNALPAINT | RDW_INVALIDATE);
|
|
}
|
|
|
|
/*
|
|
BOOL IsCustomType(BYTE nIndex)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
// First verify VID is 045E
|
|
WCHAR *pwStr = StrStrW(pwszTypeArray[nIndex],L"VID_");
|
|
|
|
if (pwStr)
|
|
{
|
|
// Increment the pointer over the VID_ and test for 045E
|
|
pwStr = &pwStr[4];
|
|
|
|
if (_wcsnicmp(pwStr, L"045e", 4) == 0)
|
|
{
|
|
OutputDebugString(TEXT("Hit \n"));
|
|
|
|
// Now, increment the pointer over 045e and &PID_ and test for the range!
|
|
pwStr = &pwStr[9];
|
|
|
|
// Second, verify PID is between 0x100 + JOY_HW_LASTENTRY and
|
|
// 0x100 + JOY_HW_LASTENTRY + 0xf
|
|
|
|
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
*/
|
|
|
|
void PostHScrollBar(HWND hCtrl, LPCTSTR lpStr, BYTE nStrLen)
|
|
{
|
|
SIZE sz;
|
|
HDC hDC = GetWindowDC(hCtrl);
|
|
if( hDC != NULL ) /* PREFIX MANBUGS: 29336*/
|
|
{
|
|
GetTextExtentPoint32(hDC, lpStr, nStrLen, &sz);
|
|
ReleaseDC(hCtrl, hDC);
|
|
::PostMessage(hCtrl, LB_SETHORIZONTALEXTENT, (WPARAM)sz.cx, 0);
|
|
}
|
|
}
|
|
|