From db4b4e40cb5c9d00940cdb76478b632804cdf244 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Mon, 20 Apr 2020 23:16:07 -0500 Subject: [PATCH] InputCommon / DolphinQt / Core: Add a "RelativeMouse" input which provides the raw delta mouse input Co-authored-by: Jordan Woyak --- Source/Core/Core/HW/SI/SI.cpp | 1 + Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp | 1 + Source/Core/DolphinQt/HotkeyScheduler.cpp | 4 +- .../ControllerInterface.cpp | 12 +++++ .../ControllerInterface/ControllerInterface.h | 53 +++++++++++++++++++ .../ControllerInterface/CoreDevice.h | 6 +++ .../DInput/DInputKeyboardMouse.cpp | 46 ++++++++++++++-- .../DInput/DInputKeyboardMouse.h | 11 ++++ .../ControllerInterface/Xlib/XInput2.cpp | 20 +++++++ .../ControllerInterface/Xlib/XInput2.h | 16 ++++++ 10 files changed, 165 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/HW/SI/SI.cpp b/Source/Core/Core/HW/SI/SI.cpp index 348a16339b..ff349c64bf 100644 --- a/Source/Core/Core/HW/SI/SI.cpp +++ b/Source/Core/Core/HW/SI/SI.cpp @@ -655,6 +655,7 @@ void UpdateDevices() // Update inputs at the rate of SI // Typically 120hz but is variable + g_controller_interface.SetCurrentInputChannel(ciface::InputChannel::SerialInterface); g_controller_interface.UpdateInput(); // Update channels and set the status bit if there's new data diff --git a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp index 9958030fbd..3440417cce 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp @@ -339,6 +339,7 @@ void BluetoothEmuDevice::Update() if (now - m_last_ticks > interval) { + g_controller_interface.SetCurrentInputChannel(ciface::InputChannel::Bluetooth); g_controller_interface.UpdateInput(); for (auto& wiimote : m_wiimotes) wiimote->UpdateInput(); diff --git a/Source/Core/DolphinQt/HotkeyScheduler.cpp b/Source/Core/DolphinQt/HotkeyScheduler.cpp index 3b81e99a1d..ac37b5de96 100644 --- a/Source/Core/DolphinQt/HotkeyScheduler.cpp +++ b/Source/Core/DolphinQt/HotkeyScheduler.cpp @@ -141,8 +141,8 @@ void HotkeyScheduler::Run() { Common::SleepCurrentThread(1000 / 60); - if (Core::GetState() == Core::State::Uninitialized || Core::GetState() == Core::State::Paused) - g_controller_interface.UpdateInput(); + g_controller_interface.SetCurrentInputChannel(ciface::InputChannel::Host); + g_controller_interface.UpdateInput(); if (!HotkeyManagerEmu::IsEnabled()) continue; diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp index 1d198ca494..fe176ce7f7 100644 --- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp +++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp @@ -37,6 +37,8 @@ ControllerInterface g_controller_interface; +static thread_local ciface::InputChannel tls_input_channel = ciface::InputChannel::Host; + void ControllerInterface::Initialize(const WindowSystemInfo& wsi) { if (m_is_init) @@ -274,6 +276,16 @@ void ControllerInterface::UpdateInput() } } +void ControllerInterface::SetCurrentInputChannel(ciface::InputChannel input_channel) +{ + tls_input_channel = input_channel; +} + +ciface::InputChannel ControllerInterface::GetCurrentInputChannel() +{ + return tls_input_channel; +} + void ControllerInterface::SetAspectRatioAdjustment(float value) { m_aspect_ratio_adjustment = value; diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h index 254516fb6e..12d17614da 100644 --- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h +++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h @@ -32,6 +32,23 @@ #endif #define CIFACE_USE_DUALSHOCKUDPCLIENT +namespace ciface +{ +// A thread local "input channel" is maintained to handle the state of relative inputs. +// This allows simultaneous use of relative inputs across different input contexts. +// e.g. binding relative mouse movements to both GameCube controllers and FreeLook. +// These operate at different rates and processing one would break the other without separate state. +enum class InputChannel +{ + Host, + SerialInterface, + Bluetooth, + FreeLook, + Count, +}; + +} // namespace ciface + // // ControllerInterface // @@ -66,6 +83,9 @@ public: void UnregisterDevicesChangedCallback(const HotplugCallbackHandle& handle); void InvokeDevicesChangedCallbacks() const; + static void SetCurrentInputChannel(ciface::InputChannel); + static ciface::InputChannel GetCurrentInputChannel(); + private: std::list> m_devices_changed_callbacks; mutable std::mutex m_callbacks_mutex; @@ -75,4 +95,37 @@ private: std::atomic m_aspect_ratio_adjustment = 1; }; +namespace ciface +{ +template +class RelativeInputState +{ +public: + void Update() + { + const auto channel = int(ControllerInterface::GetCurrentInputChannel()); + + m_value[channel] = m_delta[channel]; + m_delta[channel] = {}; + } + + T GetValue() const + { + const auto channel = int(ControllerInterface::GetCurrentInputChannel()); + + return m_value[channel]; + } + + void Move(T delta) + { + for (auto& d : m_delta) + d += delta; + } + +private: + std::array m_value; + std::array m_delta; +}; +} // namespace ciface + extern ControllerInterface g_controller_interface; diff --git a/Source/Core/InputCommon/ControllerInterface/CoreDevice.h b/Source/Core/InputCommon/ControllerInterface/CoreDevice.h index 2612f59627..c368578949 100644 --- a/Source/Core/InputCommon/ControllerInterface/CoreDevice.h +++ b/Source/Core/InputCommon/ControllerInterface/CoreDevice.h @@ -93,6 +93,12 @@ public: virtual bool IsChild(const Input*) const { return false; } }; + class RelativeInput : public Input + { + public: + bool IsDetectable() const override { return false; } + }; + // // Output // diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.cpp b/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.cpp index e5e10802cc..ebe2e84286 100644 --- a/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.cpp +++ b/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.cpp @@ -2,11 +2,14 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h" + #include +#include + #include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/ControllerInterface/DInput/DInput.h" -#include "InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h" // (lower would be more sensitive) user can lower sensitivity by setting range // seems decent here ( at 8 ), I don't think anyone would need more sensitive than this @@ -19,6 +22,30 @@ namespace ciface::DInput { +class RelativeMouseAxis final : public Core::Device::RelativeInput +{ +public: + std::string GetName() const override + { + return fmt::format("RelativeMouse {}{}", char('X' + m_index), (m_scale > 0) ? '+' : '-'); + } + + RelativeMouseAxis(u8 index, bool positive, const RelativeMouseState* state) + : m_state(*state), m_index(index), m_scale(positive * 2 - 1) + { + } + + ControlState GetState() const override + { + return ControlState(m_state.GetValue().data[m_index] * m_scale); + } + +private: + const RelativeMouseState& m_state; + const u8 m_index; + const s8 m_scale; +}; + static const struct { const BYTE code; @@ -108,9 +135,17 @@ KeyboardMouse::KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device, AddInput(new Axis(i, ax, (2 == i) ? -1 : -MOUSE_AXIS_SENSITIVITY)); AddInput(new Axis(i, ax, -(2 == i) ? 1 : MOUSE_AXIS_SENSITIVITY)); } + // cursor, with a hax for-loop for (unsigned int i = 0; i < 4; ++i) AddInput(new Cursor(!!(i & 2), (&m_state_in.cursor.x)[i / 2], !!(i & 1))); + + // Raw relative mouse movement. + for (unsigned int i = 0; i != mouse_caps.dwAxes; ++i) + { + AddInput(new RelativeMouseAxis(i, false, &m_state_in.relative_mouse)); + AddInput(new RelativeMouseAxis(i, true, &m_state_in.relative_mouse)); + } } void KeyboardMouse::UpdateCursorInput() @@ -147,6 +182,8 @@ void KeyboardMouse::UpdateInput() { // set axes to zero m_state_in.mouse = {}; + m_state_in.relative_mouse = {}; + // skip this input state m_mo_device->GetDeviceState(sizeof(tmp_mouse), &tmp_mouse); } @@ -162,14 +199,17 @@ void KeyboardMouse::UpdateInput() if (DIERR_INPUTLOST == mo_hr || DIERR_NOTACQUIRED == mo_hr) m_mo_device->Acquire(); - if (SUCCEEDED(kb_hr) && SUCCEEDED(mo_hr)) + if (SUCCEEDED(mo_hr)) { + m_state_in.relative_mouse.Move({tmp_mouse.lX, tmp_mouse.lY, tmp_mouse.lZ}); + m_state_in.relative_mouse.Update(); + // need to smooth out the axes, otherwise it doesn't work for shit for (unsigned int i = 0; i < 3; ++i) ((&m_state_in.mouse.lX)[i] += (&tmp_mouse.lX)[i]) /= 2; // copy over the buttons - memcpy(m_state_in.mouse.rgbButtons, tmp_mouse.rgbButtons, sizeof(m_state_in.mouse.rgbButtons)); + std::copy_n(tmp_mouse.rgbButtons, std::size(tmp_mouse.rgbButtons), m_state_in.mouse.rgbButtons); UpdateCursorInput(); } diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h b/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h index c3834df528..ceda59d02c 100644 --- a/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h +++ b/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h @@ -7,6 +7,7 @@ #include #include "Common/Matrix.h" +#include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/ControllerInterface/CoreDevice.h" #include "InputCommon/ControllerInterface/DInput/DInput8.h" @@ -14,14 +15,23 @@ namespace ciface::DInput { void InitKeyboardMouse(IDirectInput8* const idi8, HWND hwnd); +using RelativeMouseState = RelativeInputState>; + class KeyboardMouse : public Core::Device { private: struct State { BYTE keyboard[256]; + + // Old smoothed relative mouse movement. DIMOUSESTATE2 mouse; + + // Normalized mouse cursor position. Common::TVec2 cursor; + + // Raw relative mouse movement. + RelativeMouseState relative_mouse; }; class Key : public Input @@ -53,6 +63,7 @@ private: public: Axis(u8 index, const LONG& axis, LONG range) : m_axis(axis), m_range(range), m_index(index) {} std::string GetName() const override; + bool IsDetectable() const override { return false; } ControlState GetState() const override; private: diff --git a/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp b/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp index a60edc3282..996673becb 100644 --- a/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp @@ -197,6 +197,11 @@ KeyboardMouse::KeyboardMouse(Window window, int opcode, int pointer, int keyboar // Mouse Axis, X-/+ and Y-/+ for (int i = 0; i != 4; ++i) AddInput(new Axis(!!(i & 2), !!(i & 1), (i & 2) ? &m_state.axis.y : &m_state.axis.x)); + + // Relative Mouse, X-/+ and Y-/+ + for (int i = 0; i != 4; ++i) + AddInput(new RelativeMouse(!!(i & 2), !!(i & 1), + (i & 2) ? &m_state.relative_mouse.y : &m_state.relative_mouse.x)); } KeyboardMouse::~KeyboardMouse() @@ -302,6 +307,9 @@ void KeyboardMouse::UpdateInput() XFreeEventData(m_display, &event.xcookie); } + m_state.relative_mouse.x = delta_x; + m_state.relative_mouse.y = delta_y; + // apply axis smoothing m_state.axis.x *= MOUSE_AXIS_SMOOTHING; m_state.axis.x += delta_x; @@ -391,8 +399,20 @@ KeyboardMouse::Axis::Axis(u8 index, bool positive, const float* axis) name = fmt::format("Axis {}{}", static_cast('X' + m_index), (m_positive ? '+' : '-')); } +KeyboardMouse::RelativeMouse::RelativeMouse(u8 index, bool positive, const float* axis) + : m_axis(axis), m_index(index), m_positive(positive) +{ + name = + fmt::format("RelativeMouse {}{}", static_cast('X' + m_index), (m_positive ? '+' : '-')); +} + ControlState KeyboardMouse::Axis::GetState() const { return std::max(0.0f, *m_axis / (m_positive ? MOUSE_AXIS_SENSITIVITY : -MOUSE_AXIS_SENSITIVITY)); } + +ControlState KeyboardMouse::RelativeMouse::GetState() const +{ + return std::max(0.0f, *m_axis / (m_positive ? MOUSE_AXIS_SENSITIVITY : -MOUSE_AXIS_SENSITIVITY)); +} } // namespace ciface::XInput2 diff --git a/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.h b/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.h index a9442b6332..71681a3e10 100644 --- a/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.h +++ b/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.h @@ -30,6 +30,7 @@ private: unsigned int buttons; Common::Vec2 cursor; Common::Vec2 axis; + Common::Vec2 relative_mouse; }; class Key : public Input @@ -91,6 +92,21 @@ private: std::string name; }; + class RelativeMouse : public Input + { + public: + std::string GetName() const override { return name; } + bool IsDetectable() const override { return false; } + RelativeMouse(u8 index, bool positive, const float* axis); + ControlState GetState() const override; + + private: + const float* m_axis; + const u8 m_index; + const bool m_positive; + std::string name; + }; + private: void SelectEventsForDevice(XIEventMask* mask, int deviceid); void UpdateCursor();