mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 21:37:52 -07:00
WGInput: implement error handling
This commit is contained in:
parent
6bc8ab7001
commit
cd407abe34
@ -7,10 +7,13 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#include <fmt/format.h>
|
// For CoGetApartmentType
|
||||||
|
#include <objbase.h>
|
||||||
|
#pragma comment(lib, "ole32")
|
||||||
|
|
||||||
// TODO winrt translates com failures to c++ exceptions, so we must use try/catch in this file to
|
// NOTE: winrt translates com failures to c++ exceptions, so we must use try/catch in this file to
|
||||||
// prevent possible errors from terminating Dolphin.
|
// prevent possible errors from escaping and terminating Dolphin.
|
||||||
|
#include <winrt/base.h>
|
||||||
#include <winrt/windows.devices.haptics.h>
|
#include <winrt/windows.devices.haptics.h>
|
||||||
#include <winrt/windows.devices.power.h>
|
#include <winrt/windows.devices.power.h>
|
||||||
#include <winrt/windows.foundation.collections.h>
|
#include <winrt/windows.foundation.collections.h>
|
||||||
@ -18,6 +21,8 @@
|
|||||||
#include <winrt/windows.system.power.h>
|
#include <winrt/windows.system.power.h>
|
||||||
#pragma comment(lib, "windowsapp")
|
#pragma comment(lib, "windowsapp")
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||||
@ -108,15 +113,24 @@ public:
|
|||||||
|
|
||||||
if (use_raw_controller_axes)
|
if (use_raw_controller_axes)
|
||||||
{
|
{
|
||||||
// Axes:
|
try
|
||||||
m_axes.resize(m_raw_controller.AxisCount());
|
|
||||||
|
|
||||||
u32 i = 0;
|
|
||||||
for (auto& axis : m_axes)
|
|
||||||
{
|
{
|
||||||
// AddAnalogInputs adds additional "FullAnalogSurface" Inputs.
|
// Axes:
|
||||||
AddAnalogInputs(new IndexedAxis(&axis, 0.5, +0.5, i), new IndexedAxis(&axis, 0.5, -0.5, i));
|
m_axes.resize(m_raw_controller.AxisCount());
|
||||||
++i;
|
|
||||||
|
u32 i = 0;
|
||||||
|
for (auto& axis : m_axes)
|
||||||
|
{
|
||||||
|
// AddAnalogInputs adds additional "FullAnalogSurface" Inputs.
|
||||||
|
AddAnalogInputs(new IndexedAxis(&axis, 0.5, +0.5, i),
|
||||||
|
new IndexedAxis(&axis, 0.5, -0.5, i));
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (winrt::hresult_error)
|
||||||
|
{
|
||||||
|
// If AxisCount failed, m_axes will remain zero-sized; nothing to do.
|
||||||
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "WGInput: Error populating axes");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,26 +142,37 @@ public:
|
|||||||
// Switches (Hats):
|
// Switches (Hats):
|
||||||
if (use_raw_controller_switches)
|
if (use_raw_controller_switches)
|
||||||
{
|
{
|
||||||
m_switches.resize(m_raw_controller.SwitchCount());
|
try
|
||||||
|
|
||||||
u32 i = 0;
|
|
||||||
for (auto& swtch : m_switches)
|
|
||||||
{
|
{
|
||||||
using gcsp = WGI::GameControllerSwitchPosition;
|
m_switches.resize(m_raw_controller.SwitchCount());
|
||||||
|
// Accumulate switch kinds first, to ensure no inputs are added if there is any error.
|
||||||
|
std::vector<WGI::GameControllerSwitchKind> switch_kinds;
|
||||||
|
for (u32 i = 0; i < m_switches.size(); i++)
|
||||||
|
switch_kinds.push_back(m_raw_controller.GetSwitchKind(i));
|
||||||
|
|
||||||
WGI::GameControllerSwitchKind switch_kind = m_raw_controller.GetSwitchKind(i);
|
u32 i = 0;
|
||||||
|
for (auto& swtch : m_switches)
|
||||||
AddInput(new IndexedSwitch(&swtch, i, gcsp::Up));
|
|
||||||
AddInput(new IndexedSwitch(&swtch, i, gcsp::Down));
|
|
||||||
|
|
||||||
if (switch_kind != WGI::GameControllerSwitchKind::TwoWay)
|
|
||||||
{
|
{
|
||||||
// If it's not a "two-way" switch (up/down only) then add the left/right inputs.
|
using gcsp = WGI::GameControllerSwitchPosition;
|
||||||
AddInput(new IndexedSwitch(&swtch, i, gcsp::Left));
|
|
||||||
AddInput(new IndexedSwitch(&swtch, i, gcsp::Right));
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
AddInput(new IndexedSwitch(&swtch, i, gcsp::Up));
|
||||||
|
AddInput(new IndexedSwitch(&swtch, i, gcsp::Down));
|
||||||
|
|
||||||
|
if (switch_kinds[i] != WGI::GameControllerSwitchKind::TwoWay)
|
||||||
|
{
|
||||||
|
// If it's not a "two-way" switch (up/down only) then add the left/right inputs.
|
||||||
|
AddInput(new IndexedSwitch(&swtch, i, gcsp::Left));
|
||||||
|
AddInput(new IndexedSwitch(&swtch, i, gcsp::Right));
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (winrt::hresult_error)
|
||||||
|
{
|
||||||
|
// Safe as no inputs will have been added.
|
||||||
|
m_switches.clear();
|
||||||
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "WGInput: Error populating switches");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,10 +369,17 @@ private:
|
|||||||
|
|
||||||
m_current_state = state;
|
m_current_state = state;
|
||||||
|
|
||||||
if (state)
|
try
|
||||||
m_haptics.SendHapticFeedback(m_feedback, state);
|
{
|
||||||
else
|
if (state)
|
||||||
m_haptics.StopFeedback();
|
m_haptics.SendHapticFeedback(m_feedback, state);
|
||||||
|
else
|
||||||
|
m_haptics.StopFeedback();
|
||||||
|
}
|
||||||
|
catch (winrt::hresult_error)
|
||||||
|
{
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -380,20 +412,38 @@ private:
|
|||||||
|
|
||||||
void PopulateButtons()
|
void PopulateButtons()
|
||||||
{
|
{
|
||||||
// Using RawGameController for buttons because it gives us a nice array instead of a bitmask.
|
try
|
||||||
m_buttons.resize(m_raw_controller.ButtonCount());
|
|
||||||
|
|
||||||
u32 i = 0;
|
|
||||||
for (const auto& button : m_buttons)
|
|
||||||
{
|
{
|
||||||
const WGI::GameControllerButtonLabel lbl = m_raw_controller.GetButtonLabel(i);
|
// Using RawGameController for buttons because it gives us a nice array instead of a bitmask.
|
||||||
const int32_t button_name_idx = static_cast<int32_t>(lbl);
|
m_buttons.resize(m_raw_controller.ButtonCount());
|
||||||
if (lbl != WGI::GameControllerButtonLabel::None && button_name_idx < wgi_button_names.size())
|
|
||||||
AddInput(new NamedButton(&button, wgi_button_names[button_name_idx]));
|
|
||||||
else
|
|
||||||
AddInput(new IndexedButton(&button, i));
|
|
||||||
|
|
||||||
++i;
|
u32 i = 0;
|
||||||
|
for (const auto& button : m_buttons)
|
||||||
|
{
|
||||||
|
WGI::GameControllerButtonLabel lbl{WGI::GameControllerButtonLabel::None};
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lbl = m_raw_controller.GetButtonLabel(i);
|
||||||
|
}
|
||||||
|
catch (winrt::hresult_error)
|
||||||
|
{
|
||||||
|
lbl = WGI::GameControllerButtonLabel::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int32_t button_name_idx = static_cast<int32_t>(lbl);
|
||||||
|
if (lbl != WGI::GameControllerButtonLabel::None &&
|
||||||
|
button_name_idx < wgi_button_names.size())
|
||||||
|
AddInput(new NamedButton(&button, wgi_button_names[button_name_idx]));
|
||||||
|
else
|
||||||
|
AddInput(new IndexedButton(&button, i));
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (winrt::hresult_error)
|
||||||
|
{
|
||||||
|
// If ButtonCount failed, m_buttons will be zero-sized.
|
||||||
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "WGInput: Error populating buttons");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,25 +455,33 @@ private:
|
|||||||
{Haptics::KnownSimpleHapticsControllerWaveforms::RumbleContinuous(), "Rumble"},
|
{Haptics::KnownSimpleHapticsControllerWaveforms::RumbleContinuous(), "Rumble"},
|
||||||
};
|
};
|
||||||
|
|
||||||
// SimpleHapticsControllers is available from Windows 1709.
|
try
|
||||||
u32 haptics_index = 0;
|
|
||||||
for (auto haptics_controller : m_raw_controller.SimpleHapticsControllers())
|
|
||||||
{
|
{
|
||||||
for (Haptics::SimpleHapticsControllerFeedback feedback :
|
// SimpleHapticsControllers is available from Windows 1709.
|
||||||
haptics_controller.SupportedFeedback())
|
u32 haptics_index = 0;
|
||||||
|
for (auto haptics_controller : m_raw_controller.SimpleHapticsControllers())
|
||||||
{
|
{
|
||||||
const uint16_t waveform = feedback.Waveform();
|
for (Haptics::SimpleHapticsControllerFeedback feedback :
|
||||||
auto waveform_name_it = waveform_name_map.find(waveform);
|
haptics_controller.SupportedFeedback())
|
||||||
if (waveform_name_it == waveform_name_map.end())
|
|
||||||
{
|
{
|
||||||
WARN_LOG_FMT(CONTROLLERINTERFACE,
|
const uint16_t waveform = feedback.Waveform();
|
||||||
"WGInput: Unhandled haptics feedback waveform: 0x{:04x}.", waveform);
|
auto waveform_name_it = waveform_name_map.find(waveform);
|
||||||
continue;
|
if (waveform_name_it == waveform_name_map.end())
|
||||||
|
{
|
||||||
|
WARN_LOG_FMT(CONTROLLERINTERFACE,
|
||||||
|
"WGInput: Unhandled haptics feedback waveform: 0x{:04x}.", waveform);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
AddOutput(new NamedFeedback(haptics_controller, feedback, haptics_index,
|
||||||
|
waveform_name_it->second));
|
||||||
}
|
}
|
||||||
AddOutput(new NamedFeedback(haptics_controller, feedback, haptics_index,
|
++haptics_index;
|
||||||
waveform_name_it->second));
|
|
||||||
}
|
}
|
||||||
++haptics_index;
|
}
|
||||||
|
catch (winrt::hresult_error)
|
||||||
|
{
|
||||||
|
// Don't need to cleanup any state. It's OK if some outputs were added.
|
||||||
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "WGInput: Error populating haptics");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,54 +499,89 @@ private:
|
|||||||
auto buttons =
|
auto buttons =
|
||||||
winrt::array_view<bool>(reinterpret_cast<winrt::array_view<bool>::pointer>(&m_buttons[0]),
|
winrt::array_view<bool>(reinterpret_cast<winrt::array_view<bool>::pointer>(&m_buttons[0]),
|
||||||
static_cast<winrt::array_view<bool>::size_type>(m_buttons.size()));
|
static_cast<winrt::array_view<bool>::size_type>(m_buttons.size()));
|
||||||
m_raw_controller.GetCurrentReading(buttons, m_switches, m_axes);
|
try
|
||||||
|
{
|
||||||
|
m_raw_controller.GetCurrentReading(buttons, m_switches, m_axes);
|
||||||
|
}
|
||||||
|
catch (winrt::hresult_error error)
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(CONTROLLERINTERFACE,
|
||||||
|
"WGInput: IRawGameController::GetCurrentReading failed: {:x}", error.code());
|
||||||
|
}
|
||||||
|
|
||||||
// IGamepad:
|
// IGamepad:
|
||||||
if (m_gamepad)
|
if (m_gamepad)
|
||||||
m_gamepad_reading = m_gamepad.GetCurrentReading();
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_gamepad_reading = m_gamepad.GetCurrentReading();
|
||||||
|
}
|
||||||
|
catch (winrt::hresult_error error)
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "WGInput: IGamepad::GetCurrentReading failed: {:x}",
|
||||||
|
error.code());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// IGameControllerBatteryInfo:
|
// IGameControllerBatteryInfo:
|
||||||
if (!UpdateBatteryLevel())
|
if (!UpdateBatteryLevel())
|
||||||
DEBUG_LOG_FMT(CONTROLLERINTERFACE, "WGInput: UpdateBatteryLevel failed.");
|
DEBUG_LOG_FMT(CONTROLLERINTERFACE, "WGInput: UpdateBatteryLevel failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateMotors() { m_gamepad.Vibration(m_state_out); }
|
void UpdateMotors()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_gamepad.Vibration(m_state_out);
|
||||||
|
}
|
||||||
|
catch (winrt::hresult_error)
|
||||||
|
{
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool UpdateBatteryLevel()
|
bool UpdateBatteryLevel()
|
||||||
{
|
{
|
||||||
const winrt::Windows::Devices::Power::BatteryReport report =
|
try
|
||||||
m_raw_controller.TryGetBatteryReport();
|
|
||||||
if (!report)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// TryGetBatteryReport causes a memleak of 0x58 bytes each time it is called, up to at
|
|
||||||
// least Windows 21H2. This is a big hack to "fix" the refcount.
|
|
||||||
auto report_ = *(uintptr_t***)&report;
|
|
||||||
auto rc = &report_[0x40 / 8][0x30 / 8];
|
|
||||||
if (*rc == 2)
|
|
||||||
(*rc)--;
|
|
||||||
|
|
||||||
using winrt::Windows::System::Power::BatteryStatus;
|
|
||||||
const BatteryStatus status = report.Status();
|
|
||||||
switch (status)
|
|
||||||
{
|
{
|
||||||
case BatteryStatus::NotPresent:
|
const winrt::Windows::Devices::Power::BatteryReport report =
|
||||||
m_battery_level = 0;
|
m_raw_controller.TryGetBatteryReport();
|
||||||
return true;
|
if (!report)
|
||||||
|
return false;
|
||||||
|
|
||||||
case BatteryStatus::Idle:
|
// TryGetBatteryReport causes a memleak of 0x58 bytes each time it is called, up to at
|
||||||
case BatteryStatus::Charging:
|
// least Windows 21H2. A hack to fix the memleak is recorded here for posterity.
|
||||||
m_battery_level = BATTERY_INPUT_MAX_VALUE;
|
// auto report_ = *(uintptr_t***)&report;
|
||||||
return true;
|
// auto rc = &report_[0x40 / 8][0x30 / 8];
|
||||||
|
// if (*rc == 2)
|
||||||
|
// (*rc)--;
|
||||||
|
|
||||||
default:
|
using winrt::Windows::System::Power::BatteryStatus;
|
||||||
break;
|
const BatteryStatus status = report.Status();
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case BatteryStatus::NotPresent:
|
||||||
|
m_battery_level = 0;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case BatteryStatus::Idle:
|
||||||
|
case BatteryStatus::Charging:
|
||||||
|
m_battery_level = BATTERY_INPUT_MAX_VALUE;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int32_t full_value = report.FullChargeCapacityInMilliwattHours().GetInt32();
|
||||||
|
const int32_t remaining_value = report.RemainingCapacityInMilliwattHours().GetInt32();
|
||||||
|
m_battery_level = BATTERY_INPUT_MAX_VALUE * remaining_value / full_value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (winrt::hresult_error)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int32_t full_value = report.FullChargeCapacityInMilliwattHours().GetInt32();
|
|
||||||
const int32_t remaining_value = report.RemainingCapacityInMilliwattHours().GetInt32();
|
|
||||||
m_battery_level = BATTERY_INPUT_MAX_VALUE * remaining_value / full_value;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string m_name;
|
const std::string m_name;
|
||||||
@ -508,26 +601,48 @@ private:
|
|||||||
static thread_local bool s_initialized_winrt;
|
static thread_local bool s_initialized_winrt;
|
||||||
static winrt::event_token s_event_added, s_event_removed;
|
static winrt::event_token s_event_added, s_event_removed;
|
||||||
|
|
||||||
|
static bool COMIsInitialized()
|
||||||
|
{
|
||||||
|
APTTYPE apt_type{};
|
||||||
|
APTTYPEQUALIFIER apt_qualifier{};
|
||||||
|
return CoGetApartmentType(&apt_type, &apt_qualifier) == S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static void AddDevice(const WGI::RawGameController& raw_game_controller)
|
static void AddDevice(const WGI::RawGameController& raw_game_controller)
|
||||||
{
|
{
|
||||||
// Get user-facing device name if available. Otherwise generate a name from vid/pid.
|
// Get user-facing device name if available. Otherwise generate a name from vid/pid.
|
||||||
auto device_name =
|
std::string device_name;
|
||||||
std::string(StripWhitespace(WStringToUTF8(raw_game_controller.DisplayName().c_str())));
|
try
|
||||||
if (device_name.empty())
|
|
||||||
{
|
{
|
||||||
const u16 vid = raw_game_controller.HardwareVendorId();
|
device_name = StripWhitespace(WStringToUTF8(raw_game_controller.DisplayName().c_str()));
|
||||||
const u16 pid = raw_game_controller.HardwareProductId();
|
if (device_name.empty())
|
||||||
device_name = fmt::format("Device_{:04x}:{:04x}", vid, pid);
|
{
|
||||||
|
const u16 vid = raw_game_controller.HardwareVendorId();
|
||||||
|
const u16 pid = raw_game_controller.HardwareProductId();
|
||||||
|
device_name = fmt::format("Device_{:04x}:{:04x}", vid, pid);
|
||||||
|
INFO_LOG_FMT(CONTROLLERINTERFACE, "WGInput: Empty device name, using {}", device_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (winrt::hresult_error)
|
||||||
|
{
|
||||||
|
device_name = "Device";
|
||||||
ERROR_LOG_FMT(CONTROLLERINTERFACE, "WGInput: Failed to get device name, using {}", device_name);
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "WGInput: Failed to get device name, using {}", device_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
WGI::Gamepad gamepad = WGI::Gamepad::FromGameController(raw_game_controller);
|
try
|
||||||
// Note that gamepad may be nullptr here. The Device class will deal with this.
|
{
|
||||||
auto dev = std::make_shared<Device>(std::move(device_name), raw_game_controller, gamepad);
|
WGI::Gamepad gamepad = WGI::Gamepad::FromGameController(raw_game_controller);
|
||||||
|
// Note that gamepad may be nullptr here. The Device class will deal with this.
|
||||||
|
auto dev = std::make_shared<Device>(std::move(device_name), raw_game_controller, gamepad);
|
||||||
|
|
||||||
// Only add if it has some inputs/outputs.
|
// Only add if it has some inputs/outputs.
|
||||||
if (dev->Inputs().size() || dev->Outputs().size())
|
if (dev->Inputs().size() || dev->Outputs().size())
|
||||||
g_controller_interface.AddDevice(std::move(dev));
|
g_controller_interface.AddDevice(std::move(dev));
|
||||||
|
}
|
||||||
|
catch (winrt::hresult_error)
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "WGInput: Failed to add device {}", device_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RemoveDevice(const WGI::RawGameController& raw_game_controller)
|
static void RemoveDevice(const WGI::RawGameController& raw_game_controller)
|
||||||
@ -548,32 +663,32 @@ static void RemoveDevice(const WGI::RawGameController& raw_game_controller)
|
|||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
|
if (!COMIsInitialized())
|
||||||
|
{
|
||||||
|
// NOTE: Devices in g_controller_interface should only be accessed by threads that have had
|
||||||
|
// winrt (com) initialized.
|
||||||
|
winrt::init_apartment();
|
||||||
|
s_initialized_winrt = true;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// TODO currently, com gets initialized in STA previously on the thread that calls this
|
// These events will be invoked from WGI-managed threadpool.
|
||||||
// function. need to ensure Devices in g_controller_interface only get accessed by threads that
|
s_event_added = WGI::RawGameController::RawGameControllerAdded(
|
||||||
// have had com initialized.
|
[](auto&&, const WGI::RawGameController raw_game_controller) {
|
||||||
// winrt::init_apartment();
|
RemoveDevice(raw_game_controller);
|
||||||
// s_initialized_winrt = true;
|
AddDevice(raw_game_controller);
|
||||||
|
});
|
||||||
|
|
||||||
|
s_event_removed = WGI::RawGameController::RawGameControllerRemoved(
|
||||||
|
[](auto&&, const WGI::RawGameController raw_game_controller) {
|
||||||
|
RemoveDevice(raw_game_controller);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (winrt::hresult_error)
|
||||||
{
|
{
|
||||||
s_initialized_winrt = false;
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "WGInput: Failed to register event handlers");
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX If SDL is enabled, these get broken after the first one is fired.
|
|
||||||
|
|
||||||
// These events will be invoked from WGI-managed threadpool.
|
|
||||||
s_event_added = WGI::RawGameController::RawGameControllerAdded(
|
|
||||||
[](auto&&, const WGI::RawGameController raw_game_controller) {
|
|
||||||
RemoveDevice(raw_game_controller);
|
|
||||||
AddDevice(raw_game_controller);
|
|
||||||
});
|
|
||||||
|
|
||||||
s_event_removed = WGI::RawGameController::RawGameControllerRemoved(
|
|
||||||
[](auto&&, const WGI::RawGameController raw_game_controller) {
|
|
||||||
RemoveDevice(raw_game_controller);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
@ -604,11 +719,19 @@ void PopulateDevices()
|
|||||||
// RawGameController available from Windows 15063.
|
// RawGameController available from Windows 15063.
|
||||||
// properties added in 1709: DisplayName, NonRoamableId, SimpleHapticsControllers
|
// properties added in 1709: DisplayName, NonRoamableId, SimpleHapticsControllers
|
||||||
|
|
||||||
for (const WGI::RawGameController& raw_game_controller :
|
try
|
||||||
WGI::RawGameController::RawGameControllers())
|
|
||||||
{
|
{
|
||||||
RemoveDevice(raw_game_controller);
|
for (const WGI::RawGameController& raw_game_controller :
|
||||||
AddDevice(raw_game_controller);
|
WGI::RawGameController::RawGameControllers())
|
||||||
|
{
|
||||||
|
RemoveDevice(raw_game_controller);
|
||||||
|
AddDevice(raw_game_controller);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (winrt::hresult_error)
|
||||||
|
{
|
||||||
|
// Only reach here if RawGameControllers() failed
|
||||||
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "WGInput: PopulateDevices failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user