Merge pull request #2222 from ergo720/rawinput
Add controller hotplug support
This commit is contained in:
commit
8087b157e5
|
@ -65,6 +65,7 @@ file (GLOB CXBXR_HEADER_COMMON
|
|||
"${CXBXR_ROOT_DIR}/src/common/input/InputManager.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/SdlJoystick.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/XInputPad.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/RawDevice.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/IPCHybrid.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Logging.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/ReservedMemory.h"
|
||||
|
@ -226,6 +227,7 @@ file (GLOB CXBXR_SOURCE_COMMON
|
|||
"${CXBXR_ROOT_DIR}/src/common/input/InputManager.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/SdlJoystick.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/XInputPad.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/RawDevice.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Logging.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Settings.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Timer.cpp"
|
||||
|
|
|
@ -80,6 +80,7 @@ const char* g_EnumModules2String[to_underlying(CXBXR_MODULE::MAX)] = {
|
|||
"DSSTREAM",
|
||||
"DS3DCALC",
|
||||
"XMO ",
|
||||
"RINP ",
|
||||
"KRNL ",
|
||||
"LOG ",
|
||||
"XBOX ",
|
||||
|
|
|
@ -88,6 +88,7 @@ typedef enum class _CXBXR_MODULE: unsigned int {
|
|||
DSSTREAM,
|
||||
DS3DCALC,
|
||||
XMO,
|
||||
RINP,
|
||||
// kernel
|
||||
KRNL,
|
||||
LOG,
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <core\kernel\exports\xboxkrnl.h> // For PKINTERRUPT, etc.
|
||||
#include "SdlJoystick.h"
|
||||
#include "XInputPad.h"
|
||||
#include "RawDevice.h"
|
||||
#include "DInputKeyboardMouse.h"
|
||||
#include "InputManager.h"
|
||||
#include "..\devices\usb\XidGamepad.h"
|
||||
|
@ -88,16 +89,18 @@ void InputDeviceManager::Initialize(bool is_gui, HWND hwnd)
|
|||
}
|
||||
|
||||
XInput::Init(m_Mtx);
|
||||
RawInput::Init(m_Mtx, is_gui, m_hwnd);
|
||||
Sdl::Init(m_Mtx, m_Cv, is_gui);
|
||||
});
|
||||
|
||||
m_Cv.wait(lck, []() {
|
||||
return (Sdl::SdlInitStatus != Sdl::SDL_NOT_INIT) &&
|
||||
(XInput::XInputInitStatus != XInput::XINPUT_NOT_INIT);
|
||||
(XInput::XInputInitStatus != XInput::XINPUT_NOT_INIT) &&
|
||||
(RawInput::RawInputInitStatus != RawInput::RAWINPUT_NOT_INIT);
|
||||
});
|
||||
lck.unlock();
|
||||
|
||||
if (Sdl::SdlInitStatus < 0 || XInput::XInputInitStatus < 0) {
|
||||
if (Sdl::SdlInitStatus < 0 || XInput::XInputInitStatus < 0 || RawInput::RawInputInitStatus < 0) {
|
||||
CxbxKrnlCleanup("Failed to initialize input subsystem! Consult debug log for more information");
|
||||
}
|
||||
|
||||
|
@ -110,6 +113,8 @@ void InputDeviceManager::Initialize(bool is_gui, HWND hwnd)
|
|||
UpdateDevices(PORT_3, false);
|
||||
UpdateDevices(PORT_4, false);
|
||||
}
|
||||
|
||||
RawInput::IgnoreHotplug = false;
|
||||
}
|
||||
|
||||
void InputDeviceManager::Shutdown()
|
||||
|
@ -128,6 +133,7 @@ void InputDeviceManager::Shutdown()
|
|||
m_Devices.clear();
|
||||
|
||||
XInput::DeInit();
|
||||
RawInput::DeInit();
|
||||
Sdl::DeInit(m_PollingThread);
|
||||
}
|
||||
|
||||
|
@ -723,3 +729,40 @@ void InputDeviceManager::UpdateOpt(bool is_gui)
|
|||
DInput::mo_wheel_range_neg = -(g_Settings->m_input_general.MoWheelRange);
|
||||
}
|
||||
}
|
||||
|
||||
void InputDeviceManager::HotplugHandler(bool is_sdl)
|
||||
{
|
||||
// RawInput will start to send WM_INPUT_DEVICE_CHANGE as soon as RegisterRawInputDevices succeeds, but at that point, the input manager
|
||||
// is still not completely initialized, so we ignore hotplug events during initialization
|
||||
if (m_bPendingShutdown || RawInput::IgnoreHotplug) {
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE1: sdl devices are monitored by sdl with the SDL_JOYDEVICEADDED and SDL_JOYDEVICEREMOVED messages,
|
||||
// and xinput devices are monitored by rawinput with the WM_INPUT_DEVICE_CHANGE message
|
||||
// NOTE2: sdl devices are already added/removed to/from m_Devices with the above events, so don't need to update m_Devices here again
|
||||
if (!is_sdl) {
|
||||
std::unique_lock<std::mutex> lck(m_Mtx);
|
||||
|
||||
auto it = std::remove_if(m_Devices.begin(), m_Devices.end(), [](const auto &Device) {
|
||||
if (StrStartsWith(Device->GetAPI(), "XInput")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (it != m_Devices.end()) {
|
||||
m_Devices.erase(it, m_Devices.end());
|
||||
}
|
||||
|
||||
lck.unlock();
|
||||
XInput::PopulateDevices();
|
||||
}
|
||||
|
||||
for (int port = PORT_1; port <= PORT_4; ++port) {
|
||||
int type;
|
||||
g_EmuShared->GetInputDevTypeSettings(&type, port);
|
||||
if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) {
|
||||
BindHostDevice(port, port, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,6 +148,8 @@ public:
|
|||
void UpdateDevices(int port, bool ack);
|
||||
// update input options
|
||||
void UpdateOpt(bool is_gui);
|
||||
// device hotplug event handler
|
||||
void HotplugHandler(bool is_sdl);
|
||||
|
||||
|
||||
private:
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2021 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#define LOG_PREFIX CXBXR_MODULE::RINP
|
||||
|
||||
#include "RawDevice.h"
|
||||
#include "Logging.h"
|
||||
#include <array>
|
||||
|
||||
// NOTE: we don't implement host input devices controlled by rawinput, we only use the api to detect device changes for xinput
|
||||
|
||||
namespace RawInput
|
||||
{
|
||||
int RawInputInitStatus = RAWINPUT_NOT_INIT;
|
||||
bool IgnoreHotplug = true;
|
||||
|
||||
void Init(std::mutex &Mtx, bool is_gui, HWND hwnd)
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(Mtx);
|
||||
|
||||
if (is_gui) {
|
||||
// We don't need to monitor xinput device changes from the gui, because there we have the refresh button to detect changes
|
||||
RawInputInitStatus = RAWINPUT_INIT_SUCCESS;
|
||||
return;
|
||||
}
|
||||
|
||||
std::array<RAWINPUTDEVICE, 3> devices;
|
||||
// joystick devices
|
||||
devices[0].usUsagePage = 0x01;
|
||||
devices[0].usUsage = 0x04;
|
||||
devices[0].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
|
||||
devices[0].hwndTarget = hwnd;
|
||||
// gamepad devices
|
||||
devices[1].usUsagePage = 0x01;
|
||||
devices[1].usUsage = 0x05;
|
||||
devices[1].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
|
||||
devices[1].hwndTarget = hwnd;
|
||||
// multi axis controller devices
|
||||
devices[2].usUsagePage = 0x01;
|
||||
devices[2].usUsage = 0x08;
|
||||
devices[2].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
|
||||
devices[2].hwndTarget = hwnd;
|
||||
|
||||
if (!RegisterRawInputDevices(devices.data(), static_cast<UINT>(devices.size()),
|
||||
static_cast<UINT>(sizeof(decltype(devices)::value_type))))
|
||||
{
|
||||
EmuLog(LOG_LEVEL::ERROR2, "RegisterRawInputDevices failed: %i", GetLastError());
|
||||
RawInputInitStatus = RAWINPUT_INIT_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
RawInputInitStatus = RAWINPUT_INIT_SUCCESS;
|
||||
}
|
||||
|
||||
void DeInit()
|
||||
{
|
||||
RawInputInitStatus = RAWINPUT_NOT_INIT;
|
||||
IgnoreHotplug = true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2021 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Windows.h"
|
||||
#include <mutex>
|
||||
|
||||
|
||||
namespace RawInput
|
||||
{
|
||||
typedef enum _RAWINPUT_INIT_STATUS : int
|
||||
{
|
||||
RAWINPUT_NOT_INIT = -2,
|
||||
RAWINPUT_INIT_ERROR,
|
||||
RAWINPUT_INIT_SUCCESS,
|
||||
}
|
||||
RAWINPUT_INIT_STATUS;
|
||||
|
||||
extern int RawInputInitStatus;
|
||||
extern bool IgnoreHotplug;
|
||||
|
||||
// initialize RawInput
|
||||
void Init(std::mutex &Mtx, bool is_gui, HWND hwnd);
|
||||
// shutdown RawInput
|
||||
void DeInit();
|
||||
}
|
|
@ -104,6 +104,7 @@ namespace Sdl
|
|||
{
|
||||
if (Event.type == SDL_JOYDEVICEADDED) {
|
||||
OpenSdlDevice(Event.jdevice.which);
|
||||
g_InputDeviceManager.HotplugHandler(true);
|
||||
}
|
||||
else if (Event.type == SDL_JOYDEVICEREMOVED) {
|
||||
CloseSdlDevice(Event.jdevice.which);
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#include "core\kernel\common\strings.hpp" // For uem_str
|
||||
#include "common\input\SdlJoystick.h"
|
||||
#include "common\input\DInputKeyboardMouse.h"
|
||||
#include "common\input\InputManager.h"
|
||||
#include "common/util/strConverter.hpp" // for utf8_to_utf16
|
||||
#include "VertexShaderSource.h"
|
||||
|
||||
|
@ -1923,6 +1924,17 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar
|
|||
}
|
||||
break;
|
||||
|
||||
case WM_INPUT_DEVICE_CHANGE:
|
||||
{
|
||||
// sent by rawinput when it detects changes for the registered device types
|
||||
|
||||
if (wParam == GIDC_ARRIVAL) {
|
||||
g_InputDeviceManager.HotplugHandler(false);
|
||||
}
|
||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_SYSKEYDOWN:
|
||||
{
|
||||
if(wParam == VK_RETURN)
|
||||
|
|
|
@ -79,6 +79,7 @@ static int g_DlgIndexes[] = {
|
|||
IDC_LOG_DSSTREAM,
|
||||
IDC_LOG_DS3DCALC,
|
||||
IDC_LOG_XMO,
|
||||
IDC_LOG_RINP,
|
||||
// Kernel
|
||||
IDC_LOG_KRNL,
|
||||
IDC_LOG_LOG,
|
||||
|
|
|
@ -496,6 +496,7 @@ BEGIN
|
|||
PUSHBUTTON "Cancel",IDC_LOG_CANCEL,161,333,40,14,BS_FLAT
|
||||
PUSHBUTTON "Accept",IDC_LOG_ACCEPT,206,333,40,14,BS_FLAT
|
||||
CONTROL "VSHCACHE",IDC_LOG_VSHCACHE,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,68,140,53,10
|
||||
CONTROL "RINP",IDC_LOG_RINP,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,202,195,32,10
|
||||
END
|
||||
|
||||
IDD_ABOUT DIALOGEX 0, 0, 310, 177
|
||||
|
|
|
@ -92,6 +92,7 @@
|
|||
#define IDC_LOG_DS3DCALC 960
|
||||
#define IDC_LOG_XMO 961
|
||||
#define IDC_LOG_VSHCACHE 962
|
||||
#define IDC_LOG_RINP 963
|
||||
#define IDC_SET_MOTOR 999
|
||||
#define IDC_SET_X 1000
|
||||
#define IDC_SET_Y 1001
|
||||
|
|
Loading…
Reference in New Issue