@@ -44,7 +44,7 @@ void ControlGroup::AddDeadzoneSetting(SettingValue<double>* value, double maximu
// i18n: The percent symbol.
_trans("%"),
// i18n: Refers to the dead-zone setting of gamepad inputs.
_trans("Input strength to ignore.")},
_trans("Input strength to ignore and remap.")},
0, 0, maximum_deadzone);
}

@@ -64,7 +64,7 @@ Cursor::Cursor(std::string name_, std::string ui_name_)
AddSetting(&m_autohide_setting, {_trans("Auto-Hide")}, false);
}

Cursor::ReshapeData Cursor::GetReshapableState(bool adjusted)
Cursor::ReshapeData Cursor::GetReshapableState(bool adjusted) const
{
const ControlState y = controls[0]->GetState() - controls[1]->GetState();
const ControlState x = controls[3]->GetState() - controls[2]->GetState();
@@ -25,9 +25,10 @@ class Cursor : public ReshapableInput

Cursor(std::string name, std::string ui_name);

ReshapeData GetReshapableState(bool adjusted) final override;
ReshapeData GetReshapableState(bool adjusted) const final override;
ControlState GetGateRadiusAtAngle(double ang) const override;

// Modifies the state
StateData GetState(bool adjusted);

// Yaw movement in radians.
@@ -65,7 +65,7 @@ Force::Force(const std::string& name_) : ReshapableInput(name_, name_, GroupType
90, 1, 180);
}

Force::ReshapeData Force::GetReshapableState(bool adjusted)
Force::ReshapeData Force::GetReshapableState(bool adjusted) const
{
const ControlState y = controls[0]->GetState() - controls[1]->GetState();
const ControlState x = controls[3]->GetState() - controls[2]->GetState();
@@ -77,7 +77,7 @@ Force::ReshapeData Force::GetReshapableState(bool adjusted)
return Reshape(x, y);
}

Force::StateData Force::GetState(bool adjusted)
Force::StateData Force::GetState(bool adjusted) const
{
const auto state = GetReshapableState(adjusted);
ControlState z = controls[4]->GetState() - controls[5]->GetState();
@@ -19,12 +19,12 @@ class Force : public ReshapableInput

explicit Force(const std::string& name);

ReshapeData GetReshapableState(bool adjusted) final override;
ReshapeData GetReshapableState(bool adjusted) const final override;
ControlState GetGateRadiusAtAngle(double ang) const final override;

ControlState GetDefaultInputRadiusAtAngle(double angle) const final override;

StateData GetState(bool adjusted = true);
StateData GetState(bool adjusted = true) const;

// Velocities returned in m/s.
ControlState GetSpeed() const;
@@ -40,7 +40,7 @@ IMUGyroscope::IMUGyroscope(std::string name_, std::string ui_name_)
// i18n: "°/s" is the symbol for degrees (angular measurement) divided by seconds.
_trans("°/s"),
// i18n: Refers to the dead-zone setting of gyroscope input.
_trans("Angular velocity to ignore.")},
_trans("Angular velocity to ignore and remap.")},
2, 0, 180);

AddSetting(&m_calibration_period_setting,
@@ -26,52 +26,52 @@ ModifySettingsButton::ModifySettingsButton(std::string button_name)
void ModifySettingsButton::AddInput(std::string button_name, bool toggle)
{
ControlGroup::AddInput(Translate, std::move(button_name));
threshold_exceeded.emplace_back(false);
associated_settings.emplace_back(false);
associated_settings_toggle.emplace_back(toggle);
m_threshold_exceeded.emplace_back(false);
m_associated_settings.emplace_back(false);
m_associated_settings_toggle.emplace_back(toggle);
}

void ModifySettingsButton::GetState()
void ModifySettingsButton::UpdateState()
{
for (size_t i = 0; i < controls.size(); ++i)
{
const bool state = controls[i]->GetState<bool>();

if (!associated_settings_toggle[i])
if (!m_associated_settings_toggle[i])
{
// not toggled
associated_settings[i] = state;
m_associated_settings[i] = state;
}
else
{
// toggle (loading savestates does not en-/disable toggle)
// after we passed the threshold, we en-/disable. but after that, we don't change it
// anymore
if (!threshold_exceeded[i] && state)
if (!m_threshold_exceeded[i] && state)
{
associated_settings[i] = !associated_settings[i];
m_associated_settings[i] = !m_associated_settings[i];

if (associated_settings[i])
if (m_associated_settings[i])
OSD::AddMessage(controls[i]->ui_name + ": on");
else
OSD::AddMessage(controls[i]->ui_name + ": off");

threshold_exceeded[i] = true;
m_threshold_exceeded[i] = true;
}

if (!state)
threshold_exceeded[i] = false;
m_threshold_exceeded[i] = false;
}
}
}

const std::vector<bool>& ModifySettingsButton::isSettingToggled() const
const std::vector<bool>& ModifySettingsButton::IsSettingToggled() const
{
return associated_settings_toggle;
return m_associated_settings_toggle;
}

const std::vector<bool>& ModifySettingsButton::getSettingsModifier() const
const std::vector<bool>& ModifySettingsButton::GetSettingsModifier() const
{
return associated_settings;
return m_associated_settings;
}
} // namespace ControllerEmu
@@ -18,14 +18,14 @@ class ModifySettingsButton : public Buttons

void AddInput(std::string button_name, bool toggle = false);

void GetState();
void UpdateState();

const std::vector<bool>& isSettingToggled() const;
const std::vector<bool>& getSettingsModifier() const;
const std::vector<bool>& IsSettingToggled() const;
const std::vector<bool>& GetSettingsModifier() const;

private:
std::vector<bool> threshold_exceeded; // internal calculation (if "state" was above threshold)
std::vector<bool> associated_settings_toggle; // is setting toggled or hold?
std::vector<bool> associated_settings; // result
std::vector<bool> m_threshold_exceeded; // internal calculation (if "state" was above threshold)
std::vector<bool> m_associated_settings_toggle; // is setting toggled or hold?
std::vector<bool> m_associated_settings; // result
};
} // namespace ControllerEmu
@@ -29,7 +29,7 @@ Slider::Slider(const std::string& name_) : Slider(name_, name_)
{
}

Slider::StateData Slider::GetState()
Slider::StateData Slider::GetState() const
{
const ControlState deadzone = m_deadzone_setting.GetValue() / 100;
const ControlState state = controls[1]->GetState() - controls[0]->GetState();
@@ -23,7 +23,7 @@ class Slider : public ControlGroup
Slider(const std::string& name_, const std::string& ui_name_);
explicit Slider(const std::string& name_);

StateData GetState();
StateData GetState() const;

private:
SettingValue<double> m_deadzone_setting;
@@ -42,7 +42,7 @@ Tilt::Tilt(const std::string& name_) : ReshapableInput(name_, name_, GroupType::
7, 1, 50);
}

Tilt::ReshapeData Tilt::GetReshapableState(bool adjusted)
Tilt::ReshapeData Tilt::GetReshapableState(bool adjusted) const
{
const ControlState y = controls[0]->GetState() - controls[1]->GetState();
const ControlState x = controls[3]->GetState() - controls[2]->GetState();
@@ -56,7 +56,7 @@ Tilt::ReshapeData Tilt::GetReshapableState(bool adjusted)
return Reshape(x, y, modifier);
}

Tilt::StateData Tilt::GetState()
Tilt::StateData Tilt::GetState() const
{
return GetReshapableState(true);
}
@@ -19,14 +19,14 @@ class Tilt : public ReshapableInput

explicit Tilt(const std::string& name);

ReshapeData GetReshapableState(bool adjusted) final override;
ReshapeData GetReshapableState(bool adjusted) const final override;
ControlState GetGateRadiusAtAngle(double angle) const final override;

// Tilt is using the gate radius to adjust the tilt angle so we must provide an unadjusted value
// for the default input radius.
ControlState GetDefaultInputRadiusAtAngle(double angle) const final override;

StateData GetState();
StateData GetState() const;

// Return peak rotational velocity (for a complete turn) in radians/sec
ControlState GetMaxRotationalVelocity() const;
@@ -21,7 +21,7 @@ Triggers::Triggers(const std::string& name_) : ControlGroup(name_, GroupType::Tr
AddDeadzoneSetting(&m_deadzone_setting, 50);
}

Triggers::StateData Triggers::GetState()
Triggers::StateData Triggers::GetState() const
{
const size_t trigger_count = controls.size();
const ControlState deadzone = m_deadzone_setting.GetValue() / 100;
@@ -26,7 +26,7 @@ class Triggers : public ControlGroup

explicit Triggers(const std::string& name);

StateData GetState();
StateData GetState() const;

private:
SettingValue<double> m_deadzone_setting;
@@ -128,6 +128,7 @@ std::optional<u32> SquareStickGate::GetIdealCalibrationSampleCount() const
ReshapableInput::ReshapableInput(std::string name_, std::string ui_name_, GroupType type_)
: ControlGroup(std::move(name_), std::move(ui_name_), type_)
{
// 50 is not always enough but users can set it to more with an expression
AddDeadzoneSetting(&m_deadzone_setting, 50);
}

@@ -280,11 +281,16 @@ void ReshapableInput::SaveConfig(IniFile::Section* section, const std::string& d
}

ReshapableInput::ReshapeData ReshapableInput::Reshape(ControlState x, ControlState y,
ControlState modifier)
ControlState modifier,
ControlState clamp) const
{
x -= m_center.x;
y -= m_center.y;

// We run this even if both x and y will be zero.
// In that case, std::atan2(0, 0) returns a valid non-NaN value, but the exact value
// (which depends on the signs of x and y) does not matter here as dist is zero

// TODO: make the AtAngle functions work with negative angles:
ControlState angle = std::atan2(y, x) + MathUtil::TAU;

@@ -321,8 +327,8 @@ ReshapableInput::ReshapeData ReshapableInput::Reshape(ControlState x, ControlSta
// Scale to the gate shape/radius:
dist *= gate_max_dist;

return {std::clamp(std::cos(angle) * dist, -1.0, 1.0),
std::clamp(std::sin(angle) * dist, -1.0, 1.0)};
return {std::clamp(std::cos(angle) * dist, -clamp, clamp),
std::clamp(std::sin(angle) * dist, -clamp, clamp)};
}

} // namespace ControllerEmu
@@ -91,7 +91,7 @@ class ReshapableInput : public ControlGroup
virtual ControlState GetVirtualNotchSize() const { return 0.0; };

virtual ControlState GetGateRadiusAtAngle(double angle) const = 0;
virtual ReshapeData GetReshapableState(bool adjusted) = 0;
virtual ReshapeData GetReshapableState(bool adjusted) const = 0;
virtual ControlState GetDefaultInputRadiusAtAngle(double ang) const;

void SetCalibrationToDefault();
@@ -108,7 +108,8 @@ class ReshapableInput : public ControlGroup
void SetCenter(ReshapeData center);

protected:
ReshapeData Reshape(ControlState x, ControlState y, ControlState modifier = 0.0);
ReshapeData Reshape(ControlState x, ControlState y, ControlState modifier = 0.0,
ControlState clamp = 1.0) const;

private:
void LoadConfig(IniFile::Section*, const std::string&, const std::string&) override;
@@ -237,7 +237,7 @@ void ControllerInterface::AddDevice(std::shared_ptr<ciface::Core::Device> device
device->SetId(id);
}

NOTICE_LOG_FMT(SERIALINTERFACE, "Added device: {}", device->GetQualifiedName());
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "Added device: {}", device->GetQualifiedName());
m_devices.emplace_back(std::move(device));
}

@@ -252,7 +252,7 @@ void ControllerInterface::RemoveDevice(std::function<bool(const ciface::Core::De
auto it = std::remove_if(m_devices.begin(), m_devices.end(), [&callback](const auto& dev) {
if (callback(dev.get()))
{
NOTICE_LOG_FMT(SERIALINTERFACE, "Removed device: {}", dev->GetQualifiedName());
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "Removed device: {}", dev->GetQualifiedName());
return true;
}
return false;
@@ -205,7 +205,7 @@ static bool IsSameController(const Proto::MessageType::PortInfo& a,
static void HotplugThreadFunc()
{
Common::SetCurrentThreadName("DualShockUDPClient Hotplug Thread");
INFO_LOG_FMT(SERIALINTERFACE, "DualShockUDPClient hotplug thread started");
INFO_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient hotplug thread started");

while (s_hotplug_thread_running.IsSet())
{
@@ -225,7 +225,7 @@ static void HotplugThreadFunc()
if (server.m_socket.send(&list_ports, sizeof list_ports, server.m_address, server.m_port) !=
sf::Socket::Status::Done)
{
ERROR_LOG_FMT(SERIALINTERFACE, "DualShockUDPClient HotplugThreadFunc send failed");
ERROR_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient HotplugThreadFunc send failed");
}
}
}
@@ -277,7 +277,7 @@ static void HotplugThreadFunc()
}
}
}
INFO_LOG_FMT(SERIALINTERFACE, "DualShockUDPClient hotplug thread stopped");
INFO_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient hotplug thread stopped");
}

static void StartHotplugThread()
@@ -310,7 +310,7 @@ static void StopHotplugThread()

static void Restart()
{
INFO_LOG_FMT(SERIALINTERFACE, "DualShockUDPClient Restart");
INFO_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient Restart");

StopHotplugThread();

@@ -394,7 +394,7 @@ void Init()

void PopulateDevices()
{
INFO_LOG_FMT(SERIALINTERFACE, "DualShockUDPClient PopulateDevices");
INFO_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient PopulateDevices");

// s_servers has already been updated so we can't use it to know which devices we removed,
// also it's good to remove all of them before adding new ones so that their id will be set
@@ -510,7 +510,7 @@ void Device::UpdateInput()
if (m_socket.send(&data_req, sizeof(data_req), m_server_address, m_server_port) !=
sf::Socket::Status::Done)
{
ERROR_LOG_FMT(SERIALINTERFACE, "DualShockUDPClient UpdateInput send failed");
ERROR_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient UpdateInput send failed");
}
}

@@ -249,7 +249,7 @@ struct Message
if (crc32_in_header != crc32_calculated)
{
NOTICE_LOG_FMT(
SERIALINTERFACE,
CONTROLLERINTERFACE,
"DualShockUDPClient Received message with bad CRC in header: got {:08x}, expected {:08x}",
crc32_in_header, crc32_calculated);
return std::nullopt;
@@ -178,11 +178,11 @@ void Init(void* window)

HIDManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
if (!HIDManager)
ERROR_LOG_FMT(SERIALINTERFACE, "Failed to create HID Manager reference");
ERROR_LOG_FMT(CONTROLLERINTERFACE, "Failed to create HID Manager reference");

IOHIDManagerSetDeviceMatching(HIDManager, nullptr);
if (IOHIDManagerOpen(HIDManager, kIOHIDOptionsTypeNone) != kIOReturnSuccess)
ERROR_LOG_FMT(SERIALINTERFACE, "Failed to open HID Manager");
ERROR_LOG_FMT(CONTROLLERINTERFACE, "Failed to open HID Manager");

// Callbacks for acquisition or loss of a matching device
IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, DeviceMatchingCallback, nullptr);
@@ -198,15 +198,15 @@ void Init(void* window)
// Enable hotplugging
s_hotplug_thread = std::thread([] {
Common::SetCurrentThreadName("IOHIDManager Hotplug Thread");
NOTICE_LOG_FMT(SERIALINTERFACE, "IOHIDManager hotplug thread started");
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "IOHIDManager hotplug thread started");

IOHIDManagerScheduleWithRunLoop(HIDManager, CFRunLoopGetCurrent(), OurRunLoop);
s_stopper.AddToRunLoop(CFRunLoopGetCurrent(), OurRunLoop);
CFRunLoopRunInMode(OurRunLoop, FOREVER, FALSE);
s_stopper.RemoveFromRunLoop(CFRunLoopGetCurrent(), OurRunLoop);
IOHIDManagerUnscheduleFromRunLoop(HIDManager, CFRunLoopGetCurrent(), OurRunLoop);

NOTICE_LOG_FMT(SERIALINTERFACE, "IOHIDManager hotplug thread stopped");
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "IOHIDManager hotplug thread stopped");
});
}

@@ -109,8 +109,9 @@
break;
}

NOTICE_LOG_FMT(SERIALINTERFACE, "Unknown IOHIDElement, ignoring (Usage: {:x}, Type: {:x})",
usage, IOHIDElementGetType(e));
NOTICE_LOG_FMT(CONTROLLERINTERFACE,
"Unknown IOHIDElement, ignoring (Usage: {:x}, Type: {:x})", usage,
IOHIDElementGetType(e));

break;
}
@@ -81,7 +81,7 @@ void Init()
{
#if !SDL_VERSION_ATLEAST(2, 0, 0)
if (SDL_Init(SDL_INIT_JOYSTICK) != 0)
ERROR_LOG_FMT(SERIALINTERFACE, "SDL failed to initialize");
ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to initialize");
return;
#else
s_hotplug_thread = std::thread([] {
@@ -95,14 +95,14 @@ void Init()

if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) != 0)
{
ERROR_LOG_FMT(SERIALINTERFACE, "SDL failed to initialize");
ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to initialize");
return;
}

const Uint32 custom_events_start = SDL_RegisterEvents(2);
if (custom_events_start == static_cast<Uint32>(-1))
{
ERROR_LOG_FMT(SERIALINTERFACE, "SDL failed to register custom events");
ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to register custom events");
return;
}
s_stop_event_type = custom_events_start;
@@ -766,7 +766,7 @@ bool InputDevice::PressEvent(int button, int action)
if (binding.second->m_bind_type == BIND_BUTTON)
m_buttons[binding.second->m_button_type] = action == BUTTON_PRESSED ? true : false;
else
m_axises[binding.second->m_button_type] = action == BUTTON_PRESSED ? 1.0f : 0.0f;
m_axes[binding.second->m_button_type] = action == BUTTON_PRESSED ? 1.0f : 0.0f;
handled = true;
}
}
@@ -780,34 +780,54 @@ void InputDevice::AxisEvent(int axis, float value)
if (binding.second->m_bind == axis)
{
if (binding.second->m_bind_type == BIND_AXIS)
m_axises[binding.second->m_button_type] = value;
m_axes[binding.second->m_button_type] = value;
else
m_buttons[binding.second->m_button_type] = value > 0.5f ? true : false;
}
}
}

bool InputDevice::ButtonValue(int pad_id, ButtonType button)
bool InputDevice::ButtonValue(int pad_id, ButtonType button) const
{
const auto& binding = m_input_binds.find(std::make_pair(pad_id, button));
const auto binding = m_input_binds.find(std::make_pair(pad_id, button));
if (binding == m_input_binds.end())
return false;

if (binding->second->m_bind_type == BIND_BUTTON)
return m_buttons[binding->second->m_button_type];
{
const auto button = m_buttons.find(binding->second->m_button_type);
if (button == m_buttons.end())
return false;
return button->second;
}
else
return (m_axises[binding->second->m_button_type] * binding->second->m_neg) > 0.5f;
{
const auto axis = m_axes.find(binding->second->m_button_type);
if (axis == m_axes.end())
return false;
return (axis->second * binding->second->m_neg) > 0.5f;
}
}

float InputDevice::AxisValue(int pad_id, ButtonType axis)
float InputDevice::AxisValue(int pad_id, ButtonType axis) const
{
const auto& binding = m_input_binds.find(std::make_pair(pad_id, axis));
const auto binding = m_input_binds.find(std::make_pair(pad_id, axis));
if (binding == m_input_binds.end())
return 0.0f;

if (binding->second->m_bind_type == BIND_AXIS)
return m_axises[binding->second->m_button_type] * binding->second->m_neg;
{
const auto axis = m_axes.find(binding->second->m_button_type);
if (axis == m_axes.end())
return 0.0f;
return axis->second * binding->second->m_neg;
}
else
return m_buttons[binding->second->m_button_type] == BUTTON_PRESSED ? 1.0f : 0.0f;
{
const auto button = m_buttons.find(binding->second->m_button_type);
if (button == m_buttons.end())
return 0.0f;
return button->second == BUTTON_PRESSED ? 1.0f : 0.0f;
}
}
} // namespace ButtonManager
@@ -210,7 +210,7 @@ class Button
public:
Button() : m_state(BUTTON_RELEASED) {}
void SetState(ButtonState state) { m_state = state; }
bool Pressed() { return m_state == BUTTON_PRESSED; }
bool Pressed() const { return m_state == BUTTON_PRESSED; }
~Button() {}
};
class Axis
@@ -221,7 +221,7 @@ class Axis
public:
Axis() : m_value(0.0f) {}
void SetValue(float value) { m_value = value; }
float AxisValue() { return m_value; }
float AxisValue() const { return m_value; }
~Axis() {}
};

@@ -244,7 +244,7 @@ class InputDevice
private:
const std::string m_dev;
std::map<ButtonType, bool> m_buttons;
std::map<ButtonType, float> m_axises;
std::map<ButtonType, float> m_axes;

// Key is pad_id and ButtonType
std::map<std::pair<int, ButtonType>, sBind*> m_input_binds;
@@ -263,8 +263,8 @@ class InputDevice
}
bool PressEvent(int button, int action);
void AxisEvent(int axis, float value);
bool ButtonValue(int pad_id, ButtonType button);
float AxisValue(int pad_id, ButtonType axis);
bool ButtonValue(int pad_id, ButtonType button) const;
float AxisValue(int pad_id, ButtonType axis) const;
};

void Init(const std::string&);
@@ -53,7 +53,7 @@ void ciface::Win32::Init(void* hwnd)

if (FAILED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)))
{
ERROR_LOG_FMT(SERIALINTERFACE, "CoInitializeEx failed: {}", GetLastError());
ERROR_LOG_FMT(CONTROLLERINTERFACE, "CoInitializeEx failed: {}", GetLastError());
return;
}
Common::ScopeGuard uninit([] { CoUninitialize(); });
@@ -67,25 +67,25 @@ void ciface::Win32::Init(void* hwnd)
ATOM window_class = RegisterClassEx(&window_class_info);
if (!window_class)
{
NOTICE_LOG_FMT(SERIALINTERFACE, "RegisterClassEx failed: {}", GetLastError());
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "RegisterClassEx failed: {}", GetLastError());
return;
}
Common::ScopeGuard unregister([&window_class] {
if (!UnregisterClass(MAKEINTATOM(window_class), GetModuleHandle(nullptr)))
ERROR_LOG_FMT(SERIALINTERFACE, "UnregisterClass failed: {}", GetLastError());
ERROR_LOG_FMT(CONTROLLERINTERFACE, "UnregisterClass failed: {}", GetLastError());
});

message_window = CreateWindowEx(0, L"Message", nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr,
nullptr, nullptr);
promise_guard.Exit();
if (!message_window)
{
ERROR_LOG_FMT(SERIALINTERFACE, "CreateWindowEx failed: {}", GetLastError());
ERROR_LOG_FMT(CONTROLLERINTERFACE, "CreateWindowEx failed: {}", GetLastError());
return;
}
Common::ScopeGuard destroy([&] {
if (!DestroyWindow(message_window))
ERROR_LOG_FMT(SERIALINTERFACE, "DestroyWindow failed: {}", GetLastError());
ERROR_LOG_FMT(CONTROLLERINTERFACE, "DestroyWindow failed: {}", GetLastError());
});

std::array<RAWINPUTDEVICE, 2> devices;
@@ -103,7 +103,7 @@ void ciface::Win32::Init(void* hwnd)
if (!RegisterRawInputDevices(devices.data(), static_cast<UINT>(devices.size()),
static_cast<UINT>(sizeof(decltype(devices)::value_type))))
{
ERROR_LOG_FMT(SERIALINTERFACE, "RegisterRawInputDevices failed: {}", GetLastError());
ERROR_LOG_FMT(CONTROLLERINTERFACE, "RegisterRawInputDevices failed: {}", GetLastError());
return;
}

@@ -128,18 +128,18 @@ void ciface::Win32::PopulateDevices(void* hwnd)
s_done_populating.Reset();
PostMessage(s_message_window, WM_INPUT_DEVICE_CHANGE, 0, 0);
if (!s_done_populating.WaitFor(std::chrono::seconds(10)))
ERROR_LOG_FMT(SERIALINTERFACE, "win32 timed out when trying to populate devices");
ERROR_LOG_FMT(CONTROLLERINTERFACE, "win32 timed out when trying to populate devices");
}
else
{
ERROR_LOG_FMT(SERIALINTERFACE,
ERROR_LOG_FMT(CONTROLLERINTERFACE,
"win32 asked to populate devices, but device thread isn't running");
}
}

void ciface::Win32::DeInit()
{
NOTICE_LOG_FMT(SERIALINTERFACE, "win32 DeInit");
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "win32 DeInit");
if (s_thread.joinable())
{
PostMessage(s_message_window, WM_DOLPHIN_STOP, 0, 0);
@@ -253,7 +253,7 @@ static void AddDeviceNode(const char* devnode)
auto evdev_device = FindDeviceWithUniqueIDAndPhysicalLocation(uniq, phys);
if (evdev_device)
{
NOTICE_LOG_FMT(SERIALINTERFACE,
NOTICE_LOG_FMT(CONTROLLERINTERFACE,
"evdev combining devices with unique id: {}, physical location: {}", uniq, phys);

evdev_device->AddNode(devnode, fd, dev);
@@ -282,7 +282,7 @@ static void AddDeviceNode(const char* devnode)
static void HotplugThreadFunc()
{
Common::SetCurrentThreadName("evdev Hotplug Thread");
NOTICE_LOG_FMT(SERIALINTERFACE, "evdev hotplug thread started");
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "evdev hotplug thread started");

udev* const udev = udev_new();
Common::ScopeGuard udev_guard([udev] { udev_unref(udev); });
@@ -337,7 +337,7 @@ static void HotplugThreadFunc()
AddDeviceNode(devnode);
}
}
NOTICE_LOG_FMT(SERIALINTERFACE, "evdev hotplug thread stopped");
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "evdev hotplug thread stopped");
}

static void StartHotplugThread()
@@ -88,7 +88,8 @@ static void Read()
int err = libusb_interrupt_transfer(s_handle, s_endpoint_in, s_controller_payload_swap,
sizeof(s_controller_payload_swap), &payload_size, 16);
if (err)
ERROR_LOG_FMT(SERIALINTERFACE, "adapter libusb read failed: err={}", libusb_error_name(err));
ERROR_LOG_FMT(CONTROLLERINTERFACE, "adapter libusb read failed: err={}",
libusb_error_name(err));

{
std::lock_guard<std::mutex> lk(s_mutex);
@@ -121,7 +122,8 @@ static void Write()
const int err =
libusb_interrupt_transfer(s_handle, s_endpoint_out, payload, sizeof(payload), &size, 16);
if (err != 0)
ERROR_LOG_FMT(SERIALINTERFACE, "adapter libusb write failed: err={}", libusb_error_name(err));
ERROR_LOG_FMT(CONTROLLERINTERFACE, "adapter libusb write failed: err={}",
libusb_error_name(err));
}
}

@@ -154,7 +156,7 @@ static int HotplugCallback(libusb_context* ctx, libusb_device* dev, libusb_hotpl
static void ScanThreadFunc()
{
Common::SetCurrentThreadName("GC Adapter Scanning Thread");
NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter scanning thread started");
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter scanning thread started");

#if defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102
#ifndef __FreeBSD__
@@ -170,7 +172,7 @@ static void ScanThreadFunc()
nullptr, &s_hotplug_handle) != LIBUSB_SUCCESS)
s_libusb_hotplug_enabled = false;
if (s_libusb_hotplug_enabled)
NOTICE_LOG_FMT(SERIALINTERFACE, "Using libUSB hotplug detection");
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "Using libUSB hotplug detection");
}
#endif

@@ -187,7 +189,7 @@ static void ScanThreadFunc()
else
Common::SleepCurrentThread(500);
}
NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter scanning thread stopped");
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter scanning thread stopped");
}

void SetAdapterCallback(std::function<void()> func)
@@ -265,7 +267,7 @@ static bool CheckDeviceAccess(libusb_device* device)
if (ret != 0)
{
// could not acquire the descriptor, no point in trying to use it.
ERROR_LOG_FMT(SERIALINTERFACE, "libusb_get_device_descriptor failed with error: {}", ret);
ERROR_LOG_FMT(CONTROLLERINTERFACE, "libusb_get_device_descriptor failed with error: {}", ret);
return false;
}

@@ -275,7 +277,7 @@ static bool CheckDeviceAccess(libusb_device* device)
return false;
}

NOTICE_LOG_FMT(SERIALINTERFACE, "Found GC Adapter with Vendor: {:X} Product: {:X} Devnum: {}",
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "Found GC Adapter with Vendor: {:X} Product: {:X} Devnum: {}",
desc.idVendor, desc.idProduct, 1);

// In case of failure, capture the libusb error code into the adapter status
@@ -287,14 +289,14 @@ static bool CheckDeviceAccess(libusb_device* device)
if (ret == LIBUSB_ERROR_ACCESS)
{
ERROR_LOG_FMT(
SERIALINTERFACE,
CONTROLLERINTERFACE,
"Dolphin does not have access to this device: Bus {:03d} Device {:03d}: ID {:04X}:{:04X}.",
bus, port, desc.idVendor, desc.idProduct);
return false;
}
if (ret != 0)
{
ERROR_LOG_FMT(SERIALINTERFACE, "libusb_open failed to open device with error = {}", ret);
ERROR_LOG_FMT(CONTROLLERINTERFACE, "libusb_open failed to open device with error = {}", ret);
return false;
}

@@ -303,14 +305,14 @@ static bool CheckDeviceAccess(libusb_device* device)
{
ret = libusb_detach_kernel_driver(s_handle, 0);
if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED)
ERROR_LOG_FMT(SERIALINTERFACE, "libusb_detach_kernel_driver failed with error: {}", ret);
ERROR_LOG_FMT(CONTROLLERINTERFACE, "libusb_detach_kernel_driver failed with error: {}", ret);
}

// This call makes Nyko-brand (and perhaps other) adapters work.
// However it returns LIBUSB_ERROR_PIPE with Mayflash adapters.
const int transfer = libusb_control_transfer(s_handle, 0x21, 11, 0x0001, 0, nullptr, 0, 1000);
if (transfer < 0)
WARN_LOG_FMT(SERIALINTERFACE, "libusb_control_transfer failed with error: {}", transfer);
WARN_LOG_FMT(CONTROLLERINTERFACE, "libusb_control_transfer failed with error: {}", transfer);

// this split is needed so that we don't avoid claiming the interface when
// detaching the kernel driver is successful
@@ -324,7 +326,7 @@ static bool CheckDeviceAccess(libusb_device* device)
ret = libusb_claim_interface(s_handle, 0);
if (ret != 0)
{
ERROR_LOG_FMT(SERIALINTERFACE, "libusb_claim_interface failed with error: {}", ret);
ERROR_LOG_FMT(CONTROLLERINTERFACE, "libusb_claim_interface failed with error: {}", ret);
libusb_close(s_handle);
s_handle = nullptr;
return false;
@@ -410,7 +412,7 @@ static void Reset()
}
if (s_detect_callback != nullptr)
s_detect_callback();
NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter detached");
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter detached");
}

GCPadStatus Input(int chan)
@@ -436,8 +438,8 @@ GCPadStatus Input(int chan)
controller_payload_copy[0] != LIBUSB_DT_HID)
{
// This can occur for a few frames on initialization.
ERROR_LOG_FMT(SERIALINTERFACE, "error reading payload (size: {}, type: {:02x})", payload_size,
controller_payload_copy[0]);
ERROR_LOG_FMT(CONTROLLERINTERFACE, "error reading payload (size: {}, type: {:02x})",
payload_size, controller_payload_copy[0]);
}
else
{
@@ -446,8 +448,8 @@ GCPadStatus Input(int chan)
if (type != ControllerTypes::CONTROLLER_NONE &&
s_controller_type[chan] == ControllerTypes::CONTROLLER_NONE)
{
NOTICE_LOG_FMT(SERIALINTERFACE, "New device connected to Port {} of Type: {:02x}", chan + 1,
controller_payload_copy[1 + (9 * chan)]);
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "New device connected to Port {} of Type: {:02x}",
chan + 1, controller_payload_copy[1 + (9 * chan)]);
get_origin = true;
}

@@ -551,7 +553,7 @@ static void ResetRumbleLockNeeded()
int size = 0;
libusb_interrupt_transfer(s_handle, s_endpoint_out, rumble, sizeof(rumble), &size, 16);

INFO_LOG_FMT(SERIALINTERFACE, "Rumble state reset");
INFO_LOG_FMT(CONTROLLERINTERFACE, "Rumble state reset");
}

void Output(int chan, u8 rumble_command)
@@ -64,7 +64,7 @@ static u64 s_last_init = 0;
static void ScanThreadFunc()
{
Common::SetCurrentThreadName("GC Adapter Scanning Thread");
NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter scanning thread started");
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter scanning thread started");

JNIEnv* env = IDCache::GetEnvForThread();

@@ -78,13 +78,13 @@ static void ScanThreadFunc()
Common::SleepCurrentThread(1000);
}

NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter scanning thread stopped");
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter scanning thread stopped");
}

static void Write()
{
Common::SetCurrentThreadName("GC Adapter Write Thread");
NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter write thread started");
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter write thread started");

JNIEnv* env = IDCache::GetEnvForThread();
jmethodID output_func = env->GetStaticMethodID(s_adapter_class, "Output", "([B)I");
@@ -108,21 +108,21 @@ static void Write()
// Netplay sends invalid data which results in size = 0x00. Ignore it.
if (size != write_size && size != 0x00)
{
ERROR_LOG_FMT(SERIALINTERFACE, "error writing rumble (size: {})", size);
ERROR_LOG_FMT(CONTROLLERINTERFACE, "error writing rumble (size: {})", size);
Reset();
}
}

Common::YieldCPU();
}

NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter write thread stopped");
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter write thread stopped");
}

static void Read()
{
Common::SetCurrentThreadName("GC Adapter Read Thread");
NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter read thread started");
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter read thread started");

bool first_read = true;
JNIEnv* env = IDCache::GetEnvForThread();
@@ -179,7 +179,7 @@ static void Read()
s_fd = 0;
s_detected = false;

NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter read thread stopped");
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter read thread stopped");
}

void Init()
@@ -229,7 +229,7 @@ static void Reset()

s_detected = false;
s_fd = 0;
NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter detached");
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter detached");
}

void Shutdown()
@@ -270,8 +270,8 @@ GCPadStatus Input(int chan)
GCPadStatus pad = {};
if (payload_size != controller_payload_copy.size())
{
ERROR_LOG_FMT(SERIALINTERFACE, "error reading payload (size: {}, type: {:02x})", payload_size,
controller_payload_copy[0]);
ERROR_LOG_FMT(CONTROLLERINTERFACE, "error reading payload (size: {}, type: {:02x})",
payload_size, controller_payload_copy[0]);
Reset();
}
else
@@ -281,8 +281,8 @@ GCPadStatus Input(int chan)
if (type != ControllerTypes::CONTROLLER_NONE &&
s_controller_type[chan] == ControllerTypes::CONTROLLER_NONE)
{
ERROR_LOG_FMT(SERIALINTERFACE, "New device connected to Port {} of Type: {:02x}", chan + 1,
controller_payload_copy[1 + (9 * chan)]);
ERROR_LOG_FMT(CONTROLLERINTERFACE, "New device connected to Port {} of Type: {:02x}",
chan + 1, controller_payload_copy[1 + (9 * chan)]);
get_origin = true;
}

@@ -133,7 +133,6 @@ bool InputConfig::LoadConfig(bool isGC)
}
#endif
controller->LoadConfig(&config);
// Update refs
controller->UpdateReferences(g_controller_interface);
controller_names.push_back(controller->GetName());

@@ -171,7 +170,7 @@ void InputConfig::SaveConfig()
inifile.Save(ini_filename);
}

ControllerEmu::EmulatedController* InputConfig::GetController(int index)
ControllerEmu::EmulatedController* InputConfig::GetController(int index) const
{
return m_controllers.at(index).get();
}
@@ -34,7 +34,7 @@ class InputConfig
m_controllers.emplace_back(std::make_unique<T>(std::forward<Args>(args)...));
}

ControllerEmu::EmulatedController* GetController(int index);
ControllerEmu::EmulatedController* GetController(int index) const;
void ClearControllers();
bool ControllersNeedToBeCreated() const;
bool IsControllerControlledByGamepadDevice(int index) const;
@@ -776,6 +776,7 @@ void Renderer::UpdateDrawRectangle()
const float win_width = static_cast<float>(m_backbuffer_width);
const float win_height = static_cast<float>(m_backbuffer_height);

// FIXME: this breaks at very low widget sizes
// Make ControllerInterface aware of the render window region actually being used
// to adjust mouse cursor inputs.
g_controller_interface.SetAspectRatioAdjustment(draw_aspect_ratio / (win_width / win_height));