From f78e292796ac2626b902a3c0310f455592b32175 Mon Sep 17 00:00:00 2001 From: zilmar Date: Tue, 23 Jun 2020 17:17:46 +0930 Subject: [PATCH] Input plugin: Start to scan keyboard --- Source/Project64-input/Button.h | 27 +++ Source/Project64-input/CProject64Input.cpp | 55 +++++ Source/Project64-input/CProject64Input.h | 36 +++ Source/Project64-input/DirectInput.cpp | 215 ++++++++++++++++++ Source/Project64-input/DirectInput.h | 59 +++++ Source/Project64-input/InputConfigUI.cpp | 75 ++++-- Source/Project64-input/InputMain.cpp | 23 +- Source/Project64-input/N64Controller.h | 20 ++ .../Project64-input/Project64-input.vcxproj | 18 ++ .../Project64-input.vcxproj.filters | 24 ++ Source/Project64-input/Version.h.in | 4 +- Source/Project64-input/wtl-ScanButton.cpp | 156 +++++++++++++ Source/Project64-input/wtl-ScanButton.h | 37 +++ 13 files changed, 730 insertions(+), 19 deletions(-) create mode 100644 Source/Project64-input/Button.h create mode 100644 Source/Project64-input/CProject64Input.cpp create mode 100644 Source/Project64-input/CProject64Input.h create mode 100644 Source/Project64-input/DirectInput.cpp create mode 100644 Source/Project64-input/DirectInput.h create mode 100644 Source/Project64-input/N64Controller.h create mode 100644 Source/Project64-input/wtl-ScanButton.cpp create mode 100644 Source/Project64-input/wtl-ScanButton.h diff --git a/Source/Project64-input/Button.h b/Source/Project64-input/Button.h new file mode 100644 index 000000000..4977657aa --- /dev/null +++ b/Source/Project64-input/Button.h @@ -0,0 +1,27 @@ +#pragma once +#include + +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 +{ + uint8_t Offset; + uint8_t AxisID; + BtnType BtnType; +} BUTTON; diff --git a/Source/Project64-input/CProject64Input.cpp b/Source/Project64-input/CProject64Input.cpp new file mode 100644 index 000000000..c055bd03b --- /dev/null +++ b/Source/Project64-input/CProject64Input.cpp @@ -0,0 +1,55 @@ +#include "CProject64Input.h" + +CProject64Input * g_InputPlugin = nullptr; + +CProject64Input::CProject64Input(HINSTANCE hinst) : + m_hinst(hinst), + m_Scanning(false), + m_DisplayCtrlId(0) +{ + memset(m_Controllers, 0, sizeof(m_Controllers)); +} + +CProject64Input::~CProject64Input() +{ +} + +void CProject64Input::InitiateControllers(CONTROL_INFO * ControlInfo) +{ + if (m_DirectInput.get() == NULL) + { + m_DirectInput.reset(new CDirectInput(m_hinst)); + } + m_DirectInput->Initiate(ControlInfo); +} + +void CProject64Input::StartScanDevices(int32_t DisplayCtrlId) +{ + m_Scanning = true; + m_DisplayCtrlId = DisplayCtrlId; +} + +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"; +} diff --git a/Source/Project64-input/CProject64Input.h b/Source/Project64-input/CProject64Input.h new file mode 100644 index 000000000..8ce1aac38 --- /dev/null +++ b/Source/Project64-input/CProject64Input.h @@ -0,0 +1,36 @@ +#pragma once +#include "ControllerSpec1.1.h" +#include "DirectInput.h" +#include "N64Controller.h" +#include + +class CProject64Input +{ +public: + CProject64Input(HINSTANCE hinst); + ~CProject64Input(); + + void InitiateControllers(CONTROL_INFO * ControlInfo); + void StartScanDevices(int32_t DisplayCtrlId); + void EndScanDevices(void); + CDirectInput::ScanResult ScanDevices(BUTTON & Button); + std::wstring ButtonAssignment(BUTTON & Button); + + 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]; } + +private: + CProject64Input(); + CProject64Input(const CProject64Input&); + CProject64Input& operator=(const CProject64Input&); + + N64CONTROLLER m_Controllers[4]; + std::unique_ptr m_DirectInput; + HINSTANCE m_hinst; + bool m_Scanning; + int32_t m_DisplayCtrlId; +}; + +extern CProject64Input * g_InputPlugin; \ No newline at end of file diff --git a/Source/Project64-input/DirectInput.cpp b/Source/Project64-input/DirectInput.cpp new file mode 100644 index 000000000..de9d9c44e --- /dev/null +++ b/Source/Project64-input/DirectInput.cpp @@ -0,0 +1,215 @@ +#include "DirectInput.h" +#include + +CDirectInput::CDirectInput(HINSTANCE hinst) : + m_hDirectInputDLL(nullptr), + m_pDIHandle(nullptr), + m_hinst(hinst), + m_hWnd(nullptr) +{ + LoadConfig(); + 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; + } + } + + if (m_pDIHandle != nullptr) + { + m_pDIHandle->EnumDevices(DI8DEVCLASS_ALL, stEnumMakeDeviceList, this, DIEDFL_ATTACHEDONLY); + } + } +} + +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; +} + +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 Device; + 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 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(device.didHandle, Button); + } + else if (DeviceType == DI8DEVTYPE_MOUSE) + { + //dwReturn = ScanMouse(&g_devList[i], lpdwCounter, pButton); + } + else + { + // dwReturn = ScanGamePad(&g_devList[i], lpdwCounter, pButton, i); + } + + if (Result != SCAN_FAILED) + { + return Result; + } + } + return Result; +} + +std::wstring CDirectInput::ButtonAssignment(BUTTON & Button) +{ + 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: ???"; + } + } + else if (Button.BtnType == BTNTYPE_UNASSIGNED) + { + return L""; + } + return L"Unknown"; +} + +CDirectInput::ScanResult CDirectInput::ScanKeyboard(LPDIRECTINPUTDEVICE8 didHandle, 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 ((cKeys[i] & 0x80) == 0) + { + continue; + } + if (i == DIK_ESCAPE) + { + return SCAN_ESCAPE; + } + pButton.Offset = (uint8_t)i; + pButton.AxisID = 0; + pButton.BtnType = BTNTYPE_KEYBUTTON; + return SCAN_SUCCEED; + } + return SCAN_FAILED; +} + +void CDirectInput::LoadConfig(void) +{ + +} diff --git a/Source/Project64-input/DirectInput.h b/Source/Project64-input/DirectInput.h new file mode 100644 index 000000000..fdb135e82 --- /dev/null +++ b/Source/Project64-input/DirectInput.h @@ -0,0 +1,59 @@ +#pragma once +#include "ControllerSpec1.1.h" +#include "Button.h" +#define DIRECTINPUT_VERSION 0x0800 +#include +#include +#include +#include + +class CDirectInput +{ +public: + enum ScanResult + { + SCAN_FAILED = 0x00, + SCAN_SUCCEED = 0x01, + SCAN_ESCAPE = 0x10, + }; + + CDirectInput(HINSTANCE hinst); + ~CDirectInput(); + + void Initiate(CONTROL_INFO * ControlInfo); + ScanResult ScanDevices(BUTTON & Button); + std::wstring ButtonAssignment(BUTTON & Button); + +private: + CDirectInput(); + CDirectInput(const CDirectInput&); + CDirectInput& operator=(const CDirectInput&); + + static BOOL CALLBACK stEnumMakeDeviceList(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef); + BOOL EnumMakeDeviceList(LPCDIDEVICEINSTANCE lpddi); + ScanResult ScanKeyboard(LPDIRECTINPUTDEVICE8 didHandle, BUTTON & pButton); + void LoadConfig(void); + + typedef struct + { + LPDIRECTINPUTDEVICE8 didHandle; + uint32_t dwDevType; + std::string InstanceName; + std::string ProductName; + } DEVICE; + + struct GUIDComparer + { + bool operator()(const GUID & Left, const GUID & Right) const + { + return memcmp(&Left, &Right, sizeof(Right)) < 0; + } + }; + typedef std::map DEVICE_MAP; + + DEVICE_MAP m_Devices; + HMODULE m_hDirectInputDLL; + LPDIRECTINPUT8 m_pDIHandle; + HINSTANCE m_hinst; + HWND m_hWnd; +}; \ No newline at end of file diff --git a/Source/Project64-input/InputConfigUI.cpp b/Source/Project64-input/InputConfigUI.cpp index 179b2a273..4b543f015 100644 --- a/Source/Project64-input/InputConfigUI.cpp +++ b/Source/Project64-input/InputConfigUI.cpp @@ -1,6 +1,8 @@ #include "InputConfigUI.h" +#include "CProject64Input.h" #include "wtl.h" #include "wtl-BitmapPicture.h" +#include "wtl-ScanButton.h" #include #include #include "resource.h" @@ -8,43 +10,81 @@ class CControllerSettings : public CPropertyPageImpl { + enum + { + DETECT_KEY_TIMER = 1 + }; public: enum { IDD = IDD_Controller }; BEGIN_MSG_MAP(CDebugSettings) MSG_WM_INITDIALOG(OnInitDialog) + MSG_WM_CTLCOLORSTATIC(OnCtlColorStatic) CHAIN_MSG_MAP(CPropertyPageImpl) END_MSG_MAP() - CControllerSettings(); - void SetControllerNumber(uint32_t ControllerNumber); + CControllerSettings(uint32_t ControllerNumber); BOOL OnInitDialog(CWindow /*wndFocus*/, LPARAM /*lInitParam*/); + HBRUSH OnCtlColorStatic(CDCHandle dc, CWindow wndStatic); private: std::wstring m_Title; uint32_t m_ControllerNumber; + uint32_t m_ScanCount; CBitmapPicture m_ControllerImg; + CScanButton ButtonUDPad, ButtonDDPad, ButtonLDPad, ButtonRDPad; + CScanButton ButtonCUp, ButtonCDown, ButtonCLeft, ButtonCRight; + CScanButton ButtonA, ButtonB; }; -CControllerSettings::CControllerSettings() : - m_ControllerNumber((uint32_t)-1) -{ -} - -void CControllerSettings::SetControllerNumber(uint32_t ControllerNumber) +CControllerSettings::CControllerSettings(uint32_t ControllerNumber) : + m_ControllerNumber(ControllerNumber), + m_ScanCount(0), + ButtonUDPad(g_InputPlugin->Controllers(ControllerNumber).U_DPAD, IDC_EDIT_DIGITIAL_UP, IDC_BTN_DIGITIAL_UP), + ButtonDDPad(g_InputPlugin->Controllers(ControllerNumber).D_DPAD, IDC_EDIT_DIGITIAL_DOWN, IDC_BTN_DIGITIAL_DOWN), + ButtonLDPad(g_InputPlugin->Controllers(ControllerNumber).L_DPAD, IDC_EDIT_DIGITIAL_LEFT, IDC_BTN_DIGITIAL_LEFT), + ButtonRDPad(g_InputPlugin->Controllers(ControllerNumber).R_DPAD, IDC_EDIT_DIGITIAL_RIGHT, IDC_BTN_DIGITIAL_RIGHT), + ButtonA(g_InputPlugin->Controllers(ControllerNumber).A_BUTTON, IDC_EDIT_BUTTON_A, IDC_BTN_BUTTON_A), + ButtonB(g_InputPlugin->Controllers(ControllerNumber).B_BUTTON, IDC_EDIT_BUTTON_B, IDC_BTN_BUTTON_B), + ButtonCUp(g_InputPlugin->Controllers(ControllerNumber).U_CBUTTON, IDC_EDIT_CBUTTON_UP, IDC_BTN_CBUTTON_UP), + ButtonCDown(g_InputPlugin->Controllers(ControllerNumber).D_CBUTTON, IDC_EDIT_CBUTTON_DOWN, IDC_BTN_CBUTTON_DOWN), + ButtonCLeft(g_InputPlugin->Controllers(ControllerNumber).L_CBUTTON, IDC_EDIT_CBUTTON_LEFT, IDC_BTN_CBUTTON_LEFT), + ButtonCRight(g_InputPlugin->Controllers(ControllerNumber).R_CBUTTON, IDC_EDIT_CBUTTON_RIGHT, IDC_BTN_CBUTTON_RIGHT) { m_Title = stdstr_f("Player %d", ControllerNumber + 1).ToUTF16(); SetTitle(m_Title.c_str()); - m_ControllerNumber = ControllerNumber; } BOOL CControllerSettings::OnInitDialog(CWindow /*wndFocus*/, LPARAM /*lInitParam*/) { m_ControllerImg.SubclassWindow(GetDlgItem(IDC_BMP_CONTROLLER)); m_ControllerImg.SetBitmap(MAKEINTRESOURCE(IDB_CONTROLLER)); + ButtonUDPad.SubclassWindow(m_hWnd); + ButtonDDPad.SubclassWindow(m_hWnd); + ButtonLDPad.SubclassWindow(m_hWnd); + ButtonRDPad.SubclassWindow(m_hWnd); + ButtonA.SubclassWindow(m_hWnd); + ButtonB.SubclassWindow(m_hWnd); + ButtonCUp.SubclassWindow(m_hWnd); + ButtonCDown.SubclassWindow(m_hWnd); + ButtonCLeft.SubclassWindow(m_hWnd); + ButtonCRight.SubclassWindow(m_hWnd); 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); +} + class CInputConfigUI: public CPropertySheetImpl { @@ -55,7 +95,7 @@ public: void OnSheetInitialized(); private: - CControllerSettings m_pgController[4]; + CControllerSettings m_pgController0, m_pgController1, m_pgController2, m_pgController3; }; void ConfigInput(void * hParent) @@ -63,14 +103,17 @@ void ConfigInput(void * hParent) CInputConfigUI().DoModal((HWND)hParent); } -CInputConfigUI::CInputConfigUI() +CInputConfigUI::CInputConfigUI() : + m_pgController0(0), + m_pgController1(1), + m_pgController2(2), + m_pgController3(3) { m_psh.pszCaption = L"Configure Input"; - for (size_t i = 0, n = sizeof(m_pgController) / sizeof(m_pgController[0]); i < n; i++) - { - m_pgController[i].SetControllerNumber(i); - AddPage(&m_pgController[i].m_psp); - } + AddPage(&m_pgController0.m_psp); + AddPage(&m_pgController1.m_psp); + AddPage(&m_pgController2.m_psp); + AddPage(&m_pgController3.m_psp); } CInputConfigUI::~CInputConfigUI() diff --git a/Source/Project64-input/InputMain.cpp b/Source/Project64-input/InputMain.cpp index a48d62d24..f8cdf6862 100644 --- a/Source/Project64-input/InputMain.cpp +++ b/Source/Project64-input/InputMain.cpp @@ -11,6 +11,7 @@ #include "ControllerSpec1.1.h" #include "InputConfigUI.h" #include "Version.h" +#include "CProject64Input.h" #include /****************************************************************** @@ -121,8 +122,12 @@ EXPORT void CALL GetKeys(int32_t /*Control*/, BUTTONS * /*Keys*/) the emulator to know how to handle each controller. output: none *******************************************************************/ -EXPORT void CALL InitiateControllers(CONTROL_INFO * /*ControlInfo*/) +EXPORT void CALL InitiateControllers(CONTROL_INFO * ControlInfo) { + if (g_InputPlugin != nullptr) + { + g_InputPlugin->InitiateControllers(ControlInfo); + } } /****************************************************************** @@ -185,4 +190,20 @@ EXPORT void CALL WM_KeyUp(uint32_t /*wParam*/, uint32_t /*lParam*/) EXPORT void CALL PluginLoaded(void) { +} + +#include + +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; } \ No newline at end of file diff --git a/Source/Project64-input/N64Controller.h b/Source/Project64-input/N64Controller.h new file mode 100644 index 000000000..4aa560295 --- /dev/null +++ b/Source/Project64-input/N64Controller.h @@ -0,0 +1,20 @@ +#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; +} N64CONTROLLER; diff --git a/Source/Project64-input/Project64-input.vcxproj b/Source/Project64-input/Project64-input.vcxproj index cd1455d8d..69b3e27eb 100644 --- a/Source/Project64-input/Project64-input.vcxproj +++ b/Source/Project64-input/Project64-input.vcxproj @@ -45,17 +45,35 @@ "$(SolutionDir)Source\Script\UpdateVersion.cmd" "$(Configuration)" "$(Platform)" "$(SolutionDir)Source\Project64-input\Version.h.in" "$(SolutionDir)Source\Project64-input\Version.h" + + dinput8.lib;dxguid.lib;%(AdditionalDependencies) + $(Root)Source\3rdParty\directx\lib;%(AdditionalLibraryDirectories) + false + + + dinput8.lib;dxguid.lib;%(AdditionalDependencies) + $(Root)Source\3rdParty\directx\lib;%(AdditionalLibraryDirectories) + false + + + + + + + + + diff --git a/Source/Project64-input/Project64-input.vcxproj.filters b/Source/Project64-input/Project64-input.vcxproj.filters index a54fc15c4..a064bf712 100644 --- a/Source/Project64-input/Project64-input.vcxproj.filters +++ b/Source/Project64-input/Project64-input.vcxproj.filters @@ -24,6 +24,15 @@ Source Files + + Source Files + + + Source Files + + + Source Files + @@ -41,6 +50,21 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + diff --git a/Source/Project64-input/Version.h.in b/Source/Project64-input/Version.h.in index e26272109..14087d707 100644 --- a/Source/Project64-input/Version.h.in +++ b/Source/Project64-input/Version.h.in @@ -11,8 +11,8 @@ #define STRINGIZE2(s) #s #define STRINGIZE(s) STRINGIZE2(s) -#define VERSION_MAJOR 1 -#define VERSION_MINOR 0 +#define VERSION_MAJOR 0 +#define VERSION_MINOR 1 #define VERSION_REVISION 0 #define VERSION_BUILD 9999 #define GIT_VERSION "" diff --git a/Source/Project64-input/wtl-ScanButton.cpp b/Source/Project64-input/wtl-ScanButton.cpp new file mode 100644 index 000000000..447aab039 --- /dev/null +++ b/Source/Project64-input/wtl-ScanButton.cpp @@ -0,0 +1,156 @@ +#include "wtl-ScanButton.h" +#include "CProject64Input.h" +#include +#include + +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) +{ +} + +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::DisplayButton(void) +{ + m_DisplayCtrl.SetWindowText(g_InputPlugin->ButtonAssignment(m_Button).c_str()); +} + +void CScanButton::OnScan(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; + if (g_InputPlugin) + { + CDirectInput::ScanResult Result = g_InputPlugin->ScanDevices(m_Button); + if (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"); + + m_Overlay.DestroyWindow(); + m_Overlay = NULL; + + g_InputPlugin->EndScanDevices(); + m_DisplayCtrl.Invalidate(); + } + } +} + +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); + 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.ShowWindow(SW_SHOWNOACTIVATE); +} + +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->OnScan(); + } + } + 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_PAINT) + { + PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + EndPaint(hwnd, &ps); + return 0; + } + return DefWindowProc(hwnd, msg, wParam, lParam); +} diff --git a/Source/Project64-input/wtl-ScanButton.h b/Source/Project64-input/wtl-ScanButton.h new file mode 100644 index 000000000..81789f0f5 --- /dev/null +++ b/Source/Project64-input/wtl-ScanButton.h @@ -0,0 +1,37 @@ +#pragma once +#include "wtl.h" +#include "Button.h" + +class CScanButton +{ + enum + { + DETECT_KEY_TIMER = 1 + }; + +public: + CScanButton(BUTTON & Button, int DisplayCtrlId, int ScanBtnId); + + void SubclassWindow(CWindow Wnd); + +private: + CScanButton(void); + CScanButton(const CScanButton&); + CScanButton& operator=(const CScanButton&); + + void DisplayButton(void); + void OnScan(void); + 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; +}; \ No newline at end of file