You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2377 lines
78 KiB
2377 lines
78 KiB
/*
|
|
File: Advanced.cpp
|
|
Project: Joystick Control Panel OLE Client
|
|
Author: Brycej
|
|
Date: 02/07/97
|
|
Comments:
|
|
Window proc for Avanced page in cpanel
|
|
|
|
Copyright (c) 1997, Microsoft Corporation
|
|
*/
|
|
// This is necessary LVS_EX_INFOTIP
|
|
/*
|
|
#if (_WIN32_IE < 0x0500)
|
|
#undef _WIN32_IE
|
|
#define _WIN32_IE 0x0500
|
|
#endif
|
|
*/
|
|
|
|
#include <afxcmn.h>
|
|
#include <windowsx.h>
|
|
|
|
#include <cpl.h>
|
|
|
|
#include <winuser.h> // For RegisterDeviceNotification stuff!
|
|
#include <dbt.h> // for DBT_ defines!!!
|
|
|
|
#include "cpanel.h"
|
|
#include "hsvrguid.h"
|
|
|
|
#include "resource.h"
|
|
#include "joyarray.h"
|
|
|
|
// MyListCtrl prototypes
|
|
#include "inplace.h"
|
|
|
|
#define USE_DEFAULT 0x1000 // If this bit is set, the device is going to use GCDEF!
|
|
#define SHOW_DEFAULT 0x2000 // Show default check box if clsidConfig is != CLSID_LegacyServer
|
|
|
|
// constants
|
|
const short NO_ITEM = -1;
|
|
|
|
#define DEVICE_ID 0
|
|
#define DEVICE_FRIENDLY 1
|
|
#define DEVICE_TYPE 2
|
|
#define DEVICE_PORT 3
|
|
|
|
LPCWSTR lpMSANALOG_VXD = L"MSANALOG.VXD";
|
|
LPTSTR lpstrNone;
|
|
|
|
#define ADVANCED_ID_COLUMN 0
|
|
#define ADVANCED_DEVICE_COLUMN 1
|
|
|
|
extern const DWORD gaHelpIDs[];
|
|
|
|
// externs for arguements!
|
|
extern BYTE nID, nStartPageDef, nStartPageCPL;
|
|
|
|
// Update flag!
|
|
extern short nFlags;
|
|
|
|
// local (module-scope) variables
|
|
HWND hAdvListCtrl;
|
|
|
|
#ifdef _UNICODE
|
|
static PVOID hAdvNotifyDevNode;
|
|
#endif
|
|
|
|
extern short iItem;
|
|
static HWND ghDlg;
|
|
|
|
//static UINT JoyCfgChangedMsg;
|
|
static BOOL bProcess;
|
|
|
|
// Message Procedures for handling VK_DELETE in Advanced window
|
|
static WNDPROC fpMainWndProc;
|
|
static BOOL WINAPI SubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
// Message Procedures for handling the VK_ENTER/VK_DELETE in Adv Window
|
|
static WNDPROC fpPageWndProc;
|
|
static BOOL WINAPI KeySubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
short iAdvItem = NO_ITEM; // index of selected item
|
|
char iGameportDriverItem = NO_ITEM;
|
|
short nOldID;
|
|
|
|
// externs
|
|
extern IDirectInputJoyConfig *pDIJoyConfig;
|
|
extern LPDIRECTINPUT lpDIInterface;
|
|
|
|
extern BYTE nGameportBus;
|
|
extern PJOY pAssigned[MAX_ASSIGNED]; // List of assigned devices
|
|
extern BYTE nAssigned; // Number of elements in pAssigned array
|
|
extern HINSTANCE ghInstance;
|
|
|
|
#ifdef WINNT
|
|
// external function defined in CPANEL.CPP
|
|
extern void RunWDMJOY ( void );
|
|
#endif
|
|
|
|
// local message handlers
|
|
static BOOL OnInitDialog (HWND, HWND, LPARAM);
|
|
static void OnCommand (HWND, int, HWND, UINT);
|
|
static BOOL OnNotify (HWND, WPARAM, LPNMHDR);
|
|
static void OnDestroy (HWND);
|
|
static void OnAdvHelp (LPARAM);
|
|
static void OnContextMenu (WPARAM wParam, LPARAM lParam);
|
|
static void OnListviewContextMenu ( LPARAM lParam );
|
|
|
|
// local utility fns
|
|
static BOOL SetActiveGlobalDriver ( void );
|
|
static BOOL AdvUpdateListCtrl ( void );
|
|
static BOOL UpdateChangeListCtrl ( HWND hCtrl );
|
|
|
|
#ifndef _UNICODE
|
|
static void PopulateGlobalPortDriverComboBox( void );
|
|
extern WCHAR *pwszGameportDriverArray[MAX_GLOBAL_PORT_DRIVERS];
|
|
extern BYTE nGameportDriver; // Global Port Driver Enumeration Counter
|
|
#define POLL_FLAGS_REG_STR TEXT("PollFlags")
|
|
#endif
|
|
|
|
static void LaunchChange ( HWND hTmp );
|
|
int CALLBACK CompareIDItems (LPARAM item1, LPARAM item2, LPARAM uDirection);
|
|
|
|
void EditSubLabel( BYTE nItem, BYTE nCol );
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTION: AdvancedProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
//
|
|
// PARAMETERS: hDlg -
|
|
// uMsg -
|
|
// wParam -
|
|
// lParam -
|
|
//
|
|
// PURPOSE: Main callback function for "Advanced" sheet
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
INT_PTR CALLBACK AdvancedProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch( uMsg )
|
|
{
|
|
case WM_ACTIVATEAPP:
|
|
if( wParam )
|
|
SetListCtrlItemFocus(hAdvListCtrl, (BYTE)iAdvItem);
|
|
break;
|
|
|
|
case WM_DEVICECHANGE:
|
|
switch( (UINT)wParam )
|
|
{
|
|
case DBT_DEVICEARRIVAL:
|
|
// case DBT_DEVICEREMOVECOMPLETE:
|
|
// Clear the old "known devices" list
|
|
nFlags |= UPDATE_ALL;
|
|
|
|
// Clear pAssigned
|
|
while( nAssigned )
|
|
{
|
|
if( pAssigned[--nAssigned] )
|
|
{
|
|
delete[] (pAssigned[nAssigned]);
|
|
|
|
pAssigned[nAssigned] = 0;
|
|
}
|
|
}
|
|
|
|
// Rebuild the "known devices" list - pAssigned
|
|
lpDIInterface->EnumDevices(DIDEVTYPE_JOYSTICK, (LPDIENUMDEVICESCALLBACK)DIEnumDevicesProc, (LPVOID)hDlg, DIEDFL_ALLDEVICES);
|
|
|
|
AdvUpdateListCtrl();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
// Click Drag service for PropSheets!
|
|
PostMessage(GetParent(hDlg), WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lParam);
|
|
break;
|
|
|
|
case WM_INITDIALOG:
|
|
if( !HANDLE_WM_INITDIALOG(hDlg, wParam, lParam, OnInitDialog) )
|
|
{
|
|
// Fix #108983 NT, Remove Flash on Error condition.
|
|
SetWindowPos(::GetParent(hDlg), HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW);
|
|
DestroyWindow(hDlg);
|
|
}
|
|
return(TRUE);
|
|
|
|
case WM_COMMAND:
|
|
HANDLE_WM_COMMAND(hDlg, wParam, lParam, OnCommand);
|
|
return(TRUE);
|
|
|
|
case WM_DESTROY:
|
|
return(HANDLE_WM_DESTROY(hDlg, wParam, lParam, OnDestroy));
|
|
|
|
case WM_NOTIFY:
|
|
return(HANDLE_WM_NOTIFY(hDlg, wParam, lParam, OnNotify));
|
|
|
|
case WM_HELP:
|
|
OnAdvHelp(lParam);
|
|
return(TRUE);
|
|
|
|
case WM_CONTEXTMENU:
|
|
OnContextMenu(wParam, lParam);
|
|
return(TRUE);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTION: OnInitDialog(HWND hDlg, HWND hWnd, LPARAM lParam)
|
|
//
|
|
// PARAMETERS: hDlg -
|
|
// hWnd -
|
|
// lParam -
|
|
//
|
|
// PURPOSE: WM_INITDIALOG message handler
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
BOOL OnInitDialog(HWND hDlg, HWND hWnd, LPARAM lParam)
|
|
{
|
|
bProcess = TRUE;
|
|
|
|
// Just in case Advanced is launched as the startup page!
|
|
if( !lpDIInterface )
|
|
{
|
|
if( FAILED(DirectInputCreate(ghInstance, DIRECTINPUT_VERSION, &lpDIInterface, NULL)) )
|
|
{
|
|
#ifdef _DEBUG
|
|
OutputDebugString(TEXT("GCDEF.DLL: DirectInputCreate() failed\n"));
|
|
#endif
|
|
Error((short)IDS_INTERNAL_ERROR, (short)IDS_NO_DIJOYCONFIG);
|
|
return(FALSE);
|
|
}
|
|
|
|
if( !pDIJoyConfig )
|
|
{
|
|
if( FAILED(lpDIInterface->QueryInterface(IID_IDirectInputJoyConfig, (LPVOID*)&pDIJoyConfig)) )
|
|
{
|
|
#ifdef _DEBUG
|
|
OutputDebugString (TEXT("JOY.CPL: CoCreateInstance Failed... Closing CPL!\n"));
|
|
#endif
|
|
Error((short)IDS_INTERNAL_ERROR, (short)IDS_NO_DIJOYCONFIG);
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
VERIFY(SUCCEEDED(pDIJoyConfig->SetCooperativeLevel(hDlg, DISCL_EXCLUSIVE | DISCL_BACKGROUND)));
|
|
|
|
// Enumerate all the Types!
|
|
VERIFY(SUCCEEDED(pDIJoyConfig->EnumTypes((LPDIJOYTYPECALLBACK)DIEnumJoyTypeProc, NULL)));
|
|
|
|
// If you're here, you came in via the CMD line arg and you need to enumerate for devices so...
|
|
lpDIInterface->EnumDevices(DIDEVTYPE_JOYSTICK, (LPDIENUMDEVICESCALLBACK)DIEnumDevicesProc, (LPVOID)hDlg, DIEDFL_ALLDEVICES);
|
|
}
|
|
}
|
|
|
|
// if we find an object, then enable the Change... button
|
|
//HWND hChangeCtrl = GetDlgItem(hDlg, IDC_ADV_CHANGE);
|
|
|
|
// Determine Privilege and disable Change accordingly!
|
|
if( pDIJoyConfig->Acquire() == DIERR_INSUFFICIENTPRIVS )
|
|
{
|
|
// Assign here because the Advanced sheet could be launched first
|
|
// via command line args!
|
|
nFlags |= USER_MODE;
|
|
|
|
//PostEnableWindow(hChangeCtrl, FALSE);
|
|
}
|
|
#ifdef WINNT
|
|
else
|
|
{
|
|
// Run the WDMJOY.INF file!!!
|
|
RunWDMJOY();
|
|
}
|
|
#endif
|
|
|
|
// set the global dialog handle
|
|
ghDlg = hDlg;
|
|
|
|
// blj: TODO: Make advanced page update on JOYCONFIGCHANGED message!
|
|
// JOY_CONFIGCHANGED_MSGSTRING defined in MMDDK.H
|
|
//JoyCfgChangedMsg = RegisterWindowMessage(JOY_CONFIGCHANGED_MSGSTRING);
|
|
|
|
// initialize our list control
|
|
hAdvListCtrl = GetDlgItem(hDlg, IDC_ADV_LIST_DEVICE);
|
|
|
|
#ifdef _UNICODE
|
|
// Set the Attributes! Removed LVS_EX_ONECLICKACTIVATE per GSeirra | LVS_EX_INFOTIP
|
|
::SendMessage(hAdvListCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP);
|
|
#else
|
|
::SendMessage(hAdvListCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP);
|
|
#endif
|
|
|
|
RECT rc;
|
|
GetClientRect(hAdvListCtrl, &rc);
|
|
rc.left = (short)((rc.right-GetSystemMetrics(SM_CXVSCROLL))/5);
|
|
|
|
// Set up the columns!
|
|
#ifdef _UNICODE
|
|
InsertColumn(hAdvListCtrl, DEVICE_ID, IDS_ADV_DEVICE_HEADING, (USHORT)(rc.left >> 1 ));
|
|
InsertColumn(hAdvListCtrl, DEVICE_FRIENDLY, IDS_ADV_DEVICE_FRIENDLY, (USHORT)(rc.left + (rc.left>>1)));
|
|
InsertColumn(hAdvListCtrl, DEVICE_TYPE, IDS_ADV_GAME_CONTROLLERS, (USHORT)(rc.left << 1 ));
|
|
InsertColumn(hAdvListCtrl, DEVICE_PORT, IDS_ADV_DEVICE_PORT, (USHORT)(rc.left ));
|
|
|
|
// Remove the Global Port Driver stuff!!!
|
|
const USHORT nCtrlArray[] = {IDC_TEXT_PORTDRIVER, IDC_COMBO1, IDC_ADV_GRP2, IDC_TEXT_DRIVER};
|
|
BYTE nIndex = sizeof(nCtrlArray)/sizeof(short);
|
|
|
|
while( DestroyWindow(GetDlgItem(hDlg, nCtrlArray[--nIndex])) );
|
|
|
|
#else
|
|
rc.right = (rc.left << 1) + (rc.left >> 2);
|
|
InsertColumn(hAdvListCtrl, DEVICE_ID, IDS_ADV_DEVICE_HEADING, (USHORT)(rc.left >> 1));
|
|
InsertColumn(hAdvListCtrl, DEVICE_FRIENDLY, IDS_ADV_DEVICE_FRIENDLY, (USHORT)rc.right);
|
|
InsertColumn(hAdvListCtrl, DEVICE_TYPE, IDS_ADV_GAME_CONTROLLERS, (USHORT)rc.right);
|
|
#endif
|
|
|
|
|
|
lpstrNone = new TCHAR[STR_LEN_32];
|
|
ASSERT (lpstrNone);
|
|
|
|
// everyone needs the "None" string so I've loaded it here!
|
|
VERIFY(LoadString(ghInstance, IDS_NONE, lpstrNone, STR_LEN_32));
|
|
|
|
fpMainWndProc = (WNDPROC)SetWindowLongPtr(hAdvListCtrl, GWLP_WNDPROC, (LONG_PTR)SubClassProc);
|
|
|
|
// Only center the dialog if this was the page that we started on!
|
|
if( nStartPageCPL == 1 )
|
|
{
|
|
HWND hParentWnd = GetParent(hDlg);
|
|
|
|
GetWindowRect(hParentWnd, &rc);
|
|
|
|
// Centre the Dialog!
|
|
SetWindowPos(hParentWnd, NULL,
|
|
(GetSystemMetrics(SM_CXSCREEN) - (rc.right-rc.left))>>1,
|
|
(GetSystemMetrics(SM_CYSCREEN) - (rc.bottom-rc.top))>>1,
|
|
NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
|
|
|
|
// Do that move button thing!
|
|
MoveOK(hParentWnd);
|
|
|
|
// Set the Update flag...
|
|
nFlags |= UPDATE_FOR_ADV;
|
|
}
|
|
|
|
// the user is requesting that the CPL be shown
|
|
// and an extention associated with nID be Launched.
|
|
if( nID < NUMJOYDEVS )
|
|
{
|
|
LaunchExtention(hDlg);
|
|
|
|
// Zero out so you don't do it twice!
|
|
nID = 0;
|
|
}
|
|
|
|
// SetActive will use this flag to make sure that the ListCtrl is populated!
|
|
nFlags |= UPDATE_FOR_ADV;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// 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)
|
|
{
|
|
// Hit the "What's This..."
|
|
switch( id )
|
|
{
|
|
case IDC_RENAME:
|
|
// Only SubClass when we need to!
|
|
if( !(nFlags & USER_MODE) )
|
|
{
|
|
HWND hParentWnd = GetParent(GetDlgItem(hDlg, IDC_ADV_LIST_DEVICE));
|
|
// this is required because the CPL can be launched via RUNDLL32
|
|
if( ::IsWindow(hParentWnd) )
|
|
hParentWnd = GetParent(hParentWnd);
|
|
|
|
if( !fpPageWndProc )
|
|
fpPageWndProc = (WNDPROC)SetWindowLongPtr(hParentWnd, GWLP_WNDPROC, (LONG_PTR)KeySubClassProc);
|
|
|
|
nFlags |= UPDATE_INPROCESS;
|
|
|
|
// Find the column as it Could have been moved!
|
|
LPTSTR szName = new (TCHAR[STR_LEN_32]);
|
|
ASSERT (szName);
|
|
|
|
// First, Load the string of the column we are looking to find!
|
|
if( LoadString(ghInstance, IDS_ADV_DEVICE_FRIENDLY, szName, STR_LEN_32) )
|
|
{
|
|
// Now, traverse the columns to find the one with the title that matches szName!
|
|
HWND hHeader = GetDlgItem(hAdvListCtrl, 0);
|
|
|
|
BYTE nColumns = (BYTE)::SendMessage(hHeader, HDM_GETITEMCOUNT, 0, 0L);
|
|
|
|
|
|
HDITEM *phdItem = new (HDITEM);
|
|
ASSERT (phdItem);
|
|
|
|
ZeroMemory(phdItem, sizeof(HD_ITEM));
|
|
|
|
|
|
phdItem->pszText = new TCHAR[STR_LEN_32];
|
|
ASSERT (phdItem->pszText);
|
|
|
|
phdItem->cchTextMax = STR_LEN_32;
|
|
phdItem->mask = HDI_TEXT | HDI_ORDER;
|
|
|
|
do
|
|
{
|
|
::SendMessage(hHeader, HDM_GETITEM, (WPARAM)(int)--nColumns, (LPARAM)(LPHDITEM)phdItem);
|
|
|
|
if( _tcscmp(phdItem->pszText, szName) == 0 )
|
|
{
|
|
nColumns = (BYTE)phdItem->iOrder;
|
|
break;
|
|
}
|
|
} while( nColumns );
|
|
|
|
if( phdItem->pszText )
|
|
delete[] (phdItem->pszText);
|
|
|
|
if( phdItem )
|
|
delete (phdItem);
|
|
|
|
EditSubLabel( (BYTE)iAdvItem, nColumns );
|
|
}
|
|
|
|
if( szName )
|
|
delete[] (szName);
|
|
}
|
|
break;
|
|
|
|
case IDS_WHATSTHIS:
|
|
{
|
|
// point to help file
|
|
LPTSTR pszHelpFileName = new TCHAR[STR_LEN_32];
|
|
ASSERT (pszHelpFileName);
|
|
|
|
if( LoadString(ghInstance, IDS_HELPFILENAME, pszHelpFileName, STR_LEN_32) )
|
|
WinHelp((HWND)hAdvListCtrl, pszHelpFileName, HELP_WM_HELP, (ULONG_PTR)gaHelpIDs);
|
|
#ifdef _DEBUG
|
|
else OutputDebugString(TEXT("JOY.CPL: Advanced.cpp: OnCommand: LoadString Failed to find IDS_HELPFILENAME!\n"));
|
|
#endif // _DEBUG
|
|
|
|
if( pszHelpFileName )
|
|
delete[] (pszHelpFileName);
|
|
}
|
|
break;
|
|
|
|
#ifndef _UNICODE
|
|
// this is the handler for the Global Port Driver Combo box
|
|
case IDC_COMBO1:
|
|
if( code == CBN_SELCHANGE )
|
|
SetActiveGlobalDriver();
|
|
break;
|
|
|
|
// handler for PollFlags entry in the registry for the Global Port Driver
|
|
case IDC_POLLFLAGS:
|
|
if( iGameportDriverItem == NO_ITEM )
|
|
break;
|
|
|
|
if( SUCCEEDED(pDIJoyConfig->Acquire()) )
|
|
{
|
|
HKEY hKey;
|
|
|
|
VERIFY(SUCCEEDED(pDIJoyConfig->OpenTypeKey(pwszGameportDriverArray[iGameportDriverItem], KEY_ALL_ACCESS, &hKey)));
|
|
|
|
// this entry is only valid if the user is running MSANALOG.VXD!
|
|
DWORD nFlags = (IsDlgButtonChecked(hDlg, id)) ? 1 : 0;
|
|
|
|
RegSetValueEx(hKey, POLL_FLAGS_REG_STR, 0, REG_BINARY, (PBYTE)&nFlags, sizeof(nFlags));
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
pDIJoyConfig->SendNotify();
|
|
|
|
pDIJoyConfig->Unacquire();
|
|
}
|
|
break;
|
|
#endif // _UNICODE
|
|
|
|
// this is the handler for the Device list box
|
|
case IDC_ADV_LIST_DEVICE:
|
|
// Fall into Change on DBLCLK
|
|
if( code != LBN_DBLCLK )
|
|
break;
|
|
|
|
case IDC_ADV_CHANGE:
|
|
if( nFlags & USER_MODE )
|
|
Error((short)IDS_USER_MODE_TITLE, (short)IDS_USER_MODE);
|
|
else
|
|
{
|
|
LaunchChange(hDlg);
|
|
}
|
|
break;
|
|
|
|
case IDC_ADV_USEOEMPAGE:
|
|
if( !nAssigned ) {
|
|
break;
|
|
}
|
|
|
|
if( IsWindowVisible(GetDlgItem(hDlg,IDC_ADV_USEOEMPAGE)) )
|
|
{
|
|
// Boy are you going to pay the price for making that selection...
|
|
LPDIJOYCONFIG_DX5 lpDIJoyConfig = new (DIJOYCONFIG_DX5);
|
|
ASSERT (lpDIJoyConfig);
|
|
|
|
ZeroMemory(lpDIJoyConfig, sizeof(DIJOYCONFIG_DX5));
|
|
|
|
lpDIJoyConfig->dwSize = sizeof (DIJOYCONFIG_DX5);
|
|
|
|
// Get the index from the selected item (iAdvItem)
|
|
BYTE n1 = (BYTE)GetItemData(hAdvListCtrl, (BYTE)iAdvItem);
|
|
BYTE n = 0;
|
|
do
|
|
{
|
|
if( pAssigned[n] && (n1 == pAssigned[n]->ID) )
|
|
break;
|
|
n++;
|
|
} while( n < NUMJOYDEVS );
|
|
|
|
// Find out the type name...
|
|
if( SUCCEEDED(pDIJoyConfig->GetConfig(pAssigned[n]->ID, (LPDIJOYCONFIG)lpDIJoyConfig, DIJC_REGHWCONFIGTYPE)) )
|
|
{
|
|
LPDIJOYTYPEINFO lpDIJoyTypeInfo = new (DIJOYTYPEINFO);
|
|
ASSERT (lpDIJoyTypeInfo);
|
|
|
|
ZeroMemory(lpDIJoyTypeInfo, sizeof(DIJOYTYPEINFO));
|
|
|
|
lpDIJoyTypeInfo->dwSize = sizeof(DIJOYTYPEINFO);
|
|
|
|
// Get the TypeInfo you start with!
|
|
if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(lpDIJoyConfig->wszType, lpDIJoyTypeInfo, DITC_FLAGS1 | DITC_CLSIDCONFIG)) )
|
|
{
|
|
DWORD dwFlags = GetItemData(hAdvListCtrl, (BYTE)iAdvItem);
|
|
|
|
// If it's checked... you want the OEM supplied property sheet page!
|
|
if( IsDlgButtonChecked(hDlg, IDC_ADV_USEOEMPAGE) )
|
|
{
|
|
// Turn off the USE_DEFAULT flag
|
|
dwFlags &= ~USE_DEFAULT;
|
|
|
|
// Update the global pointer!!!
|
|
pAssigned[n]->clsidPropSheet = lpDIJoyTypeInfo->clsidConfig;
|
|
|
|
// Update the pointer being sent to the registry
|
|
lpDIJoyTypeInfo->dwFlags1 &= ~JOYTYPE_DEFAULTPROPSHEET;
|
|
} else
|
|
{
|
|
// Turn on the USE_DEFAULT flag
|
|
dwFlags |= USE_DEFAULT;
|
|
|
|
// Update the global list!
|
|
pAssigned[n]->clsidPropSheet = CLSID_LegacyServer;
|
|
|
|
// Update the pointer being sent to the registry
|
|
lpDIJoyTypeInfo->dwFlags1 |= JOYTYPE_DEFAULTPROPSHEET;
|
|
}
|
|
|
|
if( SUCCEEDED(pDIJoyConfig->Acquire()) ) {
|
|
|
|
// Update the registry
|
|
VERIFY(SUCCEEDED(pDIJoyConfig->SetTypeInfo(lpDIJoyConfig->wszType, lpDIJoyTypeInfo, DITC_FLAGS1)));
|
|
|
|
// Set the data in the list control!
|
|
SetItemData(hAdvListCtrl, (BYTE)iAdvItem, dwFlags);
|
|
}
|
|
|
|
pDIJoyConfig->Unacquire();
|
|
}
|
|
|
|
if( lpDIJoyTypeInfo )
|
|
delete (lpDIJoyTypeInfo);
|
|
}
|
|
|
|
if( lpDIJoyConfig )
|
|
delete (lpDIJoyConfig);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUNCTION: OnNotify(HWND hDlg, WPARAM idFrom, NMHDR* pnmhdr)
|
|
//
|
|
// PARAMETERS: hDlg -
|
|
// idFrom - ID of control sending WM_NOTIFY message
|
|
// pnmhdr -
|
|
//
|
|
// PURPOSE: WM_NOTIFY message handler
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL OnNotify(HWND hDlg, WPARAM idFrom, LPNMHDR pnmhdr)
|
|
{
|
|
switch( pnmhdr->code )
|
|
{
|
|
case PSN_QUERYCANCEL:
|
|
if( nFlags & UPDATE_INPROCESS )
|
|
{
|
|
nFlags &= ~UPDATE_INPROCESS;
|
|
SetFocus(hAdvListCtrl);
|
|
}
|
|
break;
|
|
/*
|
|
case LVN_GETINFOTIP:
|
|
{
|
|
LPLVHITTESTINFO lpHit = new (LVHITTESTINFO);
|
|
ASSERT (lpHit);
|
|
|
|
BOOL bRet = FALSE;
|
|
|
|
POINT pt;
|
|
GetCursorPos(&pt);
|
|
ScreenToClient(hAdvListCtrl, &pt);
|
|
|
|
lpHit->pt = pt;
|
|
lpHit->flags = lpHit->iItem = lpHit->iSubItem = 0;
|
|
|
|
::SendMessage(hAdvListCtrl, LVM_SUBITEMHITTEST, 0, (LPARAM)(LPLVHITTESTINFO)lpHit);
|
|
|
|
if (lpHit->flags & LVHT_ONITEMLABEL)
|
|
{
|
|
// Determine the text length of the column text
|
|
LPTSTR lpStr = new (TCHAR[MAX_STR_LEN+1]);
|
|
ASSERT (lpStr);
|
|
|
|
GetItemText(hAdvListCtrl, lpHit->iItem, lpHit->iSubItem, lpStr, MAX_STR_LEN);
|
|
|
|
// Determine if the latter will fit inside the former...
|
|
SIZE size;
|
|
HDC hDC = GetDC(hAdvListCtrl);
|
|
GetTextExtentPoint(hDC, lpStr, lstrlen(lpStr), &size);
|
|
ReleaseDC(hAdvListCtrl, hDC);
|
|
|
|
// Determine how wide the column is!
|
|
short nWidth = (short)::SendMessage(hAdvListCtrl, LVM_GETCOLUMNWIDTH, lpHit->iSubItem, 0);
|
|
|
|
bRet = (BOOL)(size.cx > nWidth);
|
|
|
|
if (bRet)
|
|
// if not, copy the text into lpHit->pszText
|
|
_tcscpy(((LPNMLVGETINFOTIP)pnmhdr)->pszText, lpStr);
|
|
|
|
if (lpStr)
|
|
delete[] (lpStr);
|
|
}
|
|
if (lpHit)
|
|
delete (lpHit);
|
|
|
|
return bRet;
|
|
}
|
|
*/
|
|
|
|
case LVN_BEGINLABELEDIT:
|
|
if( !(GetItemData(hAdvListCtrl, (BYTE)iAdvItem) & ID_NONE) )
|
|
OnCommand(hDlg, IDC_RENAME, 0, 0);
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, 1);
|
|
break;
|
|
|
|
case LVN_ENDLABELEDIT:
|
|
if( !(nFlags & UPDATE_INPROCESS) )
|
|
return(FALSE);
|
|
|
|
if( !bProcess )
|
|
return(FALSE);
|
|
|
|
nFlags &= ~UPDATE_INPROCESS;
|
|
|
|
if( fpPageWndProc )
|
|
{
|
|
HWND hParentWnd = GetParent(hDlg);
|
|
// this is required because the CPL can be launched via RUNDLL32
|
|
if( ::IsWindow(hParentWnd) )
|
|
hParentWnd = GetParent(hParentWnd);
|
|
// Reset the subclass proc
|
|
// SetWindowLongPtr(hParentWnd, GWLP_WNDPROC, (LONG_PTR)fpPageWndProc);
|
|
}
|
|
|
|
// Make sure the name is usable!
|
|
if( _tcschr(((NMLVDISPINFO *)pnmhdr)->item.pszText, TEXT('\\')) )
|
|
{
|
|
Error((short)IDS_INVALID_NAME_TITLE, (short)IDS_INVALID_NAME);
|
|
} else
|
|
{
|
|
nFlags |= UPDATE_ALL;
|
|
|
|
LPDIPROPSTRING pDIPropString = new (DIPROPSTRING);
|
|
ASSERT (pDIPropString);
|
|
|
|
ZeroMemory(pDIPropString, sizeof(DIPROPSTRING));
|
|
|
|
pDIPropString->diph.dwSize = sizeof(DIPROPSTRING);
|
|
pDIPropString->diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
|
pDIPropString->diph.dwHow = DIPH_DEVICE;
|
|
|
|
#ifdef _UNICODE
|
|
wcscpy(pDIPropString->wsz, ((NMLVDISPINFO *)pnmhdr)->item.pszText);
|
|
#else
|
|
USES_CONVERSION;
|
|
wcscpy(pDIPropString->wsz, A2W(((NMLVDISPINFO *)pnmhdr)->item.pszText));
|
|
#endif
|
|
// Search nAssigned for the ID...
|
|
BYTE n = nAssigned;
|
|
|
|
do
|
|
{
|
|
if( pAssigned[--n]->ID == ((NMLVDISPINFO *)pnmhdr)->item.iItem )
|
|
break;
|
|
|
|
} while( n );
|
|
|
|
if( SUCCEEDED(pAssigned[n]->fnDeviceInterface->SetProperty(DIPROP_INSTANCENAME, &pDIPropString->diph)) )
|
|
{
|
|
SetItemText(hAdvListCtrl, (BYTE)((NMLVDISPINFO *)pnmhdr)->item.iItem, 1, ((NMLVDISPINFO *)pnmhdr)->item.pszText);
|
|
} else
|
|
{
|
|
Error((short)IDS_NO_RENAME_TITLE, (short)IDS_NO_RENAME);
|
|
}
|
|
|
|
if( pDIPropString )
|
|
delete (pDIPropString);
|
|
}
|
|
break;
|
|
|
|
#if 0
|
|
case LVN_COLUMNCLICK:
|
|
switch( ((NM_LISTVIEW*)pnmhdr)->iSubItem )
|
|
{
|
|
case DEVICE_ID:
|
|
{
|
|
static BOOL bIDDirection = TRUE;
|
|
::SendMessage(hAdvListCtrl, LVM_SORTITEMS, (WPARAM)(LPARAM)(bIDDirection =! bIDDirection), (LPARAM)(PFNLVCOMPARE)CompareIDItems);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
BOOL bDirection;
|
|
|
|
CListCtrl *pCtrl = new (CListCtrl);
|
|
ASSERT(pCtrl);
|
|
|
|
pCtrl->Attach(hAdvListCtrl);
|
|
|
|
switch( ((NM_LISTVIEW*)pnmhdr)->iSubItem )
|
|
{
|
|
case DEVICE_FRIENDLY:
|
|
{
|
|
static BOOL bFriendlyDirection = FALSE;
|
|
bDirection = (bFriendlyDirection =! bFriendlyDirection);
|
|
}
|
|
break;
|
|
|
|
case DEVICE_TYPE:
|
|
{
|
|
static BOOL bTypeDirection = FALSE;
|
|
bDirection = (bTypeDirection =! bTypeDirection);
|
|
}
|
|
break;
|
|
|
|
case DEVICE_PORT:
|
|
{
|
|
static BOOL bPortDirection = FALSE;
|
|
bDirection = (bPortDirection =! bPortDirection);
|
|
}
|
|
break;
|
|
}
|
|
|
|
SortTextItems(pCtrl, (short)((NM_LISTVIEW*)pnmhdr)->iSubItem, bDirection, 0, 15);
|
|
|
|
pCtrl->Detach();
|
|
|
|
if( pCtrl )
|
|
delete (pCtrl);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if( nAssigned )
|
|
{
|
|
iAdvItem = (short)::SendMessage(hAdvListCtrl, LVM_GETNEXTITEM, (WPARAM)(int)-1, MAKELPARAM(LVNI_SELECTED, 0));
|
|
::PostMessage(hAdvListCtrl, LVM_ENSUREVISIBLE, iAdvItem, TRUE);
|
|
|
|
if( !(nFlags & USER_MODE) )
|
|
PostDlgItemEnableWindow(hDlg, IDC_ADV_CHANGE, (GetItemData(hAdvListCtrl, (BYTE)iAdvItem) & ID_NONE) ? FALSE : TRUE);
|
|
|
|
SetListCtrlItemFocus(hAdvListCtrl, (BYTE)iAdvItem);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case PSN_KILLACTIVE:
|
|
if( nFlags & UPDATE_INPROCESS )
|
|
SetFocus(hAdvListCtrl);
|
|
|
|
#ifdef _UNICODE
|
|
if( hAdvNotifyDevNode )
|
|
UnregisterDeviceNotification(hAdvNotifyDevNode);
|
|
#endif
|
|
break;
|
|
|
|
case NM_DBLCLK:
|
|
switch( idFrom )
|
|
{
|
|
case IDC_ADV_LIST_DEVICE:
|
|
if( !(GetItemData(hAdvListCtrl, (BYTE)iAdvItem) & ID_NONE) )
|
|
LaunchChange(hDlg);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case PSN_SETACTIVE:
|
|
#ifdef _UNICODE
|
|
RegisterForDevChange(hDlg, &hAdvNotifyDevNode);
|
|
#endif
|
|
|
|
if( nFlags & UPDATE_FOR_ADV )
|
|
{
|
|
if( !AdvUpdateListCtrl() )
|
|
{
|
|
#ifdef _DEBUG
|
|
OutputDebugString(TEXT("JOY.CPL: OnNotify: Failed UpdateListCtrl!\n"));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if( nAssigned )
|
|
{
|
|
iAdvItem = 0;
|
|
|
|
// This will happen when the user comes in via the CMD line!
|
|
if( iItem != NO_ITEM )
|
|
{
|
|
// Find the ID of the device... the Brute Force Method!
|
|
do
|
|
{
|
|
if( (pAssigned[iItem] != NULL) && ((BYTE)GetItemData(hAdvListCtrl, (BYTE)iAdvItem) == pAssigned[iItem]->ID) )
|
|
break;
|
|
|
|
iAdvItem++;
|
|
} while( iAdvItem < NUMJOYDEVS );
|
|
}
|
|
|
|
if( iAdvItem == NUMJOYDEVS ) {
|
|
iAdvItem = 0;
|
|
}
|
|
|
|
SetListCtrlItemFocus(hAdvListCtrl, (BYTE)iAdvItem);
|
|
::PostMessage(hAdvListCtrl, LVM_ENSUREVISIBLE, iAdvItem, FALSE );
|
|
}
|
|
|
|
// No global port drivers in NT so...
|
|
//if (nGameportDriver)
|
|
#ifndef _UNICODE
|
|
if( !(nFlags & ON_NT) )
|
|
PopulateGlobalPortDriverComboBox();
|
|
#endif
|
|
|
|
// disable the Change button if iAdvItem points to a (none) selection
|
|
if( !(nFlags & USER_MODE) )
|
|
PostDlgItemEnableWindow(hDlg, IDC_ADV_CHANGE, (nAssigned) ? ((iAdvItem & ID_NONE) ? FALSE : TRUE) : FALSE);
|
|
break;
|
|
|
|
case LVN_ITEMCHANGED:
|
|
if( iAdvItem != (short)((NM_LISTVIEW*)pnmhdr)->iItem )
|
|
{
|
|
iAdvItem = (short)((NM_LISTVIEW*)pnmhdr)->iItem;
|
|
|
|
HWND hCtrl = GetDlgItem(hDlg, IDC_ADV_USEOEMPAGE);
|
|
|
|
if( nAssigned )
|
|
{
|
|
SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
|
|
((((NM_LISTVIEW*)pnmhdr)->lParam & SHOW_DEFAULT) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW) );
|
|
|
|
// Check the box appropriatly!
|
|
if( ((NM_LISTVIEW*)pnmhdr)->lParam & SHOW_DEFAULT )
|
|
::PostMessage(GetDlgItem(hDlg, IDC_ADV_USEOEMPAGE), BM_SETCHECK, (((NM_LISTVIEW*)pnmhdr)->lParam & USE_DEFAULT) ? BST_UNCHECKED : BST_CHECKED, 0);
|
|
|
|
if( ((NM_LISTVIEW*)pnmhdr)->lParam )
|
|
PostEnableWindow(hCtrl, (BOOL)!(((NM_LISTVIEW*)pnmhdr)->lParam & ID_NONE));
|
|
|
|
if( !(nFlags & USER_MODE) )
|
|
PostDlgItemEnableWindow(hDlg, IDC_ADV_CHANGE, (BOOL)!(((NM_LISTVIEW*)pnmhdr)->lParam & ID_NONE));
|
|
} else SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW);
|
|
}
|
|
break;
|
|
|
|
case LVN_KEYDOWN:
|
|
switch( ((LV_KEYDOWN*)pnmhdr)->wVKey )
|
|
{
|
|
case VK_DELETE:
|
|
iAdvItem = (short)::SendMessage(hAdvListCtrl, LVM_GETNEXTITEM, (WPARAM)(int)-1, MAKELPARAM(LVNI_SELECTED, 0));
|
|
{
|
|
BYTE nRet = (BYTE)GetItemData(hAdvListCtrl, (BYTE)iAdvItem);
|
|
DeleteSelectedItem((PBYTE)&nRet);
|
|
}
|
|
// Missing break intentional!
|
|
|
|
case VK_F5:
|
|
Enumerate( hDlg );
|
|
AdvUpdateListCtrl();
|
|
SetListCtrlItemFocus(hAdvListCtrl, (BYTE)iAdvItem);
|
|
::PostMessage(hAdvListCtrl, LVM_ENSUREVISIBLE, iAdvItem, FALSE );
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTION: OnDestroy ( HWND hWnd )
|
|
//
|
|
// PARAMETERS: hWnd - Handle to window being destroyed
|
|
//
|
|
// PURPOSE: WM_DESTROY message handler
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
void OnDestroy(HWND hWnd)
|
|
{
|
|
ASSERT (hWnd);
|
|
|
|
if( lpstrNone )
|
|
delete[] (lpstrNone);
|
|
|
|
// Reset the subclass proc
|
|
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)fpMainWndProc);
|
|
|
|
// release the DI JoyConfig interface pointer
|
|
if( pDIJoyConfig )
|
|
{
|
|
pDIJoyConfig->Release();
|
|
pDIJoyConfig = 0;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTION: OnAdvHelp ( LPARAM lParam )
|
|
//
|
|
// PARAMETERS: lParam - Pointer to HELPINFO struct
|
|
//
|
|
// PURPOSE: WM_HELP message handler
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
void OnAdvHelp(LPARAM lParam)
|
|
{
|
|
ASSERT (lParam);
|
|
|
|
// point to help file
|
|
LPTSTR pszHelpFileName = new TCHAR[STR_LEN_32];
|
|
ASSERT (pszHelpFileName);
|
|
|
|
if( LoadString(ghInstance, IDS_HELPFILENAME, pszHelpFileName, STR_LEN_32) )
|
|
{
|
|
if( ((LPHELPINFO)lParam)->iContextType == HELPINFO_WINDOW )
|
|
WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, pszHelpFileName, HELP_WM_HELP, (ULONG_PTR)gaHelpIDs);
|
|
}
|
|
#ifdef _DEBUG
|
|
else OutputDebugString(TEXT("JOY.CPL: Advanced.cpp: OnAdvHelp: LoadString Failed to find IDS_HELPFILENAME!\n"));
|
|
#endif // _DEBUG
|
|
|
|
if( pszHelpFileName )
|
|
delete[] (pszHelpFileName);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTION: OnContextMenu ( WPARAM wParam )
|
|
//
|
|
// PARAMETERS: wParam - HWND of window under the pointer
|
|
//
|
|
// PURPOSE: Handle WM_RBUTTONDOWN over all client windows
|
|
// (except the list control... that's OnListviewContextMenu() job)
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
void OnContextMenu(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
ASSERT (wParam);
|
|
|
|
// If you are on the ListCtrl...
|
|
if( (HWND)wParam == hAdvListCtrl )
|
|
{
|
|
SetFocus(hAdvListCtrl);
|
|
|
|
// Don't attempt if nothing selected
|
|
if( iAdvItem != NO_ITEM )
|
|
OnListviewContextMenu(lParam);
|
|
} else
|
|
{
|
|
// point to help file
|
|
LPTSTR pszHelpFileName = new TCHAR[STR_LEN_32];
|
|
ASSERT (pszHelpFileName);
|
|
|
|
if( LoadString(ghInstance, IDS_HELPFILENAME, pszHelpFileName, STR_LEN_32) )
|
|
WinHelp((HWND)wParam, pszHelpFileName, HELP_CONTEXTMENU, (ULONG_PTR)gaHelpIDs);
|
|
#ifdef _DEBUG
|
|
else OutputDebugString(TEXT("JOY.CPL: Advanced.cpp: OnContextMenu: LoadString Failed to find IDS_HELPFILENAME!\n"));
|
|
#endif // _DEBUG
|
|
|
|
if( pszHelpFileName )
|
|
delete[] (pszHelpFileName);
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTION: SetActiveGlobalDriver( void )
|
|
//
|
|
// PURPOSE: Commit user selection to persistent storage.
|
|
//
|
|
// RETURN: TRUE if successfull, FALSE otherwise
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#ifndef _UNICODE
|
|
BOOL SetActiveGlobalDriver( void )
|
|
{
|
|
// It's Perfectly valid to not have a Global Port Driver so... be prepared!
|
|
short n = (short)SendDlgItemMessage(ghDlg, IDC_COMBO1, CB_GETCURSEL, 0, 0);
|
|
|
|
if( n == CB_ERR )
|
|
return(FALSE);
|
|
|
|
LPDIJOYUSERVALUES pDIJoyUserValues = new (DIJOYUSERVALUES);
|
|
ASSERT (pDIJoyUserValues);
|
|
|
|
ZeroMemory(pDIJoyUserValues, sizeof(DIJOYUSERVALUES));
|
|
|
|
pDIJoyUserValues->dwSize = sizeof(DIJOYUSERVALUES);
|
|
|
|
HWND hCtrl = GetDlgItem(ghDlg, IDC_COMBO1);
|
|
|
|
// Don't worry about this not being a TCHAR, this code will never be executed in NT!
|
|
LPSTR pszDisplayName = new char[SendMessage(hCtrl, LB_GETTEXTLEN, (WPARAM)n, 0)+1];
|
|
ASSERT (pszDisplayName);
|
|
|
|
SendMessage(hCtrl, CB_GETLBTEXT, n, (LPARAM)(LPCTSTR)pszDisplayName);
|
|
|
|
hCtrl = GetDlgItem(ghDlg, IDC_POLLFLAGS);
|
|
|
|
SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW );
|
|
|
|
// Fix #9815, Set wszGlobalDriver to
|
|
if( _tcsncmp(pszDisplayName, lpstrNone, sizeof(lpstrNone)/sizeof(TCHAR)) == 0 )
|
|
{
|
|
//wcscpy(pDIJoyUserValues->wszGlobalDriver, L"");
|
|
|
|
if( SUCCEEDED(pDIJoyConfig->Acquire()) )
|
|
{
|
|
if( FAILED(pDIJoyConfig->SetUserValues(pDIJoyUserValues, DIJU_GLOBALDRIVER)) )
|
|
{
|
|
TRACE (TEXT("JOY.CPL: SetUserValues failed to set DIJU_GLOBALDRIVER!\n"));
|
|
}
|
|
}
|
|
} else
|
|
{
|
|
LPDIJOYTYPEINFO lpdiJoyInfo = new DIJOYTYPEINFO;
|
|
ASSERT (lpdiJoyInfo);
|
|
|
|
ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO));
|
|
|
|
lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO);
|
|
|
|
USES_CONVERSION;
|
|
|
|
short nIndex = 0;
|
|
|
|
// traverse the list of Global Port Drivers 'till you find the matching display name
|
|
// this also disallows the user from doing something ugly when they only have "standard gameport"
|
|
while( pwszGameportDriverArray[nIndex] )
|
|
{
|
|
// populate the Type Info
|
|
if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszGameportDriverArray[nIndex], lpdiJoyInfo, DITC_DISPLAYNAME | DITC_CALLOUT)) )
|
|
{
|
|
if( _wcsicmp(lpdiJoyInfo->wszDisplayName, A2W(pszDisplayName)) == 0 )
|
|
{
|
|
wcscpy(pDIJoyUserValues->wszGlobalDriver, lpdiJoyInfo->wszCallout );
|
|
|
|
if( SUCCEEDED(pDIJoyConfig->Acquire()) )
|
|
{
|
|
if( FAILED(pDIJoyConfig->SetUserValues(pDIJoyUserValues, DIJU_GLOBALDRIVER)) )
|
|
{
|
|
TRACE (TEXT("JOY.CPL: SetUserValues failed to set DIJU_GLOBALDRIVER!\n"));
|
|
}
|
|
|
|
// check to see if you need to display the poll flags check box!
|
|
if( _wcsicmp(pDIJoyUserValues->wszGlobalDriver, lpMSANALOG_VXD) == 0 )
|
|
{
|
|
SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW );
|
|
|
|
// Get the state from the registry and update the check mark
|
|
HKEY hKey;
|
|
|
|
if( FAILED(pDIJoyConfig->OpenTypeKey(pwszGameportDriverArray[nIndex], KEY_ALL_ACCESS, &hKey)) )
|
|
{
|
|
TRACE (TEXT("JOY.CPL: OpenTypeKey failed to open key %s!\n"), pwszGameportDriverArray[nIndex]);
|
|
}
|
|
|
|
DWORD dwFlag;
|
|
ULONG ulType = REG_BINARY;
|
|
ULONG ulSize = sizeof(dwFlag);
|
|
|
|
// this will happen if there is no entry for POLL_FLAGS_REG_STR
|
|
if( ERROR_SUCCESS != RegQueryValueEx(hKey, POLL_FLAGS_REG_STR, NULL, &ulType, (PBYTE)&dwFlag, &ulSize) )
|
|
dwFlag = 0;
|
|
|
|
::PostMessage(GetDlgItem(ghDlg, IDC_POLLFLAGS), BM_SETCHECK, (dwFlag) ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
nIndex++;
|
|
}
|
|
|
|
// delete the DIJOYTYPEINFO variable
|
|
if( lpdiJoyInfo )
|
|
delete (lpdiJoyInfo);
|
|
}
|
|
|
|
pDIJoyConfig->SendNotify();
|
|
|
|
pDIJoyConfig->Unacquire();
|
|
|
|
if( pszDisplayName )
|
|
delete[] (pszDisplayName);
|
|
|
|
if( pDIJoyUserValues )
|
|
delete pDIJoyUserValues;
|
|
|
|
return(TRUE);
|
|
}
|
|
#endif // _UNICODE
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTION: OnListviewContextMenu( void )
|
|
//
|
|
// PURPOSE: Handle Context menu in Listview
|
|
//
|
|
// RETURN: TRUE if successfull, FALSE otherwise
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static void OnListviewContextMenu( LPARAM lParam )
|
|
{
|
|
HMENU hPopupMenu = CreatePopupMenu();
|
|
ASSERT (hPopupMenu);
|
|
|
|
// unlike life, bRet defaults to bliss
|
|
BOOL bRet = TRUE;
|
|
|
|
LPTSTR pszText = new TCHAR[STR_LEN_32];
|
|
ASSERT (pszText);
|
|
|
|
// Don't display Rename/Change if on (none) entry
|
|
if( !(GetItemData(hAdvListCtrl, (BYTE)iAdvItem) & ID_NONE) )
|
|
{
|
|
if( !(nFlags & USER_MODE) )
|
|
{
|
|
// add the "Change..." string
|
|
::SendDlgItemMessage(GetParent(hAdvListCtrl), IDC_ADV_CHANGE, WM_GETTEXT, (WPARAM)STR_LEN_32, (LPARAM)(LPCTSTR)pszText);
|
|
|
|
bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_ADV_CHANGE, pszText);
|
|
#ifdef _DEBUG
|
|
if( !bRet )
|
|
TRACE(TEXT("JOY.CPL: OnListviewCOntextMenu: AppendMenu Failed to insert %s\n"), pszText);
|
|
#endif //_DEBUG
|
|
|
|
// Add the Rename text
|
|
VERIFY(LoadString(ghInstance, IDS_RENAME, pszText, STR_LEN_32));
|
|
bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDC_RENAME, pszText);
|
|
#ifdef _DEBUG
|
|
if( !bRet )
|
|
TRACE(TEXT("JOY.CPL: OnListviewCOntextMenu: AppendMenu Failed to insert %s\n"), pszText);
|
|
#endif //_DEBUG
|
|
|
|
// Add the SEPERATOR and "What's this?"
|
|
|
|
//PREFIX #WI279965. False positive.
|
|
//MSDN: if uFlags==MF_SEPARATOR, LPCTSTR lpNewItem is ignored.
|
|
bRet = AppendMenu(hPopupMenu, MF_SEPARATOR, 0, 0);
|
|
#ifdef _DEBUG
|
|
if( !bRet )
|
|
TRACE(TEXT("JOY.CPL: OnListviewCOntextMenu: AppendMenu Failed to insert SEPERATOR!\n"));
|
|
#endif //_DEBUG
|
|
}
|
|
}
|
|
|
|
VERIFY(LoadString(ghInstance, IDS_WHATSTHIS, pszText, STR_LEN_32));
|
|
bRet = AppendMenu(hPopupMenu, MF_ENABLED, IDS_WHATSTHIS, pszText);
|
|
#ifdef _DEBUG
|
|
if( !bRet )
|
|
TRACE(TEXT("JOY.CPL: OnListviewCOntextMenu: AppendMenu Failed to insert %s\n"), pszText);
|
|
#endif //_DEBUG
|
|
|
|
if( pszText ) delete[] (pszText);
|
|
|
|
POINT pt;
|
|
|
|
// lParam is -1 if we got here via Shift+F10
|
|
if( lParam > 0 )
|
|
{
|
|
pt.x = GET_X_LPARAM(lParam);
|
|
pt.y = GET_Y_LPARAM(lParam);
|
|
} else
|
|
{
|
|
// Centre the popup on the selected item!
|
|
|
|
// This get's a good X pos, but the y is the start of the control!
|
|
::SendMessage(hAdvListCtrl, LVM_GETITEMPOSITION, iAdvItem, (LPARAM)&pt);
|
|
|
|
RECT rc;
|
|
::GetClientRect(hAdvListCtrl, &rc);
|
|
|
|
pt.x = rc.right>>1;
|
|
|
|
ClientToScreen(hAdvListCtrl, &pt);
|
|
}
|
|
|
|
bRet = TrackPopupMenu (hPopupMenu, TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON, pt.x, pt.y, 0, ghDlg, NULL);
|
|
#ifdef _DEBUG
|
|
if( !bRet )
|
|
TRACE (TEXT("JOY.CPL: OnListviewContextMenu: TrackPopupMenu Failed!\n"));
|
|
#endif //_DEBUG
|
|
|
|
if(hPopupMenu) DestroyMenu (hPopupMenu); // PREFIX 45089
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTION: UpdateListCtrl( void )
|
|
//
|
|
// PURPOSE: Refreshes enumerated device list
|
|
//
|
|
// RETURN: TRUE if successfull, FALSE otherwise
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static BOOL AdvUpdateListCtrl()
|
|
{
|
|
// Turn Redraw off here else it will flicker!
|
|
::SendMessage(hAdvListCtrl, WM_SETREDRAW, (WPARAM)FALSE, 0);
|
|
|
|
// Out with the old...
|
|
::SendMessage(hAdvListCtrl, LVM_DELETEALLITEMS, 0, 0);
|
|
|
|
// This buffer is so large because it is used to hold IDS_GEN_STATUS_UNKNOWN
|
|
TCHAR sz1[16];
|
|
|
|
// find and assign ID's
|
|
BYTE n = NUMJOYDEVS;
|
|
BYTE nIndex;
|
|
|
|
SendMessage(hAdvListCtrl, LVM_SETITEMCOUNT, (WPARAM)(int)NUMJOYDEVS, (LPARAM)LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL);
|
|
|
|
// Set everything to NONE to start!
|
|
do
|
|
{
|
|
itoa((BYTE)n--, (LPTSTR)&sz1);
|
|
|
|
// Insert the ID
|
|
// Set the device ID and ID_NONE in Extended info...
|
|
nIndex = InsertItem( hAdvListCtrl, sz1, n);
|
|
|
|
// Populate the columns with "(none)"
|
|
SetItemText(hAdvListCtrl, nIndex, DEVICE_FRIENDLY, lpstrNone);
|
|
SetItemText(hAdvListCtrl, nIndex, DEVICE_TYPE, lpstrNone);
|
|
#ifdef _UNICODE
|
|
SetItemText(hAdvListCtrl, nIndex, DEVICE_PORT, lpstrNone);
|
|
#endif
|
|
} while( n );
|
|
|
|
if( nAssigned )
|
|
{
|
|
// insert the assigned ones!
|
|
n = nAssigned;
|
|
|
|
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;
|
|
|
|
|
|
#ifndef _UNICODE
|
|
USES_CONVERSION;
|
|
#endif
|
|
|
|
// The low half will be populated by the ID, the upper by bit flags!
|
|
DWORD dwData;
|
|
|
|
do
|
|
{
|
|
// Set the Product Column!
|
|
if( SUCCEEDED(pAssigned[--n]->fnDeviceInterface->GetProperty(DIPROP_PRODUCTNAME, &pDIPropStr->diph)) )
|
|
{
|
|
#ifdef _UNICODE
|
|
SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_TYPE, (LPTSTR)pDIPropStr->wsz);
|
|
#else
|
|
SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_TYPE, (LPTSTR)W2A(pDIPropStr->wsz));
|
|
#endif
|
|
}
|
|
|
|
// Set the Friendly Name!
|
|
if( SUCCEEDED(pAssigned[n]->fnDeviceInterface->GetProperty(DIPROP_INSTANCENAME, &pDIPropStr->diph)) )
|
|
{
|
|
#ifdef _UNICODE
|
|
SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_FRIENDLY, (LPTSTR)pDIPropStr->wsz);
|
|
#else
|
|
SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_FRIENDLY, (LPTSTR)W2A(pDIPropStr->wsz));
|
|
#endif
|
|
}
|
|
|
|
#ifdef _UNICODE
|
|
// Set the Game Port Column!
|
|
if( SUCCEEDED(pAssigned[n]->fnDeviceInterface->GetProperty(DIPROP_GETPORTDISPLAYNAME, &pDIPropStr->diph)) )
|
|
{
|
|
SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_PORT, (LPTSTR)pDIPropStr->wsz);
|
|
} else
|
|
{
|
|
VERIFY(LoadString(ghInstance, IDS_GEN_STATUS_UNKNOWN, sz1, sizeof(sz1)/sizeof(TCHAR)));
|
|
SetItemText(hAdvListCtrl, pAssigned[n]->ID, DEVICE_PORT, (LPTSTR)sz1);
|
|
}
|
|
#endif // _UNICODE
|
|
|
|
// Set the ID in the data...
|
|
// This is necessary for Sorting!
|
|
dwData = pAssigned[n]->ID;
|
|
|
|
//if( pAssigned[n]->clsidPropSheet != CLSID_LegacyServer )
|
|
if( pAssigned[n]->fHasOemSheet )
|
|
{
|
|
LPDIJOYCONFIG_DX5 lpDIJoyConfig = new (DIJOYCONFIG_DX5);
|
|
ASSERT (lpDIJoyConfig);
|
|
|
|
ZeroMemory(lpDIJoyConfig, sizeof(DIJOYCONFIG_DX5));
|
|
|
|
lpDIJoyConfig->dwSize = sizeof (DIJOYCONFIG_DX5);
|
|
|
|
|
|
// Set the DefaultPropertySheet flag
|
|
if( SUCCEEDED(pDIJoyConfig->GetConfig(pAssigned[n]->ID, (LPDIJOYCONFIG)lpDIJoyConfig, DIJC_REGHWCONFIGTYPE)) )
|
|
{
|
|
LPDIJOYTYPEINFO lpDIJoyTypeInfo = new (DIJOYTYPEINFO);
|
|
ASSERT (lpDIJoyTypeInfo);
|
|
|
|
ZeroMemory(lpDIJoyTypeInfo, sizeof(DIJOYTYPEINFO));
|
|
|
|
lpDIJoyTypeInfo->dwSize = sizeof (DIJOYTYPEINFO);
|
|
|
|
if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(lpDIJoyConfig->wszType, lpDIJoyTypeInfo, DITC_FLAGS1 )) )
|
|
{
|
|
if( lpDIJoyTypeInfo->dwFlags1 & JOYTYPE_DEFAULTPROPSHEET )
|
|
{
|
|
// Set the USE_DEFAULT mask!
|
|
dwData |= USE_DEFAULT;
|
|
|
|
// Update the global list!
|
|
pAssigned[n]->clsidPropSheet = CLSID_LegacyServer;
|
|
}
|
|
}
|
|
|
|
if( lpDIJoyTypeInfo )
|
|
delete (lpDIJoyTypeInfo);
|
|
}
|
|
|
|
dwData |= SHOW_DEFAULT;
|
|
|
|
if( lpDIJoyConfig )
|
|
delete (lpDIJoyConfig);
|
|
}
|
|
|
|
// Set the Item Data to the ID!
|
|
SetItemData(hAdvListCtrl, pAssigned[n]->ID, dwData);
|
|
|
|
} while( n );
|
|
|
|
// clean up, clean up... everybody do your share!
|
|
if( pDIPropStr )
|
|
delete (pDIPropStr);
|
|
}
|
|
|
|
// turn the flag off!
|
|
if( nFlags & UPDATE_FOR_ADV )
|
|
nFlags &= ~UPDATE_FOR_ADV;
|
|
|
|
// Turn the redraw flag back on!
|
|
::SendMessage (hAdvListCtrl, WM_SETREDRAW, (WPARAM)TRUE, 0);
|
|
InvalidateRect(hAdvListCtrl, NULL, TRUE);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUNCTION: ChangeDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
//
|
|
// PARAMETERS: HWND hDlg -
|
|
// UINT uMsg -
|
|
// WPARAM wParam -
|
|
// LPARAM lParam -
|
|
//
|
|
// PURPOSE:
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
INT_PTR CALLBACK ChangeDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch( uMsg )
|
|
{
|
|
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:
|
|
{
|
|
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);
|
|
|
|
HWND hCtrl = GetDlgItem(hDlg, IDC_CHANGE_LIST);
|
|
ASSERT (hCtrl);
|
|
|
|
UpdateChangeListCtrl( hCtrl );
|
|
|
|
BYTE nCounter = nAssigned;
|
|
while( nCounter-- )
|
|
{
|
|
if( (BYTE)::SendMessage(hCtrl, LB_GETITEMDATA, (WPARAM)nCounter, 0) == nOldID )
|
|
break;
|
|
}
|
|
|
|
// Set the list box selections!
|
|
::PostMessage(hCtrl, LB_SETCURSEL, (WPARAM)nCounter, 0);
|
|
|
|
// Done with the ListCtrl, now... on to the ComboBox
|
|
if( nFlags & ON_NT )
|
|
{
|
|
|
|
if( !PopulatePortList(hDlg) )
|
|
{
|
|
#ifdef _DEBUG
|
|
OutputDebugString(TEXT("JOY.CPL: ADVANCED.CPP: PopulatePortList failed!\n"));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// Set up the Spin Control!
|
|
HWND hSpinCtrl = GetDlgItem(hDlg, IDC_SPIN);
|
|
|
|
::PostMessage(hSpinCtrl, UDM_SETRANGE, 0, MAKELPARAM(NUMJOYDEVS, 1));
|
|
::PostMessage(hSpinCtrl, UDM_SETBASE, 10, 0L);
|
|
::PostMessage(hSpinCtrl, UDM_SETPOS, 0, MAKELPARAM(nOldID+1, 0));
|
|
}
|
|
return(FALSE);
|
|
|
|
case WM_COMMAND:
|
|
{
|
|
switch( LOWORD(wParam) )
|
|
{
|
|
/* I'll leave this commented out, as it's likely they'll want double clicking back once I take it out
|
|
case IDC_CHANGE_LIST:
|
|
// Fall into Change on DBLCLK
|
|
if (HIWORD(wParam) != LBN_DBLCLK)
|
|
break;
|
|
*/
|
|
|
|
case IDOK:
|
|
{
|
|
HWND hCtrl = GetDlgItem(hDlg, IDC_CHANGE_LIST);
|
|
ASSERT (hCtrl);
|
|
|
|
char nSelectedItem = (char)(SendMessage(hCtrl, LB_GETITEMDATA, SendMessage(hCtrl, LB_GETCURSEL, 0, 0), 0));
|
|
|
|
TCHAR tsz[4];
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_SPINBUDDY);
|
|
|
|
tsz[0] = 4;
|
|
|
|
SendMessage(hCtrl, EM_GETLINE, 0, (LPARAM)(LPCSTR)&tsz);
|
|
|
|
// The '-1' is to account for the 1 based list
|
|
// and the 0 based id's!
|
|
char nSelectedID = (char)atoi((LPCTSTR)&tsz)-1;
|
|
|
|
pDIJoyConfig->Acquire();
|
|
|
|
// first check to see if the user has selected NONE!
|
|
if( nSelectedItem == -2 )
|
|
{
|
|
// User has selected NONE!
|
|
VERIFY (SUCCEEDED(pDIJoyConfig->DeleteConfig(nSelectedID)));
|
|
} else
|
|
{
|
|
// see if the selected item and the ID match!
|
|
// if so... get out of here!
|
|
if( nSelectedID == nSelectedItem )
|
|
{
|
|
#ifdef _DEBUG
|
|
OutputDebugString(TEXT("JOY.CPL: ADVANCED.CPP: OnChangeCommand: IDOK: Device already at selected ID!\n"));
|
|
#endif
|
|
} else
|
|
{
|
|
SwapIDs(nSelectedID, nSelectedItem);
|
|
// SetListCtrlItemFocus(hAdvListCtrl, (BYTE)nSelectedID);
|
|
}
|
|
}
|
|
|
|
pDIJoyConfig->Unacquire();
|
|
}
|
|
// missing break intentional!
|
|
|
|
case IDCANCEL:
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
break;
|
|
}
|
|
}
|
|
return(1);
|
|
|
|
case WM_DESTROY:
|
|
DestroyIcon((HICON)SendMessage(hDlg, WM_GETICON, (WPARAM)ICON_SMALL, 0));
|
|
return(TRUE);
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTION: PopulateGlobalPortDriverComboBox( void )
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// PURPOSE:
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#ifndef UNICODE
|
|
void PopulateGlobalPortDriverComboBox( void )
|
|
{
|
|
HWND hCtrl = GetDlgItem(ghDlg, IDC_COMBO1);
|
|
|
|
// make sure the combo is clear before we start populating it!
|
|
SendMessage(hCtrl, CB_RESETCONTENT, 0, 0);
|
|
|
|
// Type info
|
|
LPDIJOYTYPEINFO_DX5 lpdiJoyInfo = new (DIJOYTYPEINFO_DX5);
|
|
ASSERT (lpdiJoyInfo);
|
|
|
|
ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
|
|
|
|
lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
|
|
|
|
BYTE nIndex = nGameportDriver;
|
|
USES_CONVERSION;
|
|
|
|
// Populate the Combobox
|
|
while( nIndex-- )
|
|
{
|
|
// populate the Type Info and place the Index in the extra memory!
|
|
if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszGameportDriverArray[nIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_DISPLAYNAME)) )
|
|
::SendMessage(hCtrl, CB_SETITEMDATA, ::SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)W2A(lpdiJoyInfo->wszDisplayName)), nIndex);
|
|
#ifdef _DEBUG
|
|
else
|
|
OutputDebugString (TEXT("JOY.CPL: ADVANCED.CPP: PopulateGlobalPortDriverComboBox: GetTypeInfo failed!\n"));
|
|
#endif
|
|
}
|
|
|
|
// Display the Current selected GlobalPortDriver or None!
|
|
LPDIJOYUSERVALUES pDIJoyUserValues = new DIJOYUSERVALUES;
|
|
ASSERT (pDIJoyUserValues);
|
|
|
|
ZeroMemory(pDIJoyUserValues, sizeof(DIJOYUSERVALUES));
|
|
|
|
pDIJoyUserValues->dwSize = sizeof(DIJOYUSERVALUES);
|
|
|
|
VERIFY (SUCCEEDED(pDIJoyConfig->GetUserValues(pDIJoyUserValues, DIJU_GLOBALDRIVER)));
|
|
|
|
// Fix #9815, If the user has No Global port driver label as NONE!
|
|
if( !(*pDIJoyUserValues->wszGlobalDriver && pDIJoyUserValues->wszGlobalDriver) )
|
|
{
|
|
iGameportDriverItem = NO_ITEM;
|
|
|
|
PostMessage(hCtrl, CB_SETCURSEL, (WPARAM)SendMessage(hCtrl, CB_FINDSTRING, (WPARAM)-1, (LPARAM)lpstrNone), (LPARAM)0);
|
|
} else
|
|
{
|
|
ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
|
|
|
|
lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
|
|
|
|
nIndex = 0;
|
|
|
|
// get type info 'till you find the one you want and place it's callout
|
|
while( pwszGameportDriverArray[nIndex] )
|
|
{
|
|
VERIFY(SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszGameportDriverArray[nIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_CALLOUT | DITC_DISPLAYNAME)));
|
|
|
|
if( _wcsicmp(lpdiJoyInfo->wszCallout, pDIJoyUserValues->wszGlobalDriver) == 0 )
|
|
{
|
|
::PostMessage(hCtrl, CB_SETCURSEL, (WPARAM)::SendMessage(hCtrl, CB_FINDSTRING, (WPARAM)-1, (LPARAM)W2A(lpdiJoyInfo->wszDisplayName)), (LPARAM)0);
|
|
|
|
iGameportDriverItem = nIndex;
|
|
|
|
// enable the PollFlags checkbox!
|
|
if( _wcsicmp(pDIJoyUserValues->wszGlobalDriver, lpMSANALOG_VXD) == 0 )
|
|
{
|
|
SetWindowPos( GetDlgItem( ghDlg, IDC_POLLFLAGS), NULL, NULL, NULL, NULL, NULL,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW );
|
|
|
|
VERIFY(SUCCEEDED(pDIJoyConfig->Acquire()));
|
|
|
|
// Get the state from the registry and update the check mark
|
|
HKEY hKey;
|
|
DWORD dwFlag;
|
|
|
|
if( SUCCEEDED(pDIJoyConfig->OpenTypeKey(pwszGameportDriverArray[nIndex], KEY_ALL_ACCESS, &hKey)) )
|
|
{
|
|
ULONG ulType = REG_BINARY;
|
|
ULONG ulSize = sizeof(dwFlag);
|
|
|
|
// this will happen if there is no entry for POLL_FLAGS_REG_STR
|
|
if( ERROR_SUCCESS != RegQueryValueEx(hKey, POLL_FLAGS_REG_STR, NULL, &ulType, (PBYTE)&dwFlag, &ulSize) )
|
|
dwFlag = 0;
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
pDIJoyConfig->Unacquire();
|
|
|
|
::PostMessage(GetDlgItem(ghDlg, IDC_POLLFLAGS), BM_SETCHECK, (dwFlag) ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
}
|
|
break;
|
|
}
|
|
nIndex++;
|
|
}
|
|
}
|
|
|
|
// delete the DIJOYUSERVALUES variable
|
|
if( pDIJoyUserValues )
|
|
delete pDIJoyUserValues;
|
|
|
|
// clean up, clean up... everybody do your share!
|
|
if( lpdiJoyInfo )
|
|
delete (lpdiJoyInfo);
|
|
|
|
// VERIFY(SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lpstrNone) != CB_ERR);
|
|
}
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTION: SubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
//
|
|
// PARAMETERS: HWND hWnd -
|
|
// UINT uMsg -
|
|
// WPARAM wParam -
|
|
// LPARAM lParam -
|
|
//
|
|
// PURPOSE: SubClass Procedure for Setting the ID to NONE on VK_DELETE on the Advanced Page
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
BOOL WINAPI KeySubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch( uMsg )
|
|
{
|
|
case WM_COMMAND:
|
|
switch( LOWORD(wParam) )
|
|
{
|
|
case IDCANCEL:
|
|
case IDOK:
|
|
if( nFlags & UPDATE_INPROCESS )
|
|
{
|
|
bProcess = (LOWORD(wParam) == IDOK) ? TRUE : FALSE;
|
|
SetFocus(hAdvListCtrl);
|
|
nFlags &= ~UPDATE_INPROCESS;
|
|
return(FALSE);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return(BOOL)CallWindowProc(fpPageWndProc, hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTION: SubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
//
|
|
// PARAMETERS: HWND hWnd -
|
|
// UINT uMsg -
|
|
// WPARAM wParam -
|
|
// LPARAM lParam -
|
|
//
|
|
// PURPOSE: SubClass Procedure for Setting the ID to NONE on VK_DELETE on the Advanced Page
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
BOOL WINAPI SubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch( uMsg )
|
|
{
|
|
case WM_PARENTNOTIFY:
|
|
if( LOWORD(wParam) == WM_LBUTTONDOWN )
|
|
{
|
|
if( nFlags & UPDATE_INPROCESS )
|
|
SetFocus(hAdvListCtrl);
|
|
}
|
|
break;
|
|
|
|
case WM_SYSCOMMAND:
|
|
if( wParam & SC_VSCROLL )
|
|
{
|
|
if( nFlags & UPDATE_INPROCESS )
|
|
SetFocus(hAdvListCtrl);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return(BOOL)CallWindowProc(fpMainWndProc, hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTION: UpdateChangeListCtrl ( HWND hCtrl )
|
|
//
|
|
// PARAMETERS: HWND hCtrl - Handle to Change list box
|
|
//
|
|
// PURPOSE: Update the Change List box
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static BOOL UpdateChangeListCtrl ( HWND hCtrl )
|
|
{
|
|
#ifndef _UNICODE
|
|
USES_CONVERSION;
|
|
#endif
|
|
|
|
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;
|
|
|
|
BYTE n = nAssigned;
|
|
|
|
LPTSTR lpStr = new (TCHAR[MAX_STR_LEN]);
|
|
ASSERT (lpStr);
|
|
|
|
// find and assign ID's
|
|
while( n-- )
|
|
{
|
|
if( SUCCEEDED(pAssigned[n]->fnDeviceInterface->GetProperty(DIPROP_INSTANCENAME, &pDIPropStr->diph)) )
|
|
{
|
|
|
|
// Our buffer is Only soooo big...
|
|
// besides, it just doesn't make sence to display Everything!
|
|
if( wcslen(pDIPropStr->wsz) > STR_LEN_64 )
|
|
{
|
|
pDIPropStr->wsz[60] = pDIPropStr->wsz[61] = pDIPropStr->wsz[62] = TEXT('.');
|
|
pDIPropStr->wsz[63] = TEXT('\0');
|
|
}
|
|
|
|
#ifdef _UNICODE
|
|
_tcscpy(lpStr, pDIPropStr->wsz);
|
|
#else
|
|
_tcscpy(lpStr, W2A(pDIPropStr->wsz));
|
|
#endif
|
|
|
|
// Put the first bracket on...
|
|
_tcscat(lpStr, TEXT(" ("));
|
|
|
|
// Now, get the productname of the device!
|
|
if( SUCCEEDED(pAssigned[n]->fnDeviceInterface->GetProperty(DIPROP_PRODUCTNAME, &pDIPropStr->diph)) )
|
|
{
|
|
#ifdef _UNICODE
|
|
_tcscat(lpStr, pDIPropStr->wsz);
|
|
#else
|
|
_tcscat(lpStr, W2A(pDIPropStr->wsz));
|
|
#endif
|
|
}
|
|
|
|
// put the end bracket on...
|
|
_tcscat(lpStr, TEXT(")"));
|
|
|
|
BYTE n1 = (BYTE)SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpStr);
|
|
SendMessage(hCtrl, LB_SETITEMDATA, n1, pAssigned[n]->ID);
|
|
}
|
|
#ifdef _DEBUG
|
|
else OutputDebugString(TEXT("JOY.CPL: Advanced.cpp: UpdateChangeListCtrl: GetProperty failed!\n"));
|
|
#endif // _DEBUG
|
|
}
|
|
|
|
if( lpStr )
|
|
delete[] (lpStr);
|
|
|
|
if( pDIPropStr )
|
|
delete (pDIPropStr);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTION: itoa(BYTE n, LPTSTR lpStr)
|
|
//
|
|
// PARAMETERS: BYTE n - Number to be translated
|
|
// LPTSTR lpStr - Buffer to recieve translated value
|
|
//
|
|
// PURPOSE: Convert BYTE values < 20 to strings.
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void itoa(BYTE n, LPTSTR lpStr)
|
|
{
|
|
// designed for use with the CPL ONLY!
|
|
// Only supports values < NUMJOYDEVS!
|
|
if( n > NUMJOYDEVS )
|
|
{
|
|
#ifdef _DEBUG
|
|
OutputDebugString(TEXT("JOY.CPL: itoa: n > NUMJOYDEVS!\n"));
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
lpStr[0] = n % 10 + '0';
|
|
|
|
if( n > 9 )
|
|
{
|
|
// Reverse the string and send it back...
|
|
lpStr[1] = lpStr[0];
|
|
lpStr[0] = '1';
|
|
lpStr[2] = '\0';
|
|
} else lpStr[1] = '\0';
|
|
}
|
|
|
|
int CALLBACK CompareIDItems(LPARAM item1, LPARAM item2, LPARAM uDirection)
|
|
{
|
|
if( LOWORD(item1) == LOWORD(item2) )
|
|
return(0);
|
|
|
|
short nRet = (LOWORD(item1) > LOWORD(item2)) ? 1 : -1;
|
|
|
|
return(uDirection) ? nRet : (nRet < 0) ? 1 : -1;
|
|
}
|
|
|
|
void LaunchChange( HWND hTmp )
|
|
{
|
|
// Don't allow if you're in USER mode!
|
|
if( (nFlags & USER_MODE) )
|
|
return;
|
|
|
|
iAdvItem = (short)::SendMessage(hAdvListCtrl, LVM_GETNEXTITEM, (WPARAM)(int)-1, MAKELPARAM(LVNI_SELECTED, 0));
|
|
|
|
nOldID = (BYTE)GetItemData(hAdvListCtrl, (BYTE)iAdvItem);
|
|
|
|
if( nOldID & ID_NONE )
|
|
return;
|
|
|
|
// valid returns are IDOK, IDCANCEL, and IDC_CHANGE_LIST
|
|
if( IDCANCEL != DialogBox(ghInstance, (PTSTR)IDD_ADV_CHANGE, ghDlg, ChangeDialogProc) )
|
|
{
|
|
// Yeah, it's not really a DEVICEARRIVAL...
|
|
::SendMessage(hTmp, WM_DEVICECHANGE, DBT_DEVICEARRIVAL, 0);
|
|
::PostMessage(hAdvListCtrl, LVM_ENSUREVISIBLE, (BYTE)iAdvItem, TRUE);
|
|
SetFocus(hAdvListCtrl);
|
|
SetListCtrlItemFocus(hAdvListCtrl, (BYTE)iAdvItem);
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTION: SortTextItems( CListCtrl *pCtrl, short nCol, BOOL bAscending, int low, int high )
|
|
//
|
|
// SortTextItems - Sort the list based on column text
|
|
//
|
|
// PARAMETERS:
|
|
// pCtrl - pointer to list to sort
|
|
// nCol - column that contains the text to be sorted
|
|
// bAscending - indicate sort order
|
|
// low - row to start scanning from - default row is 0
|
|
// high - row to end scan. -1 indicates last row
|
|
//
|
|
// PURPOSE: Sort text items in ListCtrl
|
|
// Returns - Returns true for success
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
BOOL SortTextItems( CListCtrl *pCtrl, short nCol, BOOL bAscending, short low, short high )
|
|
{
|
|
CHeaderCtrl* pHeader = (CHeaderCtrl*) pCtrl->GetDlgItem(0);
|
|
|
|
if( nCol >= pHeader->GetItemCount() )
|
|
return(FALSE);
|
|
|
|
if( high == -1 )
|
|
high = pCtrl->GetItemCount() - 1;
|
|
|
|
short lo = low;
|
|
short hi = high;
|
|
|
|
if( hi <= lo ) return(FALSE);
|
|
|
|
// The choices here are to malloc a buffer large enough for the largest
|
|
// string, or malloc an LV_ITEM struct to get the length, then malloc
|
|
// just the size we need.
|
|
CString midItem = pCtrl->GetItemText( (lo+hi)/2, nCol );
|
|
|
|
// loop through the list until indices cross
|
|
while( lo <= hi )
|
|
{
|
|
// rowText will hold all column text for one row
|
|
CStringArray rowText;
|
|
|
|
// find the first element that is greater than or equal to
|
|
// the partition element starting from the left Index.
|
|
if( bAscending )
|
|
while( ( lo < high ) && ( pCtrl->GetItemText(lo, nCol) < midItem ) )
|
|
++lo;
|
|
else
|
|
while( ( lo < high ) && ( pCtrl->GetItemText(lo, nCol) > midItem ) )
|
|
++lo;
|
|
|
|
// find an element that is smaller than or equal to
|
|
// the partition element starting from the right Index.
|
|
if( bAscending )
|
|
while( ( hi > low ) && ( pCtrl->GetItemText(hi, nCol) > midItem ) )
|
|
--hi;
|
|
else
|
|
while( ( hi > low ) && ( pCtrl->GetItemText(hi, nCol) < midItem ) )
|
|
--hi;
|
|
|
|
// if the indexes have not crossed, swap
|
|
// and if the items are not equal
|
|
if( lo <= hi )
|
|
{
|
|
// swap only if the items are not equal
|
|
if( pCtrl->GetItemText(lo, nCol) != pCtrl->GetItemText(hi, nCol) )
|
|
{
|
|
// swap the rows
|
|
LV_ITEM lvitemlo, lvitemhi;
|
|
BYTE nColCount = (BYTE)pHeader->GetItemCount();
|
|
rowText.SetSize( nColCount );
|
|
|
|
for( BYTE i = 0; i < nColCount; i++ )
|
|
rowText[i] = pCtrl->GetItemText(lo, i);
|
|
|
|
lvitemlo.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
|
|
lvitemlo.iItem = lo;
|
|
lvitemlo.iSubItem = 0;
|
|
lvitemlo.stateMask = LVIS_CUT | LVIS_DROPHILITED | LVIS_FOCUSED | LVIS_SELECTED | LVIS_OVERLAYMASK | LVIS_STATEIMAGEMASK;
|
|
lvitemhi = lvitemlo;
|
|
lvitemhi.iItem = hi;
|
|
|
|
ListView_GetItem(pCtrl->GetSafeHwnd(), &lvitemlo );
|
|
|
|
ListView_GetItem(pCtrl->GetSafeHwnd(), &lvitemhi );
|
|
|
|
for( i=0; i<nColCount; i++ )
|
|
pCtrl->SetItemText(lo, i, pCtrl->GetItemText(hi, i));
|
|
|
|
lvitemhi.iItem = lo;
|
|
ListView_SetItem(pCtrl->GetSafeHwnd(), &lvitemhi );
|
|
|
|
for( i=0; i<nColCount; i++ )
|
|
pCtrl->SetItemText(hi, i, rowText[i]);
|
|
|
|
lvitemlo.iItem = hi;
|
|
ListView_SetItem(pCtrl->GetSafeHwnd(), &lvitemlo );
|
|
}
|
|
|
|
++lo;
|
|
--hi;
|
|
}
|
|
}
|
|
|
|
// If the right index has not reached the left side of array
|
|
// must now sort the left partition.
|
|
if( low < hi )
|
|
SortTextItems( pCtrl, nCol, bAscending, low, hi);
|
|
|
|
// If the left index has not reached the right side of array
|
|
// must now sort the right partition.
|
|
if( lo < high )
|
|
SortTextItems( pCtrl, nCol, bAscending, lo, high);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTION: EditSubLabel( BYTE nItem, BYTE nCol )
|
|
//
|
|
// PARAMETERS:
|
|
// EditSubLabel - Start edit of a sub item label
|
|
// Returns - Temporary pointer to the new edit control
|
|
// nItem - The row index of the item to edit
|
|
// nCol - The column of the sub item.
|
|
// PURPOSE: Provide editing services for any column in a CListCtrl
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void EditSubLabel( BYTE nItem, BYTE nCol )
|
|
{
|
|
#ifdef _DEBUG
|
|
// Make sure that the item is visible
|
|
if( !SendMessage(hAdvListCtrl, LVM_ENSUREVISIBLE, nItem, TRUE ) )
|
|
{
|
|
OutputDebugString(TEXT("JOY.CPL: ADVANCED.CPP: EditSubLabel: requested item not visible!\n"));
|
|
return;
|
|
}
|
|
#endif // _DEBUG
|
|
|
|
// Get the column offset
|
|
short offset = 0;
|
|
BYTE i = 0;
|
|
|
|
// OK, so here's what we have to do...
|
|
// Traverse the columns incrementing the widths of the ones lesser than the one we're looking for!
|
|
|
|
HDITEM *phdItem = new (HDITEM);
|
|
ASSERT (phdItem);
|
|
|
|
phdItem->mask = HDI_ORDER | HDI_WIDTH;
|
|
|
|
HWND hHeader = GetDlgItem(hAdvListCtrl, 0);
|
|
BYTE nColumns = (BYTE)::SendMessage(hHeader, HDM_GETITEMCOUNT, 0, 0L);
|
|
BYTE nColWidth;
|
|
|
|
do
|
|
{
|
|
::SendMessage(hHeader, HDM_GETITEM, (WPARAM)(int)--nColumns, (LPARAM)(LPHDITEM)phdItem);
|
|
|
|
if( phdItem->iOrder < nCol )
|
|
offset += (short)phdItem->cxy;
|
|
|
|
if( phdItem->iOrder == nCol )
|
|
nColWidth = (BYTE)phdItem->cxy;
|
|
} while( nColumns );
|
|
|
|
if( phdItem )
|
|
delete (phdItem);
|
|
|
|
RECT rect;
|
|
ListView_GetItemRect(hAdvListCtrl, nItem, &rect, LVIR_BOUNDS );
|
|
|
|
// Now scroll if we need to expose the column
|
|
CRect rcClient;
|
|
::GetClientRect(hAdvListCtrl, &rcClient);
|
|
|
|
if( offset + rect.left < 0 || offset + rect.left > rcClient.right )
|
|
{
|
|
::SendMessage(hAdvListCtrl, LVM_SCROLL, (WPARAM)(int)offset + rect.left, (LPARAM)(int)0);
|
|
rect.left -= (offset + rect.left);
|
|
}
|
|
|
|
rect.left += offset+4;
|
|
rect.right = rect.left + nColWidth - 3; // + ::SendMessage(hAdvListCtrl, LVM_GETCOLUMNWIDTH, (WPARAM)(int)nCol, (LPARAM)0L) - 3 ;
|
|
|
|
if( rect.right > rcClient.right )
|
|
rect.right = rcClient.right;
|
|
|
|
CEdit *pEdit = new CInPlaceEdit(nItem, 1);
|
|
ASSERT (pEdit);
|
|
|
|
// malloc the list ctrl
|
|
CWnd *pListCtrl = new (CWnd);
|
|
ASSERT (pListCtrl);
|
|
|
|
pListCtrl->Attach(hAdvListCtrl);
|
|
|
|
pEdit->Create(WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_CENTER, rect, pListCtrl, IDC_IPEDIT );
|
|
|
|
pListCtrl->Detach();
|
|
|
|
if( pListCtrl )
|
|
delete (pListCtrl);
|
|
}
|
|
|
|
#ifdef _UNICODE
|
|
void SwapIDs(BYTE nSource, BYTE nTarget)
|
|
{
|
|
// malloc and retrieve the data from the selected item
|
|
LPDIJOYCONFIG lpSelectedID = new (DIJOYCONFIG);
|
|
ASSERT (lpSelectedID);
|
|
|
|
ZeroMemory(lpSelectedID, sizeof(DIJOYCONFIG));
|
|
|
|
lpSelectedID->dwSize = sizeof(DIJOYCONFIG);
|
|
|
|
// Get the Config of device on ID taken from Change List box!
|
|
HRESULT hr = pDIJoyConfig->GetConfig(nSource, lpSelectedID, DIJC_ALL);
|
|
|
|
if( hr == DIERR_NOTFOUND || hr == S_FALSE )
|
|
{
|
|
// No Object on Selected ID!
|
|
if( lpSelectedID )
|
|
delete (lpSelectedID);
|
|
|
|
lpSelectedID = NULL;
|
|
}
|
|
|
|
// malloc and retrieve the data from the item associated
|
|
// with the ID taken from the Item selected in the List box!
|
|
LPDIJOYCONFIG lpSelectedItem = new (DIJOYCONFIG);
|
|
ASSERT (lpSelectedItem);
|
|
|
|
ZeroMemory(lpSelectedItem, sizeof(DIJOYCONFIG));
|
|
|
|
lpSelectedItem->dwSize = sizeof (DIJOYCONFIG);
|
|
|
|
hr = pDIJoyConfig->GetConfig(nTarget, lpSelectedItem, DIJC_ALL);
|
|
|
|
if( hr == DIERR_NOTFOUND || hr == S_FALSE )
|
|
{
|
|
if( lpSelectedItem )
|
|
delete (lpSelectedItem);
|
|
|
|
lpSelectedItem = NULL;
|
|
}
|
|
|
|
// ***********************************************************
|
|
// Delete the configurations!
|
|
// ***********************************************************
|
|
|
|
// Set the hour glass
|
|
SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
// ********************************************************
|
|
// OK, now... at this point you have:
|
|
// lpSelectedID: containing NULL if the device wasn't present or...
|
|
// a valid pointer containing the configuration of nSelectedID
|
|
// lpSelected : containing NULL if the device wasn't present or...
|
|
// a valid pointer containing the configuration of id
|
|
// ********************************************************
|
|
// Time to Set the Configurations!
|
|
|
|
if( lpSelectedID )
|
|
{
|
|
hr = pDIJoyConfig->SetConfig(nTarget, lpSelectedID, DIJC_ALL);
|
|
|
|
if( lpSelectedID )
|
|
delete (lpSelectedID);
|
|
} else pDIJoyConfig->DeleteConfig(nSource);
|
|
|
|
// delete both configurations
|
|
// pointers will be NULL if the config was not found!
|
|
if( lpSelectedItem )
|
|
{
|
|
hr = pDIJoyConfig->SetConfig(nSource, lpSelectedItem, DIJC_ALL );
|
|
|
|
if( lpSelectedItem )
|
|
delete (lpSelectedItem);
|
|
}
|
|
|
|
pDIJoyConfig->SendNotify();
|
|
|
|
// Set the hour glass
|
|
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
|
}
|
|
|
|
#else
|
|
|
|
// Memphis version of SwapIDs...
|
|
// Caution!!! Very Sensitive!!!
|
|
void SwapIDs(BYTE nSelectedID, BYTE nSelectedItem)
|
|
{
|
|
// malloc and retrieve the data from the selected item
|
|
LPDIJOYCONFIG lpSelectedID = new (DIJOYCONFIG);
|
|
|
|
DWORD dwSelectedID = 0, dwSelectedItem = 0;
|
|
|
|
ASSERT (lpSelectedID);
|
|
|
|
ZeroMemory(lpSelectedID, sizeof(DIJOYCONFIG));
|
|
|
|
lpSelectedID->dwSize = sizeof(DIJOYCONFIG);
|
|
|
|
// Get the Config of device on ID taken from Change List box!
|
|
HRESULT hr = pDIJoyConfig->GetConfig(nSelectedID, lpSelectedID, DIJC_ALL);
|
|
|
|
if( hr == DIERR_NOTFOUND || hr == S_FALSE )
|
|
{
|
|
// No Object on Selected ID!
|
|
if( lpSelectedID )
|
|
delete (lpSelectedID);
|
|
|
|
lpSelectedID = NULL;
|
|
} else {
|
|
if( lpSelectedID )
|
|
delete (lpSelectedID);
|
|
|
|
lpSelectedID = NULL;
|
|
|
|
Error((short)IDS_DEST_ID_OCCUPIED_TITLE, (short)IDS_DEST_ID_OCCUPIED);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// malloc and retrieve the data from the item associated
|
|
// with the ID taken from the Item selected in the List box!
|
|
LPDIJOYCONFIG lpSelectedItem = new (DIJOYCONFIG);
|
|
ASSERT (lpSelectedItem);
|
|
|
|
ZeroMemory(lpSelectedItem, sizeof(DIJOYCONFIG));
|
|
|
|
lpSelectedItem->dwSize = sizeof (DIJOYCONFIG);
|
|
|
|
hr = pDIJoyConfig->GetConfig(nSelectedItem, lpSelectedItem, DIJC_ALL);
|
|
|
|
if( hr == DIERR_NOTFOUND || hr == S_FALSE )
|
|
{
|
|
if( lpSelectedItem )
|
|
delete (lpSelectedItem);
|
|
|
|
lpSelectedItem = NULL;
|
|
|
|
return;
|
|
}
|
|
|
|
// ***********************************************************
|
|
// Delete the configurations!
|
|
// ***********************************************************
|
|
|
|
// Set the hour glass
|
|
SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
// ********************************************************
|
|
// OK, now... at this point you have:
|
|
// lpSelectedID: containing NULL if the device wasn't present or...
|
|
// a valid pointer containing the configuration of nSelectedID
|
|
// lpSelected : containing NULL if the device wasn't present or...
|
|
// a valid pointer containing the configuration of id
|
|
// ********************************************************
|
|
// Time to Set the Configurations!
|
|
|
|
|
|
if( lpSelectedID )
|
|
{
|
|
DWORD dwFlags = DIJC_REGHWCONFIGTYPE | DIJC_CALLOUT | DIJC_GAIN | DIJC_GUIDINSTANCE;
|
|
USES_CONVERSION;
|
|
|
|
// if the callout is joyhid.vxd then the device is USB so...
|
|
// OR on the DIJC_WDMGAMEPORT flag!
|
|
if( !_stricmp(TEXT("joyhid.vxd"), W2A(lpSelectedID->wszCallout)) )
|
|
{
|
|
// dwFlags |= DIJC_WDMGAMEPORT;
|
|
dwSelectedID = 2;
|
|
} else
|
|
{
|
|
dwSelectedID = 1;
|
|
}
|
|
|
|
if( dwSelectedID == 1 ) {
|
|
hr = pDIJoyConfig->DeleteConfig(nSelectedID);
|
|
|
|
/*
|
|
* This notify is to fix the bug changing id on 2-axis 2-button joystick.
|
|
*/
|
|
pDIJoyConfig->SendNotify();
|
|
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
hr = pDIJoyConfig->SetConfig(nSelectedItem, lpSelectedID, dwFlags );
|
|
|
|
if( SUCCEEDED(hr) ) {
|
|
pDIJoyConfig->SendNotify();
|
|
}
|
|
}
|
|
} else {
|
|
hr = pDIJoyConfig->SetConfig(nSelectedItem, lpSelectedID, dwFlags);
|
|
|
|
pDIJoyConfig->SendNotify();
|
|
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
hr = pDIJoyConfig->DeleteConfig(nSelectedID);
|
|
|
|
pDIJoyConfig->SendNotify();
|
|
|
|
if( nSelectedID < nSelectedItem ) {
|
|
pDIJoyConfig->SendNotify();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if( lpSelectedID )
|
|
delete (lpSelectedID);
|
|
}
|
|
|
|
// delete both configurations
|
|
// pointers will be NULL if the config was not found!
|
|
if( lpSelectedItem )
|
|
{
|
|
DWORD dwFlags = DIJC_REGHWCONFIGTYPE | DIJC_CALLOUT | DIJC_GAIN | DIJC_GUIDINSTANCE;
|
|
USES_CONVERSION;
|
|
|
|
if( _tcsicmp(TEXT("joyhid.vxd"), W2A(lpSelectedItem->wszCallout)) == 0 )
|
|
{
|
|
// dwFlags |= DIJC_WDMGAMEPORT;
|
|
dwSelectedItem = 2; //joyhid.vxd
|
|
}
|
|
#if 0
|
|
/*
|
|
* Since MSGAME.VXD will directly write to the registry with some unhealthy data.
|
|
* We have to change it before we move to other ID.
|
|
*/
|
|
else if( _tcsicmp(TEXT("MSGAME.VXD"), W2A(lpSelectedItem->wszCallout)) == 0 )
|
|
{
|
|
lpSelectedItem->hwc.dwType += 1;
|
|
dwSelectedItem = 3; //msgame.vxd (Sidewinder driver)
|
|
}
|
|
#endif
|
|
else {
|
|
dwSelectedItem = 1; //vjoyd.vxd
|
|
}
|
|
|
|
if( dwSelectedItem == 1 // VJOYD.VXD,
|
|
// || dwSelectedItem == 3
|
|
){ // MSGAME.VXD
|
|
hr = pDIJoyConfig->DeleteConfig(nSelectedItem);
|
|
|
|
/*
|
|
* This notify is to fix the bug changing id on 2-axis 2-button joystick.
|
|
*/
|
|
pDIJoyConfig->SendNotify();
|
|
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
hr = pDIJoyConfig->SetConfig(nSelectedID, lpSelectedItem, dwFlags );
|
|
|
|
if( SUCCEEDED(hr) ) {
|
|
pDIJoyConfig->SendNotify();
|
|
}
|
|
}
|
|
} else {
|
|
hr = pDIJoyConfig->SetConfig(nSelectedID, lpSelectedItem, dwFlags );
|
|
|
|
/*
|
|
* This notify is to fix the bug changing id on 2-axis 2-button joystick.
|
|
*/
|
|
pDIJoyConfig->SendNotify();
|
|
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
hr = pDIJoyConfig->DeleteConfig(nSelectedItem);
|
|
|
|
pDIJoyConfig->SendNotify();
|
|
|
|
if( nSelectedID < nSelectedItem ) {
|
|
pDIJoyConfig->SendNotify();
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( lpSelectedItem )
|
|
{
|
|
delete (lpSelectedItem);
|
|
}
|
|
}
|
|
|
|
// Set the hour glass
|
|
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
|
}
|
|
#endif
|
|
|