如何将控制器模拟摇杆映射到鼠标
How can I map the controller analog stick to the mouse
好的,所以我正在尝试使用游戏手柄上的模拟摇杆来移动桌面鼠标光标。问题是我需要能够获得与尝试 2 相同的平滑度,但不使用绝对鼠标位置。光标需要相对于其当前位置移动。这样做的原因是许多应用程序(主要是视频游戏)也将鼠标设置为绝对位置。这会导致应用程序和尝试 2 相互争夺鼠标控制权。
尝试 1(相对)
// keep updating the controller state and mouse position
while (true)
{
// getState returns a 2d float vector with normalized values from [-1, 1]
// The cursor is being set relative to its current position here.
SetCursorPosition(GetCursorPosition() + analogStick->getState());
}
此解决方案有效,但存在舍入问题,因为 GetCursorPosition 和 SetCursorPosition 基于整数。因此,小的运动不会被记录下来,因为较小的模拟运动总是会被截断。从视觉上看,模拟摇杆上的小动作只会使鼠标沿 X 或 Y 轴移动,即使您尝试进行对角线移动也是如此。
尝试 2(绝对)
vec2 mouseTargetPosition = GetCursorPosition(); // global cursor position
while (true)
{
mouseTargetPosition += leftStick->getState();
vec2 newPosition = lerp(GetCursorPos(), mouseTargetPosition, 0.8f);
SetCursorPos(round(newPosition.x), round(newPosition.y));
}
此解决方案效果很好,鼠标对最小的移动做出响应,并且由于对累积的模拟移动进行插值而非常自然地移动。但是,它将鼠标设置为绝对位置 (mouseTargetPosition),使该解决方案成为交易破坏者。
我想这首先是一个非常具体的问题。在尝试了几种配置之后,这是感觉最流畅且运行良好的配置。考虑到它基本上是神奇的,因为它可以为没有它的游戏和模型查看器添加原生感觉模拟支持:)
vec2 mouseTargetPos, mouseCurrentPos, change;
while (true)
{
// Their actual position doesn't matter so much as how the 'current' vector approaches
// the 'target vector'
mouseTargetPos += primary->state;
mouseCurrentPos = util::lerp(mouseCurrentPos, mouseTargetPos, 0.75f);
change = mouseTargetPos - mouseCurrentPos;
// movement was too small to be recognized, so we accumulate it
if (fabs(change.x) < 0.5f) accumulator.x += change.x;
if (fabs(change.y) < 0.5f) accumulator.y += change.y;
// If the value is too small to be recognized ( < 0.5 ) then the position will remain the same
SetCursorPos(GetCursorPos() + change);
SetCursorPos(GetCursorPos() + accumulator);
// once the accumulator has been used, reset it for the next accumulation.
if (fabs(accumulator.x) >= 0.5f) accumulator.x = 0;
if (fabs(accumulator.y) >= 0.5f) accumulator.y = 0;
}
好的,所以我正在尝试使用游戏手柄上的模拟摇杆来移动桌面鼠标光标。问题是我需要能够获得与尝试 2 相同的平滑度,但不使用绝对鼠标位置。光标需要相对于其当前位置移动。这样做的原因是许多应用程序(主要是视频游戏)也将鼠标设置为绝对位置。这会导致应用程序和尝试 2 相互争夺鼠标控制权。
尝试 1(相对)
// keep updating the controller state and mouse position
while (true)
{
// getState returns a 2d float vector with normalized values from [-1, 1]
// The cursor is being set relative to its current position here.
SetCursorPosition(GetCursorPosition() + analogStick->getState());
}
此解决方案有效,但存在舍入问题,因为 GetCursorPosition 和 SetCursorPosition 基于整数。因此,小的运动不会被记录下来,因为较小的模拟运动总是会被截断。从视觉上看,模拟摇杆上的小动作只会使鼠标沿 X 或 Y 轴移动,即使您尝试进行对角线移动也是如此。
尝试 2(绝对)
vec2 mouseTargetPosition = GetCursorPosition(); // global cursor position
while (true)
{
mouseTargetPosition += leftStick->getState();
vec2 newPosition = lerp(GetCursorPos(), mouseTargetPosition, 0.8f);
SetCursorPos(round(newPosition.x), round(newPosition.y));
}
此解决方案效果很好,鼠标对最小的移动做出响应,并且由于对累积的模拟移动进行插值而非常自然地移动。但是,它将鼠标设置为绝对位置 (mouseTargetPosition),使该解决方案成为交易破坏者。
我想这首先是一个非常具体的问题。在尝试了几种配置之后,这是感觉最流畅且运行良好的配置。考虑到它基本上是神奇的,因为它可以为没有它的游戏和模型查看器添加原生感觉模拟支持:)
vec2 mouseTargetPos, mouseCurrentPos, change;
while (true)
{
// Their actual position doesn't matter so much as how the 'current' vector approaches
// the 'target vector'
mouseTargetPos += primary->state;
mouseCurrentPos = util::lerp(mouseCurrentPos, mouseTargetPos, 0.75f);
change = mouseTargetPos - mouseCurrentPos;
// movement was too small to be recognized, so we accumulate it
if (fabs(change.x) < 0.5f) accumulator.x += change.x;
if (fabs(change.y) < 0.5f) accumulator.y += change.y;
// If the value is too small to be recognized ( < 0.5 ) then the position will remain the same
SetCursorPos(GetCursorPos() + change);
SetCursorPos(GetCursorPos() + accumulator);
// once the accumulator has been used, reset it for the next accumulation.
if (fabs(accumulator.x) >= 0.5f) accumulator.x = 0;
if (fabs(accumulator.y) >= 0.5f) accumulator.y = 0;
}