在ubuntu20.04环境下使用xbox one 手柄和无线适配器
1. 安装dkms
sudo apt-get install dkms
2. 安装xone
xone 是基于Linux内核为使用Xbox One 和 Xbox Series X|S 而开发的. 它作为 xpad 的现代替代品,旨在与微软的游戏输入协议(GIP)兼容。
链接:
xone.
xpad.
2.1 下载源码
git clone https://github.com/medusalix/xone
2.2 安装xone
cd xone
sudo ./install.sh --release
2.3 下载固件
这一步需要联网,安装过程中会自动下载一些文件
sudo xone-get-firmware.sh
3. 手柄测试
该部分转载自文章,不过这篇文章中使用的是xone的旧版本xow在我个人使用过程中遇到了一些bug,最终没有解决,使用xone后顺利完成了
将手柄与适配器配对(这一步不同型号手柄配对方法略有差别)
打开linux终端,运行
sudo jstest /dev/input/js4
Driver version is 2.1.0.
Joystick (Xbox One Wireless Controller) has 8 axes (X, Y, Z, Rx, Ry, Rz, Hat0X, Hat0Y)
and 11 buttons (BtnA, BtnB, BtnX, BtnY, BtnTL, BtnTR, BtnSelect, BtnStart, BtnMode, BtnThumbL, BtnThumbR).
Testing ... (interrupt to exit)
Axes: 0: 0 1: 0 2:-32767 3: 0 4: 0 5:-32767 6: 0 7: 0 Buttons: 0:off 1:off 2:off 3:off 4:off 5:off 6:off 7:off 8:off 9:off 10:off
注意:在/dev/input下可能会生成js0, js1, js2, js3, js4 5个文件,可以分别使用jstest 测试一下,运行sudo jstest /dev/input/js4 后,操作手柄操作杆查看数据是否有变化。
4. xbox手柄操作数据接收与解析
该部分转载自文章
joystick_xbox.h
#include <linux/input.h>
#include <linux/joystick.h>
#include <string>
class JoystickXBox
{
public:
JoystickXBox(const std::string &dev_name);
~JoystickXBox();
bool Open();
void Close();
bool Read(struct js_event &js);
unsigned char GetAxes()
{
return axes_;
}
unsigned char GetButtons()
{
return buttons_;
}
int GetFd()
{
return fd_;
}
void PrintData();
void ProcessData(const struct js_event &js);
private:
bool debug_ = false;
int fd_ = -1;
std::string dev_name_ = "";
int version_ = 0x000800;
char name_[512] = "Unkown";
unsigned char axes_ = 2;
unsigned char buttons_ = 2;
int *axis_ = nullptr;
char *button_ = nullptr;
};
joystick_xbox.cpp
#include <errno.h>
#include <fcntl.h>
#include <memory>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "joystick_xbox.h"
JoystickXBox::JoystickXBox(const std::string &dev_name) : fd_(-1),dev_name_(dev_name)
{
}
JoystickXBox::~JoystickXBox()
{
if (axis_)
{
delete axis_;
axis_ = nullptr;
}
if (button_)
{
delete button_;
button_ = nullptr;
}
}
bool JoystickXBox::Open()
{
int fd = -1;
if (dev_name_.length() == 0)
{
return false;
}
// O_NONBLOCK open
fd = open(dev_name_.c_str(), O_RDONLY | O_NONBLOCK);
if (fd < 0)
{
fd_ = -1;
printf("JoystickXBox open %s error, %d(%s)\n", dev_name_.c_str(), errno, strerror(errno));
return false;
}
ioctl(fd, JSIOCGVERSION, &version_);
ioctl(fd, JSIOCGAXES, &axes_);
ioctl(fd, JSIOCGBUTTONS, &buttons_);
ioctl(fd, JSIOCGNAME(512), name_);
printf("JoystickXBox Driver version is %d.%d.%d.\n", version_ >> 16, (version_ >> 8) & 0xff, version_ & 0xff);
printf("JoystickXBox (%s) has %d axes and %d buttons\n", name_, axes_, buttons_);
fd_ = fd;
axis_ = (int *)calloc(axes_, sizeof(int));
button_ = (char *)calloc(buttons_, sizeof(char));
return true;
}
void JoystickXBox::Close()
{
if (fd_ > 0)
{
close(fd_);
fd_ = -1;
}
}
bool JoystickXBox::Read(struct js_event &js)
{
int len = -1;
if (fd_ < 0)
{
return false;
}
memset(&js, 0, sizeof(js));
len = read(fd_, &js, sizeof(struct js_event));
if (len != sizeof(struct js_event))
{
printf("JoystickXBox: error reading, %d(%s)\n", errno, strerror(errno));
return false;
}
return true;
}
void JoystickXBox::ProcessData(const struct js_event &js)
{
JoystickFrame frame;
int joystick_angular_value = 0;
int joystick_linear_value = 0;
int button_angular_value = 0;
int button_linear_value = 0;
switch (js.type & ~JS_EVENT_INIT)
{
case JS_EVENT_BUTTON:
button_[js.number] = js.value;
break;
case JS_EVENT_AXIS:
axis_[js.number] = js.value;
break;
}
if (debug_)
{
PrintData();
}
}
void JoystickXBox::PrintData()
{
if (axes_ && axis_)
{
printf("Axes: ");
for (int i = 0; i < axes_; i++)
{
printf("%2d:%6d ", i, axis_[i]);
}
}
if (buttons_ && button_)
{
printf("Buttons: ");
for (int i = 0; i < buttons_; i++)
{
printf("%2d:%s ", i, button_[i] ? "on " : "off");
}
}
printf("\n");
fflush(stdout);
}
int main()
{
bool ret = false;
int err_cnt = 0;
fd_set rfds;
timeval timeout;
struct js_event js;
int fd = -1;
std::string dev_name = "/dev/input/js4";
std::unique_ptr<JoystickXBox> joystick_xbox = std::make_unique<JoystickXBox>(dev_name);
ret = joystick_xbox->Open();
if (!ret)
{
return -1;
}
fd = joystick_xbox->GetFd();
while (1)
{
usleep(100);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
int ret = select(fd + 1, &rfds, NULL, NULL, &timeout);
if (ret > 0 && FD_ISSET(fd, &rfds))
{
ret = joystick_xbox->Read(js);
if (ret)
{
joystick_xbox->ProcessData(js);
}
}
}
joystick_xbox->Close();
return 0;
}