Merge pull request #1837 from project64/input-plugin

Input plugin
This commit is contained in:
zilmar 2020-07-15 21:20:24 +09:30 committed by GitHub
commit ac45d34b29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 2687 additions and 11 deletions

5
.gitignore vendored
View File

@ -50,6 +50,8 @@ Thumbs.db
/Plugin/Input/AndroidInput_d.dll
/Plugin/Input/PJ64_NRage.dll
/Plugin/Input/PJ64_NRage_d.dll
/Plugin/Input/Project64-Input.dll
/Plugin/Input/Project64-Input_d.dll
/Plugin/RSP/lib
/Plugin/RSP/map
/Plugin/RSP/pdb
@ -76,6 +78,8 @@ Thumbs.db
/Plugin64/Input/AndroidInput_d.dll
/Plugin64/Input/PJ64_NRage.dll
/Plugin64/Input/PJ64_NRage_d.dll
/Plugin64/Input/Project64-Input.dll
/Plugin64/Input/Project64-Input_d.dll
/Plugin64/RSP/lib
/Plugin64/RSP/map
/Plugin64/RSP/pdb
@ -86,6 +90,7 @@ Thumbs.db
/Source/nragev20/Version.h
/Source/Project64-audio/Version.h
/Source/Project64-core/Version.h
/Source/Project64-input/Version.h
/Source/Project64-video/Version.h
/Source/RSP/Version.h
/Save

View File

@ -60,9 +60,14 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JoinSettings", "Source\JoinSettings\JoinSettings.vcxproj", "{B2E592F2-F416-4049-BD22-9CA9090242BB}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Project64", "Source\Project64\Project64.vcxproj", "{7E534C8E-1ACE-4A88-8807-39A11ED4DA18}"
ProjectSection(ProjectDependencies) = postProject
{D3F979CE-8FA7-48C9-A2B3-A33594B48536} = {D3F979CE-8FA7-48C9-A2B3-A33594B48536}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "discord-rpc", "Source\3rdParty\discord-rpc\discord-rpc.vcxproj", "{DCC841B2-298A-40F0-84D1-ACBABD3B86E8}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Project64-input", "Source\Project64-input\Project64-input.vcxproj", "{D3F979CE-8FA7-48C9-A2B3-A33594B48536}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@ -222,6 +227,14 @@ Global
{DCC841B2-298A-40F0-84D1-ACBABD3B86E8}.Release|Win32.Build.0 = Release|Win32
{DCC841B2-298A-40F0-84D1-ACBABD3B86E8}.Release|x64.ActiveCfg = Release|x64
{DCC841B2-298A-40F0-84D1-ACBABD3B86E8}.Release|x64.Build.0 = Release|x64
{D3F979CE-8FA7-48C9-A2B3-A33594B48536}.Debug|Win32.ActiveCfg = Debug|Win32
{D3F979CE-8FA7-48C9-A2B3-A33594B48536}.Debug|Win32.Build.0 = Debug|Win32
{D3F979CE-8FA7-48C9-A2B3-A33594B48536}.Debug|x64.ActiveCfg = Debug|x64
{D3F979CE-8FA7-48C9-A2B3-A33594B48536}.Debug|x64.Build.0 = Debug|x64
{D3F979CE-8FA7-48C9-A2B3-A33594B48536}.Release|Win32.ActiveCfg = Release|Win32
{D3F979CE-8FA7-48C9-A2B3-A33594B48536}.Release|Win32.Build.0 = Release|Win32
{D3F979CE-8FA7-48C9-A2B3-A33594B48536}.Release|x64.ActiveCfg = Release|x64
{D3F979CE-8FA7-48C9-A2B3-A33594B48536}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -68,9 +68,9 @@ typedef union
unsigned Reserved1 : 1;
unsigned Reserved2 : 1;
signed Y_AXIS : 8;
signed X_AXIS : 8;
signed Y_AXIS : 8;
};
} BUTTONS;
#pragma warning(pop)

View File

@ -149,7 +149,7 @@ void CControl_Plugin::UpdateKeys(void)
if (!m_AllocatedControllers) { return; }
for (int32_t cont = 0; cont < sizeof(m_Controllers) / sizeof(m_Controllers[0]); cont++)
{
if (!m_Controllers[cont]->m_Present) { continue; }
if (!m_Controllers[cont]->Present()) { continue; }
if (!m_Controllers[cont]->m_RawData)
{
GetKeys(cont, &m_Controllers[cont]->m_Buttons);

View File

@ -37,9 +37,9 @@ typedef union
unsigned Reserved1 : 1;
unsigned Reserved2 : 1;
signed Y_AXIS : 8;
signed X_AXIS : 8;
signed Y_AXIS : 8;
};
} BUTTONS;
#pragma warning(pop)
@ -76,7 +76,7 @@ class CCONTROL
{
public:
CCONTROL(int32_t &Present, int32_t &RawData, int32_t &PlugType);
inline bool Present(void) const { return m_Present != 0; }
inline bool Present(void) const { return m_Present != 0; }
inline uint32_t Buttons(void) const { return m_Buttons.Value; }
inline PluginType Plugin(void) const { return static_cast<PluginType>(m_PlugType); }
private:
@ -84,8 +84,8 @@ private:
int32_t & m_Present;
int32_t & m_RawData;
int32_t & m_PlugType;
BUTTONS m_Buttons;
int32_t & m_PlugType;
BUTTONS m_Buttons;
CCONTROL(void); // Disable default constructor
CCONTROL(const CCONTROL&); // Disable copy constructor

View File

@ -268,7 +268,7 @@ void CSettingTypeApplication::Save(uint32_t Index, const std::string & Value)
void CSettingTypeApplication::Save(uint32_t /*Index*/, const char * Value)
{
if (m_DefaultSetting != Default_None &&
if (m_DefaultSetting != Default_None && Value != NULL &&
((m_DefaultSetting == Default_Constant && strcmp(m_DefaultStr,Value) == 0) ||
(m_DefaultSetting != Default_Constant && strcmp(g_Settings->LoadStringVal(m_DefaultSetting).c_str(),Value) == 0)))
{

View File

@ -0,0 +1,30 @@
#pragma once
#include <Common\stdtypes.h>
#include <guiddef.h>
enum BtnType
{
BTNTYPE_UNASSIGNED = 0,
// Joystick
BTNTYPE_JOYBUTTON = 1,
BTNTYPE_JOYAXE = 2,
BTNTYPE_JOYPOV = 3,
BTNTYPE_JOYSLIDER = 4,
// Keyboard
BTNTYPE_KEYBUTTON = 5,
// Mouse
BTNTYPE_MOUSEBUTTON = 6,
BTNTYPE_MOUSEAXE = 7,
};
typedef struct _BUTTON
{
uint8_t Offset;
uint8_t AxisID;
BtnType BtnType;
GUID DeviceGuid;
void * Device;
} BUTTON;

View File

@ -0,0 +1,134 @@
#include "CProject64Input.h"
#include "InputSettings.h"
CProject64Input * g_InputPlugin = nullptr;
CProject64Input::CProject64Input(HINSTANCE hinst) :
m_hinst(hinst),
m_Scanning(false),
m_DisplayCtrlId(0),
m_iFirstController(-1)
{
memset(m_Controllers, 0, sizeof(m_Controllers));
}
CProject64Input::~CProject64Input()
{
}
void CProject64Input::DevicesChanged(void)
{
CGuard guard(m_CS);
if (m_DirectInput.get() != nullptr)
{
m_DirectInput->DevicesChanged();
}
}
void CProject64Input::InitiateControllers(CONTROL_INFO * ControlInfo)
{
CGuard guard(m_CS);
m_ControlInfo = *ControlInfo;
if (m_DirectInput.get() == NULL)
{
m_DirectInput.reset(new CDirectInput(m_hinst));
}
m_DirectInput->Initiate(ControlInfo);
m_iFirstController = -1;
for (size_t i = 0, n = sizeof(m_Controllers) / sizeof(m_Controllers[0]); i < n; i++)
{
g_Settings->LoadController(i, m_ControlInfo.Controls[i], m_Controllers[i]);
m_DirectInput->MapControllerDevice(m_Controllers[i]);
if (m_ControlInfo.Controls[i].Present != 0 && m_iFirstController < 0)
{
m_iFirstController = i;
}
}
}
void CProject64Input::GetKeys(int32_t Control, BUTTONS * Keys)
{
if (Control >= sizeof(m_Controllers) / sizeof(m_Controllers[0]))
{
return;
}
CGuard guard(m_CS);
if (Control == m_iFirstController)
{
m_DirectInput->UpdateDeviceData();
}
N64CONTROLLER & Controller = m_Controllers[Control];
Keys->R_DPAD = m_DirectInput->IsButtonPressed(Controller.R_DPAD);
Keys->L_DPAD = m_DirectInput->IsButtonPressed(Controller.L_DPAD);
Keys->D_DPAD = m_DirectInput->IsButtonPressed(Controller.D_DPAD);
Keys->U_DPAD = m_DirectInput->IsButtonPressed(Controller.U_DPAD);
Keys->START_BUTTON = m_DirectInput->IsButtonPressed(Controller.START_BUTTON);
Keys->Z_TRIG = m_DirectInput->IsButtonPressed(Controller.Z_TRIG);
Keys->B_BUTTON = m_DirectInput->IsButtonPressed(Controller.B_BUTTON);
Keys->A_BUTTON = m_DirectInput->IsButtonPressed(Controller.A_BUTTON);
Keys->R_CBUTTON = m_DirectInput->IsButtonPressed(Controller.R_CBUTTON);
Keys->L_CBUTTON = m_DirectInput->IsButtonPressed(Controller.L_CBUTTON);
Keys->D_CBUTTON = m_DirectInput->IsButtonPressed(Controller.D_CBUTTON);
Keys->U_CBUTTON = m_DirectInput->IsButtonPressed(Controller.U_CBUTTON);
Keys->R_TRIG = m_DirectInput->IsButtonPressed(Controller.R_TRIG);
Keys->L_TRIG = m_DirectInput->IsButtonPressed(Controller.L_TRIG);
m_DirectInput->GetAxis(Controller, Keys);
}
void CProject64Input::StartScanDevices(int32_t DisplayCtrlId)
{
m_Scanning = true;
m_DisplayCtrlId = DisplayCtrlId;
m_DirectInput->UpdateDeviceData();
}
void CProject64Input::EndScanDevices(void)
{
m_Scanning = false;
m_DisplayCtrlId = 0;
}
CDirectInput::ScanResult CProject64Input::ScanDevices(BUTTON & Button)
{
CDirectInput::ScanResult Result = CDirectInput::SCAN_FAILED;
if (m_DirectInput.get() != NULL)
{
Result = m_DirectInput->ScanDevices(Button);
}
return Result;
}
std::wstring CProject64Input::ButtonAssignment(BUTTON & Button)
{
if (m_DirectInput.get() != NULL)
{
return m_DirectInput->ButtonAssignment(Button);
}
return L"Unknown";
}
bool CProject64Input::SaveController(uint32_t ControlIndex)
{
CGuard guard(m_CS);
if (ControlIndex >= sizeof(m_Controllers) / sizeof(m_Controllers[0]))
{
return false;
}
g_Settings->SaveController(ControlIndex, m_ControlInfo.Controls[ControlIndex], m_Controllers[ControlIndex]);
m_DirectInput->MapControllerDevice(m_Controllers[ControlIndex]);
return true;
}
bool CProject64Input::ResetController(uint32_t ControlIndex)
{
CGuard guard(m_CS);
if (ControlIndex >= sizeof(m_Controllers) / sizeof(m_Controllers[0]))
{
return false;
}
g_Settings->ResetController(ControlIndex, m_ControlInfo.Controls[ControlIndex], m_Controllers[ControlIndex]);
m_DirectInput->MapControllerDevice(m_Controllers[ControlIndex]);
return true;
}

View File

@ -0,0 +1,45 @@
#pragma once
#include "ControllerSpec1.1.h"
#include "DirectInput.h"
#include "N64Controller.h"
#include <Common\CriticalSection.h>
#include <memory>
class CProject64Input
{
public:
CProject64Input(HINSTANCE hinst);
~CProject64Input();
void DevicesChanged(void);
void InitiateControllers(CONTROL_INFO * ControlInfo);
void GetKeys(int32_t Control, BUTTONS * Keys);
void StartScanDevices(int32_t DisplayCtrlId);
void EndScanDevices(void);
CDirectInput::ScanResult ScanDevices(BUTTON & Button);
std::wstring ButtonAssignment(BUTTON & Button);
bool SaveController(uint32_t ControlIndex);
bool ResetController(uint32_t ControlIndex);
inline HINSTANCE hInst(void) const { return m_hinst; }
inline bool IsScanning(void) const { return m_Scanning; }
inline int32_t DisplayCtrlId(void) const { return m_DisplayCtrlId; }
inline N64CONTROLLER & Controllers(int32_t Controller) { return m_Controllers[Controller]; }
inline CONTROL & ControlInfo(int32_t Controller) { return m_ControlInfo.Controls[Controller]; }
private:
CProject64Input();
CProject64Input(const CProject64Input&);
CProject64Input& operator=(const CProject64Input&);
CriticalSection m_CS;
CONTROL_INFO m_ControlInfo;
N64CONTROLLER m_Controllers[4];
std::unique_ptr<CDirectInput> m_DirectInput;
HINSTANCE m_hinst;
bool m_Scanning;
int32_t m_DisplayCtrlId;
int32_t m_iFirstController;
};
extern CProject64Input * g_InputPlugin;

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

View File

@ -0,0 +1,224 @@
/**********************************************************************************
Project64 Controller plugin spec, version #1.1
**********************************************************************************/
#pragma once
#include <Common/stdtypes.h>
enum { PLUGIN_TYPE_CONTROLLER = 4 };
#if defined(_WIN32)
#define EXPORT extern "C" __declspec(dllexport)
#define CALL __cdecl
#else
#define EXPORT extern "C" __attribute__((visibility("default")))
#define CALL
#endif
enum
{
CONTROLLER_SPECS_VERSION = 0x0102
};
enum
{
PLUGIN_NONE = 1,
PLUGIN_MEMPAK = 2,
PLUGIN_RUMBLE_PAK = 3,
PLUGIN_TRANSFER_PAK = 4,
PLUGIN_RAW = 5,
};
/***** Structures *****/
typedef struct
{
uint16_t Version; /* Should be set to 0x0101 */
uint16_t Type; /* Set to PLUGIN_TYPE_CONTROLLER */
char Name[100]; /* Name of the DLL */
int32_t NormalMemory;
int32_t MemoryBswaped;
} PLUGIN_INFO;
typedef struct
{
int32_t Present;
int32_t RawData;
int32_t Plugin;
} CONTROL;
#pragma warning(push)
#pragma warning(disable : 4201) // warning C4201: nonstandard extension used : nameless struct/union
typedef union
{
uint32_t Value;
struct
{
unsigned R_DPAD : 1;
unsigned L_DPAD : 1;
unsigned D_DPAD : 1;
unsigned U_DPAD : 1;
unsigned START_BUTTON : 1;
unsigned Z_TRIG : 1;
unsigned B_BUTTON : 1;
unsigned A_BUTTON : 1;
unsigned R_CBUTTON : 1;
unsigned L_CBUTTON : 1;
unsigned D_CBUTTON : 1;
unsigned U_CBUTTON : 1;
unsigned R_TRIG : 1;
unsigned L_TRIG : 1;
unsigned Reserved1 : 1;
unsigned Reserved2 : 1;
signed X_AXIS : 8;
signed Y_AXIS : 8;
};
} BUTTONS;
#pragma warning(pop)
typedef struct
{
void * hwnd;
void * hinst;
int32_t MemoryBswaped; // Set this to true
uint8_t * HEADER; // This is the rom header (first 40h bytes of the rom)
CONTROL * Controls; // A pointer to an array of 4 controllers .. eg:
} CONTROL_INFO;
/******************************************************************
Function: CloseDLL
Purpose: This function is called when the emulator is closing
down allowing the dll to de-initialise.
input: none
output: none
*******************************************************************/
EXPORT void CALL CloseDLL(void);
/******************************************************************
Function: ControllerCommand
Purpose: To process the raw data that has just been sent to a
specific controller.
input: - Controller Number (0 to 3) and -1 signalling end of
processing the pif ram.
- Pointer of data to be processed.
output: none
note: This function is only needed if the DLL is allowing raw
data, or the plugin is set to raw
the data that is being processed looks like this:
initilize controller: 01 03 00 FF FF FF
read controller: 01 04 01 FF FF FF FF
*******************************************************************/
EXPORT void CALL ControllerCommand(int32_t Control, uint8_t * Command);
/******************************************************************
Function: DllAbout
Purpose: This function is optional function that is provided
to give further information about the DLL.
input: a handle to the window that calls this function
output: none
*******************************************************************/
EXPORT void CALL DllAbout(void * hParent);
/******************************************************************
Function: DllConfig
Purpose: This function is optional function that is provided
to allow the user to configure the dll
input: a handle to the window that calls this function
output: none
*******************************************************************/
EXPORT void CALL DllConfig(void * hParent);
/******************************************************************
Function: DllTest
Purpose: This function is optional function that is provided
to allow the user to test the dll
input: a handle to the window that calls this function
output: none
*******************************************************************/
EXPORT void CALL DllTest(void * hParent);
/******************************************************************
Function: GetDllInfo
Purpose: This function allows the emulator to gather information
about the dll by filling in the PluginInfo structure.
input: a pointer to a PLUGIN_INFO stucture that needs to be
filled by the function. (see def above)
output: none
*******************************************************************/
EXPORT void CALL GetDllInfo(PLUGIN_INFO * PluginInfo);
/******************************************************************
Function: GetKeys
Purpose: To get the current state of the controllers buttons.
input: - Controller Number (0 to 3)
- A pointer to a BUTTONS structure to be filled with
the controller state.
output: none
*******************************************************************/
EXPORT void CALL GetKeys(int32_t Control, BUTTONS * Keys);
/******************************************************************
Function: InitiateControllers
Purpose: This function initialises how each of the controllers
should be handled.
input: - The handle to the main window.
- A controller structure that needs to be filled for
the emulator to know how to handle each controller.
output: none
*******************************************************************/
EXPORT void CALL InitiateControllers(CONTROL_INFO * ControlInfo);
/******************************************************************
Function: ReadController
Purpose: To process the raw data in the pif ram that is about to
be read.
input: - Controller Number (0 to 3) and -1 signalling end of
processing the pif ram.
- Pointer of data to be processed.
output: none
note: This function is only needed if the DLL is allowing raw
data.
*******************************************************************/
EXPORT void CALL ReadController(int Control, uint8_t * Command);
/******************************************************************
Function: RomClosed
Purpose: This function is called when a rom is closed.
input: none
output: none
*******************************************************************/
EXPORT void CALL RomClosed(void);
/******************************************************************
Function: RomOpen
Purpose: This function is called when a rom is open. (from the
emulation thread)
input: none
output: none
*******************************************************************/
EXPORT void CALL RomOpen(void);
/******************************************************************
Function: WM_KeyDown
Purpose: To pass the WM_KeyDown message from the emulator to the
plugin.
input: wParam and lParam of the WM_KEYDOWN message.
output: none
*******************************************************************/
EXPORT void CALL WM_KeyDown(uint32_t wParam, uint32_t lParam);
/******************************************************************
Function: WM_KeyUp
Purpose: To pass the WM_KEYUP message from the emulator to the
plugin.
input: wParam and lParam of the WM_KEYDOWN message.
output: none
*******************************************************************/
EXPORT void CALL WM_KeyUp(uint32_t wParam, uint32_t lParam);

View File

@ -0,0 +1,34 @@
#include "DeviceNotification.h"
#include "CProject64Input.h"
#include <dbt.h>
DeviceNotification::DeviceNotification()
{
Create(NULL);
}
DeviceNotification::~DeviceNotification()
{
DestroyWindow();
}
int DeviceNotification::OnCreate(LPCREATESTRUCT /*lpCreateStruct*/)
{
DEV_BROADCAST_DEVICEINTERFACE notificationFilter = { 0 };
notificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
notificationFilter.dbcc_size = sizeof(notificationFilter);
HDEVNOTIFY hDevNotify;
hDevNotify = RegisterDeviceNotification(m_hWnd, &notificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
return TRUE;
}
BOOL DeviceNotification::OnDeviceChange(UINT nEventType, DWORD /*dwData*/)
{
if (g_InputPlugin != nullptr && (nEventType == DBT_DEVICEARRIVAL || nEventType == DBT_DEVICEREMOVECOMPLETE))
{
g_InputPlugin->DevicesChanged();
}
return TRUE;
}

View File

@ -0,0 +1,23 @@
#pragma once
#include "wtl.h"
typedef CWinTraits<WS_OVERLAPPED, WS_EX_APPWINDOW> DeviceNotificationTraits;
class DeviceNotification :
public CWindowImpl<DeviceNotification, CWindow, DeviceNotificationTraits>
{
public:
DECLARE_WND_CLASS(_T("My Window Class"))
BEGIN_MSG_MAP(DeviceNotification)
MSG_WM_CREATE(OnCreate)
MSG_WM_DEVICECHANGE(OnDeviceChange)
END_MSG_MAP()
DeviceNotification();
~DeviceNotification();
private:
int OnCreate(LPCREATESTRUCT lpCreateStruct);
BOOL OnDeviceChange(UINT nEventType, DWORD dwData);
};

View File

@ -0,0 +1,634 @@
#include "DirectInput.h"
#include <Common\StdString.h>
#include <Common\SyncEvent.h>
CDirectInput::CDirectInput(HINSTANCE hinst) :
m_hDirectInputDLL(nullptr),
m_pDIHandle(nullptr),
m_hinst(hinst),
m_hWnd(nullptr)
{
if (m_hDirectInputDLL == nullptr)
{
m_hDirectInputDLL = LoadLibrary(L"dinput8.dll");
}
if (m_hDirectInputDLL != nullptr)
{
typedef HRESULT(WINAPI *tylpGetDIHandle)(HINSTANCE, DWORD, REFIID, LPVOID*, LPUNKNOWN);
tylpGetDIHandle lpGetDIHandle = (tylpGetDIHandle)GetProcAddress(m_hDirectInputDLL, "DirectInput8Create");
if (lpGetDIHandle != NULL)
{
HRESULT hr = lpGetDIHandle(m_hinst, DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID*)&m_pDIHandle, NULL);
if (FAILED(hr))
{
return;
}
}
RefreshDeviceList();
}
}
CDirectInput::~CDirectInput()
{
for (DEVICE_MAP::iterator itr = m_Devices.begin(); itr != m_Devices.end(); itr++)
{
if (itr->second.didHandle != nullptr)
{
itr->second.didHandle->Release();
itr->second.didHandle = NULL;
}
}
}
void CDirectInput::Initiate(CONTROL_INFO * ControlInfo)
{
m_hWnd = (HWND)ControlInfo->hwnd;
}
void CDirectInput::MapControllerDevice(N64CONTROLLER & Controller)
{
BUTTON * Buttons[] =
{
&Controller.U_DPAD,
&Controller.D_DPAD,
&Controller.L_DPAD,
&Controller.R_DPAD,
&Controller.A_BUTTON,
&Controller.B_BUTTON,
&Controller.U_CBUTTON,
&Controller.D_CBUTTON,
&Controller.L_CBUTTON,
&Controller.R_CBUTTON,
&Controller.START_BUTTON,
&Controller.Z_TRIG,
&Controller.R_TRIG,
&Controller.L_TRIG,
&Controller.U_ANALOG,
&Controller.D_ANALOG,
&Controller.L_ANALOG,
&Controller.R_ANALOG,
};
for (size_t i = 0, n = sizeof(Buttons) / sizeof(Buttons[0]); i < n; i++)
{
DEVICE_MAP::iterator itr = m_Devices.find(Buttons[i]->DeviceGuid);
if (itr != m_Devices.end())
{
Buttons[i]->Device = &itr->second;
}
else
{
Buttons[i]->Device = nullptr;
}
}
}
BOOL CDirectInput::stEnumMakeDeviceList(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)
{
return ((CDirectInput *)pvRef)->EnumMakeDeviceList(lpddi);
}
BOOL CDirectInput::EnumMakeDeviceList(LPCDIDEVICEINSTANCE lpddi)
{
uint32_t DeviceType = GET_DIDEVICE_TYPE(lpddi->dwDevType);
if (DeviceType == DI8DEVTYPE_DEVICE)
{
// ignore generic devices
return DIENUM_CONTINUE;
}
DEVICE_MAP::iterator itr = m_Devices.find(lpddi->guidInstance);
if (itr != m_Devices.end())
{
return DIENUM_CONTINUE;
}
DEVICE Device = { 0 };
Device.didHandle = nullptr;
Device.dwDevType = lpddi->dwDevType;
Device.ProductName = stdstr().FromUTF16(lpddi->tszProductName);
Device.InstanceName = stdstr().FromUTF16(lpddi->tszInstanceName);
HRESULT hResult = m_pDIHandle->CreateDevice(lpddi->guidInstance, &Device.didHandle, NULL);
if (!SUCCEEDED(hResult))
{
return DIENUM_CONTINUE;
}
LPCDIDATAFORMAT ppDiDataFormat = NULL;
if (DeviceType == DI8DEVTYPE_KEYBOARD)
{
ppDiDataFormat = &c_dfDIKeyboard;
}
else if (DeviceType == DI8DEVTYPE_MOUSE)
{
ppDiDataFormat = &c_dfDIMouse2;
}
else
{
ppDiDataFormat = &c_dfDIJoystick;
}
hResult = Device.didHandle->SetDataFormat(ppDiDataFormat);
if (!SUCCEEDED(hResult))
{
Device.didHandle->Release();
return DIENUM_CONTINUE;
}
hResult = Device.didHandle->SetCooperativeLevel(m_hWnd, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);
if (!SUCCEEDED(hResult))
{
Device.didHandle->Release();
return DIENUM_CONTINUE;
}
std::pair<DEVICE_MAP::iterator, bool> res = m_Devices.insert(DEVICE_MAP::value_type(lpddi->guidInstance, Device));
if (!res.second)
{
Device.didHandle->Release();
}
return DIENUM_CONTINUE;
}
CDirectInput::ScanResult CDirectInput::ScanDevices(BUTTON & Button)
{
ScanResult Result = SCAN_FAILED;
for (DEVICE_MAP::iterator itr = m_Devices.begin(); itr != m_Devices.end(); itr++)
{
DEVICE &device = itr->second;
if (device.didHandle == nullptr)
{
continue;
}
if (FAILED(device.didHandle->Poll()))
{
device.didHandle->Acquire();
}
}
for (DEVICE_MAP::iterator itr = m_Devices.begin(); itr != m_Devices.end(); itr++)
{
DEVICE &device = itr->second;
if (device.didHandle == nullptr)
{
continue;
}
uint8_t DeviceType = LOBYTE(device.dwDevType);
if (DeviceType == DI8DEVTYPE_KEYBOARD)
{
Result = ScanKeyboard(itr->first, device.didHandle, device.State.Keyboard, Button);
}
else if (DeviceType != DI8DEVTYPE_MOUSE)
{
Result = ScanGamePad(itr->first, device.didHandle, device.State.Joy, Button);
}
if (Result != SCAN_FAILED)
{
return Result;
}
}
return Result;
}
std::wstring CDirectInput::ButtonAssignment(BUTTON & Button)
{
static const char * iGamepad[] =
{
"X-axis",
"Y-axis",
"Z-axis",
"X-rotation",
"Y-rotation",
"Z-rotation",
"Slider",
"Slider",
"PoV",
"PoV",
"PoV",
"PoV",
"Button"
};
static const char * AxeID[] =
{
" +",
" -",
" /\\",
" >",
" \\/",
" <"
};
if (Button.BtnType == BTNTYPE_JOYBUTTON)
{
return stdstr_f("Button %u", Button.Offset).ToUTF16();
}
if (Button.BtnType == BTNTYPE_JOYAXE)
{
stdstr_f Offset("%u", Button.Offset);
if (Button.Offset < (sizeof(iGamepad) / sizeof(iGamepad[0])))
{
Offset = iGamepad[Button.Offset];
}
stdstr_f AxisId(" %u", Button.AxisID);
if (Button.AxisID < (sizeof(AxeID) / sizeof(AxeID[0])))
{
AxisId = AxeID[Button.AxisID];
}
return stdstr_f("%s%s", Offset.c_str(), AxisId.c_str()).ToUTF16();
}
if (Button.BtnType == BTNTYPE_JOYPOV)
{
stdstr_f Offset("%u", Button.Offset);
if (Button.Offset < (sizeof(iGamepad) / sizeof(iGamepad[0])))
{
Offset = iGamepad[Button.Offset];
}
stdstr_f AxisId(" %u", Button.AxisID);
if ((Button.AxisID + 2) < (sizeof(AxeID) / sizeof(AxeID[0])))
{
AxisId = AxeID[Button.AxisID + 2];
}
return stdstr_f("%s%s", Offset.c_str(), AxisId.c_str()).ToUTF16();
}
if (Button.BtnType == BTNTYPE_KEYBUTTON)
{
DEVICE_MAP::iterator itr = m_Devices.find(GUID_SysKeyboard);
if (itr != m_Devices.end())
{
DIDEVICEOBJECTINSTANCE didoi;
didoi.dwSize = sizeof(DIDEVICEOBJECTINSTANCE);
if (itr->second.didHandle->GetObjectInfo(&didoi, Button.Offset, DIPH_BYOFFSET) == DI_OK)
{
return didoi.tszName;
}
return L"Keyboard: ???";
}
}
if (Button.BtnType == BTNTYPE_UNASSIGNED)
{
return L"";
}
return L"Unknown";
}
bool CDirectInput::IsButtonPressed(BUTTON & Button)
{
if (Button.Device == nullptr)
{
return false;
}
DEVICE & Device = *(DEVICE *)Button.Device;
switch (Button.BtnType)
{
case BTNTYPE_KEYBUTTON:
return (Device.State.Keyboard[Button.Offset] & 0x80) != 0;
case BTNTYPE_JOYBUTTON:
return (Device.State.Joy.rgbButtons[Button.Offset] & 0x80) != 0;
case BTNTYPE_JOYPOV:
return JoyPadPovPressed((AI_POV)Button.AxisID, ((uint32_t *)&Device.State.Joy)[Button.Offset]);
}
return false;
}
void CDirectInput::GetAxis(N64CONTROLLER & Controller, BUTTONS * Keys)
{
enum
{
N64DIVIDER = 258,
};
Keys->X_AXIS = 0;
Keys->Y_AXIS = 0;
bool b_Value;
long l_Value = 0;
long lAxisValueX = 0;
long lAxisValueY = 0;
int bPadDeadZone = 5;
long lDeadZoneValue = bPadDeadZone * RANGE_RELATIVE / 100;
float fDeadZoneRelation = (float)RANGE_RELATIVE / (float)(RANGE_RELATIVE - lDeadZoneValue);
struct
{
BUTTON & Button;
bool Negative;
}
Buttons[] =
{
{ Controller.R_ANALOG, false },
{ Controller.L_ANALOG, true },
{ Controller.D_ANALOG, true },
{ Controller.U_ANALOG, false },
};
for (size_t i = 0, n = sizeof(Buttons) / sizeof(Buttons[0]); i < n; i++)
{
bool fNegInput = Buttons[i].Negative;
BUTTON & btnButton = Buttons[i].Button;
if (btnButton.Device == nullptr)
{
continue;
}
DEVICE & Device = *(DEVICE *)btnButton.Device;
LPLONG plRawState = (LPLONG)&Device.State.Joy;
switch (btnButton.BtnType)
{
case BTNTYPE_JOYSLIDER:
case BTNTYPE_JOYAXE:
l_Value = (plRawState[btnButton.Offset] - MAX_AXIS_VALUE) * -1;
if (btnButton.AxisID == AI_AXE_NEGATIVE)
{
fNegInput = !fNegInput;
b_Value = (l_Value <= -lDeadZoneValue);
if (b_Value)
l_Value = (long)((float)(l_Value + lDeadZoneValue) * fDeadZoneRelation);
}
else
{
b_Value = (l_Value >= lDeadZoneValue);
if (b_Value)
l_Value = (long)((float)(l_Value - lDeadZoneValue) * fDeadZoneRelation);
}
break;
case BTNTYPE_KEYBUTTON:
if ((Device.State.Keyboard[btnButton.Offset] & 0x80) != 0)
{
b_Value = true;
l_Value = MAX_AXIS_VALUE;
}
else
{
b_Value = false;
}
break;
default:
b_Value = false;
}
if (b_Value)
{
if (fNegInput)
l_Value = -l_Value;
if (i < 2)
lAxisValueX += l_Value;
else
lAxisValueY += l_Value;
}
}
if (lAxisValueX > MAX_AXIS_VALUE) { lAxisValueX = MAX_AXIS_VALUE; }
if (lAxisValueY > MAX_AXIS_VALUE) { lAxisValueY = MAX_AXIS_VALUE; }
Keys->X_AXIS = lAxisValueX / N64DIVIDER;
Keys->Y_AXIS = lAxisValueY / N64DIVIDER;
}
void CDirectInput::UpdateDeviceData(void)
{
for (DEVICE_MAP::iterator itr = m_Devices.begin(); itr != m_Devices.end(); itr++)
{
DEVICE & device = itr->second;
LPDIRECTINPUTDEVICE8 & didHandle = device.didHandle;
if (didHandle == nullptr)
{
continue;
}
if (FAILED(didHandle->Poll()) && !AcquireDevice(didHandle))
{
continue;
}
switch (LOBYTE(device.dwDevType))
{
case DI8DEVTYPE_KEYBOARD:
didHandle->GetDeviceState(sizeof(device.State.Keyboard), &device.State.Keyboard);
break;
case DI8DEVTYPE_MOUSE:
didHandle->GetDeviceState(sizeof(device.State.Mouse), &device.State.Mouse);
break;
default:
didHandle->GetDeviceState(sizeof(device.State.Joy), &device.State.Joy);
}
}
}
void CDirectInput::DevicesChanged(void)
{
RefreshDeviceList();
}
void CDirectInput::RefreshDeviceList(void)
{
if (m_pDIHandle != nullptr)
{
m_pDIHandle->EnumDevices(DI8DEVCLASS_ALL, stEnumMakeDeviceList, this, DIEDFL_ATTACHEDONLY);
}
}
CDirectInput::ScanResult CDirectInput::ScanKeyboard(const GUID & DeviceGuid, LPDIRECTINPUTDEVICE8 didHandle, uint8_t * KeyboardState, BUTTON & pButton)
{
if (didHandle == nullptr)
{
return SCAN_FAILED;
}
uint8_t cKeys[256];
HRESULT hr = didHandle->GetDeviceState(sizeof(cKeys), cKeys);
if (FAILED(hr))
{
didHandle->Acquire();
return SCAN_FAILED;
}
for (size_t i = 0, n = sizeof(cKeys) / sizeof(cKeys[0]); i < n; i++)
{
if (KeyboardState[i] == cKeys[i])
{
continue;
}
KeyboardState[i] = cKeys[i];
if ((cKeys[i] & 0x80) == 0)
{
continue;
}
if (i == DIK_ESCAPE)
{
return SCAN_ESCAPE;
}
pButton.Offset = (uint8_t)i;
pButton.AxisID = 0;
pButton.BtnType = BTNTYPE_KEYBUTTON;
pButton.DeviceGuid = DeviceGuid;
pButton.Device = nullptr;
return SCAN_SUCCEED;
}
return SCAN_FAILED;
}
CDirectInput::ScanResult CDirectInput::ScanGamePad(const GUID & DeviceGuid, LPDIRECTINPUTDEVICE8 didHandle, DIJOYSTATE & BaseState, BUTTON & pButton)
{
DIJOYSTATE JoyState = { 0 };
HRESULT hr = didHandle->GetDeviceState(sizeof(DIJOYSTATE), &JoyState);
if (FAILED(hr))
{
didHandle->Acquire();
return SCAN_FAILED;
}
uint32_t JoyPad[][2] =
{
{ FIELD_OFFSET(DIJOYSTATE, lX) / sizeof(uint32_t), BTNTYPE_JOYAXE },
{ FIELD_OFFSET(DIJOYSTATE, lY) / sizeof(uint32_t), BTNTYPE_JOYAXE },
{ FIELD_OFFSET(DIJOYSTATE, lZ) / sizeof(uint32_t), BTNTYPE_JOYAXE },
{ FIELD_OFFSET(DIJOYSTATE, lRx) / sizeof(uint32_t), BTNTYPE_JOYAXE },
{ FIELD_OFFSET(DIJOYSTATE, lRy) / sizeof(uint32_t), BTNTYPE_JOYAXE },
{ FIELD_OFFSET(DIJOYSTATE, lRz) / sizeof(uint32_t), BTNTYPE_JOYAXE },
{ FIELD_OFFSET(DIJOYSTATE, rglSlider[0]) / sizeof(uint32_t), BTNTYPE_JOYSLIDER },
{ FIELD_OFFSET(DIJOYSTATE, rglSlider[1]) / sizeof(uint32_t), BTNTYPE_JOYSLIDER },
{ FIELD_OFFSET(DIJOYSTATE, rgdwPOV[0]) / sizeof(uint32_t), BTNTYPE_JOYPOV },
{ FIELD_OFFSET(DIJOYSTATE, rgdwPOV[1]) / sizeof(uint32_t), BTNTYPE_JOYPOV },
{ FIELD_OFFSET(DIJOYSTATE, rgdwPOV[2]) / sizeof(uint32_t), BTNTYPE_JOYPOV },
{ FIELD_OFFSET(DIJOYSTATE, rgdwPOV[3]) / sizeof(uint32_t), BTNTYPE_JOYPOV }
};
uint8_t bAxeDirection = 0;
int32_t foundJoyPad = -1;
for (int32_t i = 0, n = sizeof(JoyPad) / sizeof(JoyPad[0]); i < n; i++)
{
uint32_t lValue = ((int32_t*)&JoyState)[JoyPad[i][0]];
uint32_t BaseValue = ((int32_t*)&BaseState)[JoyPad[i][0]];
if (lValue == BaseValue)
{
continue;
}
((int32_t*)&(BaseState))[JoyPad[i][0]] = lValue;
if ((JoyPad[i][1] == BTNTYPE_JOYAXE) || (JoyPad[i][1] == BTNTYPE_JOYSLIDER))
{
enum
{
AXIS_TOP_VALUE = MAX_AXIS_VALUE / 2,
AXIS_BOTTOM_VALUE = MAX_AXIS_VALUE + AXIS_TOP_VALUE,
};
if (lValue < AXIS_TOP_VALUE && BaseValue >= AXIS_TOP_VALUE)
{
bAxeDirection = AI_AXE_POSITIVE;
foundJoyPad = i;
break;
}
else if (lValue > AXIS_BOTTOM_VALUE && BaseValue <= AXIS_BOTTOM_VALUE)
{
bAxeDirection = AI_AXE_NEGATIVE;
foundJoyPad = i;
break;
}
}
if (JoyPad[i][1] == BTNTYPE_JOYPOV)
{
AI_POV pov[] =
{
AI_POV_UP,
AI_POV_DOWN,
AI_POV_LEFT,
AI_POV_RIGHT,
};
for (size_t p = 0; p < (sizeof(pov) / sizeof(pov[0])); p++)
{
if (JoyPadPovPressed(pov[p], lValue) && !JoyPadPovPressed(pov[p], BaseValue))
{
bAxeDirection = (uint8_t)pov[p];
foundJoyPad = i;
break;
}
}
if (foundJoyPad >= 0)
{
break;
}
}
}
if (foundJoyPad >= 0)
{
pButton.Offset = (uint8_t)JoyPad[foundJoyPad][0];
pButton.AxisID = (uint8_t)bAxeDirection;
pButton.BtnType = (BtnType)JoyPad[foundJoyPad][1];
pButton.DeviceGuid = DeviceGuid;
pButton.Device = nullptr;
return SCAN_SUCCEED;
}
for (uint8_t i = 0, n = sizeof(JoyState.rgbButtons) / sizeof(JoyState.rgbButtons[0]); i < n; i++)
{
if (BaseState.rgbButtons[i] == JoyState.rgbButtons[i])
{
continue;
}
BaseState.rgbButtons[i] = JoyState.rgbButtons[i];
if ((JoyState.rgbButtons[i] & 0x80) == 0)
{
continue;
}
pButton.Offset = i;
pButton.AxisID = 0;
pButton.BtnType = BTNTYPE_JOYBUTTON;
pButton.DeviceGuid = DeviceGuid;
pButton.Device = nullptr;
return SCAN_SUCCEED;
}
return SCAN_FAILED;
}
bool CDirectInput::AcquireDevice(LPDIRECTINPUTDEVICE8 lpDirectInputDevice)
{
HRESULT hResult = lpDirectInputDevice->Acquire();
if (hResult == DIERR_INPUTLOST)
{
for (uint32_t i = 0; i < 10; i++)
{
hResult = lpDirectInputDevice->Acquire();
if (hResult != DIERR_INPUTLOST)
{
break;
}
}
}
if (SUCCEEDED(hResult))
{
lpDirectInputDevice->Poll();
return true;
}
return false;
}
bool CDirectInput::JoyPadPovPressed(AI_POV Pov, int32_t Angle)
{
enum
{
POV_ANGLE_THRESH = 5675
};
if (LOWORD(Angle) == 0xFFFF)
{
return false;
}
switch (Pov)
{
case AI_POV_UP:
return ((Angle >= 36000 - POV_ANGLE_THRESH) || (Angle <= 0 + POV_ANGLE_THRESH));
case AI_POV_RIGHT:
return ((Angle >= 9000 - POV_ANGLE_THRESH) && (Angle <= 9000 + POV_ANGLE_THRESH));
case AI_POV_DOWN:
return ((Angle >= 18000 - POV_ANGLE_THRESH) && (Angle <= 18000 + POV_ANGLE_THRESH));
case AI_POV_LEFT:
return ((Angle >= 27000 - POV_ANGLE_THRESH) && (Angle <= 27000 + POV_ANGLE_THRESH));
}
return false;
}

View File

@ -0,0 +1,95 @@
#pragma once
#include "ControllerSpec1.1.h"
#include "Button.h"
#include "DeviceNotification.h"
#include "N64Controller.h"
#define DIRECTINPUT_VERSION 0x0800
#include <Windows.h>
#include <dinput.h>
#include <string>
#include <map>
class CDirectInput
{
enum
{
CONFIG_THRESHOLD = 50,
MAX_AXIS_VALUE = 0x7FFF,
RANGE_RELATIVE = 0x8000,
AI_AXE_POSITIVE = 0,
AI_AXE_NEGATIVE = 1,
THRESHOLD = 50,
ABS_THRESHOLD = (RANGE_RELATIVE * THRESHOLD / 100)
};
enum AI_POV
{
AI_POV_UP = 0,
AI_POV_RIGHT = 1,
AI_POV_DOWN = 2,
AI_POV_LEFT = 3,
};
public:
enum ScanResult
{
SCAN_FAILED = 0x00,
SCAN_SUCCEED = 0x01,
SCAN_ESCAPE = 0x10,
};
CDirectInput(HINSTANCE hinst);
~CDirectInput();
void Initiate(CONTROL_INFO * ControlInfo);
void MapControllerDevice(N64CONTROLLER & Controller);
ScanResult ScanDevices(BUTTON & Button);
std::wstring ButtonAssignment(BUTTON & Button);
bool IsButtonPressed(BUTTON & Button);
void GetAxis(N64CONTROLLER & Controller, BUTTONS * Keys);
void UpdateDeviceData(void);
void DevicesChanged(void);
private:
CDirectInput();
CDirectInput(const CDirectInput&);
CDirectInput& operator=(const CDirectInput&);
static BOOL CALLBACK stEnumMakeDeviceList(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef);
BOOL EnumMakeDeviceList(LPCDIDEVICEINSTANCE lpddi);
ScanResult ScanKeyboard(const GUID & DeviceGuid, LPDIRECTINPUTDEVICE8 didHandle, uint8_t * KeyboardState, BUTTON & pButton);
ScanResult ScanGamePad(const GUID & DeviceGuid, LPDIRECTINPUTDEVICE8 didHandle, DIJOYSTATE & BaseState, BUTTON & pButton);
bool AcquireDevice(LPDIRECTINPUTDEVICE8 lpDirectInputDevice);
void RefreshDeviceList(void);
bool JoyPadPovPressed(AI_POV Pov, int32_t Angle);
typedef struct
{
LPDIRECTINPUTDEVICE8 didHandle;
uint32_t dwDevType;
std::string InstanceName;
std::string ProductName;
union INPUTSTATE
{
DIJOYSTATE Joy;
DIMOUSESTATE2 Mouse;
uint8_t Keyboard[256];
} State;
} DEVICE;
struct GUIDComparer
{
bool operator()(const GUID & Left, const GUID & Right) const
{
return memcmp(&Left, &Right, sizeof(Right)) < 0;
}
};
typedef std::map<GUID, DEVICE, GUIDComparer> DEVICE_MAP;
DeviceNotification m_DeviceNotification;
DEVICE_MAP m_Devices;
HMODULE m_hDirectInputDLL;
LPDIRECTINPUT8 m_pDIHandle;
HINSTANCE m_hinst;
HWND m_hWnd;
};

View File

@ -0,0 +1,284 @@
#include "InputConfigUI.h"
#include "CProject64Input.h"
#include "wtl.h"
#include "wtl-BitmapPicture.h"
#include "wtl-ScanButton.h"
#include <Common\stdtypes.h>
#include <Common\StdString.h>
#include "resource.h"
class CControllerSettings :
public CPropertyPageImpl<CControllerSettings>
{
enum
{
DETECT_KEY_TIMER = 1
};
public:
enum { IDD = IDD_Controller };
BEGIN_MSG_MAP(CControllerSettings)
MSG_WM_INITDIALOG(OnInitDialog)
MSG_WM_CTLCOLORSTATIC(OnCtlColorStatic)
COMMAND_HANDLER_EX(IDC_BTN_DEFAULTS, BN_CLICKED, DefaultBtnClicked)
COMMAND_HANDLER_EX(IDC_BTN_SETUP, BN_CLICKED, SetupBtnClicked)
COMMAND_HANDLER_EX(IDC_CHK_PLUGGED_IN, BN_CLICKED, ItemChanged)
COMMAND_HANDLER_EX(IDC_CMB_DEVICE, CBN_SELCHANGE, ItemChanged)
NOTIFY_HANDLER_EX(IDC_TACK_RANGE, NM_RELEASEDCAPTURE, ItemChangedNotify);
MESSAGE_HANDLER(WM_HSCROLL, OnScroll)
MESSAGE_HANDLER(CScanButton::WM_SCAN_SUCCESS, OnScanSuccess)
MESSAGE_HANDLER(CScanButton::WM_SCAN_CANCELED, OnScanCanceled)
CHAIN_MSG_MAP(CPropertyPageImpl<CControllerSettings>)
END_MSG_MAP()
CControllerSettings(uint32_t ControllerNumber);
BOOL OnInitDialog(CWindow /*wndFocus*/, LPARAM /*lInitParam*/);
HBRUSH OnCtlColorStatic(CDCHandle dc, CWindow wndStatic);
bool OnApply();
private:
LRESULT OnScroll(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnScanSuccess(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnScanCanceled(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
void DefaultBtnClicked(UINT Code, int id, HWND ctl);
void SetupBtnClicked(UINT Code, int id, HWND ctl);
void ItemChanged(UINT Code, int id, HWND ctl);
LRESULT ItemChangedNotify(NMHDR* /*pNMHDR*/);
void DisplayController(void);
void ButtonChannged(void);
static void stButtonChanged(size_t data) { ((CControllerSettings *)data)->ButtonChannged(); }
std::wstring m_Title;
uint32_t m_ControllerNumber;
uint32_t m_ScanCount;
int32_t m_SetupIndex;
CBitmapPicture m_ControllerImg;
CButton m_PluggedIn;
CComboBox m_cmbDevice;
CTrackBarCtrl m_Range;
CScanButton m_ButtonUDPad, m_ButtonDDPad, m_ButtonLDPad, m_ButtonRDPad;
CScanButton m_ButtonCUp, m_ButtonCDown, m_ButtonCLeft, m_ButtonCRight;
CScanButton m_ButtonA, m_ButtonB, m_ButtonStart;
CScanButton m_ButtonZtrigger, m_ButtonRTrigger, m_ButtonLTrigger;
CScanButton m_ButtonAnalogU, m_ButtonAnalogD, m_ButtonAnalogL, m_ButtonAnalogR;
};
CControllerSettings::CControllerSettings(uint32_t ControllerNumber) :
m_ControllerNumber(ControllerNumber),
m_ScanCount(0),
m_SetupIndex(-1),
m_ButtonUDPad(g_InputPlugin->Controllers(ControllerNumber).U_DPAD, IDC_EDIT_DIGITIAL_UP, IDC_BTN_DIGITIAL_UP),
m_ButtonDDPad(g_InputPlugin->Controllers(ControllerNumber).D_DPAD, IDC_EDIT_DIGITIAL_DOWN, IDC_BTN_DIGITIAL_DOWN),
m_ButtonLDPad(g_InputPlugin->Controllers(ControllerNumber).L_DPAD, IDC_EDIT_DIGITIAL_LEFT, IDC_BTN_DIGITIAL_LEFT),
m_ButtonRDPad(g_InputPlugin->Controllers(ControllerNumber).R_DPAD, IDC_EDIT_DIGITIAL_RIGHT, IDC_BTN_DIGITIAL_RIGHT),
m_ButtonA(g_InputPlugin->Controllers(ControllerNumber).A_BUTTON, IDC_EDIT_BUTTON_A, IDC_BTN_BUTTON_A),
m_ButtonB(g_InputPlugin->Controllers(ControllerNumber).B_BUTTON, IDC_EDIT_BUTTON_B, IDC_BTN_BUTTON_B),
m_ButtonCUp(g_InputPlugin->Controllers(ControllerNumber).U_CBUTTON, IDC_EDIT_CBUTTON_UP, IDC_BTN_CBUTTON_UP),
m_ButtonCDown(g_InputPlugin->Controllers(ControllerNumber).D_CBUTTON, IDC_EDIT_CBUTTON_DOWN, IDC_BTN_CBUTTON_DOWN),
m_ButtonCLeft(g_InputPlugin->Controllers(ControllerNumber).L_CBUTTON, IDC_EDIT_CBUTTON_LEFT, IDC_BTN_CBUTTON_LEFT),
m_ButtonCRight(g_InputPlugin->Controllers(ControllerNumber).R_CBUTTON, IDC_EDIT_CBUTTON_RIGHT, IDC_BTN_CBUTTON_RIGHT),
m_ButtonStart(g_InputPlugin->Controllers(ControllerNumber).START_BUTTON, IDC_EDIT_BUTTON_START, IDC_BTN_BUTTON_START),
m_ButtonZtrigger(g_InputPlugin->Controllers(ControllerNumber).Z_TRIG, IDC_EDIT_BUTTON_Z, IDC_BTN_BUTTON_Z),
m_ButtonRTrigger(g_InputPlugin->Controllers(ControllerNumber).R_TRIG, IDC_EDIT_RTRIGGER, IDC_BTN_RTRIGGER),
m_ButtonLTrigger(g_InputPlugin->Controllers(ControllerNumber).L_TRIG, IDC_EDIT_LTRIGGER, IDC_BTN_LTRIGGER),
m_ButtonAnalogU(g_InputPlugin->Controllers(ControllerNumber).U_ANALOG, IDC_EDIT_ANALOG_UP, IDC_BTN_ANALOG_UP),
m_ButtonAnalogD(g_InputPlugin->Controllers(ControllerNumber).D_ANALOG, IDC_EDIT_ANALOG_DOWN, IDC_BTN_ANALOG_DOWN),
m_ButtonAnalogL(g_InputPlugin->Controllers(ControllerNumber).L_ANALOG, IDC_EDIT_ANALOG_LEFT, IDC_BTN_ANALOG_LEFT),
m_ButtonAnalogR(g_InputPlugin->Controllers(ControllerNumber).R_ANALOG, IDC_EDIT_ANALOG_RIGHT, IDC_BTN_ANALOG_RIGHT)
{
m_Title = stdstr_f("Player %d", ControllerNumber + 1).ToUTF16();
SetTitle(m_Title.c_str());
}
BOOL CControllerSettings::OnInitDialog(CWindow /*wndFocus*/, LPARAM /*lInitParam*/)
{
GetDlgItem(IDC_BTN_LOAD).EnableWindow(false);
GetDlgItem(IDC_BTN_SAVE).EnableWindow(false);
m_Range.Attach(GetDlgItem(IDC_SLIDER_RANGE));
m_Range.SetTicFreq(1);
m_Range.SetRangeMin(1);
m_Range.SetRangeMax(100);
m_PluggedIn.Attach(GetDlgItem(IDC_CHK_PLUGGED_IN));
m_cmbDevice.Attach(GetDlgItem(IDC_CMB_DEVICE));
m_cmbDevice.SetItemData(m_cmbDevice.AddString(L"None"), PLUGIN_NONE);
m_cmbDevice.SetItemData(m_cmbDevice.AddString(L"Mem Pak"), PLUGIN_MEMPAK);
m_cmbDevice.SetItemData(m_cmbDevice.AddString(L"Rumble Pak"), PLUGIN_RUMBLE_PAK);
m_ControllerImg.SubclassWindow(GetDlgItem(IDC_BMP_CONTROLLER));
m_ControllerImg.SetBitmap(MAKEINTRESOURCE(IDB_CONTROLLER));
CScanButton * Buttons[] = {
&m_ButtonUDPad, &m_ButtonDDPad, &m_ButtonLDPad, &m_ButtonRDPad, &m_ButtonA, &m_ButtonB,
&m_ButtonCUp, &m_ButtonCDown, &m_ButtonCLeft, &m_ButtonCRight, &m_ButtonStart,
&m_ButtonZtrigger, &m_ButtonRTrigger, &m_ButtonLTrigger,
&m_ButtonAnalogU, &m_ButtonAnalogD, &m_ButtonAnalogL, &m_ButtonAnalogR
};
for (size_t i = 0, n = sizeof(Buttons) / sizeof(Buttons[0]); i < n; i++)
{
Buttons[i]->SubclassWindow(m_hWnd);
Buttons[i]->SetChangeCallback(stButtonChanged, (size_t)this);
}
DisplayController();
return TRUE;
}
HBRUSH CControllerSettings::OnCtlColorStatic(CDCHandle dc, CWindow wndStatic)
{
if (g_InputPlugin->IsScanning() && wndStatic.GetDlgCtrlID() == g_InputPlugin->DisplayCtrlId())
{
dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
dc.SetBkColor(GetSysColor(COLOR_HIGHLIGHT));
return ::GetSysColorBrush(COLOR_HIGHLIGHT);
}
dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
dc.SetBkColor(GetSysColor(COLOR_WINDOW));
return ::GetSysColorBrush(COLOR_WINDOW);
}
bool CControllerSettings::OnApply()
{
N64CONTROLLER & Controller = g_InputPlugin->Controllers(m_ControllerNumber);
CONTROL & ControlInfo = g_InputPlugin->ControlInfo(m_ControllerNumber);
Controller.Range = (uint8_t)m_Range.GetPos();
ControlInfo.Present = (m_PluggedIn.GetCheck() == BST_CHECKED) ? 1 : 0;
ControlInfo.Plugin = m_cmbDevice.GetItemData(m_cmbDevice.GetCurSel());
return g_InputPlugin->SaveController(m_ControllerNumber);
}
LRESULT CControllerSettings::OnScroll(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
{
LONG SliderId = CWindow((HWND)lParam).GetWindowLong(GWL_ID);
if (SliderId == IDC_SLIDER_RANGE)
{
CWindow(GetDlgItem(IDC_LABEL_RANGE)).SetWindowText(stdstr_f("%d%%", m_Range.GetPos()).ToUTF16().c_str());
}
return 0;
}
LRESULT CControllerSettings::OnScanSuccess(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
if (m_SetupIndex < 0)
{
return 0;
}
CScanButton * Buttons[] = {
&m_ButtonUDPad, &m_ButtonDDPad, &m_ButtonLDPad, &m_ButtonRDPad,
&m_ButtonAnalogU, &m_ButtonAnalogD, &m_ButtonAnalogL, &m_ButtonAnalogR,
&m_ButtonCUp, &m_ButtonCDown, &m_ButtonCLeft, &m_ButtonCRight,
&m_ButtonB, &m_ButtonA, &m_ButtonStart, &m_ButtonZtrigger,
&m_ButtonLTrigger, &m_ButtonRTrigger
};
m_SetupIndex += 1;
if (m_SetupIndex < (sizeof(Buttons) / sizeof(Buttons[0])))
{
Buttons[m_SetupIndex]->DetectKey();
}
return 0;
}
LRESULT CControllerSettings::OnScanCanceled(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
m_SetupIndex = -1;
return 0;
}
void CControllerSettings::DefaultBtnClicked(UINT Code, int id, HWND ctl)
{
g_InputPlugin->ResetController(m_ControllerNumber);
DisplayController();
SendMessage(GetParent(), PSM_CHANGED, (WPARAM)m_hWnd, 0);
}
void CControllerSettings::SetupBtnClicked(UINT /*Code*/, int /*id*/, HWND /*ctl*/)
{
m_SetupIndex = 0;
m_ButtonUDPad.DetectKey();
}
void CControllerSettings::ItemChanged(UINT /*Code*/, int /*id*/, HWND /*ctl*/)
{
SendMessage(GetParent(), PSM_CHANGED, (WPARAM)m_hWnd, 0);
}
LRESULT CControllerSettings::ItemChangedNotify(NMHDR* /*pNMHDR*/)
{
SendMessage(GetParent(), PSM_CHANGED, (WPARAM)m_hWnd, 0);
return 0;
}
void CControllerSettings::DisplayController(void)
{
N64CONTROLLER & Controller = g_InputPlugin->Controllers(m_ControllerNumber);
CONTROL & ControlInfo = g_InputPlugin->ControlInfo(m_ControllerNumber);
m_cmbDevice.SetCurSel(0);
for (DWORD i = 0, n = m_cmbDevice.GetCount(); i < n; i++)
{
if (m_cmbDevice.GetItemData(i) == (DWORD)ControlInfo.Plugin)
{
m_cmbDevice.SetCurSel(i);
break;
}
}
m_PluggedIn.SetCheck(ControlInfo.Present != 0 ? BST_CHECKED : BST_UNCHECKED);
m_Range.SetPos(Controller.Range);
CWindow(GetDlgItem(IDC_LABEL_RANGE)).SetWindowText(stdstr_f("%d%%", m_Range.GetPos()).ToUTF16().c_str());
CScanButton * Buttons[] = {
&m_ButtonUDPad, &m_ButtonDDPad, &m_ButtonLDPad, &m_ButtonRDPad, &m_ButtonA, &m_ButtonB,
&m_ButtonCUp, &m_ButtonCDown, &m_ButtonCLeft, &m_ButtonCRight, &m_ButtonStart,
&m_ButtonZtrigger, &m_ButtonRTrigger, &m_ButtonLTrigger,
&m_ButtonAnalogU, &m_ButtonAnalogD, &m_ButtonAnalogL, &m_ButtonAnalogR
};
for (size_t i = 0, n = sizeof(Buttons) / sizeof(Buttons[0]); i < n; i++)
{
Buttons[i]->DisplayButton();
}
}
void CControllerSettings::ButtonChannged(void)
{
CPropertySheetWindow(GetParent()).SetModified(m_hWnd);
}
class CInputConfigUI:
public CPropertySheetImpl<CInputConfigUI>
{
public:
CInputConfigUI();
~CInputConfigUI();
void OnSheetInitialized();
private:
CControllerSettings m_pgController0, m_pgController1, m_pgController2, m_pgController3;
};
void ConfigInput(void * hParent)
{
CInputConfigUI().DoModal((HWND)hParent);
}
CInputConfigUI::CInputConfigUI() :
m_pgController0(0),
m_pgController1(1),
m_pgController2(2),
m_pgController3(3)
{
m_psh.pszCaption = L"Configure Input";
AddPage(&m_pgController0.m_psp);
AddPage(&m_pgController1.m_psp);
AddPage(&m_pgController2.m_psp);
AddPage(&m_pgController3.m_psp);
}
CInputConfigUI::~CInputConfigUI()
{
}
void CInputConfigUI::OnSheetInitialized()
{
ModifyStyleEx(WS_EX_CONTEXTHELP,0);
}

View File

@ -0,0 +1,3 @@
#pragma once
void ConfigInput(void * hParent);

View File

@ -0,0 +1,213 @@
/****************************************************************************
* *
* Project64-audio - A Nintendo 64 audio plugin. *
* http://www.pj64-emu.com/ *
* Copyright (C) 2020 Project64. All rights reserved. *
* *
* License: *
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
* *
****************************************************************************/
#include "ControllerSpec1.1.h"
#include "InputConfigUI.h"
#include "Version.h"
#include "CProject64Input.h"
#include "InputSettings.h"
#include <stdio.h>
/******************************************************************
Function: CloseDLL
Purpose: This function is called when the emulator is closing
down allowing the dll to de-initialise.
input: none
output: none
*******************************************************************/
EXPORT void CALL CloseDLL(void)
{
CleanupInputSettings();
}
/******************************************************************
Function: ControllerCommand
Purpose: To process the raw data that has just been sent to a
specific controller.
input: - Controller Number (0 to 3) and -1 signalling end of
processing the pif ram.
- Pointer of data to be processed.
output: none
note: This function is only needed if the DLL is allowing raw
data, or the plugin is set to raw
the data that is being processed looks like this:
initilize controller: 01 03 00 FF FF FF
read controller: 01 04 01 FF FF FF FF
*******************************************************************/
EXPORT void CALL ControllerCommand(int32_t /*Control*/, uint8_t * /*Command*/)
{
}
/******************************************************************
Function: DllAbout
Purpose: This function is optional function that is provided
to give further information about the DLL.
input: a handle to the window that calls this function
output: none
*******************************************************************/
/*EXPORT void CALL DllAbout(void * hParent)
{
}*/
/******************************************************************
Function: DllConfig
Purpose: This function is optional function that is provided
to allow the user to configure the dll
input: a handle to the window that calls this function
output: none
*******************************************************************/
#ifdef _WIN32
EXPORT void CALL DllConfig(void * hParent)
{
ConfigInput(hParent);
}
#endif
/******************************************************************
Function: DllTest
Purpose: This function is optional function that is provided
to allow the user to test the dll
input: a handle to the window that calls this function
output: none
*******************************************************************/
EXPORT void CALL DllTest(void * /*hParent*/)
{
}
/******************************************************************
Function: GetDllInfo
Purpose: This function allows the emulator to gather information
about the dll by filling in the PluginInfo structure.
input: a pointer to a PLUGIN_INFO stucture that needs to be
filled by the function. (see def above)
output: none
*******************************************************************/
EXPORT void CALL GetDllInfo(PLUGIN_INFO * PluginInfo)
{
PluginInfo->Version = CONTROLLER_SPECS_VERSION;
PluginInfo->Type = PLUGIN_TYPE_CONTROLLER;
#ifdef _DEBUG
sprintf(PluginInfo->Name, "Project64 Input Plugin (Debug): %s", VER_FILE_VERSION_STR);
#else
sprintf(PluginInfo->Name, "Project64 Input Plugin: %s", VER_FILE_VERSION_STR);
#endif
PluginInfo->MemoryBswaped = true;
PluginInfo->NormalMemory = false;
}
/******************************************************************
Function: GetKeys
Purpose: To get the current state of the controllers buttons.
input: - Controller Number (0 to 3)
- A pointer to a BUTTONS structure to be filled with
the controller state.
output: none
*******************************************************************/
EXPORT void CALL GetKeys(int32_t Control, BUTTONS * Keys)
{
g_InputPlugin->GetKeys(Control, Keys);
}
/******************************************************************
Function: InitiateControllers
Purpose: This function initialises how each of the controllers
should be handled.
input: - A controller structure that needs to be filled for
the emulator to know how to handle each controller.
output: none
*******************************************************************/
EXPORT void CALL InitiateControllers(CONTROL_INFO * ControlInfo)
{
if (g_InputPlugin != nullptr)
{
g_InputPlugin->InitiateControllers(ControlInfo);
}
}
/******************************************************************
Function: ReadController
Purpose: To process the raw data in the pif ram that is about to
be read.
input: - Controller Number (0 to 3) and -1 signalling end of
processing the pif ram.
- Pointer of data to be processed.
output: none
note: This function is only needed if the DLL is allowing raw
data.
*******************************************************************/
EXPORT void CALL ReadController(int /*Control*/, uint8_t * /*Command*/)
{
}
/******************************************************************
Function: RomClosed
Purpose: This function is called when a rom is closed.
input: none
output: none
*******************************************************************/
EXPORT void CALL RomClosed(void)
{
}
/******************************************************************
Function: RomOpen
Purpose: This function is called when a rom is open. (from the
emulation thread)
input: none
output: none
*******************************************************************/
EXPORT void CALL RomOpen(void)
{
}
/******************************************************************
Function: WM_KeyDown
Purpose: To pass the WM_KeyDown message from the emulator to the
plugin.
input: wParam and lParam of the WM_KEYDOWN message.
output: none
*******************************************************************/
EXPORT void CALL WM_KeyDown(uint32_t /*wParam*/, uint32_t /*lParam*/)
{
}
/******************************************************************
Function: WM_KeyUp
Purpose: To pass the WM_KEYUP message from the emulator to the
plugin.
input: wParam and lParam of the WM_KEYDOWN message.
output: none
*******************************************************************/
EXPORT void CALL WM_KeyUp(uint32_t /*wParam*/, uint32_t /*lParam*/)
{
}
EXPORT void CALL PluginLoaded(void)
{
SetupInputSettings();
}
#include <Windows.h>
extern "C" int WINAPI DllMain(HINSTANCE hinst, DWORD fdwReason, LPVOID /*lpReserved*/)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
g_InputPlugin = new CProject64Input(hinst);
}
else if (fdwReason == DLL_PROCESS_DETACH)
{
delete g_InputPlugin;
g_InputPlugin = NULL;
}
return TRUE;
}

View File

@ -0,0 +1,240 @@
#include <Settings/Settings.h>
#include <Common\StdString.h>
#include "InputSettingsID.h"
#include "InputSettings.h"
CInputSettings * g_Settings = nullptr;
CInputSettings::CInputSettings()
{
RegisterSettings();
}
CInputSettings::~CInputSettings()
{
}
void CInputSettings::LoadController(uint32_t ControlIndex, CONTROL & ControllerInfo, N64CONTROLLER & Controller)
{
struct {
BUTTON & Button;
InputSettingID SettingId;
uint32_t ControlIndex;
}
Buttons[] =
{
{ Controller.U_DPAD, Set_Control0_U_DPAD, 0 },
{ Controller.D_DPAD, Set_Control0_D_DPAD, 0 },
{ Controller.L_DPAD, Set_Control0_L_DPAD, 0 },
{ Controller.R_DPAD, Set_Control0_R_DPAD, 0 },
{ Controller.A_BUTTON, Set_Control0_A_BUTTON, 0 },
{ Controller.B_BUTTON, Set_Control0_B_BUTTON, 0 },
{ Controller.U_CBUTTON, Set_Control0_U_CBUTTON, 0 },
{ Controller.D_CBUTTON, Set_Control0_D_CBUTTON, 0 },
{ Controller.L_CBUTTON, Set_Control0_L_CBUTTON, 0 },
{ Controller.R_CBUTTON, Set_Control0_R_CBUTTON, 0 },
{ Controller.START_BUTTON, Set_Control0_START_BUTTON, 0 },
{ Controller.Z_TRIG, Set_Control0_Z_TRIG, 0 },
{ Controller.R_TRIG, Set_Control0_R_TRIG, 0 },
{ Controller.L_TRIG, Set_Control0_L_TRIG, 0 },
{ Controller.U_ANALOG, Set_Control0_U_ANALOG, 0 },
{ Controller.D_ANALOG, Set_Control0_D_ANALOG, 0 },
{ Controller.L_ANALOG, Set_Control0_L_ANALOG, 0 },
{ Controller.R_ANALOG, Set_Control0_R_ANALOG, 0 },
};
char Buffer[400];
for (size_t i = 0, n = sizeof(Buttons) / sizeof(Buttons[0]); i < n; i++)
{
if (Buttons[i].ControlIndex != ControlIndex)
{
continue;
}
Buttons[i].Button = StrToButton(GetSettingSz((short)Buttons[i].SettingId, Buffer, sizeof(Buffer) / sizeof(Buffer[0])));
}
InputSettingID PresentSettings[] = { Set_Control0_Present };
InputSettingID PluginSettings[] = { Set_Control0_Plugin };
InputSettingID RangeSettings[] = { Set_Control0_Range };
ControllerInfo.Present = ControlIndex < (sizeof(PresentSettings) / sizeof(PresentSettings[0])) ? GetSetting((short)PresentSettings[ControlIndex]) != 0 : 0;
ControllerInfo.Plugin = ControlIndex < (sizeof(PluginSettings) / sizeof(PluginSettings[0])) ? GetSetting((short)PluginSettings[ControlIndex]) : PLUGIN_NONE;
Controller.Range = (uint8_t)(ControlIndex < (sizeof(RangeSettings) / sizeof(RangeSettings[0])) ? GetSetting((short)RangeSettings[ControlIndex]) : 100);
if (Controller.Range == 0) { Controller.Range = 1; }
if (Controller.Range > 100) { Controller.Range = 100; }
}
void CInputSettings::SaveController(uint32_t ControlIndex, const CONTROL & ControllerInfo, const N64CONTROLLER & Controller)
{
struct {
const BUTTON & Button;
InputSettingID SettingId;
uint32_t ControlIndex;
}
Buttons[] =
{
{ Controller.U_DPAD, Set_Control0_U_DPAD, 0 },
{ Controller.D_DPAD, Set_Control0_D_DPAD, 0 },
{ Controller.L_DPAD, Set_Control0_L_DPAD, 0 },
{ Controller.R_DPAD, Set_Control0_R_DPAD, 0 },
{ Controller.A_BUTTON, Set_Control0_A_BUTTON, 0 },
{ Controller.B_BUTTON, Set_Control0_B_BUTTON, 0 },
{ Controller.U_CBUTTON, Set_Control0_U_CBUTTON, 0 },
{ Controller.D_CBUTTON, Set_Control0_D_CBUTTON, 0 },
{ Controller.L_CBUTTON, Set_Control0_L_CBUTTON, 0 },
{ Controller.R_CBUTTON, Set_Control0_R_CBUTTON, 0 },
{ Controller.START_BUTTON, Set_Control0_START_BUTTON, 0 },
{ Controller.Z_TRIG, Set_Control0_Z_TRIG, 0 },
{ Controller.R_TRIG, Set_Control0_R_TRIG, 0 },
{ Controller.L_TRIG, Set_Control0_L_TRIG, 0 },
{ Controller.U_ANALOG, Set_Control0_U_ANALOG, 0 },
{ Controller.D_ANALOG, Set_Control0_D_ANALOG, 0 },
{ Controller.L_ANALOG, Set_Control0_L_ANALOG, 0 },
{ Controller.R_ANALOG, Set_Control0_R_ANALOG, 0 },
};
for (size_t i = 0, n = sizeof(Buttons) / sizeof(Buttons[0]); i < n; i++)
{
if (Buttons[i].ControlIndex != ControlIndex)
{
continue;
}
SetSettingSz((short)Buttons[i].SettingId, ButtonToStr(Buttons[i].Button).c_str());
}
InputSettingID PresentSettings[] = { Set_Control0_Present };
if (ControlIndex < (sizeof(PresentSettings) / sizeof(PresentSettings[0])))
{
SetSetting((short)PresentSettings[ControlIndex], ControllerInfo.Present);
}
InputSettingID PluginSettings[] = { Set_Control0_Plugin };
if (ControlIndex < (sizeof(PluginSettings) / sizeof(PluginSettings[0])))
{
SetSetting((short)PluginSettings[ControlIndex], ControllerInfo.Plugin);
}
InputSettingID RangeSettings[] = { Set_Control0_Range };
if (ControlIndex < (sizeof(RangeSettings) / sizeof(RangeSettings[0])))
{
SetSetting((short)RangeSettings[ControlIndex], Controller.Range);
}
FlushSettings();
}
void CInputSettings::ResetController(uint32_t ControlIndex, CONTROL & ControllerInfo, N64CONTROLLER & Controller)
{
struct {
const BUTTON & Button;
InputSettingID SettingId;
uint32_t ControlIndex;
}
Buttons[] =
{
{ Controller.U_DPAD, Set_Control0_U_DPAD, 0 },
{ Controller.D_DPAD, Set_Control0_D_DPAD, 0 },
{ Controller.L_DPAD, Set_Control0_L_DPAD, 0 },
{ Controller.R_DPAD, Set_Control0_R_DPAD, 0 },
{ Controller.A_BUTTON, Set_Control0_A_BUTTON, 0 },
{ Controller.B_BUTTON, Set_Control0_B_BUTTON, 0 },
{ Controller.U_CBUTTON, Set_Control0_U_CBUTTON, 0 },
{ Controller.D_CBUTTON, Set_Control0_D_CBUTTON, 0 },
{ Controller.L_CBUTTON, Set_Control0_L_CBUTTON, 0 },
{ Controller.R_CBUTTON, Set_Control0_R_CBUTTON, 0 },
{ Controller.START_BUTTON, Set_Control0_START_BUTTON, 0 },
{ Controller.Z_TRIG, Set_Control0_Z_TRIG, 0 },
{ Controller.R_TRIG, Set_Control0_R_TRIG, 0 },
{ Controller.L_TRIG, Set_Control0_L_TRIG, 0 },
{ Controller.U_ANALOG, Set_Control0_U_ANALOG, 0 },
{ Controller.D_ANALOG, Set_Control0_D_ANALOG, 0 },
{ Controller.L_ANALOG, Set_Control0_L_ANALOG, 0 },
{ Controller.R_ANALOG, Set_Control0_R_ANALOG, 0 },
};
for (size_t i = 0, n = sizeof(Buttons) / sizeof(Buttons[0]); i < n; i++)
{
SetSettingSz((short)Buttons[i].SettingId, NULL);
}
FlushSettings();
LoadController(ControlIndex, ControllerInfo, Controller);
}
BUTTON CInputSettings::StrToButton(const char * Buffer)
{
BUTTON Button = { 0 };
GUID &guid = Button.DeviceGuid;
uint32_t ButtonOffset = 0, ButtonAxisID = 0, ButtonType = 0;
sscanf(Buffer,
"{%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx} %x %u %u",
&guid.Data1, &guid.Data2, &guid.Data3,
&guid.Data4[0], &guid.Data4[1], &guid.Data4[2], &guid.Data4[3],
&guid.Data4[4], &guid.Data4[5], &guid.Data4[6], &guid.Data4[7],
&ButtonOffset, &ButtonAxisID, &ButtonType);
Button.Offset = (uint8_t)(ButtonOffset & 0xFF);
Button.AxisID = (uint8_t)(ButtonAxisID & 0xFF);
Button.BtnType = (BtnType)ButtonType;
return Button;
}
std::string CInputSettings::ButtonToStr(const BUTTON & Button)
{
return stdstr_f("%s %02X %u %u", GUIDtoString(Button.DeviceGuid).c_str(), Button.Offset, Button.AxisID, Button.BtnType);
}
std::string CInputSettings::GUIDtoString(const GUID & guid)
{
return stdstr_f("{%08.8lX-%04.4hX-%04.4hX-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}", guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
}
void CInputSettings::RegisterSettings(void)
{
SetModuleName("Input");
RegisterSetting(Set_Control0_Present, Data_DWORD_General, "Present", "Controller 1", 1, nullptr);
RegisterSetting(Set_Control0_Plugin, Data_DWORD_General, "Plugin", "Controller 1", PLUGIN_MEMPAK, nullptr);
RegisterSetting(Set_Control0_Range, Data_DWORD_General, "Range", "Controller 1", 100, nullptr);
RegisterSetting(Set_Control0_U_DPAD, Data_String_General, "DPadUp", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} 17 0 5");
RegisterSetting(Set_Control0_D_DPAD, Data_String_General, "DPadDown", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} 25 0 5");
RegisterSetting(Set_Control0_L_DPAD, Data_String_General, "DPadLeft", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} 24 0 5");
RegisterSetting(Set_Control0_R_DPAD, Data_String_General, "DPadRight", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} 26 0 5");
RegisterSetting(Set_Control0_A_BUTTON, Data_String_General, "ButtonA", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} 2D 0 5");
RegisterSetting(Set_Control0_B_BUTTON, Data_String_General, "ButtonB", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} 2E 0 5");
RegisterSetting(Set_Control0_U_CBUTTON, Data_String_General, "CButtonUp", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} C7 0 5");
RegisterSetting(Set_Control0_D_CBUTTON, Data_String_General, "CButtonDown", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} CF 0 5");
RegisterSetting(Set_Control0_L_CBUTTON, Data_String_General, "CButtonLeft", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} D1 0 5");
RegisterSetting(Set_Control0_R_CBUTTON, Data_String_General, "CButtonRight", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} D3 0 5");
RegisterSetting(Set_Control0_START_BUTTON, Data_String_General, "ButtonStart", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} 1C 0 5");
RegisterSetting(Set_Control0_Z_TRIG, Data_String_General, "ButtonZ", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} 2C 0 5");
RegisterSetting(Set_Control0_R_TRIG, Data_String_General, "ButtonR", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} 1F 0 5");
RegisterSetting(Set_Control0_L_TRIG, Data_String_General, "ButtonL", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} 1E 0 5");
RegisterSetting(Set_Control0_U_ANALOG, Data_String_General, "AnalogUp", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} C8 0 5");
RegisterSetting(Set_Control0_D_ANALOG, Data_String_General, "AnalogDown", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} D0 0 5");
RegisterSetting(Set_Control0_L_ANALOG, Data_String_General, "AnalogLeft", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} CB 0 5");
RegisterSetting(Set_Control0_R_ANALOG, Data_String_General, "AnalogRight", "Controller 1", 0, "{6F1D2B61-D5A0-11CF-BFC7-444553540000} CD 0 5");
}
void SetupInputSettings(void)
{
if (g_Settings == nullptr)
{
g_Settings = new CInputSettings;
}
}
void CleanupInputSettings(void)
{
if (g_Settings)
{
delete g_Settings;
g_Settings = nullptr;
}
}
#ifdef _WIN32
#include <Windows.h>
#endif
extern "C" void UseUnregisteredSetting(int /*SettingID*/)
{
#ifdef _WIN32
DebugBreak();
#endif
}

View File

@ -0,0 +1,31 @@
#pragma once
#include <Common\stdtypes.h>
#include <string>
#include "N64Controller.h"
#include "ControllerSpec1.1.h"
class CInputSettings
{
public:
CInputSettings();
~CInputSettings();
void LoadController(uint32_t ControlIndex, CONTROL & ControllerInfo, N64CONTROLLER & Controller);
void SaveController(uint32_t ControlIndex, const CONTROL & ControllerInfo, const N64CONTROLLER & Controller);
void ResetController(uint32_t ControlIndex, CONTROL & ControllerInfo, N64CONTROLLER & Controller);
private:
CInputSettings(const CInputSettings&);
CInputSettings& operator=(const CInputSettings&);
static BUTTON StrToButton(const char * Buffer);
static std::string ButtonToStr(const BUTTON & Button);
static std::string GUIDtoString(const GUID & guid);
void RegisterSettings(void);
};
extern CInputSettings * g_Settings;
void SetupInputSettings(void);
void CleanupInputSettings(void);

View File

@ -0,0 +1,26 @@
#pragma once
enum InputSettingID
{
Set_Control0_Present,
Set_Control0_Plugin,
Set_Control0_Range,
Set_Control0_U_DPAD,
Set_Control0_D_DPAD,
Set_Control0_L_DPAD,
Set_Control0_R_DPAD,
Set_Control0_A_BUTTON,
Set_Control0_B_BUTTON,
Set_Control0_U_CBUTTON,
Set_Control0_D_CBUTTON,
Set_Control0_L_CBUTTON,
Set_Control0_R_CBUTTON,
Set_Control0_START_BUTTON,
Set_Control0_Z_TRIG,
Set_Control0_R_TRIG,
Set_Control0_L_TRIG,
Set_Control0_U_ANALOG,
Set_Control0_D_ANALOG,
Set_Control0_L_ANALOG,
Set_Control0_R_ANALOG,
};

View File

@ -0,0 +1,25 @@
#pragma once
#include "Button.h"
typedef struct
{
BUTTON U_DPAD;
BUTTON D_DPAD;
BUTTON L_DPAD;
BUTTON R_DPAD;
BUTTON A_BUTTON;
BUTTON B_BUTTON;
BUTTON U_CBUTTON;
BUTTON D_CBUTTON;
BUTTON L_CBUTTON;
BUTTON R_CBUTTON;
BUTTON START_BUTTON;
BUTTON Z_TRIG;
BUTTON R_TRIG;
BUTTON L_TRIG;
BUTTON U_ANALOG;
BUTTON D_ANALOG;
BUTTON L_ANALOG;
BUTTON R_ANALOG;
uint8_t Range;
} N64CONTROLLER;

Binary file not shown.

View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{D3F979CE-8FA7-48C9-A2B3-A33594B48536}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>Project64input</RootNamespace>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(SolutionDir)PropertySheets\Platform.$(Configuration).props" />
</ImportGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<PropertyGroup>
<TargetName>Project64-Input</TargetName>
<TargetName Condition="'$(Configuration)'=='Debug'">Project64-Input_d</TargetName>
<OutDir>$(SolutionDir)Plugin\Input\</OutDir>
<OutDir Condition="'$(Platform)'=='x64'">$(SolutionDir)Plugin64\Input\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<PreBuildEvent>
<Command>"$(SolutionDir)Source\Script\UpdateVersion.cmd" "$(Configuration)" "$(Platform)" "$(SolutionDir)Source\Project64-input\Version.h.in" "$(SolutionDir)Source\Project64-input\Version.h"</Command>
</PreBuildEvent>
<Link>
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">dinput8.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Root)Source\3rdParty\directx\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ImageHasSafeExceptionHandlers Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ImageHasSafeExceptionHandlers>
</Link>
<Link>
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">dinput8.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Root)Source\3rdParty\directx\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ImageHasSafeExceptionHandlers Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="DeviceNotification.cpp" />
<ClCompile Include="DirectInput.cpp" />
<ClCompile Include="InputConfigUI.cpp" />
<ClCompile Include="InputMain.cpp" />
<ClCompile Include="CProject64Input.cpp" />
<ClCompile Include="InputSettings.cpp" />
<ClCompile Include="wtl-BitmapPicture.cpp" />
<ClCompile Include="wtl-ScanButton.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Button.h" />
<ClInclude Include="DeviceNotification.h" />
<ClInclude Include="InputSettings.h" />
<ClInclude Include="InputSettingsID.h" />
<ClInclude Include="N64Controller.h" />
<ClInclude Include="DirectInput.h" />
<ClInclude Include="InputConfigUI.h" />
<ClInclude Include="ControllerSpec1.1.h" />
<ClInclude Include="CProject64Input.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="wtl-BitmapPicture.h" />
<ClInclude Include="wtl-ScanButton.h" />
<ClInclude Include="wtl.h" />
</ItemGroup>
<ItemGroup>
<None Include="Version.h.in" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Project64-input.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="Controller.bmp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Common\Common.vcxproj">
<Project>{b4a4b994-9111-42b1-93c2-6f1ca8bc4421}</Project>
</ProjectReference>
<ProjectReference Include="..\Settings\Settings.vcxproj">
<Project>{8b9961b1-88d9-4ea3-a752-507a00dd9f3d}</Project>
</ProjectReference>
</ItemGroup>
</Project>

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="InputMain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="InputConfigUI.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="wtl-BitmapPicture.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CProject64Input.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DirectInput.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="wtl-ScanButton.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="InputSettings.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DeviceNotification.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ControllerSpec1.1.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="InputConfigUI.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="wtl-BitmapPicture.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="wtl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CProject64Input.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DirectInput.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="wtl-ScanButton.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Button.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="N64Controller.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="InputSettings.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="InputSettingsID.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DeviceNotification.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="Version.h.in">
<Filter>Header Files</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Project64-input.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<Image Include="Controller.bmp">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
</Project>

View File

@ -0,0 +1,43 @@
/****************************************************************************
* *
* Project64-input - A Nintendo 64 audio plugin. *
* http://www.pj64-emu.com/ *
* Copyright (C) 2020 Project64. All rights reserved. *
* *
* License: *
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
* *
****************************************************************************/
#define STRINGIZE2(s) #s
#define STRINGIZE(s) STRINGIZE2(s)
#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define VERSION_REVISION 0
#define VERSION_BUILD 9999
#define GIT_VERSION ""
#define VER_FILE_DESCRIPTION_STR "Project64-input"
#define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD
#define VER_FILE_VERSION_STR STRINGIZE(VERSION_MAJOR) \
"." STRINGIZE(VERSION_MINOR) \
"." STRINGIZE(VERSION_REVISION) \
"." STRINGIZE(VERSION_BUILD) \
"-" GIT_VERSION
#define VER_PRODUCTNAME_STR "Project64-input"
#define VER_PRODUCT_VERSION VER_FILE_VERSION
#define VER_PRODUCT_VERSION_STR VER_FILE_VERSION_STR
#define VER_ORIGINAL_FILENAME_STR VER_PRODUCTNAME_STR ".dll"
#define VER_INTERNAL_NAME_STR VER_PRODUCTNAME_STR
#define VER_COPYRIGHT_STR "Copyright (C) 2020"
#ifdef _DEBUG
#define VER_VER_DEBUG VS_FF_DEBUG
#else
#define VER_VER_DEBUG 0
#endif
#define VER_FILEOS VOS_NT_WINDOWS32
#define VER_FILEFLAGS VER_VER_DEBUG
#define VER_FILETYPE VFT_DLL

Binary file not shown.

View File

@ -0,0 +1,92 @@
#include "wtl-BitmapPicture.h"
CBitmapPicture::CBitmapPicture() :
m_hBitmap(NULL),
m_nResourceID(-1),
m_ResourceIcon(false)
{
memset(&m_bmInfo, 0, sizeof(m_bmInfo));
m_BackgroundBrush.CreateSolidBrush(::GetSysColor(COLOR_3DFACE));
}
LRESULT CBitmapPicture::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL &/*bHandled*/)
{
CPaintDC dc(m_hWnd);
CRect rect;
GetClientRect(&rect);
CBrush PaintBrush;
HBRUSH OldBrush = dc.SelectBrush(m_BackgroundBrush);
dc.PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
if (m_ResourceIcon)
{
CIcon hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), m_nResourceID > 0 ? MAKEINTRESOURCE(m_nResourceID) : m_strResourceName.c_str(), IMAGE_ICON, m_IconWidth, m_IconHeight, LR_DEFAULTCOLOR | LR_DEFAULTSIZE);
if (!hIcon.IsNull())
{
dc.DrawIconEx(0, 0, hIcon, rect.Width(), rect.Height(), 0, NULL, DI_NORMAL);
}
}
else
{
CBitmap hBmp = (HBITMAP)::LoadImage(ModuleHelper::GetResourceInstance(), m_nResourceID > 0 ? MAKEINTRESOURCE(m_nResourceID) : m_strResourceName.c_str(), IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS);
BITMAP bm;
hBmp.GetBitmap(&bm);
CDC dcMem;
dcMem.CreateCompatibleDC(dc);
dcMem.SelectBitmap(hBmp);
dc.StretchBlt(rect.left, rect.top, rect.Width(), rect.Height(), dcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
}
dc.SelectBrush(OldBrush);
return 0;
}
bool CBitmapPicture::SetIcon(LPCWSTR lpszResourceName, uint32_t nWidth, uint32_t nHeight)
{
CIcon hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), lpszResourceName, IMAGE_ICON, nWidth, nHeight, LR_DEFAULTCOLOR | LR_DEFAULTSIZE);
if (hIcon.IsNull())
{
return false;
}
ICONINFO IconInfo;
if (!hIcon.GetIconInfo(&IconInfo))
{
return false;
}
if (IS_INTRESOURCE(lpszResourceName))
{
m_nResourceID = (int)lpszResourceName;
}
else
{
m_strResourceName = lpszResourceName;
}
m_ResourceIcon = true;
m_IconWidth = nWidth;
m_IconHeight = nHeight;
return true;
}
bool CBitmapPicture::SetBitmap(HBITMAP hBitmap)
{
m_hBitmap.Attach(hBitmap);
return ::GetObject(m_hBitmap, sizeof(BITMAP), &m_bmInfo) != 0;
}
void CBitmapPicture::SetBitmap(LPCWSTR lpszResourceName)
{
if (IS_INTRESOURCE(lpszResourceName))
{
m_nResourceID = (int)lpszResourceName;
}
else
{
m_strResourceName = lpszResourceName;
}
m_ResourceIcon = false;
}
void CBitmapPicture::SetBackroundBrush(HBRUSH brush)
{
m_BackgroundBrush.Attach(brush);
}

View File

@ -0,0 +1,34 @@
#pragma once
#include "wtl.h"
#include <string>
class CBitmapPicture :
public CWindowImpl <CBitmapPicture>
{
public:
BEGIN_MSG_MAP(CBitmapPicture)
MESSAGE_HANDLER(WM_PAINT, OnPaint);
END_MSG_MAP()
CBitmapPicture();
LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL &/*bHandled*/);
bool SetIcon(LPCWSTR lpszResourceName, uint32_t nWidth, uint32_t nHeight);
void SetBitmap(LPCWSTR lpszResourceName);
void SetBackroundBrush(HBRUSH brush);
private:
CBitmapPicture(const CBitmapPicture&);
CBitmapPicture& operator=(const CBitmapPicture&);
bool CBitmapPicture::SetBitmap(HBITMAP hBitmap);
int m_nResourceID;
std::wstring m_strResourceName;
uint32_t m_IconWidth, m_IconHeight;
bool m_ResourceIcon;
BITMAP m_bmInfo;
CBitmap m_hBitmap;
CBrush m_BackgroundBrush;
};

View File

@ -0,0 +1,185 @@
#include "wtl-ScanButton.h"
#include "CProject64Input.h"
#include <Common\StdString.h>
#include <time.h>
CScanButton::CScanButton(BUTTON & Button, int DisplayCtrlId, int ScanBtnId) :
m_Button(Button),
m_DisplayCtrlId(DisplayCtrlId),
m_ScanBtnId(ScanBtnId),
m_ScanBtnProc(nullptr),
m_ScanCount(0),
m_ScanStart(0),
m_ChangeCallback(nullptr),
m_ChangeCallbackData(0)
{
}
void CScanButton::SubclassWindow(CWindow Wnd)
{
m_DisplayCtrl = Wnd.GetDlgItem(m_DisplayCtrlId);
m_ScanBtn = Wnd.GetDlgItem(m_ScanBtnId);
m_ScanBtnThunk.Init((WNDPROC)ScanButtonProc, this);
m_ScanBtnProc = (WNDPROC)m_ScanBtn.SetWindowLongPtrW(GWLP_WNDPROC, (LONG_PTR)m_ScanBtnThunk.GetWNDPROC());
DisplayButton();
}
void CScanButton::SetChangeCallback(ChangeCallback callback, size_t callbackdata)
{
m_ChangeCallback = callback;
m_ChangeCallbackData = callbackdata;
}
void CScanButton::DisplayButton(void)
{
m_DisplayCtrl.SetWindowText(g_InputPlugin->ButtonAssignment(m_Button).c_str());
}
void CScanButton::DetectKey(void)
{
enum
{
SACN_INTERVAL = 20
};
m_ScanCount = 0;
time(&m_ScanStart);
g_InputPlugin->StartScanDevices(m_DisplayCtrlId);
m_DisplayCtrl.Invalidate();
m_ScanBtn.SetTimer(DETECT_KEY_TIMER, SACN_INTERVAL, NULL);
MakeOverlay();
}
void CScanButton::OnTimer(UINT_PTR nIDEvent)
{
if (nIDEvent == DETECT_KEY_TIMER)
{
bool Stop = false, ScanSuccess = false;
if (g_InputPlugin)
{
BUTTON Button = m_Button;
CDirectInput::ScanResult Result = g_InputPlugin->ScanDevices(Button);
if (Result == CDirectInput::SCAN_SUCCEED && (Button.Offset != m_Button.Offset || Button.AxisID != m_Button.AxisID || Button.BtnType != m_Button.BtnType))
{
m_Button = Button;
if (m_ChangeCallback != nullptr)
{
m_ChangeCallback(m_ChangeCallbackData);
}
}
if (Result == CDirectInput::SCAN_SUCCEED || Result == CDirectInput::SCAN_ESCAPE)
{
ScanSuccess = Result == CDirectInput::SCAN_SUCCEED;
Stop = true;
DisplayButton();
}
}
if ((m_ScanCount % 30) == 0)
{
CWindow Dialog = m_ScanBtn.GetParent().GetParent();
time_t Now = time(nullptr);
if (10 - (Now - m_ScanStart) > 0)
{
Dialog.SetWindowText(stdstr_f("Configure Input: Press Key ... (%d seconds)", 10 - (Now - m_ScanStart)).ToUTF16().c_str());
}
else
{
Stop = true;
}
}
if (m_ScanCount > 500)
{
Stop = true;
}
else
{
m_ScanCount += 1;
}
if (Stop)
{
m_ScanBtn.KillTimer(DETECT_KEY_TIMER);
CWindow Dialog = m_ScanBtn.GetParent().GetParent();
Dialog.SetWindowText(L"Configure Input");
if (m_Overlay.m_hWnd != NULL)
{
m_Overlay.DestroyWindow();
m_Overlay = NULL;
}
g_InputPlugin->EndScanDevices();
m_DisplayCtrl.Invalidate();
m_DisplayCtrl.GetParent().SendMessage(ScanSuccess ? WM_SCAN_SUCCESS : WM_SCAN_CANCELED);
}
}
}
void CScanButton::MakeOverlay(void)
{
WNDCLASS wc = { 0 };
wc.lpfnWndProc = (WNDPROC)BlockerProc;
wc.hInstance = g_InputPlugin->hInst();
wc.lpszClassName = L"BlockerClass";
RegisterClass(&wc);
CWindow ControllerDlg = m_ScanBtn.GetParent().GetParent();
CRect size;
ControllerDlg.GetWindowRect(&size);
#ifndef _DEBUG
m_Overlay = CreateWindowEx(WS_EX_TOPMOST | WS_EX_TRANSPARENT, L"BlockerClass", L"Blocker", WS_POPUP, size.left, size.top, size.Width(), size.Height(), ControllerDlg, nullptr, g_InputPlugin->hInst(), NULL);
if (m_Overlay == NULL)
{
return;
}
m_Overlay.SetFocus();
m_Overlay.ShowWindow(SW_SHOWNOACTIVATE);
#endif
}
UINT_PTR CALLBACK CScanButton::ScanButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CScanButton * _this = (CScanButton*)hWnd;
UINT_PTR uRet = 0;
if (uMsg == WM_LBUTTONUP)
{
POINT ptCursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
_this->m_ScanBtn.ClientToScreen(&ptCursor);
RECT rect = { 0 };
_this->m_ScanBtn.GetWindowRect(&rect);
if (PtInRect(&rect, ptCursor))
{
_this->DetectKey();
}
}
else if (uMsg == WM_TIMER)
{
_this->OnTimer((UINT_PTR)wParam);
}
if (_this->m_ScanBtnProc != nullptr)
{
uRet = _this->m_ScanBtnProc(_this->m_ScanBtn, uMsg, wParam, lParam);
}
return uRet;
}
UINT_PTR CALLBACK CScanButton::BlockerProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_CREATE)
{
return 0;
}
if (msg == WM_KEYDOWN || msg == WM_KEYUP)
{
return 0;
}
if (msg == WM_PAINT)
{
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}

View File

@ -0,0 +1,47 @@
#pragma once
#include "wtl.h"
#include "Button.h"
class CScanButton
{
enum
{
DETECT_KEY_TIMER = 1
};
public:
enum
{
WM_SCAN_SUCCESS = WM_USER + 0x140,
WM_SCAN_CANCELED = WM_USER + 0x141,
};
typedef void(*ChangeCallback)(size_t Data);
CScanButton(BUTTON & Button, int DisplayCtrlId, int ScanBtnId);
void SubclassWindow(CWindow Wnd);
void SetChangeCallback(ChangeCallback callback, size_t callbackdata);
void DetectKey(void);
void DisplayButton(void);
private:
CScanButton(void);
CScanButton(const CScanButton&);
CScanButton& operator=(const CScanButton&);
void OnTimer(UINT_PTR nIDEvent);
void MakeOverlay(void);
static UINT_PTR CALLBACK ScanButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static UINT_PTR CALLBACK BlockerProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
BUTTON & m_Button;
int32_t m_DisplayCtrlId, m_ScanBtnId;
CWindow m_DisplayCtrl, m_ScanBtn;
CWndProcThunk m_ScanBtnThunk;
WNDPROC m_ScanBtnProc;
uint32_t m_ScanCount;
time_t m_ScanStart;
CWindow m_Overlay;
ChangeCallback m_ChangeCallback;
size_t m_ChangeCallbackData;
};

View File

@ -0,0 +1,16 @@
#pragma once
#pragma warning(push)
#pragma warning(disable : 4091) // warning C4091: 'typedef ': ignored on left of 'tagGPFIDL_FLAGS' when no variable is declared
#pragma warning(disable : 4302) // warning C4302: 'type cast': truncation from 'LPCTSTR' to 'WORD'
#pragma warning(disable : 4458) // warning C4458: declaration of 'dwCommonButtons' hides class member
#pragma warning(disable : 4838) // warning C4838: conversion from 'int' to 'UINT' requires a narrowing conversion
#pragma warning(disable : 4996) // warning C4996: 'GetVersionExA': was declared deprecated
#pragma warning(disable : 4302) // warning C4302: 'type cast': truncation from 'LPCTSTR' to 'WORD'
#pragma warning(disable : 4457) // warning C4457: declaration of 'pstr' hides function parameter
#include <atlbase.h>
#include <WTL/atlapp.h>
#include <WTL/atldlgs.h>
#include <WTL/atlmisc.h>
#include <WTL/atlctrls.h>
#include <WTL/atlcrack.h>
#pragma warning(pop)

View File

@ -82,9 +82,9 @@ extern "C" {
unsigned Reserved1 : 1;
unsigned Reserved2 : 1;
signed Y_AXIS : 8;
signed X_AXIS : 8;
signed Y_AXIS : 8;
};
} BUTTONS;