project64/Source/Project64-input/wtl-ScanButton.cpp

203 lines
5.9 KiB
C++

#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.SetWindowLongPtr(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, nullptr);
MakeOverlay();
}
void CScanButton::OnTimer(UINT_PTR nIDEvent)
{
if (nIDEvent == DETECT_KEY_TIMER)
{
BUTTON EmptyButton = { 0 };
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_ScanBtn.KillTimer(DETECT_KEY_TIMER);
if (m_ChangeCallback != nullptr)
{
m_ChangeCallback(m_ChangeCallbackData, Button);
}
m_Button = Button;
}
if (Result == CDirectInput::SCAN_ESCAPE && (EmptyButton.Offset != m_Button.Offset || EmptyButton.AxisID != m_Button.AxisID || EmptyButton.BtnType != m_Button.BtnType))
{
m_ScanBtn.KillTimer(DETECT_KEY_TIMER);
if (m_ChangeCallback != nullptr)
{
m_ChangeCallback(m_ChangeCallbackData, EmptyButton);
}
m_Button = EmptyButton;
}
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
{
if (m_ChangeCallback != nullptr)
{
m_ChangeCallback(m_ChangeCallbackData, EmptyButton);
}
m_Button = EmptyButton;
DisplayButton();
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 != nullptr)
{
m_Overlay.DestroyWindow();
m_Overlay = nullptr;
}
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(), nullptr);
if (m_Overlay == nullptr)
{
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);
}