Merge pull request #1721 from RadWolfie/gui-input-fix-detect

Fix Bind Input Detection
This commit is contained in:
ergo720 2019-09-14 11:16:40 +02:00 committed by GitHub
commit 7c300c14ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 11 deletions

View File

@ -59,6 +59,7 @@ void InputWindow::Initialize(HWND hwnd, int port_num, int dev_type)
m_max_num_buttons = dev_num_buttons[dev_type];
m_port_num = port_num;
m_bHasChanges = false;
m_bIsBinding = false;
// Set window icon
SetClassLong(m_hwnd_window, GCL_HICON, (LONG)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_CXBX)));
@ -170,17 +171,18 @@ void InputWindow::UpdateDeviceList()
// DetectInput is derived from InputReference::Detect() in ControlReference.cpp of Dolphin emulator
// https://github.com/dolphin-emu/dolphin
InputDevice::Input* InputWindow::DetectInput(InputDevice* const Device, int ms)
InputDevice::Input* InputWindow::DetectInput(InputDevice* const Device, Button* const xbox_button, int ms)
{
using namespace std::chrono;
// The intent of the initial_states vector is to detect inputs that were pressed already when this function was called.
// Without it, the initial mouse click used to select a gui button is very likely to be registered as valid input and bound
Device->UpdateInput(); // Requirement to get current state than previous state. testcase: enter key / cursor
std::vector<InputDevice::Input*>::const_iterator i = Device->GetInputs().begin(),
e = Device->GetInputs().end(), b = i;
e = Device->GetInputs().end(), b = i, s = e;
std::vector<bool> initial_states(Device->GetInputs().size());
for (std::vector<bool>::iterator state = initial_states.begin(); i != e; i++) {
*state++ = ((*i)->GetState() > (1 - INPUT_DETECT_THRESHOLD));
*state++ = ((*i)->GetState() > INPUT_DETECT_THRESHOLD);
}
auto now = system_clock::now();
@ -190,15 +192,23 @@ InputDevice::Input* InputWindow::DetectInput(InputDevice* const Device, int ms)
Device->UpdateInput();
std::vector<bool>::iterator state = initial_states.begin();
for (; i != e; i++, state++) {
if ((*i)->IsDetectable() && (*i)->GetState() > INPUT_DETECT_THRESHOLD) {
if (*state == false) {
// input was not initially pressed or it was but released afterwards
ControlState curState = (*i)->GetState();
if (*state == true && (*i)->IsDetectable() && curState < INPUT_DETECT_THRESHOLD) {
// If selected input is released, then return input.
if (s == i) {
return *i;
}
}
else if ((*i)->GetState() < (1 - INPUT_DETECT_THRESHOLD)) {
*state = false;
}
// Check for any input pressed.
else if (*state == false && curState > INPUT_DETECT_THRESHOLD) {
// If the input bind is empty, preseve pressed input until it is release by user.
if (s == e) {
xbox_button->UpdateText(std::string("["+ (*i)->GetName()+"]").c_str());
s = i;
}
*state = true;
}
}
std::this_thread::sleep_for(milliseconds(10));
now += milliseconds(10);
@ -212,6 +222,13 @@ void InputWindow::BindButton(int ControlID)
{
auto dev = g_InputDeviceManager.FindDevice(m_host_dev);
if (dev != nullptr) {
// Check if binding thread is still active
// testcase: spacebar and enter keys; without this fix will cause repeat binding result.
if (m_bIsBinding) {
return;
}
m_bIsBinding = true;
// Don't block the message processing loop
std::thread([this, dev, ControlID]() {
EnableWindow(m_hwnd_window, FALSE);
@ -219,7 +236,7 @@ void InputWindow::BindButton(int ControlID)
Button* xbox_button = m_DeviceConfig->FindButtonById(ControlID);
xbox_button->GetText(current_text, sizeof(current_text));
xbox_button->UpdateText("...");
std::future<InputDevice::Input*> fut = std::async(std::launch::async, &InputWindow::DetectInput, this, dev.get(), INPUT_TIMEOUT);
std::future<InputDevice::Input*> fut = std::async(std::launch::async, &InputWindow::DetectInput, this, dev.get(), xbox_button, INPUT_TIMEOUT);
InputDevice::Input* dev_button = fut.get();
if (dev_button) {
xbox_button->UpdateText(dev_button->GetName().c_str());
@ -228,8 +245,9 @@ void InputWindow::BindButton(int ControlID)
else {
xbox_button->UpdateText(current_text);
}
m_bIsBinding = false;
EnableWindow(m_hwnd_window, TRUE);
}).detach();
}).detach();
}
}

View File

@ -64,7 +64,7 @@ public:
private:
typedef std::vector<Settings::s_input_profiles>::iterator ProfileIt;
InputDevice::Input* DetectInput(InputDevice* const Device, int ms);
InputDevice::Input* DetectInput(InputDevice* const Device, Button* const xbox_button, int ms);
void DetectOutput(int ms);
ProfileIt FindProfile(std::string& name);
void LoadProfile(std::string& name);
@ -100,6 +100,8 @@ private:
std::string m_rumble;
// indicates if the current profile has unsaved changes
bool m_bHasChanges;
// prevent current input attempt to set the previous input at same time
std::atomic<bool> m_bIsBinding;
};
extern InputWindow* g_InputWindow;