InputCommon / DolphinQt / Core: Add a "RelativeMouse" input which provides the raw delta mouse input
Co-authored-by: Jordan Woyak <jordan.woyak@gmail.com>
This commit is contained in:
parent
679d51c289
commit
db4b4e40cb
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<std::function<void()>> m_devices_changed_callbacks;
|
||||
mutable std::mutex m_callbacks_mutex;
|
||||
|
@ -75,4 +95,37 @@ private:
|
|||
std::atomic<float> m_aspect_ratio_adjustment = 1;
|
||||
};
|
||||
|
||||
namespace ciface
|
||||
{
|
||||
template <typename T>
|
||||
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<T, int(InputChannel::Count)> m_value;
|
||||
std::array<T, int(InputChannel::Count)> m_delta;
|
||||
};
|
||||
} // namespace ciface
|
||||
|
||||
extern ControllerInterface g_controller_interface;
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -2,11 +2,14 @@
|
|||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#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();
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <windows.h>
|
||||
|
||||
#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<Common::TVec3<LONG>>;
|
||||
|
||||
class KeyboardMouse : public Core::Device
|
||||
{
|
||||
private:
|
||||
struct State
|
||||
{
|
||||
BYTE keyboard[256];
|
||||
|
||||
// Old smoothed relative mouse movement.
|
||||
DIMOUSESTATE2 mouse;
|
||||
|
||||
// Normalized mouse cursor position.
|
||||
Common::TVec2<ControlState> 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:
|
||||
|
|
|
@ -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<char>('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<char>('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
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue